Imported Upstream version 1.38.0 upstream/1.38.0
authorJinWang An <jinwang.an@samsung.com>
Wed, 1 Dec 2021 08:53:20 +0000 (17:53 +0900)
committerJinWang An <jinwang.an@samsung.com>
Wed, 1 Dec 2021 08:53:20 +0000 (17:53 +0900)
821 files changed:
BUILD
BUILD.gn
CMakeLists.txt
Makefile
Package.swift
bazel/grpc_build_system.bzl
bazel/grpc_deps.bzl
build_autogenerated.yaml
build_config.rb
build_handwritten.yaml
cmake/modules/Findre2.cmake
config.m4
config.w32
doc/PROTOCOL-WEB.md
doc/core/grpc-error.md
doc/g_stands_for.md
doc/grpc_xds_features.md
doc/keepalive.md
doc/python/sphinx/grpc_admin.rst [new file with mode: 0644]
doc/python/sphinx/grpc_asyncio.rst
doc/python/sphinx/grpc_csds.rst [new file with mode: 0644]
doc/python/sphinx/index.rst
doc/service_config.md
doc/xds-test-descriptions.md
examples/cpp/helloworld/BUILD
examples/cpp/helloworld/xds_greeter_client.cc [new file with mode: 0644]
examples/cpp/helloworld/xds_greeter_server.cc [new file with mode: 0644]
examples/php/GPBMetadata/Helloworld.php [new file with mode: 0644]
examples/php/Helloworld/GreeterClient.php [new file with mode: 0644]
examples/php/Helloworld/GreeterStub.php [new file with mode: 0644]
examples/php/Helloworld/HelloReply.php [new file with mode: 0644]
examples/php/Helloworld/HelloRequest.php [new file with mode: 0644]
examples/php/README.md
examples/php/composer.json
examples/php/echo/composer.json
examples/php/greeter_and_routeguide_multi_server.php [new file with mode: 0644]
examples/php/greeter_proto_gen.sh
examples/php/greeter_server.php [new file with mode: 0644]
examples/php/route_guide/GPBMetadata/RouteGuide.php [new file with mode: 0644]
examples/php/route_guide/RouteGuideService.php [new file with mode: 0644]
examples/php/route_guide/Routeguide/Feature.php [new file with mode: 0644]
examples/php/route_guide/Routeguide/Point.php [new file with mode: 0644]
examples/php/route_guide/Routeguide/Rectangle.php [new file with mode: 0644]
examples/php/route_guide/Routeguide/RouteGuideClient.php [new file with mode: 0644]
examples/php/route_guide/Routeguide/RouteGuideStub.php [new file with mode: 0644]
examples/php/route_guide/Routeguide/RouteNote.php [new file with mode: 0644]
examples/php/route_guide/Routeguide/RouteSummary.php [new file with mode: 0644]
examples/php/route_guide/route_guide_db.json [new file with mode: 0644]
examples/php/route_guide/route_guide_proto_gen.sh
examples/php/route_guide/route_guide_server.php [new file with mode: 0644]
examples/python/xds/README.md
examples/python/xds/client.py
examples/python/xds/requirements.txt
examples/python/xds/server.py
gRPC-C++.podspec
gRPC-Core.podspec
gRPC-ProtoRPC.podspec
gRPC-RxLibrary.podspec
gRPC.podspec
grpc.gemspec
grpc.gyp
include/grpc/event_engine/README.md [new file with mode: 0644]
include/grpc/event_engine/channel_args.h [new file with mode: 0644]
include/grpc/event_engine/event_engine.h [new file with mode: 0644]
include/grpc/event_engine/port.h [new file with mode: 0644]
include/grpc/event_engine/slice_allocator.h [new file with mode: 0644]
include/grpc/grpc.h
include/grpc/grpc_security_constants.h
include/grpc/impl/codegen/grpc_types.h
include/grpc/impl/codegen/port_platform.h
include/grpc/module.modulemap
include/grpcpp/channel.h
include/grpcpp/generic/generic_stub.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/method_handler.h
include/grpcpp/impl/codegen/rpc_method.h
include/grpcpp/impl/codegen/stub_options.h
include/grpcpp/server.h
include/grpcpp/server_builder.h
include/grpcpp/test/mock_stream.h
include/grpcpp/xds_server_builder.h
package.xml
src/abseil-cpp/preprocessed_builds.yaml
src/boringssl/boringssl_prefix_symbols.h
src/compiler/cpp_generator.cc
src/compiler/php_generator.cc
src/compiler/php_generator.h
src/compiler/php_generator_helpers.h
src/compiler/php_plugin.cc
src/core/ext/filters/client_channel/backup_poller.cc
src/core/ext/filters/client_channel/channel_connectivity.cc
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.h
src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/config_selector.h
src/core/ext/filters/client_channel/connector.h
src/core/ext/filters/client_channel/dynamic_filters.cc
src/core/ext/filters/client_channel/dynamic_filters.h
src/core/ext/filters/client_channel/health/health_check_client.cc
src/core/ext/filters/client_channel/health/health_check_client.h
src/core/ext/filters/client_channel/http_connect_handshaker.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/client_load_reporting_filter.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
src/core/ext/filters/client_channel/lb_policy/priority/priority.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/weighted_target/weighted_target.cc
src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.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.h
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
src/core/ext/filters/client_channel/resolver/xds/xds_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/retry_filter.cc [new file with mode: 0644]
src/core/ext/filters/client_channel/retry_filter.h [moved from test/core/util/eval_args_mock_endpoint.h with 56% similarity]
src/core/ext/filters/client_channel/retry_service_config.cc [new file with mode: 0644]
src/core/ext/filters/client_channel/retry_service_config.h [new file with mode: 0644]
src/core/ext/filters/client_channel/server_address.cc
src/core/ext/filters/client_channel/service_config.cc
src/core/ext/filters/client_channel/service_config.h
src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc
src/core/ext/filters/client_channel/service_config_parser.cc
src/core/ext/filters/client_channel/service_config_parser.h
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel.h
src/core/ext/filters/client_idle/client_idle_filter.cc
src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/fault_injection/fault_injection_filter.cc
src/core/ext/filters/fault_injection/service_config_parser.cc
src/core/ext/filters/fault_injection/service_config_parser.h
src/core/ext/filters/http/client/http_client_filter.cc
src/core/ext/filters/http/client_authority_filter.cc
src/core/ext/filters/http/message_compress/message_compress_filter.cc
src/core/ext/filters/http/message_compress/message_decompress_filter.cc
src/core/ext/filters/http/server/http_server_filter.cc
src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
src/core/ext/filters/load_reporting/server_load_reporting_filter.h
src/core/ext/filters/max_age/max_age_filter.cc
src/core/ext/filters/message_size/message_size_filter.cc
src/core/ext/filters/message_size/message_size_filter.h
src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
src/core/ext/transport/chttp2/client/chttp2_connector.cc
src/core/ext/transport/chttp2/client/chttp2_connector.h
src/core/ext/transport/chttp2/client/insecure/channel_create.cc
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
src/core/ext/transport/chttp2/server/chttp2_server.cc
src/core/ext/transport/chttp2/server/chttp2_server.h
src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
src/core/ext/transport/chttp2/transport/chttp2_transport.cc
src/core/ext/transport/chttp2/transport/context_list.cc
src/core/ext/transport/chttp2/transport/context_list.h
src/core/ext/transport/chttp2/transport/flow_control.cc
src/core/ext/transport/chttp2/transport/flow_control.h
src/core/ext/transport/chttp2/transport/frame_data.cc
src/core/ext/transport/chttp2/transport/frame_data.h
src/core/ext/transport/chttp2/transport/frame_goaway.cc
src/core/ext/transport/chttp2/transport/frame_goaway.h
src/core/ext/transport/chttp2/transport/frame_ping.cc
src/core/ext/transport/chttp2/transport/frame_ping.h
src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
src/core/ext/transport/chttp2/transport/frame_rst_stream.h
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_settings.h
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/frame_window_update.h
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_parser.h
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/hpack_table.h
src/core/ext/transport/chttp2/transport/incoming_metadata.cc
src/core/ext/transport/chttp2/transport/incoming_metadata.h
src/core/ext/transport/chttp2/transport/internal.h
src/core/ext/transport/chttp2/transport/parsing.cc
src/core/ext/transport/chttp2/transport/writing.cc
src/core/ext/transport/cronet/transport/cronet_status.cc
src/core/ext/transport/cronet/transport/cronet_status.h
src/core/ext/transport/cronet/transport/cronet_transport.cc
src/core/ext/transport/inproc/inproc_transport.cc
src/core/ext/xds/certificate_provider_factory.h
src/core/ext/xds/certificate_provider_store.h
src/core/ext/xds/file_watcher_certificate_provider_factory.cc
src/core/ext/xds/file_watcher_certificate_provider_factory.h
src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc
src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h
src/core/ext/xds/xds_api.cc
src/core/ext/xds/xds_api.h
src/core/ext/xds/xds_bootstrap.cc
src/core/ext/xds/xds_bootstrap.h
src/core/ext/xds/xds_certificate_provider.cc
src/core/ext/xds/xds_certificate_provider.h
src/core/ext/xds/xds_channel_args.h
src/core/ext/xds/xds_client.cc
src/core/ext/xds/xds_client.h
src/core/ext/xds/xds_client_stats.h
src/core/ext/xds/xds_server_config_fetcher.cc
src/core/lib/address_utils/parse_address.cc [moved from src/core/lib/iomgr/parse_address.cc with 90% similarity]
src/core/lib/address_utils/parse_address.h [moved from src/core/lib/iomgr/parse_address.h with 86% similarity]
src/core/lib/address_utils/sockaddr_utils.cc [moved from src/core/lib/iomgr/sockaddr_utils.cc with 94% similarity]
src/core/lib/address_utils/sockaddr_utils.h [moved from src/core/lib/iomgr/sockaddr_utils.h with 87% similarity]
src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack.h
src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_stack_builder.h
src/core/lib/channel/channelz.cc
src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc
src/core/lib/channel/handshaker.h
src/core/lib/event_engine/slice_allocator.cc [new file with mode: 0644]
src/core/lib/event_engine/sockaddr.cc [new file with mode: 0644]
src/core/lib/gprpp/ref_counted.h
src/core/lib/gprpp/status_helper.cc [new file with mode: 0644]
src/core/lib/gprpp/status_helper.h [new file with mode: 0644]
src/core/lib/http/httpcli.cc
src/core/lib/http/httpcli_security_connector.cc
src/core/lib/http/parser.cc
src/core/lib/http/parser.h
src/core/lib/iomgr/buffer_list.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/closure.h
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/combiner.h
src/core/lib/iomgr/endpoint.cc
src/core/lib/iomgr/endpoint.h
src/core/lib/iomgr/endpoint_cfstream.cc
src/core/lib/iomgr/endpoint_pair_windows.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/error.h
src/core/lib/iomgr/error_cfstream.cc
src/core/lib/iomgr/error_cfstream.h
src/core/lib/iomgr/error_internal.h
src/core/lib/iomgr/ev_apple.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_posix.h
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/exec_ctx.h
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/executor.h
src/core/lib/iomgr/iomgr.cc
src/core/lib/iomgr/iomgr.h
src/core/lib/iomgr/iomgr_custom.cc
src/core/lib/iomgr/iomgr_internal.cc
src/core/lib/iomgr/iomgr_internal.h
src/core/lib/iomgr/iomgr_posix.cc
src/core/lib/iomgr/iomgr_posix_cfstream.cc
src/core/lib/iomgr/iomgr_windows.cc
src/core/lib/iomgr/load_file.cc
src/core/lib/iomgr/load_file.h
src/core/lib/iomgr/lockfree_event.cc
src/core/lib/iomgr/lockfree_event.h
src/core/lib/iomgr/poller/eventmanager_interface.h [deleted file]
src/core/lib/iomgr/poller/eventmanager_libuv.cc [deleted file]
src/core/lib/iomgr/poller/eventmanager_libuv.h [deleted file]
src/core/lib/iomgr/pollset.cc
src/core/lib/iomgr/pollset.h
src/core/lib/iomgr/pollset_custom.cc
src/core/lib/iomgr/pollset_windows.cc
src/core/lib/iomgr/port.h
src/core/lib/iomgr/python_util.h
src/core/lib/iomgr/resolve_address.cc
src/core/lib/iomgr/resolve_address.h
src/core/lib/iomgr/resolve_address_custom.cc
src/core/lib/iomgr/resolve_address_custom.h
src/core/lib/iomgr/resolve_address_posix.cc
src/core/lib/iomgr/resolve_address_windows.cc
src/core/lib/iomgr/resource_quota.cc
src/core/lib/iomgr/socket_utils_common_posix.cc
src/core/lib/iomgr/socket_utils_posix.h
src/core/lib/iomgr/tcp_client_cfstream.cc
src/core/lib/iomgr/tcp_client_custom.cc
src/core/lib/iomgr/tcp_client_posix.cc
src/core/lib/iomgr/tcp_client_posix.h
src/core/lib/iomgr/tcp_client_windows.cc
src/core/lib/iomgr/tcp_custom.cc
src/core/lib/iomgr/tcp_custom.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_utils_posix_common.cc
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
src/core/lib/iomgr/tcp_server_windows.cc
src/core/lib/iomgr/tcp_uv.cc
src/core/lib/iomgr/tcp_windows.cc
src/core/lib/iomgr/tcp_windows.h
src/core/lib/iomgr/timer_custom.cc
src/core/lib/iomgr/timer_custom.h
src/core/lib/iomgr/timer_generic.cc
src/core/lib/iomgr/udp_server.cc
src/core/lib/iomgr/unix_sockets_posix.cc
src/core/lib/iomgr/unix_sockets_posix.h
src/core/lib/iomgr/unix_sockets_posix_noop.cc
src/core/lib/iomgr/wakeup_fd_eventfd.cc
src/core/lib/iomgr/wakeup_fd_pipe.cc
src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/iomgr/wakeup_fd_posix.h
src/core/lib/iomgr/work_serializer.h
src/core/lib/json/json.h
src/core/lib/json/json_reader.cc
src/core/lib/matchers/matchers.cc
src/core/lib/matchers/matchers.h
src/core/lib/security/authorization/authorization_engine.h
src/core/lib/security/authorization/cel_authorization_engine.cc [moved from src/core/lib/security/authorization/authorization_engine.cc with 94% similarity]
src/core/lib/security/authorization/cel_authorization_engine.h [new file with mode: 0644]
src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/evaluate_args.h
src/core/lib/security/authorization/grpc_authorization_engine.cc [new file with mode: 0644]
src/core/lib/security/authorization/grpc_authorization_engine.h [new file with mode: 0644]
src/core/lib/security/authorization/matchers.cc [new file with mode: 0644]
src/core/lib/security/authorization/matchers.h [new file with mode: 0644]
src/core/lib/security/authorization/rbac_policy.cc
src/core/lib/security/authorization/rbac_policy.h
src/core/lib/security/authorization/rbac_translator.cc
src/core/lib/security/credentials/composite/composite_credentials.cc
src/core/lib/security/credentials/composite/composite_credentials.h
src/core/lib/security/credentials/credentials.h
src/core/lib/security/credentials/external/aws_external_account_credentials.cc
src/core/lib/security/credentials/external/aws_external_account_credentials.h
src/core/lib/security/credentials/external/aws_request_signer.cc
src/core/lib/security/credentials/external/aws_request_signer.h
src/core/lib/security/credentials/external/external_account_credentials.cc
src/core/lib/security/credentials/external/external_account_credentials.h
src/core/lib/security/credentials/external/file_external_account_credentials.cc
src/core/lib/security/credentials/external/file_external_account_credentials.h
src/core/lib/security/credentials/external/url_external_account_credentials.cc
src/core/lib/security/credentials/external/url_external_account_credentials.h
src/core/lib/security/credentials/fake/fake_credentials.cc
src/core/lib/security/credentials/fake/fake_credentials.h
src/core/lib/security/credentials/google_default/google_default_credentials.cc
src/core/lib/security/credentials/iam/iam_credentials.cc
src/core/lib/security/credentials/iam/iam_credentials.h
src/core/lib/security/credentials/jwt/json_token.cc
src/core/lib/security/credentials/jwt/jwt_credentials.cc
src/core/lib/security/credentials/jwt/jwt_credentials.h
src/core/lib/security/credentials/jwt/jwt_verifier.cc
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
src/core/lib/security/credentials/oauth2/oauth2_credentials.h
src/core/lib/security/credentials/plugin/plugin_credentials.cc
src/core/lib/security/credentials/plugin/plugin_credentials.h
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h
src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc
src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc
src/core/lib/security/credentials/xds/xds_credentials.cc
src/core/lib/security/security_connector/alts/alts_security_connector.cc
src/core/lib/security/security_connector/fake/fake_security_connector.cc
src/core/lib/security/security_connector/insecure/insecure_security_connector.cc
src/core/lib/security/security_connector/insecure/insecure_security_connector.h
src/core/lib/security/security_connector/load_system_roots_linux.cc
src/core/lib/security/security_connector/local/local_security_connector.cc
src/core/lib/security/security_connector/security_connector.h
src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
src/core/lib/security/security_connector/ssl_utils.cc
src/core/lib/security/security_connector/ssl_utils.h
src/core/lib/security/security_connector/tls/tls_security_connector.cc
src/core/lib/security/security_connector/tls/tls_security_connector.h
src/core/lib/security/transport/client_auth_filter.cc
src/core/lib/security/transport/secure_endpoint.cc
src/core/lib/security/transport/security_handshaker.cc
src/core/lib/security/transport/server_auth_filter.cc
src/core/lib/security/transport/tsi_error.cc
src/core/lib/security/transport/tsi_error.h
src/core/lib/security/util/json_util.cc
src/core/lib/security/util/json_util.h
src/core/lib/surface/call.cc
src/core/lib/surface/call.h
src/core/lib/surface/channel.cc
src/core/lib/surface/channel.h
src/core/lib/surface/channel_ping.cc
src/core/lib/surface/completion_queue.cc
src/core/lib/surface/completion_queue.h
src/core/lib/surface/lame_client.cc
src/core/lib/surface/lame_client.h
src/core/lib/surface/server.cc
src/core/lib/surface/server.h
src/core/lib/surface/validate_metadata.cc
src/core/lib/surface/validate_metadata.h
src/core/lib/surface/version.cc
src/core/lib/transport/byte_stream.cc
src/core/lib/transport/byte_stream.h
src/core/lib/transport/connectivity_state.cc
src/core/lib/transport/error_utils.cc
src/core/lib/transport/error_utils.h
src/core/lib/transport/metadata_batch.cc
src/core/lib/transport/metadata_batch.h
src/core/lib/transport/transport.cc
src/core/lib/transport/transport.h
src/core/lib/transport/transport_op_string.cc
src/core/tsi/alts/crypt/gsec.h
src/core/tsi/alts/handshaker/alts_handshaker_client.cc
src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
src/core/tsi/ssl_transport_security.cc
src/core/tsi/ssl_transport_security.h
src/core/tsi/test_creds/multi-domain-openssl.cnf
src/core/tsi/test_creds/multi-domain.key
src/core/tsi/test_creds/multi-domain.pem
src/cpp/Protobuf-C++.podspec
src/cpp/client/channel_cc.cc
src/cpp/client/client_callback.cc
src/cpp/client/secure_credentials.cc
src/cpp/common/alarm.cc
src/cpp/common/channel_filter.h
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/ext/filters/census/channel_filter.cc
src/cpp/ext/filters/census/channel_filter.h
src/cpp/ext/filters/census/client_filter.cc
src/cpp/ext/filters/census/client_filter.h
src/cpp/ext/filters/census/context.cc
src/cpp/ext/filters/census/context.h
src/cpp/ext/filters/census/rpc_encoding.cc
src/cpp/ext/filters/census/rpc_encoding.h
src/cpp/ext/filters/census/server_filter.cc
src/cpp/ext/filters/census/server_filter.h
src/cpp/server/admin/admin_services.cc
src/cpp/server/server_builder.cc
src/cpp/server/server_callback.cc
src/cpp/server/server_cc.cc
src/csharp/Grpc.Core.Api/VersionInfo.cs
src/csharp/Grpc.Core.NativeDebug/Grpc.Core.NativeDebug.csproj
src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj
src/csharp/Grpc.Core.Tests/Internal/UserAgentStringProviderTest.cs [new file with mode: 0644]
src/csharp/Grpc.Core.Tests/UserAgentStringTest.cs
src/csharp/Grpc.Core.Xamarin/Grpc.Core.Xamarin.csproj
src/csharp/Grpc.Core/Channel.cs
src/csharp/Grpc.Core/Grpc.Core.csproj
src/csharp/Grpc.Core/Internal/PlatformApis.cs
src/csharp/Grpc.Core/Internal/UserAgentStringProvider.cs [new file with mode: 0644]
src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs
src/csharp/Grpc.Tools/ProtoToolsPlatform.cs
src/csharp/README.md
src/csharp/build/dependencies.props
src/csharp/tests.json
src/objective-c/!ProtoCompiler-gRPCCppPlugin.podspec
src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
src/objective-c/!ProtoCompiler.podspec
src/objective-c/BoringSSL-GRPC.podspec
src/objective-c/GRPCClient/GRPCCallLegacy.m
src/objective-c/GRPCClient/version.h
src/objective-c/tests/InteropTests/InteropTests.m
src/objective-c/tests/version.h
src/php/README.md
src/php/bin/generate_proto_php.sh
src/php/composer.json
src/php/ext/grpc/version.h
src/php/lib/Grpc/RpcServer.php
src/php/lib/Grpc/ServerCallWriter.php
src/php/lib/Grpc/ServerContext.php
src/php/tests/interop/Grpc/Testing/LoadBalancerStatsServiceStub.php
src/php/tests/interop/Grpc/Testing/ReconnectServiceStub.php [new file with mode: 0644]
src/php/tests/interop/Grpc/Testing/TestServiceStub.php [new file with mode: 0644]
src/php/tests/interop/Grpc/Testing/UnimplementedServiceStub.php [new file with mode: 0644]
src/php/tests/interop/Grpc/Testing/XdsUpdateClientConfigureServiceStub.php
src/php/tests/interop/Grpc/Testing/XdsUpdateHealthServiceStub.php [new file with mode: 0644]
src/php/tests/interop/xds_client.php
src/php/tests/unit_tests/RpcServerTest.php [new file with mode: 0644]
src/php/tests/unit_tests/ServerCallTest.php
src/proto/grpc/testing/xds/v3/BUILD
src/python/grpcio/commands.py
src/python/grpcio/grpc/__init__.py
src/python/grpcio/grpc/_cython/_cygrpc/aio/call.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/aio/iomgr/iomgr.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/aio/iomgr/resolver.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/aio/iomgr/socket.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/aio/iomgr/timer.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/csds.pyx.pxi [new file with mode: 0644]
src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/iomgr.pxd.pxi
src/python/grpcio/grpc/_cython/_cygrpc/iomgr.pyx.pxi
src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
src/python/grpcio/grpc/_cython/cygrpc.pyx
src/python/grpcio/grpc/_grpcio_metadata.py
src/python/grpcio/grpc/_server.py
src/python/grpcio/grpc/aio/_base_server.py
src/python/grpcio/grpc_core_dependencies.py
src/python/grpcio/grpc_version.py
src/python/grpcio_admin/.gitignore [new file with mode: 0644]
src/python/grpcio_admin/MANIFEST.in [new file with mode: 0644]
src/python/grpcio_admin/README.rst [new file with mode: 0644]
src/python/grpcio_admin/grpc_admin/BUILD.bazel [new file with mode: 0644]
src/python/grpcio_admin/grpc_admin/__init__.py [new file with mode: 0644]
src/python/grpcio_admin/grpc_version.py [new file with mode: 0644]
src/python/grpcio_admin/setup.py [new file with mode: 0644]
src/python/grpcio_channelz/grpc_version.py
src/python/grpcio_csds/.gitignore [new file with mode: 0644]
src/python/grpcio_csds/MANIFEST.in [new file with mode: 0644]
src/python/grpcio_csds/README.rst [new file with mode: 0644]
src/python/grpcio_csds/grpc_csds/BUILD.bazel [new file with mode: 0644]
src/python/grpcio_csds/grpc_csds/__init__.py [new file with mode: 0644]
src/python/grpcio_csds/grpc_version.py [new file with mode: 0644]
src/python/grpcio_csds/setup.py [new file with mode: 0644]
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/commands.py
src/python/grpcio_tests/grpc_version.py
src/python/grpcio_tests/tests/admin/BUILD.bazel [new file with mode: 0644]
src/python/grpcio_tests/tests/admin/test_admin.py [new file with mode: 0644]
src/python/grpcio_tests/tests/csds/BUILD.bazel [new file with mode: 0644]
src/python/grpcio_tests/tests/csds/test_csds.py [new file with mode: 0644]
src/python/grpcio_tests/tests/tests.json
src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py
src/python/grpcio_tests/tests_aio/unit/metadata_test.py
src/python/grpcio_tests/tests_py3_only/interop/BUILD.bazel
src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client [new file with mode: 0644]
src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.server [new file with mode: 0644]
src/python/grpcio_tests/tests_py3_only/interop/xds_interop_client.py
src/python/grpcio_tests/tests_py3_only/interop/xds_interop_server.py [new file with mode: 0644]
src/ruby/README.md
src/ruby/bin/math_services_pb.rb
src/ruby/ext/grpc/rb_grpc_imports.generated.h
src/ruby/lib/grpc/version.rb
src/ruby/pb/grpc/health/v1/health_services_pb.rb
src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
src/ruby/qps/src/proto/grpc/testing/benchmark_service_services_pb.rb
src/ruby/qps/src/proto/grpc/testing/report_qps_scenario_service_services_pb.rb
src/ruby/qps/src/proto/grpc/testing/worker_service_services_pb.rb
src/ruby/tools/platform_check.rb
src/ruby/tools/version.rb
templates/CMakeLists.txt.template
templates/gRPC-C++.podspec.template
templates/gRPC-Core.podspec.template
templates/include/grpc/module.modulemap.template
templates/src/core/lib/surface/version.cc.template
templates/src/objective-c/BoringSSL-GRPC.podspec.template
templates/src/python/grpcio_admin/grpc_version.py.template [new file with mode: 0644]
templates/src/python/grpcio_csds/grpc_version.py.template [new file with mode: 0644]
templates/test/core/surface/public_headers_must_be_c89.c.template
templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
templates/tools/dockerfile/interoptest/grpc_interop_go1.16/Dockerfile.template [new file with mode: 0644]
templates/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh.template [new file with mode: 0644]
test/core/address_utils/BUILD [moved from test/core/iomgr/poller/BUILD with 54% similarity]
test/core/address_utils/parse_address_test.cc [moved from test/core/iomgr/parse_address_test.cc with 97% similarity]
test/core/address_utils/parse_address_with_named_scope_id_test.cc [moved from test/core/iomgr/parse_address_with_named_scope_id_test.cc with 97% similarity]
test/core/address_utils/sockaddr_utils_test.cc [moved from test/core/iomgr/sockaddr_utils_test.cc with 97% similarity]
test/core/bad_client/bad_client.cc
test/core/channel/channel_stack_builder_test.cc
test/core/channel/channel_stack_test.cc
test/core/channel/channelz_test.cc
test/core/client_channel/certificate_provider_registry_test.cc
test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
test/core/client_channel/resolvers/dns_resolver_test.cc
test/core/client_channel/resolvers/fake_resolver_test.cc
test/core/client_channel/resolvers/sockaddr_resolver_test.cc
test/core/client_channel/service_config_test.cc
test/core/end2end/bad_server_response_test.cc
test/core/end2end/dualstack_socket_test.cc
test/core/end2end/end2end_nosec_tests.cc
test/core/end2end/end2end_tests.cc
test/core/end2end/fixtures/h2_proxy.cc
test/core/end2end/fixtures/h2_sockpair+trace.cc
test/core/end2end/fixtures/h2_sockpair.cc
test/core/end2end/fixtures/h2_sockpair_1byte.cc
test/core/end2end/fixtures/http_proxy_fixture.cc
test/core/end2end/generate_tests.bzl
test/core/end2end/goaway_server_test.cc
test/core/end2end/tests/filter_causes_close.cc
test/core/end2end/tests/filter_context.cc
test/core/end2end/tests/filter_init_fails.cc
test/core/end2end/tests/filter_latency.cc
test/core/end2end/tests/filter_status_code.cc
test/core/end2end/tests/retry.cc
test/core/end2end/tests/retry_cancel_during_delay.cc [new file with mode: 0644]
test/core/end2end/tests/retry_cancellation.cc
test/core/end2end/tests/retry_disabled.cc
test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
test/core/end2end/tests/retry_lb_drop.cc [new file with mode: 0644]
test/core/end2end/tests/retry_non_retriable_status.cc
test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
test/core/end2end/tests/retry_recv_initial_metadata.cc
test/core/end2end/tests/retry_recv_message.cc
test/core/end2end/tests/retry_server_pushback_delay.cc
test/core/end2end/tests/retry_server_pushback_disabled.cc
test/core/end2end/tests/retry_streaming.cc
test/core/end2end/tests/retry_streaming_after_commit.cc
test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
test/core/end2end/tests/retry_throttled.cc
test/core/end2end/tests/retry_too_many_attempts.cc
test/core/gprpp/BUILD
test/core/gprpp/ref_counted_test.cc
test/core/gprpp/status_helper_test.cc [new file with mode: 0644]
test/core/handshake/readahead_handshaker_server_ssl.cc
test/core/http/httpcli_test.cc
test/core/http/httpscli_test.cc
test/core/http/parser_test.cc
test/core/iomgr/BUILD
test/core/iomgr/buffer_list_test.cc
test/core/iomgr/combiner_test.cc
test/core/iomgr/endpoint_pair_test.cc
test/core/iomgr/endpoint_tests.cc
test/core/iomgr/error_test.cc
test/core/iomgr/ev_epollex_linux_test.cc
test/core/iomgr/fd_posix_test.cc
test/core/iomgr/ios/CFStreamTests/CFStreamClientTests.mm
test/core/iomgr/ios/CFStreamTests/CFStreamEndpointTests.mm
test/core/iomgr/load_file_test.cc
test/core/iomgr/poller/eventmanager_libuv_test.cc [deleted file]
test/core/iomgr/pollset_windows_starvation_test.cc
test/core/iomgr/resolve_address_posix_test.cc
test/core/iomgr/resolve_address_test.cc
test/core/iomgr/resource_quota_test.cc
test/core/iomgr/socket_utils_test.cc
test/core/iomgr/stranded_event_test.cc
test/core/iomgr/tcp_client_posix_test.cc
test/core/iomgr/tcp_client_uv_test.cc
test/core/iomgr/tcp_posix_test.cc
test/core/iomgr/tcp_server_posix_test.cc
test/core/iomgr/tcp_server_uv_test.cc
test/core/iomgr/timer_list_test.cc
test/core/iomgr/udp_server_test.cc
test/core/json/fuzzer.cc
test/core/json/json_test.cc
test/core/security/BUILD
test/core/security/authorization_matchers_test.cc [new file with mode: 0644]
test/core/security/aws_request_signer_test.cc
test/core/security/cel_authorization_engine_test.cc [moved from test/core/security/authorization_engine_test.cc with 57% similarity]
test/core/security/credentials_test.cc
test/core/security/evaluate_args_test.cc
test/core/security/grpc_authorization_engine_test.cc [new file with mode: 0644]
test/core/security/grpc_tls_certificate_distributor_test.cc
test/core/security/grpc_tls_certificate_provider_test.cc
test/core/security/json_token_test.cc
test/core/security/jwt_verifier_test.cc
test/core/security/matchers_test.cc
test/core/security/oauth2_utils.cc
test/core/security/print_google_default_creds_token.cc
test/core/security/rbac_translator_test.cc
test/core/security/secure_endpoint_test.cc
test/core/security/security_connector_test.cc
test/core/security/ssl_server_fuzzer.cc
test/core/security/tls_security_connector_test.cc
test/core/security/xds_credentials_test.cc
test/core/surface/concurrent_connectivity_test.cc
test/core/surface/lame_client_test.cc
test/core/surface/server_test.cc
test/core/transport/BUILD
test/core/transport/byte_stream_test.cc
test/core/transport/chttp2/context_list_test.cc
test/core/transport/chttp2/hpack_parser_fuzzer_test.cc
test/core/transport/chttp2/hpack_parser_test.cc
test/core/transport/chttp2/settings_timeout_test.cc
test/core/transport/chttp2/too_many_pings_test.cc
test/core/transport/error_utils_test.cc [new file with mode: 0644]
test/core/transport/stream_owned_slice_test.cc
test/core/tsi/ssl_transport_security_test.cc
test/core/tsi/transport_security_test_lib.cc
test/core/uri/uri_parser_test.cc
test/core/util/BUILD
test/core/util/eval_args_mock_endpoint.cc [deleted file]
test/core/util/evaluate_args_test_util.h [new file with mode: 0644]
test/core/util/mock_authorization_endpoint.h [new file with mode: 0644]
test/core/util/mock_endpoint.cc
test/core/util/passthru_endpoint.cc
test/core/util/port.cc
test/core/util/port_server_client.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/test_lb_policies.cc
test/core/util/test_lb_policies.h
test/core/util/test_tcp_server.cc
test/core/util/trickle_endpoint.cc
test/core/xds/certificate_provider_store_test.cc
test/core/xds/file_watcher_certificate_provider_factory_test.cc
test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc
test/core/xds/xds_bootstrap_test.cc
test/core/xds/xds_certificate_provider_test.cc
test/cpp/client/client_channel_stress_test.cc
test/cpp/client/destroy_grpclb_channel_with_active_connect_stress_test.cc
test/cpp/codegen/compiler_test_golden
test/cpp/common/channel_filter_test.cc
test/cpp/common/time_jump_test.cc
test/cpp/common/timer_test.cc
test/cpp/end2end/BUILD
test/cpp/end2end/admin_services_end2end_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/filter_end2end_test.cc
test/cpp/end2end/grpclb_end2end_test.cc
test/cpp/end2end/interceptors_util.cc
test/cpp/end2end/interceptors_util.h
test/cpp/end2end/port_sharing_end2end_test.cc
test/cpp/end2end/service_config_end2end_test.cc
test/cpp/end2end/xds_end2end_test.cc
test/cpp/grpclb/grpclb_api_test.cc
test/cpp/interop/grpclb_fallback_test.cc
test/cpp/microbenchmarks/bm_call_create.cc
test/cpp/microbenchmarks/bm_chttp2_hpack.cc
test/cpp/microbenchmarks/bm_chttp2_transport.cc
test/cpp/microbenchmarks/bm_closure.cc
test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
test/cpp/microbenchmarks/bm_error.cc
test/cpp/microbenchmarks/bm_pollset.cc
test/cpp/microbenchmarks/bm_timer.cc
test/cpp/naming/address_sorting_test.cc
test/cpp/naming/cancel_ares_query_test.cc
test/cpp/naming/resolver_component_test.cc
test/cpp/test/BUILD
test/cpp/test/mock_stream_test.cc [new file with mode: 0644]
test/cpp/util/channel_trace_proto_helper.cc
test/distrib/php/run_distrib_test.sh
test/distrib/php/run_distrib_test_macos.sh
test/distrib/python/distribtest.py
third_party/README.md
third_party/protobuf.patch
third_party/py/BUILD
third_party/py/python_configure.bzl
tools/bazel.rc
tools/buildgen/_mako_renderer.py
tools/distrib/check_include_guards.py
tools/distrib/python/.gitignore
tools/distrib/python/grpc_prefixed/generate.py
tools/distrib/python/grpc_version.py
tools/distrib/python/grpcio_tools/grpc_tools/protoc.py
tools/distrib/python/grpcio_tools/grpc_version.py
tools/distrib/python/grpcio_tools/protoc_lib_deps.py
tools/distrib/python/xds_protos/README.rst [new file with mode: 0644]
tools/distrib/python/xds_protos/build.py [new file with mode: 0644]
tools/distrib/python/xds_protos/build_validate_upload.sh [new file with mode: 0755]
tools/distrib/python/xds_protos/setup.py [new file with mode: 0644]
tools/dockerfile/distribtest/python_python38_buster_aarch64/Dockerfile [new file with mode: 0644]
tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
tools/dockerfile/interoptest/grpc_interop_go1.16/Dockerfile [new file with mode: 0644]
tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh [new file with mode: 0644]
tools/doxygen/Doxyfile.c++
tools/doxygen/Doxyfile.c++.internal
tools/doxygen/Doxyfile.core
tools/doxygen/Doxyfile.core.internal
tools/doxygen/Doxyfile.objc
tools/doxygen/Doxyfile.objc.internal
tools/doxygen/Doxyfile.php
tools/internal_ci/helper_scripts/prepare_qemu_rc [new file with mode: 0644]
tools/internal_ci/linux/grpc_build_submodule_at_head.sh
tools/internal_ci/linux/grpc_distribtests.sh
tools/internal_ci/linux/grpc_distribtests_python.cfg [new file with mode: 0644]
tools/internal_ci/linux/grpc_distribtests_python.sh [new file with mode: 0755]
tools/internal_ci/linux/grpc_e2e_performance_v2.sh
tools/internal_ci/linux/grpc_portability_build_only.cfg
tools/internal_ci/linux/grpc_xds.cfg
tools/internal_ci/linux/grpc_xds_csharp.cfg
tools/internal_ci/linux/grpc_xds_k8s.cfg
tools/internal_ci/linux/grpc_xds_k8s.sh
tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh
tools/internal_ci/linux/grpc_xds_k8s_python.cfg [new file with mode: 0644]
tools/internal_ci/linux/grpc_xds_k8s_python.sh [new file with mode: 0755]
tools/internal_ci/linux/grpc_xds_php.cfg
tools/internal_ci/linux/grpc_xds_python.cfg
tools/internal_ci/linux/grpc_xds_ruby.cfg
tools/internal_ci/linux/grpc_xds_v3.cfg
tools/internal_ci/linux/grpc_xds_v3_csharp.cfg
tools/internal_ci/linux/grpc_xds_v3_php.cfg
tools/internal_ci/linux/grpc_xds_v3_python.cfg
tools/internal_ci/linux/grpc_xds_v3_ruby.cfg
tools/interop_matrix/README.md
tools/interop_matrix/client_matrix.py
tools/run_tests/artifacts/artifact_targets.py
tools/run_tests/artifacts/build_artifact_python.sh
tools/run_tests/artifacts/distribtest_targets.py
tools/run_tests/dockerize/build_and_run_docker.sh
tools/run_tests/generated/tests.json
tools/run_tests/helper_scripts/build_python.sh
tools/run_tests/performance/README.md
tools/run_tests/performance/loadtest_concat_yaml.py [new file with mode: 0755]
tools/run_tests/performance/loadtest_config.py [new file with mode: 0755]
tools/run_tests/performance/loadtest_template.py [new file with mode: 0755]
tools/run_tests/performance/scenario_config.py
tools/run_tests/performance/scenario_config_exporter.py
tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml [new file with mode: 0644]
tools/run_tests/python_utils/filter_pull_request_tests.py
tools/run_tests/run_xds_tests.py
tools/run_tests/sanity/check_submodules.sh
tools/run_tests/sanity/core_banned_functions.py
tools/run_tests/task_runner.py
tools/run_tests/xds_k8s_test_driver/README.md
tools/run_tests/xds_k8s_test_driver/framework/helpers/retryers.py
tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py

diff --git a/BUILD b/BUILD
index 4d35ffb..823abc2 100644 (file)
--- a/BUILD
+++ b/BUILD
@@ -32,7 +32,6 @@ package(
 load(
     "//bazel:grpc_build_system.bzl",
     "grpc_cc_library",
-    "grpc_cc_library_xds",
     "grpc_generate_one_off_targets",
     "grpc_upb_proto_library",
     "python_config_settings",
@@ -86,11 +85,11 @@ config_setting(
 python_config_settings()
 
 # This should be updated along with build_handwritten.yaml
-g_stands_for = "gilded"  # @unused
+g_stands_for = "guadalupe_river_park_conservancy"  # @unused
 
-core_version = "15.0.0"  # @unused
+core_version = "16.0.0"  # @unused
 
-version = "1.37.1"  # @unused
+version = "1.38.0"  # @unused
 
 GPR_PUBLIC_HDRS = [
     "include/grpc/support/alloc.h",
@@ -128,6 +127,13 @@ GRPC_PUBLIC_HDRS = [
     "include/grpc/support/workaround_list.h",
 ]
 
+GRPC_PUBLIC_EVENT_ENGINE_HDRS = [
+    "include/grpc/event_engine/channel_args.h",
+    "include/grpc/event_engine/event_engine.h",
+    "include/grpc/event_engine/port.h",
+    "include/grpc/event_engine/slice_allocator.h",
+]
+
 GRPC_SECURE_PUBLIC_HDRS = [
     "include/grpc/grpc_security.h",
 ]
@@ -585,6 +591,7 @@ grpc_cc_library(
         "src/core/lib/gprpp/mpscq.cc",
         "src/core/lib/gprpp/stat_posix.cc",
         "src/core/lib/gprpp/stat_windows.cc",
+        "src/core/lib/gprpp/status_helper.cc",
         "src/core/lib/gprpp/thd_posix.cc",
         "src/core/lib/gprpp/thd_windows.cc",
         "src/core/lib/gprpp/time_util.cc",
@@ -620,6 +627,7 @@ grpc_cc_library(
         "src/core/lib/gprpp/memory.h",
         "src/core/lib/gprpp/mpscq.h",
         "src/core/lib/gprpp/stat.h",
+        "src/core/lib/gprpp/status_helper.h",
         "src/core/lib/gprpp/sync.h",
         "src/core/lib/gprpp/thd.h",
         "src/core/lib/gprpp/time_util.h",
@@ -638,6 +646,8 @@ grpc_cc_library(
     language = "c++",
     public_hdrs = GPR_PUBLIC_HDRS,
     deps = [
+        "debug_location",
+        "google_api_upb",
         "gpr_codegen",
         "grpc_codegen",
     ],
@@ -746,6 +756,8 @@ grpc_cc_library(
 grpc_cc_library(
     name = "grpc_base_c",
     srcs = [
+        "src/core/lib/address_utils/parse_address.cc",
+        "src/core/lib/address_utils/sockaddr_utils.cc",
         "src/core/lib/avl/avl.cc",
         "src/core/lib/backoff/backoff.cc",
         "src/core/lib/channel/channel_args.cc",
@@ -767,6 +779,8 @@ grpc_cc_library(
         "src/core/lib/compression/stream_compression_identity.cc",
         "src/core/lib/debug/stats.cc",
         "src/core/lib/debug/stats_data.cc",
+        "src/core/lib/event_engine/slice_allocator.cc",
+        "src/core/lib/event_engine/sockaddr.cc",
         "src/core/lib/http/format_request.cc",
         "src/core/lib/http/httpcli.cc",
         "src/core/lib/http/parser.cc",
@@ -811,7 +825,6 @@ grpc_cc_library(
         "src/core/lib/iomgr/is_epollexclusive_available.cc",
         "src/core/lib/iomgr/load_file.cc",
         "src/core/lib/iomgr/lockfree_event.cc",
-        "src/core/lib/iomgr/parse_address.cc",
         "src/core/lib/iomgr/polling_entity.cc",
         "src/core/lib/iomgr/pollset.cc",
         "src/core/lib/iomgr/pollset_custom.cc",
@@ -825,7 +838,6 @@ grpc_cc_library(
         "src/core/lib/iomgr/resolve_address_posix.cc",
         "src/core/lib/iomgr/resolve_address_windows.cc",
         "src/core/lib/iomgr/resource_quota.cc",
-        "src/core/lib/iomgr/sockaddr_utils.cc",
         "src/core/lib/iomgr/socket_factory_posix.cc",
         "src/core/lib/iomgr/socket_mutator.cc",
         "src/core/lib/iomgr/socket_utils_common_posix.cc",
@@ -908,6 +920,8 @@ grpc_cc_library(
         "src/core/lib/uri/uri_parser.cc",
     ],
     hdrs = [
+        "src/core/lib/address_utils/parse_address.h",
+        "src/core/lib/address_utils/sockaddr_utils.h",
         "src/core/lib/avl/avl.h",
         "src/core/lib/backoff/backoff.h",
         "src/core/lib/channel/channel_args.h",
@@ -967,7 +981,6 @@ grpc_cc_library(
         "src/core/lib/iomgr/load_file.h",
         "src/core/lib/iomgr/lockfree_event.h",
         "src/core/lib/iomgr/nameser.h",
-        "src/core/lib/iomgr/parse_address.h",
         "src/core/lib/iomgr/polling_entity.h",
         "src/core/lib/iomgr/pollset.h",
         "src/core/lib/iomgr/pollset_custom.h",
@@ -984,7 +997,6 @@ grpc_cc_library(
         "src/core/lib/iomgr/sockaddr.h",
         "src/core/lib/iomgr/sockaddr_custom.h",
         "src/core/lib/iomgr/sockaddr_posix.h",
-        "src/core/lib/iomgr/sockaddr_utils.h",
         "src/core/lib/iomgr/sockaddr_windows.h",
         "src/core/lib/iomgr/socket_factory_posix.h",
         "src/core/lib/iomgr/socket_mutator.h",
@@ -1057,10 +1069,9 @@ grpc_cc_library(
         "absl/container:flat_hash_map",
     ],
     language = "c++",
-    public_hdrs = GRPC_PUBLIC_HDRS,
+    public_hdrs = GRPC_PUBLIC_HDRS + GRPC_PUBLIC_EVENT_ENGINE_HDRS,
     deps = [
         "dual_ref_counted",
-        "eventmanager_libuv",
         "gpr_base",
         "grpc_codegen",
         "grpc_trace",
@@ -1135,6 +1146,8 @@ grpc_cc_library(
         "src/core/ext/filters/client_channel/resolver.cc",
         "src/core/ext/filters/client_channel/resolver_registry.cc",
         "src/core/ext/filters/client_channel/resolver_result_parsing.cc",
+        "src/core/ext/filters/client_channel/retry_filter.cc",
+        "src/core/ext/filters/client_channel/retry_service_config.cc",
         "src/core/ext/filters/client_channel/retry_throttle.cc",
         "src/core/ext/filters/client_channel/server_address.cc",
         "src/core/ext/filters/client_channel/service_config.cc",
@@ -1167,6 +1180,8 @@ grpc_cc_library(
         "src/core/ext/filters/client_channel/resolver_factory.h",
         "src/core/ext/filters/client_channel/resolver_registry.h",
         "src/core/ext/filters/client_channel/resolver_result_parsing.h",
+        "src/core/ext/filters/client_channel/retry_filter.h",
+        "src/core/ext/filters/client_channel/retry_service_config.h",
         "src/core/ext/filters/client_channel/retry_throttle.h",
         "src/core/ext/filters/client_channel/server_address.h",
         "src/core/ext/filters/client_channel/service_config.h",
@@ -2050,10 +2065,15 @@ grpc_cc_library(
     name = "grpc_rbac_engine",
     srcs = [
         "src/core/lib/security/authorization/evaluate_args.cc",
+        "src/core/lib/security/authorization/grpc_authorization_engine.cc",
+        "src/core/lib/security/authorization/matchers.cc",
         "src/core/lib/security/authorization/rbac_policy.cc",
     ],
     hdrs = [
+        "src/core/lib/security/authorization/authorization_engine.h",
         "src/core/lib/security/authorization/evaluate_args.h",
+        "src/core/lib/security/authorization/grpc_authorization_engine.h",
+        "src/core/lib/security/authorization/matchers.h",
         "src/core/lib/security/authorization/rbac_policy.h",
     ],
     language = "c++",
@@ -2084,10 +2104,10 @@ grpc_cc_library(
 grpc_cc_library(
     name = "grpc_cel_engine",
     srcs = [
-        "src/core/lib/security/authorization/authorization_engine.cc",
+        "src/core/lib/security/authorization/cel_authorization_engine.cc",
     ],
     hdrs = [
-        "src/core/lib/security/authorization/authorization_engine.h",
+        "src/core/lib/security/authorization/cel_authorization_engine.h",
     ],
     external_deps = [
         "absl/container:flat_hash_set",
@@ -2614,7 +2634,7 @@ grpc_cc_library(
     alwayslink = 1,
 )
 
-grpc_cc_library_xds(
+grpc_cc_library(
     name = "grpcpp_csds",
     srcs = [
         "src/cpp/server/csds/csds.cc",
@@ -2630,7 +2650,7 @@ grpc_cc_library_xds(
     alwayslink = 1,
 )
 
-grpc_cc_library_xds(
+grpc_cc_library(
     name = "grpcpp_admin",
     srcs = [
         "src/cpp/server/admin/admin_services.cc",
@@ -2735,6 +2755,7 @@ grpc_cc_library(
         "absl-time",
         "opencensus-trace",
         "opencensus-trace-context_util",
+        "opencensus-trace-propagation",
         "opencensus-stats",
         "opencensus-context",
     ],
@@ -3605,25 +3626,3 @@ filegroup(
     ],
     visibility = ["//visibility:public"],
 )
-
-# Base classes of EventManagerInterface
-grpc_cc_library(
-    name = "eventmanager_interface",
-    hdrs = [
-        "src/core/lib/iomgr/poller/eventmanager_interface.h",
-    ],
-)
-
-# Libuv-based EventManager implementation
-grpc_cc_library(
-    name = "eventmanager_libuv",
-    srcs = [
-        "src/core/lib/iomgr/poller/eventmanager_libuv.cc",
-    ],
-    hdrs = [
-        "src/core/lib/iomgr/poller/eventmanager_libuv.h",
-    ],
-    deps = [
-        "gpr_base",
-    ],
-)
index 1d8f340..2a2889d 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -97,6 +97,28 @@ config("grpc_config") {
         "include/grpc/support/sync_windows.h",
         "include/grpc/support/thd_id.h",
         "include/grpc/support/time.h",
+        "src/core/ext/upb-generated/google/api/annotations.upb.c",
+        "src/core/ext/upb-generated/google/api/annotations.upb.h",
+        "src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c",
+        "src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h",
+        "src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c",
+        "src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h",
+        "src/core/ext/upb-generated/google/api/http.upb.c",
+        "src/core/ext/upb-generated/google/api/http.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/any.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/any.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/duration.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/duration.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/empty.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/empty.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/struct.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/struct.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/timestamp.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/timestamp.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/wrappers.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/wrappers.upb.h",
+        "src/core/ext/upb-generated/google/rpc/status.upb.c",
+        "src/core/ext/upb-generated/google/rpc/status.upb.h",
         "src/core/lib/gpr/alloc.cc",
         "src/core/lib/gpr/alloc.h",
         "src/core/lib/gpr/arena.h",
@@ -147,6 +169,7 @@ config("grpc_config") {
         "src/core/lib/gprpp/arena.cc",
         "src/core/lib/gprpp/arena.h",
         "src/core/lib/gprpp/atomic.h",
+        "src/core/lib/gprpp/debug_location.h",
         "src/core/lib/gprpp/examine_stack.cc",
         "src/core/lib/gprpp/examine_stack.h",
         "src/core/lib/gprpp/fork.cc",
@@ -165,6 +188,8 @@ config("grpc_config") {
         "src/core/lib/gprpp/stat.h",
         "src/core/lib/gprpp/stat_posix.cc",
         "src/core/lib/gprpp/stat_windows.cc",
+        "src/core/lib/gprpp/status_helper.cc",
+        "src/core/lib/gprpp/status_helper.h",
         "src/core/lib/gprpp/sync.h",
         "src/core/lib/gprpp/thd.h",
         "src/core/lib/gprpp/thd_posix.cc",
@@ -184,6 +209,7 @@ config("grpc_config") {
         ":absl/synchronization:synchronization",
         ":absl/time:time",
         ":absl/types:optional",
+        ":upb",
     ]
     
     public_configs = [
@@ -199,6 +225,10 @@ config("grpc_config") {
         "include/grpc/byte_buffer_reader.h",
         "include/grpc/census.h",
         "include/grpc/compression.h",
+        "include/grpc/event_engine/channel_args.h",
+        "include/grpc/event_engine/event_engine.h",
+        "include/grpc/event_engine/port.h",
+        "include/grpc/event_engine/slice_allocator.h",
         "include/grpc/fork.h",
         "include/grpc/grpc.h",
         "include/grpc/grpc_posix.h",
@@ -300,6 +330,10 @@ config("grpc_config") {
         "src/core/ext/filters/client_channel/resolver_registry.h",
         "src/core/ext/filters/client_channel/resolver_result_parsing.cc",
         "src/core/ext/filters/client_channel/resolver_result_parsing.h",
+        "src/core/ext/filters/client_channel/retry_filter.cc",
+        "src/core/ext/filters/client_channel/retry_filter.h",
+        "src/core/ext/filters/client_channel/retry_service_config.cc",
+        "src/core/ext/filters/client_channel/retry_service_config.h",
         "src/core/ext/filters/client_channel/retry_throttle.cc",
         "src/core/ext/filters/client_channel/retry_throttle.h",
         "src/core/ext/filters/client_channel/server_address.cc",
@@ -538,28 +572,6 @@ config("grpc_config") {
         "src/core/ext/upb-generated/envoy/type/v3/range.upb.h",
         "src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.c",
         "src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.h",
-        "src/core/ext/upb-generated/google/api/annotations.upb.c",
-        "src/core/ext/upb-generated/google/api/annotations.upb.h",
-        "src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c",
-        "src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h",
-        "src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c",
-        "src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h",
-        "src/core/ext/upb-generated/google/api/http.upb.c",
-        "src/core/ext/upb-generated/google/api/http.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/any.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/any.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/duration.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/duration.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/empty.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/empty.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/struct.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/struct.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/timestamp.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/timestamp.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/wrappers.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/wrappers.upb.h",
-        "src/core/ext/upb-generated/google/rpc/status.upb.c",
-        "src/core/ext/upb-generated/google/rpc/status.upb.h",
         "src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c",
         "src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.h",
         "src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c",
@@ -799,6 +811,10 @@ config("grpc_config") {
         "src/core/ext/xds/xds_http_filters.cc",
         "src/core/ext/xds/xds_http_filters.h",
         "src/core/ext/xds/xds_server_config_fetcher.cc",
+        "src/core/lib/address_utils/parse_address.cc",
+        "src/core/lib/address_utils/parse_address.h",
+        "src/core/lib/address_utils/sockaddr_utils.cc",
+        "src/core/lib/address_utils/sockaddr_utils.h",
         "src/core/lib/avl/avl.cc",
         "src/core/lib/avl/avl.h",
         "src/core/lib/backoff/backoff.cc",
@@ -845,8 +861,9 @@ config("grpc_config") {
         "src/core/lib/debug/stats_data.h",
         "src/core/lib/debug/trace.cc",
         "src/core/lib/debug/trace.h",
+        "src/core/lib/event_engine/slice_allocator.cc",
+        "src/core/lib/event_engine/sockaddr.cc",
         "src/core/lib/gprpp/atomic.h",
-        "src/core/lib/gprpp/debug_location.h",
         "src/core/lib/gprpp/dual_ref_counted.h",
         "src/core/lib/gprpp/orphanable.h",
         "src/core/lib/gprpp/ref_counted.h",
@@ -932,10 +949,6 @@ config("grpc_config") {
         "src/core/lib/iomgr/lockfree_event.cc",
         "src/core/lib/iomgr/lockfree_event.h",
         "src/core/lib/iomgr/nameser.h",
-        "src/core/lib/iomgr/parse_address.cc",
-        "src/core/lib/iomgr/parse_address.h",
-        "src/core/lib/iomgr/poller/eventmanager_libuv.cc",
-        "src/core/lib/iomgr/poller/eventmanager_libuv.h",
         "src/core/lib/iomgr/polling_entity.cc",
         "src/core/lib/iomgr/polling_entity.h",
         "src/core/lib/iomgr/pollset.cc",
@@ -965,8 +978,6 @@ config("grpc_config") {
         "src/core/lib/iomgr/sockaddr.h",
         "src/core/lib/iomgr/sockaddr_custom.h",
         "src/core/lib/iomgr/sockaddr_posix.h",
-        "src/core/lib/iomgr/sockaddr_utils.cc",
-        "src/core/lib/iomgr/sockaddr_utils.h",
         "src/core/lib/iomgr/sockaddr_windows.h",
         "src/core/lib/iomgr/socket_factory_posix.cc",
         "src/core/lib/iomgr/socket_factory_posix.h",
@@ -1274,7 +1285,6 @@ config("grpc_config") {
         ":gpr",
         "//third_party/boringssl",
         ":address_sorting",
-        ":upb",
         "//third_party/cares",
         ":address_sorting",
     ]
index 6729fc4..103df28 100644 (file)
 cmake_minimum_required(VERSION 3.5.1)
 
 set(PACKAGE_NAME          "grpc")
-set(PACKAGE_VERSION       "1.37.1")
-set(gRPC_CORE_VERSION     "15.0.0")
-set(gRPC_CORE_SOVERSION   "15")
-set(gRPC_CPP_VERSION      "1.37.1")
-set(gRPC_CPP_SOVERSION    "1.37")
-set(gRPC_CSHARP_VERSION   "2.37.1")
-set(gRPC_CSHARP_SOVERSION "2.37")
+set(PACKAGE_VERSION       "1.38.0")
+set(gRPC_CORE_VERSION     "16.0.0")
+set(gRPC_CORE_SOVERSION   "16")
+set(gRPC_CPP_VERSION      "1.38.0")
+set(gRPC_CPP_SOVERSION    "1.38")
+set(gRPC_CSHARP_VERSION   "2.38.0")
+set(gRPC_CSHARP_SOVERSION "2.38")
 set(PACKAGE_STRING        "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME       "${PACKAGE_NAME}-${PACKAGE_VERSION}")
 set(PACKAGE_BUGREPORT     "https://github.com/grpc/grpc/issues/")
@@ -139,6 +139,7 @@ set(gRPC_ABSL_USED_TARGETS
   absl_log_severity
   absl_malloc_internal
   absl_memory
+  absl_numeric_representation
   absl_optional
   absl_raw_hash_map
   absl_raw_hash_set
@@ -160,6 +161,7 @@ set(gRPC_ABSL_USED_TARGETS
   absl_type_traits
   absl_utility
   absl_variant
+  absl_wyhash
   absl_meta
 )
 
@@ -735,7 +737,7 @@ if(gRPC_BUILD_TESTS)
   add_dependencies(buildtests_cxx alts_util_test)
   add_dependencies(buildtests_cxx async_end2end_test)
   add_dependencies(buildtests_cxx auth_property_iterator_test)
-  add_dependencies(buildtests_cxx authorization_engine_test)
+  add_dependencies(buildtests_cxx authorization_matchers_test)
   add_dependencies(buildtests_cxx aws_request_signer_test)
   add_dependencies(buildtests_cxx backoff_test)
   add_dependencies(buildtests_cxx bad_streaming_id_bad_client_test)
@@ -809,6 +811,7 @@ if(gRPC_BUILD_TESTS)
   add_dependencies(buildtests_cxx byte_buffer_test)
   add_dependencies(buildtests_cxx byte_stream_test)
   add_dependencies(buildtests_cxx cancel_ares_query_test)
+  add_dependencies(buildtests_cxx cel_authorization_engine_test)
   add_dependencies(buildtests_cxx certificate_provider_registry_test)
   add_dependencies(buildtests_cxx certificate_provider_store_test)
   add_dependencies(buildtests_cxx cfstream_test)
@@ -839,8 +842,8 @@ if(gRPC_BUILD_TESTS)
   add_dependencies(buildtests_cxx duplicate_header_bad_client_test)
   add_dependencies(buildtests_cxx end2end_test)
   add_dependencies(buildtests_cxx error_details_test)
+  add_dependencies(buildtests_cxx error_utils_test)
   add_dependencies(buildtests_cxx evaluate_args_test)
-  add_dependencies(buildtests_cxx eventmanager_libuv_test)
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
     add_dependencies(buildtests_cxx examine_stack_test)
   endif()
@@ -854,6 +857,7 @@ if(gRPC_BUILD_TESTS)
   endif()
   add_dependencies(buildtests_cxx global_config_test)
   add_dependencies(buildtests_cxx google_mesh_ca_certificate_provider_factory_test)
+  add_dependencies(buildtests_cxx grpc_authorization_engine_test)
   add_dependencies(buildtests_cxx grpc_cli)
   add_dependencies(buildtests_cxx grpc_tls_certificate_distributor_test)
   add_dependencies(buildtests_cxx grpc_tls_certificate_provider_test)
@@ -887,6 +891,7 @@ if(gRPC_BUILD_TESTS)
   add_dependencies(buildtests_cxx log_test)
   add_dependencies(buildtests_cxx matchers_test)
   add_dependencies(buildtests_cxx message_allocator_end2end_test)
+  add_dependencies(buildtests_cxx mock_stream_test)
   add_dependencies(buildtests_cxx mock_test)
   add_dependencies(buildtests_cxx nonblocking_test)
   add_dependencies(buildtests_cxx noop-benchmark)
@@ -934,6 +939,7 @@ if(gRPC_BUILD_TESTS)
   add_dependencies(buildtests_cxx stat_test)
   add_dependencies(buildtests_cxx static_metadata_test)
   add_dependencies(buildtests_cxx stats_test)
+  add_dependencies(buildtests_cxx status_helper_test)
   add_dependencies(buildtests_cxx status_metadata_test)
   add_dependencies(buildtests_cxx status_util_test)
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -1106,10 +1112,12 @@ add_library(end2end_nosec_tests
   test/core/end2end/tests/request_with_payload.cc
   test/core/end2end/tests/resource_quota_server.cc
   test/core/end2end/tests/retry.cc
+  test/core/end2end/tests/retry_cancel_during_delay.cc
   test/core/end2end/tests/retry_cancellation.cc
   test/core/end2end/tests/retry_disabled.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  test/core/end2end/tests/retry_lb_drop.cc
   test/core/end2end/tests/retry_non_retriable_status.cc
   test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   test/core/end2end/tests/retry_recv_initial_metadata.cc
@@ -1137,6 +1145,7 @@ add_library(end2end_nosec_tests
   test/core/end2end/tests/workaround_cronet_compression.cc
   test/core/end2end/tests/write_buffering.cc
   test/core/end2end/tests/write_buffering_at_end.cc
+  test/core/util/test_lb_policies.cc
 )
 
 set_target_properties(end2end_nosec_tests PROPERTIES
@@ -1237,10 +1246,12 @@ add_library(end2end_tests
   test/core/end2end/tests/request_with_payload.cc
   test/core/end2end/tests/resource_quota_server.cc
   test/core/end2end/tests/retry.cc
+  test/core/end2end/tests/retry_cancel_during_delay.cc
   test/core/end2end/tests/retry_cancellation.cc
   test/core/end2end/tests/retry_disabled.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  test/core/end2end/tests/retry_lb_drop.cc
   test/core/end2end/tests/retry_non_retriable_status.cc
   test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   test/core/end2end/tests/retry_recv_initial_metadata.cc
@@ -1268,6 +1279,7 @@ add_library(end2end_tests
   test/core/end2end/tests/workaround_cronet_compression.cc
   test/core/end2end/tests/write_buffering.cc
   test/core/end2end/tests/write_buffering_at_end.cc
+  test/core/util/test_lb_policies.cc
 )
 
 set_target_properties(end2end_tests PROPERTIES
@@ -1308,6 +1320,17 @@ target_link_libraries(end2end_tests
 endif()
 
 add_library(gpr
+  src/core/ext/upb-generated/google/api/annotations.upb.c
+  src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
+  src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
+  src/core/ext/upb-generated/google/api/http.upb.c
+  src/core/ext/upb-generated/google/protobuf/any.upb.c
+  src/core/ext/upb-generated/google/protobuf/duration.upb.c
+  src/core/ext/upb-generated/google/protobuf/empty.upb.c
+  src/core/ext/upb-generated/google/protobuf/struct.upb.c
+  src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
+  src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
+  src/core/ext/upb-generated/google/rpc/status.upb.c
   src/core/lib/gpr/alloc.cc
   src/core/lib/gpr/atm.cc
   src/core/lib/gpr/cpu_iphone.cc
@@ -1348,6 +1371,7 @@ add_library(gpr
   src/core/lib/gprpp/mpscq.cc
   src/core/lib/gprpp/stat_posix.cc
   src/core/lib/gprpp/stat_windows.cc
+  src/core/lib/gprpp/status_helper.cc
   src/core/lib/gprpp/thd_posix.cc
   src/core/lib/gprpp/thd_windows.cc
   src/core/lib/gprpp/time_util.cc
@@ -1394,6 +1418,7 @@ target_link_libraries(gpr
   absl::synchronization
   absl::time
   absl::optional
+  upb
 )
 if(_gRPC_PLATFORM_ANDROID)
   target_link_libraries(gpr
@@ -1515,6 +1540,8 @@ add_library(grpc
   src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
   src/core/ext/filters/client_channel/resolver_registry.cc
   src/core/ext/filters/client_channel/resolver_result_parsing.cc
+  src/core/ext/filters/client_channel/retry_filter.cc
+  src/core/ext/filters/client_channel/retry_service_config.cc
   src/core/ext/filters/client_channel/retry_throttle.cc
   src/core/ext/filters/client_channel/server_address.cc
   src/core/ext/filters/client_channel/service_config.cc
@@ -1639,17 +1666,6 @@ add_library(grpc
   src/core/ext/upb-generated/envoy/type/v3/percent.upb.c
   src/core/ext/upb-generated/envoy/type/v3/range.upb.c
   src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.c
-  src/core/ext/upb-generated/google/api/annotations.upb.c
-  src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
-  src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
-  src/core/ext/upb-generated/google/api/http.upb.c
-  src/core/ext/upb-generated/google/protobuf/any.upb.c
-  src/core/ext/upb-generated/google/protobuf/duration.upb.c
-  src/core/ext/upb-generated/google/protobuf/empty.upb.c
-  src/core/ext/upb-generated/google/protobuf/struct.upb.c
-  src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
-  src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
-  src/core/ext/upb-generated/google/rpc/status.upb.c
   src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c
   src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c
   src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.c
@@ -1769,6 +1785,8 @@ add_library(grpc
   src/core/ext/xds/xds_http_fault_filter.cc
   src/core/ext/xds/xds_http_filters.cc
   src/core/ext/xds/xds_server_config_fetcher.cc
+  src/core/lib/address_utils/parse_address.cc
+  src/core/lib/address_utils/sockaddr_utils.cc
   src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
@@ -1791,6 +1809,8 @@ add_library(grpc
   src/core/lib/debug/stats.cc
   src/core/lib/debug/stats_data.cc
   src/core/lib/debug/trace.cc
+  src/core/lib/event_engine/slice_allocator.cc
+  src/core/lib/event_engine/sockaddr.cc
   src/core/lib/http/format_request.cc
   src/core/lib/http/httpcli.cc
   src/core/lib/http/httpcli_security_connector.cc
@@ -1836,8 +1856,6 @@ add_library(grpc
   src/core/lib/iomgr/is_epollexclusive_available.cc
   src/core/lib/iomgr/load_file.cc
   src/core/lib/iomgr/lockfree_event.cc
-  src/core/lib/iomgr/parse_address.cc
-  src/core/lib/iomgr/poller/eventmanager_libuv.cc
   src/core/lib/iomgr/polling_entity.cc
   src/core/lib/iomgr/pollset.cc
   src/core/lib/iomgr/pollset_custom.cc
@@ -1851,7 +1869,6 @@ add_library(grpc
   src/core/lib/iomgr/resolve_address_posix.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
-  src/core/lib/iomgr/sockaddr_utils.cc
   src/core/lib/iomgr/socket_factory_posix.cc
   src/core/lib/iomgr/socket_mutator.cc
   src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -2062,7 +2079,6 @@ target_link_libraries(grpc
   gpr
   ${_gRPC_SSL_LIBRARIES}
   address_sorting
-  upb
 )
 if(_gRPC_PLATFORM_IOS OR _gRPC_PLATFORM_MAC)
   target_link_libraries(grpc "-framework CoreFoundation")
@@ -2073,6 +2089,10 @@ foreach(_hdr
   include/grpc/byte_buffer_reader.h
   include/grpc/census.h
   include/grpc/compression.h
+  include/grpc/event_engine/channel_args.h
+  include/grpc/event_engine/event_engine.h
+  include/grpc/event_engine/port.h
+  include/grpc/event_engine/slice_allocator.h
   include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
@@ -2146,7 +2166,6 @@ if(gRPC_BUILD_TESTS)
 
 add_library(grpc_test_util
   test/core/util/cmdline.cc
-  test/core/util/eval_args_mock_endpoint.cc
   test/core/util/fuzzer_util.cc
   test/core/util/grpc_profiler.cc
   test/core/util/histogram.cc
@@ -2216,7 +2235,6 @@ if(gRPC_BUILD_TESTS)
 
 add_library(grpc_test_util_unsecure
   test/core/util/cmdline.cc
-  test/core/util/eval_args_mock_endpoint.cc
   test/core/util/fuzzer_util.cc
   test/core/util/grpc_profiler.cc
   test/core/util/histogram.cc
@@ -2328,6 +2346,8 @@ add_library(grpc_unsecure
   src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
   src/core/ext/filters/client_channel/resolver_registry.cc
   src/core/ext/filters/client_channel/resolver_result_parsing.cc
+  src/core/ext/filters/client_channel/retry_filter.cc
+  src/core/ext/filters/client_channel/retry_service_config.cc
   src/core/ext/filters/client_channel/retry_throttle.cc
   src/core/ext/filters/client_channel/server_address.cc
   src/core/ext/filters/client_channel/service_config.cc
@@ -2382,21 +2402,12 @@ add_library(grpc_unsecure
   src/core/ext/transport/chttp2/transport/writing.cc
   src/core/ext/transport/inproc/inproc_plugin.cc
   src/core/ext/transport/inproc/inproc_transport.cc
-  src/core/ext/upb-generated/google/api/annotations.upb.c
-  src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
-  src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
-  src/core/ext/upb-generated/google/api/http.upb.c
-  src/core/ext/upb-generated/google/protobuf/any.upb.c
-  src/core/ext/upb-generated/google/protobuf/duration.upb.c
-  src/core/ext/upb-generated/google/protobuf/empty.upb.c
-  src/core/ext/upb-generated/google/protobuf/struct.upb.c
-  src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
-  src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
-  src/core/ext/upb-generated/google/rpc/status.upb.c
   src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.c
   src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c
   src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
   src/core/ext/upb-generated/validate/validate.upb.c
+  src/core/lib/address_utils/parse_address.cc
+  src/core/lib/address_utils/sockaddr_utils.cc
   src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
@@ -2419,6 +2430,8 @@ add_library(grpc_unsecure
   src/core/lib/debug/stats.cc
   src/core/lib/debug/stats_data.cc
   src/core/lib/debug/trace.cc
+  src/core/lib/event_engine/slice_allocator.cc
+  src/core/lib/event_engine/sockaddr.cc
   src/core/lib/http/format_request.cc
   src/core/lib/http/httpcli.cc
   src/core/lib/http/parser.cc
@@ -2463,8 +2476,6 @@ add_library(grpc_unsecure
   src/core/lib/iomgr/is_epollexclusive_available.cc
   src/core/lib/iomgr/load_file.cc
   src/core/lib/iomgr/lockfree_event.cc
-  src/core/lib/iomgr/parse_address.cc
-  src/core/lib/iomgr/poller/eventmanager_libuv.cc
   src/core/lib/iomgr/polling_entity.cc
   src/core/lib/iomgr/pollset.cc
   src/core/lib/iomgr/pollset_custom.cc
@@ -2478,7 +2489,6 @@ add_library(grpc_unsecure
   src/core/lib/iomgr/resolve_address_posix.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
-  src/core/lib/iomgr/sockaddr_utils.cc
   src/core/lib/iomgr/socket_factory_posix.cc
   src/core/lib/iomgr/socket_mutator.cc
   src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -2607,7 +2617,6 @@ target_link_libraries(grpc_unsecure
   absl::statusor
   gpr
   address_sorting
-  upb
 )
 if(_gRPC_PLATFORM_IOS OR _gRPC_PLATFORM_MAC)
   target_link_libraries(grpc_unsecure "-framework CoreFoundation")
@@ -2618,6 +2627,10 @@ foreach(_hdr
   include/grpc/byte_buffer_reader.h
   include/grpc/census.h
   include/grpc/compression.h
+  include/grpc/event_engine/channel_args.h
+  include/grpc/event_engine/event_engine.h
+  include/grpc/event_engine/port.h
+  include/grpc/event_engine/slice_allocator.h
   include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
@@ -3779,7 +3792,9 @@ endif()
 
 if(gRPC_BUILD_CODEGEN)
 
-if(gRPC_INSTALL)
+# grpcpp_channelz doesn't build with protobuf-lite, so no install required
+# See https://github.com/grpc/grpc/issues/22826
+if(gRPC_INSTALL AND NOT gRPC_USE_PROTO_LITE)
   install(TARGETS grpcpp_channelz EXPORT gRPCTargets
     RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
     LIBRARY DESTINATION ${gRPC_INSTALL_LIBDIR}
@@ -6356,7 +6371,7 @@ endif()
 if(gRPC_BUILD_TESTS)
 
 add_executable(parse_address_test
-  test/core/iomgr/parse_address_test.cc
+  test/core/address_utils/parse_address_test.cc
 )
 
 target_include_directories(parse_address_test
@@ -6384,7 +6399,7 @@ if(gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
   add_executable(parse_address_with_named_scope_id_test
-    test/core/iomgr/parse_address_with_named_scope_id_test.cc
+    test/core/address_utils/parse_address_with_named_scope_id_test.cc
   )
 
   target_include_directories(parse_address_with_named_scope_id_test
@@ -7999,16 +8014,17 @@ target_link_libraries(auth_property_iterator_test
 endif()
 if(gRPC_BUILD_TESTS)
 
-add_executable(authorization_engine_test
-  src/core/lib/security/authorization/authorization_engine.cc
+add_executable(authorization_matchers_test
   src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
   src/core/lib/security/authorization/rbac_policy.cc
-  test/core/security/authorization_engine_test.cc
+  test/core/security/authorization_matchers_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
 )
 
-target_include_directories(authorization_engine_test
+target_include_directories(authorization_matchers_test
   PRIVATE
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${CMAKE_CURRENT_SOURCE_DIR}/include
@@ -8027,10 +8043,9 @@ target_include_directories(authorization_engine_test
     ${_gRPC_PROTO_GENS_DIR}
 )
 
-target_link_libraries(authorization_engine_test
+target_link_libraries(authorization_matchers_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  absl::flat_hash_set
   grpc_test_util
 )
 
@@ -9113,6 +9128,47 @@ target_link_libraries(cancel_ares_query_test
 endif()
 if(gRPC_BUILD_TESTS)
 
+add_executable(cel_authorization_engine_test
+  src/core/lib/security/authorization/cel_authorization_engine.cc
+  src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
+  src/core/lib/security/authorization/rbac_policy.cc
+  test/core/security/cel_authorization_engine_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(cel_authorization_engine_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(cel_authorization_engine_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flat_hash_set
+  grpc_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
 add_executable(certificate_provider_registry_test
   test/core/client_channel/certificate_provider_registry_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -10222,15 +10278,13 @@ target_link_libraries(error_details_test
 endif()
 if(gRPC_BUILD_TESTS)
 
-add_executable(evaluate_args_test
-  src/core/lib/security/authorization/evaluate_args.cc
-  src/core/lib/security/authorization/rbac_policy.cc
-  test/core/security/evaluate_args_test.cc
+add_executable(error_utils_test
+  test/core/transport/error_utils_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
 )
 
-target_include_directories(evaluate_args_test
+target_include_directories(error_utils_test
   PRIVATE
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${CMAKE_CURRENT_SOURCE_DIR}/include
@@ -10249,7 +10303,7 @@ target_include_directories(evaluate_args_test
     ${_gRPC_PROTO_GENS_DIR}
 )
 
-target_link_libraries(evaluate_args_test
+target_link_libraries(error_utils_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
@@ -10259,13 +10313,17 @@ target_link_libraries(evaluate_args_test
 endif()
 if(gRPC_BUILD_TESTS)
 
-add_executable(eventmanager_libuv_test
-  test/core/iomgr/poller/eventmanager_libuv_test.cc
+add_executable(evaluate_args_test
+  src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
+  src/core/lib/security/authorization/rbac_policy.cc
+  test/core/security/evaluate_args_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
 )
 
-target_include_directories(eventmanager_libuv_test
+target_include_directories(evaluate_args_test
   PRIVATE
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${CMAKE_CURRENT_SOURCE_DIR}/include
@@ -10284,7 +10342,7 @@ target_include_directories(eventmanager_libuv_test
     ${_gRPC_PROTO_GENS_DIR}
 )
 
-target_link_libraries(eventmanager_libuv_test
+target_link_libraries(evaluate_args_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
@@ -10671,6 +10729,45 @@ target_link_libraries(google_mesh_ca_certificate_provider_factory_test
 endif()
 if(gRPC_BUILD_TESTS)
 
+add_executable(grpc_authorization_engine_test
+  src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
+  src/core/lib/security/authorization/rbac_policy.cc
+  test/core/security/grpc_authorization_engine_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(grpc_authorization_engine_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(grpc_authorization_engine_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
 add_executable(grpc_cli
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc
@@ -12063,6 +12160,54 @@ target_link_libraries(message_allocator_end2end_test
 endif()
 if(gRPC_BUILD_TESTS)
 
+add_executable(mock_stream_test
+  ${_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_messages.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h
+  test/cpp/test/mock_stream_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(mock_stream_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(mock_stream_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test
+  grpc++_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
 add_executable(mock_test
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
@@ -12653,6 +12798,8 @@ if(gRPC_BUILD_TESTS)
 
 add_executable(rbac_translator_test
   src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
   src/core/lib/security/authorization/rbac_policy.cc
   src/core/lib/security/authorization/rbac_translator.cc
   test/core/security/rbac_translator_test.cc
@@ -13483,7 +13630,7 @@ endif()
 if(gRPC_BUILD_TESTS)
 
 add_executable(sockaddr_utils_test
-  test/core/iomgr/sockaddr_utils_test.cc
+  test/core/address_utils/sockaddr_utils_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
 )
@@ -13659,6 +13806,41 @@ target_link_libraries(stats_test
 endif()
 if(gRPC_BUILD_TESTS)
 
+add_executable(status_helper_test
+  test/core/gprpp/status_helper_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(status_helper_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(status_helper_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
 add_executable(status_metadata_test
   test/core/transport/status_metadata_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -14429,7 +14611,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h
     test/core/util/cmdline.cc
-    test/core/util/eval_args_mock_endpoint.cc
     test/core/util/fuzzer_util.cc
     test/core/util/grpc_profiler.cc
     test/core/util/histogram.cc
@@ -15505,8 +15686,8 @@ generate_pkgconfig(
   "gpr"
   "gRPC platform support library"
   "${gRPC_CORE_VERSION}"
-  ""
-  "-lgpr -labsl_synchronization -labsl_time -labsl_time_zone -labsl_civil_time -labsl_graphcycles_internal -labsl_status -labsl_cord -labsl_str_format_internal -labsl_bad_optional_access -labsl_symbolize -labsl_strings -labsl_strings_internal -labsl_int128 -labsl_demangle_internal -labsl_malloc_internal -labsl_stacktrace -labsl_debugging_internal -labsl_throw_delegate -labsl_base -labsl_spinlock_wait -labsl_raw_logging_internal -labsl_log_severity"
+  "absl_base absl_memory absl_optional absl_status absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgpr"
   ""
   "gpr.pc")
 
@@ -15515,8 +15696,8 @@ generate_pkgconfig(
   "gRPC"
   "high performance general RPC framework"
   "${gRPC_CORE_VERSION}"
-  "gpr openssl"
-  "-lgrpc -laddress_sorting -lre2 -lupb -lcares -lz -labsl_statusor -labsl_status -labsl_raw_hash_set -labsl_hashtablez_sampler -labsl_synchronization -labsl_time -labsl_time_zone -labsl_civil_time -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_malloc_internal -labsl_stacktrace -labsl_debugging_internal -labsl_exponential_biased -labsl_cord -labsl_str_format_internal -labsl_hash -labsl_bad_variant_access -labsl_bad_optional_access -labsl_strings -labsl_strings_internal -labsl_base -labsl_spinlock_wait -labsl_int128 -labsl_city -labsl_throw_delegate -labsl_raw_logging_internal -labsl_log_severity"
+  "gpr openssl absl_base absl_bind_front absl_flat_hash_map absl_inlined_vector absl_memory absl_optional absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgrpc -laddress_sorting -lre2 -lupb -lcares -lz"
   ""
   "grpc.pc")
 
@@ -15525,8 +15706,8 @@ generate_pkgconfig(
   "gRPC unsecure"
   "high performance general RPC framework without SSL"
   "${gRPC_CORE_VERSION}"
-  "gpr"
-  "-lgrpc_unsecure -labsl_statusor -labsl_status -labsl_raw_hash_set -labsl_hashtablez_sampler -labsl_synchronization -labsl_time -labsl_time_zone -labsl_civil_time -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_malloc_internal -labsl_stacktrace -labsl_debugging_internal -labsl_exponential_biased -labsl_cord -labsl_str_format_internal -labsl_hash -labsl_bad_variant_access -labsl_bad_optional_access -labsl_strings -labsl_strings_internal -labsl_base -labsl_spinlock_wait -labsl_int128 -labsl_city -labsl_throw_delegate -labsl_raw_logging_internal -labsl_log_severity"
+  "gpr absl_base absl_flat_hash_map absl_inlined_vector absl_memory absl_optional absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgrpc_unsecure"
   ""
   "grpc_unsecure.pc")
 
@@ -15535,8 +15716,8 @@ generate_pkgconfig(
   "gRPC++"
   "C++ wrapper for gRPC"
   "${gRPC_CPP_VERSION}"
-  "grpc"
-  "-lgrpc++ -labsl_statusor -labsl_status -labsl_raw_hash_set -labsl_hashtablez_sampler -labsl_synchronization -labsl_time -labsl_time_zone -labsl_civil_time -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_malloc_internal -labsl_stacktrace -labsl_debugging_internal -labsl_exponential_biased -labsl_cord -labsl_str_format_internal -labsl_hash -labsl_bad_variant_access -labsl_bad_optional_access -labsl_strings -labsl_strings_internal -labsl_base -labsl_spinlock_wait -labsl_int128 -labsl_city -labsl_throw_delegate -labsl_raw_logging_internal -labsl_log_severity"
+  "grpc absl_base absl_bind_front absl_flat_hash_map absl_inlined_vector absl_memory absl_optional absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgrpc++"
   ""
   "grpc++.pc")
 
@@ -15545,7 +15726,7 @@ generate_pkgconfig(
   "gRPC++ unsecure"
   "C++ wrapper for gRPC without SSL"
   "${gRPC_CPP_VERSION}"
-  "grpc_unsecure"
-  "-lgrpc++_unsecure -labsl_statusor -labsl_status -labsl_raw_hash_set -labsl_hashtablez_sampler -labsl_synchronization -labsl_time -labsl_time_zone -labsl_civil_time -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_malloc_internal -labsl_stacktrace -labsl_debugging_internal -labsl_exponential_biased -labsl_cord -labsl_str_format_internal -labsl_hash -labsl_bad_variant_access -labsl_bad_optional_access -labsl_strings -labsl_strings_internal -labsl_base -labsl_spinlock_wait -labsl_int128 -labsl_city -labsl_throw_delegate -labsl_raw_logging_internal -labsl_log_severity"
+  "grpc_unsecure absl_base absl_flat_hash_map absl_inlined_vector absl_memory absl_optional absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgrpc++_unsecure"
   ""
   "grpc++_unsecure.pc")
index 55e65c8..cfae8f0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -454,9 +454,9 @@ E = @echo
 Q = @
 endif
 
-CORE_VERSION = 15.0.0
-CPP_VERSION = 1.37.1
-CSHARP_VERSION = 2.37.1
+CORE_VERSION = 16.0.0
+CPP_VERSION = 1.38.0
+CSHARP_VERSION = 2.38.0
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -492,7 +492,7 @@ SHARED_EXT_CORE = dll
 SHARED_EXT_CPP = dll
 SHARED_EXT_CSHARP = dll
 SHARED_PREFIX =
-SHARED_VERSION_CORE = -15
+SHARED_VERSION_CORE = -16
 SHARED_VERSION_CPP = -1
 SHARED_VERSION_CSHARP = -2
 else ifeq ($(SYSTEM),Darwin)
@@ -891,8 +891,8 @@ $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE):
 ifeq ($(SYSTEM),Darwin)
        $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBADDRESS_SORTING_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
 else
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libaddress_sorting.so.15 -o $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBADDRESS_SORTING_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
-       $(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).so.15
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libaddress_sorting.so.16 -o $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBADDRESS_SORTING_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).so.16
        $(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -905,6 +905,17 @@ endif
 
 # start of build recipe for library "gpr" (generated by makelib(lib) template function)
 LIBGPR_SRC = \
+    src/core/ext/upb-generated/google/api/annotations.upb.c \
+    src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c \
+    src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c \
+    src/core/ext/upb-generated/google/api/http.upb.c \
+    src/core/ext/upb-generated/google/protobuf/any.upb.c \
+    src/core/ext/upb-generated/google/protobuf/duration.upb.c \
+    src/core/ext/upb-generated/google/protobuf/empty.upb.c \
+    src/core/ext/upb-generated/google/protobuf/struct.upb.c \
+    src/core/ext/upb-generated/google/protobuf/timestamp.upb.c \
+    src/core/ext/upb-generated/google/protobuf/wrappers.upb.c \
+    src/core/ext/upb-generated/google/rpc/status.upb.c \
     src/core/lib/gpr/alloc.cc \
     src/core/lib/gpr/atm.cc \
     src/core/lib/gpr/cpu_iphone.cc \
@@ -945,6 +956,7 @@ LIBGPR_SRC = \
     src/core/lib/gprpp/mpscq.cc \
     src/core/lib/gprpp/stat_posix.cc \
     src/core/lib/gprpp/stat_windows.cc \
+    src/core/lib/gprpp/status_helper.cc \
     src/core/lib/gprpp/thd_posix.cc \
     src/core/lib/gprpp/thd_windows.cc \
     src/core/lib/gprpp/time_util.cc \
@@ -1009,19 +1021,19 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP)
+$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libupb.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LIBDIR)/$(CONFIG)/libupb.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP)
+$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libupb.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LIBDIR)/$(CONFIG)/libupb.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
 else
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.15 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
-       $(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.15
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.16 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LIBDIR)/$(CONFIG)/libupb.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.16
        $(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -1086,6 +1098,8 @@ LIBGRPC_SRC = \
     src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/resolver_result_parsing.cc \
+    src/core/ext/filters/client_channel/retry_filter.cc \
+    src/core/ext/filters/client_channel/retry_service_config.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/server_address.cc \
     src/core/ext/filters/client_channel/service_config.cc \
@@ -1210,17 +1224,6 @@ LIBGRPC_SRC = \
     src/core/ext/upb-generated/envoy/type/v3/percent.upb.c \
     src/core/ext/upb-generated/envoy/type/v3/range.upb.c \
     src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.c \
-    src/core/ext/upb-generated/google/api/annotations.upb.c \
-    src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c \
-    src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c \
-    src/core/ext/upb-generated/google/api/http.upb.c \
-    src/core/ext/upb-generated/google/protobuf/any.upb.c \
-    src/core/ext/upb-generated/google/protobuf/duration.upb.c \
-    src/core/ext/upb-generated/google/protobuf/empty.upb.c \
-    src/core/ext/upb-generated/google/protobuf/struct.upb.c \
-    src/core/ext/upb-generated/google/protobuf/timestamp.upb.c \
-    src/core/ext/upb-generated/google/protobuf/wrappers.upb.c \
-    src/core/ext/upb-generated/google/rpc/status.upb.c \
     src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c \
     src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c \
     src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.c \
@@ -1340,6 +1343,8 @@ LIBGRPC_SRC = \
     src/core/ext/xds/xds_http_fault_filter.cc \
     src/core/ext/xds/xds_http_filters.cc \
     src/core/ext/xds/xds_server_config_fetcher.cc \
+    src/core/lib/address_utils/parse_address.cc \
+    src/core/lib/address_utils/sockaddr_utils.cc \
     src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
@@ -1362,6 +1367,8 @@ LIBGRPC_SRC = \
     src/core/lib/debug/stats.cc \
     src/core/lib/debug/stats_data.cc \
     src/core/lib/debug/trace.cc \
+    src/core/lib/event_engine/slice_allocator.cc \
+    src/core/lib/event_engine/sockaddr.cc \
     src/core/lib/http/format_request.cc \
     src/core/lib/http/httpcli.cc \
     src/core/lib/http/httpcli_security_connector.cc \
@@ -1407,8 +1414,6 @@ LIBGRPC_SRC = \
     src/core/lib/iomgr/is_epollexclusive_available.cc \
     src/core/lib/iomgr/load_file.cc \
     src/core/lib/iomgr/lockfree_event.cc \
-    src/core/lib/iomgr/parse_address.cc \
-    src/core/lib/iomgr/poller/eventmanager_libuv.cc \
     src/core/lib/iomgr/polling_entity.cc \
     src/core/lib/iomgr/pollset.cc \
     src/core/lib/iomgr/pollset_custom.cc \
@@ -1422,7 +1427,6 @@ LIBGRPC_SRC = \
     src/core/lib/iomgr/resolve_address_posix.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
-    src/core/lib/iomgr/sockaddr_utils.cc \
     src/core/lib/iomgr/socket_factory_posix.cc \
     src/core/lib/iomgr/socket_mutator.cc \
     src/core/lib/iomgr/socket_utils_common_posix.cc \
@@ -1593,6 +1597,10 @@ PUBLIC_HEADERS_C += \
     include/grpc/byte_buffer_reader.h \
     include/grpc/census.h \
     include/grpc/compression.h \
+    include/grpc/event_engine/channel_args.h \
+    include/grpc/event_engine/event_engine.h \
+    include/grpc/event_engine/port.h \
+    include/grpc/event_engine/slice_allocator.h \
     include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
@@ -1629,19 +1637,19 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(OPENSSL_DEP)
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(OPENSSL_DEP)
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
 else
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.15 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
-       $(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.15
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.16 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.16
        $(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -1688,8 +1696,8 @@ $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE):
 ifeq ($(SYSTEM),Darwin)
        $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
 else
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.15 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
-       $(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CORE).so.15
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.16 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CORE).so.16
        $(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -1747,6 +1755,8 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/resolver_result_parsing.cc \
+    src/core/ext/filters/client_channel/retry_filter.cc \
+    src/core/ext/filters/client_channel/retry_service_config.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/server_address.cc \
     src/core/ext/filters/client_channel/service_config.cc \
@@ -1801,21 +1811,12 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/ext/transport/chttp2/transport/writing.cc \
     src/core/ext/transport/inproc/inproc_plugin.cc \
     src/core/ext/transport/inproc/inproc_transport.cc \
-    src/core/ext/upb-generated/google/api/annotations.upb.c \
-    src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c \
-    src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c \
-    src/core/ext/upb-generated/google/api/http.upb.c \
-    src/core/ext/upb-generated/google/protobuf/any.upb.c \
-    src/core/ext/upb-generated/google/protobuf/duration.upb.c \
-    src/core/ext/upb-generated/google/protobuf/empty.upb.c \
-    src/core/ext/upb-generated/google/protobuf/struct.upb.c \
-    src/core/ext/upb-generated/google/protobuf/timestamp.upb.c \
-    src/core/ext/upb-generated/google/protobuf/wrappers.upb.c \
-    src/core/ext/upb-generated/google/rpc/status.upb.c \
     src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.c \
     src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c \
     src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
     src/core/ext/upb-generated/validate/validate.upb.c \
+    src/core/lib/address_utils/parse_address.cc \
+    src/core/lib/address_utils/sockaddr_utils.cc \
     src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
@@ -1838,6 +1839,8 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/lib/debug/stats.cc \
     src/core/lib/debug/stats_data.cc \
     src/core/lib/debug/trace.cc \
+    src/core/lib/event_engine/slice_allocator.cc \
+    src/core/lib/event_engine/sockaddr.cc \
     src/core/lib/http/format_request.cc \
     src/core/lib/http/httpcli.cc \
     src/core/lib/http/parser.cc \
@@ -1882,8 +1885,6 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/lib/iomgr/is_epollexclusive_available.cc \
     src/core/lib/iomgr/load_file.cc \
     src/core/lib/iomgr/lockfree_event.cc \
-    src/core/lib/iomgr/parse_address.cc \
-    src/core/lib/iomgr/poller/eventmanager_libuv.cc \
     src/core/lib/iomgr/polling_entity.cc \
     src/core/lib/iomgr/pollset.cc \
     src/core/lib/iomgr/pollset_custom.cc \
@@ -1897,7 +1898,6 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/lib/iomgr/resolve_address_posix.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
-    src/core/lib/iomgr/sockaddr_utils.cc \
     src/core/lib/iomgr/socket_factory_posix.cc \
     src/core/lib/iomgr/socket_mutator.cc \
     src/core/lib/iomgr/socket_utils_common_posix.cc \
@@ -1988,6 +1988,10 @@ PUBLIC_HEADERS_C += \
     include/grpc/byte_buffer_reader.h \
     include/grpc/census.h \
     include/grpc/compression.h \
+    include/grpc/event_engine/channel_args.h \
+    include/grpc/event_engine/event_engine.h \
+    include/grpc/event_engine/port.h \
+    include/grpc/event_engine/slice_allocator.h \
     include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
@@ -2013,19 +2017,19 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a
+$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a
+$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(RE2_DEP) $(UPB_DEP) $(GRPC_ABSEIL_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
        $(E) "[LD]      Linking $@"
        $(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
 else
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.15 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libupb.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
-       $(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.15
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.16 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.16
        $(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -2145,7 +2149,6 @@ LIBBORINGSSL_SRC = \
     third_party/boringssl-with-bazel/src/crypto/ex_data.c \
     third_party/boringssl-with-bazel/src/crypto/fipsmodule/bcm.c \
     third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c \
-    third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c \
     third_party/boringssl-with-bazel/src/crypto/hkdf/hkdf.c \
     third_party/boringssl-with-bazel/src/crypto/hpke/hpke.c \
     third_party/boringssl-with-bazel/src/crypto/hrss/hrss.c \
@@ -2212,7 +2215,6 @@ LIBBORINGSSL_SRC = \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c \
-    third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c \
@@ -2277,6 +2279,7 @@ LIBBORINGSSL_SRC = \
     third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc \
     third_party/boringssl-with-bazel/src/ssl/dtls_method.cc \
     third_party/boringssl-with-bazel/src/ssl/dtls_record.cc \
+    third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc \
     third_party/boringssl-with-bazel/src/ssl/handoff.cc \
     third_party/boringssl-with-bazel/src/ssl/handshake.cc \
     third_party/boringssl-with-bazel/src/ssl/handshake_client.cc \
@@ -2421,8 +2424,8 @@ $(LIBDIR)/$(CONFIG)/libupb$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBUPB_OB
 ifeq ($(SYSTEM),Darwin)
        $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)upb$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libupb$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBUPB_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
 else
-       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libupb.so.15 -o $(LIBDIR)/$(CONFIG)/libupb$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBUPB_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
-       $(Q) ln -sf $(SHARED_PREFIX)upb$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libupb$(SHARED_VERSION_CORE).so.15
+       $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libupb.so.16 -o $(LIBDIR)/$(CONFIG)/libupb$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBUPB_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(RE2_MERGE_LIBS) $(UPB_MERGE_LIBS) $(GRPC_ABSEIL_MERGE_LIBS) $(LDLIBS)
+       $(Q) ln -sf $(SHARED_PREFIX)upb$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libupb$(SHARED_VERSION_CORE).so.16
        $(Q) ln -sf $(SHARED_PREFIX)upb$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libupb$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -2579,6 +2582,7 @@ LIBGRPC_ABSEIL_SRC = \
     third_party/abseil-cpp/absl/debugging/symbolize.cc \
     third_party/abseil-cpp/absl/hash/internal/city.cc \
     third_party/abseil-cpp/absl/hash/internal/hash.cc \
+    third_party/abseil-cpp/absl/hash/internal/wyhash.cc \
     third_party/abseil-cpp/absl/numeric/int128.cc \
     third_party/abseil-cpp/absl/status/status.cc \
     third_party/abseil-cpp/absl/status/status_payload_printer.cc \
@@ -2589,6 +2593,8 @@ LIBGRPC_ABSEIL_SRC = \
     third_party/abseil-cpp/absl/strings/escaping.cc \
     third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc \
     third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc \
+    third_party/abseil-cpp/absl/strings/internal/cord_internal.cc \
+    third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc \
     third_party/abseil-cpp/absl/strings/internal/escaping.cc \
     third_party/abseil-cpp/absl/strings/internal/memutil.cc \
     third_party/abseil-cpp/absl/strings/internal/ostringstream.cc \
index c97d43f..66e4a74 100644 (file)
@@ -40,28 +40,36 @@ let package = Package(
       ],
       path: ".",
       exclude: [
-        "src/core/ext/filters/load_reporting/",
         "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc",
         "src/core/ext/filters/client_channel/xds/xds_channel.cc",
+        "src/core/ext/filters/load_reporting/",
         "src/core/ext/transport/cronet/",
         "src/core/ext/upb-generated/third_party/",
+        "src/core/ext/upb-generated/src/proto/grpc/auth/",
         "src/core/ext/upbdefs-generated/envoy/config/rbac/",
         "src/core/ext/upbdefs-generated/google/api/expr/",
         "src/core/ext/upbdefs-generated/src/",
         "src/core/ext/upbdefs-generated/third_party/",
         "src/core/ext/upbdefs-generated/udpa/data/",
+        "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h",
+        "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc",
         "src/core/lib/surface/init_unsecure.cc",
-        "src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h",
-        "src/core/lib/security/authorization/mock_cel/cel_expression.h",
-        "src/core/lib/security/authorization/mock_cel/evaluator_core.h",
-        "src/core/lib/security/authorization/mock_cel/flat_expr_builder.h",
-        "src/core/lib/security/authorization/mock_cel/statusor.h",
+        "src/core/lib/security/authorization/",
         "src/core/plugin_registry/grpc_unsecure_plugin_registry.cc",
         "third_party/re2/re2/testing/",
         "third_party/re2/re2/fuzzing/",
         "third_party/re2/util/benchmark.cc",
         "third_party/re2/util/test.cc",
         "third_party/re2/util/fuzz.cc",
+        "third_party/upb/upb/sink.c",
+        "third_party/upb/upb/json_decode.c",
+        "third_party/upb/upb/json_encode.c",
+        "third_party/upb/upb/handlers.h",
+        "third_party/upb/upb/sink.h",
+        "third_party/upb/upb/json_encode.h",
+        "third_party/upb/upb/json_decode.h",
+        "third_party/upb/upb/handlers-inl.h",
+        "third_party/upb/upb/handlers.c",
         "third_party/upb/upb/bindings/",
         "third_party/upb/upb/json/",
         "third_party/upb/upb/pb/",
@@ -78,6 +86,8 @@ let package = Package(
         "third_party/re2/re2/",
         "third_party/re2/util/",
         "third_party/upb/upb/",
+        "third_party/upb/third_party/wyhash/wyhash.h",
+        "third_party/xxhash/xxhash.h",
       ],
       publicHeadersPath: "spm-core-include",
       cSettings: [
@@ -85,10 +95,15 @@ let package = Package(
         .headerSearchPath("include/"),
         .headerSearchPath("third_party/re2/"),
         .headerSearchPath("third_party/upb/"),
+        .headerSearchPath("third_party/xxhash/"),
         .headerSearchPath("src/core/ext/upb-generated/"),
         .headerSearchPath("src/core/ext/upbdefs-generated/"),
         .define("GRPC_ARES", to: "0"),
         .unsafeFlags(["-Wno-module-import-in-extern-c"]),
+      ],
+      linkerSettings: [
+        .linkedFramework("CoreFoundation"),
+        .linkedLibrary("z"),
       ]
     ),
     .target(
@@ -100,12 +115,18 @@ let package = Package(
       path: ".",
       exclude: [
         "src/cpp/client/cronet_credentials.cc",
+        "src/cpp/client/channel_test_peer.cc",
+        "src/cpp/common/alts_util.cc",
+        "src/cpp/common/alts_context.cc",
         "src/cpp/common/insecure_create_auth_context.cc",
-        "src/cpp/ext/",
+        "src/cpp/server/admin/",
         "src/cpp/server/channelz/",
+        "src/cpp/server/csds/",
         "src/cpp/server/load_reporter/",
+        "src/cpp/ext/",
         "src/cpp/util/core_stats.cc",
         "src/cpp/util/core_stats.h",
+        "src/cpp/util/error_details.cc",
       ],
       sources: [
         "src/cpp/",
index 23afc7a..85ec2d6 100644 (file)
@@ -128,12 +128,6 @@ def grpc_cc_library(
         linkstatic = linkstatic,
     )
 
-# TODO(lidiz) remove this rule once we can depend on the xDS protos internally
-def grpc_cc_library_xds(
-        *args,
-        **kwargs):
-    grpc_cc_library(*args, **kwargs)
-
 def grpc_proto_plugin(name, srcs = [], deps = []):
     native.cc_binary(
         name = name,
@@ -248,10 +242,6 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
         **args
     )
 
-# TODO(lidiz) remove this rule once we can depend on the xDS protos internally
-def grpc_cc_test_xds(*args, **kwargs):
-    grpc_cc_test(*args, **kwargs)
-
 def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False, linkopts = [], tags = [], features = []):
     copts = []
     if language.upper() == "C":
index 2aa2dd3..a463d01 100644 (file)
@@ -122,6 +122,11 @@ def grpc_deps():
     )
 
     native.bind(
+        name = "opencensus-trace-propagation",
+        actual = "@io_opencensus_cpp//opencensus/trace:grpc_trace_bin",
+    )
+
+    native.bind(
         name = "opencensus-stats",
         actual = "@io_opencensus_cpp//opencensus/stats:stats",
     )
@@ -151,11 +156,11 @@ def grpc_deps():
             name = "boringssl",
             # Use github mirror instead of https://boringssl.googlesource.com/boringssl
             # to obtain a boringssl archive with consistent sha256
-            sha256 = "269c89eb60d3f3fcd5a0a755d1e28ffa65d423bc3c0e9562e2d666f5464680d2",
-            strip_prefix = "boringssl-1a7359455220f7010def8c63f7c7e041ce6707c6",
+            sha256 = "f8616dff15cb8aad6705af53c7caf7a5f1103b6aaf59c76b55995e179d47f89c",
+            strip_prefix = "boringssl-688fc5cf5428868679d2ae1072cad81055752068",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/boringssl/archive/1a7359455220f7010def8c63f7c7e041ce6707c6.tar.gz",
-                "https://github.com/google/boringssl/archive/1a7359455220f7010def8c63f7c7e041ce6707c6.tar.gz",
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/boringssl/archive/688fc5cf5428868679d2ae1072cad81055752068.tar.gz",
+                "https://github.com/google/boringssl/archive/688fc5cf5428868679d2ae1072cad81055752068.tar.gz",
             ],
         )
 
@@ -174,11 +179,11 @@ def grpc_deps():
     if "com_google_protobuf" not in native.existing_rules():
         http_archive(
             name = "com_google_protobuf",
-            sha256 = "09709ea1a25dc2f02e281e11f559dd979139ba2a1ddb24c489ea6bea9e3ad8bc",
-            strip_prefix = "protobuf-d7e943b8d2bc444a8c770644e73d090b486f8b37",
+            sha256 = "cf63d46ef743f4c30b0e36a562caf83cabed3f10e6ca49eb476913c4655394d5",
+            strip_prefix = "protobuf-436bd7880e458532901c58f4d9d1ea23fa7edd52",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/protobuf/archive/d7e943b8d2bc444a8c770644e73d090b486f8b37.tar.gz",
-                "https://github.com/google/protobuf/archive/d7e943b8d2bc444a8c770644e73d090b486f8b37.tar.gz",
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/protobuf/archive/436bd7880e458532901c58f4d9d1ea23fa7edd52.tar.gz",
+                "https://github.com/google/protobuf/archive/436bd7880e458532901c58f4d9d1ea23fa7edd52.tar.gz",
             ],
             patches = ["@com_github_grpc_grpc//third_party:protobuf.patch"],
             patch_args = ["-p1"],
@@ -245,11 +250,11 @@ def grpc_deps():
     if "com_google_absl" not in native.existing_rules():
         http_archive(
             name = "com_google_absl",
-            sha256 = "62c27e7a633e965a2f40ff16b487c3b778eae440bab64cad83b34ef1cbe3aa93",
-            strip_prefix = "abseil-cpp-6f9d96a1f41439ac172ee2ef7ccd8edf0e5d068c",
+            sha256 = "35f22ef5cb286f09954b7cc4c85b5a3f6221c9d4df6b8c4a1e9d399555b366ee",
+            strip_prefix = "abseil-cpp-997aaf3a28308eba1b9156aa35ab7bca9688e9f6",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/abseil/abseil-cpp/archive/6f9d96a1f41439ac172ee2ef7ccd8edf0e5d068c.tar.gz",
-                "https://github.com/abseil/abseil-cpp/archive/6f9d96a1f41439ac172ee2ef7ccd8edf0e5d068c.tar.gz",
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/abseil/abseil-cpp/archive/997aaf3a28308eba1b9156aa35ab7bca9688e9f6.tar.gz",
+                "https://github.com/abseil/abseil-cpp/archive/997aaf3a28308eba1b9156aa35ab7bca9688e9f6.tar.gz",
             ],
         )
 
index 558f424..31c9d54 100644 (file)
@@ -24,6 +24,7 @@ libs:
   - test/core/end2end/fixtures/local_util.h
   - test/core/end2end/fixtures/proxy.h
   - test/core/end2end/tests/cancel_test_helpers.h
+  - test/core/util/test_lb_policies.h
   src:
   - test/core/end2end/cq_verifier.cc
   - test/core/end2end/data/client_certs.cc
@@ -83,10 +84,12 @@ libs:
   - test/core/end2end/tests/request_with_payload.cc
   - test/core/end2end/tests/resource_quota_server.cc
   - test/core/end2end/tests/retry.cc
+  - test/core/end2end/tests/retry_cancel_during_delay.cc
   - test/core/end2end/tests/retry_cancellation.cc
   - test/core/end2end/tests/retry_disabled.cc
   - test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   - test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  - test/core/end2end/tests/retry_lb_drop.cc
   - test/core/end2end/tests/retry_non_retriable_status.cc
   - test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   - test/core/end2end/tests/retry_recv_initial_metadata.cc
@@ -114,6 +117,7 @@ libs:
   - test/core/end2end/tests/workaround_cronet_compression.cc
   - test/core/end2end/tests/write_buffering.cc
   - test/core/end2end/tests/write_buffering_at_end.cc
+  - test/core/util/test_lb_policies.cc
   deps:
   - grpc_test_util
 - name: end2end_tests
@@ -128,6 +132,7 @@ libs:
   - test/core/end2end/fixtures/local_util.h
   - test/core/end2end/fixtures/proxy.h
   - test/core/end2end/tests/cancel_test_helpers.h
+  - test/core/util/test_lb_policies.h
   src:
   - test/core/end2end/cq_verifier.cc
   - test/core/end2end/data/client_certs.cc
@@ -188,10 +193,12 @@ libs:
   - test/core/end2end/tests/request_with_payload.cc
   - test/core/end2end/tests/resource_quota_server.cc
   - test/core/end2end/tests/retry.cc
+  - test/core/end2end/tests/retry_cancel_during_delay.cc
   - test/core/end2end/tests/retry_cancellation.cc
   - test/core/end2end/tests/retry_disabled.cc
   - test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   - test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  - test/core/end2end/tests/retry_lb_drop.cc
   - test/core/end2end/tests/retry_non_retriable_status.cc
   - test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   - test/core/end2end/tests/retry_recv_initial_metadata.cc
@@ -219,6 +226,7 @@ libs:
   - test/core/end2end/tests/workaround_cronet_compression.cc
   - test/core/end2end/tests/write_buffering.cc
   - test/core/end2end/tests/write_buffering_at_end.cc
+  - test/core/util/test_lb_policies.cc
   deps:
   - grpc_test_util
 - name: gpr
@@ -267,6 +275,17 @@ libs:
   - include/grpc/support/thd_id.h
   - include/grpc/support/time.h
   headers:
+  - src/core/ext/upb-generated/google/api/annotations.upb.h
+  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h
+  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h
+  - src/core/ext/upb-generated/google/api/http.upb.h
+  - src/core/ext/upb-generated/google/protobuf/any.upb.h
+  - src/core/ext/upb-generated/google/protobuf/duration.upb.h
+  - src/core/ext/upb-generated/google/protobuf/empty.upb.h
+  - src/core/ext/upb-generated/google/protobuf/struct.upb.h
+  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.h
+  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.h
+  - src/core/ext/upb-generated/google/rpc/status.upb.h
   - src/core/lib/gpr/alloc.h
   - src/core/lib/gpr/arena.h
   - src/core/lib/gpr/env.h
@@ -284,6 +303,7 @@ libs:
   - src/core/lib/gpr/useful.h
   - src/core/lib/gprpp/arena.h
   - src/core/lib/gprpp/atomic.h
+  - src/core/lib/gprpp/debug_location.h
   - src/core/lib/gprpp/examine_stack.h
   - src/core/lib/gprpp/fork.h
   - src/core/lib/gprpp/global_config.h
@@ -295,11 +315,23 @@ libs:
   - src/core/lib/gprpp/memory.h
   - src/core/lib/gprpp/mpscq.h
   - src/core/lib/gprpp/stat.h
+  - src/core/lib/gprpp/status_helper.h
   - src/core/lib/gprpp/sync.h
   - src/core/lib/gprpp/thd.h
   - src/core/lib/gprpp/time_util.h
   - src/core/lib/profiling/timers.h
   src:
+  - src/core/ext/upb-generated/google/api/annotations.upb.c
+  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
+  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
+  - src/core/ext/upb-generated/google/api/http.upb.c
+  - src/core/ext/upb-generated/google/protobuf/any.upb.c
+  - src/core/ext/upb-generated/google/protobuf/duration.upb.c
+  - src/core/ext/upb-generated/google/protobuf/empty.upb.c
+  - src/core/ext/upb-generated/google/protobuf/struct.upb.c
+  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
+  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
+  - src/core/ext/upb-generated/google/rpc/status.upb.c
   - src/core/lib/gpr/alloc.cc
   - src/core/lib/gpr/atm.cc
   - src/core/lib/gpr/cpu_iphone.cc
@@ -340,6 +372,7 @@ libs:
   - src/core/lib/gprpp/mpscq.cc
   - src/core/lib/gprpp/stat_posix.cc
   - src/core/lib/gprpp/stat_windows.cc
+  - src/core/lib/gprpp/status_helper.cc
   - src/core/lib/gprpp/thd_posix.cc
   - src/core/lib/gprpp/thd_windows.cc
   - src/core/lib/gprpp/time_util.cc
@@ -354,6 +387,7 @@ libs:
   - absl/synchronization:synchronization
   - absl/time:time
   - absl/types:optional
+  - upb
 - name: grpc
   build: all
   language: c
@@ -362,6 +396,10 @@ libs:
   - include/grpc/byte_buffer_reader.h
   - include/grpc/census.h
   - include/grpc/compression.h
+  - include/grpc/event_engine/channel_args.h
+  - include/grpc/event_engine/event_engine.h
+  - include/grpc/event_engine/port.h
+  - include/grpc/event_engine/slice_allocator.h
   - include/grpc/fork.h
   - include/grpc/grpc.h
   - include/grpc/grpc_posix.h
@@ -412,6 +450,8 @@ libs:
   - src/core/ext/filters/client_channel/resolver_factory.h
   - src/core/ext/filters/client_channel/resolver_registry.h
   - src/core/ext/filters/client_channel/resolver_result_parsing.h
+  - src/core/ext/filters/client_channel/retry_filter.h
+  - src/core/ext/filters/client_channel/retry_service_config.h
   - src/core/ext/filters/client_channel/retry_throttle.h
   - src/core/ext/filters/client_channel/server_address.h
   - src/core/ext/filters/client_channel/service_config.h
@@ -526,17 +566,6 @@ libs:
   - src/core/ext/upb-generated/envoy/type/v3/percent.upb.h
   - src/core/ext/upb-generated/envoy/type/v3/range.upb.h
   - src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.h
-  - src/core/ext/upb-generated/google/api/annotations.upb.h
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h
-  - src/core/ext/upb-generated/google/api/http.upb.h
-  - src/core/ext/upb-generated/google/protobuf/any.upb.h
-  - src/core/ext/upb-generated/google/protobuf/duration.upb.h
-  - src/core/ext/upb-generated/google/protobuf/empty.upb.h
-  - src/core/ext/upb-generated/google/protobuf/struct.upb.h
-  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.h
-  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.h
-  - src/core/ext/upb-generated/google/rpc/status.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.h
@@ -657,6 +686,8 @@ libs:
   - src/core/ext/xds/xds_client_stats.h
   - src/core/ext/xds/xds_http_fault_filter.h
   - src/core/ext/xds/xds_http_filters.h
+  - src/core/lib/address_utils/parse_address.h
+  - src/core/lib/address_utils/sockaddr_utils.h
   - src/core/lib/avl/avl.h
   - src/core/lib/backoff/backoff.h
   - src/core/lib/channel/channel_args.h
@@ -682,7 +713,6 @@ libs:
   - src/core/lib/debug/stats_data.h
   - src/core/lib/debug/trace.h
   - src/core/lib/gprpp/atomic.h
-  - src/core/lib/gprpp/debug_location.h
   - src/core/lib/gprpp/dual_ref_counted.h
   - src/core/lib/gprpp/orphanable.h
   - src/core/lib/gprpp/ref_counted.h
@@ -723,8 +753,6 @@ libs:
   - src/core/lib/iomgr/load_file.h
   - src/core/lib/iomgr/lockfree_event.h
   - src/core/lib/iomgr/nameser.h
-  - src/core/lib/iomgr/parse_address.h
-  - src/core/lib/iomgr/poller/eventmanager_libuv.h
   - src/core/lib/iomgr/polling_entity.h
   - src/core/lib/iomgr/pollset.h
   - src/core/lib/iomgr/pollset_custom.h
@@ -741,7 +769,6 @@ libs:
   - src/core/lib/iomgr/sockaddr.h
   - src/core/lib/iomgr/sockaddr_custom.h
   - src/core/lib/iomgr/sockaddr_posix.h
-  - src/core/lib/iomgr/sockaddr_utils.h
   - src/core/lib/iomgr/sockaddr_windows.h
   - src/core/lib/iomgr/socket_factory_posix.h
   - src/core/lib/iomgr/socket_mutator.h
@@ -928,6 +955,8 @@ libs:
   - src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
   - src/core/ext/filters/client_channel/resolver_registry.cc
   - src/core/ext/filters/client_channel/resolver_result_parsing.cc
+  - src/core/ext/filters/client_channel/retry_filter.cc
+  - src/core/ext/filters/client_channel/retry_service_config.cc
   - src/core/ext/filters/client_channel/retry_throttle.cc
   - src/core/ext/filters/client_channel/server_address.cc
   - src/core/ext/filters/client_channel/service_config.cc
@@ -1052,17 +1081,6 @@ libs:
   - src/core/ext/upb-generated/envoy/type/v3/percent.upb.c
   - src/core/ext/upb-generated/envoy/type/v3/range.upb.c
   - src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.c
-  - src/core/ext/upb-generated/google/api/annotations.upb.c
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
-  - src/core/ext/upb-generated/google/api/http.upb.c
-  - src/core/ext/upb-generated/google/protobuf/any.upb.c
-  - src/core/ext/upb-generated/google/protobuf/duration.upb.c
-  - src/core/ext/upb-generated/google/protobuf/empty.upb.c
-  - src/core/ext/upb-generated/google/protobuf/struct.upb.c
-  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
-  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
-  - src/core/ext/upb-generated/google/rpc/status.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.c
@@ -1182,6 +1200,8 @@ libs:
   - src/core/ext/xds/xds_http_fault_filter.cc
   - src/core/ext/xds/xds_http_filters.cc
   - src/core/ext/xds/xds_server_config_fetcher.cc
+  - src/core/lib/address_utils/parse_address.cc
+  - src/core/lib/address_utils/sockaddr_utils.cc
   - src/core/lib/avl/avl.cc
   - src/core/lib/backoff/backoff.cc
   - src/core/lib/channel/channel_args.cc
@@ -1204,6 +1224,8 @@ libs:
   - src/core/lib/debug/stats.cc
   - src/core/lib/debug/stats_data.cc
   - src/core/lib/debug/trace.cc
+  - src/core/lib/event_engine/slice_allocator.cc
+  - src/core/lib/event_engine/sockaddr.cc
   - src/core/lib/http/format_request.cc
   - src/core/lib/http/httpcli.cc
   - src/core/lib/http/httpcli_security_connector.cc
@@ -1249,8 +1271,6 @@ libs:
   - src/core/lib/iomgr/is_epollexclusive_available.cc
   - src/core/lib/iomgr/load_file.cc
   - src/core/lib/iomgr/lockfree_event.cc
-  - src/core/lib/iomgr/parse_address.cc
-  - src/core/lib/iomgr/poller/eventmanager_libuv.cc
   - src/core/lib/iomgr/polling_entity.cc
   - src/core/lib/iomgr/pollset.cc
   - src/core/lib/iomgr/pollset_custom.cc
@@ -1264,7 +1284,6 @@ libs:
   - src/core/lib/iomgr/resolve_address_posix.cc
   - src/core/lib/iomgr/resolve_address_windows.cc
   - src/core/lib/iomgr/resource_quota.cc
-  - src/core/lib/iomgr/sockaddr_utils.cc
   - src/core/lib/iomgr/socket_factory_posix.cc
   - src/core/lib/iomgr/socket_mutator.cc
   - src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -1437,7 +1456,6 @@ libs:
   - gpr
   - libssl
   - address_sorting
-  - upb
   baselib: true
   generate_plugin_registry: true
 - name: grpc_csharp_ext
@@ -1455,11 +1473,12 @@ libs:
   public_headers: []
   headers:
   - test/core/util/cmdline.h
-  - test/core/util/eval_args_mock_endpoint.h
+  - test/core/util/evaluate_args_test_util.h
   - test/core/util/fuzzer_util.h
   - test/core/util/grpc_profiler.h
   - test/core/util/histogram.h
   - test/core/util/memory_counters.h
+  - test/core/util/mock_authorization_endpoint.h
   - test/core/util/mock_endpoint.h
   - test/core/util/parse_hexstring.h
   - test/core/util/passthru_endpoint.h
@@ -1477,7 +1496,6 @@ libs:
   - test/core/util/trickle_endpoint.h
   src:
   - test/core/util/cmdline.cc
-  - test/core/util/eval_args_mock_endpoint.cc
   - test/core/util/fuzzer_util.cc
   - test/core/util/grpc_profiler.cc
   - test/core/util/histogram.cc
@@ -1510,11 +1528,12 @@ libs:
   public_headers: []
   headers:
   - test/core/util/cmdline.h
-  - test/core/util/eval_args_mock_endpoint.h
+  - test/core/util/evaluate_args_test_util.h
   - test/core/util/fuzzer_util.h
   - test/core/util/grpc_profiler.h
   - test/core/util/histogram.h
   - test/core/util/memory_counters.h
+  - test/core/util/mock_authorization_endpoint.h
   - test/core/util/mock_endpoint.h
   - test/core/util/parse_hexstring.h
   - test/core/util/passthru_endpoint.h
@@ -1531,7 +1550,6 @@ libs:
   - test/core/util/trickle_endpoint.h
   src:
   - test/core/util/cmdline.cc
-  - test/core/util/eval_args_mock_endpoint.cc
   - test/core/util/fuzzer_util.cc
   - test/core/util/grpc_profiler.cc
   - test/core/util/histogram.cc
@@ -1565,6 +1583,10 @@ libs:
   - include/grpc/byte_buffer_reader.h
   - include/grpc/census.h
   - include/grpc/compression.h
+  - include/grpc/event_engine/channel_args.h
+  - include/grpc/event_engine/event_engine.h
+  - include/grpc/event_engine/port.h
+  - include/grpc/event_engine/slice_allocator.h
   - include/grpc/fork.h
   - include/grpc/grpc.h
   - include/grpc/grpc_posix.h
@@ -1610,6 +1632,8 @@ libs:
   - src/core/ext/filters/client_channel/resolver_factory.h
   - src/core/ext/filters/client_channel/resolver_registry.h
   - src/core/ext/filters/client_channel/resolver_result_parsing.h
+  - src/core/ext/filters/client_channel/retry_filter.h
+  - src/core/ext/filters/client_channel/retry_service_config.h
   - src/core/ext/filters/client_channel/retry_throttle.h
   - src/core/ext/filters/client_channel/server_address.h
   - src/core/ext/filters/client_channel/service_config.h
@@ -1656,21 +1680,12 @@ libs:
   - src/core/ext/transport/chttp2/transport/stream_map.h
   - src/core/ext/transport/chttp2/transport/varint.h
   - src/core/ext/transport/inproc/inproc_transport.h
-  - src/core/ext/upb-generated/google/api/annotations.upb.h
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h
-  - src/core/ext/upb-generated/google/api/http.upb.h
-  - src/core/ext/upb-generated/google/protobuf/any.upb.h
-  - src/core/ext/upb-generated/google/protobuf/duration.upb.h
-  - src/core/ext/upb-generated/google/protobuf/empty.upb.h
-  - src/core/ext/upb-generated/google/protobuf/struct.upb.h
-  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.h
-  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.h
-  - src/core/ext/upb-generated/google/rpc/status.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.h
   - src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h
   - src/core/ext/upb-generated/validate/validate.upb.h
+  - src/core/lib/address_utils/parse_address.h
+  - src/core/lib/address_utils/sockaddr_utils.h
   - src/core/lib/avl/avl.h
   - src/core/lib/backoff/backoff.h
   - src/core/lib/channel/channel_args.h
@@ -1696,7 +1711,6 @@ libs:
   - src/core/lib/debug/stats_data.h
   - src/core/lib/debug/trace.h
   - src/core/lib/gprpp/atomic.h
-  - src/core/lib/gprpp/debug_location.h
   - src/core/lib/gprpp/dual_ref_counted.h
   - src/core/lib/gprpp/orphanable.h
   - src/core/lib/gprpp/ref_counted.h
@@ -1737,8 +1751,6 @@ libs:
   - src/core/lib/iomgr/load_file.h
   - src/core/lib/iomgr/lockfree_event.h
   - src/core/lib/iomgr/nameser.h
-  - src/core/lib/iomgr/parse_address.h
-  - src/core/lib/iomgr/poller/eventmanager_libuv.h
   - src/core/lib/iomgr/polling_entity.h
   - src/core/lib/iomgr/pollset.h
   - src/core/lib/iomgr/pollset_custom.h
@@ -1755,7 +1767,6 @@ libs:
   - src/core/lib/iomgr/sockaddr.h
   - src/core/lib/iomgr/sockaddr_custom.h
   - src/core/lib/iomgr/sockaddr_posix.h
-  - src/core/lib/iomgr/sockaddr_utils.h
   - src/core/lib/iomgr/sockaddr_windows.h
   - src/core/lib/iomgr/socket_factory_posix.h
   - src/core/lib/iomgr/socket_mutator.h
@@ -1863,6 +1874,8 @@ libs:
   - src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
   - src/core/ext/filters/client_channel/resolver_registry.cc
   - src/core/ext/filters/client_channel/resolver_result_parsing.cc
+  - src/core/ext/filters/client_channel/retry_filter.cc
+  - src/core/ext/filters/client_channel/retry_service_config.cc
   - src/core/ext/filters/client_channel/retry_throttle.cc
   - src/core/ext/filters/client_channel/server_address.cc
   - src/core/ext/filters/client_channel/service_config.cc
@@ -1917,21 +1930,12 @@ libs:
   - src/core/ext/transport/chttp2/transport/writing.cc
   - src/core/ext/transport/inproc/inproc_plugin.cc
   - src/core/ext/transport/inproc/inproc_transport.cc
-  - src/core/ext/upb-generated/google/api/annotations.upb.c
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
-  - src/core/ext/upb-generated/google/api/http.upb.c
-  - src/core/ext/upb-generated/google/protobuf/any.upb.c
-  - src/core/ext/upb-generated/google/protobuf/duration.upb.c
-  - src/core/ext/upb-generated/google/protobuf/empty.upb.c
-  - src/core/ext/upb-generated/google/protobuf/struct.upb.c
-  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
-  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
-  - src/core/ext/upb-generated/google/rpc/status.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c
   - src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
   - src/core/ext/upb-generated/validate/validate.upb.c
+  - src/core/lib/address_utils/parse_address.cc
+  - src/core/lib/address_utils/sockaddr_utils.cc
   - src/core/lib/avl/avl.cc
   - src/core/lib/backoff/backoff.cc
   - src/core/lib/channel/channel_args.cc
@@ -1954,6 +1958,8 @@ libs:
   - src/core/lib/debug/stats.cc
   - src/core/lib/debug/stats_data.cc
   - src/core/lib/debug/trace.cc
+  - src/core/lib/event_engine/slice_allocator.cc
+  - src/core/lib/event_engine/sockaddr.cc
   - src/core/lib/http/format_request.cc
   - src/core/lib/http/httpcli.cc
   - src/core/lib/http/parser.cc
@@ -1998,8 +2004,6 @@ libs:
   - src/core/lib/iomgr/is_epollexclusive_available.cc
   - src/core/lib/iomgr/load_file.cc
   - src/core/lib/iomgr/lockfree_event.cc
-  - src/core/lib/iomgr/parse_address.cc
-  - src/core/lib/iomgr/poller/eventmanager_libuv.cc
   - src/core/lib/iomgr/polling_entity.cc
   - src/core/lib/iomgr/pollset.cc
   - src/core/lib/iomgr/pollset_custom.cc
@@ -2013,7 +2017,6 @@ libs:
   - src/core/lib/iomgr/resolve_address_posix.cc
   - src/core/lib/iomgr/resolve_address_windows.cc
   - src/core/lib/iomgr/resource_quota.cc
-  - src/core/lib/iomgr/sockaddr_utils.cc
   - src/core/lib/iomgr/socket_factory_posix.cc
   - src/core/lib/iomgr/socket_mutator.cc
   - src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -2104,7 +2107,6 @@ libs:
   - absl/status:statusor
   - gpr
   - address_sorting
-  - upb
   baselib: true
   generate_plugin_registry: true
 - name: benchmark_helpers
@@ -3634,7 +3636,7 @@ targets:
   language: c
   headers: []
   src:
-  - test/core/iomgr/parse_address_test.cc
+  - test/core/address_utils/parse_address_test.cc
   deps:
   - grpc_test_util
 - name: parse_address_with_named_scope_id_test
@@ -3642,7 +3644,7 @@ targets:
   language: c
   headers: []
   src:
-  - test/core/iomgr/parse_address_with_named_scope_id_test.cc
+  - test/core/address_utils/parse_address_with_named_scope_id_test.cc
   deps:
   - grpc_test_util
   platforms:
@@ -4222,27 +4224,23 @@ targets:
   deps:
   - grpc++_test_util
   uses_polling: false
-- name: authorization_engine_test
+- name: authorization_matchers_test
   gtest: true
   build: test
   language: c++
   headers:
   - src/core/lib/security/authorization/authorization_engine.h
   - src/core/lib/security/authorization/evaluate_args.h
-  - src/core/lib/security/authorization/mock_cel/activation.h
-  - src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h
-  - src/core/lib/security/authorization/mock_cel/cel_expression.h
-  - src/core/lib/security/authorization/mock_cel/cel_value.h
-  - src/core/lib/security/authorization/mock_cel/evaluator_core.h
-  - src/core/lib/security/authorization/mock_cel/flat_expr_builder.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
   - src/core/lib/security/authorization/rbac_policy.h
   src:
-  - src/core/lib/security/authorization/authorization_engine.cc
   - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
   - src/core/lib/security/authorization/rbac_policy.cc
-  - test/core/security/authorization_engine_test.cc
+  - test/core/security/authorization_matchers_test.cc
   deps:
-  - absl/container:flat_hash_set
   - grpc_test_util
 - name: aws_request_signer_test
   gtest: true
@@ -4648,6 +4646,33 @@ targets:
   deps:
   - grpc++_test_config
   - grpc++_test_util
+- name: cel_authorization_engine_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - src/core/lib/security/authorization/authorization_engine.h
+  - src/core/lib/security/authorization/cel_authorization_engine.h
+  - src/core/lib/security/authorization/evaluate_args.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
+  - src/core/lib/security/authorization/mock_cel/activation.h
+  - src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h
+  - src/core/lib/security/authorization/mock_cel/cel_expression.h
+  - src/core/lib/security/authorization/mock_cel/cel_value.h
+  - src/core/lib/security/authorization/mock_cel/evaluator_core.h
+  - src/core/lib/security/authorization/mock_cel/flat_expr_builder.h
+  - src/core/lib/security/authorization/rbac_policy.h
+  src:
+  - src/core/lib/security/authorization/cel_authorization_engine.cc
+  - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
+  - src/core/lib/security/authorization/rbac_policy.cc
+  - test/core/security/cel_authorization_engine_test.cc
+  deps:
+  - absl/container:flat_hash_set
+  - grpc_test_util
 - name: certificate_provider_registry_test
   gtest: true
   build: test
@@ -5016,29 +5041,33 @@ targets:
   deps:
   - grpc++_error_details
   - grpc_test_util
+- name: error_utils_test
+  gtest: true
+  build: test
+  language: c++
+  headers: []
+  src:
+  - test/core/transport/error_utils_test.cc
+  deps:
+  - grpc_test_util
 - name: evaluate_args_test
   gtest: true
   build: test
   language: c++
   headers:
+  - src/core/lib/security/authorization/authorization_engine.h
   - src/core/lib/security/authorization/evaluate_args.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
   - src/core/lib/security/authorization/rbac_policy.h
   src:
   - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
   - src/core/lib/security/authorization/rbac_policy.cc
   - test/core/security/evaluate_args_test.cc
   deps:
   - grpc_test_util
-- name: eventmanager_libuv_test
-  gtest: true
-  build: test
-  language: c++
-  headers: []
-  src:
-  - test/core/iomgr/poller/eventmanager_libuv_test.cc
-  deps:
-  - grpc_test_util
-  uses_polling: false
 - name: examine_stack_test
   gtest: true
   build: test
@@ -5150,6 +5179,24 @@ targets:
   - test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc
   deps:
   - grpc_test_util
+- name: grpc_authorization_engine_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - src/core/lib/security/authorization/authorization_engine.h
+  - src/core/lib/security/authorization/evaluate_args.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
+  - src/core/lib/security/authorization/rbac_policy.h
+  src:
+  - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
+  - src/core/lib/security/authorization/rbac_policy.cc
+  - test/core/security/grpc_authorization_engine_test.cc
+  deps:
+  - grpc_test_util
 - name: grpc_cli
   build: test
   run: false
@@ -5630,6 +5677,19 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
+- name: mock_stream_test
+  gtest: true
+  build: test
+  language: c++
+  headers: []
+  src:
+  - src/proto/grpc/testing/echo.proto
+  - src/proto/grpc/testing/echo_messages.proto
+  - src/proto/grpc/testing/simple_messages.proto
+  - test/cpp/test/mock_stream_test.cc
+  deps:
+  - grpc++_test
+  - grpc++_test_util
 - name: mock_test
   gtest: true
   build: test
@@ -5898,11 +5958,16 @@ targets:
   build: test
   language: c++
   headers:
+  - src/core/lib/security/authorization/authorization_engine.h
   - src/core/lib/security/authorization/evaluate_args.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
   - src/core/lib/security/authorization/rbac_policy.h
   - src/core/lib/security/authorization/rbac_translator.h
   src:
   - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
   - src/core/lib/security/authorization/rbac_policy.cc
   - src/core/lib/security/authorization/rbac_translator.cc
   - test/core/security/rbac_translator_test.cc
@@ -6165,7 +6230,7 @@ targets:
   language: c++
   headers: []
   src:
-  - test/core/iomgr/sockaddr_utils_test.cc
+  - test/core/address_utils/sockaddr_utils_test.cc
   deps:
   - grpc_test_util
 - name: ssl_server_fuzzer
@@ -6225,6 +6290,16 @@ targets:
   deps:
   - grpc_test_util
   uses_polling: false
+- name: status_helper_test
+  gtest: true
+  build: test
+  language: c++
+  headers: []
+  src:
+  - test/core/gprpp/status_helper_test.cc
+  deps:
+  - grpc_test_util
+  uses_polling: false
 - name: status_metadata_test
   gtest: true
   build: test
@@ -6479,11 +6554,12 @@ targets:
   language: c++
   headers:
   - test/core/util/cmdline.h
-  - test/core/util/eval_args_mock_endpoint.h
+  - test/core/util/evaluate_args_test_util.h
   - test/core/util/fuzzer_util.h
   - test/core/util/grpc_profiler.h
   - test/core/util/histogram.h
   - test/core/util/memory_counters.h
+  - test/core/util/mock_authorization_endpoint.h
   - test/core/util/mock_endpoint.h
   - test/core/util/parse_hexstring.h
   - test/core/util/passthru_endpoint.h
@@ -6503,7 +6579,6 @@ targets:
   - src/proto/grpc/testing/echo_messages.proto
   - src/proto/grpc/testing/simple_messages.proto
   - test/core/util/cmdline.cc
-  - test/core/util/eval_args_mock_endpoint.cc
   - test/core/util/fuzzer_util.cc
   - test/core/util/grpc_profiler.cc
   - test/core/util/histogram.cc
index ee37965..98253e2 100644 (file)
@@ -13,5 +13,5 @@
 # limitations under the License.
 
 module GrpcBuildConfig
-  CORE_WINDOWS_DLL = '/tmp/libs/opt/grpc-15.dll'
+  CORE_WINDOWS_DLL = '/tmp/libs/opt/grpc-16.dll'
 end
index f1bf3ce..49a93de 100644 (file)
@@ -12,11 +12,11 @@ settings:
   '#08': Use "-preN" suffixes to identify pre-release versions
   '#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: 15.0.0
+  core_version: 16.0.0
   csharp_major_version: 2
-  g_stands_for: gilded
-  protobuf_version: 3.15.2
-  version: 1.37.1
+  g_stands_for: guadalupe_river_park_conservancy
+  protobuf_version: 3.15.8
+  version: 1.38.0
 targets:
 - name: check_epollexclusive
   build: tool
index 41df454..e4f8e4d 100644 (file)
@@ -18,6 +18,13 @@ if(re2_FOUND)
   return()
 endif()
 
+# As per https://github.com/grpc/grpc/issues/25434, idempotence is necessary
+# because CMake fails when another target with the same name already exists.
+if(TARGET re2::re2)
+  message(STATUS "Found RE2 via pkg-config already?")
+  return()
+endif()
+
 find_package(PkgConfig REQUIRED)
 # TODO(junyer): Use the IMPORTED_TARGET option whenever CMake 3.6 (or newer)
 # becomes the minimum required: that will take care of the add_library() and
index 1579483..5965358 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -92,6 +92,8 @@ if test "$PHP_GRPC" != "no"; then
     src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/resolver_result_parsing.cc \
+    src/core/ext/filters/client_channel/retry_filter.cc \
+    src/core/ext/filters/client_channel/retry_service_config.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/server_address.cc \
     src/core/ext/filters/client_channel/service_config.cc \
@@ -348,6 +350,8 @@ if test "$PHP_GRPC" != "no"; then
     src/core/ext/xds/xds_http_fault_filter.cc \
     src/core/ext/xds/xds_http_filters.cc \
     src/core/ext/xds/xds_server_config_fetcher.cc \
+    src/core/lib/address_utils/parse_address.cc \
+    src/core/lib/address_utils/sockaddr_utils.cc \
     src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
@@ -370,6 +374,8 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/debug/stats.cc \
     src/core/lib/debug/stats_data.cc \
     src/core/lib/debug/trace.cc \
+    src/core/lib/event_engine/slice_allocator.cc \
+    src/core/lib/event_engine/sockaddr.cc \
     src/core/lib/gpr/alloc.cc \
     src/core/lib/gpr/atm.cc \
     src/core/lib/gpr/cpu_iphone.cc \
@@ -410,6 +416,7 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/gprpp/mpscq.cc \
     src/core/lib/gprpp/stat_posix.cc \
     src/core/lib/gprpp/stat_windows.cc \
+    src/core/lib/gprpp/status_helper.cc \
     src/core/lib/gprpp/thd_posix.cc \
     src/core/lib/gprpp/thd_windows.cc \
     src/core/lib/gprpp/time_util.cc \
@@ -458,8 +465,6 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/iomgr/is_epollexclusive_available.cc \
     src/core/lib/iomgr/load_file.cc \
     src/core/lib/iomgr/lockfree_event.cc \
-    src/core/lib/iomgr/parse_address.cc \
-    src/core/lib/iomgr/poller/eventmanager_libuv.cc \
     src/core/lib/iomgr/polling_entity.cc \
     src/core/lib/iomgr/pollset.cc \
     src/core/lib/iomgr/pollset_custom.cc \
@@ -473,7 +478,6 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/iomgr/resolve_address_posix.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
-    src/core/lib/iomgr/sockaddr_utils.cc \
     src/core/lib/iomgr/socket_factory_posix.cc \
     src/core/lib/iomgr/socket_mutator.cc \
     src/core/lib/iomgr/socket_utils_common_posix.cc \
@@ -672,6 +676,7 @@ if test "$PHP_GRPC" != "no"; then
     third_party/abseil-cpp/absl/debugging/symbolize.cc \
     third_party/abseil-cpp/absl/hash/internal/city.cc \
     third_party/abseil-cpp/absl/hash/internal/hash.cc \
+    third_party/abseil-cpp/absl/hash/internal/wyhash.cc \
     third_party/abseil-cpp/absl/numeric/int128.cc \
     third_party/abseil-cpp/absl/status/status.cc \
     third_party/abseil-cpp/absl/status/status_payload_printer.cc \
@@ -682,6 +687,8 @@ if test "$PHP_GRPC" != "no"; then
     third_party/abseil-cpp/absl/strings/escaping.cc \
     third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc \
     third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc \
+    third_party/abseil-cpp/absl/strings/internal/cord_internal.cc \
+    third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc \
     third_party/abseil-cpp/absl/strings/internal/escaping.cc \
     third_party/abseil-cpp/absl/strings/internal/memutil.cc \
     third_party/abseil-cpp/absl/strings/internal/ostringstream.cc \
@@ -834,7 +841,6 @@ if test "$PHP_GRPC" != "no"; then
     third_party/boringssl-with-bazel/src/crypto/ex_data.c \
     third_party/boringssl-with-bazel/src/crypto/fipsmodule/bcm.c \
     third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c \
-    third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c \
     third_party/boringssl-with-bazel/src/crypto/hkdf/hkdf.c \
     third_party/boringssl-with-bazel/src/crypto/hpke/hpke.c \
     third_party/boringssl-with-bazel/src/crypto/hrss/hrss.c \
@@ -901,7 +907,6 @@ if test "$PHP_GRPC" != "no"; then
     third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c \
-    third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c \
@@ -966,6 +971,7 @@ if test "$PHP_GRPC" != "no"; then
     third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc \
     third_party/boringssl-with-bazel/src/ssl/dtls_method.cc \
     third_party/boringssl-with-bazel/src/ssl/dtls_record.cc \
+    third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc \
     third_party/boringssl-with-bazel/src/ssl/handoff.cc \
     third_party/boringssl-with-bazel/src/ssl/handshake.cc \
     third_party/boringssl-with-bazel/src/ssl/handshake_client.cc \
@@ -1148,17 +1154,18 @@ if test "$PHP_GRPC" != "no"; then
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/validate)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/xds/core/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/xds)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/address_utils)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/avl)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/backoff)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/channel)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/event_engine)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gpr)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gprpp)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/http)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr/executor)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr/poller)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/json)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/matchers)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/profiling)
index ee6a8d5..1e65f5b 100644 (file)
@@ -58,6 +58,8 @@ if (PHP_GRPC != "no") {
     "src\\core\\ext\\filters\\client_channel\\resolver\\xds\\xds_resolver.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver_registry.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver_result_parsing.cc " +
+    "src\\core\\ext\\filters\\client_channel\\retry_filter.cc " +
+    "src\\core\\ext\\filters\\client_channel\\retry_service_config.cc " +
     "src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " +
     "src\\core\\ext\\filters\\client_channel\\server_address.cc " +
     "src\\core\\ext\\filters\\client_channel\\service_config.cc " +
@@ -314,6 +316,8 @@ if (PHP_GRPC != "no") {
     "src\\core\\ext\\xds\\xds_http_fault_filter.cc " +
     "src\\core\\ext\\xds\\xds_http_filters.cc " +
     "src\\core\\ext\\xds\\xds_server_config_fetcher.cc " +
+    "src\\core\\lib\\address_utils\\parse_address.cc " +
+    "src\\core\\lib\\address_utils\\sockaddr_utils.cc " +
     "src\\core\\lib\\avl\\avl.cc " +
     "src\\core\\lib\\backoff\\backoff.cc " +
     "src\\core\\lib\\channel\\channel_args.cc " +
@@ -336,6 +340,8 @@ if (PHP_GRPC != "no") {
     "src\\core\\lib\\debug\\stats.cc " +
     "src\\core\\lib\\debug\\stats_data.cc " +
     "src\\core\\lib\\debug\\trace.cc " +
+    "src\\core\\lib\\event_engine\\slice_allocator.cc " +
+    "src\\core\\lib\\event_engine\\sockaddr.cc " +
     "src\\core\\lib\\gpr\\alloc.cc " +
     "src\\core\\lib\\gpr\\atm.cc " +
     "src\\core\\lib\\gpr\\cpu_iphone.cc " +
@@ -376,6 +382,7 @@ if (PHP_GRPC != "no") {
     "src\\core\\lib\\gprpp\\mpscq.cc " +
     "src\\core\\lib\\gprpp\\stat_posix.cc " +
     "src\\core\\lib\\gprpp\\stat_windows.cc " +
+    "src\\core\\lib\\gprpp\\status_helper.cc " +
     "src\\core\\lib\\gprpp\\thd_posix.cc " +
     "src\\core\\lib\\gprpp\\thd_windows.cc " +
     "src\\core\\lib\\gprpp\\time_util.cc " +
@@ -424,8 +431,6 @@ if (PHP_GRPC != "no") {
     "src\\core\\lib\\iomgr\\is_epollexclusive_available.cc " +
     "src\\core\\lib\\iomgr\\load_file.cc " +
     "src\\core\\lib\\iomgr\\lockfree_event.cc " +
-    "src\\core\\lib\\iomgr\\parse_address.cc " +
-    "src\\core\\lib\\iomgr\\poller\\eventmanager_libuv.cc " +
     "src\\core\\lib\\iomgr\\polling_entity.cc " +
     "src\\core\\lib\\iomgr\\pollset.cc " +
     "src\\core\\lib\\iomgr\\pollset_custom.cc " +
@@ -439,7 +444,6 @@ if (PHP_GRPC != "no") {
     "src\\core\\lib\\iomgr\\resolve_address_posix.cc " +
     "src\\core\\lib\\iomgr\\resolve_address_windows.cc " +
     "src\\core\\lib\\iomgr\\resource_quota.cc " +
-    "src\\core\\lib\\iomgr\\sockaddr_utils.cc " +
     "src\\core\\lib\\iomgr\\socket_factory_posix.cc " +
     "src\\core\\lib\\iomgr\\socket_mutator.cc " +
     "src\\core\\lib\\iomgr\\socket_utils_common_posix.cc " +
@@ -638,6 +642,7 @@ if (PHP_GRPC != "no") {
     "third_party\\abseil-cpp\\absl\\debugging\\symbolize.cc " +
     "third_party\\abseil-cpp\\absl\\hash\\internal\\city.cc " +
     "third_party\\abseil-cpp\\absl\\hash\\internal\\hash.cc " +
+    "third_party\\abseil-cpp\\absl\\hash\\internal\\wyhash.cc " +
     "third_party\\abseil-cpp\\absl\\numeric\\int128.cc " +
     "third_party\\abseil-cpp\\absl\\status\\status.cc " +
     "third_party\\abseil-cpp\\absl\\status\\status_payload_printer.cc " +
@@ -648,6 +653,8 @@ if (PHP_GRPC != "no") {
     "third_party\\abseil-cpp\\absl\\strings\\escaping.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\charconv_bigint.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\charconv_parse.cc " +
+    "third_party\\abseil-cpp\\absl\\strings\\internal\\cord_internal.cc " +
+    "third_party\\abseil-cpp\\absl\\strings\\internal\\cord_rep_ring.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\escaping.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\memutil.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\ostringstream.cc " +
@@ -800,7 +807,6 @@ if (PHP_GRPC != "no") {
     "third_party\\boringssl-with-bazel\\src\\crypto\\ex_data.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\fipsmodule\\bcm.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\fipsmodule\\fips_shared_support.c " +
-    "third_party\\boringssl-with-bazel\\src\\crypto\\fipsmodule\\is_fips.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\hkdf\\hkdf.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\hpke\\hpke.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\hrss\\hrss.c " +
@@ -867,7 +873,6 @@ if (PHP_GRPC != "no") {
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_ext.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_lu.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_obj.c " +
-    "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_r2x.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_req.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_set.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_trs.c " +
@@ -932,6 +937,7 @@ if (PHP_GRPC != "no") {
     "third_party\\boringssl-with-bazel\\src\\ssl\\d1_srtp.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\dtls_method.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\dtls_record.cc " +
+    "third_party\\boringssl-with-bazel\\src\\ssl\\encrypted_client_hello.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\handoff.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\handshake.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\handshake_client.cc " +
@@ -1249,17 +1255,18 @@ if (PHP_GRPC != "no") {
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\xds\\core\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\xds");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\address_utils");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\avl");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\backoff");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\channel");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\compression");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\debug");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\event_engine");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gpr");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gprpp");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\http");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr\\executor");
-  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr\\poller");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\json");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\matchers");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\profiling");
index 1ee9360..c3f9169 100644 (file)
@@ -137,5 +137,5 @@ Versioning
 ---
 
 Browser-specific features
-
-* For features that are unique to browser or HTML clients, check the [spec doc](https://github.com/grpc/grpc-web/blob/master/BROWSER-FEATURES.md) published in the grpc/grpc-web repo.
+                                                                                
+* For features that are unique to browser or HTML clients, check the [spec doc](https://github.com/grpc/grpc-web/blob/master/doc/browser-features.md) published in the grpc/grpc-web repo.
index 105a648..dc0e0ea 100644 (file)
@@ -56,8 +56,8 @@ For example, in the following code block, error1 and error2 are owned by the
 current function.
 
 ```C
-grpc_error* error1 = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
-grpc_error* error2 = some_operation_that_might_fail(...);
+grpc_error_handle error1 = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
+grpc_error_handle error2 = some_operation_that_might_fail(...);
 ```
 
 The current function would have to explicitly call GRPC_ERROR_UNREF on the
@@ -71,24 +71,24 @@ errors, or pass them along to a function that would take over the ownership.
 A `grpc_closure` callback function is any function that has the signature:
 
 ```C
-void (*cb)(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+void (*cb)(void *arg, grpc_error_handle error);
 ```
 
 This means that the error ownership is NOT transferred when a functions calls:
 
 ```C
-c->cb(exec_ctx, c->cb_arg, err);
+c->cb(c->cb_arg, err);
 ```
 
 The caller is still responsible for unref-ing the error.
 
-However, the above line is currently being phased out! It is safer to invoke
-callbacks with `GRPC_CLOSURE_RUN` and `GRPC_CLOSURE_SCHED`. These functions are
-not callbacks, so they will take ownership of the error passed to them.
+Note that you'll likely never need to run `c->cb(...)` yourself; the idiomatic
+way to execute callbacks is via the `Closure::Run` method, which takes ownership
+of the error variable.
 
 ```C
-grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
-GRPC_CLOSURE_RUN(exec_ctx, cb, error);
+grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
+grpc_core::Closure::Run(DEBUG_LOCATION, c->cb, error);
 // current function no longer has ownership of the error
 ```
 
@@ -96,8 +96,8 @@ If you schedule or run a closure, but still need ownership of the error, then
 you must explicitly take a reference.
 
 ```C
-grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
-GRPC_CLOSURE_RUN(exec_ctx, cb, GRPC_ERROR_REF(error));
+grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
+grpc_core::Closure::Run(DEBUG_LOCATION, c->cb, GRPC_ERROR_REF(error));
 // do some other things with the error
 GRPC_ERROR_UNREF(error);
 ```
@@ -109,7 +109,7 @@ would take ownership of the error, without explicitly taking ownership yourself.
 For example:
 
 ```C
-void on_some_action(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+void on_some_action(void *arg, grpc_error_handle error) {
   // this would cause a crash, because some_function will unref the error,
   // and the caller of this callback will also unref it.
   some_function(error);
@@ -128,7 +128,7 @@ void on_some_action(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
 Take the following example:
 
 ```C
-grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
+grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
 // do some things
 some_function(error);
 // can't use error anymore! might be gone.
@@ -142,7 +142,7 @@ if would have to take on a reference to it. This is a common pattern seen.
 
 ```C
 void func() {
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error");
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error");
   some_function(GRPC_ERROR_REF(error));
   // do things
   some_other_function(GRPC_ERROR_REF(error));
index f7de7ad..7a71931 100644 (file)
@@ -37,3 +37,4 @@
 - 1.35 'g' stands for ['gecko'](https://github.com/grpc/grpc/tree/v1.35.x)
 - 1.36 'g' stands for ['gummybear'](https://github.com/grpc/grpc/tree/v1.36.x)
 - 1.37 'g' stands for ['gilded'](https://github.com/grpc/grpc/tree/v1.37.x)
+- 1.38 'g' stands for ['guadalupe_river_park_conservancy'](https://github.com/grpc/grpc/tree/v1.38.x)
index 1a72c8d..8c3332a 100644 (file)
@@ -41,6 +41,10 @@ Features | gRFCs  | [C++, Python,<br> Ruby, PHP](https://github.com/grpc/grpc/re
 ---------|--------|--------------|------|------|------
 **xDS Infrastructure in gRPC client channel:**<ul><li>LDS->RDS->CDS->EDS flow</li><li>ADS stream</li></ul> | [A27](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) | v1.30.0  | v1.30.0 | v1.30.0 | v1.2.0 |
 **Load Balancing:**<ul><li>[Virtual host](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-virtualhost) domains matching</li><li>Only default path ("" or "/") matching</li><li>Priority-based weighted round-robin locality picking</li><li>Round-robin endpoint picking within locality</li><li>[Cluster](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#envoy-api-msg-route-routeaction) route action</li><li>Client-side Load reporting via [LRS](https://github.com/envoyproxy/data-plane-api/blob/master/envoy/service/load_stats/v2/lrs.proto)</li></ul> | [A27](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) | v1.30.0  | v1.30.0 | v1.30.0 | v1.2.0 |
-Request matching based on:<ul><li>[Path](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-routematch) (prefix, full path and safe regex)</li><ul><li>[case_sensitive](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-routematch) must be true else config is NACKed</li></ul><li>[Headers](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-headermatcher)</li></ul>Request routing to multiple clusters based on [weights](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-weightedcluster) | [A28](https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md) | v1.31.0 | v1.31.0 | v1.31.0 | |
-Case insensitive prefix/full path matching:<ul><li>[case_sensitive](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-routematch) can be true or false</li></ul> | | v1.34.0 | v1.34.0 | v1.34.0 | |
+Request matching based on:<ul><li>[Path](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-routematch) (prefix, full path and safe regex)</li><ul><li>[case_sensitive](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-routematch) must be true else config is NACKed</li></ul><li>[Headers](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-headermatcher)</li></ul>Request routing to multiple clusters based on [weights](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-weightedcluster) | [A28](https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md) | v1.31.0 | v1.31.0 | v1.31.0 | v1.3.0 |
+Case insensitive prefix/full path matching:<ul><li>[case_sensitive](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-routematch) can be true or false</li></ul> | | v1.34.0 | v1.34.0 | v1.34.0 | v1.3.0 |
 Support for [xDS v3 APIs](https://www.envoyproxy.io/docs/envoy/latest/api-v3/api) | [A30](https://github.com/grpc/proposal/blob/master/A30-xds-v3.md) | v1.36.0 | v1.36.0 | v1.36.0 | |
+[Maximum Stream Duration](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#config-route-v3-routeaction-maxstreamduration):<ul><li>Only max_stream_duration is supported.</li></ul> | [A31](https://github.com/grpc/proposal/blob/master/A31-xds-timeout-support-and-config-selector.md) | v1.37.1  | v1.37.0 | v1.37.0 | |
+[Circuit Breaking](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/circuit_breaker.proto):<ul><li>Only max_requests is supported.</li></ul> | [A32](https://github.com/grpc/proposal/blob/master/A32-xds-circuit-breaking.md) | v1.37.1 (N/A for PHP) | v1.37.0 | v1.37.0 | |
+[Fault Injection](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/fault/v3/fault.proto):<br> Only the following fields are supported:<ul><li>delay</li><li>abort</li><li>max_active_faults</li><li>headers</li></ul> | [A33](https://github.com/grpc/proposal/blob/master/A33-Fault-Injection.md) | v1.37.1  | v1.37.0 | v1.37.0 | |
+[Client Status Discovery Service](https://github.com/envoyproxy/envoy/blob/main/api/envoy/service/status/v3/csds.proto) | [A40](https://github.com/grpc/proposal/blob/master/A40-csds-support.md) | v1.37.1 (Only C++)  | v1.37.0 | v1.37.0 | |
index b598a28..f773bd8 100644 (file)
@@ -4,25 +4,27 @@ The keepalive ping is a way to check if a channel is currently working by sendin
 
 This guide documents the knobs within gRPC core to control the current behavior of the keepalive ping.
 
-The keepalive ping is controlled by two important channel arguments -
+The keepalive ping in core is controlled by the following channel arguments -
 
 * **GRPC_ARG_KEEPALIVE_TIME_MS**
   * This channel argument controls the period (in milliseconds) after which a keepalive ping is sent on the transport.
 * **GRPC_ARG_KEEPALIVE_TIMEOUT_MS**
   * This channel argument controls the amount of time (in milliseconds) the sender of the keepalive ping waits for an acknowledgement. If it does not receive an acknowledgment within this time, it will close the connection.
-
-The above two channel arguments should be sufficient for most users, but the following arguments can also be useful in certain use cases.
-
+* **GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA**
+  * This channel argument controls the maximum number of pings that can be sent when there is no data/header frame to be sent. gRPC Core will not continue sending pings if we run over the limit. Setting it to 0 allows sending pings without such a restriction. (Note that this is an unfortunate setting that does not agree with [A8-client-side-keepalive.md](https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md). There should ideally be no such restriction on the keepalive ping and we plan to deprecate it in the future.)
 * **GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS**
   * This channel argument if set to 1 (0 : false; 1 : true), allows keepalive pings to be sent even if there are no calls in flight.
-* **GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA**
-  * This channel argument controls the maximum number of pings that can be sent when there is no data/header frame to be sent. GRPC Core will not continue sending pings if we run over the limit. Setting it to 0 allows sending pings without such a restriction.
+
+On the server-side, the following additional channel arguments need to be configured -
+
 * **GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS**
   * If there are no data/header frames being sent on the transport, this channel argument on the server side controls the minimum time (in milliseconds) that gRPC Core would expect between receiving successive pings. If the time between successive pings is less that than this time, then the ping will be considered a bad ping from the peer. Such a ping counts as a â€˜ping strike’.
 On the client side, this does not have any effect.
 * **GRPC_ARG_HTTP2_MAX_PING_STRIKES**
   * This arg controls the maximum number of bad pings that the server will tolerate before sending an HTTP2 GOAWAY frame and closing the transport. Setting it to 0 allows the server to accept any number of bad pings.
 
+**IMPORTANT NOTE** - For keepalive to work properly and as intended, all of the above channel arguments should be configured appropriately. The client-side keepalive settings should also be in agreement with the server-side settings. If a client sends pings more often than the server is willing to accept, the connection will be terminated with a GOAWAY frame with "too_many_pings" as the debug data. 
+
 ### Defaults Values
 
 Channel Argument| Client|Server
@@ -46,3 +48,7 @@ GRPC_ARG_HTTP2_MAX_PING_STRIKES|N/A|2
   * A server sends a GOAWAY with `ENHANCE_YOUR_CALM` if the client sends too many misbehaving pings as described in [A8-client-side-keepalive.md](https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md). Some scenarios where this can happen are -
     * if a server has `GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS` set to false while the client has set this to true resulting in keepalive pings being sent even when there is no call in flight.
     * if the client's `GRPC_ARG_KEEPALIVE_TIME_MS` setting is lower than the server's `GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS`.
+* Why is my client not sending keepalive pings even after configuring `GRPC_ARG_KEEPALIVE_TIME_MS` and `GRPC_ARG_KEEPALIVE_TIMEOUT_MS`?
+  * This can happen in the following cases -
+    * There are no RPCs in flight and `GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS` has not been set to 1(defaults to 0). If we require the endpoint to be able to send pings even when there are no ongoing RPCs, `GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS` should be set to 1 as documented above.
+    * When there isn't any data/header being sent on the transport, gRPC clients restrict the number of pings to 2 by default. Setting `GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA` to 0 will remove this limit.
diff --git a/doc/python/sphinx/grpc_admin.rst b/doc/python/sphinx/grpc_admin.rst
new file mode 100644 (file)
index 0000000..40ae9f0
--- /dev/null
@@ -0,0 +1,14 @@
+gRPC Admin
+==========
+
+What is gRPC Admin?
+---------------------------------------------
+
+It's a convenient API to improve the usability of creating a gRPC server with admin services to expose states in the gRPC library.
+
+Design Document `gRPC Admin Interface <https://github.com/grpc/proposal/blob/master/A38-admin-interface-api.md>`_
+
+Module Contents
+---------------
+
+.. automodule:: grpc_admin
index b0ba347..39584c3 100644 (file)
@@ -76,6 +76,11 @@ gRPC Exceptions
 .. autoexception:: InternalError
 .. autoexception:: AioRpcError
 
+gRPC Metadata
+^^^^^^^^^^^^^
+
+.. autoclass:: Metadata
+
 
 Shared Context
 ^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/python/sphinx/grpc_csds.rst b/doc/python/sphinx/grpc_csds.rst
new file mode 100644 (file)
index 0000000..e1550c7
--- /dev/null
@@ -0,0 +1,14 @@
+gRPC CSDS
+=========
+
+What is gRPC CSDS?
+---------------------------------------------
+
+In short, it's a xDS configuration dump protocol.
+
+Design Document `gRPC CSDS <https://github.com/grpc/proposal/blob/master/A40-csds-support.md>`_
+
+Module Contents
+---------------
+
+.. automodule:: grpc_csds
index c033542..2bdd60b 100644 (file)
@@ -11,7 +11,9 @@ API Reference
 
    grpc
    grpc_asyncio
+   grpc_admin
    grpc_channelz
+   grpc_csds
    grpc_health_checking
    grpc_reflection
    grpc_status
index 928f27b..57f5e19 100644 (file)
@@ -8,12 +8,38 @@ parameters to be automatically used by all clients of their service.
 
 # Format
 
-The format of the service config is defined by the
+The fields of the service config are defined by the
 [`grpc.service_config.ServiceConfig` protocol buffer
 message](https://github.com/grpc/grpc-proto/blob/master/grpc/service_config/service_config.proto).
 Note that new fields may be added in the future as new functionality is
 introduced.
 
+Internally, gRPC uses the service config in JSON form.  The JSON
+representation is the result of converting the protobuf form into JSON
+using the normal [protobuf to JSON translation
+rules](https://developers.google.com/protocol-buffers/docs/proto3#json).
+In particular, this means:
+- Field names are converted from `snake_case` to `camelCase`.
+- Field values are converted as per the documented translation rules:
+  - Strings, 32-bit integers, and bools are converted into the
+    corresponding JSON types.
+  - 64-bit integers are converted into strings (e.g., `"251"`).
+  - The value of a repeated field will be represented as a JSON array.
+  - The value of a `google.protobuf.Duration` will be represented as a
+    string containing a decimal number of seconds (e.g., `"1.000340012s"`).
+
+For more details, see the protobuf docs linked above.
+
+Note that the JSON representation has one advantage over the protobuf
+representation, which is that it is possible to encode configurations
+for [LB policies](load-balancing.md) that are not known to gRPC.  In
+protobuf form, the `loadBalancingConfig` field contains a `oneof`
+supporting only the built-in LB policies.  However, in JSON form, the
+field inside the `oneof` is encoded as a string that indicates the LB
+policy name.  In JSON form, that string can be any arbitrary value, not
+just one of the supported policies inside of the `oneof`, so third-party
+policies can be selected.
+
 # Architecture
 
 A service config is associated with a server name.  The [name
@@ -23,11 +49,10 @@ name, will return both the resolved addresses and the service config.
 The name resolver returns the service config to the gRPC client in JSON form.
 Individual resolver implementations determine where and in what format the
 service config is stored.  If the resolver implemention obtains the
-service config in protobuf form, it must convert it to JSON using the
-normal [protobuf to JSON translation
-rules](https://developers.google.com/protocol-buffers/docs/proto3#json).
+service config in protobuf form, it must convert it to JSON.
 Alternatively, a resolver implementation may obtain the service config
-already in JSON form, in which case it may return it directly.
+already in JSON form, in which case it may return it directly.  Or it
+may construct the JSON dynamically from some other source data.
 
 For details of how the DNS resolver plugin supports service configs, see
 [gRFC A2: Service Config via
@@ -71,7 +96,7 @@ Here is the same example service config in JSON form:
         { "service": "foo", "method": "bar" },
         { "service": "baz" }
       ],
-      "timeout": "1.0000000001s"
+      "timeout": "1.000000001s"
     }
   ]
 }
index 83771d2..6a82a7b 100644 (file)
@@ -69,6 +69,9 @@ message ClientConfigureRequest {
   repeated RpcType types = 1;
   // The collection of custom metadata to be attached to RPCs sent by the client.
   repeated Metadata metadata = 2;
+  // The deadline to use, in seconds, for all RPCs.  If unset or zero, the
+  // client will use the default from the command-line.
+  int32 timeout_sec = 3;
 }
 
 message ClientConfigureResponse {}
@@ -81,7 +84,7 @@ service XdsUpdateClientConfigureService {
 
 The test client changes its behavior right after receiving the
 `ClientConfigureRequest`. Currently it only supports configuring the type(s) 
-of RPCs sent by the test client and metadata attached to each type of RPCs.
+of RPCs sent by the test client, metadata attached to each type of RPCs, and the timeout.
 
 ## Test Driver
 
@@ -105,21 +108,42 @@ message LoadBalancerStatsRequest {
 }
 
 message LoadBalancerStatsResponse {
+  message RpcsByPeer {
+    // The number of completed RPCs for each peer.
+    map<string, int32> rpcs_by_peer = 1;
+  }
   // The number of completed RPCs for each peer.
   map<string, int32> rpcs_by_peer = 1;
   // The number of RPCs that failed to record a remote peer.
   int32 num_failures = 2;
+  map<string, RpcsByPeer> rpcs_by_method = 3;
 }
 
 message LoadBalancerAccumulatedStatsRequest {}
 
 message LoadBalancerAccumulatedStatsResponse {
   // The total number of RPCs have ever issued for each type.
-  map<string, int32> num_rpcs_started_by_method = 1;
+  // Deprecated: use stats_per_method.rpcs_started instead.
+  map<string, int32> num_rpcs_started_by_method = 1 [deprecated = true];
   // The total number of RPCs have ever completed successfully for each type.
-  map<string, int32> num_rpcs_succeeded_by_method = 2;
+  // Deprecated: use stats_per_method.result instead.
+  map<string, int32> num_rpcs_succeeded_by_method = 2 [deprecated = true];
   // The total number of RPCs have ever failed for each type.
-  map<string, int32> num_rpcs_failed_by_method = 3;
+  // Deprecated: use stats_per_method.result instead.
+  map<string, int32> num_rpcs_failed_by_method = 3 [deprecated = true];
+
+  message MethodStats {
+    // The number of RPCs that were started for this method.
+    int32 rpcs_started = 1;
+
+    // The number of RPCs that completed with each status for this method.  The
+    // key is the integral value of a google.rpc.Code; the value is the count.
+    map<int32, int32> result = 2;
+  }
+
+  // Per-method RPC statistics.  The key is the RpcType in string form; e.g.
+  // 'EMPTY_CALL' or 'UNARY_CALL'
+  map<string, MethodStats> stats_per_method = 4;
 }
 
 service LoadBalancerStatsService {
index ac13e52..747f0b2 100644 (file)
@@ -45,6 +45,18 @@ cc_binary(
 )
 
 cc_binary(
+    name = "xds_greeter_client",
+    srcs = ["xds_greeter_client.cc"],
+    defines = ["BAZEL_BUILD"],
+    deps = [
+        "//:grpc++",
+        "//examples/protos:helloworld_cc_grpc",
+        "@com_google_absl//absl/flags:flag",
+        "@com_google_absl//absl/flags:parse",
+    ],
+)
+
+cc_binary(
     name = "greeter_server",
     srcs = ["greeter_server.cc"],
     defines = ["BAZEL_BUILD"],
@@ -64,3 +76,17 @@ cc_binary(
         "//examples/protos:helloworld_cc_grpc",
     ],
 )
+
+cc_binary(
+    name = "xds_greeter_server",
+    srcs = ["xds_greeter_server.cc"],
+    defines = ["BAZEL_BUILD"],
+    deps = [
+        "//:grpc++",
+        "//:grpc++_reflection",
+        "//:grpcpp_admin",
+        "//examples/protos:helloworld_cc_grpc",
+        "@com_google_absl//absl/flags:flag",
+        "@com_google_absl//absl/flags:parse",
+    ],
+)
diff --git a/examples/cpp/helloworld/xds_greeter_client.cc b/examples/cpp/helloworld/xds_greeter_client.cc
new file mode 100644 (file)
index 0000000..839625e
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *
+ * Copyright 2021 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 <iostream>
+#include <memory>
+#include <string>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+
+#include <grpcpp/grpcpp.h>
+
+#ifdef BAZEL_BUILD
+#include "examples/protos/helloworld.grpc.pb.h"
+#else
+#include "helloworld.grpc.pb.h"
+#endif
+
+ABSL_FLAG(std::string, target, "xds:///helloworld:50051", "Target string");
+ABSL_FLAG(bool, secure, true, "Secure mode");
+
+using grpc::Channel;
+using grpc::ClientContext;
+using grpc::Status;
+using helloworld::Greeter;
+using helloworld::HelloReply;
+using helloworld::HelloRequest;
+
+class GreeterClient {
+ public:
+  GreeterClient(std::shared_ptr<Channel> channel)
+      : stub_(Greeter::NewStub(channel)) {}
+
+  // Assembles the client's payload, sends it and presents the response back
+  // from the server.
+  std::string SayHello(const std::string& user) {
+    // Data we are sending to the server.
+    HelloRequest request;
+    request.set_name(user);
+
+    // Container for the data we expect from the server.
+    HelloReply reply;
+
+    // Context for the client. It could be used to convey extra information to
+    // the server and/or tweak certain RPC behaviors.
+    ClientContext context;
+
+    // The actual RPC.
+    Status status = stub_->SayHello(&context, request, &reply);
+
+    // Act upon its status.
+    if (status.ok()) {
+      return reply.message();
+    } else {
+      std::cout << status.error_code() << ": " << status.error_message()
+                << std::endl;
+      return "RPC failed";
+    }
+  }
+
+ private:
+  std::unique_ptr<Greeter::Stub> stub_;
+};
+
+int main(int argc, char** argv) {
+  absl::ParseCommandLine(argc, argv);
+  GreeterClient greeter(grpc::CreateChannel(
+      absl::GetFlag(FLAGS_target), absl::GetFlag(FLAGS_secure)
+                                       ? grpc::experimental::XdsCredentials(
+                                             grpc::InsecureChannelCredentials())
+                                       : grpc::InsecureChannelCredentials()));
+  std::string user("world");
+  std::string reply = greeter.SayHello(user);
+  std::cout << "Greeter received: " << reply << std::endl;
+
+  return 0;
+}
diff --git a/examples/cpp/helloworld/xds_greeter_server.cc b/examples/cpp/helloworld/xds_greeter_server.cc
new file mode 100644 (file)
index 0000000..21a964d
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright 2021 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 <iostream>
+#include <memory>
+#include <string>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "absl/strings/str_cat.h"
+
+#include <grpcpp/ext/admin_services.h>
+#include <grpcpp/ext/proto_server_reflection_plugin.h>
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/health_check_service_interface.h>
+#include <grpcpp/xds_server_builder.h>
+
+#ifdef BAZEL_BUILD
+#include "examples/protos/helloworld.grpc.pb.h"
+#else
+#include "helloworld.grpc.pb.h"
+#endif
+
+ABSL_FLAG(int32_t, port, 50051, "Server port for service.");
+ABSL_FLAG(int32_t, maintenance_port, 50052,
+          "Server port for maintenance if --secure is used.");
+ABSL_FLAG(bool, secure, true, "Secure mode");
+
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+using grpc::Status;
+using helloworld::Greeter;
+using helloworld::HelloReply;
+using helloworld::HelloRequest;
+
+// Logic and data behind the server's behavior.
+class GreeterServiceImpl final : public Greeter::Service {
+  Status SayHello(ServerContext* context, const HelloRequest* request,
+                  HelloReply* reply) override {
+    std::string prefix("Hello ");
+    reply->set_message(prefix + request->name());
+    return Status::OK;
+  }
+};
+
+void RunServer() {
+  grpc::EnableDefaultHealthCheckService(true);
+  grpc::reflection::InitProtoReflectionServerBuilderPlugin();
+  int port = absl::GetFlag(FLAGS_port);
+  int maintenance_port = absl::GetFlag(FLAGS_maintenance_port);
+  grpc::experimental::XdsServerBuilder xds_builder;
+  ServerBuilder builder;
+  std::unique_ptr<Server> xds_enabled_server;
+  std::unique_ptr<Server> server;
+  GreeterServiceImpl service;
+  // Register "service" as the instance through which we'll communicate with
+  // clients. In this case it corresponds to an *synchronous* service.
+  xds_builder.RegisterService(&service);
+  if (absl::GetFlag(FLAGS_secure)) {
+    // Listen on the given address with XdsServerCredentials and a fallback of
+    // InsecureServerCredentials
+    xds_builder.AddListeningPort(absl::StrCat("0.0.0.0:", port),
+                                 grpc::experimental::XdsServerCredentials(
+                                     grpc::InsecureServerCredentials()));
+    xds_enabled_server = xds_builder.BuildAndStart();
+    gpr_log(GPR_INFO, "Server starting on 0.0.0.0:%d", port);
+    grpc::AddAdminServices(&builder);
+    // For the maintenance server, do not use any authentication mechanism.
+    builder.AddListeningPort(absl::StrCat("0.0.0.0:", maintenance_port),
+                             grpc::InsecureServerCredentials());
+    server = builder.BuildAndStart();
+    gpr_log(GPR_INFO, "Maintenance server listening on 0.0.0.0:%d",
+            maintenance_port);
+  } else {
+    grpc::AddAdminServices(&xds_builder);
+    // Listen on the given address without any authentication mechanism.
+    builder.AddListeningPort(absl::StrCat("0.0.0.0:", port),
+                             grpc::InsecureServerCredentials());
+    server = xds_builder.BuildAndStart();
+    gpr_log(GPR_INFO, "Server listening on 0.0.0.0:%d", port);
+  }
+
+  // Wait for the server to shutdown. Note that some other thread must be
+  // responsible for shutting down the server for this call to ever return.
+  server->Wait();
+}
+
+int main(int argc, char** argv) {
+  absl::ParseCommandLine(argc, argv);
+  RunServer();
+  return 0;
+}
diff --git a/examples/php/GPBMetadata/Helloworld.php b/examples/php/GPBMetadata/Helloworld.php
new file mode 100644 (file)
index 0000000..0927516
Binary files /dev/null and b/examples/php/GPBMetadata/Helloworld.php differ
diff --git a/examples/php/Helloworld/GreeterClient.php b/examples/php/Helloworld/GreeterClient.php
new file mode 100644 (file)
index 0000000..f90303a
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// 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.
+//
+namespace Helloworld;
+
+/**
+ * The greeting service definition.
+ */
+class GreeterClient extends \Grpc\BaseStub {
+
+    /**
+     * @param string $hostname hostname
+     * @param array $opts channel options
+     * @param \Grpc\Channel $channel (optional) re-use channel object
+     */
+    public function __construct($hostname, $opts, $channel = null) {
+        parent::__construct($hostname, $opts, $channel);
+    }
+
+    /**
+     * Sends a greeting
+     * @param \Helloworld\HelloRequest $argument input argument
+     * @param array $metadata metadata
+     * @param array $options call options
+     * @return \Grpc\UnaryCall
+     */
+    public function SayHello(\Helloworld\HelloRequest $argument,
+      $metadata = [], $options = []) {
+        return $this->_simpleRequest('/helloworld.Greeter/SayHello',
+        $argument,
+        ['\Helloworld\HelloReply', 'decode'],
+        $metadata, $options);
+    }
+
+}
diff --git a/examples/php/Helloworld/GreeterStub.php b/examples/php/Helloworld/GreeterStub.php
new file mode 100644 (file)
index 0000000..6667f18
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// 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.
+//
+namespace Helloworld;
+
+/**
+ * The greeting service definition.
+ */
+class GreeterStub {
+
+    /**
+     * Sends a greeting
+     * @param \Helloworld\HelloRequest $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Helloworld\HelloReply for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function SayHello(
+        \Helloworld\HelloRequest $request,
+        \Grpc\ServerContext $context
+    ): ?\Helloworld\HelloReply {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * Get the method descriptors of the service for server registration
+     *
+     * @return array of \Grpc\MethodDescriptor for the service methods
+     */
+    public final function getMethodDescriptors(): array
+    {
+        return [
+            '/helloworld.Greeter/SayHello' => new \Grpc\MethodDescriptor(
+                $this,
+                'SayHello',
+                '\Helloworld\HelloRequest',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+        ];
+    }
+
+}
diff --git a/examples/php/Helloworld/HelloReply.php b/examples/php/Helloworld/HelloReply.php
new file mode 100644 (file)
index 0000000..74c7f87
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: helloworld.proto
+
+namespace Helloworld;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * The response message containing the greetings
+ *
+ * Generated from protobuf message <code>helloworld.HelloReply</code>
+ */
+class HelloReply extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Generated from protobuf field <code>string message = 1;</code>
+     */
+    protected $message = '';
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type string $message
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\Helloworld::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * Generated from protobuf field <code>string message = 1;</code>
+     * @return string
+     */
+    public function getMessage()
+    {
+        return $this->message;
+    }
+
+    /**
+     * Generated from protobuf field <code>string message = 1;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setMessage($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->message = $var;
+
+        return $this;
+    }
+
+}
+
diff --git a/examples/php/Helloworld/HelloRequest.php b/examples/php/Helloworld/HelloRequest.php
new file mode 100644 (file)
index 0000000..d0b5278
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: helloworld.proto
+
+namespace Helloworld;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * The request message containing the user's name.
+ *
+ * Generated from protobuf message <code>helloworld.HelloRequest</code>
+ */
+class HelloRequest extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Generated from protobuf field <code>string name = 1;</code>
+     */
+    protected $name = '';
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type string $name
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\Helloworld::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setName($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->name = $var;
+
+        return $this;
+    }
+
+}
+
index 2182e39..e027d32 100644 (file)
@@ -1,56 +1,9 @@
-# gRPC PHP Quick Start Example
+# gRPC PHP examples
 
+This directory contains the sources for the following PHP examples:
 
-## Prerequisites
+- [Quick start][]
+- [Basics tutorial][]
 
-This requires `php` >= 5.5, `pecl`, `composer`
-
-## Install
-
- - Install the `grpc` extension
-
-   ```sh
-   $ [sudo] pecl install grpc
-   ```
-
- - Install the `protoc` compiler plugin `grpc_php_plugin`
-
-   ```sh
-   $ git clone -b RELEASE_TAG_HERE https://github.com/grpc/grpc
-   $ cd grpc
-   $ make grpc_php_plugin
-   ```
-
- - Install the `grpc/grpc` composer package
-
-   ```
-   $ cd examples/php
-   $ composer install
-   ```
-
-## Try it!
-
- - Run the server
-
-   Please follow the instruction in [Node][] to run the server
-   ```
-   $ cd examples/node
-   $ npm install
-   $ cd dynamic_codegen or cd static_codegen
-   $ node greeter_server.js
-   ```
-
- - Generate proto files and run the client
-
-   ```
-   $ cd examples/php
-   $ ./greeter_proto_gen.sh
-   $ ./run_greeter_client.sh
-   ```
-
-## In-depth Tutorial
-
-You can find a more detailed tutorial in [gRPC Basics: PHP][]
-
-[Node]:https://github.com/grpc/grpc/tree/master/examples/node
-[gRPC Basics: PHP]:https://grpc.io/docs/languages/php/basics
+[Quick start]: https://grpc.io/docs/languages/php/quickstart/
+[Basics tutorial]: https://grpc.io/docs/languages/php/basics/
index 927f7df..1d44bba 100644 (file)
@@ -2,8 +2,8 @@
   "name": "grpc/grpc-demo",
   "description": "gRPC example for PHP",
   "require": {
-    "grpc/grpc": "^v1.3.0",
-    "google/protobuf": "^v3.3.0"
+    "grpc/grpc": "^v1.30.0",
+    "google/protobuf": "^v3.12.2"
   },
   "autoload": {
     "psr-4": {
index c74e552..541d91a 100644 (file)
@@ -1,8 +1,8 @@
 {
   "name": "grpc-php/echo-example",
   "require": {
-    "grpc/grpc": "^v1.22.0",
-    "google/protobuf": "^3.7.0"
+    "grpc/grpc": "^v1.30.0",
+    "google/protobuf": "^3.12.2"
   },
   "autoload": {
     "psr-4": {
diff --git a/examples/php/greeter_and_routeguide_multi_server.php b/examples/php/greeter_and_routeguide_multi_server.php
new file mode 100644 (file)
index 0000000..1bdc1d7
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+/*
+ *
+ * Copyright 2020 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.
+ *
+ */
+
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/MethodDescriptor.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/Status.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/ServerCallReader.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/ServerCallWriter.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/ServerContext.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/RpcServer.php';
+require dirname(__FILE__) . '/vendor/autoload.php';
+require dirname(__FILE__) . '/route_guide/RouteGuideService.php';
+
+class Greeter extends \Helloworld\GreeterStub
+{
+    public function SayHello(
+        \Helloworld\HelloRequest $request,
+        \Grpc\ServerContext $serverContext
+    ): ?\Helloworld\HelloReply {
+        $name = $request->getName();
+        $response = new \Helloworld\HelloReply();
+        $response->setMessage("Hello " . $name);
+        return $response;
+    }
+}
+
+
+$server = new \Grpc\RpcServer();
+$server->addHttp2Port('0.0.0.0:50051');
+$server->handle(new RouteGuideService(null));
+$server->handle(new Greeter());
+$server->run();
index 4322bbd..07c7e61 100755 (executable)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-protoc --proto_path=../protos --php_out=. --grpc_out=. --plugin=protoc-gen-grpc=../../bins/opt/grpc_php_plugin ../protos/helloworld.proto
+set -e
+
+cd $(dirname $0)/../..
+
+# protoc and grpc_*_plugin binaries can be obtained by running
+# $ bazel build @com_google_protobuf//:protoc //src/compiler:all
+PROTOC=bazel-bin/external/com_google_protobuf/protoc
+PLUGIN=protoc-gen-grpc=bazel-bin/src/compiler/grpc_php_plugin
+
+$PROTOC --proto_path=examples/protos \
+       --php_out=examples/php \
+       --grpc_out=generate_server:examples/php \
+       --plugin=$PLUGIN examples/protos/helloworld.proto
diff --git a/examples/php/greeter_server.php b/examples/php/greeter_server.php
new file mode 100644 (file)
index 0000000..a5d749b
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/*
+ *
+ * Copyright 2020 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.
+ *
+ */
+
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/MethodDescriptor.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/Status.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/ServerCallReader.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/ServerCallWriter.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/ServerContext.php';
+require dirname(__FILE__) . '/../../src/php/lib/Grpc/RpcServer.php';
+require dirname(__FILE__) . '/vendor/autoload.php';
+
+class Greeter extends Helloworld\GreeterStub
+{
+    public function SayHello(
+        \Helloworld\HelloRequest $request,
+        \Grpc\ServerContext $serverContext
+    ): ?\Helloworld\HelloReply {
+        $name = $request->getName();
+        $response = new \Helloworld\HelloReply();
+        $response->setMessage("Hello " . $name);
+        return $response;
+    }
+}
+
+$server = new \Grpc\RpcServer();
+$server->addHttp2Port('0.0.0.0:50051');
+$server->handle(new Greeter());
+$server->run();
diff --git a/examples/php/route_guide/GPBMetadata/RouteGuide.php b/examples/php/route_guide/GPBMetadata/RouteGuide.php
new file mode 100644 (file)
index 0000000..ffd390b
Binary files /dev/null and b/examples/php/route_guide/GPBMetadata/RouteGuide.php differ
diff --git a/examples/php/route_guide/RouteGuideService.php b/examples/php/route_guide/RouteGuideService.php
new file mode 100644 (file)
index 0000000..ac1894c
--- /dev/null
@@ -0,0 +1,182 @@
+<?php
+/*
+ *
+ * Copyright 2020 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.
+ *
+ */
+
+
+class RouteGuideService extends \Routeguide\RouteGuideStub
+{
+    public function __construct($dbFilePath)
+    {
+        $dbFilePath = $dbFilePath ?? dirname(__FILE__) . '/route_guide_db.json';
+        $dbData = file_get_contents($dbFilePath);
+        if (!$dbData) {
+            throw new InvalidArgumentException(
+                "Error reading route db file: " . $dbFilePath
+            );
+        }
+        $featureList = json_decode($dbData);
+        if (!$featureList) {
+            throw new InvalidArgumentException(
+                "Error decoding route db file: " . $dbFilePath
+            );
+        }
+        foreach ($featureList as $feature) {
+            array_push($this->featureList, new Routeguide\Feature([
+                'name' => $feature->name,
+                'location' => new Routeguide\Point([
+                    'latitude' => $feature->location->latitude,
+                    'longitude' => $feature->location->longitude,
+                ]),
+            ]));
+        }
+    }
+
+    private function findFeature(\Routeguide\Point $point)
+    {
+        foreach ($this->featureList as $feature) {
+            $location = $feature->getLocation();
+            if (
+                $location->getLatitude() === $point->getLatitude()
+                && $location->getLongitude() === $point->getLongitude()
+            ) {
+                return $feature;
+            }
+        }
+        return null;
+    }
+
+    // The formula is based on http://mathforum.org/library/drmath/view/51879.html
+    private function calculateDistance(
+        \Routeguide\Point $start,
+        \Routeguide\Point $end
+    ) {
+        $toRadians = function (float $num) {
+            return $num * 3.1415926 / 180;
+        };
+        $coordFactor = 10000000.0;
+        $R = 6371000; // metres
+
+        $lat_1 = $start->getLatitude() / $coordFactor;
+        $lat_2 = $end->getLatitude() / $coordFactor;
+        $lon_1 = $start->getLongitude() / $coordFactor;
+        $lon_2 = $end->getLongitude() / $coordFactor;
+        $lat_rad_1 = $toRadians($lat_1);
+        $lat_rad_2 = $toRadians($lat_2);
+        $delta_lat_rad = $toRadians($lat_2 - $lat_1);
+        $delta_lon_rad = $toRadians($lon_2 - $lon_1);
+
+        $a = pow(sin($delta_lat_rad / 2), 2) +
+            cos($lat_rad_1) * cos($lat_rad_2) * pow(sin($delta_lon_rad / 2), 2);
+        $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
+
+        return $R * $c;
+    }
+
+    public function GetFeature(
+        \Routeguide\Point $request,
+        \Grpc\ServerContext $serverContext
+    ): ?\Routeguide\Feature {
+        $feature = $this->findFeature($request);
+        $notFoundFeature = new Routeguide\Feature([
+            'name' => '',
+            'location' => $request,
+        ]);
+        return $feature ?? $notFoundFeature;
+    }
+
+    public function ListFeatures(
+        \Routeguide\Rectangle $request,
+        \Grpc\ServerCallWriter $writer,
+        \Grpc\ServerContext $serverContext
+    ): void {
+        $lo = $request->getLo();
+        $hi = $request->getHi();
+        $left = min($lo->getLongitude(), $hi->getLongitude());
+        $right = max($lo->getLongitude(), $hi->getLongitude());
+        $top = max($lo->getLatitude(), $hi->getLatitude());
+        $bottom = min($lo->getLatitude(), $hi->getLatitude());
+
+        foreach ($this->featureList as $feature) {
+            $longitude = $feature->getLocation()->getLongitude();
+            $latitude = $feature->getLocation()->getLatitude();
+            if (
+                $longitude >= $left && $longitude <= $right
+                && $latitude >= $bottom && $latitude <= $top
+            ) {
+                $writer->write($feature);
+            }
+        }
+
+        $writer->finish();
+    }
+
+    public function RecordRoute(
+        \Grpc\ServerCallReader $reader,
+        \Grpc\ServerContext $serverContext
+    ): ?\Routeguide\RouteSummary {
+        $point_count = 0;
+        $feature_count = 0;
+        $distance = 0;
+        $previous = null;
+
+        $start_time = time();
+        while ($point = $reader->read()) {
+            $point_count++;
+            $feature = $this->findFeature($point);
+            if ($feature) {
+                $feature_count++;
+                if ($previous) {
+                    $distance += $this->calculateDistance($previous, $point);
+                }
+                $previous = $point;
+            }
+        }
+
+        $summary = new \Routeguide\RouteSummary();
+        $summary->setPointCount($point_count);
+        $summary->setFeatureCount($feature_count);
+        $summary->setDistance($distance);
+        $summary->setElapsedTime(time() - $start_time);
+
+        return $summary;
+    }
+
+    public function RouteChat(
+        \Grpc\ServerCallReader $reader,
+        \Grpc\ServerCallWriter $writer,
+        \Grpc\ServerContext $serverContext
+    ): void {
+        while ($note = $reader->read()) {
+            foreach ($this->received_notes as $n) {
+                if (
+                    $n->getLocation()->getLatitude() ===
+                    $note->getLocation()->getLatitude()
+                    && $n->getLocation()->getLongitude() ===
+                    $note->getLocation()->getLongitude()
+                ) {
+                    $writer->write($n);
+                }
+            }
+            array_push($this->received_notes, $note);
+        }
+        $writer->finish();
+    }
+
+    private $received_notes = [];
+    private $featureList = [];
+}
diff --git a/examples/php/route_guide/Routeguide/Feature.php b/examples/php/route_guide/Routeguide/Feature.php
new file mode 100644 (file)
index 0000000..43362f1
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: route_guide.proto
+
+namespace Routeguide;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * A feature names something at a given point.
+ * If a feature could not be named, the name is empty.
+ *
+ * Generated from protobuf message <code>routeguide.Feature</code>
+ */
+class Feature extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * The name of the feature.
+     *
+     * Generated from protobuf field <code>string name = 1;</code>
+     */
+    protected $name = '';
+    /**
+     * The point where the feature is detected.
+     *
+     * Generated from protobuf field <code>.routeguide.Point location = 2;</code>
+     */
+    protected $location = null;
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type string $name
+     *           The name of the feature.
+     *     @type \Routeguide\Point $location
+     *           The point where the feature is detected.
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\RouteGuide::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * The name of the feature.
+     *
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * The name of the feature.
+     *
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setName($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->name = $var;
+
+        return $this;
+    }
+
+    /**
+     * The point where the feature is detected.
+     *
+     * Generated from protobuf field <code>.routeguide.Point location = 2;</code>
+     * @return \Routeguide\Point|null
+     */
+    public function getLocation()
+    {
+        return isset($this->location) ? $this->location : null;
+    }
+
+    public function hasLocation()
+    {
+        return isset($this->location);
+    }
+
+    public function clearLocation()
+    {
+        unset($this->location);
+    }
+
+    /**
+     * The point where the feature is detected.
+     *
+     * Generated from protobuf field <code>.routeguide.Point location = 2;</code>
+     * @param \Routeguide\Point $var
+     * @return $this
+     */
+    public function setLocation($var)
+    {
+        GPBUtil::checkMessage($var, \Routeguide\Point::class);
+        $this->location = $var;
+
+        return $this;
+    }
+
+}
+
diff --git a/examples/php/route_guide/Routeguide/Point.php b/examples/php/route_guide/Routeguide/Point.php
new file mode 100644 (file)
index 0000000..094939f
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: route_guide.proto
+
+namespace Routeguide;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Points are represented as latitude-longitude pairs in the E7 representation
+ * (degrees multiplied by 10**7 and rounded to the nearest integer).
+ * Latitudes should be in the range +/- 90 degrees and longitude should be in
+ * the range +/- 180 degrees (inclusive).
+ *
+ * Generated from protobuf message <code>routeguide.Point</code>
+ */
+class Point extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Generated from protobuf field <code>int32 latitude = 1;</code>
+     */
+    protected $latitude = 0;
+    /**
+     * Generated from protobuf field <code>int32 longitude = 2;</code>
+     */
+    protected $longitude = 0;
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type int $latitude
+     *     @type int $longitude
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\RouteGuide::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * Generated from protobuf field <code>int32 latitude = 1;</code>
+     * @return int
+     */
+    public function getLatitude()
+    {
+        return $this->latitude;
+    }
+
+    /**
+     * Generated from protobuf field <code>int32 latitude = 1;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setLatitude($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->latitude = $var;
+
+        return $this;
+    }
+
+    /**
+     * Generated from protobuf field <code>int32 longitude = 2;</code>
+     * @return int
+     */
+    public function getLongitude()
+    {
+        return $this->longitude;
+    }
+
+    /**
+     * Generated from protobuf field <code>int32 longitude = 2;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setLongitude($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->longitude = $var;
+
+        return $this;
+    }
+
+}
+
diff --git a/examples/php/route_guide/Routeguide/Rectangle.php b/examples/php/route_guide/Routeguide/Rectangle.php
new file mode 100644 (file)
index 0000000..29292cc
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: route_guide.proto
+
+namespace Routeguide;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * A latitude-longitude rectangle, represented as two diagonally opposite
+ * points "lo" and "hi".
+ *
+ * Generated from protobuf message <code>routeguide.Rectangle</code>
+ */
+class Rectangle extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * One corner of the rectangle.
+     *
+     * Generated from protobuf field <code>.routeguide.Point lo = 1;</code>
+     */
+    protected $lo = null;
+    /**
+     * The other corner of the rectangle.
+     *
+     * Generated from protobuf field <code>.routeguide.Point hi = 2;</code>
+     */
+    protected $hi = null;
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type \Routeguide\Point $lo
+     *           One corner of the rectangle.
+     *     @type \Routeguide\Point $hi
+     *           The other corner of the rectangle.
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\RouteGuide::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * One corner of the rectangle.
+     *
+     * Generated from protobuf field <code>.routeguide.Point lo = 1;</code>
+     * @return \Routeguide\Point|null
+     */
+    public function getLo()
+    {
+        return isset($this->lo) ? $this->lo : null;
+    }
+
+    public function hasLo()
+    {
+        return isset($this->lo);
+    }
+
+    public function clearLo()
+    {
+        unset($this->lo);
+    }
+
+    /**
+     * One corner of the rectangle.
+     *
+     * Generated from protobuf field <code>.routeguide.Point lo = 1;</code>
+     * @param \Routeguide\Point $var
+     * @return $this
+     */
+    public function setLo($var)
+    {
+        GPBUtil::checkMessage($var, \Routeguide\Point::class);
+        $this->lo = $var;
+
+        return $this;
+    }
+
+    /**
+     * The other corner of the rectangle.
+     *
+     * Generated from protobuf field <code>.routeguide.Point hi = 2;</code>
+     * @return \Routeguide\Point|null
+     */
+    public function getHi()
+    {
+        return isset($this->hi) ? $this->hi : null;
+    }
+
+    public function hasHi()
+    {
+        return isset($this->hi);
+    }
+
+    public function clearHi()
+    {
+        unset($this->hi);
+    }
+
+    /**
+     * The other corner of the rectangle.
+     *
+     * Generated from protobuf field <code>.routeguide.Point hi = 2;</code>
+     * @param \Routeguide\Point $var
+     * @return $this
+     */
+    public function setHi($var)
+    {
+        GPBUtil::checkMessage($var, \Routeguide\Point::class);
+        $this->hi = $var;
+
+        return $this;
+    }
+
+}
+
diff --git a/examples/php/route_guide/Routeguide/RouteGuideClient.php b/examples/php/route_guide/Routeguide/RouteGuideClient.php
new file mode 100644 (file)
index 0000000..c0d466d
--- /dev/null
@@ -0,0 +1,105 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// 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.
+//
+namespace Routeguide;
+
+/**
+ * Interface exported by the server.
+ */
+class RouteGuideClient extends \Grpc\BaseStub {
+
+    /**
+     * @param string $hostname hostname
+     * @param array $opts channel options
+     * @param \Grpc\Channel $channel (optional) re-use channel object
+     */
+    public function __construct($hostname, $opts, $channel = null) {
+        parent::__construct($hostname, $opts, $channel);
+    }
+
+    /**
+     * A simple RPC.
+     *
+     * Obtains the feature at a given position.
+     *
+     * A feature with an empty name is returned if there's no feature at the given
+     * position.
+     * @param \Routeguide\Point $argument input argument
+     * @param array $metadata metadata
+     * @param array $options call options
+     * @return \Grpc\UnaryCall
+     */
+    public function GetFeature(\Routeguide\Point $argument,
+      $metadata = [], $options = []) {
+        return $this->_simpleRequest('/routeguide.RouteGuide/GetFeature',
+        $argument,
+        ['\Routeguide\Feature', 'decode'],
+        $metadata, $options);
+    }
+
+    /**
+     * A server-to-client streaming RPC.
+     *
+     * Obtains the Features available within the given Rectangle.  Results are
+     * streamed rather than returned at once (e.g. in a response message with a
+     * repeated field), as the rectangle may cover a large area and contain a
+     * huge number of features.
+     * @param \Routeguide\Rectangle $argument input argument
+     * @param array $metadata metadata
+     * @param array $options call options
+     * @return \Grpc\ServerStreamingCall
+     */
+    public function ListFeatures(\Routeguide\Rectangle $argument,
+      $metadata = [], $options = []) {
+        return $this->_serverStreamRequest('/routeguide.RouteGuide/ListFeatures',
+        $argument,
+        ['\Routeguide\Feature', 'decode'],
+        $metadata, $options);
+    }
+
+    /**
+     * A client-to-server streaming RPC.
+     *
+     * Accepts a stream of Points on a route being traversed, returning a
+     * RouteSummary when traversal is completed.
+     * @param array $metadata metadata
+     * @param array $options call options
+     * @return \Grpc\ClientStreamingCall
+     */
+    public function RecordRoute($metadata = [], $options = []) {
+        return $this->_clientStreamRequest('/routeguide.RouteGuide/RecordRoute',
+        ['\Routeguide\RouteSummary','decode'],
+        $metadata, $options);
+    }
+
+    /**
+     * A Bidirectional streaming RPC.
+     *
+     * Accepts a stream of RouteNotes sent while a route is being traversed,
+     * while receiving other RouteNotes (e.g. from other users).
+     * @param array $metadata metadata
+     * @param array $options call options
+     * @return \Grpc\BidiStreamingCall
+     */
+    public function RouteChat($metadata = [], $options = []) {
+        return $this->_bidiRequest('/routeguide.RouteGuide/RouteChat',
+        ['\Routeguide\RouteNote','decode'],
+        $metadata, $options);
+    }
+
+}
diff --git a/examples/php/route_guide/Routeguide/RouteGuideStub.php b/examples/php/route_guide/Routeguide/RouteGuideStub.php
new file mode 100644 (file)
index 0000000..6beb57c
--- /dev/null
@@ -0,0 +1,139 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// 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.
+//
+namespace Routeguide;
+
+/**
+ * Interface exported by the server.
+ */
+class RouteGuideStub {
+
+    /**
+     * A simple RPC.
+     *
+     * Obtains the feature at a given position.
+     *
+     * A feature with an empty name is returned if there's no feature at the given
+     * position.
+     * @param \Routeguide\Point $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Routeguide\Feature for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function GetFeature(
+        \Routeguide\Point $request,
+        \Grpc\ServerContext $context
+    ): ?\Routeguide\Feature {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * A server-to-client streaming RPC.
+     *
+     * Obtains the Features available within the given Rectangle.  Results are
+     * streamed rather than returned at once (e.g. in a response message with a
+     * repeated field), as the rectangle may cover a large area and contain a
+     * huge number of features.
+     * @param \Routeguide\Rectangle $request client request
+     * @param \Grpc\ServerCallWriter $writer write response data of \Routeguide\Feature
+     * @param \Grpc\ServerContext $context server request context
+     * @return void
+     */
+    public function ListFeatures(
+        \Routeguide\Rectangle $request,
+        \Grpc\ServerCallWriter $writer,
+        \Grpc\ServerContext $context
+    ): void {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        $writer->finish();
+    }
+
+    /**
+     * A client-to-server streaming RPC.
+     *
+     * Accepts a stream of Points on a route being traversed, returning a
+     * RouteSummary when traversal is completed.
+     * @param \Grpc\ServerCallReader $reader read client request data of \Routeguide\Point
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Routeguide\RouteSummary for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function RecordRoute(
+        \Grpc\ServerCallReader $reader,
+        \Grpc\ServerContext $context
+    ): ?\Routeguide\RouteSummary {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * A Bidirectional streaming RPC.
+     *
+     * Accepts a stream of RouteNotes sent while a route is being traversed,
+     * while receiving other RouteNotes (e.g. from other users).
+     * @param \Grpc\ServerCallReader $reader read client request data of \Routeguide\RouteNote
+     * @param \Grpc\ServerCallWriter $writer write response data of \Routeguide\RouteNote
+     * @param \Grpc\ServerContext $context server request context
+     * @return void
+     */
+    public function RouteChat(
+        \Grpc\ServerCallReader $reader,
+        \Grpc\ServerCallWriter $writer,
+        \Grpc\ServerContext $context
+    ): void {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        $writer->finish();
+    }
+
+    /**
+     * Get the method descriptors of the service for server registration
+     *
+     * @return array of \Grpc\MethodDescriptor for the service methods
+     */
+    public final function getMethodDescriptors(): array
+    {
+        return [
+            '/routeguide.RouteGuide/GetFeature' => new \Grpc\MethodDescriptor(
+                $this,
+                'GetFeature',
+                '\Routeguide\Point',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+            '/routeguide.RouteGuide/ListFeatures' => new \Grpc\MethodDescriptor(
+                $this,
+                'ListFeatures',
+                '\Routeguide\Rectangle',
+                \Grpc\MethodDescriptor::SERVER_STREAMING_CALL
+            ),
+            '/routeguide.RouteGuide/RecordRoute' => new \Grpc\MethodDescriptor(
+                $this,
+                'RecordRoute',
+                '\Routeguide\Point',
+                \Grpc\MethodDescriptor::CLIENT_STREAMING_CALL
+            ),
+            '/routeguide.RouteGuide/RouteChat' => new \Grpc\MethodDescriptor(
+                $this,
+                'RouteChat',
+                '\Routeguide\RouteNote',
+                \Grpc\MethodDescriptor::BIDI_STREAMING_CALL
+            ),
+        ];
+    }
+
+}
diff --git a/examples/php/route_guide/Routeguide/RouteNote.php b/examples/php/route_guide/Routeguide/RouteNote.php
new file mode 100644 (file)
index 0000000..153c0a2
--- /dev/null
@@ -0,0 +1,111 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: route_guide.proto
+
+namespace Routeguide;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * A RouteNote is a message sent while at a given point.
+ *
+ * Generated from protobuf message <code>routeguide.RouteNote</code>
+ */
+class RouteNote extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * The location from which the message is sent.
+     *
+     * Generated from protobuf field <code>.routeguide.Point location = 1;</code>
+     */
+    protected $location = null;
+    /**
+     * The message to be sent.
+     *
+     * Generated from protobuf field <code>string message = 2;</code>
+     */
+    protected $message = '';
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type \Routeguide\Point $location
+     *           The location from which the message is sent.
+     *     @type string $message
+     *           The message to be sent.
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\RouteGuide::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * The location from which the message is sent.
+     *
+     * Generated from protobuf field <code>.routeguide.Point location = 1;</code>
+     * @return \Routeguide\Point|null
+     */
+    public function getLocation()
+    {
+        return isset($this->location) ? $this->location : null;
+    }
+
+    public function hasLocation()
+    {
+        return isset($this->location);
+    }
+
+    public function clearLocation()
+    {
+        unset($this->location);
+    }
+
+    /**
+     * The location from which the message is sent.
+     *
+     * Generated from protobuf field <code>.routeguide.Point location = 1;</code>
+     * @param \Routeguide\Point $var
+     * @return $this
+     */
+    public function setLocation($var)
+    {
+        GPBUtil::checkMessage($var, \Routeguide\Point::class);
+        $this->location = $var;
+
+        return $this;
+    }
+
+    /**
+     * The message to be sent.
+     *
+     * Generated from protobuf field <code>string message = 2;</code>
+     * @return string
+     */
+    public function getMessage()
+    {
+        return $this->message;
+    }
+
+    /**
+     * The message to be sent.
+     *
+     * Generated from protobuf field <code>string message = 2;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setMessage($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->message = $var;
+
+        return $this;
+    }
+
+}
+
diff --git a/examples/php/route_guide/Routeguide/RouteSummary.php b/examples/php/route_guide/Routeguide/RouteSummary.php
new file mode 100644 (file)
index 0000000..23c264a
--- /dev/null
@@ -0,0 +1,172 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: route_guide.proto
+
+namespace Routeguide;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * A RouteSummary is received in response to a RecordRoute rpc.
+ * It contains the number of individual points received, the number of
+ * detected features, and the total distance covered as the cumulative sum of
+ * the distance between each point.
+ *
+ * Generated from protobuf message <code>routeguide.RouteSummary</code>
+ */
+class RouteSummary extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * The number of points received.
+     *
+     * Generated from protobuf field <code>int32 point_count = 1;</code>
+     */
+    protected $point_count = 0;
+    /**
+     * The number of known features passed while traversing the route.
+     *
+     * Generated from protobuf field <code>int32 feature_count = 2;</code>
+     */
+    protected $feature_count = 0;
+    /**
+     * The distance covered in metres.
+     *
+     * Generated from protobuf field <code>int32 distance = 3;</code>
+     */
+    protected $distance = 0;
+    /**
+     * The duration of the traversal in seconds.
+     *
+     * Generated from protobuf field <code>int32 elapsed_time = 4;</code>
+     */
+    protected $elapsed_time = 0;
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type int $point_count
+     *           The number of points received.
+     *     @type int $feature_count
+     *           The number of known features passed while traversing the route.
+     *     @type int $distance
+     *           The distance covered in metres.
+     *     @type int $elapsed_time
+     *           The duration of the traversal in seconds.
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\RouteGuide::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * The number of points received.
+     *
+     * Generated from protobuf field <code>int32 point_count = 1;</code>
+     * @return int
+     */
+    public function getPointCount()
+    {
+        return $this->point_count;
+    }
+
+    /**
+     * The number of points received.
+     *
+     * Generated from protobuf field <code>int32 point_count = 1;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setPointCount($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->point_count = $var;
+
+        return $this;
+    }
+
+    /**
+     * The number of known features passed while traversing the route.
+     *
+     * Generated from protobuf field <code>int32 feature_count = 2;</code>
+     * @return int
+     */
+    public function getFeatureCount()
+    {
+        return $this->feature_count;
+    }
+
+    /**
+     * The number of known features passed while traversing the route.
+     *
+     * Generated from protobuf field <code>int32 feature_count = 2;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setFeatureCount($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->feature_count = $var;
+
+        return $this;
+    }
+
+    /**
+     * The distance covered in metres.
+     *
+     * Generated from protobuf field <code>int32 distance = 3;</code>
+     * @return int
+     */
+    public function getDistance()
+    {
+        return $this->distance;
+    }
+
+    /**
+     * The distance covered in metres.
+     *
+     * Generated from protobuf field <code>int32 distance = 3;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setDistance($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->distance = $var;
+
+        return $this;
+    }
+
+    /**
+     * The duration of the traversal in seconds.
+     *
+     * Generated from protobuf field <code>int32 elapsed_time = 4;</code>
+     * @return int
+     */
+    public function getElapsedTime()
+    {
+        return $this->elapsed_time;
+    }
+
+    /**
+     * The duration of the traversal in seconds.
+     *
+     * Generated from protobuf field <code>int32 elapsed_time = 4;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setElapsedTime($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->elapsed_time = $var;
+
+        return $this;
+    }
+
+}
+
diff --git a/examples/php/route_guide/route_guide_db.json b/examples/php/route_guide/route_guide_db.json
new file mode 100644 (file)
index 0000000..9d6a980
--- /dev/null
@@ -0,0 +1,601 @@
+[{
+    "location": {
+        "latitude": 407838351,
+        "longitude": -746143763
+    },
+    "name": "Patriots Path, Mendham, NJ 07945, USA"
+}, {
+    "location": {
+        "latitude": 408122808,
+        "longitude": -743999179
+    },
+    "name": "101 New Jersey 10, Whippany, NJ 07981, USA"
+}, {
+    "location": {
+        "latitude": 413628156,
+        "longitude": -749015468
+    },
+    "name": "U.S. 6, Shohola, PA 18458, USA"
+}, {
+    "location": {
+        "latitude": 419999544,
+        "longitude": -740371136
+    },
+    "name": "5 Conners Road, Kingston, NY 12401, USA"
+}, {
+    "location": {
+        "latitude": 414008389,
+        "longitude": -743951297
+    },
+    "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
+}, {
+    "location": {
+        "latitude": 419611318,
+        "longitude": -746524769
+    },
+    "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
+}, {
+    "location": {
+        "latitude": 406109563,
+        "longitude": -742186778
+    },
+    "name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
+}, {
+    "location": {
+        "latitude": 416802456,
+        "longitude": -742370183
+    },
+    "name": "352 South Mountain Road, Wallkill, NY 12589, USA"
+}, {
+    "location": {
+        "latitude": 412950425,
+        "longitude": -741077389
+    },
+    "name": "Bailey Turn Road, Harriman, NY 10926, USA"
+}, {
+    "location": {
+        "latitude": 412144655,
+        "longitude": -743949739
+    },
+    "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
+}, {
+    "location": {
+        "latitude": 415736605,
+        "longitude": -742847522
+    },
+    "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA"
+}, {
+    "location": {
+        "latitude": 413843930,
+        "longitude": -740501726
+    },
+    "name": "162 Merrill Road, Highland Mills, NY 10930, USA"
+}, {
+    "location": {
+        "latitude": 410873075,
+        "longitude": -744459023
+    },
+    "name": "Clinton Road, West Milford, NJ 07480, USA"
+}, {
+    "location": {
+        "latitude": 412346009,
+        "longitude": -744026814
+    },
+    "name": "16 Old Brook Lane, Warwick, NY 10990, USA"
+}, {
+    "location": {
+        "latitude": 402948455,
+        "longitude": -747903913
+    },
+    "name": "3 Drake Lane, Pennington, NJ 08534, USA"
+}, {
+    "location": {
+        "latitude": 406337092,
+        "longitude": -740122226
+    },
+    "name": "6324 8th Avenue, Brooklyn, NY 11220, USA"
+}, {
+    "location": {
+        "latitude": 406421967,
+        "longitude": -747727624
+    },
+    "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA"
+}, {
+    "location": {
+        "latitude": 416318082,
+        "longitude": -749677716
+    },
+    "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA"
+}, {
+    "location": {
+        "latitude": 415301720,
+        "longitude": -748416257
+    },
+    "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA"
+}, {
+    "location": {
+        "latitude": 402647019,
+        "longitude": -747071791
+    },
+    "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA"
+}, {
+    "location": {
+        "latitude": 412567807,
+        "longitude": -741058078
+    },
+    "name": "New York State Reference Route 987E, Southfields, NY 10975, USA"
+}, {
+    "location": {
+        "latitude": 416855156,
+        "longitude": -744420597
+    },
+    "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA"
+}, {
+    "location": {
+        "latitude": 404663628,
+        "longitude": -744820157
+    },
+    "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA"
+}, {
+    "location": {
+        "latitude": 407113723,
+        "longitude": -749746483
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 402133926,
+        "longitude": -743613249
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 400273442,
+        "longitude": -741220915
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 411236786,
+        "longitude": -744070769
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 411633782,
+        "longitude": -746784970
+    },
+    "name": "211-225 Plains Road, Augusta, NJ 07822, USA"
+}, {
+    "location": {
+        "latitude": 415830701,
+        "longitude": -742952812
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 413447164,
+        "longitude": -748712898
+    },
+    "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA"
+}, {
+    "location": {
+        "latitude": 405047245,
+        "longitude": -749800722
+    },
+    "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA"
+}, {
+    "location": {
+        "latitude": 418858923,
+        "longitude": -746156790
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 417951888,
+        "longitude": -748484944
+    },
+    "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA"
+}, {
+    "location": {
+        "latitude": 407033786,
+        "longitude": -743977337
+    },
+    "name": "26 East 3rd Street, New Providence, NJ 07974, USA"
+}, {
+    "location": {
+        "latitude": 417548014,
+        "longitude": -740075041
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 410395868,
+        "longitude": -744972325
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 404615353,
+        "longitude": -745129803
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 406589790,
+        "longitude": -743560121
+    },
+    "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA"
+}, {
+    "location": {
+        "latitude": 414653148,
+        "longitude": -740477477
+    },
+    "name": "18 Lannis Avenue, New Windsor, NY 12553, USA"
+}, {
+    "location": {
+        "latitude": 405957808,
+        "longitude": -743255336
+    },
+    "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA"
+}, {
+    "location": {
+        "latitude": 411733589,
+        "longitude": -741648093
+    },
+    "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA"
+}, {
+    "location": {
+        "latitude": 412676291,
+        "longitude": -742606606
+    },
+    "name": "1270 Lakes Road, Monroe, NY 10950, USA"
+}, {
+    "location": {
+        "latitude": 409224445,
+        "longitude": -748286738
+    },
+    "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA"
+}, {
+    "location": {
+        "latitude": 406523420,
+        "longitude": -742135517
+    },
+    "name": "652 Garden Street, Elizabeth, NJ 07202, USA"
+}, {
+    "location": {
+        "latitude": 401827388,
+        "longitude": -740294537
+    },
+    "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA"
+}, {
+    "location": {
+        "latitude": 410564152,
+        "longitude": -743685054
+    },
+    "name": "13-17 Stanley Street, West Milford, NJ 07480, USA"
+}, {
+    "location": {
+        "latitude": 408472324,
+        "longitude": -740726046
+    },
+    "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA"
+}, {
+    "location": {
+        "latitude": 412452168,
+        "longitude": -740214052
+    },
+    "name": "5 White Oak Lane, Stony Point, NY 10980, USA"
+}, {
+    "location": {
+        "latitude": 409146138,
+        "longitude": -746188906
+    },
+    "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA"
+}, {
+    "location": {
+        "latitude": 404701380,
+        "longitude": -744781745
+    },
+    "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA"
+}, {
+    "location": {
+        "latitude": 409642566,
+        "longitude": -746017679
+    },
+    "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA"
+}, {
+    "location": {
+        "latitude": 408031728,
+        "longitude": -748645385
+    },
+    "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA"
+}, {
+    "location": {
+        "latitude": 413700272,
+        "longitude": -742135189
+    },
+    "name": "367 Prospect Road, Chester, NY 10918, USA"
+}, {
+    "location": {
+        "latitude": 404310607,
+        "longitude": -740282632
+    },
+    "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA"
+}, {
+    "location": {
+        "latitude": 409319800,
+        "longitude": -746201391
+    },
+    "name": "11 Ward Street, Mount Arlington, NJ 07856, USA"
+}, {
+    "location": {
+        "latitude": 406685311,
+        "longitude": -742108603
+    },
+    "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA"
+}, {
+    "location": {
+        "latitude": 419018117,
+        "longitude": -749142781
+    },
+    "name": "43 Dreher Road, Roscoe, NY 12776, USA"
+}, {
+    "location": {
+        "latitude": 412856162,
+        "longitude": -745148837
+    },
+    "name": "Swan Street, Pine Island, NY 10969, USA"
+}, {
+    "location": {
+        "latitude": 416560744,
+        "longitude": -746721964
+    },
+    "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA"
+}, {
+    "location": {
+        "latitude": 405314270,
+        "longitude": -749836354
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 414219548,
+        "longitude": -743327440
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 415534177,
+        "longitude": -742900616
+    },
+    "name": "565 Winding Hills Road, Montgomery, NY 12549, USA"
+}, {
+    "location": {
+        "latitude": 406898530,
+        "longitude": -749127080
+    },
+    "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA"
+}, {
+    "location": {
+        "latitude": 407586880,
+        "longitude": -741670168
+    },
+    "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA"
+}, {
+    "location": {
+        "latitude": 400106455,
+        "longitude": -742870190
+    },
+    "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA"
+}, {
+    "location": {
+        "latitude": 400066188,
+        "longitude": -746793294
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 418803880,
+        "longitude": -744102673
+    },
+    "name": "40 Mountain Road, Napanoch, NY 12458, USA"
+}, {
+    "location": {
+        "latitude": 414204288,
+        "longitude": -747895140
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 414777405,
+        "longitude": -740615601
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 415464475,
+        "longitude": -747175374
+    },
+    "name": "48 North Road, Forestburgh, NY 12777, USA"
+}, {
+    "location": {
+        "latitude": 404062378,
+        "longitude": -746376177
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 405688272,
+        "longitude": -749285130
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 400342070,
+        "longitude": -748788996
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 401809022,
+        "longitude": -744157964
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 404226644,
+        "longitude": -740517141
+    },
+    "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA"
+}, {
+    "location": {
+        "latitude": 410322033,
+        "longitude": -747871659
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 407100674,
+        "longitude": -747742727
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 418811433,
+        "longitude": -741718005
+    },
+    "name": "213 Bush Road, Stone Ridge, NY 12484, USA"
+}, {
+    "location": {
+        "latitude": 415034302,
+        "longitude": -743850945
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 411349992,
+        "longitude": -743694161
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 404839914,
+        "longitude": -744759616
+    },
+    "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA"
+}, {
+    "location": {
+        "latitude": 414638017,
+        "longitude": -745957854
+    },
+    "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA"
+}, {
+    "location": {
+        "latitude": 412127800,
+        "longitude": -740173578
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 401263460,
+        "longitude": -747964303
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 412843391,
+        "longitude": -749086026
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 418512773,
+        "longitude": -743067823
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 404318328,
+        "longitude": -740835638
+    },
+    "name": "42-102 Main Street, Belford, NJ 07718, USA"
+}, {
+    "location": {
+        "latitude": 419020746,
+        "longitude": -741172328
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 404080723,
+        "longitude": -746119569
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 401012643,
+        "longitude": -744035134
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 404306372,
+        "longitude": -741079661
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 403966326,
+        "longitude": -748519297
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 405002031,
+        "longitude": -748407866
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 409532885,
+        "longitude": -742200683
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 416851321,
+        "longitude": -742674555
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 406411633,
+        "longitude": -741722051
+    },
+    "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
+}, {
+    "location": {
+        "latitude": 413069058,
+        "longitude": -744597778
+    },
+    "name": "261 Van Sickle Road, Goshen, NY 10924, USA"
+}, {
+    "location": {
+        "latitude": 418465462,
+        "longitude": -746859398
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 411733222,
+        "longitude": -744228360
+    },
+    "name": ""
+}, {
+    "location": {
+        "latitude": 410248224,
+        "longitude": -747127767
+    },
+    "name": "3 Hasta Way, Newton, NJ 07860, USA"
+}]
index bfd7cdb..8b7e61c 100755 (executable)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-protoc --proto_path=./../../protos  --php_out=./  --grpc_out=./ --plugin=protoc-gen-grpc=./../../../bins/opt/grpc_php_plugin ./../../protos/route_guide.proto
+set -e
+
+cd $(dirname $0)/../../..
+
+# protoc and grpc_*_plugin binaries can be obtained by running
+# $ bazel build @com_google_protobuf//:protoc //src/compiler:all
+PROTOC=bazel-bin/external/com_google_protobuf/protoc
+PLUGIN=protoc-gen-grpc=bazel-bin/src/compiler/grpc_php_plugin
+
+$PROTOC --proto_path=examples/protos \
+       --php_out=examples/php/route_guide \
+       --grpc_out=generate_server:examples/php/route_guide \
+       --plugin=$PLUGIN examples/protos/route_guide.proto
diff --git a/examples/php/route_guide/route_guide_server.php b/examples/php/route_guide/route_guide_server.php
new file mode 100644 (file)
index 0000000..29b086f
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/*
+ *
+ * Copyright 2020 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.
+ *
+ */
+
+require dirname(__FILE__) . '/../../../src/php/lib/Grpc/MethodDescriptor.php';
+require dirname(__FILE__) . '/../../../src/php/lib/Grpc/Status.php';
+require dirname(__FILE__) . '/../../../src/php/lib/Grpc/ServerCallReader.php';
+require dirname(__FILE__) . '/../../../src/php/lib/Grpc/ServerCallWriter.php';
+require dirname(__FILE__) . '/../../../src/php/lib/Grpc/ServerContext.php';
+require dirname(__FILE__) . '/../../../src/php/lib/Grpc/RpcServer.php';
+require dirname(__FILE__) . '/../vendor/autoload.php';
+require dirname(__FILE__) . '/RouteGuideService.php';
+
+$routeDbFile = $argv[1];
+
+$server = new \Grpc\RpcServer();
+$server->addHttp2Port('0.0.0.0:50051');
+$server->handle(new RouteGuideService($routeDbFile));
+$server->run();
index cd9587a..cba8c06 100644 (file)
@@ -56,7 +56,7 @@ export GRPC_XDS_BOOTSTRAP=/etc/xds-bootstrap.json
 3. Run the client:
 
 ```
-python client.py xds-experimental:///my-backend
+python client.py xds:///my-backend
 ```
 
 ### Verifying Configuration with a CLI Tool
@@ -101,3 +101,23 @@ grpc.health.v1.Health/Check
   "status": "SERVING"
 }
 ```
+
+### Running with Proxyless Security
+
+#### Run the Server with Secure Credentials
+
+Add the `--secure true` flag to the invocation outlined above.
+
+```sh
+python server.py --secure true
+```
+
+#### Run the Client with Secure Credentials
+
+Add the `--secure true` flag to the invocation outlined above.
+
+3. Run the client:
+
+```
+python client.py xds:///my-backend --secure true
+```
index ee30026..a969b60 100644 (file)
@@ -18,6 +18,7 @@ import logging
 import argparse
 
 import grpc
+import grpc.experimental
 
 import helloworld_pb2
 import helloworld_pb2_grpc
@@ -25,11 +26,17 @@ import helloworld_pb2_grpc
 _DESCRIPTION = "Get a greeting from a server."
 
 
-def run(server_address):
-    with grpc.insecure_channel(server_address) as channel:
+def run(server_address, secure):
+    if secure:
+        fallback_creds = grpc.experimental.insecure_channel_credentials()
+        channel_creds = grpc.xds_channel_credentials(fallback_creds)
+        channel = grpc.secure_channel(server_address, channel_creds)
+    else:
+        channel = grpc.insecure_channel(server_address)
+    with channel:
         stub = helloworld_pb2_grpc.GreeterStub(channel)
         response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
-    print("Greeter client received: " + response.message)
+        print("Greeter client received: " + response.message)
 
 
 if __name__ == '__main__':
@@ -37,6 +44,10 @@ if __name__ == '__main__':
     parser.add_argument("server",
                         default=None,
                         help="The address of the server.")
+    parser.add_argument(
+        "--xds-creds",
+        action="store_true",
+        help="If specified, uses xDS credentials to connect to the server.")
     args = parser.parse_args()
     logging.basicConfig()
-    run(args.server)
+    run(args.server, args.xds_creds)
index 7ba651e..6be5698 100644 (file)
@@ -1,4 +1,4 @@
-grpcio>=1.28.1
+grpcio>=1.37.1
 protobuf
 grpcio-reflection
 grpcio-health-checking
index 196e2c1..82fabf2 100644 (file)
@@ -16,7 +16,6 @@
 from concurrent import futures
 import argparse
 import logging
-import multiprocessing
 import socket
 
 import grpc
@@ -31,6 +30,16 @@ from grpc_health.v1 import health_pb2_grpc
 
 _DESCRIPTION = "A general purpose phony server."
 
+_LISTEN_HOST = "[::]"
+
+_THREAD_POOL_SIZE = 256
+
+logger = logging.getLogger()
+console_handler = logging.StreamHandler()
+formatter = logging.Formatter(fmt='%(asctime)s: %(levelname)-8s %(message)s')
+console_handler.setFormatter(formatter)
+logger.addHandler(console_handler)
+
 
 class Greeter(helloworld_pb2_grpc.GreeterServicer):
 
@@ -43,19 +52,17 @@ class Greeter(helloworld_pb2_grpc.GreeterServicer):
             message=f"Hello {request.name} from {self._hostname}!")
 
 
-def serve(port: int, hostname: str):
-    server = grpc.server(
-        futures.ThreadPoolExecutor(max_workers=multiprocessing.cpu_count()))
-
-    # Add the application servicer to the server.
-    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(hostname), server)
+def _configure_maintenance_server(server: grpc.Server,
+                                  maintenance_port: int) -> None:
+    listen_address = f"{_LISTEN_HOST}:{maintenance_port}"
+    server.add_insecure_port(listen_address)
 
     # Create a health check servicer. We use the non-blocking implementation
     # to avoid thread starvation.
     health_servicer = health.HealthServicer(
         experimental_non_blocking=True,
-        experimental_thread_pool=futures.ThreadPoolExecutor(max_workers=1))
-    health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)
+        experimental_thread_pool=futures.ThreadPoolExecutor(
+            max_workers=_THREAD_POOL_SIZE))
 
     # Create a tuple of all of the services we want to export via reflection.
     services = tuple(
@@ -63,18 +70,57 @@ def serve(port: int, hostname: str):
         for service in helloworld_pb2.DESCRIPTOR.services_by_name.values()) + (
             reflection.SERVICE_NAME, health.SERVICE_NAME)
 
-    # Add the reflection service to the server.
-    reflection.enable_server_reflection(services, server)
-    server.add_insecure_port(f"[::]:{port}")
-    server.start()
-
     # Mark all services as healthy.
-    overall_server_health = ""
-    for service in services + (overall_server_health,):
+    health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)
+    for service in services:
         health_servicer.set(service, health_pb2.HealthCheckResponse.SERVING)
+    reflection.enable_server_reflection(services, server)
 
-    # Park the main application thread.
-    server.wait_for_termination()
+
+def _configure_greeter_server(server: grpc.Server, port: int, secure_mode: bool,
+                              hostname) -> None:
+    # Add the application servicer to the server.
+    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(hostname), server)
+    listen_address = f"{_LISTEN_HOST}:{port}"
+    if not secure_mode:
+        server.add_insecure_port(listen_address)
+    else:
+        # Use xDS credentials.
+        logger.info("Running with xDS Server credentials")
+
+        # Fall back to insecure credentials.
+        server_fallback_creds = grpc.insecure_server_credentials()
+        server_creds = grpc.xds_server_credentials(server_fallback_creds)
+        server.add_secure_port(listen_address, server_creds)
+
+
+def serve(port: int, hostname: str, maintenance_port: int,
+          secure_mode: bool) -> None:
+    if port == maintenance_port:
+        # If maintenance port and port are the same, start a single server.
+        server = grpc.server(
+            futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE))
+        _configure_greeter_server(server, port, secure_mode, hostname)
+        _configure_maintenance_server(server, maintenance_port)
+        server.start()
+        logger.info("Greeter server listening on port %d", port)
+        logger.info("Maintenance server listening on port %d", maintenance_port)
+        server.wait_for_termination()
+    else:
+        # Otherwise, start two different servers.
+        greeter_server = grpc.server(
+            futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE),
+            xds=secure_mode)
+        _configure_greeter_server(greeter_server, port, secure_mode, hostname)
+        greeter_server.start()
+        logger.info("Greeter server listening on port %d", port)
+        maintenance_server = grpc.server(
+            futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE))
+        _configure_maintenance_server(maintenance_server, maintenance_port)
+        maintenance_server.start()
+        logger.info("Maintenance server listening on port %d", maintenance_port)
+        greeter_server.wait_for_termination()
+        maintenance_server.wait_for_termination()
 
 
 if __name__ == '__main__':
@@ -89,6 +135,11 @@ if __name__ == '__main__':
                         default=None,
                         nargs="?",
                         help="The name clients will see in responses.")
+    parser.add_argument(
+        "--xds-creds",
+        action="store_true",
+        help="If specified, uses xDS credentials to connect to the server.")
     args = parser.parse_args()
     logging.basicConfig()
-    serve(args.port, args.hostname)
+    logger.setLevel(logging.INFO)
+    serve(args.port, args.hostname, args.port + 1, args.xds_creds)
index 60ceae3..ce3ec33 100644 (file)
@@ -22,7 +22,7 @@
 Pod::Spec.new do |s|
   s.name     = 'gRPC-C++'
   # TODO (mxyan): use version that match gRPC version when pod is stabilized
-  version = '1.37.1'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'gRPC C++ library'
   s.homepage = 'https://grpc.io'
@@ -186,7 +186,7 @@ Pod::Spec.new do |s|
     ss.header_mappings_dir = '.'
     ss.dependency "#{s.name}/Interface", version
     ss.dependency 'gRPC-Core', version
-    abseil_version = '1.20200923.3'
+    abseil_version = '1.20210324.0'
     ss.dependency 'abseil/base/base', abseil_version
     ss.dependency 'abseil/container/flat_hash_map', abseil_version
     ss.dependency 'abseil/container/inlined_vector', abseil_version
@@ -239,6 +239,8 @@ Pod::Spec.new do |s|
                       'src/core/ext/filters/client_channel/resolver_factory.h',
                       'src/core/ext/filters/client_channel/resolver_registry.h',
                       'src/core/ext/filters/client_channel/resolver_result_parsing.h',
+                      'src/core/ext/filters/client_channel/retry_filter.h',
+                      'src/core/ext/filters/client_channel/retry_service_config.h',
                       'src/core/ext/filters/client_channel/retry_throttle.h',
                       'src/core/ext/filters/client_channel/server_address.h',
                       'src/core/ext/filters/client_channel/service_config.h',
@@ -486,6 +488,8 @@ Pod::Spec.new do |s|
                       'src/core/ext/xds/xds_client_stats.h',
                       'src/core/ext/xds/xds_http_fault_filter.h',
                       'src/core/ext/xds/xds_http_filters.h',
+                      'src/core/lib/address_utils/parse_address.h',
+                      'src/core/lib/address_utils/sockaddr_utils.h',
                       'src/core/lib/avl/avl.h',
                       'src/core/lib/backoff/backoff.h',
                       'src/core/lib/channel/channel_args.h',
@@ -543,6 +547,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/gprpp/ref_counted.h',
                       'src/core/lib/gprpp/ref_counted_ptr.h',
                       'src/core/lib/gprpp/stat.h',
+                      'src/core/lib/gprpp/status_helper.h',
                       'src/core/lib/gprpp/sync.h',
                       'src/core/lib/gprpp/thd.h',
                       'src/core/lib/gprpp/time_util.h',
@@ -582,8 +587,6 @@ Pod::Spec.new do |s|
                       'src/core/lib/iomgr/load_file.h',
                       'src/core/lib/iomgr/lockfree_event.h',
                       'src/core/lib/iomgr/nameser.h',
-                      'src/core/lib/iomgr/parse_address.h',
-                      'src/core/lib/iomgr/poller/eventmanager_libuv.h',
                       'src/core/lib/iomgr/polling_entity.h',
                       'src/core/lib/iomgr/pollset.h',
                       'src/core/lib/iomgr/pollset_custom.h',
@@ -600,7 +603,6 @@ Pod::Spec.new do |s|
                       'src/core/lib/iomgr/sockaddr.h',
                       'src/core/lib/iomgr/sockaddr_custom.h',
                       'src/core/lib/iomgr/sockaddr_posix.h',
-                      'src/core/lib/iomgr/sockaddr_utils.h',
                       'src/core/lib/iomgr/sockaddr_windows.h',
                       'src/core/lib/iomgr/socket_factory_posix.h',
                       'src/core/lib/iomgr/socket_mutator.h',
@@ -878,6 +880,8 @@ Pod::Spec.new do |s|
                               'src/core/ext/filters/client_channel/resolver_factory.h',
                               'src/core/ext/filters/client_channel/resolver_registry.h',
                               'src/core/ext/filters/client_channel/resolver_result_parsing.h',
+                              'src/core/ext/filters/client_channel/retry_filter.h',
+                              'src/core/ext/filters/client_channel/retry_service_config.h',
                               'src/core/ext/filters/client_channel/retry_throttle.h',
                               'src/core/ext/filters/client_channel/server_address.h',
                               'src/core/ext/filters/client_channel/service_config.h',
@@ -1125,6 +1129,8 @@ Pod::Spec.new do |s|
                               'src/core/ext/xds/xds_client_stats.h',
                               'src/core/ext/xds/xds_http_fault_filter.h',
                               'src/core/ext/xds/xds_http_filters.h',
+                              'src/core/lib/address_utils/parse_address.h',
+                              'src/core/lib/address_utils/sockaddr_utils.h',
                               'src/core/lib/avl/avl.h',
                               'src/core/lib/backoff/backoff.h',
                               'src/core/lib/channel/channel_args.h',
@@ -1182,6 +1188,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/gprpp/ref_counted.h',
                               'src/core/lib/gprpp/ref_counted_ptr.h',
                               'src/core/lib/gprpp/stat.h',
+                              'src/core/lib/gprpp/status_helper.h',
                               'src/core/lib/gprpp/sync.h',
                               'src/core/lib/gprpp/thd.h',
                               'src/core/lib/gprpp/time_util.h',
@@ -1221,8 +1228,6 @@ Pod::Spec.new do |s|
                               'src/core/lib/iomgr/load_file.h',
                               'src/core/lib/iomgr/lockfree_event.h',
                               'src/core/lib/iomgr/nameser.h',
-                              'src/core/lib/iomgr/parse_address.h',
-                              'src/core/lib/iomgr/poller/eventmanager_libuv.h',
                               'src/core/lib/iomgr/polling_entity.h',
                               'src/core/lib/iomgr/pollset.h',
                               'src/core/lib/iomgr/pollset_custom.h',
@@ -1239,7 +1244,6 @@ Pod::Spec.new do |s|
                               'src/core/lib/iomgr/sockaddr.h',
                               'src/core/lib/iomgr/sockaddr_custom.h',
                               'src/core/lib/iomgr/sockaddr_posix.h',
-                              'src/core/lib/iomgr/sockaddr_utils.h',
                               'src/core/lib/iomgr/sockaddr_windows.h',
                               'src/core/lib/iomgr/socket_factory_posix.h',
                               'src/core/lib/iomgr/socket_mutator.h',
index 1807b8a..eb58ccc 100644 (file)
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.37.1'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'https://grpc.io'
@@ -46,7 +46,7 @@ Pod::Spec.new do |s|
   s.requires_arc = false
 
   name = 'grpc'
-  abseil_version = '1.20200923.3'
+  abseil_version = '1.20210324.0'
 
   # When creating a dynamic framework, name it grpc.framework instead of gRPC-Core.framework.
   # This lets users write their includes like `#include <grpc/grpc.h>` as opposed to `#include
@@ -117,6 +117,7 @@ Pod::Spec.new do |s|
                       'include/grpc/byte_buffer_reader.h',
                       'include/grpc/census.h',
                       'include/grpc/compression.h',
+                      'include/grpc/event_engine/port.h',
                       'include/grpc/fork.h',
                       'include/grpc/grpc.h',
                       'include/grpc/grpc_posix.h',
@@ -173,7 +174,7 @@ Pod::Spec.new do |s|
     ss.header_mappings_dir = '.'
     ss.libraries = 'z'
     ss.dependency "#{s.name}/Interface", version
-    ss.dependency 'BoringSSL-GRPC', '0.0.17'
+    ss.dependency 'BoringSSL-GRPC', '0.0.18'
     ss.dependency 'abseil/base/base', abseil_version
     ss.dependency 'abseil/container/flat_hash_map', abseil_version
     ss.dependency 'abseil/container/inlined_vector', abseil_version
@@ -279,6 +280,10 @@ Pod::Spec.new do |s|
                       'src/core/ext/filters/client_channel/resolver_registry.h',
                       'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
                       'src/core/ext/filters/client_channel/resolver_result_parsing.h',
+                      'src/core/ext/filters/client_channel/retry_filter.cc',
+                      'src/core/ext/filters/client_channel/retry_filter.h',
+                      'src/core/ext/filters/client_channel/retry_service_config.cc',
+                      'src/core/ext/filters/client_channel/retry_service_config.h',
                       'src/core/ext/filters/client_channel/retry_throttle.cc',
                       'src/core/ext/filters/client_channel/retry_throttle.h',
                       'src/core/ext/filters/client_channel/server_address.cc',
@@ -782,6 +787,10 @@ Pod::Spec.new do |s|
                       'src/core/ext/xds/xds_http_filters.cc',
                       'src/core/ext/xds/xds_http_filters.h',
                       'src/core/ext/xds/xds_server_config_fetcher.cc',
+                      'src/core/lib/address_utils/parse_address.cc',
+                      'src/core/lib/address_utils/parse_address.h',
+                      'src/core/lib/address_utils/sockaddr_utils.cc',
+                      'src/core/lib/address_utils/sockaddr_utils.h',
                       'src/core/lib/avl/avl.cc',
                       'src/core/lib/avl/avl.h',
                       'src/core/lib/backoff/backoff.cc',
@@ -901,6 +910,8 @@ Pod::Spec.new do |s|
                       'src/core/lib/gprpp/stat.h',
                       'src/core/lib/gprpp/stat_posix.cc',
                       'src/core/lib/gprpp/stat_windows.cc',
+                      'src/core/lib/gprpp/status_helper.cc',
+                      'src/core/lib/gprpp/status_helper.h',
                       'src/core/lib/gprpp/sync.h',
                       'src/core/lib/gprpp/thd.h',
                       'src/core/lib/gprpp/thd_posix.cc',
@@ -988,10 +999,6 @@ Pod::Spec.new do |s|
                       'src/core/lib/iomgr/lockfree_event.cc',
                       'src/core/lib/iomgr/lockfree_event.h',
                       'src/core/lib/iomgr/nameser.h',
-                      'src/core/lib/iomgr/parse_address.cc',
-                      'src/core/lib/iomgr/parse_address.h',
-                      'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
-                      'src/core/lib/iomgr/poller/eventmanager_libuv.h',
                       'src/core/lib/iomgr/polling_entity.cc',
                       'src/core/lib/iomgr/polling_entity.h',
                       'src/core/lib/iomgr/pollset.cc',
@@ -1021,8 +1028,6 @@ Pod::Spec.new do |s|
                       'src/core/lib/iomgr/sockaddr.h',
                       'src/core/lib/iomgr/sockaddr_custom.h',
                       'src/core/lib/iomgr/sockaddr_posix.h',
-                      'src/core/lib/iomgr/sockaddr_utils.cc',
-                      'src/core/lib/iomgr/sockaddr_utils.h',
                       'src/core/lib/iomgr/sockaddr_windows.h',
                       'src/core/lib/iomgr/socket_factory_posix.cc',
                       'src/core/lib/iomgr/socket_factory_posix.h',
@@ -1436,6 +1441,8 @@ Pod::Spec.new do |s|
                               'src/core/ext/filters/client_channel/resolver_factory.h',
                               'src/core/ext/filters/client_channel/resolver_registry.h',
                               'src/core/ext/filters/client_channel/resolver_result_parsing.h',
+                              'src/core/ext/filters/client_channel/retry_filter.h',
+                              'src/core/ext/filters/client_channel/retry_service_config.h',
                               'src/core/ext/filters/client_channel/retry_throttle.h',
                               'src/core/ext/filters/client_channel/server_address.h',
                               'src/core/ext/filters/client_channel/service_config.h',
@@ -1683,6 +1690,8 @@ Pod::Spec.new do |s|
                               'src/core/ext/xds/xds_client_stats.h',
                               'src/core/ext/xds/xds_http_fault_filter.h',
                               'src/core/ext/xds/xds_http_filters.h',
+                              'src/core/lib/address_utils/parse_address.h',
+                              'src/core/lib/address_utils/sockaddr_utils.h',
                               'src/core/lib/avl/avl.h',
                               'src/core/lib/backoff/backoff.h',
                               'src/core/lib/channel/channel_args.h',
@@ -1740,6 +1749,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/gprpp/ref_counted.h',
                               'src/core/lib/gprpp/ref_counted_ptr.h',
                               'src/core/lib/gprpp/stat.h',
+                              'src/core/lib/gprpp/status_helper.h',
                               'src/core/lib/gprpp/sync.h',
                               'src/core/lib/gprpp/thd.h',
                               'src/core/lib/gprpp/time_util.h',
@@ -1779,8 +1789,6 @@ Pod::Spec.new do |s|
                               'src/core/lib/iomgr/load_file.h',
                               'src/core/lib/iomgr/lockfree_event.h',
                               'src/core/lib/iomgr/nameser.h',
-                              'src/core/lib/iomgr/parse_address.h',
-                              'src/core/lib/iomgr/poller/eventmanager_libuv.h',
                               'src/core/lib/iomgr/polling_entity.h',
                               'src/core/lib/iomgr/pollset.h',
                               'src/core/lib/iomgr/pollset_custom.h',
@@ -1797,7 +1805,6 @@ Pod::Spec.new do |s|
                               'src/core/lib/iomgr/sockaddr.h',
                               'src/core/lib/iomgr/sockaddr_custom.h',
                               'src/core/lib/iomgr/sockaddr_posix.h',
-                              'src/core/lib/iomgr/sockaddr_utils.h',
                               'src/core/lib/iomgr/sockaddr_windows.h',
                               'src/core/lib/iomgr/socket_factory_posix.h',
                               'src/core/lib/iomgr/socket_mutator.h',
@@ -2077,10 +2084,12 @@ Pod::Spec.new do |s|
                       'test/core/end2end/tests/request_with_payload.cc',
                       'test/core/end2end/tests/resource_quota_server.cc',
                       'test/core/end2end/tests/retry.cc',
+                      'test/core/end2end/tests/retry_cancel_during_delay.cc',
                       'test/core/end2end/tests/retry_cancellation.cc',
                       'test/core/end2end/tests/retry_disabled.cc',
                       'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
                       'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
+                      'test/core/end2end/tests/retry_lb_drop.cc',
                       'test/core/end2end/tests/retry_non_retriable_status.cc',
                       'test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc',
                       'test/core/end2end/tests/retry_recv_initial_metadata.cc',
@@ -2110,8 +2119,7 @@ Pod::Spec.new do |s|
                       'test/core/end2end/tests/write_buffering_at_end.cc',
                       'test/core/util/cmdline.cc',
                       'test/core/util/cmdline.h',
-                      'test/core/util/eval_args_mock_endpoint.cc',
-                      'test/core/util/eval_args_mock_endpoint.h',
+                      'test/core/util/evaluate_args_test_util.h',
                       'test/core/util/fuzzer_util.cc',
                       'test/core/util/fuzzer_util.h',
                       'test/core/util/grpc_profiler.cc',
@@ -2120,6 +2128,7 @@ Pod::Spec.new do |s|
                       'test/core/util/histogram.h',
                       'test/core/util/memory_counters.cc',
                       'test/core/util/memory_counters.h',
+                      'test/core/util/mock_authorization_endpoint.h',
                       'test/core/util/mock_endpoint.cc',
                       'test/core/util/mock_endpoint.h',
                       'test/core/util/parse_hexstring.cc',
@@ -2143,6 +2152,8 @@ Pod::Spec.new do |s|
                       'test/core/util/subprocess_windows.cc',
                       'test/core/util/test_config.cc',
                       'test/core/util/test_config.h',
+                      'test/core/util/test_lb_policies.cc',
+                      'test/core/util/test_lb_policies.h',
                       'test/core/util/test_tcp_server.cc',
                       'test/core/util/test_tcp_server.h',
                       'test/core/util/tls_utils.cc',
index df1d73a..68dcb4d 100644 (file)
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.37.1'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'https://grpc.io'
index fac08be..dbfc8de 100644 (file)
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.37.1'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'https://grpc.io'
index 4cdd9f2..af62f2e 100644 (file)
@@ -20,7 +20,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.37.1'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'https://grpc.io'
index 51895f7..2185cbf 100644 (file)
@@ -53,6 +53,10 @@ Gem::Specification.new do |s|
   s.files += %w( include/grpc/byte_buffer_reader.h )
   s.files += %w( include/grpc/census.h )
   s.files += %w( include/grpc/compression.h )
+  s.files += %w( include/grpc/event_engine/channel_args.h )
+  s.files += %w( include/grpc/event_engine/event_engine.h )
+  s.files += %w( include/grpc/event_engine/port.h )
+  s.files += %w( include/grpc/event_engine/slice_allocator.h )
   s.files += %w( include/grpc/fork.h )
   s.files += %w( include/grpc/grpc.h )
   s.files += %w( include/grpc/grpc_posix.h )
@@ -195,6 +199,10 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h )
   s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.h )
+  s.files += %w( src/core/ext/filters/client_channel/retry_filter.cc )
+  s.files += %w( src/core/ext/filters/client_channel/retry_filter.h )
+  s.files += %w( src/core/ext/filters/client_channel/retry_service_config.cc )
+  s.files += %w( src/core/ext/filters/client_channel/retry_service_config.h )
   s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc )
   s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h )
   s.files += %w( src/core/ext/filters/client_channel/server_address.cc )
@@ -698,6 +706,10 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/ext/xds/xds_http_filters.cc )
   s.files += %w( src/core/ext/xds/xds_http_filters.h )
   s.files += %w( src/core/ext/xds/xds_server_config_fetcher.cc )
+  s.files += %w( src/core/lib/address_utils/parse_address.cc )
+  s.files += %w( src/core/lib/address_utils/parse_address.h )
+  s.files += %w( src/core/lib/address_utils/sockaddr_utils.cc )
+  s.files += %w( src/core/lib/address_utils/sockaddr_utils.h )
   s.files += %w( src/core/lib/avl/avl.cc )
   s.files += %w( src/core/lib/avl/avl.h )
   s.files += %w( src/core/lib/backoff/backoff.cc )
@@ -744,6 +756,8 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/debug/stats_data.h )
   s.files += %w( src/core/lib/debug/trace.cc )
   s.files += %w( src/core/lib/debug/trace.h )
+  s.files += %w( src/core/lib/event_engine/slice_allocator.cc )
+  s.files += %w( src/core/lib/event_engine/sockaddr.cc )
   s.files += %w( src/core/lib/gpr/alloc.cc )
   s.files += %w( src/core/lib/gpr/alloc.h )
   s.files += %w( src/core/lib/gpr/arena.h )
@@ -817,6 +831,8 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/gprpp/stat.h )
   s.files += %w( src/core/lib/gprpp/stat_posix.cc )
   s.files += %w( src/core/lib/gprpp/stat_windows.cc )
+  s.files += %w( src/core/lib/gprpp/status_helper.cc )
+  s.files += %w( src/core/lib/gprpp/status_helper.h )
   s.files += %w( src/core/lib/gprpp/sync.h )
   s.files += %w( src/core/lib/gprpp/thd.h )
   s.files += %w( src/core/lib/gprpp/thd_posix.cc )
@@ -904,10 +920,6 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/iomgr/lockfree_event.cc )
   s.files += %w( src/core/lib/iomgr/lockfree_event.h )
   s.files += %w( src/core/lib/iomgr/nameser.h )
-  s.files += %w( src/core/lib/iomgr/parse_address.cc )
-  s.files += %w( src/core/lib/iomgr/parse_address.h )
-  s.files += %w( src/core/lib/iomgr/poller/eventmanager_libuv.cc )
-  s.files += %w( src/core/lib/iomgr/poller/eventmanager_libuv.h )
   s.files += %w( src/core/lib/iomgr/polling_entity.cc )
   s.files += %w( src/core/lib/iomgr/polling_entity.h )
   s.files += %w( src/core/lib/iomgr/pollset.cc )
@@ -937,8 +949,6 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/iomgr/sockaddr.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_custom.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_posix.h )
-  s.files += %w( src/core/lib/iomgr/sockaddr_utils.cc )
-  s.files += %w( src/core/lib/iomgr/sockaddr_utils.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_windows.h )
   s.files += %w( src/core/lib/iomgr/socket_factory_posix.cc )
   s.files += %w( src/core/lib/iomgr/socket_factory_posix.h )
@@ -1247,7 +1257,6 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/abseil-cpp/absl/base/const_init.h )
   s.files += %w( third_party/abseil-cpp/absl/base/dynamic_annotations.h )
   s.files += %w( third_party/abseil-cpp/absl/base/internal/atomic_hook.h )
-  s.files += %w( third_party/abseil-cpp/absl/base/internal/bits.h )
   s.files += %w( third_party/abseil-cpp/absl/base/internal/cycleclock.cc )
   s.files += %w( third_party/abseil-cpp/absl/base/internal/cycleclock.h )
   s.files += %w( third_party/abseil-cpp/absl/base/internal/direct_mmap.h )
@@ -1346,12 +1355,17 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/abseil-cpp/absl/hash/internal/city.h )
   s.files += %w( third_party/abseil-cpp/absl/hash/internal/hash.cc )
   s.files += %w( third_party/abseil-cpp/absl/hash/internal/hash.h )
+  s.files += %w( third_party/abseil-cpp/absl/hash/internal/wyhash.cc )
+  s.files += %w( third_party/abseil-cpp/absl/hash/internal/wyhash.h )
   s.files += %w( third_party/abseil-cpp/absl/memory/memory.h )
   s.files += %w( third_party/abseil-cpp/absl/meta/type_traits.h )
+  s.files += %w( third_party/abseil-cpp/absl/numeric/bits.h )
   s.files += %w( third_party/abseil-cpp/absl/numeric/int128.cc )
   s.files += %w( third_party/abseil-cpp/absl/numeric/int128.h )
   s.files += %w( third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc )
   s.files += %w( third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc )
+  s.files += %w( third_party/abseil-cpp/absl/numeric/internal/bits.h )
+  s.files += %w( third_party/abseil-cpp/absl/numeric/internal/representation.h )
   s.files += %w( third_party/abseil-cpp/absl/status/internal/status_internal.h )
   s.files += %w( third_party/abseil-cpp/absl/status/internal/statusor_internal.h )
   s.files += %w( third_party/abseil-cpp/absl/status/status.cc )
@@ -1373,7 +1387,12 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/charconv_bigint.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/charconv_parse.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_internal.cc )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_internal.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/escaping.cc )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/escaping.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/memutil.cc )
@@ -1397,6 +1416,7 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/str_format/parser.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/str_join_internal.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/str_split_internal.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/string_constant.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/utf8.cc )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/utf8.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/match.cc )
@@ -1422,10 +1442,10 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/abseil-cpp/absl/synchronization/blocking_counter.h )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.h )
+  s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/futex.h )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h )
-  s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/waiter.cc )
@@ -1662,9 +1682,9 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/wnaf.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdh/ecdh.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdsa/ecdsa.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdsa/internal.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/hmac/hmac.c )
-  s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/md4/md4.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/md5/internal.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/md5/md5.c )
@@ -1688,6 +1708,7 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/padding.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/rsa.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/rsa_impl.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/self_check/fips.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/self_check/self_check.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/sha/internal.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/sha/sha1-altivec.c )
@@ -1774,7 +1795,6 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c )
-  s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c )
@@ -1871,6 +1891,7 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/engine.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/err.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/evp.h )
+  s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/evp_errors.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/ex_data.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/hkdf.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/hmac.h )
@@ -1919,6 +1940,7 @@ Gem::Specification.new do |s|
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/dtls_method.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/dtls_record.cc )
+  s.files += %w( third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/handoff.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/handshake.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/handshake_client.cc )
index 479bf55..2418290 100644 (file)
--- a/grpc.gyp
+++ b/grpc.gyp
         'test/core/end2end/tests/request_with_payload.cc',
         'test/core/end2end/tests/resource_quota_server.cc',
         'test/core/end2end/tests/retry.cc',
+        'test/core/end2end/tests/retry_cancel_during_delay.cc',
         'test/core/end2end/tests/retry_cancellation.cc',
         'test/core/end2end/tests/retry_disabled.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
+        'test/core/end2end/tests/retry_lb_drop.cc',
         'test/core/end2end/tests/retry_non_retriable_status.cc',
         'test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc',
         'test/core/end2end/tests/retry_recv_initial_metadata.cc',
         'test/core/end2end/tests/workaround_cronet_compression.cc',
         'test/core/end2end/tests/write_buffering.cc',
         'test/core/end2end/tests/write_buffering_at_end.cc',
+        'test/core/util/test_lb_policies.cc',
       ],
     },
     {
         'test/core/end2end/tests/request_with_payload.cc',
         'test/core/end2end/tests/resource_quota_server.cc',
         'test/core/end2end/tests/retry.cc',
+        'test/core/end2end/tests/retry_cancel_during_delay.cc',
         'test/core/end2end/tests/retry_cancellation.cc',
         'test/core/end2end/tests/retry_disabled.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
+        'test/core/end2end/tests/retry_lb_drop.cc',
         'test/core/end2end/tests/retry_non_retriable_status.cc',
         'test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc',
         'test/core/end2end/tests/retry_recv_initial_metadata.cc',
         'test/core/end2end/tests/workaround_cronet_compression.cc',
         'test/core/end2end/tests/write_buffering.cc',
         'test/core/end2end/tests/write_buffering_at_end.cc',
+        'test/core/util/test_lb_policies.cc',
       ],
     },
     {
         'absl/synchronization:synchronization',
         'absl/time:time',
         'absl/types:optional',
+        'upb',
       ],
       'sources': [
+        'src/core/ext/upb-generated/google/api/annotations.upb.c',
+        'src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c',
+        'src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c',
+        'src/core/ext/upb-generated/google/api/http.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/any.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/duration.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/empty.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/struct.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c',
+        'src/core/ext/upb-generated/google/rpc/status.upb.c',
         'src/core/lib/gpr/alloc.cc',
         'src/core/lib/gpr/atm.cc',
         'src/core/lib/gpr/cpu_iphone.cc',
         'src/core/lib/gprpp/mpscq.cc',
         'src/core/lib/gprpp/stat_posix.cc',
         'src/core/lib/gprpp/stat_windows.cc',
+        'src/core/lib/gprpp/status_helper.cc',
         'src/core/lib/gprpp/thd_posix.cc',
         'src/core/lib/gprpp/thd_windows.cc',
         'src/core/lib/gprpp/time_util.cc',
         'absl/status:statusor',
         'gpr',
         'address_sorting',
-        'upb',
       ],
       'sources': [
         'src/core/ext/filters/census/grpc_context.cc',
         'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
         'src/core/ext/filters/client_channel/resolver_registry.cc',
         'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
+        'src/core/ext/filters/client_channel/retry_filter.cc',
+        'src/core/ext/filters/client_channel/retry_service_config.cc',
         'src/core/ext/filters/client_channel/retry_throttle.cc',
         'src/core/ext/filters/client_channel/server_address.cc',
         'src/core/ext/filters/client_channel/service_config.cc',
         'src/core/ext/upb-generated/envoy/type/v3/percent.upb.c',
         'src/core/ext/upb-generated/envoy/type/v3/range.upb.c',
         'src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.c',
-        'src/core/ext/upb-generated/google/api/annotations.upb.c',
-        'src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c',
-        'src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c',
-        'src/core/ext/upb-generated/google/api/http.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/any.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/duration.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/empty.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/struct.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c',
-        'src/core/ext/upb-generated/google/rpc/status.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.c',
         'src/core/ext/xds/xds_http_fault_filter.cc',
         'src/core/ext/xds/xds_http_filters.cc',
         'src/core/ext/xds/xds_server_config_fetcher.cc',
+        'src/core/lib/address_utils/parse_address.cc',
+        'src/core/lib/address_utils/sockaddr_utils.cc',
         'src/core/lib/avl/avl.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/debug/stats.cc',
         'src/core/lib/debug/stats_data.cc',
         'src/core/lib/debug/trace.cc',
+        'src/core/lib/event_engine/slice_allocator.cc',
+        'src/core/lib/event_engine/sockaddr.cc',
         'src/core/lib/http/format_request.cc',
         'src/core/lib/http/httpcli.cc',
         'src/core/lib/http/httpcli_security_connector.cc',
         'src/core/lib/iomgr/is_epollexclusive_available.cc',
         'src/core/lib/iomgr/load_file.cc',
         'src/core/lib/iomgr/lockfree_event.cc',
-        'src/core/lib/iomgr/parse_address.cc',
-        'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
         'src/core/lib/iomgr/polling_entity.cc',
         'src/core/lib/iomgr/pollset.cc',
         'src/core/lib/iomgr/pollset_custom.cc',
         'src/core/lib/iomgr/resolve_address_posix.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
         'src/core/lib/iomgr/resource_quota.cc',
-        'src/core/lib/iomgr/sockaddr_utils.cc',
         'src/core/lib/iomgr/socket_factory_posix.cc',
         'src/core/lib/iomgr/socket_mutator.cc',
         'src/core/lib/iomgr/socket_utils_common_posix.cc',
       ],
       'sources': [
         'test/core/util/cmdline.cc',
-        'test/core/util/eval_args_mock_endpoint.cc',
         'test/core/util/fuzzer_util.cc',
         'test/core/util/grpc_profiler.cc',
         'test/core/util/histogram.cc',
       ],
       'sources': [
         'test/core/util/cmdline.cc',
-        'test/core/util/eval_args_mock_endpoint.cc',
         'test/core/util/fuzzer_util.cc',
         'test/core/util/grpc_profiler.cc',
         'test/core/util/histogram.cc',
         'absl/status:statusor',
         'gpr',
         'address_sorting',
-        'upb',
       ],
       'sources': [
         'src/core/ext/filters/census/grpc_context.cc',
         'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
         'src/core/ext/filters/client_channel/resolver_registry.cc',
         'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
+        'src/core/ext/filters/client_channel/retry_filter.cc',
+        'src/core/ext/filters/client_channel/retry_service_config.cc',
         'src/core/ext/filters/client_channel/retry_throttle.cc',
         'src/core/ext/filters/client_channel/server_address.cc',
         'src/core/ext/filters/client_channel/service_config.cc',
         'src/core/ext/transport/chttp2/transport/writing.cc',
         'src/core/ext/transport/inproc/inproc_plugin.cc',
         'src/core/ext/transport/inproc/inproc_transport.cc',
-        'src/core/ext/upb-generated/google/api/annotations.upb.c',
-        'src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c',
-        'src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c',
-        'src/core/ext/upb-generated/google/api/http.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/any.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/duration.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/empty.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/struct.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c',
-        'src/core/ext/upb-generated/google/rpc/status.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c',
         'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c',
         'src/core/ext/upb-generated/validate/validate.upb.c',
+        'src/core/lib/address_utils/parse_address.cc',
+        'src/core/lib/address_utils/sockaddr_utils.cc',
         'src/core/lib/avl/avl.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/debug/stats.cc',
         'src/core/lib/debug/stats_data.cc',
         'src/core/lib/debug/trace.cc',
+        'src/core/lib/event_engine/slice_allocator.cc',
+        'src/core/lib/event_engine/sockaddr.cc',
         'src/core/lib/http/format_request.cc',
         'src/core/lib/http/httpcli.cc',
         'src/core/lib/http/parser.cc',
         'src/core/lib/iomgr/is_epollexclusive_available.cc',
         'src/core/lib/iomgr/load_file.cc',
         'src/core/lib/iomgr/lockfree_event.cc',
-        'src/core/lib/iomgr/parse_address.cc',
-        'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
         'src/core/lib/iomgr/polling_entity.cc',
         'src/core/lib/iomgr/pollset.cc',
         'src/core/lib/iomgr/pollset_custom.cc',
         'src/core/lib/iomgr/resolve_address_posix.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
         'src/core/lib/iomgr/resource_quota.cc',
-        'src/core/lib/iomgr/sockaddr_utils.cc',
         'src/core/lib/iomgr/socket_factory_posix.cc',
         'src/core/lib/iomgr/socket_mutator.cc',
         'src/core/lib/iomgr/socket_utils_common_posix.cc',
         'third_party/boringssl-with-bazel/src/crypto/ex_data.c',
         'third_party/boringssl-with-bazel/src/crypto/fipsmodule/bcm.c',
         'third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c',
-        'third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c',
         'third_party/boringssl-with-bazel/src/crypto/hkdf/hkdf.c',
         'third_party/boringssl-with-bazel/src/crypto/hpke/hpke.c',
         'third_party/boringssl-with-bazel/src/crypto/hrss/hrss.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c',
-        'third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c',
         'third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc',
         'third_party/boringssl-with-bazel/src/ssl/dtls_method.cc',
         'third_party/boringssl-with-bazel/src/ssl/dtls_record.cc',
+        'third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc',
         'third_party/boringssl-with-bazel/src/ssl/handoff.cc',
         'third_party/boringssl-with-bazel/src/ssl/handshake.cc',
         'third_party/boringssl-with-bazel/src/ssl/handshake_client.cc',
diff --git a/include/grpc/event_engine/README.md b/include/grpc/event_engine/README.md
new file mode 100644 (file)
index 0000000..b2d4fef
--- /dev/null
@@ -0,0 +1,38 @@
+# gRPC EventEngine
+
+An EventEngine handles all cross-platform I/O, task execution, and DNS
+resolution for gRPC. A default, cross-platform implementation is provided with
+gRPC, but part of the intent here is to provide an interface for external
+integrators to bring their own functionality. This allows for integration with
+external event loops, siloing I/O and task execution between channels or
+servers, and other custom integrations that were previously unsupported.
+
+*WARNING*: This is experimental code and is subject to change.
+
+## High level expectations of an EventEngine implementation
+
+### Provide their own I/O threads
+EventEngines are expected to internally create whatever threads are required to
+perform I/O and execute callbacks. For example, an EventEngine implementation
+may want to spawn separate thread pools for polling and callback execution.
+
+### Provisioning data buffers via Slice allocation
+At a high level, gRPC provides a `ResourceQuota` system that allows gRPC to
+reclaim memory and degrade gracefully when memory reaches application-defined
+thresholds. To enable this feature, the memory allocation of read/write buffers
+within an EventEngine must be acquired in the form of Slices from
+SliceAllocators. This is covered more fully in the gRFC and code.
+
+### Documentating expectations around callback execution
+Some callbacks may be expensive to run. EventEngines should decide on and
+document whether callback execution might block polling operations. This way,
+application developers can plan accordingly (e.g., run their expensive callbacks
+on a separate thread if necessary).
+
+### Handling concurrent usage
+Assume that gRPC may use an EventEngine concurrently across multiple threads.
+
+## TODO: documentation
+
+* Example usage
+* Link to gRFC
diff --git a/include/grpc/event_engine/channel_args.h b/include/grpc/event_engine/channel_args.h
new file mode 100644 (file)
index 0000000..d809b1f
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2021 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.
+#ifndef GRPC_EVENT_ENGINE_CHANNEL_ARGS_H
+#define GRPC_EVENT_ENGINE_CHANNEL_ARGS_H
+
+#include <grpc/support/port_platform.h>
+
+namespace grpc_event_engine {
+namespace experimental {
+
+// TODO(hork): define
+class ChannelArgs;
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
+
+#endif  // GRPC_EVENT_ENGINE_CHANNEL_ARGS_H
diff --git a/include/grpc/event_engine/event_engine.h b/include/grpc/event_engine/event_engine.h
new file mode 100644 (file)
index 0000000..cdb5966
--- /dev/null
@@ -0,0 +1,336 @@
+// Copyright 2021 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.
+#ifndef GRPC_EVENT_ENGINE_EVENT_ENGINE_H
+#define GRPC_EVENT_ENGINE_EVENT_ENGINE_H
+
+#include <grpc/support/port_platform.h>
+
+#include <functional>
+#include <vector>
+
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/time/time.h"
+
+#include "grpc/event_engine/channel_args.h"
+#include "grpc/event_engine/port.h"
+#include "grpc/event_engine/slice_allocator.h"
+
+// TODO(hork): explicitly define lifetimes and ownership of all objects.
+// TODO(hork): Define the Endpoint::Write metrics collection system
+
+namespace grpc_event_engine {
+namespace experimental {
+
+////////////////////////////////////////////////////////////////////////////////
+/// The EventEngine encapsulates all platform-specific behaviors related to low
+/// level network I/O, timers, asynchronous execution, and DNS resolution.
+///
+/// This interface allows developers to provide their own event management and
+/// network stacks. Motivating uses cases for supporting custom EventEngines
+/// include the ability to hook into external event loops, and using different
+/// EventEngine instances for each channel to better insulate network I/O and
+/// callback processing from other channels.
+///
+/// A default cross-platform EventEngine instance is provided by gRPC.
+///
+/// LIFESPAN AND OWNERSHIP
+///
+/// gRPC takes shared ownership of EventEngines via std::shared_ptrs to ensure
+/// that the engines remain available until they are no longer needed. Depending
+/// on the use case, engines may live until gRPC is shut down.
+///
+/// EXAMPLE USAGE (Not yet implemented)
+///
+/// Custom EventEngines can be specified per channel, and allow configuration
+/// for both clients and servers. To set a custom EventEngine for a client
+/// channel, you can do something like the following:
+///
+///    ChannelArguments args;
+///    std::shared_ptr<EventEngine> engine = std::make_shared<MyEngine>(...);
+///    args.SetEventEngine(engine);
+///    MyAppClient client(grpc::CreateCustomChannel(
+///        "localhost:50051", grpc::InsecureChannelCredentials(), args));
+///
+/// A gRPC server can use a custom EventEngine by calling the
+/// ServerBuilder::SetEventEngine method:
+///
+///    ServerBuilder builder;
+///    std::shared_ptr<EventEngine> engine = std::make_shared<MyEngine>(...);
+///    builder.SetEventEngine(engine);
+///    std::unique_ptr<Server> server(builder.BuildAndStart());
+///    server->Wait();
+///
+////////////////////////////////////////////////////////////////////////////////
+class EventEngine {
+ public:
+  /// A basic callable function. The first argument to all callbacks is an
+  /// absl::Status indicating the status of the operation associated with this
+  /// callback. Each EventEngine method that takes a callback parameter, defines
+  /// the expected sets and meanings of statuses for that use case.
+  using Callback = std::function<void(absl::Status)>;
+  /// A callback handle, used to cancel a callback.
+  struct TaskHandle {
+    intptr_t key;
+  };
+  /// A thin wrapper around a platform-specific sockaddr type. A sockaddr struct
+  /// exists on all platforms that gRPC supports.
+  ///
+  /// Platforms are expected to provide definitions for:
+  /// * sockaddr
+  /// * sockaddr_in
+  /// * sockaddr_in6
+  class ResolvedAddress {
+   public:
+    static constexpr socklen_t MAX_SIZE_BYTES = 128;
+
+    ResolvedAddress(const sockaddr* address, socklen_t size);
+    const struct sockaddr* address() const;
+    socklen_t size() const;
+
+   private:
+    char address_[MAX_SIZE_BYTES];
+    socklen_t size_;
+  };
+
+  /// An Endpoint represents one end of a connection between a gRPC client and
+  /// server. Endpoints are created when connections are established, and
+  /// Endpoint operations are gRPC's primary means of communication.
+  ///
+  /// Endpoints must use the provided SliceAllocator for all data buffer memory
+  /// allocations. gRPC allows applications to set memory constraints per
+  /// Channel or Server, and the implementation depends on all dynamic memory
+  /// allocation being handled by the quota system.
+  class Endpoint {
+   public:
+    /// The Endpoint destructor is responsible for shutting down all connections
+    /// and invoking all pending read or write callbacks with an error status.
+    virtual ~Endpoint() = default;
+    /// Read data from the Endpoint.
+    ///
+    /// When data is available on the connection, that data is moved into the
+    /// \a buffer, and the \a on_read callback is called. The caller must ensure
+    /// that the callback has access to the buffer when executed later.
+    /// Ownership of the buffer is not transferred. Valid slices *may* be placed
+    /// into the buffer even if the callback is invoked with a non-OK Status.
+    ///
+    /// For failed read operations, implementations should pass the appropriate
+    /// statuses to \a on_read. For example, callbacks might expect to receive
+    /// DEADLINE_EXCEEDED when the deadline is exceeded, and CANCELLED on
+    /// endpoint shutdown.
+    virtual void Read(Callback on_read, SliceBuffer* buffer,
+                      absl::Time deadline) = 0;
+    /// Write data out on the connection.
+    ///
+    /// \a on_writable is called when the connection is ready for more data. The
+    /// Slices within the \a data buffer may be mutated at will by the Endpoint
+    /// until \a on_writable is called. The \a data SliceBuffer will remain
+    /// valid after calling \a Write, but its state is otherwise undefined.
+    ///
+    /// For failed write operations, implementations should pass the appropriate
+    /// statuses to \a on_writable. For example, callbacks might expect to
+    /// receive DEADLINE_EXCEEDED when the deadline is exceeded, and CANCELLED
+    /// on endpoint shutdown.
+    virtual void Write(Callback on_writable, SliceBuffer* data,
+                       absl::Time deadline) = 0;
+    // TODO(hork): define status codes for the callback
+    // TODO(hork): define cleanup operations, lifetimes, responsibilities.
+    virtual void Close(Callback on_close) = 0;
+    /// These methods return an address in the format described in DNSResolver.
+    /// The returned values are owned by the Endpoint and are expected to remain
+    /// valid for the life of the Endpoint.
+    virtual const ResolvedAddress* GetPeerAddress() const = 0;
+    virtual const ResolvedAddress* GetLocalAddress() const = 0;
+  };
+
+  /// Called when a new connection is established.
+  ///
+  /// If the connection attempt was not successful, implementations should pass
+  /// the appropriate statuses to this callback. For example, callbacks might
+  /// expect to receive DEADLINE_EXCEEDED statuses when appropriate, or
+  /// CANCELLED statuses on EventEngine shutdown.
+  using OnConnectCallback =
+      std::function<void(absl::StatusOr<std::unique_ptr<Endpoint>>)>;
+
+  /// An EventEngine Listener listens for incoming connection requests from gRPC
+  /// clients and initiates request processing once connections are established.
+  class Listener {
+   public:
+    /// Called when the listener has accepted a new client connection.
+    using AcceptCallback = std::function<void(std::unique_ptr<Endpoint>)>;
+    virtual ~Listener() = default;
+    /// Bind an address/port to this Listener.
+    ///
+    /// It is expected that multiple addresses/ports can be bound to this
+    /// Listener before Listener::Start has been called. Returns either the
+    /// bound port or an appropriate error status.
+    virtual absl::StatusOr<int> Bind(const ResolvedAddress& addr) = 0;
+    virtual absl::Status Start() = 0;
+  };
+
+  /// Factory method to create a network listener / server.
+  ///
+  /// Once a \a Listener is created and started, the \a on_accept callback will
+  /// be called once asynchronously for each established connection. Note that
+  /// unlike other callbacks, there is no status code parameter since the
+  /// callback will only be called in healthy scenarios where connections can be
+  /// accepted.
+  ///
+  /// This method may return a non-OK status immediately if an error was
+  /// encountered in any synchronous steps required to create the Listener. In
+  /// this case, \a on_shutdown will never be called.
+  ///
+  /// If this method returns a Listener, then \a on_shutdown will be invoked
+  /// exactly once, when the Listener is shut down. The status passed to it will
+  /// indicate if there was a problem during shutdown.
+  ///
+  /// The provided \a SliceAllocatorFactory is used to create \a SliceAllocators
+  /// for Endpoint construction.
+  virtual absl::StatusOr<std::unique_ptr<Listener>> CreateListener(
+      Listener::AcceptCallback on_accept, Callback on_shutdown,
+      const ChannelArgs& args,
+      SliceAllocatorFactory slice_allocator_factory) = 0;
+  /// Creates a client network connection to a remote network listener.
+  ///
+  /// \a Connect may return an error status immediately if there was a failure
+  /// in the synchronous part of establishing a connection. In that event, the
+  /// \a on_connect callback *will not* have been executed. Otherwise, it is
+  /// expected that the \a on_connect callback will be asynchronously executed
+  /// exactly once by the EventEngine.
+  ///
+  /// Implementation Note: it is important that the \a slice_allocator be used
+  /// for all read/write buffer allocations in the EventEngine implementation.
+  /// This allows gRPC's \a ResourceQuota system to monitor and control memory
+  /// usage with graceful degradation mechanisms. Please see the \a
+  /// SliceAllocator API for more information.
+  virtual absl::Status Connect(OnConnectCallback on_connect,
+                               const ResolvedAddress& addr,
+                               const ChannelArgs& args,
+                               SliceAllocator slice_allocator,
+                               absl::Time deadline) = 0;
+
+  /// The DNSResolver that provides asynchronous resolution.
+  class DNSResolver {
+   public:
+    /// A task handle for DNS Resolution requests.
+    struct LookupTaskHandle {
+      intptr_t key;
+    };
+    /// A DNS SRV record type.
+    struct SRVRecord {
+      std::string host;
+      int port = 0;
+      int priority = 0;
+      int weight = 0;
+    };
+    /// Called with the collection of sockaddrs that were resolved from a given
+    /// target address.
+    using LookupHostnameCallback =
+        std::function<void(absl::StatusOr<std::vector<ResolvedAddress>>)>;
+    /// Called with a collection of SRV records.
+    using LookupSRVCallback =
+        std::function<void(absl::StatusOr<std::vector<SRVRecord>>)>;
+    /// Called with the result of a TXT record lookup
+    using LookupTXTCallback = std::function<void(absl::StatusOr<std::string>)>;
+
+    virtual ~DNSResolver() = default;
+
+    /// Asynchronously resolve an address.
+    ///
+    /// \a default_port may be a non-numeric named service port, and will only
+    /// be used if \a address does not already contain a port component.
+    ///
+    /// When the lookup is complete, the \a on_resolve callback will be invoked
+    /// with a status indicating the success or failure of the lookup.
+    /// Implementations should pass the appropriate statuses to the callback.
+    /// For example, callbacks might expect to receive DEADLINE_EXCEEDED when
+    /// the deadline is exceeded or CANCELLED if the lookup was cancelled.
+    virtual LookupTaskHandle LookupHostname(LookupHostnameCallback on_resolve,
+                                            absl::string_view address,
+                                            absl::string_view default_port,
+                                            absl::Time deadline) = 0;
+    /// Asynchronously perform an SRV record lookup.
+    ///
+    /// \a on_resolve has the same meaning and expectations as \a
+    /// LookupHostname's \a on_resolve callback.
+    virtual LookupTaskHandle LookupSRV(LookupSRVCallback on_resolve,
+                                       absl::string_view name,
+                                       absl::Time deadline) = 0;
+    /// Asynchronously perform a TXT record lookup.
+    ///
+    /// \a on_resolve has the same meaning and expectations as \a
+    /// LookupHostname's \a on_resolve callback.
+    virtual LookupTaskHandle LookupTXT(LookupTXTCallback on_resolve,
+                                       absl::string_view name,
+                                       absl::Time deadline) = 0;
+    /// Cancel an asynchronous lookup operation.
+    virtual void TryCancelLookup(LookupTaskHandle handle) = 0;
+  };
+
+  virtual ~EventEngine() = default;
+
+  // TODO(hork): define return status codes
+  /// Retrieves an instance of a DNSResolver.
+  virtual absl::StatusOr<std::unique_ptr<DNSResolver>> GetDNSResolver() = 0;
+
+  /// Intended for future expansion of Task run functionality.
+  struct RunOptions {};
+  // TODO(hork): consider recommendation to make TaskHandle an output arg
+  /// Run a callback as soon as possible.
+  ///
+  /// The \a fn callback's \a status argument is used to indicate whether it was
+  /// executed normally. For example, the status may be CANCELLED if
+  /// \a TryCancel was called, or if the EventEngine is being shut down.
+  virtual TaskHandle Run(Callback fn, RunOptions opts) = 0;
+  /// Synonymous with scheduling an alarm to run at time \a when.
+  ///
+  /// The callback \a fn will execute when either when time \a when arrives
+  /// (receiving status OK), or when the \a fn is cancelled (reveiving status
+  /// CANCELLED). The callback is guaranteed to be called exactly once.
+  virtual TaskHandle RunAt(absl::Time when, Callback fn, RunOptions opts) = 0;
+  /// Immediately tries to cancel a callback.
+  /// Note that this is a "best effort" cancellation. No guarantee is made that
+  /// the callback will be cancelled, the call could be in any stage.
+  ///
+  /// There are three scenarios in which we may cancel a scheduled function:
+  ///   1. We cancel the execution before it has run.
+  ///   2. The callback has already run.
+  ///   3. We can't cancel it because it is "in flight".
+  ///
+  /// In all cases, the cancellation is still considered successful, the
+  /// callback will be run exactly once from either cancellation or from its
+  /// activation.
+  virtual void TryCancel(TaskHandle handle) = 0;
+  /// Immediately run all callbacks with status indicating the shutdown. Every
+  /// EventEngine is expected to shut down exactly once. No new callbacks/tasks
+  /// should be scheduled after shutdown has begun, no new connections should be
+  /// created.
+  ///
+  /// If the \a on_shutdown_complete callback is given a non-OK status, errors
+  /// are expected to be unrecoverable. For example, an implementation could
+  /// warn callers about leaks if memory cannot be freed within a certain
+  /// timeframe.
+  virtual void Shutdown(Callback on_shutdown_complete) = 0;
+};
+
+/// Lazily instantiate and return a default global EventEngine instance if no
+/// custom instance is provided. If a custom EventEngine is provided for every
+/// channel/server via ChannelArgs, this method should never be called, and the
+/// default instance will never be instantiated.
+std::shared_ptr<EventEngine> GetDefaultEventEngine();
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
+
+#endif  // GRPC_EVENT_ENGINE_EVENT_ENGINE_H
diff --git a/include/grpc/event_engine/port.h b/include/grpc/event_engine/port.h
new file mode 100644 (file)
index 0000000..c24b8f9
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2021 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.
+#ifndef GRPC_EVENT_ENGINE_PORT_H
+#define GRPC_EVENT_ENGINE_PORT_H
+
+#include <grpc/support/port_platform.h>
+
+// Platform-specific sockaddr includes
+#ifdef GRPC_UV
+#include <uv.h>
+#elif defined(GPR_ANDROID) || defined(GPR_LINUX) || defined(GPR_APPLE) ||   \
+    defined(GPR_FREEBSD) || defined(GPR_OPENBSD) || defined(GPR_SOLARIS) || \
+    defined(GPR_AIX) || defined(GPR_NACL) || defined(GPR_FUCHSIA) ||        \
+    defined(GRPC_POSIX_SOCKET)
+#define GRPC_EVENT_ENGINE_POSIX
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#elif defined(GPR_WINDOWS)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+// must be included after the above
+#include <mswsock.h>
+#else
+#error UNKNOWN PLATFORM
+#endif
+
+#endif  // GRPC_EVENT_ENGINE_PORT_H
diff --git a/include/grpc/event_engine/slice_allocator.h b/include/grpc/event_engine/slice_allocator.h
new file mode 100644 (file)
index 0000000..4370cd5
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2021 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.
+#ifndef GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H
+#define GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include <functional>
+
+#include "absl/status/status.h"
+
+// forward-declaring an internal struct, not used publicly.
+struct grpc_resource_quota;
+struct grpc_resource_user;
+
+namespace grpc_event_engine {
+namespace experimental {
+
+// TODO(nnoble): forward declared here, needs definition.
+class SliceBuffer;
+
+class SliceAllocator {
+ public:
+  // gRPC-internal constructor
+  explicit SliceAllocator(grpc_resource_user* user);
+  // Not copyable
+  SliceAllocator(SliceAllocator& other) = delete;
+  SliceAllocator& operator=(const SliceAllocator& other) = delete;
+  // Moveable
+  SliceAllocator(SliceAllocator&& other) = default;
+  SliceAllocator& operator=(SliceAllocator&& other) = default;
+  ~SliceAllocator();
+
+  using AllocateCallback =
+      std::function<void(absl::Status, SliceBuffer* buffer)>;
+  // TODO(hork): explain what happens under resource exhaustion.
+  /// Requests \a size bytes from gRPC, and populates \a dest with the allocated
+  /// slices. Ownership of the \a SliceBuffer is not transferred.
+  absl::Status Allocate(size_t size, SliceBuffer* dest,
+                        SliceAllocator::AllocateCallback cb);
+
+ private:
+  grpc_resource_user* resource_user_;
+};
+
+class SliceAllocatorFactory {
+ public:
+  // gRPC-internal constructor
+  explicit SliceAllocatorFactory(grpc_resource_quota* quota);
+  // Not copyable
+  SliceAllocatorFactory(SliceAllocatorFactory& other) = delete;
+  SliceAllocatorFactory& operator=(const SliceAllocatorFactory& other) = delete;
+  // Moveable
+  SliceAllocatorFactory(SliceAllocatorFactory&& other) = default;
+  SliceAllocatorFactory& operator=(SliceAllocatorFactory&& other) = default;
+  ~SliceAllocatorFactory();
+
+  /// On Endpoint creation, call \a CreateSliceAllocator with the name of the
+  /// endpoint peer (a URI string, most likely). Note: \a peer_name must outlive
+  /// the Endpoint.
+  SliceAllocator CreateSliceAllocator(absl::string_view peer_name);
+
+ private:
+  grpc_resource_quota* resource_quota_;
+};
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
+
+#endif  // GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H
index 156d4db..f4408e1 100644 (file)
@@ -414,7 +414,7 @@ GRPCAPI void grpc_server_register_completion_queue(grpc_server* server,
 // There might be more methods added later, so users should take care to memset
 // this to 0 before using it.
 typedef struct {
-  void (*on_serving_status_change)(void* user_data, const char* uri,
+  void (*on_serving_status_update)(void* user_data, const char* uri,
                                    grpc_status_code code,
                                    const char* error_message);
   void* user_data;
@@ -424,7 +424,7 @@ typedef struct grpc_server_config_fetcher grpc_server_config_fetcher;
 
 /** EXPERIMENTAL.  Creates an xDS config fetcher. */
 GRPCAPI grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create(
-    grpc_server_xds_status_notifier notifier);
+    grpc_server_xds_status_notifier notifier, const grpc_channel_args* args);
 
 /** EXPERIMENTAL.  Destroys a config fetcher. */
 GRPCAPI void grpc_server_config_fetcher_destroy(
index a62f767..4d7f078 100644 (file)
@@ -29,10 +29,24 @@ extern "C" {
 #define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
 #define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
 #define GRPC_X509_PEM_CERT_PROPERTY_NAME "x509_pem_cert"
+// Please note that internally, we just faithfully pass whatever value we got by
+// calling SSL_get_peer_cert_chain() in OpenSSL/BoringSSL. This will mean in
+// OpenSSL, the following conditions might apply:
+// 1. On the client side, this property returns the full certificate chain. On
+// the server side, this property will return the certificate chain without the
+// leaf certificate. Application can use GRPC_X509_PEM_CERT_PROPERTY_NAME to
+// get the peer leaf certificate.
+// 2. If the session is resumed, this property could be empty for OpenSSL (but
+// not for BoringSSL).
+// For more, please refer to the official OpenSSL manual:
+// https://www.openssl.org/docs/man1.1.0/man3/SSL_get_peer_cert_chain.html.
 #define GRPC_X509_PEM_CERT_CHAIN_PROPERTY_NAME "x509_pem_cert_chain"
 #define GRPC_SSL_SESSION_REUSED_PROPERTY "ssl_session_reused"
 #define GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME "security_level"
+#define GRPC_PEER_DNS_PROPERTY_NAME "peer_dns"
 #define GRPC_PEER_SPIFFE_ID_PROPERTY_NAME "peer_spiffe_id"
+#define GRPC_PEER_EMAIL_PROPERTY_NAME "peer_email"
+#define GRPC_PEER_IP_PROPERTY_NAME "peer_ip"
 
 /** Environment variable that points to the default SSL roots file. This file
    must be a PEM encoded file with all the roots such as the one that can be
index d67a9e9..9cf6d83 100644 (file)
@@ -353,6 +353,17 @@ typedef struct {
 /* Timeout in milliseconds to use for calls to the grpclb load balancer.
    If 0 or unset, the balancer calls will have no deadline. */
 #define GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS "grpc.grpclb_call_timeout_ms"
+/* Specifies the xDS bootstrap config as a JSON string.
+   FOR TESTING PURPOSES ONLY -- DO NOT USE IN PRODUCTION.
+   This option allows controlling the bootstrap configuration on a
+   per-channel basis, which is useful in tests.  However, this results
+   in having a separate xDS client instance per channel rather than
+   using the global instance, which is not the intended way to use xDS.
+   Currently, this will (a) add unnecessary load on the xDS server and
+   (b) break use of CSDS, and there may be additional side effects in
+   the future. */
+#define GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG \
+  "grpc.TEST_ONLY_DO_NOT_USE_IN_PROD.xds_bootstrap_config"
 /* Timeout in milliseconds to wait for the serverlist from the grpclb load
    balancer before using fallback backend addresses from the resolver.
    If 0, enter fallback mode immediately. Default value is 10000. */
index cd0310d..387639b 100644 (file)
 #endif
 #endif  // GPR_ABSEIL_SYNC
 
+/*
+ * Defines GRPC_ERROR_IS_ABSEIL_STATUS to use absl::Status for grpc_error_handle
+ */
+// #define GRPC_ERROR_IS_ABSEIL_STATUS 1
+
 /* Get windows.h included everywhere (we need it) */
 #if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
 #ifndef WIN32_LEAN_AND_MEAN
index 06c1e97..40606e5 100644 (file)
@@ -2,6 +2,15 @@
 framework module grpc {
   umbrella header "grpc.h"
 
+header "byte_buffer.h"
+  header "byte_buffer_reader.h"
+  header "census.h"
+  header "compression.h"
+  header "fork.h"
+  header "grpc.h"
+  header "grpc_posix.h"
+  header "grpc_security.h"
+  header "grpc_security_constants.h"
   header "impl/codegen/atm.h"
   header "impl/codegen/byte_buffer.h"
   header "impl/codegen/byte_buffer_reader.h"
@@ -19,6 +28,10 @@ framework module grpc {
   header "impl/codegen/sync.h"
   header "impl/codegen/sync_abseil.h"
   header "impl/codegen/sync_generic.h"
+  header "load_reporting.h"
+  header "slice.h"
+  header "slice_buffer.h"
+  header "status.h"
   header "support/alloc.h"
   header "support/atm.h"
   header "support/cpu.h"
@@ -31,22 +44,9 @@ framework module grpc {
   header "support/sync_generic.h"
   header "support/thd_id.h"
   header "support/time.h"
-  header "byte_buffer.h"
-  header "byte_buffer_reader.h"
-  header "census.h"
-  header "compression.h"
-  header "fork.h"
-  header "grpc.h"
-  header "grpc_posix.h"
-  header "grpc_security.h"
-  header "grpc_security_constants.h"
-  header "load_reporting.h"
-  header "slice.h"
-  header "slice_buffer.h"
-  header "status.h"
   header "support/workaround_list.h"
 
-  textual header "impl/codegen/atm_gcc_atomic.h"
+textual header "impl/codegen/atm_gcc_atomic.h"
   textual header "impl/codegen/atm_gcc_sync.h"
   textual header "impl/codegen/atm_windows.h"
   textual header "impl/codegen/sync_custom.h"
index 5e67c64..65cc46d 100644 (file)
@@ -114,7 +114,7 @@ class Channel final : public ::grpc::ChannelInterface,
   // with this channel (if any). It is set on the first call to CallbackCQ().
   // It is _not owned_ by the channel; ownership belongs with its internal
   // shutdown callback tag (invoked when the CQ is fully shutdown).
-  ::grpc::CompletionQueue* callback_cq_ = nullptr;
+  std::atomic<CompletionQueue*> callback_cq_{nullptr};
 
   std::vector<
       std::unique_ptr<::grpc::experimental::ClientInterceptorFactoryInterface>>
index e4576af..e9564c3 100644 (file)
@@ -22,6 +22,7 @@
 #include <functional>
 
 #include <grpcpp/client_context.h>
+#include <grpcpp/impl/codegen/stub_options.h>
 #include <grpcpp/impl/rpc_method.h>
 #include <grpcpp/support/async_stream.h>
 #include <grpcpp/support/async_unary_call.h>
@@ -53,7 +54,8 @@ class TemplatedGenericStub final {
   std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
   PrepareCall(ClientContext* context, const std::string& method,
               ::grpc::CompletionQueue* cq) {
-    return CallInternal(channel_.get(), context, method, cq, false, nullptr);
+    return CallInternal(channel_.get(), context, method, /*options=*/{}, cq,
+                        false, nullptr);
   }
 
   /// Setup a unary call to a named method \a method using \a context, and don't
@@ -67,6 +69,7 @@ class TemplatedGenericStub final {
         internal::ClientAsyncResponseReaderHelper::Create<ResponseType>(
             channel_.get(), cq,
             grpc::internal::RpcMethod(method.c_str(),
+                                      /*suffix_for_stats=*/nullptr,
                                       grpc::internal::RpcMethod::NORMAL_RPC),
             context, request));
   }
@@ -80,7 +83,8 @@ class TemplatedGenericStub final {
   std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> Call(
       ClientContext* context, const std::string& method,
       ::grpc::CompletionQueue* cq, void* tag) {
-    return CallInternal(channel_.get(), context, method, cq, true, tag);
+    return CallInternal(channel_.get(), context, method, /*options=*/{}, cq,
+                        true, tag);
   }
 
 #ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
@@ -89,7 +93,7 @@ class TemplatedGenericStub final {
   void UnaryCall(ClientContext* context, const std::string& method,
                  const RequestType* request, ResponseType* response,
                  std::function<void(grpc::Status)> on_completion) {
-    UnaryCallInternal(context, method, request, response,
+    UnaryCallInternal(context, method, /*options=*/{}, request, response,
                       std::move(on_completion));
   }
 
@@ -100,7 +104,8 @@ class TemplatedGenericStub final {
   void PrepareUnaryCall(ClientContext* context, const std::string& method,
                         const RequestType* request, ResponseType* response,
                         ClientUnaryReactor* reactor) {
-    PrepareUnaryCallInternal(context, method, request, response, reactor);
+    PrepareUnaryCallInternal(context, method, /*options=*/{}, request, response,
+                             reactor);
   }
 
   /// Setup a call to a named method \a method using \a context and tied to
@@ -109,7 +114,7 @@ class TemplatedGenericStub final {
   void PrepareBidiStreamingCall(
       ClientContext* context, const std::string& method,
       ClientBidiReactor<RequestType, ResponseType>* reactor) {
-    PrepareBidiStreamingCallInternal(context, method, reactor);
+    PrepareBidiStreamingCallInternal(context, method, /*options=*/{}, reactor);
   }
 #endif
 
@@ -123,9 +128,10 @@ class TemplatedGenericStub final {
     /// Setup and start a unary call to a named method \a method using
     /// \a context and specifying the \a request and \a response buffers.
     void UnaryCall(ClientContext* context, const std::string& method,
-                   const RequestType* request, ResponseType* response,
+                   StubOptions options, const RequestType* request,
+                   ResponseType* response,
                    std::function<void(grpc::Status)> on_completion) {
-      stub_->UnaryCallInternal(context, method, request, response,
+      stub_->UnaryCallInternal(context, method, options, request, response,
                                std::move(on_completion));
     }
 
@@ -134,19 +140,20 @@ class TemplatedGenericStub final {
     /// Like any other reactor-based RPC, it will not be activated until
     /// StartCall is invoked on its reactor.
     void PrepareUnaryCall(ClientContext* context, const std::string& method,
-                          const RequestType* request, ResponseType* response,
-                          ClientUnaryReactor* reactor) {
-      stub_->PrepareUnaryCallInternal(context, method, request, response,
-                                      reactor);
+                          StubOptions options, const RequestType* request,
+                          ResponseType* response, ClientUnaryReactor* reactor) {
+      stub_->PrepareUnaryCallInternal(context, method, options, request,
+                                      response, reactor);
     }
 
     /// Setup a call to a named method \a method using \a context and tied to
     /// \a reactor . Like any other bidi streaming RPC, it will not be activated
     /// until StartCall is invoked on its reactor.
     void PrepareBidiStreamingCall(
-        ClientContext* context, const std::string& method,
+        ClientContext* context, const std::string& method, StubOptions options,
         ClientBidiReactor<RequestType, ResponseType>* reactor) {
-      stub_->PrepareBidiStreamingCallInternal(context, method, reactor);
+      stub_->PrepareBidiStreamingCallInternal(context, method, options,
+                                              reactor);
     }
 
    private:
@@ -162,48 +169,50 @@ class TemplatedGenericStub final {
   std::shared_ptr<grpc::ChannelInterface> channel_;
 
   void UnaryCallInternal(ClientContext* context, const std::string& method,
-                         const RequestType* request, ResponseType* response,
+                         StubOptions options, const RequestType* request,
+                         ResponseType* response,
                          std::function<void(grpc::Status)> on_completion) {
     internal::CallbackUnaryCall(
         channel_.get(),
-        grpc::internal::RpcMethod(method.c_str(),
+        grpc::internal::RpcMethod(method.c_str(), options.suffix_for_stats(),
                                   grpc::internal::RpcMethod::NORMAL_RPC),
         context, request, response, std::move(on_completion));
   }
 
   void PrepareUnaryCallInternal(ClientContext* context,
-                                const std::string& method,
+                                const std::string& method, StubOptions options,
                                 const RequestType* request,
                                 ResponseType* response,
                                 ClientUnaryReactor* reactor) {
     internal::ClientCallbackUnaryFactory::Create<RequestType, ResponseType>(
         channel_.get(),
-        grpc::internal::RpcMethod(method.c_str(),
+        grpc::internal::RpcMethod(method.c_str(), options.suffix_for_stats(),
                                   grpc::internal::RpcMethod::NORMAL_RPC),
         context, request, response, reactor);
   }
 
   void PrepareBidiStreamingCallInternal(
-      ClientContext* context, const std::string& method,
+      ClientContext* context, const std::string& method, StubOptions options,
       ClientBidiReactor<RequestType, ResponseType>* reactor) {
     internal::ClientCallbackReaderWriterFactory<RequestType, ResponseType>::
         Create(channel_.get(),
                grpc::internal::RpcMethod(
-                   method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
+                   method.c_str(), options.suffix_for_stats(),
+                   grpc::internal::RpcMethod::BIDI_STREAMING),
                context, reactor);
   }
 
   std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
   CallInternal(grpc::ChannelInterface* channel, ClientContext* context,
-               const std::string& method, ::grpc::CompletionQueue* cq,
-               bool start, void* tag) {
+               const std::string& method, StubOptions options,
+               ::grpc::CompletionQueue* cq, bool start, void* tag) {
     return std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>(
         internal::ClientAsyncReaderWriterFactory<RequestType, ResponseType>::
-            Create(
-                channel, cq,
-                grpc::internal::RpcMethod(
-                    method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
-                context, start, tag));
+            Create(channel, cq,
+                   grpc::internal::RpcMethod(
+                       method.c_str(), options.suffix_for_stats(),
+                       grpc::internal::RpcMethod::BIDI_STREAMING),
+                   context, start, tag));
   }
 };
 
index acf1d85..952a7ba 100644 (file)
@@ -464,12 +464,13 @@ class ClientContext {
                 const std::shared_ptr<::grpc::Channel>& channel);
 
   grpc::experimental::ClientRpcInfo* set_client_rpc_info(
-      const char* method, grpc::internal::RpcMethod::RpcType type,
-      grpc::ChannelInterface* channel,
+      const char* method, const char* suffix_for_stats,
+      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_ = grpc::experimental::ClientRpcInfo(this, type, method,
+                                                  suffix_for_stats, channel);
     rpc_info_.RegisterInterceptors(creators, interceptor_pos);
     return &rpc_info_;
   }
index 78be1f7..ec78074 100644 (file)
@@ -87,6 +87,10 @@ class ClientRpcInfo {
   /// Return the fully-specified method name
   const char* method() const { return method_; }
 
+  /// Return an identifying suffix for the client stub, or nullptr if one wasn't
+  /// specified.
+  const char* suffix_for_stats() const { return suffix_for_stats_; }
+
   /// Return a pointer to the channel on which the RPC is being sent
   ChannelInterface* channel() { return channel_; }
 
@@ -116,10 +120,12 @@ class ClientRpcInfo {
 
   // Constructor will only be called from ClientContext
   ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type,
-                const char* method, grpc::ChannelInterface* channel)
+                const char* method, const char* suffix_for_stats,
+                grpc::ChannelInterface* channel)
       : ctx_(ctx),
         type_(static_cast<Type>(type)),
         method_(method),
+        suffix_for_stats_(suffix_for_stats),
         channel_(channel) {}
 
   // Move assignment should only be used by ClientContext
@@ -162,6 +168,7 @@ class ClientRpcInfo {
   // TODO(yashykt): make type_ const once move-assignment is deleted
   Type type_{Type::UNKNOWN};
   const char* method_ = nullptr;
+  const char* suffix_for_stats_ = nullptr;
   grpc::ChannelInterface* channel_ = nullptr;
   std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
   bool hijacked_ = false;
index 756f4aa..fb093f5 100644 (file)
@@ -357,9 +357,12 @@ class SplitServerStreamingHandler
 template <::grpc::StatusCode code>
 class ErrorMethodHandler : public ::grpc::internal::MethodHandler {
  public:
+  explicit ErrorMethodHandler(const std::string& message) : message_(message) {}
+
   template <class T>
-  static void FillOps(::grpc::ServerContextBase* context, T* ops) {
-    ::grpc::Status status(code, "");
+  static void FillOps(::grpc::ServerContextBase* context,
+                      const std::string& message, T* ops) {
+    ::grpc::Status status(code, message);
     if (!context->sent_initial_metadata_) {
       ops->SendInitialMetadata(&context->initial_metadata_,
                                context->initial_metadata_flags());
@@ -375,7 +378,7 @@ class ErrorMethodHandler : public ::grpc::internal::MethodHandler {
     ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
                                 ::grpc::internal::CallOpServerSendStatus>
         ops;
-    FillOps(param.server_context, &ops);
+    FillOps(param.server_context, message_, &ops);
     param.call->PerformOps(&ops);
     param.call->cq()->Pluck(&ops);
   }
@@ -388,6 +391,9 @@ class ErrorMethodHandler : public ::grpc::internal::MethodHandler {
     }
     return nullptr;
   }
+
+ private:
+  const std::string message_;
 };
 
 typedef ErrorMethodHandler<::grpc::StatusCode::UNIMPLEMENTED>
index 394a29b..388784e 100644 (file)
@@ -36,21 +36,40 @@ class RpcMethod {
   };
 
   RpcMethod(const char* name, RpcType type)
-      : name_(name), method_type_(type), channel_tag_(nullptr) {}
+      : name_(name),
+        suffix_for_stats_(nullptr),
+        method_type_(type),
+        channel_tag_(nullptr) {}
+
+  RpcMethod(const char* name, const char* suffix_for_stats, RpcType type)
+      : name_(name),
+        suffix_for_stats_(suffix_for_stats),
+        method_type_(type),
+        channel_tag_(nullptr) {}
 
   RpcMethod(const char* name, RpcType type,
             const std::shared_ptr<ChannelInterface>& channel)
       : name_(name),
+        suffix_for_stats_(nullptr),
+        method_type_(type),
+        channel_tag_(channel->RegisterMethod(name)) {}
+
+  RpcMethod(const char* name, const char* suffix_for_stats, RpcType type,
+            const std::shared_ptr<ChannelInterface>& channel)
+      : name_(name),
+        suffix_for_stats_(suffix_for_stats),
         method_type_(type),
         channel_tag_(channel->RegisterMethod(name)) {}
 
   const char* name() const { return name_; }
+  const char* suffix_for_stats() const { return suffix_for_stats_; }
   RpcType method_type() const { return method_type_; }
   void SetMethodType(RpcType type) { method_type_ = type; }
   void* channel_tag() const { return channel_tag_; }
 
  private:
   const char* const name_;
+  const char* const suffix_for_stats_;
   RpcType method_type_;
   void* const channel_tag_;
 };
index a56695a..30509c2 100644 (file)
 namespace grpc {
 
 /// Useful interface for generated stubs
-class StubOptions {};
+class StubOptions {
+ public:
+  StubOptions() = default;
+  explicit StubOptions(const char* suffix_for_stats)
+      : suffix_for_stats_(suffix_for_stats) {}
+
+  void set_suffix_for_stats(const char* suffix_for_stats) {
+    suffix_for_stats_ = suffix_for_stats;
+  }
+  const char* suffix_for_stats() const { return suffix_for_stats_; }
+
+ private:
+  const char* suffix_for_stats_ = nullptr;
+};
 
 }  // namespace grpc
 
index 7f367dc..a69e64b 100644 (file)
@@ -380,7 +380,7 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
   // with this server (if any). It is set on the first call to CallbackCQ().
   // It is _not owned_ by the server; ownership belongs with its internal
   // shutdown callback tag (invoked when the CQ is fully shutdown).
-  CompletionQueue* callback_cq_ ABSL_GUARDED_BY(mu_) = nullptr;
+  std::atomic<CompletionQueue*> callback_cq_{nullptr};
 
   // List of CQs passed in by user that must be Shutdown only after Server is
   // Shutdown.  Even though this is only used with NDEBUG, instantiate it in all
index 28e8cfd..00e82a1 100644 (file)
@@ -357,6 +357,9 @@ class ServerBuilder {
     server_config_fetcher_ = server_config_fetcher;
   }
 
+  /// Experimental API, subject to change.
+  virtual ChannelArguments BuildChannelArgs();
+
  private:
   friend class ::grpc::testing::ServerBuilderPluginTest;
 
index e33595d..deffad3 100644 (file)
@@ -90,6 +90,8 @@ class MockClientAsyncResponseReader
  public:
   MockClientAsyncResponseReader() = default;
 
+  /// ClientAsyncResponseReaderInterface
+  MOCK_METHOD0_T(StartCall, void());
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD3_T(Finish, void(R*, Status*, void*));
 };
@@ -100,6 +102,7 @@ class MockClientAsyncReader : public ClientAsyncReaderInterface<R> {
   MockClientAsyncReader() = default;
 
   /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(StartCall, void(void*));
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD2_T(Finish, void(Status*, void*));
 
@@ -113,11 +116,13 @@ class MockClientAsyncWriter : public ::grpc::ClientAsyncWriterInterface<W> {
   MockClientAsyncWriter() = default;
 
   /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(StartCall, void(void*));
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD2_T(Finish, void(Status*, void*));
 
   /// AsyncWriterInterface
   MOCK_METHOD2_T(Write, void(const W&, void*));
+  MOCK_METHOD3_T(Write, void(const W&, ::grpc::WriteOptions, void*));
 
   /// ClientAsyncWriterInterface
   MOCK_METHOD1_T(WritesDone, void(void*));
@@ -130,11 +135,13 @@ class MockClientAsyncReaderWriter
   MockClientAsyncReaderWriter() = default;
 
   /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(StartCall, void(void*));
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD2_T(Finish, void(Status*, void*));
 
   /// AsyncWriterInterface
   MOCK_METHOD2_T(Write, void(const W&, void*));
+  MOCK_METHOD3_T(Write, void(const W&, ::grpc::WriteOptions, void*));
 
   /// AsyncReaderInterface
   MOCK_METHOD2_T(Read, void(R*, void*));
index 96f1d5a..076c377 100644 (file)
@@ -32,9 +32,12 @@ class XdsServerServingStatusNotifierInterface {
 
   // \a uri contains the listening target associated with the notification. Note
   // that a single target provided to XdsServerBuilder can get resolved to
-  // multiple listening addresses. Status::OK signifies that the server is
-  // serving, while a non-OK status signifies that the server is not serving.
-  virtual void OnServingStatusChange(std::string uri, grpc::Status status) = 0;
+  // multiple listening addresses.
+  // The callback is invoked each time there is an update to the serving status.
+  // The API does not provide any guarantees around duplicate updates.
+  // Status::OK signifies that the server is serving, while a non-OK status
+  // signifies that the server is not serving.
+  virtual void OnServingStatusUpdate(std::string uri, grpc::Status status) = 0;
 };
 
 class XdsServerBuilder : public ::grpc::ServerBuilder {
@@ -47,22 +50,24 @@ class XdsServerBuilder : public ::grpc::ServerBuilder {
     notifier_ = notifier;
   }
 
-  std::unique_ptr<Server> BuildAndStart() override {
+ private:
+  // Called at the beginning of BuildAndStart().
+  ChannelArguments BuildChannelArgs() override {
+    ChannelArguments args = ServerBuilder::BuildChannelArgs();
+    grpc_channel_args c_channel_args = args.c_channel_args();
     grpc_server_config_fetcher* fetcher = grpc_server_config_fetcher_xds_create(
-        {OnServingStatusChange, notifier_});
-    if (fetcher == nullptr) return nullptr;
-    set_fetcher(fetcher);
-    return ServerBuilder::BuildAndStart();
+        {OnServingStatusUpdate, notifier_}, &c_channel_args);
+    if (fetcher != nullptr) set_fetcher(fetcher);
+    return args;
   }
 
- private:
-  static void OnServingStatusChange(void* user_data, const char* uri,
+  static void OnServingStatusUpdate(void* user_data, const char* uri,
                                     grpc_status_code code,
                                     const char* error_message) {
     if (user_data == nullptr) return;
     XdsServerServingStatusNotifierInterface* notifier =
         static_cast<XdsServerServingStatusNotifierInterface*>(user_data);
-    notifier->OnServingStatusChange(
+    notifier->OnServingStatusUpdate(
         uri, grpc::Status(static_cast<StatusCode>(code), error_message));
   }
 
index 540616f..c8935d3 100644 (file)
@@ -13,8 +13,8 @@
  <date>2019-09-24</date>
  <time>16:06:07</time>
  <version>
-  <release>1.37.1</release>
-  <api>1.37.1</api>
+  <release>1.38.0</release>
+  <api>1.38.0</api>
  </version>
  <stability>
   <release>stable</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>Apache 2.0</license>
  <notes>
-- gRPC Core 1.37.1 update
+- gRPC Core 1.38.0 update
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
     <file baseinstalldir="/" name="include/grpc/byte_buffer_reader.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/census.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/compression.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/event_engine/channel_args.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/event_engine/event_engine.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/event_engine/port.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/event_engine/slice_allocator.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/fork.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc_posix.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_result_parsing.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_result_parsing.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_service_config.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_service_config.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/server_address.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/xds/xds_http_filters.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/xds/xds_http_filters.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/xds/xds_server_config_fetcher.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/address_utils/parse_address.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/address_utils/parse_address.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/address_utils/sockaddr_utils.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/address_utils/sockaddr_utils.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/avl/avl.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/avl/avl.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/backoff/backoff.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/debug/stats_data.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/debug/trace.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/debug/trace.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/event_engine/slice_allocator.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/event_engine/sockaddr.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/alloc.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/alloc.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/arena.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/stat.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/stat_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/stat_windows.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gprpp/status_helper.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gprpp/status_helper.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/sync.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/thd.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/thd_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/nameser.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/parse_address.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/parse_address.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/poller/eventmanager_libuv.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/poller/eventmanager_libuv.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_custom.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_windows.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/socket_factory_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/socket_factory_posix.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/const_init.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/dynamic_annotations.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/atomic_hook.h" role="src" />
-    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/bits.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/cycleclock.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/cycleclock.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/direct_mmap.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/city.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/hash.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/hash.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/wyhash.cc" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/wyhash.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/memory/memory.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/meta/type_traits.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/bits.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/int128.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/int128.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/internal/bits.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/internal/representation.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/status/internal/status_internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/status/internal/statusor_internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/status/status.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/charconv_bigint.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/charconv_parse.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_internal.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/escaping.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/escaping.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/memutil.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/str_format/parser.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/str_join_internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/str_split_internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/string_constant.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/utf8.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/utf8.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/match.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/blocking_counter.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/futex.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h" role="src" />
-    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/waiter.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/wnaf.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdh/ecdh.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdsa/ecdsa.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdsa/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/hmac/hmac.c" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/md4/md4.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/md5/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/md5/md5.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/padding.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/rsa.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/rsa_impl.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/self_check/fips.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/self_check/self_check.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/sha/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/sha/sha1-altivec.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/engine.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/err.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/evp.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/evp_errors.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/ex_data.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/hkdf.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/hmac.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/dtls_method.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/dtls_record.cc" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/handoff.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/handshake.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/handshake_client.cc" role="src" />
index 257efad..6c73dd3 100644 (file)
   - third_party/abseil-cpp/absl/base/internal/scheduling_mode.h
   name: absl/base:base_internal
   src: []
-- cmake_target: absl::bits
-  deps:
-  - absl/base:config
-  - absl/base:core_headers
-  headers:
-  - third_party/abseil-cpp/absl/base/internal/bits.h
-  name: absl/base:bits
-  src: []
 - cmake_target: absl::config
   deps: []
   headers:
   src: []
 - cmake_target: absl::endian
   deps:
+  - absl/base:base
   - absl/base:config
   - absl/base:core_headers
   headers:
   name: absl/base:throw_delegate
   src:
   - third_party/abseil-cpp/absl/base/internal/throw_delegate.cc
+- cmake_target: absl::cleanup
+  deps:
+  - absl/base:config
+  - absl/base:core_headers
+  - absl/cleanup:cleanup_internal
+  headers:
+  - third_party/abseil-cpp/absl/cleanup/cleanup.h
+  name: absl/cleanup:cleanup
+  src: []
+- cmake_target: absl::cleanup_internal
+  deps:
+  - absl/base:base_internal
+  - absl/base:core_headers
+  - absl/utility:utility
+  headers:
+  - third_party/abseil-cpp/absl/cleanup/internal/cleanup.h
+  name: absl/cleanup:cleanup_internal
+  src: []
 - cmake_target: absl::btree
   deps:
   - absl/base:core_headers
   src: []
 - cmake_target: absl::raw_hash_set
   deps:
-  - absl/base:bits
   - absl/base:config
   - absl/base:core_headers
   - absl/base:endian
   - absl/container:layout
   - absl/memory:memory
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/utility:utility
   headers:
   - third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
   - absl/utility:utility
   headers:
   - third_party/abseil-cpp/absl/flags/internal/flag.h
+  - third_party/abseil-cpp/absl/flags/internal/sequence_lock.h
   name: absl/flags:flag_internal
   src:
   - third_party/abseil-cpp/absl/flags/internal/flag.cc
   - third_party/abseil-cpp/absl/hash/internal/city.cc
 - cmake_target: absl::hash
   deps:
+  - absl/base:config
   - absl/base:core_headers
   - absl/base:endian
   - absl/container:fixed_array
   - absl/hash:city
+  - absl/hash:wyhash
   - absl/meta:type_traits
   - absl/numeric:int128
   - absl/strings:strings
   name: absl/hash:hash
   src:
   - third_party/abseil-cpp/absl/hash/internal/hash.cc
+- cmake_target: absl::wyhash
+  deps:
+  - absl/base:config
+  - absl/base:endian
+  - absl/numeric:int128
+  headers:
+  - third_party/abseil-cpp/absl/hash/internal/wyhash.h
+  name: absl/hash:wyhash
+  src:
+  - third_party/abseil-cpp/absl/hash/internal/wyhash.cc
 - cmake_target: absl::memory
   deps:
   - absl/base:core_headers
   - third_party/abseil-cpp/absl/meta/type_traits.h
   name: absl/meta:type_traits
   src: []
+- cmake_target: absl::bits
+  deps:
+  - absl/base:config
+  - absl/base:core_headers
+  headers:
+  - third_party/abseil-cpp/absl/numeric/bits.h
+  - third_party/abseil-cpp/absl/numeric/internal/bits.h
+  name: absl/numeric:bits
+  src: []
 - cmake_target: absl::int128
   deps:
-  - absl/base:bits
   - absl/base:config
   - absl/base:core_headers
+  - absl/numeric:bits
   headers:
   - third_party/abseil-cpp/absl/numeric/int128.h
   - third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc
   name: absl/numeric:int128
   src:
   - third_party/abseil-cpp/absl/numeric/int128.cc
+- cmake_target: absl::numeric_representation
+  deps:
+  - absl/base:config
+  headers:
+  - third_party/abseil-cpp/absl/numeric/internal/representation.h
+  name: absl/numeric:representation
+  src: []
 - cmake_target: absl::random_internal_distribution_caller
   deps:
   - absl/base:config
   src: []
 - cmake_target: absl::random_internal_fastmath
   deps:
-  - absl/base:bits
+  - absl/numeric:bits
   headers:
   - third_party/abseil-cpp/absl/random/internal/fastmath.h
   name: absl/random/internal:fastmath
   src: []
 - cmake_target: absl::random_internal_generate_real
   deps:
-  - absl/base:bits
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/random/internal:fastmath
   - absl/random/internal:traits
   headers:
   deps:
   - absl/base:config
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/numeric:int128
   - absl/random/internal:fastmath
   - absl/random/internal:iostream_state_saver
   - third_party/abseil-cpp/absl/random/internal/randen.cc
 - cmake_target: absl::random_internal_randen_engine
   deps:
+  - absl/base:endian
   - absl/meta:type_traits
   - absl/random/internal:iostream_state_saver
   - absl/random/internal:randen
   src: []
 - cmake_target: absl::random_internal_wide_multiply
   deps:
-  - absl/base:bits
   - absl/base:config
+  - absl/numeric:bits
   - absl/numeric:int128
   - absl/random/internal:traits
   headers:
   - absl/base:config
   - absl/base:core_headers
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/random/internal:distribution_caller
   - absl/random/internal:fast_uniform_bits
   - absl/random/internal:fastmath
 - cmake_target: absl::cord
   deps:
   - absl/base:base_internal
+  - absl/base:config
+  - absl/base:core_headers
+  - absl/base:endian
+  - absl/base:raw_logging_internal
+  - absl/base:throw_delegate
   - absl/container:compressed_tuple
+  - absl/container:inlined_vector
+  - absl/container:layout
   - absl/meta:type_traits
   - absl/strings:strings
   headers:
   - third_party/abseil-cpp/absl/strings/internal/cord_internal.h
+  - third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h
+  - third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h
+  - third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h
   name: absl/strings:cord_internal
-  src: []
+  src:
+  - third_party/abseil-cpp/absl/strings/internal/cord_internal.cc
+  - third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc
 - cmake_target: absl::strings_internal
   deps:
   - absl/base:config
   src: []
 - cmake_target: absl::str_format_internal
   deps:
-  - absl/base:bits
   - absl/base:config
   - absl/base:core_headers
   - absl/functional:function_ref
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/numeric:int128
+  - absl/numeric:representation
   - absl/strings:strings
   - absl/types:optional
   - absl/types:span
 - cmake_target: absl::strings
   deps:
   - absl/base:base
-  - absl/base:bits
   - absl/base:config
   - absl/base:core_headers
   - absl/base:endian
   - absl/base:throw_delegate
   - absl/memory:memory
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/numeric:int128
   - absl/strings:internal
   headers:
   - third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h
   - third_party/abseil-cpp/absl/strings/internal/str_join_internal.h
   - third_party/abseil-cpp/absl/strings/internal/str_split_internal.h
+  - third_party/abseil-cpp/absl/strings/internal/string_constant.h
   - third_party/abseil-cpp/absl/strings/match.h
   - third_party/abseil-cpp/absl/strings/numbers.h
   - third_party/abseil-cpp/absl/strings/str_cat.h
   - third_party/abseil-cpp/absl/synchronization/barrier.h
   - third_party/abseil-cpp/absl/synchronization/blocking_counter.h
   - third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.h
-  - third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc
+  - third_party/abseil-cpp/absl/synchronization/internal/futex.h
   - third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h
   - third_party/abseil-cpp/absl/synchronization/internal/waiter.h
   - third_party/abseil-cpp/absl/synchronization/mutex.h
index 40d458c..1991903 100644 (file)
@@ -1,4 +1,4 @@
-// generated by generate_boringssl_prefix_header.sh on BoringSSL commit: 1a7359455220f7010def8c63f7c7e041ce6707c6
+// generated by generate_boringssl_prefix_header.sh on BoringSSL commit: 688fc5cf5428868679d2ae1072cad81055752068
 
 // Copyright (c) 2018, Google Inc.
 //
 #define SSL_CTX_set1_chain BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_chain)
 #define SSL_CTX_set1_curves BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_curves)
 #define SSL_CTX_set1_curves_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_curves_list)
+#define SSL_CTX_set1_ech_server_config_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_ech_server_config_list)
 #define SSL_CTX_set1_param BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_param)
 #define SSL_CTX_set1_sigalgs BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_sigalgs)
 #define SSL_CTX_set1_sigalgs_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_sigalgs_list)
 #define SSL_CTX_set_ex_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_ex_data)
 #define SSL_CTX_set_false_start_allowed_without_alpn BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_false_start_allowed_without_alpn)
 #define SSL_CTX_set_grease_enabled BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_grease_enabled)
-#define SSL_CTX_set_ignore_tls13_downgrade BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_ignore_tls13_downgrade)
 #define SSL_CTX_set_info_callback BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_info_callback)
 #define SSL_CTX_set_keylog_callback BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_keylog_callback)
 #define SSL_CTX_set_max_cert_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_max_cert_list)
 #define SSL_CTX_use_certificate_chain_file BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_use_certificate_chain_file)
 #define SSL_CTX_use_certificate_file BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_use_certificate_file)
 #define SSL_CTX_use_psk_identity_hint BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_use_psk_identity_hint)
+#define SSL_ECH_SERVER_CONFIG_LIST_add BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_ECH_SERVER_CONFIG_LIST_add)
+#define SSL_ECH_SERVER_CONFIG_LIST_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_ECH_SERVER_CONFIG_LIST_free)
+#define SSL_ECH_SERVER_CONFIG_LIST_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_ECH_SERVER_CONFIG_LIST_new)
+#define SSL_ECH_SERVER_CONFIG_LIST_up_ref BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_ECH_SERVER_CONFIG_LIST_up_ref)
 #define SSL_SESSION_copy_without_early_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_SESSION_copy_without_early_data)
 #define SSL_SESSION_early_data_capable BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_SESSION_early_data_capable)
 #define SSL_SESSION_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_SESSION_free)
 #define SSL_is_init_finished BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_init_finished)
 #define SSL_is_server BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_server)
 #define SSL_is_signature_algorithm_rsa_pss BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_signature_algorithm_rsa_pss)
-#define SSL_is_tls13_downgrade BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_tls13_downgrade)
 #define SSL_is_token_binding_negotiated BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_token_binding_negotiated)
 #define SSL_key_update BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_key_update)
 #define SSL_library_init BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_library_init)
 #define SSL_read BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_read)
 #define SSL_renegotiate BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_renegotiate)
 #define SSL_renegotiate_pending BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_renegotiate_pending)
+#define SSL_request_handshake_hints BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_request_handshake_hints)
 #define SSL_reset_early_data_reject BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_reset_early_data_reject)
 #define SSL_select_next_proto BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_select_next_proto)
 #define SSL_send_fatal_alert BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_send_fatal_alert)
+#define SSL_serialize_capabilities BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_serialize_capabilities)
+#define SSL_serialize_handshake_hints BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_serialize_handshake_hints)
 #define SSL_session_reused BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_session_reused)
 #define SSL_set0_chain BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set0_chain)
 #define SSL_set0_client_CAs BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set0_client_CAs)
 #define SSL_set_enforce_rsa_key_usage BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_enforce_rsa_key_usage)
 #define SSL_set_ex_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_ex_data)
 #define SSL_set_fd BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_fd)
-#define SSL_set_ignore_tls13_downgrade BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_ignore_tls13_downgrade)
+#define SSL_set_handshake_hints BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_handshake_hints)
 #define SSL_set_info_callback BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_info_callback)
 #define SSL_set_jdk11_workaround BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_jdk11_workaround)
 #define SSL_set_max_cert_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_max_cert_list)
 #define ECDSA_do_sign BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_do_sign)
 #define ECDSA_do_verify BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_do_verify)
 #define ECDSA_sign BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_sign)
+#define ECDSA_sign_with_nonce_and_leak_private_key_for_testing BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_sign_with_nonce_and_leak_private_key_for_testing)
 #define ECDSA_size BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_size)
 #define ECDSA_verify BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_verify)
 #define EC_GFp_mont_method BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GFp_mont_method)
 #define EC_GROUP_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_free)
 #define EC_GROUP_get0_generator BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get0_generator)
 #define EC_GROUP_get0_order BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get0_order)
+#define EC_GROUP_get_asn1_flag BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get_asn1_flag)
 #define EC_GROUP_get_cofactor BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get_cofactor)
 #define EC_GROUP_get_curve_GFp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get_curve_GFp)
 #define EC_GROUP_get_curve_name BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get_curve_name)
 #define EVP_EncryptUpdate BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_EncryptUpdate)
 #define EVP_HPKE_CTX_cleanup BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_cleanup)
 #define EVP_HPKE_CTX_export BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_export)
+#define EVP_HPKE_CTX_get_aead_id BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_get_aead_id)
+#define EVP_HPKE_CTX_get_kdf_id BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_get_kdf_id)
 #define EVP_HPKE_CTX_init BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_init)
 #define EVP_HPKE_CTX_max_overhead BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_max_overhead)
 #define EVP_HPKE_CTX_open BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_open)
 #define EVP_add_digest BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_add_digest)
 #define EVP_aead_aes_128_cbc_sha1_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_cbc_sha1_tls)
 #define EVP_aead_aes_128_cbc_sha1_tls_implicit_iv BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_cbc_sha1_tls_implicit_iv)
-#define EVP_aead_aes_128_cbc_sha256_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_cbc_sha256_tls)
 #define EVP_aead_aes_128_ccm_bluetooth BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_ccm_bluetooth)
 #define EVP_aead_aes_128_ccm_bluetooth_8 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_ccm_bluetooth_8)
 #define EVP_aead_aes_128_ctr_hmac_sha256 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_ctr_hmac_sha256)
 #define EVP_aead_aes_192_gcm BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_192_gcm)
 #define EVP_aead_aes_256_cbc_sha1_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_cbc_sha1_tls)
 #define EVP_aead_aes_256_cbc_sha1_tls_implicit_iv BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_cbc_sha1_tls_implicit_iv)
-#define EVP_aead_aes_256_cbc_sha256_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_cbc_sha256_tls)
-#define EVP_aead_aes_256_cbc_sha384_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_cbc_sha384_tls)
 #define EVP_aead_aes_256_ctr_hmac_sha256 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_ctr_hmac_sha256)
 #define EVP_aead_aes_256_gcm BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_gcm)
 #define EVP_aead_aes_256_gcm_randnonce BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_gcm_randnonce)
 #define EVP_rc2_cbc BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_rc2_cbc)
 #define EVP_rc4 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_rc4)
 #define EVP_sha1 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha1)
+#define EVP_sha1_final_with_secret_suffix BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha1_final_with_secret_suffix)
 #define EVP_sha224 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha224)
 #define EVP_sha256 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha256)
 #define EVP_sha384 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha384)
 #define EXTENDED_KEY_USAGE_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EXTENDED_KEY_USAGE_new)
 #define FIPS_mode BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, FIPS_mode)
 #define FIPS_mode_set BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, FIPS_mode_set)
+#define FIPS_read_counter BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, FIPS_read_counter)
 #define GENERAL_NAMES_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, GENERAL_NAMES_free)
 #define GENERAL_NAMES_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, GENERAL_NAMES_it)
 #define GENERAL_NAMES_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, GENERAL_NAMES_new)
 #define X509_ALGOR_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ALGOR_new)
 #define X509_ALGOR_set0 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ALGOR_set0)
 #define X509_ALGOR_set_md BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ALGOR_set_md)
-#define X509_ATTRIBUTE_SET_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ATTRIBUTE_SET_it)
 #define X509_ATTRIBUTE_count BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ATTRIBUTE_count)
 #define X509_ATTRIBUTE_create BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ATTRIBUTE_create)
 #define X509_ATTRIBUTE_create_by_NID BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ATTRIBUTE_create_by_NID)
 #define X509_CERT_AUX_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CERT_AUX_new)
 #define X509_CERT_AUX_print BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CERT_AUX_print)
 #define X509_CINF_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_free)
-#define X509_CINF_get_signature BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_get_signature)
 #define X509_CINF_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_it)
 #define X509_CINF_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_new)
-#define X509_CINF_set_modified BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_set_modified)
 #define X509_CRL_INFO_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CRL_INFO_free)
 #define X509_CRL_INFO_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CRL_INFO_it)
 #define X509_CRL_INFO_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CRL_INFO_new)
 #define X509_PUBKEY_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_free)
 #define X509_PUBKEY_get BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_get)
 #define X509_PUBKEY_get0_param BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_get0_param)
+#define X509_PUBKEY_get0_public_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_get0_public_key)
 #define X509_PUBKEY_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_it)
 #define X509_PUBKEY_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_new)
 #define X509_PUBKEY_set BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_set)
 #define X509_REQ_get_attr_by_NID BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_attr_by_NID)
 #define X509_REQ_get_attr_by_OBJ BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_attr_by_OBJ)
 #define X509_REQ_get_attr_count BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_attr_count)
-#define X509_REQ_get_extension_nids BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_extension_nids)
 #define X509_REQ_get_extensions BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_extensions)
 #define X509_REQ_get_pubkey BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_pubkey)
 #define X509_REQ_get_signature_nid BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_signature_nid)
 #define X509_REQ_print BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_print)
 #define X509_REQ_print_ex BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_print_ex)
 #define X509_REQ_print_fp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_print_fp)
-#define X509_REQ_set_extension_nids BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_set_extension_nids)
 #define X509_REQ_set_pubkey BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_set_pubkey)
 #define X509_REQ_set_subject_name BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_set_subject_name)
 #define X509_REQ_set_version BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_set_version)
 #define X509_REQ_sign BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_sign)
 #define X509_REQ_sign_ctx BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_sign_ctx)
-#define X509_REQ_to_X509 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_to_X509)
 #define X509_REQ_verify BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_verify)
 #define X509_REVOKED_add1_ext_i2d BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REVOKED_add1_ext_i2d)
 #define X509_REVOKED_add_ext BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REVOKED_add_ext)
 #define X509_get1_email BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get1_email)
 #define X509_get1_ocsp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get1_ocsp)
 #define X509_get_X509_PUBKEY BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_X509_PUBKEY)
-#define X509_get_cert_info BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_cert_info)
 #define X509_get_default_cert_area BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_default_cert_area)
 #define X509_get_default_cert_dir BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_default_cert_dir)
 #define X509_get_default_cert_dir_env BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_default_cert_dir_env)
 #define asn1_refcount_dec_and_test_zero BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_refcount_dec_and_test_zero)
 #define asn1_refcount_set_one BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_refcount_set_one)
 #define asn1_set_choice_selector BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_set_choice_selector)
+#define asn1_type_value_as_pointer BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_type_value_as_pointer)
 #define asn1_utctime_to_tm BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_utctime_to_tm)
 #define beeu_mod_inverse_vartime BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, beeu_mod_inverse_vartime)
 #define bio_clear_socket_error BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bio_clear_socket_error)
 #define ec_set_to_safe_point BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ec_set_to_safe_point)
 #define ec_simple_scalar_inv0_montgomery BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ec_simple_scalar_inv0_montgomery)
 #define ec_simple_scalar_to_montgomery_inv_vartime BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ec_simple_scalar_to_montgomery_inv_vartime)
+#define ecdsa_sign_with_nonce_for_known_answer_test BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ecdsa_sign_with_nonce_for_known_answer_test)
 #define ecp_nistz256_avx2_select_w7 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ecp_nistz256_avx2_select_w7)
 #define ecp_nistz256_mul_mont BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ecp_nistz256_mul_mont)
 #define ecp_nistz256_neg BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ecp_nistz256_neg)
index 1024d78..c8dff73 100644 (file)
@@ -1557,7 +1557,8 @@ void PrintHeaderService(grpc_generator::Printer* printer,
   printer->Indent();
   printer->Print(
       "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& "
-      "channel);\n");
+      "channel, const ::grpc::StubOptions& options = "
+      "::grpc::StubOptions());\n");
   for (int i = 0; i < service->method_count(); ++i) {
     PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
   }
@@ -2163,12 +2164,13 @@ void PrintSourceService(grpc_generator::Printer* printer,
                  "const ::grpc::StubOptions& options) {\n"
                  "  (void)options;\n"
                  "  std::unique_ptr< $ns$$Service$::Stub> stub(new "
-                 "$ns$$Service$::Stub(channel));\n"
+                 "$ns$$Service$::Stub(channel, options));\n"
                  "  return stub;\n"
                  "}\n\n");
   printer->Print(*vars,
                  "$ns$$Service$::Stub::Stub(const std::shared_ptr< "
-                 "::grpc::ChannelInterface>& channel)\n");
+                 "::grpc::ChannelInterface>& channel, const "
+                 "::grpc::StubOptions& options)\n");
   printer->Indent();
   printer->Print(": channel_(channel)");
   for (int i = 0; i < service->method_count(); ++i) {
@@ -2187,12 +2189,13 @@ void PrintSourceService(grpc_generator::Printer* printer,
     } else {
       (*vars)["StreamingType"] = "BIDI_STREAMING";
     }
-    printer->Print(*vars,
-                   ", rpcmethod_$Method$_("
-                   "$prefix$$Service$_method_names[$Idx$], "
-                   "::grpc::internal::RpcMethod::$StreamingType$, "
-                   "channel"
-                   ")\n");
+    printer->Print(
+        *vars,
+        ", rpcmethod_$Method$_("
+        "$prefix$$Service$_method_names[$Idx$], options.suffix_for_stats(),"
+        "::grpc::internal::RpcMethod::$StreamingType$, "
+        "channel"
+        ")\n");
   }
   printer->Print("{}\n\n");
   printer->Outdent();
index b2a26e5..28bbebd 100644 (file)
@@ -131,34 +131,177 @@ void PrintMethod(const MethodDescriptor* method, Printer* out) {
   out->Print("}\n\n");
 }
 
-// Prints out the service descriptor object
-void PrintService(const ServiceDescriptor* service,
-                  const std::string& class_suffix, Printer* out) {
+void PrintServerMethod(const MethodDescriptor* method, Printer* out) {
   map<std::string, std::string> vars;
+  const Descriptor* input_type = method->input_type();
+  const Descriptor* output_type = method->output_type();
+  vars["service_name"] = method->service()->full_name();
+  vars["method_name"] = method->name();
+  vars["input_type_id"] =
+      MessageIdentifierName(GeneratedClassName(input_type), input_type->file());
+  vars["output_type_id"] = MessageIdentifierName(
+      GeneratedClassName(output_type), output_type->file());
+
   out->Print("/**\n");
-  out->Print(GetPHPComments(service, " *").c_str());
-  out->Print(" */\n");
-  vars["name"] = GetPHPServiceClassname(service, class_suffix);
-  out->Print(vars, "class $name$ extends \\Grpc\\BaseStub {\n\n");
+  out->Print(GetPHPComments(method, " *").c_str());
+
+  const char* method_template;
+  if (method->client_streaming() && method->server_streaming()) {
+    method_template =
+        " * @param \\Grpc\\ServerCallReader $$reader read client request data "
+        "of \\$input_type_id$\n"
+        " * @param \\Grpc\\ServerCallWriter $$writer write response data of "
+        "\\$output_type_id$\n"
+        " * @param \\Grpc\\ServerContext $$context server request context\n"
+        " * @return void\n"
+        " */\n"
+        "public function $method_name$(\n"
+        "    \\Grpc\\ServerCallReader $$reader,\n"
+        "    \\Grpc\\ServerCallWriter $$writer,\n"
+        "    \\Grpc\\ServerContext $$context\n"
+        "): void {\n"
+        "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
+        "    $$writer->finish();\n"
+        "}\n\n";
+  } else if (method->client_streaming()) {
+    method_template =
+        " * @param \\Grpc\\ServerCallReader $$reader read client request data "
+        "of \\$input_type_id$\n"
+        " * @param \\Grpc\\ServerContext $$context server request context\n"
+        " * @return \\$output_type_id$ for response data, null if if error "
+        "occured\n"
+        " *     initial metadata (if any) and status (if not ok) should be set "
+        "to $$context\n"
+        " */\n"
+        "public function $method_name$(\n"
+        "    \\Grpc\\ServerCallReader $$reader,\n"
+        "    \\Grpc\\ServerContext $$context\n"
+        "): ?\\$output_type_id$ {\n"
+        "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
+        "    return null;\n"
+        "}\n\n";
+  } else if (method->server_streaming()) {
+    method_template =
+        " * @param \\$input_type_id$ $$request client request\n"
+        " * @param \\Grpc\\ServerCallWriter $$writer write response data of "
+        "\\$output_type_id$\n"
+        " * @param \\Grpc\\ServerContext $$context server request context\n"
+        " * @return void\n"
+        " */\n"
+        "public function $method_name$(\n"
+        "    \\$input_type_id$ $$request,\n"
+        "    \\Grpc\\ServerCallWriter $$writer,\n"
+        "    \\Grpc\\ServerContext $$context\n"
+        "): void {\n"
+        "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
+        "    $$writer->finish();\n"
+        "}\n\n";
+  } else {
+    method_template =
+        " * @param \\$input_type_id$ $$request client request\n"
+        " * @param \\Grpc\\ServerContext $$context server request context\n"
+        " * @return \\$output_type_id$ for response data, null if if error "
+        "occured\n"
+        " *     initial metadata (if any) and status (if not ok) should be set "
+        "to $$context\n"
+        " */\n"
+        "public function $method_name$(\n"
+        "    \\$input_type_id$ $$request,\n"
+        "    \\Grpc\\ServerContext $$context\n"
+        "): ?\\$output_type_id$ {\n"
+        "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
+        "    return null;\n"
+        "}\n\n";
+  }
+  out->Print(vars, method_template);
+}
+
+void PrintServerMethodDescriptors(const ServiceDescriptor* service,
+                                  Printer* out) {
+  map<std::string, std::string> vars;
+  vars["service_name"] = service->full_name();
+
+  out->Print(
+      "/**\n"
+      " * Get the method descriptors of the service for server registration\n"
+      " *\n"
+      " * @return array of \\Grpc\\MethodDescriptor for the service methods\n"
+      " */\n"
+      "public final function getMethodDescriptors(): array\n{\n");
   out->Indent();
   out->Indent();
-  out->Print(
-      "/**\n * @param string $$hostname hostname\n"
-      " * @param array $$opts channel options\n"
-      " * @param \\Grpc\\Channel $$channel (optional) re-use channel "
-      "object\n */\n"
-      "public function __construct($$hostname, $$opts, "
-      "$$channel = null) {\n");
+  out->Print("return [\n");
   out->Indent();
   out->Indent();
-  out->Print("parent::__construct($$hostname, $$opts, $$channel);\n");
+  for (int i = 0; i < service->method_count(); i++) {
+    auto method = service->method(i);
+    auto input_type = method->input_type();
+    vars["method_name"] = method->name();
+    vars["input_type_id"] = MessageIdentifierName(
+        GeneratedClassName(input_type), input_type->file());
+    if (method->client_streaming() && method->server_streaming()) {
+      vars["call_type"] = "BIDI_STREAMING_CALL";
+    } else if (method->client_streaming()) {
+      vars["call_type"] = "CLIENT_STREAMING_CALL";
+    } else if (method->server_streaming()) {
+      vars["call_type"] = "SERVER_STREAMING_CALL";
+    } else {
+      vars["call_type"] = "UNARY_CALL";
+    }
+    out->Print(
+        vars,
+        "'/$service_name$/$method_name$' => new \\Grpc\\MethodDescriptor(\n"
+        "    $$this,\n"
+        "    '$method_name$',\n"
+        "    '\\$input_type_id$',\n"
+        "    \\Grpc\\MethodDescriptor::$call_type$\n"
+        "),\n");
+  }
+  out->Outdent();
+  out->Outdent();
+  out->Print("];\n");
   out->Outdent();
   out->Outdent();
   out->Print("}\n\n");
+}
+
+// Prints out the service descriptor object
+void PrintService(const ServiceDescriptor* service,
+                  const std::string& class_suffix, bool is_server,
+                  Printer* out) {
+  map<std::string, std::string> vars;
+  out->Print("/**\n");
+  out->Print(GetPHPComments(service, " *").c_str());
+  out->Print(" */\n");
+  vars["name"] = GetPHPServiceClassname(service, class_suffix, is_server);
+  vars["extends"] = is_server ? "" : "extends \\Grpc\\BaseStub ";
+  out->Print(vars, "class $name$ $extends${\n\n");
+  out->Indent();
+  out->Indent();
+  if (!is_server) {
+    out->Print(
+        "/**\n * @param string $$hostname hostname\n"
+        " * @param array $$opts channel options\n"
+        " * @param \\Grpc\\Channel $$channel (optional) re-use channel object\n"
+        " */\n"
+        "public function __construct($$hostname, $$opts, "
+        "$$channel = null) {\n");
+    out->Indent();
+    out->Indent();
+    out->Print("parent::__construct($$hostname, $$opts, $$channel);\n");
+    out->Outdent();
+    out->Outdent();
+    out->Print("}\n\n");
+  }
   for (int i = 0; i < service->method_count(); i++) {
-    std::string method_name =
-        grpc_generator::LowercaseFirstLetter(service->method(i)->name());
-    PrintMethod(service->method(i), out);
+    if (is_server) {
+      PrintServerMethod(service->method(i), out);
+    } else {
+      PrintMethod(service->method(i), out);
+    }
+  }
+  if (is_server) {
+    PrintServerMethodDescriptors(service, out);
   }
   out->Outdent();
   out->Outdent();
@@ -168,7 +311,7 @@ void PrintService(const ServiceDescriptor* service,
 
 std::string GenerateFile(const FileDescriptor* file,
                          const ServiceDescriptor* service,
-                         const std::string& class_suffix) {
+                         const std::string& class_suffix, bool is_server) {
   std::string output;
   {
     StringOutputStream output_stream(&output);
@@ -188,7 +331,7 @@ std::string GenerateFile(const FileDescriptor* file,
     vars["package"] = php_namespace;
     out.Print(vars, "namespace $package$;\n\n");
 
-    PrintService(service, class_suffix, &out);
+    PrintService(service, class_suffix, is_server, &out);
   }
   return output;
 }
index aa6d20c..f775c8f 100644 (file)
@@ -25,7 +25,8 @@ namespace grpc_php_generator {
 
 std::string GenerateFile(const grpc::protobuf::FileDescriptor* file,
                          const grpc::protobuf::ServiceDescriptor* service,
-                         const std::string& class_suffix);
+                         const std::string& class_suffix,
+                         bool is_server = false);
 
 }  // namespace grpc_php_generator
 
index 24560e4..a4617df 100644 (file)
@@ -28,8 +28,10 @@ namespace grpc_php_generator {
 
 inline std::string GetPHPServiceClassname(
     const grpc::protobuf::ServiceDescriptor* service,
-    const std::string& class_suffix) {
-  return service->name() + (class_suffix == "" ? "Client" : class_suffix);
+    const std::string& class_suffix, bool is_server) {
+  return service->name() +
+         (class_suffix == "" ? (is_server ? "" : "Client") : class_suffix) +
+         (is_server ? "Stub" : "");
 }
 
 // ReplaceAll replaces all instances of search with replace in s.
@@ -46,7 +48,7 @@ inline std::string ReplaceAll(std::string s, const std::string& search,
 inline std::string GetPHPServiceFilename(
     const grpc::protobuf::FileDescriptor* file,
     const grpc::protobuf::ServiceDescriptor* service,
-    const std::string& class_suffix) {
+    const std::string& class_suffix, bool is_server) {
   std::ostringstream oss;
   if (file->options().has_php_namespace()) {
     oss << ReplaceAll(file->options().php_namespace(), "\\", "/");
@@ -58,8 +60,8 @@ inline std::string GetPHPServiceFilename(
           << grpc_generator::CapitalizeFirstLetter(tokens[i]);
     }
   }
-  return oss.str() + "/" + GetPHPServiceClassname(service, class_suffix) +
-         ".php";
+  return oss.str() + "/" +
+         GetPHPServiceClassname(service, class_suffix, is_server) + ".php";
 }
 
 // Get leading or trailing comments in a string. Comment lines start with "// ".
index c1be387..7d4e4ce 100644 (file)
@@ -48,10 +48,13 @@ class PHPGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
     std::vector<std::pair<std::string, std::string> > options;
     ParseGeneratorParameter(parameter, &options);
 
+    bool generate_server = false;
     std::string class_suffix;
     for (size_t i = 0; i < options.size(); ++i) {
       if (options[i].first == "class_suffix") {
         class_suffix = options[i].second;
+      } else if (options[i].first == "generate_server") {
+        generate_server = true;
       } else {
         *error = "unsupported options: " + options[i].first;
         return false;
@@ -59,20 +62,32 @@ class PHPGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
     }
 
     for (int i = 0; i < file->service_count(); i++) {
-      std::string code = GenerateFile(file, file->service(i), class_suffix);
-
-      // Get output file name
-      std::string file_name =
-          GetPHPServiceFilename(file, file->service(i), class_suffix);
-
-      std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
-          context->Open(file_name));
-      grpc::protobuf::io::CodedOutputStream coded_out(output.get());
-      coded_out.WriteRaw(code.data(), code.size());
+      GenerateService(file, file->service(i), class_suffix, false, context);
+      if (generate_server) {
+        GenerateService(file, file->service(i), class_suffix, true, context);
+      }
     }
 
     return true;
   }
+
+ private:
+  void GenerateService(
+      const grpc::protobuf::FileDescriptor* file,
+      const grpc::protobuf::ServiceDescriptor* service,
+      const std::string& class_suffix, bool is_server,
+      grpc::protobuf::compiler::GeneratorContext* context) const {
+    std::string code = GenerateFile(file, service, class_suffix, is_server);
+
+    // Get output file name
+    std::string file_name =
+        GetPHPServiceFilename(file, service, class_suffix, is_server);
+
+    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
+        context->Open(file_name));
+    grpc::protobuf::io::CodedOutputStream coded_out(output.get());
+    coded_out.WriteRaw(code.data(), code.size());
+  }
 };
 
 int main(int argc, char* argv[]) {
index 1b77089..ad7f892 100644 (file)
@@ -89,7 +89,7 @@ static void backup_poller_shutdown_unref(backup_poller* p) {
   }
 }
 
-static void done_poller(void* arg, grpc_error* /*error*/) {
+static void done_poller(void* arg, grpc_error_handle /*error*/) {
   backup_poller_shutdown_unref(static_cast<backup_poller*>(arg));
 }
 
@@ -112,7 +112,7 @@ static void g_poller_unref() {
   }
 }
 
-static void run_poller(void* arg, grpc_error* error) {
+static void run_poller(void* arg, grpc_error_handle error) {
   backup_poller* p = static_cast<backup_poller*>(arg);
   if (error != GRPC_ERROR_NONE) {
     if (error != GRPC_ERROR_CANCELLED) {
@@ -127,7 +127,7 @@ static void run_poller(void* arg, grpc_error* error) {
     backup_poller_shutdown_unref(p);
     return;
   }
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_pollset_work(p->pollset, nullptr, grpc_core::ExecCtx::Get()->Now());
   gpr_mu_unlock(p->pollset_mu);
   GRPC_LOG_IF_ERROR("Run client channel backup poller", err);
index 4ebb976..e5ec5c5 100644 (file)
@@ -1,28 +1,23 @@
-/*
- *
- * 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.
- *
- */
+//
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 
 #include <grpc/support/port_platform.h>
 
 #include "src/core/lib/surface/channel.h"
 
-#include <inttypes.h>
-
-#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
 #include "src/core/ext/filters/client_channel/client_channel.h"
 
 grpc_connectivity_state grpc_channel_check_connectivity_state(
     grpc_channel* channel, int try_to_connect) {
-  /* forward through to the underlying client channel */
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
-  grpc_connectivity_state state;
   GRPC_API_TRACE(
       "grpc_channel_check_connectivity_state(channel=%p, try_to_connect=%d)", 2,
       (channel, try_to_connect));
-  if (GPR_LIKELY(client_channel_elem->filter == &grpc_client_channel_filter)) {
-    state = grpc_client_channel_check_connectivity_state(client_channel_elem,
-                                                         try_to_connect);
-
-    return state;
+  // Forward through to the underlying client channel.
+  grpc_core::ClientChannel* client_channel =
+      grpc_core::ClientChannel::GetFromChannel(channel);
+  if (GPR_UNLIKELY(client_channel == nullptr)) {
+    gpr_log(GPR_ERROR,
+            "grpc_channel_check_connectivity_state called on something that is "
+            "not a client channel");
+    return GRPC_CHANNEL_SHUTDOWN;
   }
-  gpr_log(GPR_ERROR,
-          "grpc_channel_check_connectivity_state called on something that is "
-          "not a client channel, but '%s'",
-          client_channel_elem->filter->name);
+  return client_channel->CheckConnectivityState(try_to_connect);
+}
 
-  return GRPC_CHANNEL_SHUTDOWN;
+int grpc_channel_num_external_connectivity_watchers(grpc_channel* channel) {
+  grpc_core::ClientChannel* client_channel =
+      grpc_core::ClientChannel::GetFromChannel(channel);
+  if (client_channel == nullptr) {
+    gpr_log(GPR_ERROR,
+            "grpc_channel_num_external_connectivity_watchers called on "
+            "something that is not a client channel");
+    return 0;
+  }
+  return client_channel->NumExternalConnectivityWatchers();
 }
 
-typedef enum {
-  WAITING,
-  READY_TO_CALL_BACK,
-  CALLING_BACK_AND_FINISHED,
-} callback_phase;
+int grpc_channel_support_connectivity_watcher(grpc_channel* channel) {
+  return grpc_core::ClientChannel::GetFromChannel(channel) != nullptr;
+}
 
+namespace grpc_core {
 namespace {
-struct state_watcher {
-  gpr_mu mu;
-  callback_phase phase;
-  grpc_closure on_complete;
-  grpc_closure on_timeout;
-  grpc_closure watcher_timer_init;
-  grpc_timer alarm;
-  grpc_connectivity_state state;
-  grpc_completion_queue* cq;
-  grpc_cq_completion completion_storage;
-  grpc_channel* channel;
-  grpc_error* error;
-  void* tag;
-};
-}  // namespace
-
-static void delete_state_watcher(state_watcher* w) {
-  grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
-      grpc_channel_get_channel_stack(w->channel));
-  if (client_channel_elem->filter == &grpc_client_channel_filter) {
-    GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_channel_connectivity");
-  } else {
-    abort();
-  }
-  gpr_mu_destroy(&w->mu);
-  gpr_free(w);
-}
 
-static void finished_completion(void* pw, grpc_cq_completion* /*ignored*/) {
-  bool should_delete = false;
-  state_watcher* w = static_cast<state_watcher*>(pw);
-  gpr_mu_lock(&w->mu);
-  switch (w->phase) {
-    case WAITING:
-    case READY_TO_CALL_BACK:
-      GPR_UNREACHABLE_CODE(return );
-    case CALLING_BACK_AND_FINISHED:
-      should_delete = true;
-      break;
+class StateWatcher {
+ public:
+  StateWatcher(grpc_channel* channel, grpc_completion_queue* cq, void* tag,
+               grpc_connectivity_state last_observed_state,
+               gpr_timespec deadline)
+      : channel_(channel), cq_(cq), tag_(tag), state_(last_observed_state) {
+    GPR_ASSERT(grpc_cq_begin_op(cq, tag));
+    GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
+    GRPC_CLOSURE_INIT(&on_complete_, WatchComplete, this, nullptr);
+    GRPC_CLOSURE_INIT(&on_timeout_, TimeoutComplete, this, nullptr);
+    auto* watcher_timer_init_state = new WatcherTimerInitState(
+        this, grpc_timespec_to_millis_round_up(deadline));
+    ClientChannel* client_channel = ClientChannel::GetFromChannel(channel);
+    GPR_ASSERT(client_channel != nullptr);
+    client_channel->AddExternalConnectivityWatcher(
+        grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &state_,
+        &on_complete_, watcher_timer_init_state->closure());
   }
-  gpr_mu_unlock(&w->mu);
 
-  if (should_delete) {
-    delete_state_watcher(w);
+  ~StateWatcher() {
+    GRPC_CHANNEL_INTERNAL_UNREF(channel_, "watch_channel_connectivity");
   }
-}
-
-static void partly_done(state_watcher* w, bool due_to_completion,
-                        grpc_error* error) {
-  bool end_op = false;
-  void* end_op_tag = nullptr;
-  grpc_error* end_op_error = nullptr;
-  grpc_completion_queue* end_op_cq = nullptr;
-  grpc_cq_completion* end_op_completion_storage = nullptr;
 
-  if (due_to_completion) {
-    grpc_timer_cancel(&w->alarm);
-  } else {
-    grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
-        grpc_channel_get_channel_stack(w->channel));
-    grpc_client_channel_watch_connectivity_state(
-        client_channel_elem,
-        grpc_polling_entity_create_from_pollset(grpc_cq_pollset(w->cq)),
-        nullptr, &w->on_complete, nullptr);
-  }
+ private:
+  // A fire-and-forget object used to delay starting the timer until the
+  // ClientChannel actually starts the watch.
+  class WatcherTimerInitState {
+   public:
+    WatcherTimerInitState(StateWatcher* state_watcher, grpc_millis deadline)
+        : state_watcher_(state_watcher), deadline_(deadline) {
+      GRPC_CLOSURE_INIT(&closure_, WatcherTimerInit, this, nullptr);
+    }
 
-  gpr_mu_lock(&w->mu);
+    grpc_closure* closure() { return &closure_; }
 
-  if (due_to_completion) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures)) {
-      GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error));
+   private:
+    static void WatcherTimerInit(void* arg, grpc_error_handle /*error*/) {
+      auto* self = static_cast<WatcherTimerInitState*>(arg);
+      grpc_timer_init(&self->state_watcher_->timer_, self->deadline_,
+                      &self->state_watcher_->on_timeout_);
+      delete self;
     }
-    GRPC_ERROR_UNREF(error);
-    error = GRPC_ERROR_NONE;
-  } else {
-    if (error == GRPC_ERROR_NONE) {
-      error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "Timed out waiting for connection state change");
-    } else if (error == GRPC_ERROR_CANCELLED) {
-      error = GRPC_ERROR_NONE;
+
+    StateWatcher* state_watcher_;
+    grpc_millis deadline_;
+    grpc_closure closure_;
+  };
+
+  enum CallbackPhase { kWaiting, kReadyToCallBack, kCallingBackAndFinished };
+
+  // Called when the completion is returned to the CQ.
+  static void FinishedCompletion(void* arg, grpc_cq_completion* /*ignored*/) {
+    auto* self = static_cast<StateWatcher*>(arg);
+    bool should_delete = false;
+    {
+      MutexLock lock(&self->mu_);
+      switch (self->phase_) {
+        case kWaiting:
+        case kReadyToCallBack:
+          GPR_UNREACHABLE_CODE(return );
+        case kCallingBackAndFinished:
+          should_delete = true;
+      }
     }
+    if (should_delete) delete self;
   }
-  switch (w->phase) {
-    case WAITING:
-      GRPC_ERROR_REF(error);
-      w->error = error;
-      w->phase = READY_TO_CALL_BACK;
-      break;
-    case READY_TO_CALL_BACK:
-      if (error != GRPC_ERROR_NONE) {
-        GPR_ASSERT(!due_to_completion);
-        GRPC_ERROR_UNREF(w->error);
-        GRPC_ERROR_REF(error);
-        w->error = error;
+
+  void PartlyDone(bool due_to_completion, grpc_error_handle error) {
+    bool end_op = false;
+    void* end_op_tag = nullptr;
+    grpc_error_handle end_op_error = GRPC_ERROR_NONE;
+    grpc_completion_queue* end_op_cq = nullptr;
+    grpc_cq_completion* end_op_completion_storage = nullptr;
+    if (due_to_completion) {
+      grpc_timer_cancel(&timer_);
+    } else {
+      grpc_core::ClientChannel* client_channel =
+          grpc_core::ClientChannel::GetFromChannel(channel_);
+      GPR_ASSERT(client_channel != nullptr);
+      client_channel->CancelExternalConnectivityWatcher(&on_complete_);
+    }
+    {
+      MutexLock lock(&mu_);
+      if (due_to_completion) {
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures)) {
+          GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error));
+        }
+        GRPC_ERROR_UNREF(error);
+        error = GRPC_ERROR_NONE;
+      } else {
+        if (error == GRPC_ERROR_NONE) {
+          error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+              "Timed out waiting for connection state change");
+        } else if (error == GRPC_ERROR_CANCELLED) {
+          error = GRPC_ERROR_NONE;
+        }
+      }
+      switch (phase_) {
+        case kWaiting:
+          GRPC_ERROR_REF(error);
+          error_ = error;
+          phase_ = kReadyToCallBack;
+          break;
+        case kReadyToCallBack:
+          if (error != GRPC_ERROR_NONE) {
+            GPR_ASSERT(!due_to_completion);
+            GRPC_ERROR_UNREF(error_);
+            GRPC_ERROR_REF(error);
+            error_ = error;
+          }
+          phase_ = kCallingBackAndFinished;
+          end_op = true;
+          end_op_cq = cq_;
+          end_op_tag = tag_;
+          end_op_error = error_;
+          end_op_completion_storage = &completion_storage_;
+          break;
+        case kCallingBackAndFinished:
+          GPR_UNREACHABLE_CODE(return );
       }
-      w->phase = CALLING_BACK_AND_FINISHED;
-      end_op = true;
-      end_op_cq = w->cq;
-      end_op_tag = w->tag;
-      end_op_error = w->error;
-      end_op_completion_storage = &w->completion_storage;
-      break;
-    case CALLING_BACK_AND_FINISHED:
-      GPR_UNREACHABLE_CODE(return );
-      break;
+    }
+    if (end_op) {
+      grpc_cq_end_op(end_op_cq, end_op_tag, end_op_error, FinishedCompletion,
+                     this, end_op_completion_storage);
+    }
+    GRPC_ERROR_UNREF(error);
   }
-  gpr_mu_unlock(&w->mu);
 
-  if (end_op) {
-    grpc_cq_end_op(end_op_cq, end_op_tag, end_op_error, finished_completion, w,
-                   end_op_completion_storage);
+  static void WatchComplete(void* arg, grpc_error_handle error) {
+    auto* self = static_cast<StateWatcher*>(arg);
+    self->PartlyDone(/*due_to_completion=*/true, GRPC_ERROR_REF(error));
   }
 
-  GRPC_ERROR_UNREF(error);
-}
-
-static void watch_complete(void* pw, grpc_error* error) {
-  partly_done(static_cast<state_watcher*>(pw), true, GRPC_ERROR_REF(error));
-}
+  static void TimeoutComplete(void* arg, grpc_error_handle error) {
+    auto* self = static_cast<StateWatcher*>(arg);
+    self->PartlyDone(/*due_to_completion=*/false, GRPC_ERROR_REF(error));
+  }
 
-static void timeout_complete(void* pw, grpc_error* error) {
-  partly_done(static_cast<state_watcher*>(pw), false, GRPC_ERROR_REF(error));
-}
+  grpc_channel* channel_;
+  grpc_completion_queue* cq_;
+  void* tag_;
 
-int grpc_channel_num_external_connectivity_watchers(grpc_channel* channel) {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
-  return grpc_client_channel_num_external_connectivity_watchers(
-      client_channel_elem);
-}
+  grpc_connectivity_state state_;
 
-typedef struct watcher_timer_init_arg {
-  state_watcher* w;
-  gpr_timespec deadline;
-} watcher_timer_init_arg;
+  grpc_cq_completion completion_storage_;
 
-static void watcher_timer_init(void* arg, grpc_error* /*error_ignored*/) {
-  watcher_timer_init_arg* wa = static_cast<watcher_timer_init_arg*>(arg);
+  grpc_closure on_complete_;
+  grpc_timer timer_;
+  grpc_closure on_timeout_;
 
-  grpc_timer_init(&wa->w->alarm, grpc_timespec_to_millis_round_up(wa->deadline),
-                  &wa->w->on_timeout);
-  gpr_free(wa);
-}
+  Mutex mu_;
+  CallbackPhase phase_ ABSL_GUARDED_BY(mu_) = kWaiting;
+  grpc_error_handle error_ ABSL_GUARDED_BY(mu_) = GRPC_ERROR_NONE;
+};
 
-int grpc_channel_support_connectivity_watcher(grpc_channel* channel) {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
-  return client_channel_elem->filter != &grpc_client_channel_filter ? 0 : 1;
-}
+}  // namespace
+}  // namespace grpc_core
 
 void grpc_channel_watch_connectivity_state(
     grpc_channel* channel, grpc_connectivity_state last_observed_state,
     gpr_timespec deadline, grpc_completion_queue* cq, void* tag) {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
-  state_watcher* w = static_cast<state_watcher*>(gpr_malloc(sizeof(*w)));
-
   GRPC_API_TRACE(
       "grpc_channel_watch_connectivity_state("
       "channel=%p, last_observed_state=%d, "
@@ -230,35 +235,5 @@ void grpc_channel_watch_connectivity_state(
       7,
       (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec,
        (int)deadline.clock_type, cq, tag));
-
-  GPR_ASSERT(grpc_cq_begin_op(cq, tag));
-
-  gpr_mu_init(&w->mu);
-  GRPC_CLOSURE_INIT(&w->on_complete, watch_complete, w,
-                    grpc_schedule_on_exec_ctx);
-  GRPC_CLOSURE_INIT(&w->on_timeout, timeout_complete, w,
-                    grpc_schedule_on_exec_ctx);
-  w->phase = WAITING;
-  w->state = last_observed_state;
-  w->cq = cq;
-  w->tag = tag;
-  w->channel = channel;
-  w->error = nullptr;
-
-  watcher_timer_init_arg* wa = static_cast<watcher_timer_init_arg*>(
-      gpr_malloc(sizeof(watcher_timer_init_arg)));
-  wa->w = w;
-  wa->deadline = deadline;
-  GRPC_CLOSURE_INIT(&w->watcher_timer_init, watcher_timer_init, wa,
-                    grpc_schedule_on_exec_ctx);
-
-  if (client_channel_elem->filter == &grpc_client_channel_filter) {
-    GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
-    grpc_client_channel_watch_connectivity_state(
-        client_channel_elem,
-        grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &w->state,
-        &w->on_complete, &w->watcher_timer_init);
-  } else {
-    abort();
-  }
+  new grpc_core::StateWatcher(channel, cq, tag, last_observed_state, deadline);
 }
index c86ff90..3bbec5e 100644 (file)
@@ -51,7 +51,7 @@
 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
-#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/retry_filter.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
 #include "src/core/ext/filters/client_channel/service_config_call_data.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
@@ -61,7 +61,6 @@
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/polling_entity.h"
 // Client channel filter
 //
 
-// By default, we buffer 256 KiB per RPC for retries.
-// TODO(roth): Do we have any data to suggest a better value?
-#define DEFAULT_PER_RPC_RETRY_BUFFER_SIZE (256 << 10)
-
-// This value was picked arbitrarily.  It can be changed if there is
-// any even moderately compelling reason to do so.
-#define RETRY_BACKOFF_JITTER 0.2
-
-// Max number of batches that can be pending on a call at any given
-// time.  This includes one batch for each of the following ops:
-//   recv_initial_metadata
-//   send_initial_metadata
-//   recv_message
-//   send_message
-//   recv_trailing_metadata
-//   send_trailing_metadata
-#define MAX_PENDING_BATCHES 6
-
-// Channel arg containing a pointer to the ChannelData object.
-#define GRPC_ARG_CLIENT_CHANNEL_DATA "grpc.internal.client_channel_data"
-
-// Channel arg containing a pointer to the RetryThrottleData object.
-#define GRPC_ARG_RETRY_THROTTLE_DATA "grpc.internal.retry_throttle_data"
-
 namespace grpc_core {
 
 using internal::ClientChannelGlobalParsedConfig;
 using internal::ClientChannelMethodParsedConfig;
 using internal::ClientChannelServiceConfigParser;
-using internal::ServerRetryThrottleData;
 
 TraceFlag grpc_client_channel_call_trace(false, "client_channel_call");
 TraceFlag grpc_client_channel_routing_trace(false, "client_channel_routing");
 
-namespace {
-
-//
-// ChannelData definition
-//
-
-class ChannelData {
- public:
-  class CallData;
-  class RetryingCall;
-  class LoadBalancedCall;
-
-  static grpc_error* Init(grpc_channel_element* elem,
-                          grpc_channel_element_args* args);
-  static void Destroy(grpc_channel_element* elem);
-  static void StartTransportOp(grpc_channel_element* elem,
-                               grpc_transport_op* op);
-  static void GetChannelInfo(grpc_channel_element* elem,
-                             const grpc_channel_info* info);
-
-  grpc_connectivity_state CheckConnectivityState(bool try_to_connect);
-
-  void AddExternalConnectivityWatcher(grpc_polling_entity pollent,
-                                      grpc_connectivity_state* state,
-                                      grpc_closure* on_complete,
-                                      grpc_closure* watcher_timer_init) {
-    new ExternalConnectivityWatcher(this, pollent, state, on_complete,
-                                    watcher_timer_init);
-  }
-
-  void RemoveExternalConnectivityWatcher(grpc_closure* on_complete,
-                                         bool cancel) {
-    ExternalConnectivityWatcher::RemoveWatcherFromExternalWatchersMap(
-        this, on_complete, cancel);
-  }
-
-  int NumExternalConnectivityWatchers() const {
-    MutexLock lock(&external_watchers_mu_);
-    return static_cast<int>(external_watchers_.size());
-  }
-
-  void AddConnectivityWatcher(
-      grpc_connectivity_state initial_state,
-      OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher);
-  void RemoveConnectivityWatcher(
-      AsyncConnectivityStateWatcherInterface* watcher);
-
- private:
-  class DynamicTerminationFilterChannelData;
-  class SubchannelWrapper;
-  class ClientChannelControlHelper;
-  class ConnectivityWatcherAdder;
-  class ConnectivityWatcherRemover;
-
-  // Represents a pending connectivity callback from an external caller
-  // via grpc_client_channel_watch_connectivity_state().
-  class ExternalConnectivityWatcher : public ConnectivityStateWatcherInterface {
-   public:
-    ExternalConnectivityWatcher(ChannelData* chand, grpc_polling_entity pollent,
-                                grpc_connectivity_state* state,
-                                grpc_closure* on_complete,
-                                grpc_closure* watcher_timer_init);
-
-    ~ExternalConnectivityWatcher() override;
-
-    // Removes the watcher from the external_watchers_ map.
-    static void RemoveWatcherFromExternalWatchersMap(ChannelData* chand,
-                                                     grpc_closure* on_complete,
-                                                     bool cancel);
-
-    void Notify(grpc_connectivity_state state,
-                const absl::Status& /* status */) override;
-
-    void Cancel();
-
-   private:
-    // Adds the watcher to state_tracker_. Consumes the ref that is passed to it
-    // from Start().
-    void AddWatcherLocked();
-    void RemoveWatcherLocked();
-
-    ChannelData* chand_;
-    grpc_polling_entity pollent_;
-    grpc_connectivity_state initial_state_;
-    grpc_connectivity_state* state_;
-    grpc_closure* on_complete_;
-    grpc_closure* watcher_timer_init_;
-    Atomic<bool> done_{false};
-  };
-
-  class ResolverResultHandler : public Resolver::ResultHandler {
-   public:
-    explicit ResolverResultHandler(ChannelData* chand) : chand_(chand) {
-      GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ResolverResultHandler");
-    }
-
-    ~ResolverResultHandler() override {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
-        gpr_log(GPR_INFO, "chand=%p: resolver shutdown complete", chand_);
-      }
-      GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "ResolverResultHandler");
-    }
-
-    void ReturnResult(Resolver::Result result) override {
-      chand_->OnResolverResultChangedLocked(std::move(result));
-    }
-
-    void ReturnError(grpc_error* error) override {
-      chand_->OnResolverErrorLocked(error);
-    }
-
-   private:
-    ChannelData* chand_;
-  };
-
-  struct ResolverQueuedCall {
-    grpc_call_element* elem;
-    ResolverQueuedCall* next = nullptr;
-  };
-  struct LbQueuedCall {
-    LoadBalancedCall* lb_call;
-    LbQueuedCall* next = nullptr;
-  };
-
-  ChannelData(grpc_channel_element_args* args, grpc_error** error);
-  ~ChannelData();
-
-  // Note: Does NOT return a new ref.
-  grpc_error* disconnect_error() const {
-    return disconnect_error_.Load(MemoryOrder::ACQUIRE);
-  }
-
-  // Note: All methods with "Locked" suffix must be invoked from within
-  // work_serializer_.
-
-  void OnResolverResultChangedLocked(Resolver::Result result);
-  void OnResolverErrorLocked(grpc_error* error);
-
-  void CreateOrUpdateLbPolicyLocked(
-      RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
-      Resolver::Result result);
-  OrphanablePtr<LoadBalancingPolicy> CreateLbPolicyLocked(
-      const grpc_channel_args& args);
-
-  void UpdateStateAndPickerLocked(
-      grpc_connectivity_state state, const absl::Status& status,
-      const char* reason,
-      std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker);
-
-  void UpdateServiceConfigInControlPlaneLocked(
-      RefCountedPtr<ServiceConfig> service_config,
-      RefCountedPtr<ConfigSelector> config_selector,
-      const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
-      const char* lb_policy_name);
-
-  void UpdateServiceConfigInDataPlaneLocked();
-
-  void CreateResolverLocked();
-  void DestroyResolverAndLbPolicyLocked();
-
-  grpc_error* DoPingLocked(grpc_transport_op* op);
-
-  void StartTransportOpLocked(grpc_transport_op* op);
-
-  void TryToConnectLocked();
-
-  // These methods all require holding resolution_mu_.
-  void AddResolverQueuedCall(ResolverQueuedCall* call,
-                             grpc_polling_entity* pollent)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(resolution_mu_);
-  void RemoveResolverQueuedCall(ResolverQueuedCall* to_remove,
-                                grpc_polling_entity* pollent)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(resolution_mu_);
-
-  // These methods all require holding data_plane_mu_.
-  void AddLbQueuedCall(LbQueuedCall* call, grpc_polling_entity* pollent)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(data_plane_mu_);
-  void RemoveLbQueuedCall(LbQueuedCall* to_remove, grpc_polling_entity* pollent)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(data_plane_mu_);
-  RefCountedPtr<ConnectedSubchannel> GetConnectedSubchannelInDataPlane(
-      SubchannelInterface* subchannel) const
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(data_plane_mu_);
-
-  //
-  // Fields set at construction and never modified.
-  //
-  const bool deadline_checking_enabled_;
-  const bool enable_retries_;
-  const size_t per_rpc_retry_buffer_size_;
-  grpc_channel_stack* owning_stack_;
-  ClientChannelFactory* client_channel_factory_;
-  const grpc_channel_args* channel_args_;
-  RefCountedPtr<ServiceConfig> default_service_config_;
-  std::string server_name_;
-  UniquePtr<char> target_uri_;
-  channelz::ChannelNode* channelz_node_;
-
-  //
-  // Fields related to name resolution.  Guarded by resolution_mu_.
-  //
-  mutable Mutex resolution_mu_;
-  // Linked list of calls queued waiting for resolver result.
-  ResolverQueuedCall* resolver_queued_calls_ ABSL_GUARDED_BY(resolution_mu_) =
-      nullptr;
-  // Data from service config.
-  grpc_error* resolver_transient_failure_error_
-      ABSL_GUARDED_BY(resolution_mu_) = GRPC_ERROR_NONE;
-  bool received_service_config_data_ ABSL_GUARDED_BY(resolution_mu_) = false;
-  RefCountedPtr<ServiceConfig> service_config_ ABSL_GUARDED_BY(resolution_mu_);
-  RefCountedPtr<ConfigSelector> config_selector_
-      ABSL_GUARDED_BY(resolution_mu_);
-  RefCountedPtr<DynamicFilters> dynamic_filters_
-      ABSL_GUARDED_BY(resolution_mu_);
-
-  //
-  // Fields used in the data plane.  Guarded by data_plane_mu_.
-  //
-  mutable Mutex data_plane_mu_;
-  std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker_
-      ABSL_GUARDED_BY(data_plane_mu_);
-  // Linked list of calls queued waiting for LB pick.
-  LbQueuedCall* lb_queued_calls_ ABSL_GUARDED_BY(data_plane_mu_) = nullptr;
-
-  //
-  // Fields used in the control plane.  Guarded by work_serializer.
-  //
-  std::shared_ptr<WorkSerializer> work_serializer_;
-  grpc_pollset_set* interested_parties_;
-  ConnectivityStateTracker state_tracker_;
-  OrphanablePtr<Resolver> resolver_;
-  bool previous_resolution_contained_addresses_ = false;
-  RefCountedPtr<ServiceConfig> saved_service_config_;
-  RefCountedPtr<ConfigSelector> saved_config_selector_;
-  absl::optional<std::string> health_check_service_name_;
-  OrphanablePtr<LoadBalancingPolicy> lb_policy_;
-  RefCountedPtr<SubchannelPoolInterface> subchannel_pool_;
-  // The number of SubchannelWrapper instances referencing a given Subchannel.
-  std::map<Subchannel*, int> subchannel_refcount_map_;
-  // The set of SubchannelWrappers that currently exist.
-  // No need to hold a ref, since the map is updated in the control-plane
-  // work_serializer when the SubchannelWrappers are created and destroyed.
-  std::set<SubchannelWrapper*> subchannel_wrappers_;
-  // Pending ConnectedSubchannel updates for each SubchannelWrapper.
-  // Updates are queued here in the control plane work_serializer and then
-  // applied in the data plane mutex when the picker is updated.
-  std::map<RefCountedPtr<SubchannelWrapper>, RefCountedPtr<ConnectedSubchannel>>
-      pending_subchannel_updates_;
-  int keepalive_time_ = -1;
-
-  //
-  // Fields accessed from both data plane mutex and control plane
-  // work_serializer.
-  //
-  Atomic<grpc_error*> disconnect_error_;
-
-  //
-  // Fields guarded by a mutex, since they need to be accessed
-  // synchronously via get_channel_info().
-  //
-  Mutex info_mu_;
-  UniquePtr<char> info_lb_policy_name_ ABSL_GUARDED_BY(info_mu_);
-  UniquePtr<char> info_service_config_json_ ABSL_GUARDED_BY(info_mu_);
-
-  //
-  // Fields guarded by a mutex, since they need to be accessed
-  // synchronously via grpc_channel_num_external_connectivity_watchers().
-  //
-  mutable Mutex external_watchers_mu_;
-  std::map<grpc_closure*, RefCountedPtr<ExternalConnectivityWatcher>>
-      external_watchers_ ABSL_GUARDED_BY(external_watchers_mu_);
-};
-
 //
-// ChannelData::CallData definition
+// ClientChannel::CallData definition
 //
 
-class ChannelData::CallData {
+class ClientChannel::CallData {
  public:
-  static grpc_error* Init(grpc_call_element* elem,
-                          const grpc_call_element_args* args);
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args);
   static void Destroy(grpc_call_element* elem,
                       const grpc_call_final_info* final_info,
                       grpc_closure* then_schedule_closure);
@@ -403,23 +105,23 @@ class ChannelData::CallData {
   static void SetPollent(grpc_call_element* elem, grpc_polling_entity* pollent);
 
   // Invoked by channel for queued calls when name resolution is completed.
-  static void CheckResolution(void* arg, grpc_error* error);
+  static void CheckResolution(void* arg, grpc_error_handle error);
   // Helper function for applying the service config to a call while
-  // holding ChannelData::resolution_mu_.
+  // holding ClientChannel::resolution_mu_.
   // Returns true if the service config has been applied to the call, in which
   // case the caller must invoke ResolutionDone() or AsyncResolutionDone()
   // with the returned error.
-  bool CheckResolutionLocked(grpc_call_element* elem, grpc_error** error)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ChannelData::resolution_mu_);
+  bool CheckResolutionLocked(grpc_call_element* elem, grpc_error_handle* error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::resolution_mu_);
   // Schedules a callback to continue processing the call once
   // resolution is complete.  The callback will not run until after this
   // method returns.
-  void AsyncResolutionDone(grpc_call_element* elem, grpc_error* error);
+  void AsyncResolutionDone(grpc_call_element* elem, grpc_error_handle error);
 
  private:
   class ResolverQueuedCallCanceller;
 
-  CallData(grpc_call_element* elem, const ChannelData& chand,
+  CallData(grpc_call_element* elem, const ClientChannel& chand,
            const grpc_call_element_args& args);
   ~CallData();
 
@@ -427,7 +129,8 @@ class ChannelData::CallData {
   static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
   void PendingBatchesAdd(grpc_call_element* elem,
                          grpc_transport_stream_op_batch* batch);
-  static void FailPendingBatchInCallCombiner(void* arg, grpc_error* error);
+  static void FailPendingBatchInCallCombiner(void* arg,
+                                             grpc_error_handle error);
   // A predicate type and some useful implementations for PendingBatchesFail().
   typedef bool (*YieldCallCombinerPredicate)(
       const CallCombinerClosureList& closures);
@@ -445,9 +148,10 @@ class ChannelData::CallData {
   // If yield_call_combiner_predicate returns true, assumes responsibility for
   // yielding the call combiner.
   void PendingBatchesFail(
-      grpc_call_element* elem, grpc_error* error,
+      grpc_call_element* elem, grpc_error_handle error,
       YieldCallCombinerPredicate yield_call_combiner_predicate);
-  static void ResumePendingBatchInCallCombiner(void* arg, grpc_error* ignored);
+  static void ResumePendingBatchInCallCombiner(void* arg,
+                                               grpc_error_handle ignored);
   // Resumes all pending batches on lb_call_.
   void PendingBatchesResume(grpc_call_element* elem);
 
@@ -455,23 +159,23 @@ class ChannelData::CallData {
   // that the resolver has returned results to the channel.
   // If an error is returned, the error indicates the status with which
   // the call should be failed.
-  grpc_error* ApplyServiceConfigToCallLocked(
+  grpc_error_handle ApplyServiceConfigToCallLocked(
       grpc_call_element* elem, grpc_metadata_batch* initial_metadata)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ChannelData::resolution_mu_);
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::resolution_mu_);
   // Invoked when the resolver result is applied to the caller, on both
   // success or failure.
-  static void ResolutionDone(void* arg, grpc_error* error);
+  static void ResolutionDone(void* arg, grpc_error_handle error);
   // Removes the call (if present) from the channel's list of calls queued
   // for name resolution.
   void MaybeRemoveCallFromResolverQueuedCallsLocked(grpc_call_element* elem)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ChannelData::resolution_mu_);
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::resolution_mu_);
   // Adds the call (if not already present) to the channel's list of
   // calls queued for name resolution.
   void MaybeAddCallToResolverQueuedCallsLocked(grpc_call_element* elem)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ChannelData::resolution_mu_);
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::resolution_mu_);
 
   static void RecvInitialMetadataReadyForConfigSelectorCommitCallback(
-      void* arg, grpc_error* error);
+      void* arg, grpc_error_handle error);
   void InjectRecvInitialMetadataReadyForConfigSelectorCommitCallback(
       grpc_transport_stream_op_batch* batch);
 
@@ -497,11 +201,15 @@ class ChannelData::CallData {
 
   grpc_closure pick_closure_;
 
-  // Accessed while holding ChannelData::resolution_mu_.
-  bool service_config_applied_ = false;
-  bool queued_pending_resolver_result_ = false;
-  ChannelData::ResolverQueuedCall resolver_queued_call_;
-  ResolverQueuedCallCanceller* resolver_call_canceller_ = nullptr;
+  // Accessed while holding ClientChannel::resolution_mu_.
+  bool service_config_applied_ ABSL_GUARDED_BY(&ClientChannel::resolution_mu_) =
+      false;
+  bool queued_pending_resolver_result_
+      ABSL_GUARDED_BY(&ClientChannel::resolution_mu_) = false;
+  ClientChannel::ResolverQueuedCall resolver_queued_call_
+      ABSL_GUARDED_BY(&ClientChannel::resolution_mu_);
+  ResolverQueuedCallCanceller* resolver_call_canceller_
+      ABSL_GUARDED_BY(&ClientChannel::resolution_mu_) = nullptr;
 
   std::function<void()> on_call_committed_;
 
@@ -519,565 +227,72 @@ class ChannelData::CallData {
   grpc_transport_stream_op_batch* pending_batches_[MAX_PENDING_BATCHES] = {};
 
   // Set when we get a cancel_stream op.
-  grpc_error* cancel_error_ = GRPC_ERROR_NONE;
-};
-
-//
-// ChannelData::RetryingCall definition
-//
-
-class ChannelData::RetryingCall {
- public:
-  RetryingCall(
-      ChannelData* chand, const grpc_call_element_args& args,
-      grpc_polling_entity* pollent,
-      RefCountedPtr<ServerRetryThrottleData> retry_throttle_data,
-      const ClientChannelMethodParsedConfig::RetryPolicy* retry_policy);
-  ~RetryingCall();
-
-  void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
-
-  RefCountedPtr<SubchannelCall> subchannel_call() const;
-
- private:
-  // State used for starting a retryable batch on a subchannel call.
-  // This provides its own grpc_transport_stream_op_batch and other data
-  // structures needed to populate the ops in the batch.
-  // We allocate one struct on the arena for each attempt at starting a
-  // batch on a given subchannel call.
-  struct SubchannelCallBatchData {
-    // Creates a SubchannelCallBatchData object on the call's arena with the
-    // specified refcount.  If set_on_complete is true, the batch's
-    // on_complete callback will be set to point to on_complete();
-    // otherwise, the batch's on_complete callback will be null.
-    static SubchannelCallBatchData* Create(RetryingCall* call, int refcount,
-                                           bool set_on_complete);
-
-    void Unref() {
-      if (gpr_unref(&refs)) Destroy();
-    }
-
-    SubchannelCallBatchData(RetryingCall* call, int refcount,
-                            bool set_on_complete);
-    // All dtor code must be added in `Destroy()`. This is because we may
-    // call closures in `SubchannelCallBatchData` after they are unrefed by
-    // `Unref()`, and msan would complain about accessing this class
-    // after calling dtor. As a result we cannot call the `dtor` in `Unref()`.
-    // TODO(soheil): We should try to call the dtor in `Unref()`.
-    ~SubchannelCallBatchData() { Destroy(); }
-    void Destroy();
-
-    gpr_refcount refs;
-    grpc_call_element* elem;
-    RetryingCall* call;
-    RefCountedPtr<ChannelData::LoadBalancedCall> lb_call;
-    // The batch to use in the subchannel call.
-    // Its payload field points to SubchannelCallRetryState::batch_payload.
-    grpc_transport_stream_op_batch batch;
-    // For intercepting on_complete.
-    grpc_closure on_complete;
-  };
-
-  // Retry state associated with a subchannel call.
-  // Stored in the parent_data of the subchannel call object.
-  struct SubchannelCallRetryState {
-    explicit SubchannelCallRetryState(grpc_call_context_element* context)
-        : batch_payload(context),
-          started_send_initial_metadata(false),
-          completed_send_initial_metadata(false),
-          started_send_trailing_metadata(false),
-          completed_send_trailing_metadata(false),
-          started_recv_initial_metadata(false),
-          completed_recv_initial_metadata(false),
-          started_recv_trailing_metadata(false),
-          completed_recv_trailing_metadata(false),
-          retry_dispatched(false) {}
-
-    // SubchannelCallBatchData.batch.payload points to this.
-    grpc_transport_stream_op_batch_payload batch_payload;
-    // For send_initial_metadata.
-    // Note that we need to make a copy of the initial metadata for each
-    // subchannel call instead of just referring to the copy in call_data,
-    // because filters in the subchannel stack will probably add entries,
-    // so we need to start in a pristine state for each attempt of the call.
-    grpc_linked_mdelem* send_initial_metadata_storage;
-    grpc_metadata_batch send_initial_metadata;
-    // For send_message.
-    // TODO(roth): Restructure this to eliminate use of ManualConstructor.
-    ManualConstructor<ByteStreamCache::CachingByteStream> send_message;
-    // For send_trailing_metadata.
-    grpc_linked_mdelem* send_trailing_metadata_storage;
-    grpc_metadata_batch send_trailing_metadata;
-    // For intercepting recv_initial_metadata.
-    grpc_metadata_batch recv_initial_metadata;
-    grpc_closure recv_initial_metadata_ready;
-    bool trailing_metadata_available = false;
-    // For intercepting recv_message.
-    grpc_closure recv_message_ready;
-    OrphanablePtr<ByteStream> recv_message;
-    // For intercepting recv_trailing_metadata.
-    grpc_metadata_batch recv_trailing_metadata;
-    grpc_transport_stream_stats collect_stats;
-    grpc_closure recv_trailing_metadata_ready;
-    // These fields indicate which ops have been started and completed on
-    // this subchannel call.
-    size_t started_send_message_count = 0;
-    size_t completed_send_message_count = 0;
-    size_t started_recv_message_count = 0;
-    size_t completed_recv_message_count = 0;
-    bool started_send_initial_metadata : 1;
-    bool completed_send_initial_metadata : 1;
-    bool started_send_trailing_metadata : 1;
-    bool completed_send_trailing_metadata : 1;
-    bool started_recv_initial_metadata : 1;
-    bool completed_recv_initial_metadata : 1;
-    bool started_recv_trailing_metadata : 1;
-    bool completed_recv_trailing_metadata : 1;
-    // State for callback processing.
-    SubchannelCallBatchData* recv_initial_metadata_ready_deferred_batch =
-        nullptr;
-    grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
-    SubchannelCallBatchData* recv_message_ready_deferred_batch = nullptr;
-    grpc_error* recv_message_error = GRPC_ERROR_NONE;
-    SubchannelCallBatchData* recv_trailing_metadata_internal_batch = nullptr;
-    // NOTE: Do not move this next to the metadata bitfields above. That would
-    //       save space but will also result in a data race because compiler
-    //       will generate a 2 byte store which overwrites the meta-data
-    //       fields upon setting this field.
-    bool retry_dispatched : 1;
-  };
-
-  // Pending batches stored in call data.
-  struct PendingBatch {
-    // The pending batch.  If nullptr, this slot is empty.
-    grpc_transport_stream_op_batch* batch = nullptr;
-    // Indicates whether payload for send ops has been cached in CallData.
-    bool send_ops_cached = false;
-  };
-
-  // Caches data for send ops so that it can be retried later, if not
-  // already cached.
-  void MaybeCacheSendOpsForBatch(PendingBatch* pending);
-  void FreeCachedSendInitialMetadata();
-  // Frees cached send_message at index idx.
-  void FreeCachedSendMessage(size_t idx);
-  void FreeCachedSendTrailingMetadata();
-  // Frees cached send ops that have already been completed after
-  // committing the call.
-  void FreeCachedSendOpDataAfterCommit(SubchannelCallRetryState* retry_state);
-  // Frees cached send ops that were completed by the completed batch in
-  // batch_data.  Used when batches are completed after the call is committed.
-  void FreeCachedSendOpDataForCompletedBatch(
-      SubchannelCallBatchData* batch_data,
-      SubchannelCallRetryState* retry_state);
-
-  // Returns the index into pending_batches_ to be used for batch.
-  static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
-  void PendingBatchesAdd(grpc_transport_stream_op_batch* batch);
-  void PendingBatchClear(PendingBatch* pending);
-  void MaybeClearPendingBatch(PendingBatch* pending);
-  static void FailPendingBatchInCallCombiner(void* arg, grpc_error* error);
-  // A predicate type and some useful implementations for PendingBatchesFail().
-  typedef bool (*YieldCallCombinerPredicate)(
-      const CallCombinerClosureList& closures);
-  static bool YieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
-    return true;
-  }
-  static bool NoYieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
-    return false;
-  }
-  static bool YieldCallCombinerIfPendingBatchesFound(
-      const CallCombinerClosureList& closures) {
-    return closures.size() > 0;
-  }
-  // Fails all pending batches.
-  // If yield_call_combiner_predicate returns true, assumes responsibility for
-  // yielding the call combiner.
-  void PendingBatchesFail(
-      grpc_error* error,
-      YieldCallCombinerPredicate yield_call_combiner_predicate);
-  static void ResumePendingBatchInCallCombiner(void* arg, grpc_error* ignored);
-  // Resumes all pending batches on lb_call_.
-  void PendingBatchesResume();
-  // Returns a pointer to the first pending batch for which predicate(batch)
-  // returns true, or null if not found.
-  template <typename Predicate>
-  PendingBatch* PendingBatchFind(const char* log_message, Predicate predicate);
-
-  // Commits the call so that no further retry attempts will be performed.
-  void RetryCommit(SubchannelCallRetryState* retry_state);
-  // Starts a retry after appropriate back-off.
-  void DoRetry(SubchannelCallRetryState* retry_state,
-               grpc_millis server_pushback_ms);
-  // Returns true if the call is being retried.
-  bool MaybeRetry(SubchannelCallBatchData* batch_data, grpc_status_code status,
-                  grpc_mdelem* server_pushback_md);
-
-  // Invokes recv_initial_metadata_ready for a subchannel batch.
-  static void InvokeRecvInitialMetadataCallback(void* arg, grpc_error* error);
-  // Intercepts recv_initial_metadata_ready callback for retries.
-  // Commits the call and returns the initial metadata up the stack.
-  static void RecvInitialMetadataReady(void* arg, grpc_error* error);
-
-  // Invokes recv_message_ready for a subchannel batch.
-  static void InvokeRecvMessageCallback(void* arg, grpc_error* error);
-  // Intercepts recv_message_ready callback for retries.
-  // Commits the call and returns the message up the stack.
-  static void RecvMessageReady(void* arg, grpc_error* error);
-
-  // Sets *status and *server_pushback_md based on md_batch and error.
-  // Only sets *server_pushback_md if server_pushback_md != nullptr.
-  void GetCallStatus(grpc_metadata_batch* md_batch, grpc_error* error,
-                     grpc_status_code* status,
-                     grpc_mdelem** server_pushback_md);
-  // Adds recv_trailing_metadata_ready closure to closures.
-  void AddClosureForRecvTrailingMetadataReady(
-      SubchannelCallBatchData* batch_data, grpc_error* error,
-      CallCombinerClosureList* closures);
-  // Adds any necessary closures for deferred recv_initial_metadata and
-  // recv_message callbacks to closures.
-  static void AddClosuresForDeferredRecvCallbacks(
-      SubchannelCallBatchData* batch_data,
-      SubchannelCallRetryState* retry_state, CallCombinerClosureList* closures);
-  // Returns true if any op in the batch was not yet started.
-  // Only looks at send ops, since recv ops are always started immediately.
-  bool PendingBatchIsUnstarted(PendingBatch* pending,
-                               SubchannelCallRetryState* retry_state);
-  // For any pending batch containing an op that has not yet been started,
-  // adds the pending batch's completion closures to closures.
-  void AddClosuresToFailUnstartedPendingBatches(
-      SubchannelCallRetryState* retry_state, grpc_error* error,
-      CallCombinerClosureList* closures);
-  // Runs necessary closures upon completion of a call attempt.
-  void RunClosuresForCompletedCall(SubchannelCallBatchData* batch_data,
-                                   grpc_error* error);
-  // Intercepts recv_trailing_metadata_ready callback for retries.
-  // Commits the call and returns the trailing metadata up the stack.
-  static void RecvTrailingMetadataReady(void* arg, grpc_error* error);
-
-  // Adds the on_complete closure for the pending batch completed in
-  // batch_data to closures.
-  void AddClosuresForCompletedPendingBatch(SubchannelCallBatchData* batch_data,
-                                           grpc_error* error,
-                                           CallCombinerClosureList* closures);
-
-  // If there are any cached ops to replay or pending ops to start on the
-  // subchannel call, adds a closure to closures to invoke
-  // StartRetriableSubchannelBatches().
-  void AddClosuresForReplayOrPendingSendOps(
-      SubchannelCallBatchData* batch_data,
-      SubchannelCallRetryState* retry_state, CallCombinerClosureList* closures);
-
-  // Callback used to intercept on_complete from subchannel calls.
-  // Called only when retries are enabled.
-  static void OnComplete(void* arg, grpc_error* error);
-
-  static void StartBatchInCallCombiner(void* arg, grpc_error* ignored);
-  // Adds a closure to closures that will execute batch in the call combiner.
-  void AddClosureForSubchannelBatch(grpc_transport_stream_op_batch* batch,
-                                    CallCombinerClosureList* closures);
-  // Adds retriable send_initial_metadata op to batch_data.
-  void AddRetriableSendInitialMetadataOp(SubchannelCallRetryState* retry_state,
-                                         SubchannelCallBatchData* batch_data);
-  // Adds retriable send_message op to batch_data.
-  void AddRetriableSendMessageOp(SubchannelCallRetryState* retry_state,
-                                 SubchannelCallBatchData* batch_data);
-  // Adds retriable send_trailing_metadata op to batch_data.
-  void AddRetriableSendTrailingMetadataOp(SubchannelCallRetryState* retry_state,
-                                          SubchannelCallBatchData* batch_data);
-  // Adds retriable recv_initial_metadata op to batch_data.
-  void AddRetriableRecvInitialMetadataOp(SubchannelCallRetryState* retry_state,
-                                         SubchannelCallBatchData* batch_data);
-  // Adds retriable recv_message op to batch_data.
-  void AddRetriableRecvMessageOp(SubchannelCallRetryState* retry_state,
-                                 SubchannelCallBatchData* batch_data);
-  // Adds retriable recv_trailing_metadata op to batch_data.
-  void AddRetriableRecvTrailingMetadataOp(SubchannelCallRetryState* retry_state,
-                                          SubchannelCallBatchData* batch_data);
-  // Helper function used to start a recv_trailing_metadata batch.  This
-  // is used in the case where a recv_initial_metadata or recv_message
-  // op fails in a way that we know the call is over but when the application
-  // has not yet started its own recv_trailing_metadata op.
-  void StartInternalRecvTrailingMetadata();
-  // If there are any cached send ops that need to be replayed on the
-  // current subchannel call, creates and returns a new subchannel batch
-  // to replay those ops.  Otherwise, returns nullptr.
-  SubchannelCallBatchData* MaybeCreateSubchannelBatchForReplay(
-      SubchannelCallRetryState* retry_state);
-  // Adds subchannel batches for pending batches to closures.
-  void AddSubchannelBatchesForPendingBatches(
-      SubchannelCallRetryState* retry_state, CallCombinerClosureList* closures);
-  // Constructs and starts whatever subchannel batches are needed on the
-  // subchannel call.
-  static void StartRetriableSubchannelBatches(void* arg, grpc_error* ignored);
-
-  static void CreateLbCall(void* arg, grpc_error* error);
-
-  ChannelData* chand_;
-  grpc_polling_entity* pollent_;
-  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
-  const ClientChannelMethodParsedConfig::RetryPolicy* retry_policy_ = nullptr;
-  BackOff retry_backoff_;
-
-  grpc_slice path_;  // Request path.
-  gpr_cycle_counter call_start_time_;
-  grpc_millis deadline_;
-  Arena* arena_;
-  grpc_call_stack* owning_call_;
-  CallCombiner* call_combiner_;
-  grpc_call_context_element* call_context_;
-
-  grpc_closure retry_closure_;
-
-  RefCountedPtr<ChannelData::LoadBalancedCall> lb_call_;
-
-  // Batches are added to this list when received from above.
-  // They are removed when we are done handling the batch (i.e., when
-  // either we have invoked all of the batch's callbacks or we have
-  // passed the batch down to the LB call and are not intercepting any of
-  // its callbacks).
-  // TODO(roth): Now that the retry code is split out into its own call
-  // object, revamp this to work in a cleaner way, since we no longer need
-  // for batches to ever wait for name resolution or LB picks.
-  PendingBatch pending_batches_[MAX_PENDING_BATCHES];
-  bool pending_send_initial_metadata_ : 1;
-  bool pending_send_message_ : 1;
-  bool pending_send_trailing_metadata_ : 1;
-
-  // Set when we get a cancel_stream op.
-  grpc_error* cancel_error_ = GRPC_ERROR_NONE;
-
-  // Retry state.
-  bool enable_retries_ : 1;
-  bool retry_committed_ : 1;
-  bool last_attempt_got_server_pushback_ : 1;
-  int num_attempts_completed_ = 0;
-  size_t bytes_buffered_for_retry_ = 0;
-  grpc_timer retry_timer_;
-
-  // The number of pending retriable subchannel batches containing send ops.
-  // We hold a ref to the call stack while this is non-zero, since replay
-  // batches may not complete until after all callbacks have been returned
-  // to the surface, and we need to make sure that the call is not destroyed
-  // until all of these batches have completed.
-  // Note that we actually only need to track replay batches, but it's
-  // easier to track all batches with send ops.
-  int num_pending_retriable_subchannel_send_batches_ = 0;
-
-  // Cached data for retrying send ops.
-  // send_initial_metadata
-  bool seen_send_initial_metadata_ = false;
-  grpc_linked_mdelem* send_initial_metadata_storage_ = nullptr;
-  grpc_metadata_batch send_initial_metadata_;
-  uint32_t send_initial_metadata_flags_;
-  gpr_atm* peer_string_;
-  // send_message
-  // When we get a send_message op, we replace the original byte stream
-  // with a CachingByteStream that caches the slices to a local buffer for
-  // use in retries.
-  // Note: We inline the cache for the first 3 send_message ops and use
-  // dynamic allocation after that.  This number was essentially picked
-  // at random; it could be changed in the future to tune performance.
-  absl::InlinedVector<ByteStreamCache*, 3> send_messages_;
-  // send_trailing_metadata
-  bool seen_send_trailing_metadata_ = false;
-  grpc_linked_mdelem* send_trailing_metadata_storage_ = nullptr;
-  grpc_metadata_batch send_trailing_metadata_;
+  grpc_error_handle cancel_error_ = GRPC_ERROR_NONE;
 };
 
 //
-// ChannelData::LoadBalancedCall definition
+// Filter vtable
 //
 
-// This object is ref-counted, but it cannot inherit from RefCounted<>,
-// because it is allocated on the arena and can't free its memory when
-// its refcount goes to zero.  So instead, it manually implements the
-// same API as RefCounted<>, so that it can be used with RefCountedPtr<>.
-class ChannelData::LoadBalancedCall {
- public:
-  static RefCountedPtr<LoadBalancedCall> Create(
-      ChannelData* chand, const grpc_call_element_args& args,
-      grpc_polling_entity* pollent, size_t parent_data_size);
-
-  LoadBalancedCall(ChannelData* chand, const grpc_call_element_args& args,
-                   grpc_polling_entity* pollent);
-  ~LoadBalancedCall();
-
-  // Interface of RefCounted<>.
-  RefCountedPtr<LoadBalancedCall> Ref() GRPC_MUST_USE_RESULT;
-  RefCountedPtr<LoadBalancedCall> Ref(const DebugLocation& location,
-                                      const char* reason) GRPC_MUST_USE_RESULT;
-  // When refcount drops to 0, destroys itself and the associated call stack,
-  // but does NOT free the memory because it's in the call arena.
-  void Unref();
-  void Unref(const DebugLocation& location, const char* reason);
-
-  void* GetParentData();
-
-  void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
-
-  // Invoked by channel for queued LB picks when the picker is updated.
-  static void PickSubchannel(void* arg, grpc_error* error);
-  // Helper function for performing an LB pick while holding the data plane
-  // mutex.  Returns true if the pick is complete, in which case the caller
-  // must invoke PickDone() or AsyncPickDone() with the returned error.
-  bool PickSubchannelLocked(grpc_error** error)
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ChannelData::data_plane_mu_);
-  // Schedules a callback to process the completed pick.  The callback
-  // will not run until after this method returns.
-  void AsyncPickDone(grpc_error* error);
-
-  RefCountedPtr<SubchannelCall> subchannel_call() const {
-    return subchannel_call_;
-  }
-
- private:
-  // Allow RefCountedPtr<> to access IncrementRefCount().
-  template <typename T>
-  friend class ::grpc_core::RefCountedPtr;
-
-  class LbQueuedCallCanceller;
-  class Metadata;
-  class LbCallState;
-
-  // Interface of RefCounted<>.
-  void IncrementRefCount();
-  void IncrementRefCount(const DebugLocation& location, const char* reason);
-
-  // Returns the index into pending_batches_ to be used for batch.
-  static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
-  void PendingBatchesAdd(grpc_transport_stream_op_batch* batch);
-  static void FailPendingBatchInCallCombiner(void* arg, grpc_error* error);
-  // A predicate type and some useful implementations for PendingBatchesFail().
-  typedef bool (*YieldCallCombinerPredicate)(
-      const CallCombinerClosureList& closures);
-  static bool YieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
-    return true;
-  }
-  static bool NoYieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
-    return false;
-  }
-  static bool YieldCallCombinerIfPendingBatchesFound(
-      const CallCombinerClosureList& closures) {
-    return closures.size() > 0;
-  }
-  // Fails all pending batches.
-  // If yield_call_combiner_predicate returns true, assumes responsibility for
-  // yielding the call combiner.
-  void PendingBatchesFail(
-      grpc_error* error,
-      YieldCallCombinerPredicate yield_call_combiner_predicate);
-  static void ResumePendingBatchInCallCombiner(void* arg, grpc_error* ignored);
-  // Resumes all pending batches on subchannel_call_.
-  void PendingBatchesResume();
-
-  static void RecvTrailingMetadataReadyForLoadBalancingPolicy(
-      void* arg, grpc_error* error);
-  void InjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
-      grpc_transport_stream_op_batch* batch);
-
-  void CreateSubchannelCall();
-  // Invoked when a pick is completed, on both success or failure.
-  static void PickDone(void* arg, grpc_error* error);
-  // Removes the call from the channel's list of queued picks if present.
-  void MaybeRemoveCallFromLbQueuedCallsLocked()
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ChannelData::data_plane_mu_);
-  // Adds the call to the channel's list of queued picks if not already present.
-  void MaybeAddCallToLbQueuedCallsLocked()
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ChannelData::data_plane_mu_);
-
-  RefCount refs_;
-
-  ChannelData* chand_;
-
-  // TODO(roth): Instead of duplicating these fields in every filter
-  // that uses any one of them, we should store them in the call
-  // context.  This will save per-call memory overhead.
-  grpc_slice path_;  // Request path.
-  gpr_cycle_counter call_start_time_;
-  grpc_millis deadline_;
-  Arena* arena_;
-  grpc_call_stack* owning_call_;
-  CallCombiner* call_combiner_;
-  grpc_call_context_element* call_context_;
-
-  // Set when we get a cancel_stream op.
-  grpc_error* cancel_error_ = GRPC_ERROR_NONE;
-
-  grpc_polling_entity* pollent_ = nullptr;
-
-  grpc_closure pick_closure_;
-
-  // Accessed while holding ChannelData::data_plane_mu_.
-  ChannelData::LbQueuedCall queued_call_;
-  bool queued_pending_lb_pick_ = false;
-  const LoadBalancingPolicy::BackendMetricData* backend_metric_data_ = nullptr;
-  RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
-  std::function<void(grpc_error*, LoadBalancingPolicy::MetadataInterface*,
-                     LoadBalancingPolicy::CallState*)>
-      lb_recv_trailing_metadata_ready_;
-  LbQueuedCallCanceller* lb_call_canceller_ = nullptr;
-
-  RefCountedPtr<SubchannelCall> subchannel_call_;
-
-  // 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;
-
-  // Batches are added to this list when received from above.
-  // They are removed when we are done handling the batch (i.e., when
-  // either we have invoked all of the batch's callbacks or we have
-  // passed the batch down to the subchannel call and are not
-  // intercepting any of its callbacks).
-  grpc_transport_stream_op_batch* pending_batches_[MAX_PENDING_BATCHES] = {};
+const grpc_channel_filter ClientChannel::kFilterVtable = {
+    ClientChannel::CallData::StartTransportStreamOpBatch,
+    ClientChannel::StartTransportOp,
+    sizeof(ClientChannel::CallData),
+    ClientChannel::CallData::Init,
+    ClientChannel::CallData::SetPollent,
+    ClientChannel::CallData::Destroy,
+    sizeof(ClientChannel),
+    ClientChannel::Init,
+    ClientChannel::Destroy,
+    ClientChannel::GetChannelInfo,
+    "client-channel",
 };
 
 //
 // dynamic termination filter
 //
 
-// Channel arg pointer vtable for GRPC_ARG_CLIENT_CHANNEL_DATA.
-void* ChannelDataArgCopy(void* p) { return p; }
-void ChannelDataArgDestroy(void* /*p*/) {}
-int ChannelDataArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
-const grpc_arg_pointer_vtable kChannelDataArgPointerVtable = {
-    ChannelDataArgCopy, ChannelDataArgDestroy, ChannelDataArgCmp};
-
-// Channel arg pointer vtable for GRPC_ARG_RETRY_THROTTLE_DATA.
-void* RetryThrottleDataArgCopy(void* p) {
-  auto* retry_throttle_data = static_cast<ServerRetryThrottleData*>(p);
-  retry_throttle_data->Ref().release();
+namespace {
+
+// Channel arg pointer vtable for GRPC_ARG_CLIENT_CHANNEL.
+void* ClientChannelArgCopy(void* p) { return p; }
+void ClientChannelArgDestroy(void* /*p*/) {}
+int ClientChannelArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
+const grpc_arg_pointer_vtable kClientChannelArgPointerVtable = {
+    ClientChannelArgCopy, ClientChannelArgDestroy, ClientChannelArgCmp};
+
+// Channel arg pointer vtable for GRPC_ARG_SERVICE_CONFIG_OBJ.
+void* ServiceConfigObjArgCopy(void* p) {
+  auto* service_config = static_cast<ServiceConfig*>(p);
+  service_config->Ref().release();
   return p;
 }
-void RetryThrottleDataArgDestroy(void* p) {
-  auto* retry_throttle_data = static_cast<ServerRetryThrottleData*>(p);
-  retry_throttle_data->Unref();
+void ServiceConfigObjArgDestroy(void* p) {
+  auto* service_config = static_cast<ServiceConfig*>(p);
+  service_config->Unref();
 }
-int RetryThrottleDataArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
-const grpc_arg_pointer_vtable kRetryThrottleDataArgPointerVtable = {
-    RetryThrottleDataArgCopy, RetryThrottleDataArgDestroy,
-    RetryThrottleDataArgCmp};
+int ServiceConfigObjArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
+const grpc_arg_pointer_vtable kServiceConfigObjArgPointerVtable = {
+    ServiceConfigObjArgCopy, ServiceConfigObjArgDestroy,
+    ServiceConfigObjArgCmp};
 
-class ChannelData::DynamicTerminationFilterChannelData {
+class DynamicTerminationFilter {
  public:
-  class DynamicTerminationFilterCallData;
+  class CallData;
 
-  static const grpc_channel_filter kDynamicTerminationFilterVtable;
+  static const grpc_channel_filter kFilterVtable;
 
-  static grpc_error* Init(grpc_channel_element* elem,
-                          grpc_channel_element_args* args) {
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args) {
     GPR_ASSERT(args->is_last);
-    GPR_ASSERT(elem->filter == &kDynamicTerminationFilterVtable);
-    new (elem->channel_data)
-        DynamicTerminationFilterChannelData(args->channel_args);
+    GPR_ASSERT(elem->filter == &kFilterVtable);
+    new (elem->channel_data) DynamicTerminationFilter(args->channel_args);
     return GRPC_ERROR_NONE;
   }
 
   static void Destroy(grpc_channel_element* elem) {
-    auto* chand =
-        static_cast<DynamicTerminationFilterChannelData*>(elem->channel_data);
-    chand->~DynamicTerminationFilterChannelData();
+    auto* chand = static_cast<DynamicTerminationFilter*>(elem->channel_data);
+    chand->~DynamicTerminationFilter();
   }
 
   // Will never be called.
@@ -1087,52 +302,30 @@ class ChannelData::DynamicTerminationFilterChannelData {
                              const grpc_channel_info* /*info*/) {}
 
  private:
-  static RefCountedPtr<ServerRetryThrottleData> GetRetryThrottleDataFromArgs(
-      const grpc_channel_args* args) {
-    auto* retry_throttle_data =
-        grpc_channel_args_find_pointer<ServerRetryThrottleData>(
-            args, GRPC_ARG_RETRY_THROTTLE_DATA);
-    if (retry_throttle_data == nullptr) return nullptr;
-    return retry_throttle_data->Ref();
-  }
-
-  explicit DynamicTerminationFilterChannelData(const grpc_channel_args* args)
-      : chand_(grpc_channel_args_find_pointer<ChannelData>(
-            args, GRPC_ARG_CLIENT_CHANNEL_DATA)),
-        retry_throttle_data_(GetRetryThrottleDataFromArgs(args)) {}
-
-  ChannelData* chand_;
-  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
+  explicit DynamicTerminationFilter(const grpc_channel_args* args)
+      : chand_(grpc_channel_args_find_pointer<ClientChannel>(
+            args, GRPC_ARG_CLIENT_CHANNEL)) {}
+
+  ClientChannel* chand_;
 };
 
-class ChannelData::DynamicTerminationFilterChannelData::
-    DynamicTerminationFilterCallData {
+class DynamicTerminationFilter::CallData {
  public:
-  static grpc_error* Init(grpc_call_element* elem,
-                          const grpc_call_element_args* args) {
-    new (elem->call_data) DynamicTerminationFilterCallData(*args);
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args) {
+    new (elem->call_data) CallData(*args);
     return GRPC_ERROR_NONE;
   }
 
   static void Destroy(grpc_call_element* elem,
                       const grpc_call_final_info* /*final_info*/,
                       grpc_closure* then_schedule_closure) {
-    auto* calld =
-        static_cast<DynamicTerminationFilterCallData*>(elem->call_data);
-    auto* chand =
-        static_cast<DynamicTerminationFilterChannelData*>(elem->channel_data);
+    auto* calld = static_cast<CallData*>(elem->call_data);
     RefCountedPtr<SubchannelCall> subchannel_call;
-    if (chand->chand_->enable_retries_) {
-      if (GPR_LIKELY(calld->retrying_call_ != nullptr)) {
-        subchannel_call = calld->retrying_call_->subchannel_call();
-        calld->retrying_call_->~RetryingCall();
-      }
-    } else {
-      if (GPR_LIKELY(calld->lb_call_ != nullptr)) {
-        subchannel_call = calld->lb_call_->subchannel_call();
-      }
+    if (GPR_LIKELY(calld->lb_call_ != nullptr)) {
+      subchannel_call = calld->lb_call_->subchannel_call();
     }
-    calld->~DynamicTerminationFilterCallData();
+    calld->~CallData();
     if (GPR_LIKELY(subchannel_call != nullptr)) {
       subchannel_call->SetAfterCallStackDestroy(then_schedule_closure);
     } else {
@@ -1143,60 +336,31 @@ class ChannelData::DynamicTerminationFilterChannelData::
 
   static void StartTransportStreamOpBatch(
       grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
-    auto* calld =
-        static_cast<DynamicTerminationFilterCallData*>(elem->call_data);
-    auto* chand =
-        static_cast<DynamicTerminationFilterChannelData*>(elem->channel_data);
-    if (chand->chand_->enable_retries_) {
-      calld->retrying_call_->StartTransportStreamOpBatch(batch);
-    } else {
-      calld->lb_call_->StartTransportStreamOpBatch(batch);
-    }
+    auto* calld = static_cast<CallData*>(elem->call_data);
+    calld->lb_call_->StartTransportStreamOpBatch(batch);
   }
 
   static void SetPollent(grpc_call_element* elem,
                          grpc_polling_entity* pollent) {
-    auto* calld =
-        static_cast<DynamicTerminationFilterCallData*>(elem->call_data);
-    auto* chand =
-        static_cast<DynamicTerminationFilterChannelData*>(elem->channel_data);
-    ChannelData* client_channel = chand->chand_;
+    auto* calld = static_cast<CallData*>(elem->call_data);
+    auto* chand = static_cast<DynamicTerminationFilter*>(elem->channel_data);
+    ClientChannel* client_channel = chand->chand_;
     grpc_call_element_args args = {
         calld->owning_call_,     nullptr,
         calld->call_context_,    calld->path_,
         calld->call_start_time_, calld->deadline_,
         calld->arena_,           calld->call_combiner_};
-    if (client_channel->enable_retries_) {
-      // Get retry settings from service config.
-      auto* svc_cfg_call_data = static_cast<ServiceConfigCallData*>(
-          calld->call_context_[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value);
-      GPR_ASSERT(svc_cfg_call_data != nullptr);
-      auto* method_config = static_cast<const ClientChannelMethodParsedConfig*>(
-          svc_cfg_call_data->GetMethodParsedConfig(
-              ClientChannelServiceConfigParser::ParserIndex()));
-      // Create retrying call.
-      calld->retrying_call_ = calld->arena_->New<ChannelData::RetryingCall>(
-          client_channel, args, pollent, chand->retry_throttle_data_,
-          method_config == nullptr ? nullptr : method_config->retry_policy());
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
-        gpr_log(
-            GPR_INFO,
-            "chand=%p dymamic_termination_calld=%p: create retrying_call=%p",
-            client_channel, calld, calld->retrying_call_);
-      }
-    } else {
-      calld->lb_call_ = ChannelData::LoadBalancedCall::Create(client_channel,
-                                                              args, pollent, 0);
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
-        gpr_log(GPR_INFO,
-                "chand=%p dynamic_termination_calld=%p: create lb_call=%p",
-                chand, client_channel, calld->lb_call_.get());
-      }
+    calld->lb_call_ =
+        client_channel->CreateLoadBalancedCall(args, pollent, nullptr);
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p dynamic_termination_calld=%p: create lb_call=%p", chand,
+              client_channel, calld->lb_call_.get());
     }
   }
 
  private:
-  explicit DynamicTerminationFilterCallData(const grpc_call_element_args& args)
+  explicit CallData(const grpc_call_element_args& args)
       : path_(grpc_slice_ref_internal(args.path)),
         call_start_time_(args.start_time),
         deadline_(args.deadline),
@@ -1205,7 +369,7 @@ class ChannelData::DynamicTerminationFilterChannelData::
         call_combiner_(args.call_combiner),
         call_context_(args.context) {}
 
-  ~DynamicTerminationFilterCallData() { grpc_slice_unref_internal(path_); }
+  ~CallData() { grpc_slice_unref_internal(path_); }
 
   grpc_slice path_;  // Request path.
   gpr_cycle_counter call_start_time_;
@@ -1215,32 +379,58 @@ class ChannelData::DynamicTerminationFilterChannelData::
   CallCombiner* call_combiner_;
   grpc_call_context_element* call_context_;
 
-  ChannelData::RetryingCall* retrying_call_ = nullptr;
-  RefCountedPtr<LoadBalancedCall> lb_call_;
+  RefCountedPtr<ClientChannel::LoadBalancedCall> lb_call_;
 };
 
-const grpc_channel_filter ChannelData::DynamicTerminationFilterChannelData::
-    kDynamicTerminationFilterVtable = {
-        ChannelData::DynamicTerminationFilterChannelData::
-            DynamicTerminationFilterCallData::StartTransportStreamOpBatch,
-        ChannelData::DynamicTerminationFilterChannelData::StartTransportOp,
-        sizeof(ChannelData::DynamicTerminationFilterChannelData::
-                   DynamicTerminationFilterCallData),
-        ChannelData::DynamicTerminationFilterChannelData::
-            DynamicTerminationFilterCallData::Init,
-        ChannelData::DynamicTerminationFilterChannelData::
-            DynamicTerminationFilterCallData::SetPollent,
-        ChannelData::DynamicTerminationFilterChannelData::
-            DynamicTerminationFilterCallData::Destroy,
-        sizeof(ChannelData::DynamicTerminationFilterChannelData),
-        ChannelData::DynamicTerminationFilterChannelData::Init,
-        ChannelData::DynamicTerminationFilterChannelData::Destroy,
-        ChannelData::DynamicTerminationFilterChannelData::GetChannelInfo,
-        "dynamic_filter_termination",
+const grpc_channel_filter DynamicTerminationFilter::kFilterVtable = {
+    DynamicTerminationFilter::CallData::StartTransportStreamOpBatch,
+    DynamicTerminationFilter::StartTransportOp,
+    sizeof(DynamicTerminationFilter::CallData),
+    DynamicTerminationFilter::CallData::Init,
+    DynamicTerminationFilter::CallData::SetPollent,
+    DynamicTerminationFilter::CallData::Destroy,
+    sizeof(DynamicTerminationFilter),
+    DynamicTerminationFilter::Init,
+    DynamicTerminationFilter::Destroy,
+    DynamicTerminationFilter::GetChannelInfo,
+    "dynamic_filter_termination",
+};
+
+}  // namespace
+
+//
+// ClientChannel::ResolverResultHandler
+//
+
+class ClientChannel::ResolverResultHandler : public Resolver::ResultHandler {
+ public:
+  explicit ResolverResultHandler(ClientChannel* chand) : chand_(chand) {
+    GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ResolverResultHandler");
+  }
+
+  ~ResolverResultHandler() override {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
+      gpr_log(GPR_INFO, "chand=%p: resolver shutdown complete", chand_);
+    }
+    GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "ResolverResultHandler");
+  }
+
+  void ReturnResult(Resolver::Result result) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+    chand_->OnResolverResultChangedLocked(std::move(result));
+  }
+
+  void ReturnError(grpc_error_handle error) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+    chand_->OnResolverErrorLocked(error);
+  }
+
+ private:
+  ClientChannel* chand_;
 };
 
 //
-// ChannelData::SubchannelWrapper
+// ClientChannel::SubchannelWrapper
 //
 
 // This class is a wrapper for Subchannel that hides details of the
@@ -1251,9 +441,9 @@ const grpc_channel_filter ChannelData::DynamicTerminationFilterChannelData::
 // 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 work_serializer.
-class ChannelData::SubchannelWrapper : public SubchannelInterface {
+class ClientChannel::SubchannelWrapper : public SubchannelInterface {
  public:
-  SubchannelWrapper(ChannelData* chand, RefCountedPtr<Subchannel> subchannel,
+  SubchannelWrapper(ClientChannel* chand, RefCountedPtr<Subchannel> subchannel,
                     absl::optional<std::string> health_check_service_name)
       : SubchannelInterface(
             GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)
@@ -1301,7 +491,8 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
     GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "SubchannelWrapper");
   }
 
-  grpc_connectivity_state CheckConnectivityState() override {
+  grpc_connectivity_state CheckConnectivityState() override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     RefCountedPtr<ConnectedSubchannel> connected_subchannel;
     grpc_connectivity_state connectivity_state =
         subchannel_->CheckConnectivityState(health_check_service_name_,
@@ -1380,16 +571,19 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
   }
 
   // Caller must be holding the control-plane work_serializer.
-  ConnectedSubchannel* connected_subchannel() const {
+  ConnectedSubchannel* connected_subchannel() const
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::work_serializer_) {
     return connected_subchannel_.get();
   }
 
   // Caller must be holding the data-plane mutex.
-  ConnectedSubchannel* connected_subchannel_in_data_plane() const {
+  ConnectedSubchannel* connected_subchannel_in_data_plane() const
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_) {
     return connected_subchannel_in_data_plane_.get();
   }
   void set_connected_subchannel_in_data_plane(
-      RefCountedPtr<ConnectedSubchannel> connected_subchannel) {
+      RefCountedPtr<ConnectedSubchannel> connected_subchannel)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_) {
     connected_subchannel_in_data_plane_ = std::move(connected_subchannel);
   }
 
@@ -1422,7 +616,10 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
     ~WatcherWrapper() override {
       auto* parent = parent_.release();  // ref owned by lambda
       parent->chand_->work_serializer_->Run(
-          [parent]() { parent->Unref(DEBUG_LOCATION, "WatcherWrapper"); },
+          [parent]()
+              ABSL_EXCLUSIVE_LOCKS_REQUIRED(parent_->chand_->work_serializer_) {
+                parent->Unref(DEBUG_LOCATION, "WatcherWrapper");
+              },
           DEBUG_LOCATION);
     }
 
@@ -1435,10 +632,11 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
       }
       Ref().release();  // ref owned by lambda
       parent_->chand_->work_serializer_->Run(
-          [this]() {
-            ApplyUpdateInControlPlaneWorkSerializer();
-            Unref();
-          },
+          [this]()
+              ABSL_EXCLUSIVE_LOCKS_REQUIRED(parent_->chand_->work_serializer_) {
+                ApplyUpdateInControlPlaneWorkSerializer();
+                Unref();
+              },
           DEBUG_LOCATION);
     }
 
@@ -1459,7 +657,8 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
     grpc_connectivity_state last_seen_state() const { return last_seen_state_; }
 
    private:
-    void ApplyUpdateInControlPlaneWorkSerializer() {
+    void ApplyUpdateInControlPlaneWorkSerializer()
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(parent_->chand_->work_serializer_) {
       if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
         gpr_log(GPR_INFO,
                 "chand=%p: processing connectivity change in work serializer "
@@ -1513,7 +712,8 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
   };
 
   void MaybeUpdateConnectedSubchannel(
-      RefCountedPtr<ConnectedSubchannel> connected_subchannel) {
+      RefCountedPtr<ConnectedSubchannel> connected_subchannel)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::work_serializer_) {
     // Update the connected subchannel only if the channel is not shutting
     // down.  This is because once the channel is shutting down, we
     // ignore picker updates from the LB policy, which means that
@@ -1521,7 +721,7 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
     // in chand_->pending_subchannel_updates_.  So we don't want to add
     // entries there that will never be processed, since that would
     // leave dangling refs to the channel and prevent its destruction.
-    grpc_error* disconnect_error = chand_->disconnect_error();
+    grpc_error_handle disconnect_error = chand_->disconnect_error();
     if (disconnect_error != GRPC_ERROR_NONE) return;
     // Not shutting down, so do the update.
     if (connected_subchannel_ != connected_subchannel) {
@@ -1533,7 +733,7 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
     }
   }
 
-  ChannelData* chand_;
+  ClientChannel* chand_;
   RefCountedPtr<Subchannel> subchannel_;
   absl::optional<std::string> health_check_service_name_;
   // Maps from the address of the watcher passed to us by the LB policy
@@ -1543,17 +743,19 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
   // corresponding WrapperWatcher to cancel on the underlying subchannel.
   std::map<ConnectivityStateWatcherInterface*, WatcherWrapper*> watcher_map_;
   // To be accessed only in the control plane work_serializer.
-  RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
+  RefCountedPtr<ConnectedSubchannel> connected_subchannel_
+      ABSL_GUARDED_BY(&ClientChannel::work_serializer_);
   // To be accessed only in the data plane mutex.
-  RefCountedPtr<ConnectedSubchannel> connected_subchannel_in_data_plane_;
+  RefCountedPtr<ConnectedSubchannel> connected_subchannel_in_data_plane_
+      ABSL_GUARDED_BY(&ClientChannel::data_plane_mu_);
 };
 
 //
-// ChannelData::ExternalConnectivityWatcher
+// ClientChannel::ExternalConnectivityWatcher
 //
 
-ChannelData::ExternalConnectivityWatcher::ExternalConnectivityWatcher(
-    ChannelData* chand, grpc_polling_entity pollent,
+ClientChannel::ExternalConnectivityWatcher::ExternalConnectivityWatcher(
+    ClientChannel* chand, grpc_polling_entity pollent,
     grpc_connectivity_state* state, grpc_closure* on_complete,
     grpc_closure* watcher_timer_init)
     : chand_(chand),
@@ -1575,22 +777,22 @@ ChannelData::ExternalConnectivityWatcher::ExternalConnectivityWatcher(
   }
   // Pass the ref from creating the object to Start().
   chand_->work_serializer_->Run(
-      [this]() {
+      [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
         // The ref is passed to AddWatcherLocked().
         AddWatcherLocked();
       },
       DEBUG_LOCATION);
 }
 
-ChannelData::ExternalConnectivityWatcher::~ExternalConnectivityWatcher() {
+ClientChannel::ExternalConnectivityWatcher::~ExternalConnectivityWatcher() {
   grpc_polling_entity_del_from_pollset_set(&pollent_,
                                            chand_->interested_parties_);
   GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_,
                            "ExternalConnectivityWatcher");
 }
 
-void ChannelData::ExternalConnectivityWatcher::
-    RemoveWatcherFromExternalWatchersMap(ChannelData* chand,
+void ClientChannel::ExternalConnectivityWatcher::
+    RemoveWatcherFromExternalWatchersMap(ClientChannel* chand,
                                          grpc_closure* on_complete,
                                          bool cancel) {
   RefCountedPtr<ExternalConnectivityWatcher> watcher;
@@ -1607,7 +809,7 @@ void ChannelData::ExternalConnectivityWatcher::
   if (watcher != nullptr && cancel) watcher->Cancel();
 }
 
-void ChannelData::ExternalConnectivityWatcher::Notify(
+void ClientChannel::ExternalConnectivityWatcher::Notify(
     grpc_connectivity_state state, const absl::Status& /* status */) {
   bool done = false;
   if (!done_.CompareExchangeStrong(&done, true, MemoryOrder::RELAXED,
@@ -1615,7 +817,8 @@ void ChannelData::ExternalConnectivityWatcher::Notify(
     return;  // Already done.
   }
   // Remove external watcher.
-  chand_->RemoveExternalConnectivityWatcher(on_complete_, /*cancel=*/false);
+  ExternalConnectivityWatcher::RemoveWatcherFromExternalWatchersMap(
+      chand_, on_complete_, /*cancel=*/false);
   // Report new state to the user.
   *state_ = state;
   ExecCtx::Run(DEBUG_LOCATION, on_complete_, GRPC_ERROR_NONE);
@@ -1623,12 +826,15 @@ void ChannelData::ExternalConnectivityWatcher::Notify(
   // Not needed in state SHUTDOWN, because the tracker will
   // automatically remove all watchers in that case.
   if (state != GRPC_CHANNEL_SHUTDOWN) {
-    chand_->work_serializer_->Run([this]() { RemoveWatcherLocked(); },
-                                  DEBUG_LOCATION);
+    chand_->work_serializer_->Run(
+        [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+          RemoveWatcherLocked();
+        },
+        DEBUG_LOCATION);
   }
 }
 
-void ChannelData::ExternalConnectivityWatcher::Cancel() {
+void ClientChannel::ExternalConnectivityWatcher::Cancel() {
   bool done = false;
   if (!done_.CompareExchangeStrong(&done, true, MemoryOrder::RELAXED,
                                    MemoryOrder::RELAXED)) {
@@ -1636,84 +842,95 @@ void ChannelData::ExternalConnectivityWatcher::Cancel() {
   }
   ExecCtx::Run(DEBUG_LOCATION, on_complete_, GRPC_ERROR_CANCELLED);
   // Hop back into the work_serializer to clean up.
-  chand_->work_serializer_->Run([this]() { RemoveWatcherLocked(); },
-                                DEBUG_LOCATION);
+  chand_->work_serializer_->Run(
+      [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+        RemoveWatcherLocked();
+      },
+      DEBUG_LOCATION);
 }
 
-void ChannelData::ExternalConnectivityWatcher::AddWatcherLocked() {
+void ClientChannel::ExternalConnectivityWatcher::AddWatcherLocked() {
   Closure::Run(DEBUG_LOCATION, watcher_timer_init_, GRPC_ERROR_NONE);
   // Add new watcher. Pass the ref of the object from creation to OrphanablePtr.
   chand_->state_tracker_.AddWatcher(
       initial_state_, OrphanablePtr<ConnectivityStateWatcherInterface>(this));
 }
 
-void ChannelData::ExternalConnectivityWatcher::RemoveWatcherLocked() {
+void ClientChannel::ExternalConnectivityWatcher::RemoveWatcherLocked() {
   chand_->state_tracker_.RemoveWatcher(this);
 }
 
 //
-// ChannelData::ConnectivityWatcherAdder
+// ClientChannel::ConnectivityWatcherAdder
 //
 
-class ChannelData::ConnectivityWatcherAdder {
+class ClientChannel::ConnectivityWatcherAdder {
  public:
   ConnectivityWatcherAdder(
-      ChannelData* chand, grpc_connectivity_state initial_state,
+      ClientChannel* chand, grpc_connectivity_state initial_state,
       OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher)
       : chand_(chand),
         initial_state_(initial_state),
         watcher_(std::move(watcher)) {
     GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ConnectivityWatcherAdder");
-    chand_->work_serializer_->Run([this]() { AddWatcherLocked(); },
-                                  DEBUG_LOCATION);
+    chand_->work_serializer_->Run(
+        [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+          AddWatcherLocked();
+        },
+        DEBUG_LOCATION);
   }
 
  private:
-  void AddWatcherLocked() {
+  void AddWatcherLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     chand_->state_tracker_.AddWatcher(initial_state_, std::move(watcher_));
     GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "ConnectivityWatcherAdder");
     delete this;
   }
 
-  ChannelData* chand_;
+  ClientChannel* chand_;
   grpc_connectivity_state initial_state_;
   OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher_;
 };
 
 //
-// ChannelData::ConnectivityWatcherRemover
+// ClientChannel::ConnectivityWatcherRemover
 //
 
-class ChannelData::ConnectivityWatcherRemover {
+class ClientChannel::ConnectivityWatcherRemover {
  public:
-  ConnectivityWatcherRemover(ChannelData* chand,
+  ConnectivityWatcherRemover(ClientChannel* chand,
                              AsyncConnectivityStateWatcherInterface* watcher)
       : chand_(chand), watcher_(watcher) {
     GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ConnectivityWatcherRemover");
-    chand_->work_serializer_->Run([this]() { RemoveWatcherLocked(); },
-                                  DEBUG_LOCATION);
+    chand_->work_serializer_->Run(
+        [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+          RemoveWatcherLocked();
+        },
+        DEBUG_LOCATION);
   }
 
  private:
-  void RemoveWatcherLocked() {
+  void RemoveWatcherLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     chand_->state_tracker_.RemoveWatcher(watcher_);
     GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_,
                              "ConnectivityWatcherRemover");
     delete this;
   }
 
-  ChannelData* chand_;
+  ClientChannel* chand_;
   AsyncConnectivityStateWatcherInterface* watcher_;
 };
 
 //
-// ChannelData::ClientChannelControlHelper
+// ClientChannel::ClientChannelControlHelper
 //
 
-class ChannelData::ClientChannelControlHelper
+class ClientChannel::ClientChannelControlHelper
     : public LoadBalancingPolicy::ChannelControlHelper {
  public:
-  explicit ClientChannelControlHelper(ChannelData* chand) : chand_(chand) {
+  explicit ClientChannelControlHelper(ClientChannel* chand) : chand_(chand) {
     GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ClientChannelControlHelper");
   }
 
@@ -1723,11 +940,12 @@ class ChannelData::ClientChannelControlHelper
   }
 
   RefCountedPtr<SubchannelInterface> CreateSubchannel(
-      ServerAddress address, const grpc_channel_args& args) override {
+      ServerAddress address, const grpc_channel_args& args) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     if (chand_->resolver_ == nullptr) return nullptr;  // Shutting down.
     // Determine health check service name.
-    bool inhibit_health_checking = grpc_channel_arg_get_bool(
-        grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false);
+    bool inhibit_health_checking = grpc_channel_args_find_bool(
+        &args, GRPC_ARG_INHIBIT_HEALTH_CHECKING, false);
     absl::optional<std::string> health_check_service_name;
     if (!inhibit_health_checking) {
       health_check_service_name = chand_->health_check_service_name_;
@@ -1766,9 +984,10 @@ class ChannelData::ClientChannelControlHelper
 
   void UpdateState(
       grpc_connectivity_state state, const absl::Status& status,
-      std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker) override {
+      std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     if (chand_->resolver_ == nullptr) return;  // Shutting down.
-    grpc_error* disconnect_error = chand_->disconnect_error();
+    grpc_error_handle disconnect_error = chand_->disconnect_error();
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       const char* extra = disconnect_error == GRPC_ERROR_NONE
                               ? ""
@@ -1784,7 +1003,8 @@ class ChannelData::ClientChannelControlHelper
     }
   }
 
-  void RequestReresolution() override {
+  void RequestReresolution() override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     if (chand_->resolver_ == nullptr) return;  // Shutting down.
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO, "chand=%p: started name re-resolving", chand_);
@@ -1792,8 +1012,8 @@ class ChannelData::ClientChannelControlHelper
     chand_->resolver_->RequestReresolutionLocked();
   }
 
-  void AddTraceEvent(TraceSeverity severity,
-                     absl::string_view message) override {
+  void AddTraceEvent(TraceSeverity severity, absl::string_view message) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     if (chand_->resolver_ == nullptr) return;  // Shutting down.
     if (chand_->channelz_node_ != nullptr) {
       chand_->channelz_node_->AddTraceEvent(
@@ -1810,42 +1030,44 @@ class ChannelData::ClientChannelControlHelper
     return channelz::ChannelTrace::Error;
   }
 
-  ChannelData* chand_;
+  ClientChannel* chand_;
 };
 
 //
-// ChannelData implementation
+// ClientChannel implementation
 //
 
-grpc_error* ChannelData::Init(grpc_channel_element* elem,
-                              grpc_channel_element_args* args) {
+ClientChannel* ClientChannel::GetFromChannel(grpc_channel* channel) {
+  grpc_channel_element* elem =
+      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
+  if (elem->filter != &kFilterVtable) return nullptr;
+  return static_cast<ClientChannel*>(elem->channel_data);
+}
+
+grpc_error_handle ClientChannel::Init(grpc_channel_element* elem,
+                                      grpc_channel_element_args* args) {
   GPR_ASSERT(args->is_last);
-  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
-  grpc_error* error = GRPC_ERROR_NONE;
-  new (elem->channel_data) ChannelData(args, &error);
+  GPR_ASSERT(elem->filter == &kFilterVtable);
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  new (elem->channel_data) ClientChannel(args, &error);
   return error;
 }
 
-void ChannelData::Destroy(grpc_channel_element* elem) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
-  chand->~ChannelData();
+void ClientChannel::Destroy(grpc_channel_element* elem) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
+  chand->~ClientChannel();
 }
 
-bool GetEnableRetries(const grpc_channel_args* args) {
-  return grpc_channel_arg_get_bool(
-      grpc_channel_args_find(args, GRPC_ARG_ENABLE_RETRIES), true);
-}
+namespace {
 
-size_t GetMaxPerRpcRetryBufferSize(const grpc_channel_args* args) {
-  return static_cast<size_t>(grpc_channel_arg_get_integer(
-      grpc_channel_args_find(args, GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE),
-      {DEFAULT_PER_RPC_RETRY_BUFFER_SIZE, 0, INT_MAX}));
+bool GetEnableRetries(const grpc_channel_args* args) {
+  return grpc_channel_args_find_bool(args, GRPC_ARG_ENABLE_RETRIES, false);
 }
 
 RefCountedPtr<SubchannelPoolInterface> GetSubchannelPool(
     const grpc_channel_args* args) {
-  const bool use_local_subchannel_pool = grpc_channel_arg_get_bool(
-      grpc_channel_args_find(args, GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL), false);
+  const bool use_local_subchannel_pool = grpc_channel_args_find_bool(
+      args, GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, false);
   if (use_local_subchannel_pool) {
     return MakeRefCounted<LocalSubchannelPool>();
   }
@@ -1853,26 +1075,23 @@ RefCountedPtr<SubchannelPoolInterface> GetSubchannelPool(
 }
 
 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;
+  return grpc_channel_args_find_pointer<channelz::ChannelNode>(
+      args, GRPC_ARG_CHANNELZ_CHANNEL_NODE);
 }
 
-ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
+}  // namespace
+
+ClientChannel::ClientChannel(grpc_channel_element_args* args,
+                             grpc_error_handle* error)
     : deadline_checking_enabled_(
           grpc_deadline_checking_enabled(args->channel_args)),
       enable_retries_(GetEnableRetries(args->channel_args)),
-      per_rpc_retry_buffer_size_(
-          GetMaxPerRpcRetryBufferSize(args->channel_args)),
       owning_stack_(args->channel_stack),
       client_channel_factory_(
           ClientChannelFactory::GetFromChannelArgs(args->channel_args)),
       channelz_node_(GetChannelzNode(args->channel_args)),
-      work_serializer_(std::make_shared<WorkSerializer>()),
       interested_parties_(grpc_pollset_set_create()),
+      work_serializer_(std::make_shared<WorkSerializer>()),
       state_tracker_("client_channel", GRPC_CHANNEL_IDLE),
       subchannel_pool_(GetSubchannelPool(args->channel_args)),
       disconnect_error_(GRPC_ERROR_NONE) {
@@ -1889,8 +1108,8 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
     return;
   }
   // Get server name to resolve, using proxy mapper if needed.
-  const char* server_uri = grpc_channel_arg_get_string(
-      grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI));
+  const char* server_uri =
+      grpc_channel_args_find_string(args->channel_args, GRPC_ARG_SERVER_URI);
   if (server_uri == nullptr) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "server URI channel arg missing or wrong type in client channel "
@@ -1899,8 +1118,8 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
   }
   // Get default service config.  If none is specified via the client API,
   // we use an empty config.
-  const char* service_config_json = grpc_channel_arg_get_string(
-      grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG));
+  const char* service_config_json = grpc_channel_args_find_string(
+      args->channel_args, GRPC_ARG_SERVICE_CONFIG);
   if (service_config_json == nullptr) service_config_json = "{}";
   *error = GRPC_ERROR_NONE;
   default_service_config_ =
@@ -1937,7 +1156,7 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
   *error = GRPC_ERROR_NONE;
 }
 
-ChannelData::~ChannelData() {
+ClientChannel::~ClientChannel() {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p: destroying channel", this);
   }
@@ -1950,6 +1169,16 @@ ChannelData::~ChannelData() {
   GRPC_ERROR_UNREF(disconnect_error_.Load(MemoryOrder::RELAXED));
 }
 
+RefCountedPtr<ClientChannel::LoadBalancedCall>
+ClientChannel::CreateLoadBalancedCall(
+    const grpc_call_element_args& args, grpc_polling_entity* pollent,
+    grpc_closure* on_call_destruction_complete) {
+  return args.arena->New<LoadBalancedCall>(this, args, pollent,
+                                           on_call_destruction_complete);
+}
+
+namespace {
+
 RefCountedPtr<LoadBalancingPolicy::Config> ChooseLbPolicy(
     const Resolver::Result& resolver_result,
     const internal::ClientChannelGlobalParsedConfig* parsed_service_config) {
@@ -1963,9 +1192,8 @@ RefCountedPtr<LoadBalancingPolicy::Config> ChooseLbPolicy(
   if (!parsed_service_config->parsed_deprecated_lb_policy().empty()) {
     policy_name = parsed_service_config->parsed_deprecated_lb_policy().c_str();
   } else {
-    const grpc_arg* channel_arg =
-        grpc_channel_args_find(resolver_result.args, GRPC_ARG_LB_POLICY_NAME);
-    policy_name = grpc_channel_arg_get_string(channel_arg);
+    policy_name = grpc_channel_args_find_string(resolver_result.args,
+                                                GRPC_ARG_LB_POLICY_NAME);
   }
   // Use pick_first if nothing was specified and we didn't select grpclb
   // above.
@@ -1974,7 +1202,7 @@ RefCountedPtr<LoadBalancingPolicy::Config> ChooseLbPolicy(
   Json config_json = Json::Array{Json::Object{
       {policy_name, Json::Object{}},
   }};
-  grpc_error* parse_error = GRPC_ERROR_NONE;
+  grpc_error_handle parse_error = GRPC_ERROR_NONE;
   auto lb_policy_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
       config_json, &parse_error);
   // The policy name came from one of three places:
@@ -1994,7 +1222,9 @@ RefCountedPtr<LoadBalancingPolicy::Config> ChooseLbPolicy(
   return lb_policy_config;
 }
 
-void ChannelData::OnResolverResultChangedLocked(Resolver::Result result) {
+}  // namespace
+
+void ClientChannel::OnResolverResultChangedLocked(Resolver::Result result) {
   // Handle race conditions.
   if (resolver_ == nullptr) return;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
@@ -2017,21 +1247,19 @@ void ChannelData::OnResolverResultChangedLocked(Resolver::Result result) {
     trace_strings.push_back("Address list became non-empty");
   }
   previous_resolution_contained_addresses_ = !result.addresses.empty();
-  // The result of grpc_error_string() is owned by the error itself.
-  // We're storing that string in trace_strings, so we need to make sure
-  // that the error lives until we're done with the string.
-  grpc_error* service_config_error =
-      GRPC_ERROR_REF(result.service_config_error);
-  if (service_config_error != GRPC_ERROR_NONE) {
-    trace_strings.push_back(grpc_error_string(service_config_error));
+  std::string service_config_error_string_storage;
+  if (result.service_config_error != GRPC_ERROR_NONE) {
+    service_config_error_string_storage =
+        grpc_error_std_string(result.service_config_error);
+    trace_strings.push_back(service_config_error_string_storage.c_str());
   }
   // Choose the service config.
   RefCountedPtr<ServiceConfig> service_config;
   RefCountedPtr<ConfigSelector> config_selector;
-  if (service_config_error != GRPC_ERROR_NONE) {
+  if (result.service_config_error != GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO, "chand=%p: resolver returned service config error: %s",
-              this, grpc_error_string(service_config_error));
+              this, grpc_error_std_string(result.service_config_error).c_str());
     }
     // If the service config was invalid, then fallback to the
     // previously returned service config.
@@ -2048,7 +1276,7 @@ void ChannelData::OnResolverResultChangedLocked(Resolver::Result result) {
       // We received an invalid service config and we don't have a
       // previous service config to fall back to.  Put the channel into
       // TRANSIENT_FAILURE.
-      OnResolverErrorLocked(GRPC_ERROR_REF(service_config_error));
+      OnResolverErrorLocked(GRPC_ERROR_REF(result.service_config_error));
       trace_strings.push_back("no valid service config");
     }
   } else if (result.service_config == nullptr) {
@@ -2113,24 +1341,24 @@ void ChannelData::OnResolverResultChangedLocked(Resolver::Result result) {
                                     grpc_slice_from_cpp_string(message));
     }
   }
-  GRPC_ERROR_UNREF(service_config_error);
 }
 
-void ChannelData::OnResolverErrorLocked(grpc_error* error) {
+void ClientChannel::OnResolverErrorLocked(grpc_error_handle error) {
   if (resolver_ == nullptr) {
     GRPC_ERROR_UNREF(error);
     return;
   }
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p: resolver transient failure: %s", this,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   // If we already have an LB policy from a previous resolution
   // result, then we continue to let it set the connectivity state.
   // Otherwise, we go into TRANSIENT_FAILURE.
   if (lb_policy_ == nullptr) {
-    grpc_error* state_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-        "Resolver transient failure", &error, 1);
+    grpc_error_handle state_error =
+        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+            "Resolver transient failure", &error, 1);
     {
       MutexLock lock(&resolution_mu_);
       // Update resolver transient failure.
@@ -2141,7 +1369,7 @@ void ChannelData::OnResolverErrorLocked(grpc_error* error) {
            call = call->next) {
         grpc_call_element* elem = call->elem;
         CallData* calld = static_cast<CallData*>(elem->call_data);
-        grpc_error* error = GRPC_ERROR_NONE;
+        grpc_error_handle error = GRPC_ERROR_NONE;
         if (calld->CheckResolutionLocked(elem, &error)) {
           calld->AsyncResolutionDone(elem, error);
         }
@@ -2157,7 +1385,7 @@ void ChannelData::OnResolverErrorLocked(grpc_error* error) {
   GRPC_ERROR_UNREF(error);
 }
 
-void ChannelData::CreateOrUpdateLbPolicyLocked(
+void ClientChannel::CreateOrUpdateLbPolicyLocked(
     RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
     Resolver::Result result) {
   // Construct update.
@@ -2183,7 +1411,7 @@ void ChannelData::CreateOrUpdateLbPolicyLocked(
 }
 
 // Creates a new LB policy.
-OrphanablePtr<LoadBalancingPolicy> ChannelData::CreateLbPolicyLocked(
+OrphanablePtr<LoadBalancingPolicy> ClientChannel::CreateLbPolicyLocked(
     const grpc_channel_args& args) {
   LoadBalancingPolicy::Args lb_policy_args;
   lb_policy_args.work_serializer = work_serializer_;
@@ -2202,8 +1430,8 @@ OrphanablePtr<LoadBalancingPolicy> ChannelData::CreateLbPolicyLocked(
   return lb_policy;
 }
 
-void ChannelData::AddResolverQueuedCall(ResolverQueuedCall* call,
-                                        grpc_polling_entity* pollent) {
+void ClientChannel::AddResolverQueuedCall(ResolverQueuedCall* call,
+                                          grpc_polling_entity* pollent) {
   // Add call to queued calls list.
   call->next = resolver_queued_calls_;
   resolver_queued_calls_ = call;
@@ -2212,8 +1440,8 @@ void ChannelData::AddResolverQueuedCall(ResolverQueuedCall* call,
   grpc_polling_entity_add_to_pollset_set(pollent, interested_parties_);
 }
 
-void ChannelData::RemoveResolverQueuedCall(ResolverQueuedCall* to_remove,
-                                           grpc_polling_entity* pollent) {
+void ClientChannel::RemoveResolverQueuedCall(ResolverQueuedCall* to_remove,
+                                             grpc_polling_entity* pollent) {
   // Remove call's pollent from channel's interested_parties.
   grpc_polling_entity_del_from_pollset_set(pollent, interested_parties_);
   // Remove from queued calls list.
@@ -2226,7 +1454,7 @@ void ChannelData::RemoveResolverQueuedCall(ResolverQueuedCall* to_remove,
   }
 }
 
-void ChannelData::UpdateServiceConfigInControlPlaneLocked(
+void ClientChannel::UpdateServiceConfigInControlPlaneLocked(
     RefCountedPtr<ServiceConfig> service_config,
     RefCountedPtr<ConfigSelector> config_selector,
     const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
@@ -2266,7 +1494,7 @@ void ChannelData::UpdateServiceConfigInControlPlaneLocked(
   }
 }
 
-void ChannelData::UpdateServiceConfigInDataPlaneLocked() {
+void ClientChannel::UpdateServiceConfigInDataPlaneLocked() {
   // Grab ref to service config.
   RefCountedPtr<ServiceConfig> service_config = saved_service_config_;
   // Grab ref to config selector.  Use default if resolver didn't supply one.
@@ -2279,33 +1507,22 @@ void ChannelData::UpdateServiceConfigInDataPlaneLocked() {
     config_selector =
         MakeRefCounted<DefaultConfigSelector>(saved_service_config_);
   }
-  // Get retry throttle data from service config.
-  const internal::ClientChannelGlobalParsedConfig* parsed_service_config =
-      static_cast<const internal::ClientChannelGlobalParsedConfig*>(
-          saved_service_config_->GetGlobalParsedConfig(
-              internal::ClientChannelServiceConfigParser::ParserIndex()));
-  absl::optional<internal::ClientChannelGlobalParsedConfig::RetryThrottling>
-      retry_throttle_config = parsed_service_config->retry_throttling();
-  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data;
-  if (retry_throttle_config.has_value()) {
-    retry_throttle_data = internal::ServerRetryThrottleMap::GetDataForServer(
-        server_name_, retry_throttle_config.value().max_milli_tokens,
-        retry_throttle_config.value().milli_token_ratio);
-  }
   // Construct dynamic filter stack.
   std::vector<const grpc_channel_filter*> filters =
       config_selector->GetFilters();
-  filters.push_back(
-      &DynamicTerminationFilterChannelData::kDynamicTerminationFilterVtable);
-  absl::InlinedVector<grpc_arg, 2> args_to_add;
-  args_to_add.push_back(grpc_channel_arg_pointer_create(
-      const_cast<char*>(GRPC_ARG_CLIENT_CHANNEL_DATA), this,
-      &kChannelDataArgPointerVtable));
-  if (retry_throttle_data != nullptr) {
-    args_to_add.push_back(grpc_channel_arg_pointer_create(
-        const_cast<char*>(GRPC_ARG_RETRY_THROTTLE_DATA),
-        retry_throttle_data.get(), &kRetryThrottleDataArgPointerVtable));
-  }
+  if (enable_retries_) {
+    filters.push_back(&kRetryFilterVtable);
+  } else {
+    filters.push_back(&DynamicTerminationFilter::kFilterVtable);
+  }
+  absl::InlinedVector<grpc_arg, 2> args_to_add = {
+      grpc_channel_arg_pointer_create(
+          const_cast<char*>(GRPC_ARG_CLIENT_CHANNEL), this,
+          &kClientChannelArgPointerVtable),
+      grpc_channel_arg_pointer_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG_OBJ), service_config.get(),
+          &kServiceConfigObjArgPointerVtable),
+  };
   grpc_channel_args* new_args = grpc_channel_args_copy_and_add(
       channel_args_, args_to_add.data(), args_to_add.size());
   new_args = config_selector->ModifyChannelArgs(new_args);
@@ -2333,7 +1550,7 @@ void ChannelData::UpdateServiceConfigInDataPlaneLocked() {
          call = call->next) {
       grpc_call_element* elem = call->elem;
       CallData* calld = static_cast<CallData*>(elem->call_data);
-      grpc_error* error = GRPC_ERROR_NONE;
+      grpc_error_handle error = GRPC_ERROR_NONE;
       if (calld->CheckResolutionLocked(elem, &error)) {
         calld->AsyncResolutionDone(elem, error);
       }
@@ -2343,7 +1560,7 @@ void ChannelData::UpdateServiceConfigInDataPlaneLocked() {
   // of scope.
 }
 
-void ChannelData::CreateResolverLocked() {
+void ClientChannel::CreateResolverLocked() {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p: starting name resolution", this);
   }
@@ -2362,7 +1579,7 @@ void ChannelData::CreateResolverLocked() {
   }
 }
 
-void ChannelData::DestroyResolverAndLbPolicyLocked() {
+void ClientChannel::DestroyResolverAndLbPolicyLocked() {
   if (resolver_ != nullptr) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO, "chand=%p: shutting down resolver=%p", this,
@@ -2381,7 +1598,7 @@ void ChannelData::DestroyResolverAndLbPolicyLocked() {
   }
 }
 
-void ChannelData::UpdateStateAndPickerLocked(
+void ClientChannel::UpdateStateAndPickerLocked(
     grpc_connectivity_state state, const absl::Status& status,
     const char* reason,
     std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker) {
@@ -2443,7 +1660,7 @@ void ChannelData::UpdateStateAndPickerLocked(
     // Re-process queued picks.
     for (LbQueuedCall* call = lb_queued_calls_; call != nullptr;
          call = call->next) {
-      grpc_error* error = GRPC_ERROR_NONE;
+      grpc_error_handle error = GRPC_ERROR_NONE;
       if (call->lb_call->PickSubchannelLocked(&error)) {
         call->lb_call->AsyncPickDone(error);
       }
@@ -2454,7 +1671,7 @@ void ChannelData::UpdateStateAndPickerLocked(
   pending_subchannel_updates_.clear();
 }
 
-grpc_error* ChannelData::DoPingLocked(grpc_transport_op* op) {
+grpc_error_handle ClientChannel::DoPingLocked(grpc_transport_op* op) {
   if (state_tracker_.state() != GRPC_CHANNEL_READY) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("channel not connected");
   }
@@ -2480,7 +1697,7 @@ grpc_error* ChannelData::DoPingLocked(grpc_transport_op* op) {
   return result.error;
 }
 
-void ChannelData::StartTransportOpLocked(grpc_transport_op* op) {
+void ClientChannel::StartTransportOpLocked(grpc_transport_op* op) {
   // Connectivity watch.
   if (op->start_connectivity_watch != nullptr) {
     state_tracker_.AddWatcher(op->start_connectivity_watch_state,
@@ -2491,7 +1708,7 @@ void ChannelData::StartTransportOpLocked(grpc_transport_op* op) {
   }
   // Ping.
   if (op->send_ping.on_initiate != nullptr || op->send_ping.on_ack != nullptr) {
-    grpc_error* error = DoPingLocked(op);
+    grpc_error_handle error = DoPingLocked(op);
     if (error != GRPC_ERROR_NONE) {
       ExecCtx::Run(DEBUG_LOCATION, op->send_ping.on_initiate,
                    GRPC_ERROR_REF(error));
@@ -2511,7 +1728,7 @@ void ChannelData::StartTransportOpLocked(grpc_transport_op* op) {
   if (op->disconnect_with_error != GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p: disconnect_with_error: %s", this,
-              grpc_error_string(op->disconnect_with_error));
+              grpc_error_std_string(op->disconnect_with_error).c_str());
     }
     DestroyResolverAndLbPolicyLocked();
     intptr_t value;
@@ -2539,9 +1756,9 @@ void ChannelData::StartTransportOpLocked(grpc_transport_op* op) {
   ExecCtx::Run(DEBUG_LOCATION, op->on_consumed, GRPC_ERROR_NONE);
 }
 
-void ChannelData::StartTransportOp(grpc_channel_element* elem,
-                                   grpc_transport_op* op) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+void ClientChannel::StartTransportOp(grpc_channel_element* elem,
+                                     grpc_transport_op* op) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   GPR_ASSERT(op->set_accept_stream == false);
   // Handle bind_pollset.
   if (op->bind_pollset != nullptr) {
@@ -2550,12 +1767,15 @@ void ChannelData::StartTransportOp(grpc_channel_element* elem,
   // Pop into control plane work_serializer for remaining ops.
   GRPC_CHANNEL_STACK_REF(chand->owning_stack_, "start_transport_op");
   chand->work_serializer_->Run(
-      [chand, op]() { chand->StartTransportOpLocked(op); }, DEBUG_LOCATION);
+      [chand, op]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand->work_serializer_) {
+        chand->StartTransportOpLocked(op);
+      },
+      DEBUG_LOCATION);
 }
 
-void ChannelData::GetChannelInfo(grpc_channel_element* elem,
-                                 const grpc_channel_info* info) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+void ClientChannel::GetChannelInfo(grpc_channel_element* elem,
+                                   const grpc_channel_info* info) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   MutexLock lock(&chand->info_mu_);
   if (info->lb_policy_name != nullptr) {
     *info->lb_policy_name = gpr_strdup(chand->info_lb_policy_name_.get());
@@ -2566,8 +1786,8 @@ void ChannelData::GetChannelInfo(grpc_channel_element* elem,
   }
 }
 
-void ChannelData::AddLbQueuedCall(LbQueuedCall* call,
-                                  grpc_polling_entity* pollent) {
+void ClientChannel::AddLbQueuedCall(LbQueuedCall* call,
+                                    grpc_polling_entity* pollent) {
   // Add call to queued picks list.
   call->next = lb_queued_calls_;
   lb_queued_calls_ = call;
@@ -2576,8 +1796,8 @@ void ChannelData::AddLbQueuedCall(LbQueuedCall* call,
   grpc_polling_entity_add_to_pollset_set(pollent, interested_parties_);
 }
 
-void ChannelData::RemoveLbQueuedCall(LbQueuedCall* to_remove,
-                                     grpc_polling_entity* pollent) {
+void ClientChannel::RemoveLbQueuedCall(LbQueuedCall* to_remove,
+                                       grpc_polling_entity* pollent) {
   // Remove call's pollent from channel's interested_parties.
   grpc_polling_entity_del_from_pollset_set(pollent, interested_parties_);
   // Remove from queued picks list.
@@ -2591,7 +1811,7 @@ void ChannelData::RemoveLbQueuedCall(LbQueuedCall* to_remove,
 }
 
 RefCountedPtr<ConnectedSubchannel>
-ChannelData::GetConnectedSubchannelInDataPlane(
+ClientChannel::GetConnectedSubchannelInDataPlane(
     SubchannelInterface* subchannel) const {
   SubchannelWrapper* subchannel_wrapper =
       static_cast<SubchannelWrapper*>(subchannel);
@@ -2601,7 +1821,7 @@ ChannelData::GetConnectedSubchannelInDataPlane(
   return connected_subchannel->Ref();
 }
 
-void ChannelData::TryToConnectLocked() {
+void ClientChannel::TryToConnectLocked() {
   if (lb_policy_ != nullptr) {
     lb_policy_->ExitIdleLocked();
   } else if (resolver_ == nullptr) {
@@ -2610,23 +1830,29 @@ void ChannelData::TryToConnectLocked() {
   GRPC_CHANNEL_STACK_UNREF(owning_stack_, "TryToConnect");
 }
 
-grpc_connectivity_state ChannelData::CheckConnectivityState(
+grpc_connectivity_state ClientChannel::CheckConnectivityState(
     bool try_to_connect) {
-  grpc_connectivity_state out = state_tracker_.state();
+  // state_tracker_ is guarded by work_serializer_, which we're not
+  // holding here.  But the one method of state_tracker_ that *is*
+  // thread-safe to call without external synchronization is the state()
+  // method, so we can disable thread-safety analysis for this one read.
+  grpc_connectivity_state out = ABSL_TS_UNCHECKED_READ(state_tracker_).state();
   if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
     GRPC_CHANNEL_STACK_REF(owning_stack_, "TryToConnect");
-    work_serializer_->Run([this]() { TryToConnectLocked(); }, DEBUG_LOCATION);
+    work_serializer_->Run([this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(
+                              work_serializer_) { TryToConnectLocked(); },
+                          DEBUG_LOCATION);
   }
   return out;
 }
 
-void ChannelData::AddConnectivityWatcher(
+void ClientChannel::AddConnectivityWatcher(
     grpc_connectivity_state initial_state,
     OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher) {
   new ConnectivityWatcherAdder(this, initial_state, std::move(watcher));
 }
 
-void ChannelData::RemoveConnectivityWatcher(
+void ClientChannel::RemoveConnectivityWatcher(
     AsyncConnectivityStateWatcherInterface* watcher) {
   new ConnectivityWatcherRemover(this, watcher);
 }
@@ -2635,9 +1861,9 @@ void ChannelData::RemoveConnectivityWatcher(
 // CallData implementation
 //
 
-ChannelData::CallData::CallData(grpc_call_element* elem,
-                                const ChannelData& chand,
-                                const grpc_call_element_args& args)
+ClientChannel::CallData::CallData(grpc_call_element* elem,
+                                  const ClientChannel& chand,
+                                  const grpc_call_element_args& args)
     : deadline_state_(elem, args,
                       GPR_LIKELY(chand.deadline_checking_enabled_)
                           ? args.deadline
@@ -2654,7 +1880,7 @@ ChannelData::CallData::CallData(grpc_call_element* elem,
   }
 }
 
-ChannelData::CallData::~CallData() {
+ClientChannel::CallData::~CallData() {
   grpc_slice_unref_internal(path_);
   GRPC_ERROR_UNREF(cancel_error_);
   // Make sure there are no remaining pending batches.
@@ -2663,16 +1889,16 @@ ChannelData::CallData::~CallData() {
   }
 }
 
-grpc_error* ChannelData::CallData::Init(grpc_call_element* elem,
-                                        const grpc_call_element_args* args) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+grpc_error_handle ClientChannel::CallData::Init(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   new (elem->call_data) CallData(elem, *chand, *args);
   return GRPC_ERROR_NONE;
 }
 
-void ChannelData::CallData::Destroy(grpc_call_element* elem,
-                                    const grpc_call_final_info* /*final_info*/,
-                                    grpc_closure* then_schedule_closure) {
+void ClientChannel::CallData::Destroy(
+    grpc_call_element* elem, const grpc_call_final_info* /*final_info*/,
+    grpc_closure* then_schedule_closure) {
   CallData* calld = static_cast<CallData*>(elem->call_data);
   RefCountedPtr<DynamicFilters::Call> dynamic_call =
       std::move(calld->dynamic_call_);
@@ -2685,11 +1911,11 @@ void ChannelData::CallData::Destroy(grpc_call_element* elem,
   }
 }
 
-void ChannelData::CallData::StartTransportStreamOpBatch(
+void ClientChannel::CallData::StartTransportStreamOpBatch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
   GPR_TIMER_SCOPE("cc_start_transport_stream_op_batch", 0);
   CallData* calld = static_cast<CallData*>(elem->call_data);
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   if (GPR_LIKELY(chand->deadline_checking_enabled_)) {
     grpc_deadline_state_client_start_transport_stream_op_batch(elem, batch);
   }
@@ -2701,7 +1927,8 @@ void ChannelData::CallData::StartTransportStreamOpBatch(
   if (GPR_UNLIKELY(calld->cancel_error_ != GRPC_ERROR_NONE)) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p calld=%p: failing batch with error: %s",
-              chand, calld, grpc_error_string(calld->cancel_error_));
+              chand, calld,
+              grpc_error_std_string(calld->cancel_error_).c_str());
     }
     // Note: This will release the call combiner.
     grpc_transport_stream_op_batch_finish_with_failure(
@@ -2720,7 +1947,7 @@ void ChannelData::CallData::StartTransportStreamOpBatch(
         GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p calld=%p: recording cancel_error=%s", chand,
-              calld, grpc_error_string(calld->cancel_error_));
+              calld, grpc_error_std_string(calld->cancel_error_).c_str());
     }
     // If we do not have a dynamic call (i.e., name resolution has not
     // yet completed), fail all pending batches.  Otherwise, send the
@@ -2774,8 +2001,8 @@ void ChannelData::CallData::StartTransportStreamOpBatch(
   }
 }
 
-void ChannelData::CallData::SetPollent(grpc_call_element* elem,
-                                       grpc_polling_entity* pollent) {
+void ClientChannel::CallData::SetPollent(grpc_call_element* elem,
+                                         grpc_polling_entity* pollent) {
   CallData* calld = static_cast<CallData*>(elem->call_data);
   calld->pollent_ = pollent;
 }
@@ -2784,10 +2011,11 @@ void ChannelData::CallData::SetPollent(grpc_call_element* elem,
 // pending_batches management
 //
 
-size_t ChannelData::CallData::GetBatchIndex(
+size_t ClientChannel::CallData::GetBatchIndex(
     grpc_transport_stream_op_batch* batch) {
   // Note: It is important the send_initial_metadata be the first entry
-  // here, since the code in pick_subchannel_locked() assumes it will be.
+  // here, since the code in ApplyServiceConfigToCallLocked() and
+  // CheckResolutionLocked() assumes it will be.
   if (batch->send_initial_metadata) return 0;
   if (batch->send_message) return 1;
   if (batch->send_trailing_metadata) return 2;
@@ -2798,9 +2026,9 @@ size_t ChannelData::CallData::GetBatchIndex(
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::CallData::PendingBatchesAdd(
+void ClientChannel::CallData::PendingBatchesAdd(
     grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   const size_t idx = GetBatchIndex(batch);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
     gpr_log(GPR_INFO,
@@ -2813,8 +2041,8 @@ void ChannelData::CallData::PendingBatchesAdd(
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::CallData::FailPendingBatchInCallCombiner(void* arg,
-                                                           grpc_error* error) {
+void ClientChannel::CallData::FailPendingBatchInCallCombiner(
+    void* arg, grpc_error_handle error) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   CallData* calld = static_cast<CallData*>(batch->handler_private.extra_arg);
@@ -2824,8 +2052,8 @@ void ChannelData::CallData::FailPendingBatchInCallCombiner(void* arg,
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::CallData::PendingBatchesFail(
-    grpc_call_element* elem, grpc_error* error,
+void ClientChannel::CallData::PendingBatchesFail(
+    grpc_call_element* elem, grpc_error_handle error,
     YieldCallCombinerPredicate yield_call_combiner_predicate) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
@@ -2835,7 +2063,8 @@ void ChannelData::CallData::PendingBatchesFail(
     }
     gpr_log(GPR_INFO,
             "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s",
-            elem->channel_data, this, num_batches, grpc_error_string(error));
+            elem->channel_data, this, num_batches,
+            grpc_error_std_string(error).c_str());
   }
   CallCombinerClosureList closures;
   for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
@@ -2859,8 +2088,8 @@ void ChannelData::CallData::PendingBatchesFail(
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::CallData::ResumePendingBatchInCallCombiner(
-    void* arg, grpc_error* /*ignored*/) {
+void ClientChannel::CallData::ResumePendingBatchInCallCombiner(
+    void* arg, grpc_error_handle /*ignored*/) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   auto* elem =
@@ -2871,8 +2100,8 @@ void ChannelData::CallData::ResumePendingBatchInCallCombiner(
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::CallData::PendingBatchesResume(grpc_call_element* elem) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+void ClientChannel::CallData::PendingBatchesResume(grpc_call_element* elem) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   // Retries not enabled; send down batches as-is.
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
     size_t num_batches = 0;
@@ -2906,7 +2135,7 @@ void ChannelData::CallData::PendingBatchesResume(grpc_call_element* elem) {
 
 // A class to handle the call combiner cancellation callback for a
 // queued pick.
-class ChannelData::CallData::ResolverQueuedCallCanceller {
+class ClientChannel::CallData::ResolverQueuedCallCanceller {
  public:
   explicit ResolverQueuedCallCanceller(grpc_call_element* elem) : elem_(elem) {
     auto* calld = static_cast<CallData*>(elem->call_data);
@@ -2917,9 +2146,9 @@ class ChannelData::CallData::ResolverQueuedCallCanceller {
   }
 
  private:
-  static void CancelLocked(void* arg, grpc_error* error) {
+  static void CancelLocked(void* arg, grpc_error_handle error) {
     auto* self = static_cast<ResolverQueuedCallCanceller*>(arg);
-    auto* chand = static_cast<ChannelData*>(self->elem_->channel_data);
+    auto* chand = static_cast<ClientChannel*>(self->elem_->channel_data);
     auto* calld = static_cast<CallData*>(self->elem_->call_data);
     {
       MutexLock lock(&chand->resolution_mu_);
@@ -2927,7 +2156,7 @@ class ChannelData::CallData::ResolverQueuedCallCanceller {
         gpr_log(GPR_INFO,
                 "chand=%p calld=%p: cancelling resolver queued pick: "
                 "error=%s self=%p calld->resolver_pick_canceller=%p",
-                chand, calld, grpc_error_string(error), self,
+                chand, calld, grpc_error_std_string(error).c_str(), self,
                 calld->resolver_call_canceller_);
       }
       if (calld->resolver_call_canceller_ == self && error != GRPC_ERROR_NONE) {
@@ -2946,10 +2175,10 @@ class ChannelData::CallData::ResolverQueuedCallCanceller {
   grpc_closure closure_;
 };
 
-void ChannelData::CallData::MaybeRemoveCallFromResolverQueuedCallsLocked(
+void ClientChannel::CallData::MaybeRemoveCallFromResolverQueuedCallsLocked(
     grpc_call_element* elem) {
   if (!queued_pending_resolver_result_) return;
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
+  auto* chand = static_cast<ClientChannel*>(elem->channel_data);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO,
             "chand=%p calld=%p: removing from resolver queued picks list",
@@ -2961,10 +2190,10 @@ void ChannelData::CallData::MaybeRemoveCallFromResolverQueuedCallsLocked(
   resolver_call_canceller_ = nullptr;
 }
 
-void ChannelData::CallData::MaybeAddCallToResolverQueuedCallsLocked(
+void ClientChannel::CallData::MaybeAddCallToResolverQueuedCallsLocked(
     grpc_call_element* elem) {
   if (queued_pending_resolver_result_) return;
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
+  auto* chand = static_cast<ClientChannel*>(elem->channel_data);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p calld=%p: adding to resolver queued picks list",
             chand, this);
@@ -2976,9 +2205,9 @@ void ChannelData::CallData::MaybeAddCallToResolverQueuedCallsLocked(
   resolver_call_canceller_ = new ResolverQueuedCallCanceller(elem);
 }
 
-grpc_error* ChannelData::CallData::ApplyServiceConfigToCallLocked(
+grpc_error_handle ClientChannel::CallData::ApplyServiceConfigToCallLocked(
     grpc_call_element* elem, grpc_metadata_batch* initial_metadata) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p calld=%p: applying service config to call",
             chand, this);
@@ -3035,9 +2264,9 @@ grpc_error* ChannelData::CallData::ApplyServiceConfigToCallLocked(
   return GRPC_ERROR_NONE;
 }
 
-void ChannelData::CallData::
-    RecvInitialMetadataReadyForConfigSelectorCommitCallback(void* arg,
-                                                            grpc_error* error) {
+void ClientChannel::CallData::
+    RecvInitialMetadataReadyForConfigSelectorCommitCallback(
+        void* arg, grpc_error_handle error) {
   auto* self = static_cast<CallData*>(arg);
   if (self->on_call_committed_ != nullptr) {
     self->on_call_committed_();
@@ -3050,7 +2279,7 @@ void ChannelData::CallData::
 
 // TODO(roth): Consider not intercepting this callback unless we
 // actually need to, if this causes a performance problem.
-void ChannelData::CallData::
+void ClientChannel::CallData::
     InjectRecvInitialMetadataReadyForConfigSelectorCommitCallback(
         grpc_transport_stream_op_batch* batch) {
   original_recv_initial_metadata_ready_ =
@@ -3062,21 +2291,22 @@ void ChannelData::CallData::
       &recv_initial_metadata_ready_;
 }
 
-void ChannelData::CallData::AsyncResolutionDone(grpc_call_element* elem,
-                                                grpc_error* error) {
+void ClientChannel::CallData::AsyncResolutionDone(grpc_call_element* elem,
+                                                  grpc_error_handle error) {
   GRPC_CLOSURE_INIT(&pick_closure_, ResolutionDone, elem, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &pick_closure_, error);
 }
 
-void ChannelData::CallData::ResolutionDone(void* arg, grpc_error* error) {
+void ClientChannel::CallData::ResolutionDone(void* arg,
+                                             grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO,
               "chand=%p calld=%p: error applying config to call: error=%s",
-              chand, calld, grpc_error_string(error));
+              chand, calld, grpc_error_std_string(error).c_str());
     }
     calld->PendingBatchesFail(elem, GRPC_ERROR_REF(error), YieldCallCombiner);
     return;
@@ -3084,10 +2314,11 @@ void ChannelData::CallData::ResolutionDone(void* arg, grpc_error* error) {
   calld->CreateDynamicCall(elem);
 }
 
-void ChannelData::CallData::CheckResolution(void* arg, grpc_error* error) {
+void ClientChannel::CallData::CheckResolution(void* arg,
+                                              grpc_error_handle 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);
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   bool resolution_complete;
   {
     MutexLock lock(&chand->resolution_mu_);
@@ -3099,9 +2330,9 @@ void ChannelData::CallData::CheckResolution(void* arg, grpc_error* error) {
   }
 }
 
-bool ChannelData::CallData::CheckResolutionLocked(grpc_call_element* elem,
-                                                  grpc_error** error) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+bool ClientChannel::CallData::CheckResolutionLocked(grpc_call_element* elem,
+                                                    grpc_error_handle* error) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   // If we're still in IDLE, we need to start resolving.
   if (GPR_UNLIKELY(chand->CheckConnectivityState(false) == GRPC_CHANNEL_IDLE)) {
     // Bounce into the control plane work serializer to start resolving,
@@ -3112,14 +2343,15 @@ bool ChannelData::CallData::CheckResolutionLocked(grpc_call_element* elem,
     ExecCtx::Run(
         DEBUG_LOCATION,
         GRPC_CLOSURE_CREATE(
-            [](void* arg, grpc_error* /*error*/) {
-              auto* chand = static_cast<ChannelData*>(arg);
+            [](void* arg, grpc_error_handle /*error*/) {
+              auto* chand = static_cast<ClientChannel*>(arg);
               chand->work_serializer_->Run(
-                  [chand]() {
-                    chand->CheckConnectivityState(/*try_to_connect=*/true);
-                    GRPC_CHANNEL_STACK_UNREF(chand->owning_stack_,
-                                             "CheckResolutionLocked");
-                  },
+                  [chand]()
+                      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand->work_serializer_) {
+                        chand->CheckConnectivityState(/*try_to_connect=*/true);
+                        GRPC_CHANNEL_STACK_UNREF(chand->owning_stack_,
+                                                 "CheckResolutionLocked");
+                      },
                   DEBUG_LOCATION);
             },
             chand, nullptr),
@@ -3137,7 +2369,7 @@ bool ChannelData::CallData::CheckResolutionLocked(grpc_call_element* elem,
   if (GPR_UNLIKELY(!chand->received_service_config_data_)) {
     // If the resolver returned transient failure before returning the
     // first service config, fail any non-wait_for_ready calls.
-    grpc_error* resolver_error = chand->resolver_transient_failure_error_;
+    grpc_error_handle resolver_error = chand->resolver_transient_failure_error_;
     if (resolver_error != GRPC_ERROR_NONE &&
         (send_initial_metadata_flags & GRPC_INITIAL_METADATA_WAIT_FOR_READY) ==
             0) {
@@ -3160,8 +2392,8 @@ bool ChannelData::CallData::CheckResolutionLocked(grpc_call_element* elem,
   return true;
 }
 
-void ChannelData::CallData::CreateDynamicCall(grpc_call_element* elem) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
+void ClientChannel::CallData::CreateDynamicCall(grpc_call_element* elem) {
+  auto* chand = static_cast<ClientChannel*>(elem->channel_data);
   DynamicFilters::Call::Args args = {std::move(dynamic_filters_),
                                      pollent_,
                                      path_,
@@ -3170,7 +2402,7 @@ void ChannelData::CallData::CreateDynamicCall(grpc_call_element* elem) {
                                      arena_,
                                      call_context_,
                                      call_combiner_};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   DynamicFilters* channel_stack = args.channel_stack.get();
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(
@@ -3183,7 +2415,7 @@ void ChannelData::CallData::CreateDynamicCall(grpc_call_element* elem) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO,
               "chand=%p calld=%p: failed to create dynamic call: error=%s",
-              chand, this, grpc_error_string(error));
+              chand, this, grpc_error_std_string(error).c_str());
     }
     PendingBatchesFail(elem, error, YieldCallCombiner);
     return;
@@ -3192,264 +2424,151 @@ void ChannelData::CallData::CreateDynamicCall(grpc_call_element* elem) {
 }
 
 //
-// RetryingCall implementation
+// ClientChannel::LoadBalancedCall::Metadata
 //
 
-// Retry support:
-//
-// In order to support retries, we act as a proxy for stream op batches.
-// When we get a batch from the surface, we add it to our list of pending
-// batches, and we then use those batches to construct separate "child"
-// batches to be started on the subchannel call.  When the child batches
-// return, we then decide which pending batches have been completed and
-// schedule their callbacks accordingly.  If a subchannel call fails and
-// we want to retry it, we do a new pick and start again, constructing
-// new "child" batches for the new subchannel call.
-//
-// Note that retries are committed when receiving data from the server
-// (except for Trailers-Only responses).  However, there may be many
-// send ops started before receiving any data, so we may have already
-// completed some number of send ops (and returned the completions up to
-// the surface) by the time we realize that we need to retry.  To deal
-// with this, we cache data for send ops, so that we can replay them on a
-// different subchannel call even after we have completed the original
-// batches.
-//
-// There are two sets of data to maintain:
-// - In call_data (in the parent channel), we maintain a list of pending
-//   ops and cached data for send ops.
-// - In the subchannel call, we maintain state to indicate what ops have
-//   already been sent down to that call.
-//
-// When constructing the "child" batches, we compare those two sets of
-// data to see which batches need to be sent to the subchannel call.
-
-// TODO(roth): In subsequent PRs:
-// - add support for transparent retries (including initial metadata)
-// - figure out how to record stats in census for retries
-//   (census filter is on top of this one)
-// - add census stats for retries
-
-ChannelData::RetryingCall::RetryingCall(
-    ChannelData* chand, const grpc_call_element_args& args,
-    grpc_polling_entity* pollent,
-    RefCountedPtr<ServerRetryThrottleData> retry_throttle_data,
-    const ClientChannelMethodParsedConfig::RetryPolicy* retry_policy)
-    : chand_(chand),
-      pollent_(pollent),
-      retry_throttle_data_(std::move(retry_throttle_data)),
-      retry_policy_(retry_policy),
-      retry_backoff_(
-          BackOff::Options()
-              .set_initial_backoff(
-                  retry_policy_ == nullptr ? 0 : retry_policy_->initial_backoff)
-              .set_multiplier(retry_policy_ == nullptr
-                                  ? 0
-                                  : retry_policy_->backoff_multiplier)
-              .set_jitter(RETRY_BACKOFF_JITTER)
-              .set_max_backoff(
-                  retry_policy_ == nullptr ? 0 : retry_policy_->max_backoff)),
-      path_(grpc_slice_ref_internal(args.path)),
-      call_start_time_(args.start_time),
-      deadline_(args.deadline),
-      arena_(args.arena),
-      owning_call_(args.call_stack),
-      call_combiner_(args.call_combiner),
-      call_context_(args.context),
-      pending_send_initial_metadata_(false),
-      pending_send_message_(false),
-      pending_send_trailing_metadata_(false),
-      enable_retries_(true),
-      retry_committed_(false),
-      last_attempt_got_server_pushback_(false) {}
-
-ChannelData::RetryingCall::~RetryingCall() {
-  grpc_slice_unref_internal(path_);
-  GRPC_ERROR_UNREF(cancel_error_);
-  // Make sure there are no remaining pending batches.
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    GPR_ASSERT(pending_batches_[i].batch == nullptr);
+class ClientChannel::LoadBalancedCall::Metadata
+    : public LoadBalancingPolicy::MetadataInterface {
+ public:
+  Metadata(LoadBalancedCall* lb_call, grpc_metadata_batch* batch)
+      : lb_call_(lb_call), batch_(batch) {}
+
+  void Add(absl::string_view key, absl::string_view value) override {
+    grpc_linked_mdelem* linked_mdelem = static_cast<grpc_linked_mdelem*>(
+        lb_call_->arena_->Alloc(sizeof(grpc_linked_mdelem)));
+    linked_mdelem->md = grpc_mdelem_from_slices(
+        ExternallyManagedSlice(key.data(), key.size()),
+        ExternallyManagedSlice(value.data(), value.size()));
+    GPR_ASSERT(grpc_metadata_batch_link_tail(batch_, linked_mdelem) ==
+               GRPC_ERROR_NONE);
   }
-}
 
-void ChannelData::RetryingCall::StartTransportStreamOpBatch(
-    grpc_transport_stream_op_batch* batch) {
-  // If we've previously been cancelled, immediately fail any new batches.
-  if (GPR_UNLIKELY(cancel_error_ != GRPC_ERROR_NONE)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: failing batch with error: %s", chand_,
-              this, grpc_error_string(cancel_error_));
-    }
-    // Note: This will release the call combiner.
-    grpc_transport_stream_op_batch_finish_with_failure(
-        batch, GRPC_ERROR_REF(cancel_error_), call_combiner_);
-    return;
+  iterator begin() const override {
+    static_assert(sizeof(grpc_linked_mdelem*) <= sizeof(intptr_t),
+                  "iterator size too large");
+    return iterator(
+        this, reinterpret_cast<intptr_t>(MaybeSkipEntry(batch_->list.head)));
   }
-  // Handle cancellation.
-  if (GPR_UNLIKELY(batch->cancel_stream)) {
-    // Stash a copy of cancel_error in our call data, so that we can use
-    // it for subsequent operations.  This ensures that if the call is
-    // cancelled before any batches are passed down (e.g., if the deadline
-    // is in the past when the call starts), we can return the right
-    // error to the caller when the first batch does get passed down.
-    GRPC_ERROR_UNREF(cancel_error_);
-    cancel_error_ = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: recording cancel_error=%s",
-              chand_, this, grpc_error_string(cancel_error_));
-    }
-    // If we do not have an LB call (i.e., a pick has not yet been started),
-    // fail all pending batches.  Otherwise, send the cancellation down to the
-    // LB call.
-    if (lb_call_ == nullptr) {
-      // TODO(roth): If there is a pending retry callback, do we need to
-      // cancel it here?
-      PendingBatchesFail(GRPC_ERROR_REF(cancel_error_), NoYieldCallCombiner);
-      // Note: This will release the call combiner.
-      grpc_transport_stream_op_batch_finish_with_failure(
-          batch, GRPC_ERROR_REF(cancel_error_), call_combiner_);
-    } else {
-      // Note: This will release the call combiner.
-      lb_call_->StartTransportStreamOpBatch(batch);
-    }
-    return;
+  iterator end() const override {
+    static_assert(sizeof(grpc_linked_mdelem*) <= sizeof(intptr_t),
+                  "iterator size too large");
+    return iterator(this, 0);
   }
-  // Add the batch to the pending list.
-  PendingBatchesAdd(batch);
-  // Create LB call if needed.
-  // TODO(roth): If we get a new batch from the surface after the
-  // initial retry attempt has failed, while the retry timer is pending,
-  // we should queue the batch and not try to send it immediately.
-  if (lb_call_ == nullptr) {
-    // We do not yet have an LB call, so create one.
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: creating LB call", chand_,
-              this);
+
+  iterator erase(iterator it) override {
+    grpc_linked_mdelem* linked_mdelem =
+        reinterpret_cast<grpc_linked_mdelem*>(GetIteratorHandle(it));
+    intptr_t handle = reinterpret_cast<intptr_t>(linked_mdelem->next);
+    grpc_metadata_batch_remove(batch_, linked_mdelem);
+    return iterator(this, handle);
+  }
+
+ private:
+  grpc_linked_mdelem* MaybeSkipEntry(grpc_linked_mdelem* entry) const {
+    if (entry != nullptr && batch_->idx.named.path == entry) {
+      return entry->next;
     }
-    CreateLbCall(this, GRPC_ERROR_NONE);
-    return;
+    return entry;
   }
-  // Send batches to LB call.
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO, "chand=%p retrying_call=%p: starting batch on lb_call=%p",
-            chand_, this, lb_call_.get());
+
+  intptr_t IteratorHandleNext(intptr_t handle) const override {
+    grpc_linked_mdelem* linked_mdelem =
+        reinterpret_cast<grpc_linked_mdelem*>(handle);
+    return reinterpret_cast<intptr_t>(MaybeSkipEntry(linked_mdelem->next));
   }
-  PendingBatchesResume();
-}
 
-RefCountedPtr<SubchannelCall> ChannelData::RetryingCall::subchannel_call()
-    const {
-  if (lb_call_ == nullptr) return nullptr;
-  return lb_call_->subchannel_call();
-}
+  std::pair<absl::string_view, absl::string_view> IteratorHandleGet(
+      intptr_t handle) const override {
+    grpc_linked_mdelem* linked_mdelem =
+        reinterpret_cast<grpc_linked_mdelem*>(handle);
+    return std::make_pair(StringViewFromSlice(GRPC_MDKEY(linked_mdelem->md)),
+                          StringViewFromSlice(GRPC_MDVALUE(linked_mdelem->md)));
+  }
+
+  LoadBalancedCall* lb_call_;
+  grpc_metadata_batch* batch_;
+};
 
 //
-// send op data caching
+// ClientChannel::LoadBalancedCall::LbCallState
 //
 
-void ChannelData::RetryingCall::MaybeCacheSendOpsForBatch(
-    PendingBatch* pending) {
-  if (pending->send_ops_cached) return;
-  pending->send_ops_cached = true;
-  grpc_transport_stream_op_batch* batch = pending->batch;
-  // Save a copy of metadata for send_initial_metadata ops.
-  if (batch->send_initial_metadata) {
-    seen_send_initial_metadata_ = true;
-    GPR_ASSERT(send_initial_metadata_storage_ == nullptr);
-    grpc_metadata_batch* send_initial_metadata =
-        batch->payload->send_initial_metadata.send_initial_metadata;
-    send_initial_metadata_storage_ =
-        static_cast<grpc_linked_mdelem*>(arena_->Alloc(
-            sizeof(grpc_linked_mdelem) * send_initial_metadata->list.count));
-    grpc_metadata_batch_copy(send_initial_metadata, &send_initial_metadata_,
-                             send_initial_metadata_storage_);
-    send_initial_metadata_flags_ =
-        batch->payload->send_initial_metadata.send_initial_metadata_flags;
-    peer_string_ = batch->payload->send_initial_metadata.peer_string;
-  }
-  // Set up cache for send_message ops.
-  if (batch->send_message) {
-    ByteStreamCache* cache = arena_->New<ByteStreamCache>(
-        std::move(batch->payload->send_message.send_message));
-    send_messages_.push_back(cache);
-  }
-  // Save metadata batch for send_trailing_metadata ops.
-  if (batch->send_trailing_metadata) {
-    seen_send_trailing_metadata_ = true;
-    GPR_ASSERT(send_trailing_metadata_storage_ == nullptr);
-    grpc_metadata_batch* send_trailing_metadata =
-        batch->payload->send_trailing_metadata.send_trailing_metadata;
-    send_trailing_metadata_storage_ =
-        static_cast<grpc_linked_mdelem*>(arena_->Alloc(
-            sizeof(grpc_linked_mdelem) * send_trailing_metadata->list.count));
-    grpc_metadata_batch_copy(send_trailing_metadata, &send_trailing_metadata_,
-                             send_trailing_metadata_storage_);
-  }
-}
+class ClientChannel::LoadBalancedCall::LbCallState
+    : public LoadBalancingPolicy::CallState {
+ public:
+  explicit LbCallState(LoadBalancedCall* lb_call) : lb_call_(lb_call) {}
 
-void ChannelData::RetryingCall::FreeCachedSendInitialMetadata() {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: destroying send_initial_metadata",
-            chand_, this);
-  }
-  grpc_metadata_batch_destroy(&send_initial_metadata_);
-}
+  void* Alloc(size_t size) override { return lb_call_->arena_->Alloc(size); }
 
-void ChannelData::RetryingCall::FreeCachedSendMessage(size_t idx) {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: destroying send_messages[%" PRIuPTR "]",
-            chand_, this, idx);
+  const LoadBalancingPolicy::BackendMetricData* GetBackendMetricData()
+      override {
+    if (lb_call_->backend_metric_data_ == nullptr) {
+      grpc_linked_mdelem* md = lb_call_->recv_trailing_metadata_->idx.named
+                                   .x_endpoint_load_metrics_bin;
+      if (md != nullptr) {
+        lb_call_->backend_metric_data_ =
+            ParseBackendMetricData(GRPC_MDVALUE(md->md), lb_call_->arena_);
+      }
+    }
+    return lb_call_->backend_metric_data_;
   }
-  send_messages_[idx]->Destroy();
-}
 
-void ChannelData::RetryingCall::FreeCachedSendTrailingMetadata() {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand_=%p retrying_call=%p: destroying send_trailing_metadata",
-            chand_, this);
+  absl::string_view ExperimentalGetCallAttribute(const char* key) override {
+    auto* service_config_call_data = static_cast<ServiceConfigCallData*>(
+        lb_call_->call_context_[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value);
+    auto& call_attributes = service_config_call_data->call_attributes();
+    auto it = call_attributes.find(key);
+    if (it == call_attributes.end()) return absl::string_view();
+    return it->second;
   }
-  grpc_metadata_batch_destroy(&send_trailing_metadata_);
-}
 
-void ChannelData::RetryingCall::FreeCachedSendOpDataAfterCommit(
-    SubchannelCallRetryState* retry_state) {
-  if (retry_state->completed_send_initial_metadata) {
-    FreeCachedSendInitialMetadata();
-  }
-  for (size_t i = 0; i < retry_state->completed_send_message_count; ++i) {
-    FreeCachedSendMessage(i);
-  }
-  if (retry_state->completed_send_trailing_metadata) {
-    FreeCachedSendTrailingMetadata();
-  }
-}
+ private:
+  LoadBalancedCall* lb_call_;
+};
+
+//
+// LoadBalancedCall
+//
+
+ClientChannel::LoadBalancedCall::LoadBalancedCall(
+    ClientChannel* chand, const grpc_call_element_args& args,
+    grpc_polling_entity* pollent, grpc_closure* on_call_destruction_complete)
+    : RefCounted(GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)
+                     ? "LoadBalancedCall"
+                     : nullptr),
+      chand_(chand),
+      path_(grpc_slice_ref_internal(args.path)),
+      call_start_time_(args.start_time),
+      deadline_(args.deadline),
+      arena_(args.arena),
+      owning_call_(args.call_stack),
+      call_combiner_(args.call_combiner),
+      call_context_(args.context),
+      pollent_(pollent),
+      on_call_destruction_complete_(on_call_destruction_complete) {}
 
-void ChannelData::RetryingCall::FreeCachedSendOpDataForCompletedBatch(
-    SubchannelCallBatchData* batch_data,
-    SubchannelCallRetryState* retry_state) {
-  if (batch_data->batch.send_initial_metadata) {
-    FreeCachedSendInitialMetadata();
+ClientChannel::LoadBalancedCall::~LoadBalancedCall() {
+  grpc_slice_unref_internal(path_);
+  GRPC_ERROR_UNREF(cancel_error_);
+  GRPC_ERROR_UNREF(failure_error_);
+  if (backend_metric_data_ != nullptr) {
+    backend_metric_data_
+        ->LoadBalancingPolicy::BackendMetricData::~BackendMetricData();
   }
-  if (batch_data->batch.send_message) {
-    FreeCachedSendMessage(retry_state->completed_send_message_count - 1);
+  // Make sure there are no remaining pending batches.
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
+    GPR_ASSERT(pending_batches_[i] == nullptr);
   }
-  if (batch_data->batch.send_trailing_metadata) {
-    FreeCachedSendTrailingMetadata();
+  if (on_call_destruction_complete_ != nullptr) {
+    ExecCtx::Run(DEBUG_LOCATION, on_call_destruction_complete_,
+                 GRPC_ERROR_NONE);
   }
 }
 
-//
-// pending_batches management
-//
-
-size_t ChannelData::RetryingCall::GetBatchIndex(
+size_t ClientChannel::LoadBalancedCall::GetBatchIndex(
     grpc_transport_stream_op_batch* batch) {
   // Note: It is important the send_initial_metadata be the first entry
-  // here, since the code in pick_subchannel_locked() assumes it will be.
+  // here, since the code in PickSubchannelLocked() assumes it will be.
   if (batch->send_initial_metadata) return 0;
   if (batch->send_message) return 1;
   if (batch->send_trailing_metadata) return 2;
@@ -3460,133 +2579,48 @@ size_t ChannelData::RetryingCall::GetBatchIndex(
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::RetryingCall::PendingBatchesAdd(
+void ClientChannel::LoadBalancedCall::PendingBatchesAdd(
     grpc_transport_stream_op_batch* batch) {
   const size_t idx = GetBatchIndex(batch);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(
-        GPR_INFO,
-        "chand_=%p retrying_call=%p: adding pending batch at index %" PRIuPTR,
-        chand_, this, idx);
-  }
-  PendingBatch* pending = &pending_batches_[idx];
-  GPR_ASSERT(pending->batch == nullptr);
-  pending->batch = batch;
-  pending->send_ops_cached = false;
-  if (enable_retries_) {
-    // Update state in calld about pending batches.
-    // Also check if the batch takes us over the retry buffer limit.
-    // Note: We don't check the size of trailing metadata here, because
-    // gRPC clients do not send trailing metadata.
-    if (batch->send_initial_metadata) {
-      pending_send_initial_metadata_ = true;
-      bytes_buffered_for_retry_ += grpc_metadata_batch_size(
-          batch->payload->send_initial_metadata.send_initial_metadata);
-    }
-    if (batch->send_message) {
-      pending_send_message_ = true;
-      bytes_buffered_for_retry_ +=
-          batch->payload->send_message.send_message->length();
-    }
-    if (batch->send_trailing_metadata) {
-      pending_send_trailing_metadata_ = true;
-    }
-    if (GPR_UNLIKELY(bytes_buffered_for_retry_ >
-                     chand_->per_rpc_retry_buffer_size_)) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(GPR_INFO,
-                "chand=%p retrying_call=%p: exceeded retry buffer size, "
-                "committing",
-                chand_, this);
-      }
-      SubchannelCallRetryState* retry_state =
-          lb_call_ == nullptr ? nullptr
-                              : static_cast<SubchannelCallRetryState*>(
-                                    lb_call_->GetParentData());
-      RetryCommit(retry_state);
-      // If we are not going to retry and have not yet started, pretend
-      // retries are disabled so that we don't bother with retry overhead.
-      if (num_attempts_completed_ == 0) {
-        if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-          gpr_log(GPR_INFO,
-                  "chand=%p retrying_call=%p: disabling retries before first "
-                  "attempt",
-                  chand_, this);
-        }
-        // TODO(roth): Treat this as a commit?
-        enable_retries_ = false;
-      }
-    }
-  }
-}
-
-void ChannelData::RetryingCall::PendingBatchClear(PendingBatch* pending) {
-  if (enable_retries_) {
-    if (pending->batch->send_initial_metadata) {
-      pending_send_initial_metadata_ = false;
-    }
-    if (pending->batch->send_message) {
-      pending_send_message_ = false;
-    }
-    if (pending->batch->send_trailing_metadata) {
-      pending_send_trailing_metadata_ = false;
-    }
-  }
-  pending->batch = nullptr;
-}
-
-void ChannelData::RetryingCall::MaybeClearPendingBatch(PendingBatch* pending) {
-  grpc_transport_stream_op_batch* batch = pending->batch;
-  // We clear the pending batch if all of its callbacks have been
-  // scheduled and reset to nullptr.
-  if (batch->on_complete == nullptr &&
-      (!batch->recv_initial_metadata ||
-       batch->payload->recv_initial_metadata.recv_initial_metadata_ready ==
-           nullptr) &&
-      (!batch->recv_message ||
-       batch->payload->recv_message.recv_message_ready == nullptr) &&
-      (!batch->recv_trailing_metadata ||
-       batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready ==
-           nullptr)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: clearing pending batch",
-              chand_, this);
-    }
-    PendingBatchClear(pending);
+    gpr_log(GPR_INFO,
+            "chand=%p lb_call=%p: adding pending batch at index %" PRIuPTR,
+            chand_, this, idx);
   }
+  GPR_ASSERT(pending_batches_[idx] == nullptr);
+  pending_batches_[idx] = batch;
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::RetryingCall::FailPendingBatchInCallCombiner(
-    void* arg, grpc_error* error) {
+void ClientChannel::LoadBalancedCall::FailPendingBatchInCallCombiner(
+    void* arg, grpc_error_handle error) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
-  RetryingCall* call =
-      static_cast<RetryingCall*>(batch->handler_private.extra_arg);
+  auto* self = static_cast<LoadBalancedCall*>(batch->handler_private.extra_arg);
   // Note: This will release the call combiner.
   grpc_transport_stream_op_batch_finish_with_failure(
-      batch, GRPC_ERROR_REF(error), call->call_combiner_);
+      batch, GRPC_ERROR_REF(error), self->call_combiner_);
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::RetryingCall::PendingBatchesFail(
-    grpc_error* error,
+void ClientChannel::LoadBalancedCall::PendingBatchesFail(
+    grpc_error_handle error,
     YieldCallCombinerPredicate yield_call_combiner_predicate) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
+  GRPC_ERROR_UNREF(failure_error_);
+  failure_error_ = error;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
     size_t num_batches = 0;
     for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-      if (pending_batches_[i].batch != nullptr) ++num_batches;
+      if (pending_batches_[i] != nullptr) ++num_batches;
     }
     gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: failing %" PRIuPTR
-            " pending batches: %s",
-            chand_, this, num_batches, grpc_error_string(error));
+            "chand=%p lb_call=%p: failing %" PRIuPTR " pending batches: %s",
+            chand_, this, num_batches, grpc_error_std_string(error).c_str());
   }
   CallCombinerClosureList closures;
   for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    grpc_transport_stream_op_batch* batch = pending->batch;
+    grpc_transport_stream_op_batch*& batch = pending_batches_[i];
     if (batch != nullptr) {
       batch->handler_private.extra_arg = this;
       GRPC_CLOSURE_INIT(&batch->handler_private.closure,
@@ -3594,7 +2628,7 @@ void ChannelData::RetryingCall::PendingBatchesFail(
                         grpc_schedule_on_exec_ctx);
       closures.Add(&batch->handler_private.closure, GRPC_ERROR_REF(error),
                    "PendingBatchesFail");
-      PendingBatchClear(pending);
+      batch = nullptr;
     }
   }
   if (yield_call_combiner_predicate(closures)) {
@@ -3602,1518 +2636,59 @@ void ChannelData::RetryingCall::PendingBatchesFail(
   } else {
     closures.RunClosuresWithoutYielding(call_combiner_);
   }
-  GRPC_ERROR_UNREF(error);
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::RetryingCall::ResumePendingBatchInCallCombiner(
-    void* arg, grpc_error* /*ignored*/) {
+void ClientChannel::LoadBalancedCall::ResumePendingBatchInCallCombiner(
+    void* arg, grpc_error_handle /*ignored*/) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
-  auto* lb_call = static_cast<ChannelData::LoadBalancedCall*>(
-      batch->handler_private.extra_arg);
+  SubchannelCall* subchannel_call =
+      static_cast<SubchannelCall*>(batch->handler_private.extra_arg);
   // Note: This will release the call combiner.
-  lb_call->StartTransportStreamOpBatch(batch);
+  subchannel_call->StartTransportStreamOpBatch(batch);
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::RetryingCall::PendingBatchesResume() {
-  if (enable_retries_) {
-    StartRetriableSubchannelBatches(this, GRPC_ERROR_NONE);
-    return;
-  }
-  // Retries not enabled; send down batches as-is.
+void ClientChannel::LoadBalancedCall::PendingBatchesResume() {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
     size_t num_batches = 0;
     for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-      if (pending_batches_[i].batch != nullptr) ++num_batches;
+      if (pending_batches_[i] != nullptr) ++num_batches;
     }
     gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: starting %" PRIuPTR
-            " pending batches on lb_call=%p",
-            chand_, this, num_batches, lb_call_.get());
+            "chand=%p lb_call=%p: starting %" PRIuPTR
+            " pending batches on subchannel_call=%p",
+            chand_, this, num_batches, subchannel_call_.get());
   }
   CallCombinerClosureList closures;
   for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    grpc_transport_stream_op_batch* batch = pending->batch;
+    grpc_transport_stream_op_batch*& batch = pending_batches_[i];
     if (batch != nullptr) {
-      batch->handler_private.extra_arg = lb_call_.get();
+      batch->handler_private.extra_arg = subchannel_call_.get();
       GRPC_CLOSURE_INIT(&batch->handler_private.closure,
-                        ResumePendingBatchInCallCombiner, batch, nullptr);
+                        ResumePendingBatchInCallCombiner, batch,
+                        grpc_schedule_on_exec_ctx);
       closures.Add(&batch->handler_private.closure, GRPC_ERROR_NONE,
                    "PendingBatchesResume");
-      PendingBatchClear(pending);
+      batch = nullptr;
     }
   }
   // Note: This will release the call combiner.
   closures.RunClosures(call_combiner_);
 }
 
-template <typename Predicate>
-ChannelData::RetryingCall::PendingBatch*
-ChannelData::RetryingCall::PendingBatchFind(const char* log_message,
-                                            Predicate predicate) {
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    grpc_transport_stream_op_batch* batch = pending->batch;
-    if (batch != nullptr && predicate(batch)) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(
-            GPR_INFO,
-            "chand=%p retrying_call=%p: %s pending batch at index %" PRIuPTR,
-            chand_, this, log_message, i);
-      }
-      return pending;
-    }
-  }
-  return nullptr;
-}
-
-//
-// retry code
-//
-
-void ChannelData::RetryingCall::RetryCommit(
-    SubchannelCallRetryState* retry_state) {
-  if (retry_committed_) return;
-  retry_committed_ = true;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO, "chand=%p retrying_call=%p: committing retries", chand_,
-            this);
-  }
-  if (retry_state != nullptr) {
-    FreeCachedSendOpDataAfterCommit(retry_state);
-  }
-}
-
-void ChannelData::RetryingCall::DoRetry(SubchannelCallRetryState* retry_state,
-                                        grpc_millis server_pushback_ms) {
-  GPR_ASSERT(retry_policy_ != nullptr);
-  // Reset LB call.
-  lb_call_.reset();
-  // Compute backoff delay.
-  grpc_millis next_attempt_time;
-  if (server_pushback_ms >= 0) {
-    next_attempt_time = ExecCtx::Get()->Now() + server_pushback_ms;
-    last_attempt_got_server_pushback_ = true;
-  } else {
-    if (num_attempts_completed_ == 1 || last_attempt_got_server_pushback_) {
-      last_attempt_got_server_pushback_ = false;
-    }
-    next_attempt_time = retry_backoff_.NextAttemptTime();
-  }
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: retrying failed call in %" PRId64 " ms",
-            chand_, this, next_attempt_time - ExecCtx::Get()->Now());
-  }
-  // Schedule retry after computed delay.
-  GRPC_CLOSURE_INIT(&retry_closure_, CreateLbCall, this, nullptr);
-  grpc_timer_init(&retry_timer_, next_attempt_time, &retry_closure_);
-  // Update bookkeeping.
-  if (retry_state != nullptr) retry_state->retry_dispatched = true;
-}
-
-bool ChannelData::RetryingCall::MaybeRetry(SubchannelCallBatchData* batch_data,
-                                           grpc_status_code status,
-                                           grpc_mdelem* server_pushback_md) {
-  // Get retry policy.
-  if (retry_policy_ == nullptr) return false;
-  // If we've already dispatched a retry from this call, return true.
-  // This catches the case where the batch has multiple callbacks
-  // (i.e., it includes either recv_message or recv_initial_metadata).
-  SubchannelCallRetryState* retry_state = nullptr;
-  if (batch_data != nullptr) {
-    retry_state = static_cast<SubchannelCallRetryState*>(
-        batch_data->lb_call->GetParentData());
-    if (retry_state->retry_dispatched) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(GPR_INFO, "chand=%p retrying_call=%p: retry already dispatched",
-                chand_, this);
-      }
-      return true;
-    }
-  }
-  // Check status.
-  if (GPR_LIKELY(status == GRPC_STATUS_OK)) {
-    if (retry_throttle_data_ != nullptr) {
-      retry_throttle_data_->RecordSuccess();
-    }
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: call succeeded", chand_,
-              this);
-    }
-    return false;
-  }
-  // Status is not OK.  Check whether the status is retryable.
-  if (!retry_policy_->retryable_status_codes.Contains(status)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(
-          GPR_INFO,
-          "chand=%p retrying_call=%p: status %s not configured as retryable",
-          chand_, this, grpc_status_code_to_string(status));
-    }
-    return false;
-  }
-  // Record the failure and check whether retries are throttled.
-  // Note that it's important for this check to come after the status
-  // code check above, since we should only record failures whose statuses
-  // match the configured retryable status codes, so that we don't count
-  // things like failures due to malformed requests (INVALID_ARGUMENT).
-  // Conversely, it's important for this to come before the remaining
-  // checks, so that we don't fail to record failures due to other factors.
-  if (retry_throttle_data_ != nullptr &&
-      !retry_throttle_data_->RecordFailure()) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: retries throttled", chand_,
-              this);
-    }
-    return false;
-  }
-  // Check whether the call is committed.
-  if (retry_committed_) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: retries already committed",
-              chand_, this);
-    }
-    return false;
-  }
-  // Check whether we have retries remaining.
-  ++num_attempts_completed_;
-  if (num_attempts_completed_ >= retry_policy_->max_attempts) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: exceeded %d retry attempts",
-              chand_, this, retry_policy_->max_attempts);
-    }
-    return false;
-  }
-  // If the call was cancelled from the surface, don't retry.
-  if (cancel_error_ != GRPC_ERROR_NONE) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: call cancelled from surface, not "
-              "retrying",
-              chand_, this);
-    }
-    return false;
-  }
-  // Check server push-back.
-  grpc_millis server_pushback_ms = -1;
-  if (server_pushback_md != nullptr) {
-    // If the value is "-1" or any other unparseable string, we do not retry.
-    uint32_t ms;
-    if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(*server_pushback_md), &ms)) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(
-            GPR_INFO,
-            "chand=%p retrying_call=%p: not retrying due to server push-back",
-            chand_, this);
-      }
-      return false;
-    } else {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(GPR_INFO,
-                "chand=%p retrying_call=%p: server push-back: retry in %u ms",
-                chand_, this, ms);
-      }
-      server_pushback_ms = static_cast<grpc_millis>(ms);
-    }
-  }
-  DoRetry(retry_state, server_pushback_ms);
-  return true;
-}
-
-//
-// ChannelData::RetryingCall::SubchannelCallBatchData
-//
-
-ChannelData::RetryingCall::SubchannelCallBatchData*
-ChannelData::RetryingCall::SubchannelCallBatchData::Create(
-    RetryingCall* call, int refcount, bool set_on_complete) {
-  return call->arena_->New<SubchannelCallBatchData>(call, refcount,
-                                                    set_on_complete);
-}
-
-ChannelData::RetryingCall::SubchannelCallBatchData::SubchannelCallBatchData(
-    RetryingCall* call, int refcount, bool set_on_complete)
-    : call(call), lb_call(call->lb_call_) {
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(lb_call->GetParentData());
-  batch.payload = &retry_state->batch_payload;
-  gpr_ref_init(&refs, refcount);
-  if (set_on_complete) {
-    GRPC_CLOSURE_INIT(&on_complete, ChannelData::RetryingCall::OnComplete, this,
-                      grpc_schedule_on_exec_ctx);
-    batch.on_complete = &on_complete;
-  }
-  GRPC_CALL_STACK_REF(call->owning_call_, "batch_data");
-}
-
-void ChannelData::RetryingCall::SubchannelCallBatchData::Destroy() {
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(lb_call->GetParentData());
-  if (batch.send_initial_metadata) {
-    grpc_metadata_batch_destroy(&retry_state->send_initial_metadata);
-  }
-  if (batch.send_trailing_metadata) {
-    grpc_metadata_batch_destroy(&retry_state->send_trailing_metadata);
-  }
-  if (batch.recv_initial_metadata) {
-    grpc_metadata_batch_destroy(&retry_state->recv_initial_metadata);
-  }
-  if (batch.recv_trailing_metadata) {
-    grpc_metadata_batch_destroy(&retry_state->recv_trailing_metadata);
-  }
-  lb_call.reset();
-  GRPC_CALL_STACK_UNREF(call->owning_call_, "batch_data");
-}
-
-//
-// recv_initial_metadata callback handling
-//
-
-void ChannelData::RetryingCall::InvokeRecvInitialMetadataCallback(
-    void* arg, grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  // Find pending batch.
-  PendingBatch* pending = batch_data->call->PendingBatchFind(
-      "invoking recv_initial_metadata_ready for",
-      [](grpc_transport_stream_op_batch* batch) {
-        return batch->recv_initial_metadata &&
-               batch->payload->recv_initial_metadata
-                       .recv_initial_metadata_ready != nullptr;
-      });
-  GPR_ASSERT(pending != nullptr);
-  // Return metadata.
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  grpc_metadata_batch_move(
-      &retry_state->recv_initial_metadata,
-      pending->batch->payload->recv_initial_metadata.recv_initial_metadata);
-  // Update bookkeeping.
-  // Note: Need to do this before invoking the callback, since invoking
-  // the callback will result in yielding the call combiner.
-  grpc_closure* recv_initial_metadata_ready =
-      pending->batch->payload->recv_initial_metadata
-          .recv_initial_metadata_ready;
-  pending->batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
-      nullptr;
-  batch_data->call->MaybeClearPendingBatch(pending);
-  batch_data->Unref();
-  // Invoke callback.
-  Closure::Run(DEBUG_LOCATION, recv_initial_metadata_ready,
-               GRPC_ERROR_REF(error));
-}
-
-void ChannelData::RetryingCall::RecvInitialMetadataReady(void* arg,
-                                                         grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(
-        GPR_INFO,
-        "chand=%p retrying_call=%p: got recv_initial_metadata_ready, error=%s",
-        call->chand_, call, grpc_error_string(error));
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  retry_state->completed_recv_initial_metadata = true;
-  // If a retry was already dispatched, then we're not going to use the
-  // result of this recv_initial_metadata op, so do nothing.
-  if (retry_state->retry_dispatched) {
-    GRPC_CALL_COMBINER_STOP(
-        call->call_combiner_,
-        "recv_initial_metadata_ready after retry dispatched");
-    return;
-  }
-  // If we got an error or a Trailers-Only response and have not yet gotten
-  // the recv_trailing_metadata_ready callback, then defer propagating this
-  // callback back to the surface.  We can evaluate whether to retry when
-  // recv_trailing_metadata comes back.
-  if (GPR_UNLIKELY((retry_state->trailing_metadata_available ||
-                    error != GRPC_ERROR_NONE) &&
-                   !retry_state->completed_recv_trailing_metadata)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(
-          GPR_INFO,
-          "chand=%p retrying_call=%p: deferring recv_initial_metadata_ready "
-          "(Trailers-Only)",
-          call->chand_, call);
-    }
-    retry_state->recv_initial_metadata_ready_deferred_batch = batch_data;
-    retry_state->recv_initial_metadata_error = GRPC_ERROR_REF(error);
-    if (!retry_state->started_recv_trailing_metadata) {
-      // recv_trailing_metadata not yet started by application; start it
-      // ourselves to get status.
-      call->StartInternalRecvTrailingMetadata();
-    } else {
-      GRPC_CALL_COMBINER_STOP(
-          call->call_combiner_,
-          "recv_initial_metadata_ready trailers-only or error");
-    }
-    return;
-  }
-  // Received valid initial metadata, so commit the call.
-  call->RetryCommit(retry_state);
-  // Invoke the callback to return the result to the surface.
-  // Manually invoking a callback function; it does not take ownership of error.
-  call->InvokeRecvInitialMetadataCallback(batch_data, error);
-}
-
-//
-// recv_message callback handling
-//
-
-void ChannelData::RetryingCall::InvokeRecvMessageCallback(void* arg,
-                                                          grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  // Find pending op.
-  PendingBatch* pending = call->PendingBatchFind(
-      "invoking recv_message_ready for",
-      [](grpc_transport_stream_op_batch* batch) {
-        return batch->recv_message &&
-               batch->payload->recv_message.recv_message_ready != nullptr;
-      });
-  GPR_ASSERT(pending != nullptr);
-  // Return payload.
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  *pending->batch->payload->recv_message.recv_message =
-      std::move(retry_state->recv_message);
-  // Update bookkeeping.
-  // Note: Need to do this before invoking the callback, since invoking
-  // the callback will result in yielding the call combiner.
-  grpc_closure* recv_message_ready =
-      pending->batch->payload->recv_message.recv_message_ready;
-  pending->batch->payload->recv_message.recv_message_ready = nullptr;
-  call->MaybeClearPendingBatch(pending);
-  batch_data->Unref();
-  // Invoke callback.
-  Closure::Run(DEBUG_LOCATION, recv_message_ready, GRPC_ERROR_REF(error));
-}
-
-void ChannelData::RetryingCall::RecvMessageReady(void* arg, grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: got recv_message_ready, error=%s",
-            call->chand_, call, grpc_error_string(error));
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  ++retry_state->completed_recv_message_count;
-  // If a retry was already dispatched, then we're not going to use the
-  // result of this recv_message op, so do nothing.
-  if (retry_state->retry_dispatched) {
-    GRPC_CALL_COMBINER_STOP(call->call_combiner_,
-                            "recv_message_ready after retry dispatched");
-    return;
-  }
-  // If we got an error or the payload was nullptr and we have not yet gotten
-  // the recv_trailing_metadata_ready callback, then defer propagating this
-  // callback back to the surface.  We can evaluate whether to retry when
-  // recv_trailing_metadata comes back.
-  if (GPR_UNLIKELY(
-          (retry_state->recv_message == nullptr || error != GRPC_ERROR_NONE) &&
-          !retry_state->completed_recv_trailing_metadata)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(
-          GPR_INFO,
-          "chand=%p retrying_call=%p: deferring recv_message_ready (nullptr "
-          "message and recv_trailing_metadata pending)",
-          call->chand_, call);
-    }
-    retry_state->recv_message_ready_deferred_batch = batch_data;
-    retry_state->recv_message_error = GRPC_ERROR_REF(error);
-    if (!retry_state->started_recv_trailing_metadata) {
-      // recv_trailing_metadata not yet started by application; start it
-      // ourselves to get status.
-      call->StartInternalRecvTrailingMetadata();
-    } else {
-      GRPC_CALL_COMBINER_STOP(call->call_combiner_, "recv_message_ready null");
-    }
-    return;
-  }
-  // Received a valid message, so commit the call.
-  call->RetryCommit(retry_state);
-  // Invoke the callback to return the result to the surface.
-  // Manually invoking a callback function; it does not take ownership of error.
-  call->InvokeRecvMessageCallback(batch_data, error);
-}
-
-//
-// recv_trailing_metadata handling
-//
-
-void ChannelData::RetryingCall::GetCallStatus(
-    grpc_metadata_batch* md_batch, grpc_error* error, grpc_status_code* status,
-    grpc_mdelem** server_pushback_md) {
-  if (error != GRPC_ERROR_NONE) {
-    grpc_error_get_status(error, deadline_, status, nullptr, nullptr, nullptr);
-  } else {
-    GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
-    *status =
-        grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md);
-    if (server_pushback_md != nullptr &&
-        md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
-      *server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
-    }
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-void ChannelData::RetryingCall::AddClosureForRecvTrailingMetadataReady(
-    SubchannelCallBatchData* batch_data, grpc_error* error,
-    CallCombinerClosureList* closures) {
-  // Find pending batch.
-  PendingBatch* pending = PendingBatchFind(
-      "invoking recv_trailing_metadata for",
-      [](grpc_transport_stream_op_batch* batch) {
-        return batch->recv_trailing_metadata &&
-               batch->payload->recv_trailing_metadata
-                       .recv_trailing_metadata_ready != nullptr;
-      });
-  // If we generated the recv_trailing_metadata op internally via
-  // StartInternalRecvTrailingMetadata(), then there will be no pending batch.
-  if (pending == nullptr) {
-    GRPC_ERROR_UNREF(error);
-    return;
-  }
-  // Return metadata.
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  grpc_metadata_batch_move(
-      &retry_state->recv_trailing_metadata,
-      pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata);
-  // Add closure.
-  closures->Add(pending->batch->payload->recv_trailing_metadata
-                    .recv_trailing_metadata_ready,
-                error, "recv_trailing_metadata_ready for pending batch");
-  // Update bookkeeping.
-  pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
-      nullptr;
-  MaybeClearPendingBatch(pending);
-}
-
-void ChannelData::RetryingCall::AddClosuresForDeferredRecvCallbacks(
-    SubchannelCallBatchData* batch_data, SubchannelCallRetryState* retry_state,
-    CallCombinerClosureList* closures) {
-  if (batch_data->batch.recv_trailing_metadata) {
-    // Add closure for deferred recv_initial_metadata_ready.
-    if (GPR_UNLIKELY(retry_state->recv_initial_metadata_ready_deferred_batch !=
-                     nullptr)) {
-      GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready,
-                        InvokeRecvInitialMetadataCallback,
-                        retry_state->recv_initial_metadata_ready_deferred_batch,
-                        grpc_schedule_on_exec_ctx);
-      closures->Add(&retry_state->recv_initial_metadata_ready,
-                    retry_state->recv_initial_metadata_error,
-                    "resuming recv_initial_metadata_ready");
-      retry_state->recv_initial_metadata_ready_deferred_batch = nullptr;
-    }
-    // Add closure for deferred recv_message_ready.
-    if (GPR_UNLIKELY(retry_state->recv_message_ready_deferred_batch !=
-                     nullptr)) {
-      GRPC_CLOSURE_INIT(&retry_state->recv_message_ready,
-                        InvokeRecvMessageCallback,
-                        retry_state->recv_message_ready_deferred_batch,
-                        grpc_schedule_on_exec_ctx);
-      closures->Add(&retry_state->recv_message_ready,
-                    retry_state->recv_message_error,
-                    "resuming recv_message_ready");
-      retry_state->recv_message_ready_deferred_batch = nullptr;
-    }
-  }
-}
-
-bool ChannelData::RetryingCall::PendingBatchIsUnstarted(
-    PendingBatch* pending, SubchannelCallRetryState* retry_state) {
-  if (pending->batch == nullptr || pending->batch->on_complete == nullptr) {
-    return false;
-  }
-  if (pending->batch->send_initial_metadata &&
-      !retry_state->started_send_initial_metadata) {
-    return true;
-  }
-  if (pending->batch->send_message &&
-      retry_state->started_send_message_count < send_messages_.size()) {
-    return true;
-  }
-  if (pending->batch->send_trailing_metadata &&
-      !retry_state->started_send_trailing_metadata) {
-    return true;
-  }
-  return false;
-}
-
-void ChannelData::RetryingCall::AddClosuresToFailUnstartedPendingBatches(
-    SubchannelCallRetryState* retry_state, grpc_error* error,
-    CallCombinerClosureList* closures) {
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    if (PendingBatchIsUnstarted(pending, retry_state)) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(GPR_INFO,
-                "chand=%p retrying_call=%p: failing unstarted pending batch at "
-                "index "
-                "%" PRIuPTR,
-                chand_, this, i);
-      }
-      closures->Add(pending->batch->on_complete, GRPC_ERROR_REF(error),
-                    "failing on_complete for pending batch");
-      pending->batch->on_complete = nullptr;
-      MaybeClearPendingBatch(pending);
-    }
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-void ChannelData::RetryingCall::RunClosuresForCompletedCall(
-    SubchannelCallBatchData* batch_data, grpc_error* error) {
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  // Construct list of closures to execute.
-  CallCombinerClosureList closures;
-  // First, add closure for recv_trailing_metadata_ready.
-  AddClosureForRecvTrailingMetadataReady(batch_data, GRPC_ERROR_REF(error),
-                                         &closures);
-  // If there are deferred recv_initial_metadata_ready or recv_message_ready
-  // callbacks, add them to closures.
-  AddClosuresForDeferredRecvCallbacks(batch_data, retry_state, &closures);
-  // Add closures to fail any pending batches that have not yet been started.
-  AddClosuresToFailUnstartedPendingBatches(retry_state, GRPC_ERROR_REF(error),
-                                           &closures);
-  // Don't need batch_data anymore.
-  batch_data->Unref();
-  // Schedule all of the closures identified above.
-  // Note: This will release the call combiner.
-  closures.RunClosures(call_combiner_);
-  GRPC_ERROR_UNREF(error);
-}
-
-void ChannelData::RetryingCall::RecvTrailingMetadataReady(void* arg,
-                                                          grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(
-        GPR_INFO,
-        "chand=%p retrying_call=%p: got recv_trailing_metadata_ready, error=%s",
-        call->chand_, call, grpc_error_string(error));
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  retry_state->completed_recv_trailing_metadata = true;
-  // Get the call's status and check for server pushback metadata.
-  grpc_status_code status = GRPC_STATUS_OK;
-  grpc_mdelem* server_pushback_md = nullptr;
-  grpc_metadata_batch* md_batch =
-      batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata;
-  call->GetCallStatus(md_batch, GRPC_ERROR_REF(error), &status,
-                      &server_pushback_md);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO, "chand=%p retrying_call=%p: call finished, status=%s",
-            call->chand_, call, grpc_status_code_to_string(status));
-  }
-  // Check if we should retry.
-  if (call->MaybeRetry(batch_data, status, server_pushback_md)) {
-    // Unref batch_data for deferred recv_initial_metadata_ready or
-    // recv_message_ready callbacks, if any.
-    if (retry_state->recv_initial_metadata_ready_deferred_batch != nullptr) {
-      batch_data->Unref();
-      GRPC_ERROR_UNREF(retry_state->recv_initial_metadata_error);
-    }
-    if (retry_state->recv_message_ready_deferred_batch != nullptr) {
-      batch_data->Unref();
-      GRPC_ERROR_UNREF(retry_state->recv_message_error);
-    }
-    batch_data->Unref();
-    return;
-  }
-  // Not retrying, so commit the call.
-  call->RetryCommit(retry_state);
-  // Run any necessary closures.
-  call->RunClosuresForCompletedCall(batch_data, GRPC_ERROR_REF(error));
-}
-
-//
-// on_complete callback handling
-//
-
-void ChannelData::RetryingCall::AddClosuresForCompletedPendingBatch(
-    SubchannelCallBatchData* batch_data, grpc_error* error,
-    CallCombinerClosureList* closures) {
-  PendingBatch* pending = PendingBatchFind(
-      "completed", [batch_data](grpc_transport_stream_op_batch* batch) {
-        // Match the pending batch with the same set of send ops as the
-        // subchannel batch we've just completed.
-        return batch->on_complete != nullptr &&
-               batch_data->batch.send_initial_metadata ==
-                   batch->send_initial_metadata &&
-               batch_data->batch.send_message == batch->send_message &&
-               batch_data->batch.send_trailing_metadata ==
-                   batch->send_trailing_metadata;
-      });
-  // If batch_data is a replay batch, then there will be no pending
-  // batch to complete.
-  if (pending == nullptr) {
-    GRPC_ERROR_UNREF(error);
-    return;
-  }
-  // Add closure.
-  closures->Add(pending->batch->on_complete, error,
-                "on_complete for pending batch");
-  pending->batch->on_complete = nullptr;
-  MaybeClearPendingBatch(pending);
-}
-
-void ChannelData::RetryingCall::AddClosuresForReplayOrPendingSendOps(
-    SubchannelCallBatchData* batch_data, SubchannelCallRetryState* retry_state,
-    CallCombinerClosureList* closures) {
-  bool have_pending_send_message_ops =
-      retry_state->started_send_message_count < send_messages_.size();
-  bool have_pending_send_trailing_metadata_op =
-      seen_send_trailing_metadata_ &&
-      !retry_state->started_send_trailing_metadata;
-  if (!have_pending_send_message_ops &&
-      !have_pending_send_trailing_metadata_op) {
-    for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-      PendingBatch* pending = &pending_batches_[i];
-      grpc_transport_stream_op_batch* batch = pending->batch;
-      if (batch == nullptr || pending->send_ops_cached) continue;
-      if (batch->send_message) have_pending_send_message_ops = true;
-      if (batch->send_trailing_metadata) {
-        have_pending_send_trailing_metadata_op = true;
-      }
-    }
-  }
-  if (have_pending_send_message_ops || have_pending_send_trailing_metadata_op) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: starting next batch for pending send "
-              "op(s)",
-              chand_, this);
-    }
-    GRPC_CLOSURE_INIT(&batch_data->batch.handler_private.closure,
-                      StartRetriableSubchannelBatches, this,
-                      grpc_schedule_on_exec_ctx);
-    closures->Add(&batch_data->batch.handler_private.closure, GRPC_ERROR_NONE,
-                  "starting next batch for send_* op(s)");
-  }
-}
-
-void ChannelData::RetryingCall::OnComplete(void* arg, grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: got on_complete, error=%s, batch=%s",
-            call->chand_, call, grpc_error_string(error),
-            grpc_transport_stream_op_batch_string(&batch_data->batch).c_str());
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  // Update bookkeeping in retry_state.
-  if (batch_data->batch.send_initial_metadata) {
-    retry_state->completed_send_initial_metadata = true;
-  }
-  if (batch_data->batch.send_message) {
-    ++retry_state->completed_send_message_count;
-  }
-  if (batch_data->batch.send_trailing_metadata) {
-    retry_state->completed_send_trailing_metadata = true;
-  }
-  // If the call is committed, free cached data for send ops that we've just
-  // completed.
-  if (call->retry_committed_) {
-    call->FreeCachedSendOpDataForCompletedBatch(batch_data, retry_state);
-  }
-  // Construct list of closures to execute.
-  CallCombinerClosureList closures;
-  // If a retry was already dispatched, that means we saw
-  // recv_trailing_metadata before this, so we do nothing here.
-  // Otherwise, invoke the callback to return the result to the surface.
-  if (!retry_state->retry_dispatched) {
-    // Add closure for the completed pending batch, if any.
-    call->AddClosuresForCompletedPendingBatch(batch_data, GRPC_ERROR_REF(error),
-                                              &closures);
-    // If needed, add a callback to start any replay or pending send ops on
-    // the subchannel call.
-    if (!retry_state->completed_recv_trailing_metadata) {
-      call->AddClosuresForReplayOrPendingSendOps(batch_data, retry_state,
-                                                 &closures);
-    }
-  }
-  // Track number of pending subchannel send batches and determine if this
-  // was the last one.
-  --call->num_pending_retriable_subchannel_send_batches_;
-  const bool last_send_batch_complete =
-      call->num_pending_retriable_subchannel_send_batches_ == 0;
-  // Don't need batch_data anymore.
-  batch_data->Unref();
-  // Schedule all of the closures identified above.
-  // Note: This yeilds the call combiner.
-  closures.RunClosures(call->call_combiner_);
-  // If this was the last subchannel send batch, unref the call stack.
-  if (last_send_batch_complete) {
-    GRPC_CALL_STACK_UNREF(call->owning_call_, "subchannel_send_batches");
-  }
-}
-
-//
-// subchannel batch construction
-//
-
-void ChannelData::RetryingCall::StartBatchInCallCombiner(
-    void* arg, grpc_error* /*ignored*/) {
-  grpc_transport_stream_op_batch* batch =
-      static_cast<grpc_transport_stream_op_batch*>(arg);
-  auto* lb_call = static_cast<ChannelData::LoadBalancedCall*>(
-      batch->handler_private.extra_arg);
-  // Note: This will release the call combiner.
-  lb_call->StartTransportStreamOpBatch(batch);
-}
-
-void ChannelData::RetryingCall::AddClosureForSubchannelBatch(
-    grpc_transport_stream_op_batch* batch, CallCombinerClosureList* closures) {
-  batch->handler_private.extra_arg = lb_call_.get();
-  GRPC_CLOSURE_INIT(&batch->handler_private.closure, StartBatchInCallCombiner,
-                    batch, grpc_schedule_on_exec_ctx);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: starting subchannel batch: %s", chand_,
-            this, grpc_transport_stream_op_batch_string(batch).c_str());
-  }
-  closures->Add(&batch->handler_private.closure, GRPC_ERROR_NONE,
-                "start_subchannel_batch");
-}
-
-void ChannelData::RetryingCall::AddRetriableSendInitialMetadataOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  // Maps the number of retries to the corresponding metadata value slice.
-  const grpc_slice* retry_count_strings[] = {&GRPC_MDSTR_1, &GRPC_MDSTR_2,
-                                             &GRPC_MDSTR_3, &GRPC_MDSTR_4};
-  // We need to make a copy of the metadata batch for each attempt, since
-  // the filters in the subchannel stack may modify this batch, and we don't
-  // want those modifications to be passed forward to subsequent attempts.
-  //
-  // If we've already completed one or more attempts, add the
-  // grpc-retry-attempts header.
-  retry_state->send_initial_metadata_storage =
-      static_cast<grpc_linked_mdelem*>(arena_->Alloc(
-          sizeof(grpc_linked_mdelem) *
-          (send_initial_metadata_.list.count + (num_attempts_completed_ > 0))));
-  grpc_metadata_batch_copy(&send_initial_metadata_,
-                           &retry_state->send_initial_metadata,
-                           retry_state->send_initial_metadata_storage);
-  if (GPR_UNLIKELY(retry_state->send_initial_metadata.idx.named
-                       .grpc_previous_rpc_attempts != nullptr)) {
-    grpc_metadata_batch_remove(&retry_state->send_initial_metadata,
-                               GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS);
-  }
-  if (GPR_UNLIKELY(num_attempts_completed_ > 0)) {
-    grpc_mdelem retry_md = grpc_mdelem_create(
-        GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS,
-        *retry_count_strings[num_attempts_completed_ - 1], nullptr);
-    grpc_error* error = grpc_metadata_batch_add_tail(
-        &retry_state->send_initial_metadata,
-        &retry_state
-             ->send_initial_metadata_storage[send_initial_metadata_.list.count],
-        retry_md, GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS);
-    if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
-      gpr_log(GPR_ERROR, "error adding retry metadata: %s",
-              grpc_error_string(error));
-      GPR_ASSERT(false);
-    }
-  }
-  retry_state->started_send_initial_metadata = true;
-  batch_data->batch.send_initial_metadata = true;
-  batch_data->batch.payload->send_initial_metadata.send_initial_metadata =
-      &retry_state->send_initial_metadata;
-  batch_data->batch.payload->send_initial_metadata.send_initial_metadata_flags =
-      send_initial_metadata_flags_;
-  batch_data->batch.payload->send_initial_metadata.peer_string = peer_string_;
-}
-
-void ChannelData::RetryingCall::AddRetriableSendMessageOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: starting calld->send_messages[%" PRIuPTR
-            "]",
-            chand_, this, retry_state->started_send_message_count);
-  }
-  ByteStreamCache* cache =
-      send_messages_[retry_state->started_send_message_count];
-  ++retry_state->started_send_message_count;
-  retry_state->send_message.Init(cache);
-  batch_data->batch.send_message = true;
-  batch_data->batch.payload->send_message.send_message.reset(
-      retry_state->send_message.get());
-}
-
-void ChannelData::RetryingCall::AddRetriableSendTrailingMetadataOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  // We need to make a copy of the metadata batch for each attempt, since
-  // the filters in the subchannel stack may modify this batch, and we don't
-  // want those modifications to be passed forward to subsequent attempts.
-  retry_state->send_trailing_metadata_storage =
-      static_cast<grpc_linked_mdelem*>(arena_->Alloc(
-          sizeof(grpc_linked_mdelem) * send_trailing_metadata_.list.count));
-  grpc_metadata_batch_copy(&send_trailing_metadata_,
-                           &retry_state->send_trailing_metadata,
-                           retry_state->send_trailing_metadata_storage);
-  retry_state->started_send_trailing_metadata = true;
-  batch_data->batch.send_trailing_metadata = true;
-  batch_data->batch.payload->send_trailing_metadata.send_trailing_metadata =
-      &retry_state->send_trailing_metadata;
-}
-
-void ChannelData::RetryingCall::AddRetriableRecvInitialMetadataOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  retry_state->started_recv_initial_metadata = true;
-  batch_data->batch.recv_initial_metadata = true;
-  grpc_metadata_batch_init(&retry_state->recv_initial_metadata);
-  batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata =
-      &retry_state->recv_initial_metadata;
-  batch_data->batch.payload->recv_initial_metadata.trailing_metadata_available =
-      &retry_state->trailing_metadata_available;
-  GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready,
-                    RecvInitialMetadataReady, batch_data,
-                    grpc_schedule_on_exec_ctx);
-  batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata_ready =
-      &retry_state->recv_initial_metadata_ready;
-}
-
-void ChannelData::RetryingCall::AddRetriableRecvMessageOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  ++retry_state->started_recv_message_count;
-  batch_data->batch.recv_message = true;
-  batch_data->batch.payload->recv_message.recv_message =
-      &retry_state->recv_message;
-  GRPC_CLOSURE_INIT(&retry_state->recv_message_ready, RecvMessageReady,
-                    batch_data, grpc_schedule_on_exec_ctx);
-  batch_data->batch.payload->recv_message.recv_message_ready =
-      &retry_state->recv_message_ready;
-}
-
-void ChannelData::RetryingCall::AddRetriableRecvTrailingMetadataOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  retry_state->started_recv_trailing_metadata = true;
-  batch_data->batch.recv_trailing_metadata = true;
-  grpc_metadata_batch_init(&retry_state->recv_trailing_metadata);
-  batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata =
-      &retry_state->recv_trailing_metadata;
-  batch_data->batch.payload->recv_trailing_metadata.collect_stats =
-      &retry_state->collect_stats;
-  GRPC_CLOSURE_INIT(&retry_state->recv_trailing_metadata_ready,
-                    RecvTrailingMetadataReady, batch_data,
-                    grpc_schedule_on_exec_ctx);
-  batch_data->batch.payload->recv_trailing_metadata
-      .recv_trailing_metadata_ready =
-      &retry_state->recv_trailing_metadata_ready;
-}
-
-void ChannelData::RetryingCall::StartInternalRecvTrailingMetadata() {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(
-        GPR_INFO,
-        "chand=%p retrying_call=%p: call failed but recv_trailing_metadata not "
-        "started; starting it internally",
-        chand_, this);
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(lb_call_->GetParentData());
-  // Create batch_data with 2 refs, since this batch will be unreffed twice:
-  // once for the recv_trailing_metadata_ready callback when the subchannel
-  // batch returns, and again when we actually get a recv_trailing_metadata
-  // op from the surface.
-  SubchannelCallBatchData* batch_data =
-      SubchannelCallBatchData::Create(this, 2, false /* set_on_complete */);
-  AddRetriableRecvTrailingMetadataOp(retry_state, batch_data);
-  retry_state->recv_trailing_metadata_internal_batch = batch_data;
-  // Note: This will release the call combiner.
-  lb_call_->StartTransportStreamOpBatch(&batch_data->batch);
-}
-
-// If there are any cached send ops that need to be replayed on the
-// current subchannel call, creates and returns a new subchannel batch
-// to replay those ops.  Otherwise, returns nullptr.
-ChannelData::RetryingCall::SubchannelCallBatchData*
-ChannelData::RetryingCall::MaybeCreateSubchannelBatchForReplay(
-    SubchannelCallRetryState* retry_state) {
-  SubchannelCallBatchData* replay_batch_data = nullptr;
-  // send_initial_metadata.
-  if (seen_send_initial_metadata_ &&
-      !retry_state->started_send_initial_metadata &&
-      !pending_send_initial_metadata_) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: replaying previously completed "
-              "send_initial_metadata op",
-              chand_, this);
-    }
-    replay_batch_data =
-        SubchannelCallBatchData::Create(this, 1, true /* set_on_complete */);
-    AddRetriableSendInitialMetadataOp(retry_state, replay_batch_data);
-  }
-  // send_message.
-  // Note that we can only have one send_message op in flight at a time.
-  if (retry_state->started_send_message_count < send_messages_.size() &&
-      retry_state->started_send_message_count ==
-          retry_state->completed_send_message_count &&
-      !pending_send_message_) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: replaying previously completed "
-              "send_message op",
-              chand_, this);
-    }
-    if (replay_batch_data == nullptr) {
-      replay_batch_data =
-          SubchannelCallBatchData::Create(this, 1, true /* set_on_complete */);
-    }
-    AddRetriableSendMessageOp(retry_state, replay_batch_data);
-  }
-  // send_trailing_metadata.
-  // Note that we only add this op if we have no more send_message ops
-  // to start, since we can't send down any more send_message ops after
-  // send_trailing_metadata.
-  if (seen_send_trailing_metadata_ &&
-      retry_state->started_send_message_count == send_messages_.size() &&
-      !retry_state->started_send_trailing_metadata &&
-      !pending_send_trailing_metadata_) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: replaying previously completed "
-              "send_trailing_metadata op",
-              chand_, this);
-    }
-    if (replay_batch_data == nullptr) {
-      replay_batch_data =
-          SubchannelCallBatchData::Create(this, 1, true /* set_on_complete */);
-    }
-    AddRetriableSendTrailingMetadataOp(retry_state, replay_batch_data);
-  }
-  return replay_batch_data;
-}
-
-void ChannelData::RetryingCall::AddSubchannelBatchesForPendingBatches(
-    SubchannelCallRetryState* retry_state, CallCombinerClosureList* closures) {
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    grpc_transport_stream_op_batch* batch = pending->batch;
-    if (batch == nullptr) continue;
-    // Skip any batch that either (a) has already been started on this
-    // subchannel call or (b) we can't start yet because we're still
-    // replaying send ops that need to be completed first.
-    // TODO(roth): Note that if any one op in the batch can't be sent
-    // yet due to ops that we're replaying, we don't start any of the ops
-    // in the batch.  This is probably okay, but it could conceivably
-    // lead to increased latency in some cases -- e.g., we could delay
-    // starting a recv op due to it being in the same batch with a send
-    // op.  If/when we revamp the callback protocol in
-    // transport_stream_op_batch, we may be able to fix this.
-    if (batch->send_initial_metadata &&
-        retry_state->started_send_initial_metadata) {
-      continue;
-    }
-    if (batch->send_message && retry_state->completed_send_message_count <
-                                   retry_state->started_send_message_count) {
-      continue;
-    }
-    // Note that we only start send_trailing_metadata if we have no more
-    // send_message ops to start, since we can't send down any more
-    // send_message ops after send_trailing_metadata.
-    if (batch->send_trailing_metadata &&
-        (retry_state->started_send_message_count + batch->send_message <
-             send_messages_.size() ||
-         retry_state->started_send_trailing_metadata)) {
-      continue;
-    }
-    if (batch->recv_initial_metadata &&
-        retry_state->started_recv_initial_metadata) {
-      continue;
-    }
-    if (batch->recv_message && retry_state->completed_recv_message_count <
-                                   retry_state->started_recv_message_count) {
-      continue;
-    }
-    if (batch->recv_trailing_metadata &&
-        retry_state->started_recv_trailing_metadata) {
-      // If we previously completed a recv_trailing_metadata op
-      // initiated by StartInternalRecvTrailingMetadata(), use the
-      // result of that instead of trying to re-start this op.
-      if (GPR_UNLIKELY((retry_state->recv_trailing_metadata_internal_batch !=
-                        nullptr))) {
-        // If the batch completed, then trigger the completion callback
-        // directly, so that we return the previously returned results to
-        // the application.  Otherwise, just unref the internally
-        // started subchannel batch, since we'll propagate the
-        // completion when it completes.
-        if (retry_state->completed_recv_trailing_metadata) {
-          // Batches containing recv_trailing_metadata always succeed.
-          closures->Add(
-              &retry_state->recv_trailing_metadata_ready, GRPC_ERROR_NONE,
-              "re-executing recv_trailing_metadata_ready to propagate "
-              "internally triggered result");
-        } else {
-          retry_state->recv_trailing_metadata_internal_batch->Unref();
-        }
-        retry_state->recv_trailing_metadata_internal_batch = nullptr;
-      }
-      continue;
-    }
-    // If we're not retrying, just send the batch as-is.
-    // TODO(roth): This condition doesn't seem exactly right -- maybe need a
-    // notion of "draining" once we've committed and are done replaying?
-    if (retry_policy_ == nullptr || retry_committed_) {
-      AddClosureForSubchannelBatch(batch, closures);
-      PendingBatchClear(pending);
-      continue;
-    }
-    // Create batch with the right number of callbacks.
-    const bool has_send_ops = batch->send_initial_metadata ||
-                              batch->send_message ||
-                              batch->send_trailing_metadata;
-    const int num_callbacks = has_send_ops + batch->recv_initial_metadata +
-                              batch->recv_message +
-                              batch->recv_trailing_metadata;
-    SubchannelCallBatchData* batch_data = SubchannelCallBatchData::Create(
-        this, num_callbacks, has_send_ops /* set_on_complete */);
-    // Cache send ops if needed.
-    MaybeCacheSendOpsForBatch(pending);
-    // send_initial_metadata.
-    if (batch->send_initial_metadata) {
-      AddRetriableSendInitialMetadataOp(retry_state, batch_data);
-    }
-    // send_message.
-    if (batch->send_message) {
-      AddRetriableSendMessageOp(retry_state, batch_data);
-    }
-    // send_trailing_metadata.
-    if (batch->send_trailing_metadata) {
-      AddRetriableSendTrailingMetadataOp(retry_state, batch_data);
-    }
-    // recv_initial_metadata.
-    if (batch->recv_initial_metadata) {
-      // recv_flags is only used on the server side.
-      GPR_ASSERT(batch->payload->recv_initial_metadata.recv_flags == nullptr);
-      AddRetriableRecvInitialMetadataOp(retry_state, batch_data);
-    }
-    // recv_message.
-    if (batch->recv_message) {
-      AddRetriableRecvMessageOp(retry_state, batch_data);
-    }
-    // recv_trailing_metadata.
-    if (batch->recv_trailing_metadata) {
-      AddRetriableRecvTrailingMetadataOp(retry_state, batch_data);
-    }
-    AddClosureForSubchannelBatch(&batch_data->batch, closures);
-    // Track number of pending subchannel send batches.
-    // If this is the first one, take a ref to the call stack.
-    if (batch->send_initial_metadata || batch->send_message ||
-        batch->send_trailing_metadata) {
-      if (num_pending_retriable_subchannel_send_batches_ == 0) {
-        GRPC_CALL_STACK_REF(owning_call_, "subchannel_send_batches");
-      }
-      ++num_pending_retriable_subchannel_send_batches_;
-    }
-  }
-}
-
-void ChannelData::RetryingCall::StartRetriableSubchannelBatches(
-    void* arg, grpc_error* /*ignored*/) {
-  RetryingCall* call = static_cast<RetryingCall*>(arg);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: constructing retriable batches",
-            call->chand_, call);
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(call->lb_call_->GetParentData());
-  // Construct list of closures to execute, one for each pending batch.
-  CallCombinerClosureList closures;
-  // Replay previously-returned send_* ops if needed.
-  SubchannelCallBatchData* replay_batch_data =
-      call->MaybeCreateSubchannelBatchForReplay(retry_state);
-  if (replay_batch_data != nullptr) {
-    call->AddClosureForSubchannelBatch(&replay_batch_data->batch, &closures);
-    // Track number of pending subchannel send batches.
-    // If this is the first one, take a ref to the call stack.
-    if (call->num_pending_retriable_subchannel_send_batches_ == 0) {
-      GRPC_CALL_STACK_REF(call->owning_call_, "subchannel_send_batches");
-    }
-    ++call->num_pending_retriable_subchannel_send_batches_;
-  }
-  // Now add pending batches.
-  call->AddSubchannelBatchesForPendingBatches(retry_state, &closures);
-  // Start batches on subchannel call.
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: starting %" PRIuPTR
-            " retriable batches on lb_call=%p",
-            call->chand_, call, closures.size(), call->lb_call_.get());
-  }
-  // Note: This will yield the call combiner.
-  closures.RunClosures(call->call_combiner_);
-}
-
-void ChannelData::RetryingCall::CreateLbCall(void* arg, grpc_error* /*error*/) {
-  auto* call = static_cast<RetryingCall*>(arg);
-  const size_t parent_data_size =
-      call->enable_retries_ ? sizeof(SubchannelCallRetryState) : 0;
-  grpc_call_element_args args = {call->owning_call_,     nullptr,
-                                 call->call_context_,    call->path_,
-                                 call->call_start_time_, call->deadline_,
-                                 call->arena_,           call->call_combiner_};
-  call->lb_call_ = ChannelData::LoadBalancedCall::Create(
-      call->chand_, args, call->pollent_, parent_data_size);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
-    gpr_log(GPR_INFO, "chand=%p retrying_call=%p: create lb_call=%p",
-            call->chand_, call, call->lb_call_.get());
-  }
-  if (parent_data_size > 0) {
-    new (call->lb_call_->GetParentData())
-        SubchannelCallRetryState(call->call_context_);
-  }
-  call->PendingBatchesResume();
-}
-
-//
-// ChannelData::LoadBalancedCall::Metadata
-//
-
-class ChannelData::LoadBalancedCall::Metadata
-    : public LoadBalancingPolicy::MetadataInterface {
- public:
-  Metadata(LoadBalancedCall* lb_call, grpc_metadata_batch* batch)
-      : lb_call_(lb_call), batch_(batch) {}
-
-  void Add(absl::string_view key, absl::string_view value) override {
-    grpc_linked_mdelem* linked_mdelem = static_cast<grpc_linked_mdelem*>(
-        lb_call_->arena_->Alloc(sizeof(grpc_linked_mdelem)));
-    linked_mdelem->md = grpc_mdelem_from_slices(
-        ExternallyManagedSlice(key.data(), key.size()),
-        ExternallyManagedSlice(value.data(), value.size()));
-    GPR_ASSERT(grpc_metadata_batch_link_tail(batch_, linked_mdelem) ==
-               GRPC_ERROR_NONE);
-  }
-
-  iterator begin() const override {
-    static_assert(sizeof(grpc_linked_mdelem*) <= sizeof(intptr_t),
-                  "iterator size too large");
-    return iterator(
-        this, reinterpret_cast<intptr_t>(MaybeSkipEntry(batch_->list.head)));
-  }
-  iterator end() const override {
-    static_assert(sizeof(grpc_linked_mdelem*) <= sizeof(intptr_t),
-                  "iterator size too large");
-    return iterator(this, 0);
-  }
-
-  iterator erase(iterator it) override {
-    grpc_linked_mdelem* linked_mdelem =
-        reinterpret_cast<grpc_linked_mdelem*>(GetIteratorHandle(it));
-    intptr_t handle = reinterpret_cast<intptr_t>(linked_mdelem->next);
-    grpc_metadata_batch_remove(batch_, linked_mdelem);
-    return iterator(this, handle);
-  }
-
- private:
-  grpc_linked_mdelem* MaybeSkipEntry(grpc_linked_mdelem* entry) const {
-    if (entry != nullptr && batch_->idx.named.path == entry) {
-      return entry->next;
-    }
-    return entry;
-  }
-
-  intptr_t IteratorHandleNext(intptr_t handle) const override {
-    grpc_linked_mdelem* linked_mdelem =
-        reinterpret_cast<grpc_linked_mdelem*>(handle);
-    return reinterpret_cast<intptr_t>(MaybeSkipEntry(linked_mdelem->next));
-  }
-
-  std::pair<absl::string_view, absl::string_view> IteratorHandleGet(
-      intptr_t handle) const override {
-    grpc_linked_mdelem* linked_mdelem =
-        reinterpret_cast<grpc_linked_mdelem*>(handle);
-    return std::make_pair(StringViewFromSlice(GRPC_MDKEY(linked_mdelem->md)),
-                          StringViewFromSlice(GRPC_MDVALUE(linked_mdelem->md)));
-  }
-
-  LoadBalancedCall* lb_call_;
-  grpc_metadata_batch* batch_;
-};
-
-//
-// ChannelData::LoadBalancedCall::LbCallState
-//
-
-class ChannelData::LoadBalancedCall::LbCallState
-    : public LoadBalancingPolicy::CallState {
- public:
-  explicit LbCallState(LoadBalancedCall* lb_call) : lb_call_(lb_call) {}
-
-  void* Alloc(size_t size) override { return lb_call_->arena_->Alloc(size); }
-
-  const LoadBalancingPolicy::BackendMetricData* GetBackendMetricData()
-      override {
-    if (lb_call_->backend_metric_data_ == nullptr) {
-      grpc_linked_mdelem* md = lb_call_->recv_trailing_metadata_->idx.named
-                                   .x_endpoint_load_metrics_bin;
-      if (md != nullptr) {
-        lb_call_->backend_metric_data_ =
-            ParseBackendMetricData(GRPC_MDVALUE(md->md), lb_call_->arena_);
-      }
-    }
-    return lb_call_->backend_metric_data_;
-  }
-
-  absl::string_view ExperimentalGetCallAttribute(const char* key) override {
-    auto* service_config_call_data = static_cast<ServiceConfigCallData*>(
-        lb_call_->call_context_[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value);
-    auto& call_attributes = service_config_call_data->call_attributes();
-    auto it = call_attributes.find(key);
-    if (it == call_attributes.end()) return absl::string_view();
-    return it->second;
-  }
-
- private:
-  LoadBalancedCall* lb_call_;
-};
-
-//
-// LoadBalancedCall
-//
-
-RefCountedPtr<ChannelData::LoadBalancedCall>
-ChannelData::LoadBalancedCall::Create(ChannelData* chand,
-                                      const grpc_call_element_args& args,
-                                      grpc_polling_entity* pollent,
-                                      size_t parent_data_size) {
-  const size_t alloc_size =
-      parent_data_size > 0
-          ? (GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(LoadBalancedCall)) +
-             parent_data_size)
-          : sizeof(LoadBalancedCall);
-  auto* lb_call = static_cast<LoadBalancedCall*>(args.arena->Alloc(alloc_size));
-  new (lb_call) LoadBalancedCall(chand, args, pollent);
-  return lb_call;
-}
-
-ChannelData::LoadBalancedCall::LoadBalancedCall(
-    ChannelData* chand, const grpc_call_element_args& args,
-    grpc_polling_entity* pollent)
-    : refs_(1, GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)
-                   ? "LoadBalancedCall"
-                   : nullptr),
-      chand_(chand),
-      path_(grpc_slice_ref_internal(args.path)),
-      call_start_time_(args.start_time),
-      deadline_(args.deadline),
-      arena_(args.arena),
-      owning_call_(args.call_stack),
-      call_combiner_(args.call_combiner),
-      call_context_(args.context),
-      pollent_(pollent) {}
-
-ChannelData::LoadBalancedCall::~LoadBalancedCall() {
-  grpc_slice_unref_internal(path_);
-  GRPC_ERROR_UNREF(cancel_error_);
-  if (backend_metric_data_ != nullptr) {
-    backend_metric_data_
-        ->LoadBalancingPolicy::BackendMetricData::~BackendMetricData();
-  }
-  // Make sure there are no remaining pending batches.
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    GPR_ASSERT(pending_batches_[i] == nullptr);
-  }
-}
-
-RefCountedPtr<ChannelData::LoadBalancedCall>
-ChannelData::LoadBalancedCall::Ref() {
-  IncrementRefCount();
-  return RefCountedPtr<LoadBalancedCall>(this);
-}
-
-RefCountedPtr<ChannelData::LoadBalancedCall> ChannelData::LoadBalancedCall::Ref(
-    const DebugLocation& location, const char* reason) {
-  IncrementRefCount(location, reason);
-  return RefCountedPtr<LoadBalancedCall>(this);
-}
-
-void ChannelData::LoadBalancedCall::Unref() {
-  if (GPR_UNLIKELY(refs_.Unref())) {
-    this->~LoadBalancedCall();
-  }
-}
-
-void ChannelData::LoadBalancedCall::Unref(const DebugLocation& location,
-                                          const char* reason) {
-  if (GPR_UNLIKELY(refs_.Unref(location, reason))) {
-    this->~LoadBalancedCall();
-  }
-}
-
-void ChannelData::LoadBalancedCall::IncrementRefCount() { refs_.Ref(); }
-
-void ChannelData::LoadBalancedCall::IncrementRefCount(
-    const DebugLocation& location, const char* reason) {
-  refs_.Ref(location, reason);
-}
-
-void* ChannelData::LoadBalancedCall::GetParentData() {
-  return reinterpret_cast<char*>(this) +
-         GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(LoadBalancedCall));
-}
-
-size_t ChannelData::LoadBalancedCall::GetBatchIndex(
-    grpc_transport_stream_op_batch* batch) {
-  // Note: It is important the send_initial_metadata be the first entry
-  // here, since the code in pick_subchannel_locked() assumes it will be.
-  if (batch->send_initial_metadata) return 0;
-  if (batch->send_message) return 1;
-  if (batch->send_trailing_metadata) return 2;
-  if (batch->recv_initial_metadata) return 3;
-  if (batch->recv_message) return 4;
-  if (batch->recv_trailing_metadata) return 5;
-  GPR_UNREACHABLE_CODE(return (size_t)-1);
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::LoadBalancedCall::PendingBatchesAdd(
-    grpc_transport_stream_op_batch* batch) {
-  const size_t idx = GetBatchIndex(batch);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p lb_call=%p: adding pending batch at index %" PRIuPTR,
-            chand_, this, idx);
-  }
-  GPR_ASSERT(pending_batches_[idx] == nullptr);
-  pending_batches_[idx] = batch;
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::LoadBalancedCall::FailPendingBatchInCallCombiner(
-    void* arg, grpc_error* error) {
-  grpc_transport_stream_op_batch* batch =
-      static_cast<grpc_transport_stream_op_batch*>(arg);
-  auto* self = static_cast<LoadBalancedCall*>(batch->handler_private.extra_arg);
-  // Note: This will release the call combiner.
-  grpc_transport_stream_op_batch_finish_with_failure(
-      batch, GRPC_ERROR_REF(error), self->call_combiner_);
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::LoadBalancedCall::PendingBatchesFail(
-    grpc_error* error,
-    YieldCallCombinerPredicate yield_call_combiner_predicate) {
-  GPR_ASSERT(error != GRPC_ERROR_NONE);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    size_t num_batches = 0;
-    for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-      if (pending_batches_[i] != nullptr) ++num_batches;
-    }
-    gpr_log(GPR_INFO,
-            "chand=%p lb_call=%p: failing %" PRIuPTR " pending batches: %s",
-            chand_, this, num_batches, grpc_error_string(error));
-  }
-  CallCombinerClosureList closures;
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    grpc_transport_stream_op_batch*& batch = pending_batches_[i];
-    if (batch != nullptr) {
-      batch->handler_private.extra_arg = this;
-      GRPC_CLOSURE_INIT(&batch->handler_private.closure,
-                        FailPendingBatchInCallCombiner, batch,
-                        grpc_schedule_on_exec_ctx);
-      closures.Add(&batch->handler_private.closure, GRPC_ERROR_REF(error),
-                   "PendingBatchesFail");
-      batch = nullptr;
-    }
-  }
-  if (yield_call_combiner_predicate(closures)) {
-    closures.RunClosures(call_combiner_);
-  } else {
-    closures.RunClosuresWithoutYielding(call_combiner_);
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::LoadBalancedCall::ResumePendingBatchInCallCombiner(
-    void* arg, grpc_error* /*ignored*/) {
-  grpc_transport_stream_op_batch* batch =
-      static_cast<grpc_transport_stream_op_batch*>(arg);
-  SubchannelCall* subchannel_call =
-      static_cast<SubchannelCall*>(batch->handler_private.extra_arg);
-  // Note: This will release the call combiner.
-  subchannel_call->StartTransportStreamOpBatch(batch);
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void ChannelData::LoadBalancedCall::PendingBatchesResume() {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    size_t num_batches = 0;
-    for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-      if (pending_batches_[i] != nullptr) ++num_batches;
-    }
-    gpr_log(GPR_INFO,
-            "chand=%p lb_call=%p: starting %" PRIuPTR
-            " pending batches on subchannel_call=%p",
-            chand_, this, num_batches, subchannel_call_.get());
-  }
-  CallCombinerClosureList closures;
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    grpc_transport_stream_op_batch*& batch = pending_batches_[i];
-    if (batch != nullptr) {
-      batch->handler_private.extra_arg = subchannel_call_.get();
-      GRPC_CLOSURE_INIT(&batch->handler_private.closure,
-                        ResumePendingBatchInCallCombiner, batch,
-                        grpc_schedule_on_exec_ctx);
-      closures.Add(&batch->handler_private.closure, GRPC_ERROR_NONE,
-                   "PendingBatchesResume");
-      batch = nullptr;
-    }
-  }
-  // Note: This will release the call combiner.
-  closures.RunClosures(call_combiner_);
-}
-
-void ChannelData::LoadBalancedCall::StartTransportStreamOpBatch(
-    grpc_transport_stream_op_batch* batch) {
-  // Intercept recv_trailing_metadata_ready for LB callback.
-  if (batch->recv_trailing_metadata) {
-    InjectRecvTrailingMetadataReadyForLoadBalancingPolicy(batch);
+void ClientChannel::LoadBalancedCall::StartTransportStreamOpBatch(
+    grpc_transport_stream_op_batch* batch) {
+  // Intercept recv_trailing_metadata_ready for LB callback.
+  if (batch->recv_trailing_metadata) {
+    InjectRecvTrailingMetadataReadyForLoadBalancingPolicy(batch);
   }
   // If we've previously been cancelled, immediately fail any new batches.
   if (GPR_UNLIKELY(cancel_error_ != GRPC_ERROR_NONE)) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p lb_call=%p: failing batch with error: %s",
-              chand_, this, grpc_error_string(cancel_error_));
+              chand_, this, grpc_error_std_string(cancel_error_).c_str());
     }
     // Note: This will release the call combiner.
     grpc_transport_stream_op_batch_finish_with_failure(
@@ -5131,7 +2706,7 @@ void ChannelData::LoadBalancedCall::StartTransportStreamOpBatch(
     cancel_error_ = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p lb_call=%p: recording cancel_error=%s",
-              chand_, this, grpc_error_string(cancel_error_));
+              chand_, this, grpc_error_std_string(cancel_error_).c_str());
     }
     // If we do not have a subchannel call (i.e., a pick has not yet
     // been started), fail all pending batches.  Otherwise, send the
@@ -5184,13 +2759,13 @@ void ChannelData::LoadBalancedCall::StartTransportStreamOpBatch(
   }
 }
 
-void ChannelData::LoadBalancedCall::
+void ClientChannel::LoadBalancedCall::
     RecvTrailingMetadataReadyForLoadBalancingPolicy(void* arg,
-                                                    grpc_error* error) {
+                                                    grpc_error_handle error) {
   auto* self = static_cast<LoadBalancedCall*>(arg);
   if (self->lb_recv_trailing_metadata_ready_ != nullptr) {
     // Set error if call did not succeed.
-    grpc_error* error_for_lb = GRPC_ERROR_NONE;
+    grpc_error_handle error_for_lb = GRPC_ERROR_NONE;
     if (error != GRPC_ERROR_NONE) {
       error_for_lb = error;
     } else {
@@ -5218,13 +2793,17 @@ void ChannelData::LoadBalancedCall::
     if (error == GRPC_ERROR_NONE) GRPC_ERROR_UNREF(error_for_lb);
   }
   // Chain to original callback.
+  if (self->failure_error_ != GRPC_ERROR_NONE) {
+    error = self->failure_error_;
+    self->failure_error_ = GRPC_ERROR_NONE;
+  } else {
+    error = GRPC_ERROR_REF(error);
+  }
   Closure::Run(DEBUG_LOCATION, self->original_recv_trailing_metadata_ready_,
-               GRPC_ERROR_REF(error));
+               error);
 }
 
-// TODO(roth): Consider not intercepting this callback unless we
-// actually need to, if this causes a performance problem.
-void ChannelData::LoadBalancedCall::
+void ClientChannel::LoadBalancedCall::
     InjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
         grpc_transport_stream_op_batch* batch) {
   recv_trailing_metadata_ =
@@ -5238,19 +2817,23 @@ void ChannelData::LoadBalancedCall::
       &recv_trailing_metadata_ready_;
 }
 
-void ChannelData::LoadBalancedCall::CreateSubchannelCall() {
+void ClientChannel::LoadBalancedCall::CreateSubchannelCall() {
   SubchannelCall::Args call_args = {
       std::move(connected_subchannel_), pollent_, path_, call_start_time_,
       deadline_, arena_,
       // TODO(roth): When we implement hedging support, we will probably
       // need to use a separate call context for each subchannel call.
       call_context_, call_combiner_};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   subchannel_call_ = SubchannelCall::Create(std::move(call_args), &error);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO,
             "chand=%p lb_call=%p: create subchannel_call=%p: error=%s", chand_,
-            this, subchannel_call_.get(), grpc_error_string(error));
+            this, subchannel_call_.get(), grpc_error_std_string(error).c_str());
+  }
+  if (on_call_destruction_complete_ != nullptr) {
+    subchannel_call_->SetAfterCallStackDestroy(on_call_destruction_complete_);
+    on_call_destruction_complete_ = nullptr;
   }
   if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
     PendingBatchesFail(error, YieldCallCombiner);
@@ -5266,7 +2849,7 @@ void ChannelData::LoadBalancedCall::CreateSubchannelCall() {
 // because there may be multiple LB picks happening in parallel.
 // Instead, we will probably need to maintain a list in the CallData
 // object of pending LB picks to be cancelled when the closure runs.
-class ChannelData::LoadBalancedCall::LbQueuedCallCanceller {
+class ClientChannel::LoadBalancedCall::LbQueuedCallCanceller {
  public:
   explicit LbQueuedCallCanceller(RefCountedPtr<LoadBalancedCall> lb_call)
       : lb_call_(std::move(lb_call)) {
@@ -5276,7 +2859,7 @@ class ChannelData::LoadBalancedCall::LbQueuedCallCanceller {
   }
 
  private:
-  static void CancelLocked(void* arg, grpc_error* error) {
+  static void CancelLocked(void* arg, grpc_error_handle error) {
     auto* self = static_cast<LbQueuedCallCanceller*>(arg);
     auto* lb_call = self->lb_call_.get();
     auto* chand = lb_call->chand_;
@@ -5286,7 +2869,7 @@ class ChannelData::LoadBalancedCall::LbQueuedCallCanceller {
         gpr_log(GPR_INFO,
                 "chand=%p lb_call=%p: cancelling queued pick: "
                 "error=%s self=%p calld->pick_canceller=%p",
-                chand, lb_call, grpc_error_string(error), self,
+                chand, lb_call, grpc_error_std_string(error).c_str(), self,
                 lb_call->lb_call_canceller_);
       }
       if (lb_call->lb_call_canceller_ == self && error != GRPC_ERROR_NONE) {
@@ -5305,7 +2888,7 @@ class ChannelData::LoadBalancedCall::LbQueuedCallCanceller {
   grpc_closure closure_;
 };
 
-void ChannelData::LoadBalancedCall::MaybeRemoveCallFromLbQueuedCallsLocked() {
+void ClientChannel::LoadBalancedCall::MaybeRemoveCallFromLbQueuedCallsLocked() {
   if (!queued_pending_lb_pick_) return;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p lb_call=%p: removing from queued picks list",
@@ -5317,7 +2900,7 @@ void ChannelData::LoadBalancedCall::MaybeRemoveCallFromLbQueuedCallsLocked() {
   lb_call_canceller_ = nullptr;
 }
 
-void ChannelData::LoadBalancedCall::MaybeAddCallToLbQueuedCallsLocked() {
+void ClientChannel::LoadBalancedCall::MaybeAddCallToLbQueuedCallsLocked() {
   if (queued_pending_lb_pick_) return;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p lb_call=%p: adding to queued picks list",
@@ -5330,18 +2913,19 @@ void ChannelData::LoadBalancedCall::MaybeAddCallToLbQueuedCallsLocked() {
   lb_call_canceller_ = new LbQueuedCallCanceller(Ref());
 }
 
-void ChannelData::LoadBalancedCall::AsyncPickDone(grpc_error* error) {
+void ClientChannel::LoadBalancedCall::AsyncPickDone(grpc_error_handle error) {
   GRPC_CLOSURE_INIT(&pick_closure_, PickDone, this, grpc_schedule_on_exec_ctx);
   ExecCtx::Run(DEBUG_LOCATION, &pick_closure_, error);
 }
 
-void ChannelData::LoadBalancedCall::PickDone(void* arg, grpc_error* error) {
+void ClientChannel::LoadBalancedCall::PickDone(void* arg,
+                                               grpc_error_handle error) {
   auto* self = static_cast<LoadBalancedCall*>(arg);
   if (error != GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO,
               "chand=%p lb_call=%p: failed to pick subchannel: error=%s",
-              self->chand_, self, grpc_error_string(error));
+              self->chand_, self, grpc_error_std_string(error).c_str());
     }
     self->PendingBatchesFail(GRPC_ERROR_REF(error), YieldCallCombiner);
     return;
@@ -5349,6 +2933,8 @@ void ChannelData::LoadBalancedCall::PickDone(void* arg, grpc_error* error) {
   self->CreateSubchannelCall();
 }
 
+namespace {
+
 const char* PickResultTypeName(
     LoadBalancingPolicy::PickResult::ResultType type) {
   switch (type) {
@@ -5362,8 +2948,10 @@ const char* PickResultTypeName(
   GPR_UNREACHABLE_CODE(return "UNKNOWN");
 }
 
-void ChannelData::LoadBalancedCall::PickSubchannel(void* arg,
-                                                   grpc_error* error) {
+}  // namespace
+
+void ClientChannel::LoadBalancedCall::PickSubchannel(void* arg,
+                                                     grpc_error_handle error) {
   auto* self = static_cast<LoadBalancedCall*>(arg);
   bool pick_complete;
   {
@@ -5376,7 +2964,8 @@ void ChannelData::LoadBalancedCall::PickSubchannel(void* arg,
   }
 }
 
-bool ChannelData::LoadBalancedCall::PickSubchannelLocked(grpc_error** error) {
+bool ClientChannel::LoadBalancedCall::PickSubchannelLocked(
+    grpc_error_handle* error) {
   GPR_ASSERT(connected_subchannel_ == nullptr);
   GPR_ASSERT(subchannel_call_ == nullptr);
   // Grab initial metadata.
@@ -5399,12 +2988,12 @@ bool ChannelData::LoadBalancedCall::PickSubchannelLocked(grpc_error** error) {
         GPR_INFO,
         "chand=%p lb_call=%p: LB pick returned %s (subchannel=%p, error=%s)",
         chand_, this, PickResultTypeName(result.type), result.subchannel.get(),
-        grpc_error_string(result.error));
+        grpc_error_std_string(result.error).c_str());
   }
   switch (result.type) {
     case LoadBalancingPolicy::PickResult::PICK_FAILED: {
       // If we're shutting down, fail all RPCs.
-      grpc_error* disconnect_error = chand_->disconnect_error();
+      grpc_error_handle disconnect_error = chand_->disconnect_error();
       if (disconnect_error != GRPC_ERROR_NONE) {
         GRPC_ERROR_UNREF(result.error);
         MaybeRemoveCallFromLbQueuedCallsLocked();
@@ -5415,7 +3004,7 @@ bool ChannelData::LoadBalancedCall::PickSubchannelLocked(grpc_error** error) {
       // attempt's final status.
       if ((send_initial_metadata_flags &
            GRPC_INITIAL_METADATA_WAIT_FOR_READY) == 0) {
-        grpc_error* new_error =
+        grpc_error_handle new_error =
             GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                 "Failed to pick subchannel", &result.error, 1);
         GRPC_ERROR_UNREF(result.error);
@@ -5436,9 +3025,11 @@ bool ChannelData::LoadBalancedCall::PickSubchannelLocked(grpc_error** error) {
       // Handle drops.
       if (GPR_UNLIKELY(result.subchannel == nullptr)) {
         result.error = grpc_error_set_int(
-            GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                "Call dropped by load balancing policy"),
-            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
+            grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                                   "Call dropped by load balancing policy"),
+                               GRPC_ERROR_INT_GRPC_STATUS,
+                               GRPC_STATUS_UNAVAILABLE),
+            GRPC_ERROR_INT_LB_POLICY_DROP, 1);
       } else {
         // Grab a ref to the connected subchannel while we're still
         // holding the data plane mutex.
@@ -5452,68 +3043,4 @@ bool ChannelData::LoadBalancedCall::PickSubchannelLocked(grpc_error** error) {
   }
 }
 
-}  // namespace
 }  // namespace grpc_core
-
-/*************************************************************************
- * EXPORTED SYMBOLS
- */
-
-using grpc_core::ChannelData;
-
-const grpc_channel_filter grpc_client_channel_filter = {
-    ChannelData::CallData::StartTransportStreamOpBatch,
-    ChannelData::StartTransportOp,
-    sizeof(ChannelData::CallData),
-    ChannelData::CallData::Init,
-    ChannelData::CallData::SetPollent,
-    ChannelData::CallData::Destroy,
-    sizeof(ChannelData),
-    ChannelData::Init,
-    ChannelData::Destroy,
-    ChannelData::GetChannelInfo,
-    "client-channel",
-};
-
-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);
-  return chand->CheckConnectivityState(try_to_connect);
-}
-
-int grpc_client_channel_num_external_connectivity_watchers(
-    grpc_channel_element* elem) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  return chand->NumExternalConnectivityWatchers();
-}
-
-void grpc_client_channel_watch_connectivity_state(
-    grpc_channel_element* elem, grpc_polling_entity pollent,
-    grpc_connectivity_state* state, grpc_closure* on_complete,
-    grpc_closure* watcher_timer_init) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  if (state == nullptr) {
-    // Handle cancellation.
-    GPR_ASSERT(watcher_timer_init == nullptr);
-    chand->RemoveExternalConnectivityWatcher(on_complete, /*cancel=*/true);
-    return;
-  }
-  // Handle addition.
-  return chand->AddExternalConnectivityWatcher(pollent, state, on_complete,
-                                               watcher_timer_init);
-}
-
-void grpc_client_channel_start_connectivity_watch(
-    grpc_channel_element* elem, grpc_connectivity_state initial_state,
-    grpc_core::OrphanablePtr<grpc_core::AsyncConnectivityStateWatcherInterface>
-        watcher) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  chand->AddConnectivityWatcher(initial_state, std::move(watcher));
-}
-
-void grpc_client_channel_stop_connectivity_watch(
-    grpc_channel_element* elem,
-    grpc_core::AsyncConnectivityStateWatcherInterface* watcher) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  chand->RemoveConnectivityWatcher(watcher);
-}
index af011ca..b7dd1a1 100644 (file)
-/*
- *
- * 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.
- *
- */
+//
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "absl/status/status.h"
+#include "absl/types/optional.h"
+
+#include <grpc/support/log.h>
+
 #include "src/core/ext/filters/client_channel/client_channel_factory.h"
+#include "src/core/ext/filters/client_channel/config_selector.h"
+#include "src/core/ext/filters/client_channel/dynamic_filters.h"
+#include "src/core/ext/filters/client_channel/lb_policy.h"
 #include "src/core/ext/filters/client_channel/resolver.h"
-#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/service_config.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
+#include "src/core/lib/gprpp/sync.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/polling_entity.h"
+#include "src/core/lib/iomgr/work_serializer.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/connectivity_state.h"
+
+//
+// Client channel filter
+//
+
+// A client channel is a channel that begins disconnected, and can connect
+// to some endpoint on demand. If that endpoint disconnects, it will be
+// connected to again later.
+//
+// Calls on a disconnected client channel are queued until a connection is
+// established.
 
 // Channel arg key for server URI string.
 #define GRPC_ARG_SERVER_URI "grpc.server_uri"
 
-/* A client channel is a channel that begins disconnected, and can connect
-   to some endpoint on demand. If that endpoint disconnects, it will be
-   connected to again later.
+// Channel arg containing a pointer to the ClientChannel object.
+#define GRPC_ARG_CLIENT_CHANNEL "grpc.internal.client_channel"
+
+// Channel arg containing a pointer to the ServiceConfig object.
+#define GRPC_ARG_SERVICE_CONFIG_OBJ "grpc.internal.service_config_obj"
+
+// Max number of batches that can be pending on a call at any given
+// time.  This includes one batch for each of the following ops:
+//   recv_initial_metadata
+//   send_initial_metadata
+//   recv_message
+//   send_message
+//   recv_trailing_metadata
+//   send_trailing_metadata
+#define MAX_PENDING_BATCHES 6
+
+namespace grpc_core {
+
+class ClientChannel {
+ public:
+  static const grpc_channel_filter kFilterVtable;
+
+  class LoadBalancedCall;
+
+  // Returns the ClientChannel object from channel, or null if channel
+  // is not a client channel.
+  static ClientChannel* GetFromChannel(grpc_channel* channel);
+
+  grpc_connectivity_state CheckConnectivityState(bool try_to_connect);
+
+  // Starts a one-time connectivity state watch.  When the channel's state
+  // becomes different from *state, sets *state to the new state and
+  // schedules on_complete.  The watcher_timer_init callback is invoked as
+  // soon as the watch is actually started (i.e., after hopping into the
+  // client channel combiner).  I/O will be serviced via pollent.
+  //
+  // This is intended to be used when starting a watch from outside of C-core
+  // via grpc_channel_watch_connectivity_state().  It should not be used
+  // by other callers.
+  void AddExternalConnectivityWatcher(grpc_polling_entity pollent,
+                                      grpc_connectivity_state* state,
+                                      grpc_closure* on_complete,
+                                      grpc_closure* watcher_timer_init) {
+    new ExternalConnectivityWatcher(this, pollent, state, on_complete,
+                                    watcher_timer_init);
+  }
+
+  // Cancels a pending external watcher previously added by
+  // AddExternalConnectivityWatcher().
+  void CancelExternalConnectivityWatcher(grpc_closure* on_complete) {
+    ExternalConnectivityWatcher::RemoveWatcherFromExternalWatchersMap(
+        this, on_complete, /*cancel=*/true);
+  }
+
+  int NumExternalConnectivityWatchers() const {
+    MutexLock lock(&external_watchers_mu_);
+    return static_cast<int>(external_watchers_.size());
+  }
+
+  // Starts and stops a connectivity watch.  The watcher will be initially
+  // notified as soon as the state changes from initial_state and then on
+  // every subsequent state change until either the watch is stopped or
+  // it is notified that the state has changed to SHUTDOWN.
+  //
+  // This is intended to be used when starting watches from code inside of
+  // C-core (e.g., for a nested control plane channel for things like xds).
+  void AddConnectivityWatcher(
+      grpc_connectivity_state initial_state,
+      OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher);
+  void RemoveConnectivityWatcher(
+      AsyncConnectivityStateWatcherInterface* watcher);
+
+  RefCountedPtr<LoadBalancedCall> CreateLoadBalancedCall(
+      const grpc_call_element_args& args, grpc_polling_entity* pollent,
+      grpc_closure* on_call_destruction_complete);
+
+ private:
+  class CallData;
+  class ResolverResultHandler;
+  class SubchannelWrapper;
+  class ClientChannelControlHelper;
+  class ConnectivityWatcherAdder;
+  class ConnectivityWatcherRemover;
+
+  // Represents a pending connectivity callback from an external caller
+  // via grpc_client_channel_watch_connectivity_state().
+  class ExternalConnectivityWatcher : public ConnectivityStateWatcherInterface {
+   public:
+    ExternalConnectivityWatcher(ClientChannel* chand,
+                                grpc_polling_entity pollent,
+                                grpc_connectivity_state* state,
+                                grpc_closure* on_complete,
+                                grpc_closure* watcher_timer_init);
+
+    ~ExternalConnectivityWatcher() override;
+
+    // Removes the watcher from the external_watchers_ map.
+    static void RemoveWatcherFromExternalWatchersMap(ClientChannel* chand,
+                                                     grpc_closure* on_complete,
+                                                     bool cancel);
+
+    void Notify(grpc_connectivity_state state,
+                const absl::Status& /* status */) override;
+
+    void Cancel();
+
+   private:
+    // Adds the watcher to state_tracker_. Consumes the ref that is passed to it
+    // from Start().
+    void AddWatcherLocked()
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_);
+    void RemoveWatcherLocked()
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_);
+
+    ClientChannel* chand_;
+    grpc_polling_entity pollent_;
+    grpc_connectivity_state initial_state_;
+    grpc_connectivity_state* state_;
+    grpc_closure* on_complete_;
+    grpc_closure* watcher_timer_init_;
+    Atomic<bool> done_{false};
+  };
+
+  struct ResolverQueuedCall {
+    grpc_call_element* elem;
+    ResolverQueuedCall* next = nullptr;
+  };
+  struct LbQueuedCall {
+    LoadBalancedCall* lb_call;
+    LbQueuedCall* next = nullptr;
+  };
+
+  ClientChannel(grpc_channel_element_args* args, grpc_error_handle* error);
+  ~ClientChannel();
+
+  // Filter vtable functions.
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args);
+  static void Destroy(grpc_channel_element* elem);
+  static void StartTransportOp(grpc_channel_element* elem,
+                               grpc_transport_op* op);
+  static void GetChannelInfo(grpc_channel_element* elem,
+                             const grpc_channel_info* info);
 
-   Calls on a disconnected client channel are queued until a connection is
-   established. */
+  // Note: Does NOT return a new ref.
+  grpc_error_handle disconnect_error() const {
+    return disconnect_error_.Load(MemoryOrder::ACQUIRE);
+  }
 
-extern const grpc_channel_filter grpc_client_channel_filter;
+  // Note: All methods with "Locked" suffix must be invoked from within
+  // work_serializer_.
 
-grpc_connectivity_state grpc_client_channel_check_connectivity_state(
-    grpc_channel_element* elem, int try_to_connect);
+  void OnResolverResultChangedLocked(Resolver::Result result)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+  void OnResolverErrorLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
 
-int grpc_client_channel_num_external_connectivity_watchers(
-    grpc_channel_element* elem);
+  void CreateOrUpdateLbPolicyLocked(
+      RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
+      Resolver::Result result) ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+  OrphanablePtr<LoadBalancingPolicy> CreateLbPolicyLocked(
+      const grpc_channel_args& args)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void UpdateStateAndPickerLocked(
+      grpc_connectivity_state state, const absl::Status& status,
+      const char* reason,
+      std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void UpdateServiceConfigInControlPlaneLocked(
+      RefCountedPtr<ServiceConfig> service_config,
+      RefCountedPtr<ConfigSelector> config_selector,
+      const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
+      const char* lb_policy_name)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void UpdateServiceConfigInDataPlaneLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void CreateResolverLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+  void DestroyResolverAndLbPolicyLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  grpc_error_handle DoPingLocked(grpc_transport_op* op)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void StartTransportOpLocked(grpc_transport_op* op)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void TryToConnectLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  // These methods all require holding resolution_mu_.
+  void AddResolverQueuedCall(ResolverQueuedCall* call,
+                             grpc_polling_entity* pollent)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(resolution_mu_);
+  void RemoveResolverQueuedCall(ResolverQueuedCall* to_remove,
+                                grpc_polling_entity* pollent)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(resolution_mu_);
+
+  // These methods all require holding data_plane_mu_.
+  void AddLbQueuedCall(LbQueuedCall* call, grpc_polling_entity* pollent)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(data_plane_mu_);
+  void RemoveLbQueuedCall(LbQueuedCall* to_remove, grpc_polling_entity* pollent)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(data_plane_mu_);
+  RefCountedPtr<ConnectedSubchannel> GetConnectedSubchannelInDataPlane(
+      SubchannelInterface* subchannel) const
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(data_plane_mu_);
+
+  //
+  // Fields set at construction and never modified.
+  //
+  const bool deadline_checking_enabled_;
+  const bool enable_retries_;
+  grpc_channel_stack* owning_stack_;
+  ClientChannelFactory* client_channel_factory_;
+  const grpc_channel_args* channel_args_;
+  RefCountedPtr<ServiceConfig> default_service_config_;
+  std::string server_name_;
+  UniquePtr<char> target_uri_;
+  channelz::ChannelNode* channelz_node_;
+  grpc_pollset_set* interested_parties_;
+
+  //
+  // Fields related to name resolution.  Guarded by resolution_mu_.
+  //
+  mutable Mutex resolution_mu_;
+  // Linked list of calls queued waiting for resolver result.
+  ResolverQueuedCall* resolver_queued_calls_ ABSL_GUARDED_BY(resolution_mu_) =
+      nullptr;
+  // Data from service config.
+  grpc_error_handle resolver_transient_failure_error_
+      ABSL_GUARDED_BY(resolution_mu_) = GRPC_ERROR_NONE;
+  bool received_service_config_data_ ABSL_GUARDED_BY(resolution_mu_) = false;
+  RefCountedPtr<ServiceConfig> service_config_ ABSL_GUARDED_BY(resolution_mu_);
+  RefCountedPtr<ConfigSelector> config_selector_
+      ABSL_GUARDED_BY(resolution_mu_);
+  RefCountedPtr<DynamicFilters> dynamic_filters_
+      ABSL_GUARDED_BY(resolution_mu_);
+
+  //
+  // Fields used in the data plane.  Guarded by data_plane_mu_.
+  //
+  mutable Mutex data_plane_mu_;
+  std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker_
+      ABSL_GUARDED_BY(data_plane_mu_);
+  // Linked list of calls queued waiting for LB pick.
+  LbQueuedCall* lb_queued_calls_ ABSL_GUARDED_BY(data_plane_mu_) = nullptr;
+
+  //
+  // Fields used in the control plane.  Guarded by work_serializer.
+  //
+  std::shared_ptr<WorkSerializer> work_serializer_;
+  ConnectivityStateTracker state_tracker_ ABSL_GUARDED_BY(work_serializer_);
+  OrphanablePtr<Resolver> resolver_ ABSL_GUARDED_BY(work_serializer_);
+  bool previous_resolution_contained_addresses_
+      ABSL_GUARDED_BY(work_serializer_) = false;
+  RefCountedPtr<ServiceConfig> saved_service_config_
+      ABSL_GUARDED_BY(work_serializer_);
+  RefCountedPtr<ConfigSelector> saved_config_selector_
+      ABSL_GUARDED_BY(work_serializer_);
+  absl::optional<std::string> health_check_service_name_
+      ABSL_GUARDED_BY(work_serializer_);
+  OrphanablePtr<LoadBalancingPolicy> lb_policy_
+      ABSL_GUARDED_BY(work_serializer_);
+  RefCountedPtr<SubchannelPoolInterface> subchannel_pool_
+      ABSL_GUARDED_BY(work_serializer_);
+  // The number of SubchannelWrapper instances referencing a given Subchannel.
+  std::map<Subchannel*, int> subchannel_refcount_map_
+      ABSL_GUARDED_BY(work_serializer_);
+  // The set of SubchannelWrappers that currently exist.
+  // No need to hold a ref, since the map is updated in the control-plane
+  // work_serializer when the SubchannelWrappers are created and destroyed.
+  std::set<SubchannelWrapper*> subchannel_wrappers_
+      ABSL_GUARDED_BY(work_serializer_);
+  // Pending ConnectedSubchannel updates for each SubchannelWrapper.
+  // Updates are queued here in the control plane work_serializer and then
+  // applied in the data plane mutex when the picker is updated.
+  std::map<RefCountedPtr<SubchannelWrapper>, RefCountedPtr<ConnectedSubchannel>>
+      pending_subchannel_updates_ ABSL_GUARDED_BY(work_serializer_);
+  int keepalive_time_ ABSL_GUARDED_BY(work_serializer_) = -1;
+
+  //
+  // Fields accessed from both data plane mutex and control plane
+  // work_serializer.
+  //
+  Atomic<grpc_error_handle> disconnect_error_;
+
+  //
+  // Fields guarded by a mutex, since they need to be accessed
+  // synchronously via get_channel_info().
+  //
+  Mutex info_mu_;
+  UniquePtr<char> info_lb_policy_name_ ABSL_GUARDED_BY(info_mu_);
+  UniquePtr<char> info_service_config_json_ ABSL_GUARDED_BY(info_mu_);
+
+  //
+  // Fields guarded by a mutex, since they need to be accessed
+  // synchronously via grpc_channel_num_external_connectivity_watchers().
+  //
+  mutable Mutex external_watchers_mu_;
+  std::map<grpc_closure*, RefCountedPtr<ExternalConnectivityWatcher>>
+      external_watchers_ ABSL_GUARDED_BY(external_watchers_mu_);
+};
 
-// Starts a one-time connectivity state watch.  When the channel's state
-// becomes different from *state, sets *state to the new state and
-// schedules on_complete.  The watcher_timer_init callback is invoked as
-// soon as the watch is actually started (i.e., after hopping into the
-// client channel combiner).  I/O will be serviced via pollent.
 //
-// This is intended to be used when starting a watch from outside of C-core
-// via grpc_channel_watch_connectivity_state().  It should not be used
-// by other callers.
-void grpc_client_channel_watch_connectivity_state(
-    grpc_channel_element* elem, grpc_polling_entity pollent,
-    grpc_connectivity_state* state, grpc_closure* on_complete,
-    grpc_closure* watcher_timer_init);
-
-// Starts and stops a connectivity watch.  The watcher will be initially
-// notified as soon as the state changes from initial_state and then on
-// every subsequent state change until either the watch is stopped or
-// it is notified that the state has changed to SHUTDOWN.
+// ClientChannel::LoadBalancedCall
 //
-// This is intended to be used when starting watches from code inside of
-// C-core (e.g., for a nested control plane channel for things like xds).
-void grpc_client_channel_start_connectivity_watch(
-    grpc_channel_element* elem, grpc_connectivity_state initial_state,
-    grpc_core::OrphanablePtr<grpc_core::AsyncConnectivityStateWatcherInterface>
-        watcher);
-void grpc_client_channel_stop_connectivity_watch(
-    grpc_channel_element* elem,
-    grpc_core::AsyncConnectivityStateWatcherInterface* watcher);
+
+// This object is ref-counted, but it cannot inherit from RefCounted<>,
+// because it is allocated on the arena and can't free its memory when
+// its refcount goes to zero.  So instead, it manually implements the
+// same API as RefCounted<>, so that it can be used with RefCountedPtr<>.
+class ClientChannel::LoadBalancedCall
+    : public RefCounted<LoadBalancedCall, PolymorphicRefCount, kUnrefCallDtor> {
+ public:
+  // If on_call_destruction_complete is non-null, then it will be
+  // invoked once the LoadBalancedCall is completely destroyed.
+  // If it is null, then the caller is responsible for checking whether
+  // the LB call has a subchannel call and ensuring that the
+  // on_call_destruction_complete closure passed down from the surface
+  // is not invoked until after the subchannel call stack is destroyed.
+  LoadBalancedCall(ClientChannel* chand, const grpc_call_element_args& args,
+                   grpc_polling_entity* pollent,
+                   grpc_closure* on_call_destruction_complete);
+  ~LoadBalancedCall() override;
+
+  void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
+
+  // Invoked by channel for queued LB picks when the picker is updated.
+  static void PickSubchannel(void* arg, grpc_error_handle error);
+  // Helper function for performing an LB pick while holding the data plane
+  // mutex.  Returns true if the pick is complete, in which case the caller
+  // must invoke PickDone() or AsyncPickDone() with the returned error.
+  bool PickSubchannelLocked(grpc_error_handle* error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_);
+  // Schedules a callback to process the completed pick.  The callback
+  // will not run until after this method returns.
+  void AsyncPickDone(grpc_error_handle error);
+
+  RefCountedPtr<SubchannelCall> subchannel_call() const {
+    return subchannel_call_;
+  }
+
+ private:
+  class LbQueuedCallCanceller;
+  class Metadata;
+  class LbCallState;
+
+  // Returns the index into pending_batches_ to be used for batch.
+  static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
+  void PendingBatchesAdd(grpc_transport_stream_op_batch* batch);
+  static void FailPendingBatchInCallCombiner(void* arg,
+                                             grpc_error_handle error);
+  // A predicate type and some useful implementations for PendingBatchesFail().
+  typedef bool (*YieldCallCombinerPredicate)(
+      const CallCombinerClosureList& closures);
+  static bool YieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
+    return true;
+  }
+  static bool NoYieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
+    return false;
+  }
+  static bool YieldCallCombinerIfPendingBatchesFound(
+      const CallCombinerClosureList& closures) {
+    return closures.size() > 0;
+  }
+  // Fails all pending batches.
+  // If yield_call_combiner_predicate returns true, assumes responsibility for
+  // yielding the call combiner.
+  void PendingBatchesFail(
+      grpc_error_handle error,
+      YieldCallCombinerPredicate yield_call_combiner_predicate);
+  static void ResumePendingBatchInCallCombiner(void* arg,
+                                               grpc_error_handle ignored);
+  // Resumes all pending batches on subchannel_call_.
+  void PendingBatchesResume();
+
+  static void RecvTrailingMetadataReadyForLoadBalancingPolicy(
+      void* arg, grpc_error_handle error);
+  void InjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
+      grpc_transport_stream_op_batch* batch);
+
+  void CreateSubchannelCall();
+  // Invoked when a pick is completed, on both success or failure.
+  static void PickDone(void* arg, grpc_error_handle error);
+  // Removes the call from the channel's list of queued picks if present.
+  void MaybeRemoveCallFromLbQueuedCallsLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_);
+  // Adds the call to the channel's list of queued picks if not already present.
+  void MaybeAddCallToLbQueuedCallsLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_);
+
+  ClientChannel* chand_;
+
+  // TODO(roth): Instead of duplicating these fields in every filter
+  // that uses any one of them, we should store them in the call
+  // context.  This will save per-call memory overhead.
+  grpc_slice path_;  // Request path.
+  gpr_cycle_counter call_start_time_;
+  grpc_millis deadline_;
+  Arena* arena_;
+  grpc_call_stack* owning_call_;
+  CallCombiner* call_combiner_;
+  grpc_call_context_element* call_context_;
+  grpc_polling_entity* pollent_;
+  grpc_closure* on_call_destruction_complete_;
+
+  // Set when we get a cancel_stream op.
+  grpc_error_handle cancel_error_ = GRPC_ERROR_NONE;
+
+  // Set when we fail inside the LB call.
+  grpc_error_handle failure_error_ = GRPC_ERROR_NONE;
+
+  grpc_closure pick_closure_;
+
+  // Accessed while holding ClientChannel::data_plane_mu_.
+  ClientChannel::LbQueuedCall queued_call_
+      ABSL_GUARDED_BY(&ClientChannel::data_plane_mu_);
+  bool queued_pending_lb_pick_ ABSL_GUARDED_BY(&ClientChannel::data_plane_mu_) =
+      false;
+  LbQueuedCallCanceller* lb_call_canceller_
+      ABSL_GUARDED_BY(&ClientChannel::data_plane_mu_) = nullptr;
+
+  RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
+  const LoadBalancingPolicy::BackendMetricData* backend_metric_data_ = nullptr;
+  std::function<void(grpc_error_handle, LoadBalancingPolicy::MetadataInterface*,
+                     LoadBalancingPolicy::CallState*)>
+      lb_recv_trailing_metadata_ready_;
+
+  RefCountedPtr<SubchannelCall> subchannel_call_;
+
+  // 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;
+
+  // Batches are added to this list when received from above.
+  // They are removed when we are done handling the batch (i.e., when
+  // either we have invoked all of the batch's callbacks or we have
+  // passed the batch down to the subchannel call and are not
+  // intercepting any of its callbacks).
+  grpc_transport_stream_op_batch* pending_batches_[MAX_PENDING_BATCHES] = {};
+};
+
+}  // namespace grpc_core
 
 #endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H
index 1a35abe..a106897 100644 (file)
@@ -63,7 +63,7 @@ class SubchannelNode : public BaseNode {
  private:
   Atomic<grpc_connectivity_state> connectivity_state_{GRPC_CHANNEL_IDLE};
   Mutex socket_mu_;
-  RefCountedPtr<SocketNode> child_socket_;
+  RefCountedPtr<SocketNode> child_socket_ ABSL_GUARDED_BY(socket_mu_);
   std::string target_;
   CallCountingHelper call_counter_;
   ChannelTrace trace_;
index 5690545..1d33d25 100644 (file)
@@ -34,6 +34,7 @@
 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
+#include "src/core/ext/filters/client_channel/retry_service_config.h"
 #include "src/core/ext/filters/client_channel/retry_throttle.h"
 #include "src/core/ext/filters/client_channel/service_config_parser.h"
 #include "src/core/lib/surface/channel_init.h"
@@ -46,6 +47,7 @@ static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
 void grpc_client_channel_init(void) {
   grpc_core::ServiceConfigParser::Init();
   grpc_core::internal::ClientChannelServiceConfigParser::Register();
+  grpc_core::internal::RetryServiceConfigParser::Register();
   grpc_core::LoadBalancingPolicyRegistry::Builder::InitRegistry();
   grpc_core::ResolverRegistry::Builder::InitRegistry();
   grpc_core::internal::ServerRetryThrottleMap::Init();
@@ -54,7 +56,8 @@ void grpc_client_channel_init(void) {
   grpc_core::GlobalSubchannelPool::Init();
   grpc_channel_init_register_stage(
       GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, append_filter,
-      const_cast<grpc_channel_filter*>(&grpc_client_channel_filter));
+      const_cast<grpc_channel_filter*>(
+          &grpc_core::ClientChannel::kFilterVtable));
   grpc_http_connect_register_handshaker_factory();
   grpc_client_channel_global_init_backup_polling();
 }
index 61916d2..98ae07e 100644 (file)
@@ -52,7 +52,7 @@ class ConfigSelector : public RefCounted<ConfigSelector> {
 
   struct CallConfig {
     // Can be set to indicate the call should be failed.
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     // The per-method parsed configs that will be passed to
     // ServiceConfigCallData.
     const ServiceConfigParser::ParsedConfigVector* method_configs = nullptr;
index 2564714..20e25b5 100644 (file)
@@ -66,7 +66,7 @@ class SubchannelConnector : public InternallyRefCounted<SubchannelConnector> {
 
   // Cancels any in-flight connection attempt and shuts down the
   // connector.
-  virtual void Shutdown(grpc_error* error) = 0;
+  virtual void Shutdown(grpc_error_handle error) = 0;
 
   void Orphan() override {
     Shutdown(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Subchannel disconnected"));
index 1286fce..47c05a3 100644 (file)
@@ -37,7 +37,7 @@ namespace grpc_core {
 // DynamicFilters::Call
 //
 
-DynamicFilters::Call::Call(Args args, grpc_error** error)
+DynamicFilters::Call::Call(Args args, grpc_error_handle* error)
     : channel_stack_(std::move(args.channel_stack)) {
   grpc_call_stack* call_stack = CALL_TO_CALL_STACK(this);
   const grpc_call_element_args call_args = {
@@ -53,8 +53,7 @@ DynamicFilters::Call::Call(Args args, grpc_error** error)
   *error = grpc_call_stack_init(channel_stack_->channel_stack_, 1, Destroy,
                                 this, &call_args);
   if (GPR_UNLIKELY(*error != GRPC_ERROR_NONE)) {
-    const char* error_string = grpc_error_string(*error);
-    gpr_log(GPR_ERROR, "error: %s", error_string);
+    gpr_log(GPR_ERROR, "error: %s", grpc_error_std_string(*error).c_str());
     return;
   }
   grpc_call_stack_set_pollset_or_pollset_set(call_stack, args.pollent);
@@ -94,7 +93,7 @@ void DynamicFilters::Call::Unref(const DebugLocation& /*location*/,
   GRPC_CALL_STACK_UNREF(CALL_TO_CALL_STACK(this), reason);
 }
 
-void DynamicFilters::Call::Destroy(void* arg, grpc_error* /*error*/) {
+void DynamicFilters::Call::Destroy(void* arg, grpc_error_handle /*error*/) {
   DynamicFilters::Call* self = static_cast<DynamicFilters::Call*>(arg);
   // Keep some members before destroying the subchannel call.
   grpc_closure* after_call_stack_destroy = self->after_call_stack_destroy_;
@@ -124,13 +123,13 @@ void DynamicFilters::Call::IncrementRefCount(
 
 namespace {
 
-void DestroyChannelStack(void* arg, grpc_error* /*error*/) {
+void DestroyChannelStack(void* arg, grpc_error_handle /*error*/) {
   grpc_channel_stack* channel_stack = static_cast<grpc_channel_stack*>(arg);
   grpc_channel_stack_destroy(channel_stack);
   gpr_free(channel_stack);
 }
 
-std::pair<grpc_channel_stack*, grpc_error*> CreateChannelStack(
+std::pair<grpc_channel_stack*, grpc_error_handle> CreateChannelStack(
     const grpc_channel_args* args,
     std::vector<const grpc_channel_filter*> filters) {
   // Allocate memory for channel stack.
@@ -139,13 +138,13 @@ std::pair<grpc_channel_stack*, grpc_error*> CreateChannelStack(
   grpc_channel_stack* channel_stack =
       reinterpret_cast<grpc_channel_stack*>(gpr_zalloc(channel_stack_size));
   // Initialize stack.
-  grpc_error* error = grpc_channel_stack_init(
+  grpc_error_handle error = grpc_channel_stack_init(
       /*initial_refs=*/1, DestroyChannelStack, channel_stack, filters.data(),
       filters.size(), args, /*optional_transport=*/nullptr, "DynamicFilters",
       channel_stack);
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "error initializing client internal stack: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     grpc_channel_stack_destroy(channel_stack);
     gpr_free(channel_stack);
     return {nullptr, error};
@@ -163,7 +162,7 @@ RefCountedPtr<DynamicFilters> DynamicFilters::Create(
   if (p.second != GRPC_ERROR_NONE) {
     // Channel stack creation failed with requested filters.
     // Create with lame filter instead.
-    grpc_error* error = p.second;
+    grpc_error_handle error = p.second;
     grpc_arg error_arg = MakeLameClientErrorArg(error);
     grpc_channel_args* new_args =
         grpc_channel_args_copy_and_add(args, &error_arg, 1);
@@ -180,7 +179,7 @@ DynamicFilters::~DynamicFilters() {
 }
 
 RefCountedPtr<DynamicFilters::Call> DynamicFilters::CreateCall(
-    DynamicFilters::Call::Args args, grpc_error** error) {
+    DynamicFilters::Call::Args args, grpc_error_handle* error) {
   size_t allocation_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Call)) +
                            channel_stack_->call_stack_size;
   Call* call = static_cast<Call*>(args.arena->Alloc(allocation_size));
index bcdc6d3..08a7f49 100644 (file)
@@ -46,7 +46,7 @@ class DynamicFilters : public RefCounted<DynamicFilters> {
       CallCombiner* call_combiner;
     };
 
-    Call(Args args, grpc_error** error);
+    Call(Args args, grpc_error_handle* error);
 
     // Continues processing a transport stream op batch.
     void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
@@ -73,7 +73,7 @@ class DynamicFilters : public RefCounted<DynamicFilters> {
     void IncrementRefCount();
     void IncrementRefCount(const DebugLocation& location, const char* reason);
 
-    static void Destroy(void* arg, grpc_error* error);
+    static void Destroy(void* arg, grpc_error_handle error);
 
     RefCountedPtr<DynamicFilters> channel_stack_;
     grpc_closure* after_call_stack_destroy_ = nullptr;
@@ -88,7 +88,7 @@ class DynamicFilters : public RefCounted<DynamicFilters> {
 
   ~DynamicFilters() override;
 
-  RefCountedPtr<Call> CreateCall(Call::Args args, grpc_error** error);
+  RefCountedPtr<Call> CreateCall(Call::Args args, grpc_error_handle* error);
 
  private:
   grpc_channel_stack* channel_stack_;
index 7885fad..adde23d 100644 (file)
@@ -157,7 +157,7 @@ void HealthCheckClient::StartRetryTimerLocked() {
   grpc_timer_init(&retry_timer_, next_try, &retry_timer_callback_);
 }
 
-void HealthCheckClient::OnRetryTimer(void* arg, grpc_error* error) {
+void HealthCheckClient::OnRetryTimer(void* arg, grpc_error_handle error) {
   HealthCheckClient* self = static_cast<HealthCheckClient*>(arg);
   {
     MutexLock lock(&self->mu_);
@@ -202,7 +202,7 @@ void EncodeRequest(const std::string& service_name,
 
 // Returns true if healthy.
 // If there was an error parsing the response, sets *error and returns false.
-bool DecodeResponse(grpc_slice_buffer* slice_buffer, grpc_error** error) {
+bool DecodeResponse(grpc_slice_buffer* slice_buffer, grpc_error_handle* error) {
   // If message is empty, assume unhealthy.
   if (slice_buffer->length == 0) {
     *error =
@@ -269,11 +269,8 @@ HealthCheckClient::CallState::~CallState() {
   // Unset the call combiner cancellation closure.  This has the
   // effect of scheduling the previously set cancellation closure, if
   // any, so that it can release any internal references it may be
-  // holding to the call stack. Also flush the closures on exec_ctx so that
-  // filters that schedule cancel notification closures on exec_ctx do not
-  // need to take a ref of the call stack to guarantee closure liveness.
+  // holding to the call stack.
   call_combiner_.SetNotifyOnCancel(nullptr);
-  ExecCtx::Get()->Flush();
   arena_->Destroy();
 }
 
@@ -293,7 +290,7 @@ void HealthCheckClient::CallState::StartCall() {
       context_,
       &call_combiner_,
   };
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   call_ = SubchannelCall::Create(std::move(args), &error).release();
   // Register after-destruction callback.
   GRPC_CLOSURE_INIT(&after_call_stack_destruction_, AfterCallStackDestruction,
@@ -304,7 +301,8 @@ void HealthCheckClient::CallState::StartCall() {
     gpr_log(GPR_ERROR,
             "HealthCheckClient %p CallState %p: error creating health "
             "checking call on subchannel (%s); will retry",
-            health_check_client_.get(), this, grpc_error_string(error));
+            health_check_client_.get(), this,
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     CallEndedLocked(/*retry=*/true);
     return;
@@ -381,7 +379,7 @@ void HealthCheckClient::CallState::StartCall() {
 }
 
 void HealthCheckClient::CallState::StartBatchInCallCombiner(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   SubchannelCall* call =
@@ -399,14 +397,14 @@ void HealthCheckClient::CallState::StartBatch(
 }
 
 void HealthCheckClient::CallState::AfterCallStackDestruction(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   delete self;
 }
 
-void HealthCheckClient::CallState::OnCancelComplete(void* arg,
-                                                    grpc_error* /*error*/) {
+void HealthCheckClient::CallState::OnCancelComplete(
+    void* arg, grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "health_cancel");
@@ -414,7 +412,7 @@ void HealthCheckClient::CallState::OnCancelComplete(void* arg,
 }
 
 void HealthCheckClient::CallState::StartCancel(void* arg,
-                                               grpc_error* /*error*/) {
+                                               grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   auto* batch = grpc_make_transport_stream_op(
@@ -437,7 +435,7 @@ void HealthCheckClient::CallState::Cancel() {
 }
 
 void HealthCheckClient::CallState::OnComplete(void* arg,
-                                              grpc_error* /*error*/) {
+                                              grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "on_complete");
@@ -447,7 +445,7 @@ void HealthCheckClient::CallState::OnComplete(void* arg,
 }
 
 void HealthCheckClient::CallState::RecvInitialMetadataReady(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "recv_initial_metadata_ready");
@@ -455,7 +453,8 @@ void HealthCheckClient::CallState::RecvInitialMetadataReady(
   self->call_->Unref(DEBUG_LOCATION, "recv_initial_metadata_ready");
 }
 
-void HealthCheckClient::CallState::DoneReadingRecvMessage(grpc_error* error) {
+void HealthCheckClient::CallState::DoneReadingRecvMessage(
+    grpc_error_handle error) {
   recv_message_.reset();
   if (error != GRPC_ERROR_NONE) {
     GRPC_ERROR_UNREF(error);
@@ -467,10 +466,10 @@ void HealthCheckClient::CallState::DoneReadingRecvMessage(grpc_error* error) {
   const bool healthy = DecodeResponse(&recv_message_buffer_, &error);
   const grpc_connectivity_state state =
       healthy ? GRPC_CHANNEL_READY : GRPC_CHANNEL_TRANSIENT_FAILURE;
-  const char* reason = error == GRPC_ERROR_NONE && !healthy
-                           ? "backend unhealthy"
-                           : grpc_error_string(error);
-  health_check_client_->SetHealthStatus(state, reason);
+  health_check_client_->SetHealthStatus(
+      state, error == GRPC_ERROR_NONE && !healthy
+                 ? "backend unhealthy"
+                 : grpc_error_std_string(error).c_str());
   seen_response_.Store(true, MemoryOrder::RELEASE);
   grpc_slice_buffer_destroy_internal(&recv_message_buffer_);
   // Start another recv_message batch.
@@ -485,9 +484,9 @@ void HealthCheckClient::CallState::DoneReadingRecvMessage(grpc_error* error) {
   StartBatch(&recv_message_batch_);
 }
 
-grpc_error* HealthCheckClient::CallState::PullSliceFromRecvMessage() {
+grpc_error_handle HealthCheckClient::CallState::PullSliceFromRecvMessage() {
   grpc_slice slice;
-  grpc_error* error = recv_message_->Pull(&slice);
+  grpc_error_handle error = recv_message_->Pull(&slice);
   if (error == GRPC_ERROR_NONE) {
     grpc_slice_buffer_add(&recv_message_buffer_, slice);
   }
@@ -496,7 +495,7 @@ grpc_error* HealthCheckClient::CallState::PullSliceFromRecvMessage() {
 
 void HealthCheckClient::CallState::ContinueReadingRecvMessage() {
   while (recv_message_->Next(SIZE_MAX, &recv_message_ready_)) {
-    grpc_error* error = PullSliceFromRecvMessage();
+    grpc_error_handle error = PullSliceFromRecvMessage();
     if (error != GRPC_ERROR_NONE) {
       DoneReadingRecvMessage(error);
       return;
@@ -509,7 +508,7 @@ void HealthCheckClient::CallState::ContinueReadingRecvMessage() {
 }
 
 void HealthCheckClient::CallState::OnByteStreamNext(void* arg,
-                                                    grpc_error* error) {
+                                                    grpc_error_handle error) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   if (error != GRPC_ERROR_NONE) {
@@ -528,8 +527,8 @@ void HealthCheckClient::CallState::OnByteStreamNext(void* arg,
   }
 }
 
-void HealthCheckClient::CallState::RecvMessageReady(void* arg,
-                                                    grpc_error* /*error*/) {
+void HealthCheckClient::CallState::RecvMessageReady(
+    void* arg, grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "recv_message_ready");
@@ -545,7 +544,7 @@ void HealthCheckClient::CallState::RecvMessageReady(void* arg,
 }
 
 void HealthCheckClient::CallState::RecvTrailingMetadataReady(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_,
index 0fc39b0..d1f063b 100644 (file)
@@ -64,30 +64,30 @@ class HealthCheckClient : public InternallyRefCounted<HealthCheckClient> {
 
     void Orphan() override;
 
-    void StartCall();
+    void StartCall() ABSL_EXCLUSIVE_LOCKS_REQUIRED(&HealthCheckClient::mu_);
 
    private:
     void Cancel();
 
     void StartBatch(grpc_transport_stream_op_batch* batch);
-    static void StartBatchInCallCombiner(void* arg, grpc_error* error);
+    static void StartBatchInCallCombiner(void* arg, grpc_error_handle error);
 
-    // Requires holding health_check_client_->mu_.
-    void CallEndedLocked(bool retry);
+    void CallEndedLocked(bool retry)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(health_check_client_->mu_);
 
-    static void OnComplete(void* arg, grpc_error* error);
-    static void RecvInitialMetadataReady(void* arg, grpc_error* error);
-    static void RecvMessageReady(void* arg, grpc_error* error);
-    static void RecvTrailingMetadataReady(void* arg, grpc_error* error);
-    static void StartCancel(void* arg, grpc_error* error);
-    static void OnCancelComplete(void* arg, grpc_error* error);
+    static void OnComplete(void* arg, grpc_error_handle error);
+    static void RecvInitialMetadataReady(void* arg, grpc_error_handle error);
+    static void RecvMessageReady(void* arg, grpc_error_handle error);
+    static void RecvTrailingMetadataReady(void* arg, grpc_error_handle error);
+    static void StartCancel(void* arg, grpc_error_handle error);
+    static void OnCancelComplete(void* arg, grpc_error_handle error);
 
-    static void OnByteStreamNext(void* arg, grpc_error* error);
+    static void OnByteStreamNext(void* arg, grpc_error_handle error);
     void ContinueReadingRecvMessage();
-    grpc_error* PullSliceFromRecvMessage();
-    void DoneReadingRecvMessage(grpc_error* error);
+    grpc_error_handle PullSliceFromRecvMessage();
+    void DoneReadingRecvMessage(grpc_error_handle error);
 
-    static void AfterCallStackDestruction(void* arg, grpc_error* error);
+    static void AfterCallStackDestruction(void* arg, grpc_error_handle error);
 
     RefCountedPtr<HealthCheckClient> health_check_client_;
     grpc_polling_entity pollent_;
@@ -141,14 +141,14 @@ class HealthCheckClient : public InternallyRefCounted<HealthCheckClient> {
   };
 
   void StartCall();
-  void StartCallLocked();  // Requires holding mu_.
+  void StartCallLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
-  void StartRetryTimerLocked();  // Requires holding mu_.
-  static void OnRetryTimer(void* arg, grpc_error* error);
+  void StartRetryTimerLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
+  static void OnRetryTimer(void* arg, grpc_error_handle error);
 
   void SetHealthStatus(grpc_connectivity_state state, const char* reason);
-  void SetHealthStatusLocked(grpc_connectivity_state state,
-                             const char* reason);  // Requires holding mu_.
+  void SetHealthStatusLocked(grpc_connectivity_state state, const char* reason)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   std::string service_name_;
   RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
@@ -156,18 +156,19 @@ class HealthCheckClient : public InternallyRefCounted<HealthCheckClient> {
   RefCountedPtr<channelz::SubchannelNode> channelz_node_;
 
   Mutex mu_;
-  RefCountedPtr<ConnectivityStateWatcherInterface> watcher_;
-  bool shutting_down_ = false;
+  RefCountedPtr<ConnectivityStateWatcherInterface> watcher_
+      ABSL_GUARDED_BY(mu_);
+  bool shutting_down_ ABSL_GUARDED_BY(mu_) = false;
 
   // The data associated with the current health check call.  It holds a ref
   // to this HealthCheckClient object.
-  OrphanablePtr<CallState> call_state_;
+  OrphanablePtr<CallState> call_state_ ABSL_GUARDED_BY(mu_);
 
   // Call retry state.
-  BackOff retry_backoff_;
-  grpc_timer retry_timer_;
-  grpc_closure retry_timer_callback_;
-  bool retry_timer_callback_pending_ = false;
+  BackOff retry_backoff_ ABSL_GUARDED_BY(mu_);
+  grpc_timer retry_timer_ ABSL_GUARDED_BY(mu_);
+  grpc_closure retry_timer_callback_ ABSL_GUARDED_BY(mu_);
+  bool retry_timer_callback_pending_ ABSL_GUARDED_BY(mu_) = false;
 };
 
 }  // namespace grpc_core
index 8880806..3dff824 100644 (file)
@@ -47,7 +47,7 @@ namespace {
 class HttpConnectHandshaker : public Handshaker {
  public:
   HttpConnectHandshaker();
-  void Shutdown(grpc_error* why) override;
+  void Shutdown(grpc_error_handle why) override;
   void DoHandshake(grpc_tcp_server_acceptor* acceptor,
                    grpc_closure* on_handshake_done,
                    HandshakerArgs* args) override;
@@ -55,30 +55,31 @@ class HttpConnectHandshaker : public Handshaker {
 
  private:
   ~HttpConnectHandshaker() override;
-  void CleanupArgsForFailureLocked();
-  void HandshakeFailedLocked(grpc_error* error);
-  static void OnWriteDone(void* arg, grpc_error* error);
-  static void OnReadDone(void* arg, grpc_error* error);
-  static void OnWriteDoneScheduler(void* arg, grpc_error* error);
-  static void OnReadDoneScheduler(void* arg, grpc_error* error);
+  void CleanupArgsForFailureLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
+  void HandshakeFailedLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
+  static void OnWriteDone(void* arg, grpc_error_handle error);
+  static void OnReadDone(void* arg, grpc_error_handle error);
+  static void OnWriteDoneScheduler(void* arg, grpc_error_handle error);
+  static void OnReadDoneScheduler(void* arg, grpc_error_handle error);
 
   Mutex mu_;
 
-  bool is_shutdown_ = false;
+  bool is_shutdown_ ABSL_GUARDED_BY(mu_) = false;
   // Endpoint and read buffer to destroy after a shutdown.
-  grpc_endpoint* endpoint_to_destroy_ = nullptr;
-  grpc_slice_buffer* read_buffer_to_destroy_ = nullptr;
+  grpc_endpoint* endpoint_to_destroy_ ABSL_GUARDED_BY(mu_) = nullptr;
+  grpc_slice_buffer* read_buffer_to_destroy_ ABSL_GUARDED_BY(mu_) = nullptr;
 
   // State saved while performing the handshake.
   HandshakerArgs* args_ = nullptr;
   grpc_closure* on_handshake_done_ = nullptr;
 
   // Objects for processing the HTTP CONNECT request and response.
-  grpc_slice_buffer write_buffer_;
-  grpc_closure request_done_closure_;
-  grpc_closure response_read_closure_;
-  grpc_http_parser http_parser_;
-  grpc_http_response http_response_;
+  grpc_slice_buffer write_buffer_ ABSL_GUARDED_BY(mu_);
+  grpc_closure request_done_closure_ ABSL_GUARDED_BY(mu_);
+  grpc_closure response_read_closure_ ABSL_GUARDED_BY(mu_);
+  grpc_http_parser http_parser_ ABSL_GUARDED_BY(mu_);
+  grpc_http_response http_response_ ABSL_GUARDED_BY(mu_);
 };
 
 HttpConnectHandshaker::~HttpConnectHandshaker() {
@@ -107,7 +108,7 @@ void HttpConnectHandshaker::CleanupArgsForFailureLocked() {
 
 // If the handshake failed or we're shutting down, clean up and invoke the
 // callback with the error.
-void HttpConnectHandshaker::HandshakeFailedLocked(grpc_error* error) {
+void HttpConnectHandshaker::HandshakeFailedLocked(grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) {
     // If we were shut down after an endpoint operation succeeded but
     // before the endpoint callback was invoked, we need to generate our
@@ -133,7 +134,8 @@ void HttpConnectHandshaker::HandshakeFailedLocked(grpc_error* error) {
 
 // This callback can be invoked inline while already holding onto the mutex. To
 // avoid deadlocks, schedule OnWriteDone on ExecCtx.
-void HttpConnectHandshaker::OnWriteDoneScheduler(void* arg, grpc_error* error) {
+void HttpConnectHandshaker::OnWriteDoneScheduler(void* arg,
+                                                 grpc_error_handle error) {
   auto* handshaker = static_cast<HttpConnectHandshaker*>(arg);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION,
@@ -144,7 +146,7 @@ void HttpConnectHandshaker::OnWriteDoneScheduler(void* arg, grpc_error* error) {
 }
 
 // Callback invoked when finished writing HTTP CONNECT request.
-void HttpConnectHandshaker::OnWriteDone(void* arg, grpc_error* error) {
+void HttpConnectHandshaker::OnWriteDone(void* arg, grpc_error_handle error) {
   auto* handshaker = static_cast<HttpConnectHandshaker*>(arg);
   ReleasableMutexLock lock(&handshaker->mu_);
   if (error != GRPC_ERROR_NONE || handshaker->is_shutdown_) {
@@ -167,7 +169,8 @@ void HttpConnectHandshaker::OnWriteDone(void* arg, grpc_error* error) {
 
 // This callback can be invoked inline while already holding onto the mutex. To
 // avoid deadlocks, schedule OnReadDone on ExecCtx.
-void HttpConnectHandshaker::OnReadDoneScheduler(void* arg, grpc_error* error) {
+void HttpConnectHandshaker::OnReadDoneScheduler(void* arg,
+                                                grpc_error_handle error) {
   auto* handshaker = static_cast<HttpConnectHandshaker*>(arg);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION,
@@ -178,7 +181,7 @@ void HttpConnectHandshaker::OnReadDoneScheduler(void* arg, grpc_error* error) {
 }
 
 // Callback invoked for reading HTTP CONNECT response.
-void HttpConnectHandshaker::OnReadDone(void* arg, grpc_error* error) {
+void HttpConnectHandshaker::OnReadDone(void* arg, grpc_error_handle error) {
   auto* handshaker = static_cast<HttpConnectHandshaker*>(arg);
   ReleasableMutexLock lock(&handshaker->mu_);
   if (error != GRPC_ERROR_NONE || handshaker->is_shutdown_) {
@@ -264,7 +267,7 @@ done:
 // Public handshaker methods
 //
 
-void HttpConnectHandshaker::Shutdown(grpc_error* why) {
+void HttpConnectHandshaker::Shutdown(grpc_error_handle why) {
   {
     MutexLock lock(&mu_);
     if (!is_shutdown_) {
index 5470df8..b927224 100644 (file)
@@ -113,7 +113,7 @@ LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
     auto* parent = parent_->Ref().release();  // ref held by lambda.
     ExecCtx::Run(DEBUG_LOCATION,
                  GRPC_CLOSURE_CREATE(
-                     [](void* arg, grpc_error* /*error*/) {
+                     [](void* arg, grpc_error_handle /*error*/) {
                        auto* parent = static_cast<LoadBalancingPolicy*>(arg);
                        parent->work_serializer()->Run(
                            [parent]() {
index c9fc142..1c6f309 100644 (file)
@@ -230,7 +230,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
     /// Error to be set when returning a 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;
+    grpc_error_handle error = GRPC_ERROR_NONE;
 
     /// Used only if type is PICK_COMPLETE.
     /// Callback set by LB policy to be notified of trailing metadata.
@@ -243,7 +243,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
     // TODO(roth): The arguments to this callback should be moved into a
     // struct, so that we can later add new fields without breaking
     // existing implementations.
-    std::function<void(grpc_error*, MetadataInterface*, CallState*)>
+    std::function<void(grpc_error_handle, MetadataInterface*, CallState*)>
         recv_trailing_metadata_ready;
   };
 
@@ -387,13 +387,13 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
   // A picker that returns PICK_TRANSIENT_FAILURE for all picks.
   class TransientFailurePicker : public SubchannelPicker {
    public:
-    explicit TransientFailurePicker(grpc_error* error) : error_(error) {}
+    explicit TransientFailurePicker(grpc_error_handle error) : error_(error) {}
     ~TransientFailurePicker() override { GRPC_ERROR_UNREF(error_); }
 
     PickResult Pick(PickArgs args) override;
 
    private:
-    grpc_error* error_;
+    grpc_error_handle error_;
   };
 
  protected:
index c8d1b1d..5f7d75c 100644 (file)
@@ -30,8 +30,8 @@
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/profiling/timers.h"
 
-static grpc_error* clr_init_channel_elem(grpc_channel_element* /*elem*/,
-                                         grpc_channel_element_args* /*args*/) {
+static grpc_error_handle clr_init_channel_elem(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
@@ -54,7 +54,7 @@ struct call_data {
 
 }  // namespace
 
-static void on_complete_for_send(void* arg, grpc_error* error) {
+static void on_complete_for_send(void* arg, grpc_error_handle error) {
   call_data* calld = static_cast<call_data*>(arg);
   if (error == GRPC_ERROR_NONE) {
     calld->send_initial_metadata_succeeded = true;
@@ -63,7 +63,7 @@ static void on_complete_for_send(void* arg, grpc_error* error) {
                           GRPC_ERROR_REF(error));
 }
 
-static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
+static void recv_initial_metadata_ready(void* arg, grpc_error_handle error) {
   call_data* calld = static_cast<call_data*>(arg);
   if (error == GRPC_ERROR_NONE) {
     calld->recv_initial_metadata_succeeded = true;
@@ -73,8 +73,8 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
                           GRPC_ERROR_REF(error));
 }
 
-static grpc_error* clr_init_call_elem(grpc_call_element* elem,
-                                      const grpc_call_element_args* args) {
+static grpc_error_handle clr_init_call_elem(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   GPR_ASSERT(args->context != nullptr);
   new (elem->call_data) call_data();
   return GRPC_ERROR_NONE;
index 3b6e59b..4b4f1ab 100644 (file)
@@ -90,6 +90,8 @@
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
@@ -186,17 +186,17 @@ class GrpcLb : public LoadBalancingPolicy {
     void ScheduleNextClientLoadReportLocked();
     void SendClientLoadReportLocked();
 
-    static void MaybeSendClientLoadReport(void* arg, grpc_error* error);
-    static void ClientLoadReportDone(void* arg, grpc_error* error);
-    static void OnInitialRequestSent(void* arg, grpc_error* error);
-    static void OnBalancerMessageReceived(void* arg, grpc_error* error);
-    static void OnBalancerStatusReceived(void* arg, grpc_error* error);
+    static void MaybeSendClientLoadReport(void* arg, grpc_error_handle error);
+    static void ClientLoadReportDone(void* arg, grpc_error_handle error);
+    static void OnInitialRequestSent(void* arg, grpc_error_handle error);
+    static void OnBalancerMessageReceived(void* arg, grpc_error_handle error);
+    static void OnBalancerStatusReceived(void* arg, grpc_error_handle error);
 
-    void MaybeSendClientLoadReportLocked(grpc_error* error);
-    void ClientLoadReportDoneLocked(grpc_error* error);
+    void MaybeSendClientLoadReportLocked(grpc_error_handle error);
+    void ClientLoadReportDoneLocked(grpc_error_handle error);
     void OnInitialRequestSentLocked();
     void OnBalancerMessageReceivedLocked();
-    void OnBalancerStatusReceivedLocked(grpc_error* error);
+    void OnBalancerStatusReceivedLocked(grpc_error_handle error);
 
     // The owning LB policy.
     RefCountedPtr<LoadBalancingPolicy> grpclb_policy_;
@@ -410,14 +410,14 @@ class GrpcLb : public LoadBalancingPolicy {
 
   // Methods for dealing with fallback state.
   void MaybeEnterFallbackModeAfterStartup();
-  static void OnFallbackTimer(void* arg, grpc_error* error);
-  void OnFallbackTimerLocked(grpc_error* error);
+  static void OnFallbackTimer(void* arg, grpc_error_handle error);
+  void OnFallbackTimerLocked(grpc_error_handle error);
 
   // Methods for dealing with the balancer call.
   void StartBalancerCallLocked();
   void StartBalancerCallRetryTimerLocked();
-  static void OnBalancerCallRetryTimer(void* arg, grpc_error* error);
-  void OnBalancerCallRetryTimerLocked(grpc_error* error);
+  static void OnBalancerCallRetryTimer(void* arg, grpc_error_handle error);
+  void OnBalancerCallRetryTimerLocked(grpc_error_handle error);
 
   // Methods for dealing with the child policy.
   grpc_channel_args* CreateChildPolicyArgsLocked(
@@ -893,6 +893,10 @@ void GrpcLb::BalancerCallState::StartQuery() {
 }
 
 void GrpcLb::BalancerCallState::ScheduleNextClientLoadReportLocked() {
+  // InvalidateNow to avoid getting stuck re-initializing this timer
+  // in a loop while draining the currently-held WorkSerializer.
+  // Also see https://github.com/grpc/grpc/issues/26079.
+  ExecCtx::Get()->InvalidateNow();
   const grpc_millis next_client_load_report_time =
       ExecCtx::Get()->Now() + client_stats_report_interval_;
   GRPC_CLOSURE_INIT(&client_load_report_closure_, MaybeSendClientLoadReport,
@@ -902,8 +906,8 @@ void GrpcLb::BalancerCallState::ScheduleNextClientLoadReportLocked() {
   client_load_report_timer_callback_pending_ = true;
 }
 
-void GrpcLb::BalancerCallState::MaybeSendClientLoadReport(void* arg,
-                                                          grpc_error* error) {
+void GrpcLb::BalancerCallState::MaybeSendClientLoadReport(
+    void* arg, grpc_error_handle error) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   lb_calld->grpclb_policy()->work_serializer()->Run(
@@ -912,7 +916,7 @@ void GrpcLb::BalancerCallState::MaybeSendClientLoadReport(void* arg,
 }
 
 void GrpcLb::BalancerCallState::MaybeSendClientLoadReportLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   client_load_report_timer_callback_pending_ = false;
   if (error != GRPC_ERROR_NONE || this != grpclb_policy()->lb_calld_.get()) {
     Unref(DEBUG_LOCATION, "client_load_report");
@@ -982,7 +986,7 @@ void GrpcLb::BalancerCallState::SendClientLoadReportLocked() {
 }
 
 void GrpcLb::BalancerCallState::ClientLoadReportDone(void* arg,
-                                                     grpc_error* error) {
+                                                     grpc_error_handle error) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   lb_calld->grpclb_policy()->work_serializer()->Run(
@@ -990,7 +994,8 @@ void GrpcLb::BalancerCallState::ClientLoadReportDone(void* arg,
       DEBUG_LOCATION);
 }
 
-void GrpcLb::BalancerCallState::ClientLoadReportDoneLocked(grpc_error* error) {
+void GrpcLb::BalancerCallState::ClientLoadReportDoneLocked(
+    grpc_error_handle error) {
   grpc_byte_buffer_destroy(send_message_payload_);
   send_message_payload_ = nullptr;
   if (error != GRPC_ERROR_NONE || this != grpclb_policy()->lb_calld_.get()) {
@@ -1001,8 +1006,8 @@ void GrpcLb::BalancerCallState::ClientLoadReportDoneLocked(grpc_error* error) {
   ScheduleNextClientLoadReportLocked();
 }
 
-void GrpcLb::BalancerCallState::OnInitialRequestSent(void* arg,
-                                                     grpc_error* /*error*/) {
+void GrpcLb::BalancerCallState::OnInitialRequestSent(
+    void* arg, grpc_error_handle /*error*/) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   lb_calld->grpclb_policy()->work_serializer()->Run(
       [lb_calld]() { lb_calld->OnInitialRequestSentLocked(); }, DEBUG_LOCATION);
@@ -1021,7 +1026,7 @@ void GrpcLb::BalancerCallState::OnInitialRequestSentLocked() {
 }
 
 void GrpcLb::BalancerCallState::OnBalancerMessageReceived(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   lb_calld->grpclb_policy()->work_serializer()->Run(
       [lb_calld]() { lb_calld->OnBalancerMessageReceivedLocked(); },
@@ -1183,8 +1188,8 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked() {
   }
 }
 
-void GrpcLb::BalancerCallState::OnBalancerStatusReceived(void* arg,
-                                                         grpc_error* error) {
+void GrpcLb::BalancerCallState::OnBalancerStatusReceived(
+    void* arg, grpc_error_handle error) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   GRPC_ERROR_REF(error);  // owned by lambda
   lb_calld->grpclb_policy()->work_serializer()->Run(
@@ -1193,7 +1198,7 @@ void GrpcLb::BalancerCallState::OnBalancerStatusReceived(void* arg,
 }
 
 void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   GPR_ASSERT(lb_call_ != nullptr);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) {
     char* status_details = grpc_slice_to_c_string(lb_call_status_details_);
@@ -1201,7 +1206,7 @@ void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked(
             "[grpclb %p] lb_calld=%p: Status from LB server received. "
             "Status = %d, details = '%s', (lb_call: %p), error '%s'",
             grpclb_policy(), this, lb_call_status_, status_details, lb_call_,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     gpr_free(status_details);
   }
   GRPC_ERROR_UNREF(error);
@@ -1420,13 +1425,12 @@ void GrpcLb::UpdateLocked(UpdateArgs args) {
     // Start watching the channel's connectivity state.  If the channel
     // goes into state TRANSIENT_FAILURE before the timer fires, we go into
     // fallback mode even if the fallback timeout has not elapsed.
-    grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
-        grpc_channel_get_channel_stack(lb_channel_));
-    GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
+    ClientChannel* client_channel = ClientChannel::GetFromChannel(lb_channel_);
+    GPR_ASSERT(client_channel != nullptr);
     // Ref held by callback.
     watcher_ = new StateWatcher(Ref(DEBUG_LOCATION, "StateWatcher"));
-    grpc_client_channel_start_connectivity_watch(
-        client_channel_elem, GRPC_CHANNEL_IDLE,
+    client_channel->AddConnectivityWatcher(
+        GRPC_CHANNEL_IDLE,
         OrphanablePtr<AsyncConnectivityStateWatcherInterface>(watcher_));
     // Start balancer call.
     StartBalancerCallLocked();
@@ -1490,10 +1494,9 @@ void GrpcLb::ProcessAddressesAndChannelArgsLocked(
 }
 
 void GrpcLb::CancelBalancerChannelConnectivityWatchLocked() {
-  grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
-      grpc_channel_get_channel_stack(lb_channel_));
-  GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
-  grpc_client_channel_stop_connectivity_watch(client_channel_elem, watcher_);
+  ClientChannel* client_channel = ClientChannel::GetFromChannel(lb_channel_);
+  GPR_ASSERT(client_channel != nullptr);
+  client_channel->RemoveConnectivityWatcher(watcher_);
 }
 
 //
@@ -1536,7 +1539,7 @@ void GrpcLb::StartBalancerCallRetryTimerLocked() {
   grpc_timer_init(&lb_call_retry_timer_, next_try, &lb_on_call_retry_);
 }
 
-void GrpcLb::OnBalancerCallRetryTimer(void* arg, grpc_error* error) {
+void GrpcLb::OnBalancerCallRetryTimer(void* arg, grpc_error_handle error) {
   GrpcLb* grpclb_policy = static_cast<GrpcLb*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   grpclb_policy->work_serializer()->Run(
@@ -1546,7 +1549,7 @@ void GrpcLb::OnBalancerCallRetryTimer(void* arg, grpc_error* error) {
       DEBUG_LOCATION);
 }
 
-void GrpcLb::OnBalancerCallRetryTimerLocked(grpc_error* error) {
+void GrpcLb::OnBalancerCallRetryTimerLocked(grpc_error_handle error) {
   retry_timer_callback_pending_ = false;
   if (!shutting_down_ && error == GRPC_ERROR_NONE && lb_calld_ == nullptr) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) {
@@ -1580,7 +1583,7 @@ void GrpcLb::MaybeEnterFallbackModeAfterStartup() {
   }
 }
 
-void GrpcLb::OnFallbackTimer(void* arg, grpc_error* error) {
+void GrpcLb::OnFallbackTimer(void* arg, grpc_error_handle error) {
   GrpcLb* grpclb_policy = static_cast<GrpcLb*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   grpclb_policy->work_serializer()->Run(
@@ -1588,7 +1591,7 @@ void GrpcLb::OnFallbackTimer(void* arg, grpc_error* error) {
       DEBUG_LOCATION);
 }
 
-void GrpcLb::OnFallbackTimerLocked(grpc_error* error) {
+void GrpcLb::OnFallbackTimerLocked(grpc_error_handle error) {
   // If we receive a serverlist after the timer fires but before this callback
   // actually runs, don't fall back.
   if (fallback_at_startup_checks_pending_ && !shutting_down_ &&
@@ -1692,12 +1695,12 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
   const char* name() const override { return kGrpclb; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       return MakeRefCounted<GrpcLbConfig>(nullptr, "");
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     Json child_policy_config_json_tmp;
     const Json* child_policy_config_json;
     std::string service_name;
@@ -1720,12 +1723,12 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
     } else {
       child_policy_config_json = &it->second;
     }
-    grpc_error* parse_error = GRPC_ERROR_NONE;
+    grpc_error_handle parse_error = GRPC_ERROR_NONE;
     RefCountedPtr<LoadBalancingPolicy::Config> child_policy_config =
         LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
             *child_policy_config_json, &parse_error);
     if (parse_error != GRPC_ERROR_NONE) {
-      std::vector<grpc_error*> child_errors;
+      std::vector<grpc_error_handle> child_errors;
       child_errors.push_back(parse_error);
       error_list.push_back(
           GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
index d2a1029..837cc09 100644 (file)
@@ -31,9 +31,9 @@
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/slice/slice_internal.h"
 
index f6e9440..c369827 100644 (file)
@@ -66,7 +66,8 @@ class GrpcLbClientStats : public RefCounted<GrpcLbClientStats> {
   gpr_atm num_calls_finished_with_client_failed_to_send_ = 0;
   gpr_atm num_calls_finished_known_received_ = 0;
   Mutex drop_count_mu_;  // Guards drop_token_counts_.
-  std::unique_ptr<DroppedCallCounts> drop_token_counts_;
+  std::unique_ptr<DroppedCallCounts> drop_token_counts_
+      ABSL_GUARDED_BY(drop_count_mu_);
 };
 
 }  // namespace grpc_core
index e7e98d9..6b7568c 100644 (file)
@@ -26,9 +26,9 @@
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/sync.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/error_utils.h"
 
@@ -197,7 +197,7 @@ void PickFirst::AttemptToConnectUsingLatestUpdateArgsLocked() {
     // (If we are idle, then this will happen in ExitIdleLocked() if we
     // haven't gotten a non-empty update by the time the application tries
     // to start a new call.)
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
                            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
     channel_control_helper()->UpdateState(
@@ -314,7 +314,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
       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()) {
-        grpc_error* error = grpc_error_set_int(
+        grpc_error_handle error = grpc_error_set_int(
             GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                 "selected subchannel failed; switching to pending update"),
             GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
@@ -393,7 +393,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
         subchannel_list()->set_in_transient_failure(true);
         // Only report new state in case 1.
         if (subchannel_list() == p->subchannel_list_.get()) {
-          grpc_error* error = grpc_error_set_int(
+          grpc_error_handle error = grpc_error_set_int(
               GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                   "failed to connect to all addresses"),
               GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
@@ -497,7 +497,7 @@ class PickFirstFactory : public LoadBalancingPolicyFactory {
   const char* name() const override { return kPickFirst; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& /*json*/, grpc_error** /*error*/) const override {
+      const Json& /*json*/, grpc_error_handle* /*error*/) const override {
     return MakeRefCounted<PickFirstConfig>();
   }
 };
index ca4bc90..3cd7c54 100644 (file)
@@ -179,10 +179,10 @@ class PriorityLb : public LoadBalancingPolicy {
 
     void StartFailoverTimerLocked();
 
-    static void OnFailoverTimer(void* arg, grpc_error* error);
-    void OnFailoverTimerLocked(grpc_error* error);
-    static void OnDeactivationTimer(void* arg, grpc_error* error);
-    void OnDeactivationTimerLocked(grpc_error* error);
+    static void OnFailoverTimer(void* arg, grpc_error_handle error);
+    void OnFailoverTimerLocked(grpc_error_handle error);
+    static void OnDeactivationTimer(void* arg, grpc_error_handle error);
+    void OnDeactivationTimerLocked(grpc_error_handle error);
 
     RefCountedPtr<PriorityLb> priority_policy_;
     const std::string name_;
@@ -472,7 +472,7 @@ void PriorityLb::TryNextPriorityLocked(bool report_connecting) {
             this);
   }
   current_child_from_before_update_ = nullptr;
-  grpc_error* error = grpc_error_set_int(
+  grpc_error_handle error = grpc_error_set_int(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("no ready priority"),
       GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
   channel_control_helper()->UpdateState(
@@ -655,14 +655,15 @@ void PriorityLb::ChildPriority::MaybeCancelFailoverTimerLocked() {
   }
 }
 
-void PriorityLb::ChildPriority::OnFailoverTimer(void* arg, grpc_error* error) {
+void PriorityLb::ChildPriority::OnFailoverTimer(void* arg,
+                                                grpc_error_handle error) {
   ChildPriority* self = static_cast<ChildPriority*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   self->priority_policy_->work_serializer()->Run(
       [self, error]() { self->OnFailoverTimerLocked(error); }, DEBUG_LOCATION);
 }
 
-void PriorityLb::ChildPriority::OnFailoverTimerLocked(grpc_error* error) {
+void PriorityLb::ChildPriority::OnFailoverTimerLocked(grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE && failover_timer_callback_pending_ &&
       !priority_policy_->shutting_down_) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_priority_trace)) {
@@ -712,7 +713,7 @@ void PriorityLb::ChildPriority::MaybeReactivateLocked() {
 }
 
 void PriorityLb::ChildPriority::OnDeactivationTimer(void* arg,
-                                                    grpc_error* error) {
+                                                    grpc_error_handle error) {
   ChildPriority* self = static_cast<ChildPriority*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   self->priority_policy_->work_serializer()->Run(
@@ -720,7 +721,8 @@ void PriorityLb::ChildPriority::OnDeactivationTimer(void* arg,
       DEBUG_LOCATION);
 }
 
-void PriorityLb::ChildPriority::OnDeactivationTimerLocked(grpc_error* error) {
+void PriorityLb::ChildPriority::OnDeactivationTimerLocked(
+    grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE && deactivation_timer_callback_pending_ &&
       !priority_policy_->shutting_down_) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_priority_trace)) {
@@ -785,7 +787,7 @@ class PriorityLbFactory : public LoadBalancingPolicyFactory {
   const char* name() const override { return kPriority; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // priority was mentioned as a policy in the deprecated
@@ -796,7 +798,7 @@ class PriorityLbFactory : public LoadBalancingPolicyFactory {
           "config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     // Children.
     std::map<std::string, PriorityLbConfig::PriorityLbChild> children;
     auto it = json.object_value().find("children");
@@ -824,7 +826,7 @@ class PriorityLbFactory : public LoadBalancingPolicyFactory {
                              " error:missing 'config' field")
                     .c_str()));
           } else {
-            grpc_error* parse_error = GRPC_ERROR_NONE;
+            grpc_error_handle parse_error = GRPC_ERROR_NONE;
             auto config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
                 it2->second, &parse_error);
             bool ignore_resolution_requests = false;
index efc7942..529d90d 100644 (file)
 #include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h"
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/error_utils.h"
 #include "src/core/lib/transport/static_metadata.h"
@@ -331,7 +331,7 @@ void RoundRobin::RoundRobinSubchannelList::
         absl::make_unique<QueuePicker>(p->Ref(DEBUG_LOCATION, "QueuePicker")));
   } else if (num_transient_failure_ == num_subchannels()) {
     /* 3) TRANSIENT_FAILURE */
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                "connections to all backends failing"),
                            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
@@ -449,7 +449,7 @@ void RoundRobin::UpdateLocked(UpdateArgs args) {
   if (latest_pending_subchannel_list_->num_subchannels() == 0) {
     // If the new list is empty, immediately promote the new list to the
     // current list and transition to TRANSIENT_FAILURE.
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
                            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
     channel_control_helper()->UpdateState(
@@ -487,7 +487,7 @@ class RoundRobinFactory : public LoadBalancingPolicyFactory {
   const char* name() const override { return kRoundRobin; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& /*json*/, grpc_error** /*error*/) const override {
+      const Json& /*json*/, grpc_error_handle* /*error*/) const override {
     return MakeRefCounted<RoundRobinConfig>();
   }
 };
index a240a2d..b894c59 100644 (file)
 // 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/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/closure.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/transport/connectivity_state.h"
 
 // Code for maintaining a list of subchannels within an LB policy.
index 1eca478..ac1857b 100644 (file)
@@ -165,8 +165,8 @@ class WeightedTargetLb : public LoadBalancingPolicy {
         grpc_connectivity_state state, const absl::Status& status,
         std::unique_ptr<SubchannelPicker> picker);
 
-    static void OnDelayedRemovalTimer(void* arg, grpc_error* error);
-    void OnDelayedRemovalTimerLocked(grpc_error* error);
+    static void OnDelayedRemovalTimer(void* arg, grpc_error_handle error);
+    void OnDelayedRemovalTimerLocked(grpc_error_handle error);
 
     // The owning LB policy.
     RefCountedPtr<WeightedTargetLb> weighted_target_policy_;
@@ -387,7 +387,7 @@ void WeightedTargetLb::UpdateStateLocked() {
           absl::make_unique<QueuePicker>(Ref(DEBUG_LOCATION, "QueuePicker"));
       break;
     default:
-      grpc_error* error = grpc_error_set_int(
+      grpc_error_handle error = grpc_error_set_int(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "weighted_target: all children report state TRANSIENT_FAILURE"),
           GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
@@ -564,8 +564,8 @@ void WeightedTargetLb::WeightedChild::DeactivateLocked() {
                   &on_delayed_removal_timer_);
 }
 
-void WeightedTargetLb::WeightedChild::OnDelayedRemovalTimer(void* arg,
-                                                            grpc_error* error) {
+void WeightedTargetLb::WeightedChild::OnDelayedRemovalTimer(
+    void* arg, grpc_error_handle error) {
   WeightedChild* self = static_cast<WeightedChild*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   self->weighted_target_policy_->work_serializer()->Run(
@@ -574,7 +574,7 @@ void WeightedTargetLb::WeightedChild::OnDelayedRemovalTimer(void* arg,
 }
 
 void WeightedTargetLb::WeightedChild::OnDelayedRemovalTimerLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE && delayed_removal_timer_callback_pending_ &&
       !shutdown_ && weight_ == 0) {
     delayed_removal_timer_callback_pending_ = false;
@@ -631,7 +631,7 @@ class WeightedTargetLbFactory : public LoadBalancingPolicyFactory {
   const char* name() const override { return kWeightedTarget; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // weighted_target was mentioned as a policy in the deprecated
@@ -642,7 +642,7 @@ class WeightedTargetLbFactory : public LoadBalancingPolicyFactory {
           "config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     // Weight map.
     WeightedTargetLbConfig::TargetMap target_map;
     auto it = json.object_value().find("targets");
@@ -655,14 +655,14 @@ class WeightedTargetLbFactory : public LoadBalancingPolicyFactory {
     } else {
       for (const auto& p : it->second.object_value()) {
         WeightedTargetLbConfig::ChildConfig child_config;
-        std::vector<grpc_error*> child_errors =
+        std::vector<grpc_error_handle> child_errors =
             ParseChildConfig(p.second, &child_config);
         if (!child_errors.empty()) {
           // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
           // string is not static in this case.
-          grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
               absl::StrCat("field:targets key:", p.first).c_str());
-          for (grpc_error* child_error : child_errors) {
+          for (grpc_error_handle child_error : child_errors) {
             error = grpc_error_add_child(error, child_error);
           }
           error_list.push_back(error);
@@ -680,9 +680,9 @@ class WeightedTargetLbFactory : public LoadBalancingPolicyFactory {
   }
 
  private:
-  static std::vector<grpc_error*> ParseChildConfig(
+  static std::vector<grpc_error_handle> ParseChildConfig(
       const Json& json, WeightedTargetLbConfig::ChildConfig* child_config) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "value should be of type object"));
@@ -711,13 +711,13 @@ class WeightedTargetLbFactory : public LoadBalancingPolicyFactory {
     // Child policy.
     it = json.object_value().find("childPolicy");
     if (it != json.object_value().end()) {
-      grpc_error* parse_error = GRPC_ERROR_NONE;
+      grpc_error_handle parse_error = GRPC_ERROR_NONE;
       child_config->config =
           LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(it->second,
                                                                 &parse_error);
       if (child_config->config == nullptr) {
         GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
-        std::vector<grpc_error*> child_errors;
+        std::vector<grpc_error_handle> child_errors;
         child_errors.push_back(parse_error);
         error_list.push_back(
             GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
index 46cdb32..49bff27 100644 (file)
@@ -75,7 +75,7 @@ class CdsLb : public LoadBalancingPolicy {
     void OnClusterChanged(XdsApi::CdsUpdate cluster_data) override {
       new Notifier(parent_, name_, std::move(cluster_data));
     }
-    void OnError(grpc_error* error) override {
+    void OnError(grpc_error_handle error) override {
       new Notifier(parent_, name_, error);
     }
     void OnResourceDoesNotExist() override { new Notifier(parent_, name_); }
@@ -86,14 +86,14 @@ class CdsLb : public LoadBalancingPolicy {
       Notifier(RefCountedPtr<CdsLb> parent, std::string name,
                XdsApi::CdsUpdate update);
       Notifier(RefCountedPtr<CdsLb> parent, std::string name,
-               grpc_error* error);
+               grpc_error_handle error);
       explicit Notifier(RefCountedPtr<CdsLb> parent, std::string name);
 
      private:
       enum Type { kUpdate, kError, kDoesNotExist };
 
-      static void RunInExecCtx(void* arg, grpc_error* error);
-      void RunInWorkSerializer(grpc_error* error);
+      static void RunInExecCtx(void* arg, grpc_error_handle error);
+      void RunInWorkSerializer(grpc_error_handle error);
 
       RefCountedPtr<CdsLb> parent_;
       std::string name_;
@@ -139,10 +139,10 @@ class CdsLb : public LoadBalancingPolicy {
       std::set<std::string>* clusters_needed);
   void OnClusterChanged(const std::string& name,
                         XdsApi::CdsUpdate cluster_data);
-  void OnError(const std::string& name, grpc_error* error);
+  void OnError(const std::string& name, grpc_error_handle error);
   void OnResourceDoesNotExist(const std::string& name);
 
-  grpc_error* UpdateXdsCertificateProvider(
+  grpc_error_handle UpdateXdsCertificateProvider(
       const std::string& cluster_name, const XdsApi::CdsUpdate& cluster_data);
 
   void CancelClusterDataWatch(absl::string_view cluster_name,
@@ -190,7 +190,8 @@ CdsLb::ClusterWatcher::Notifier::Notifier(RefCountedPtr<CdsLb> parent,
 }
 
 CdsLb::ClusterWatcher::Notifier::Notifier(RefCountedPtr<CdsLb> parent,
-                                          std::string name, grpc_error* error)
+                                          std::string name,
+                                          grpc_error_handle error)
     : parent_(std::move(parent)), name_(std::move(name)), type_(kError) {
   GRPC_CLOSURE_INIT(&closure_, &RunInExecCtx, this, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &closure_, error);
@@ -204,14 +205,15 @@ CdsLb::ClusterWatcher::Notifier::Notifier(RefCountedPtr<CdsLb> parent,
 }
 
 void CdsLb::ClusterWatcher::Notifier::RunInExecCtx(void* arg,
-                                                   grpc_error* error) {
+                                                   grpc_error_handle error) {
   Notifier* self = static_cast<Notifier*>(arg);
   GRPC_ERROR_REF(error);
   self->parent_->work_serializer()->Run(
       [self, error]() { self->RunInWorkSerializer(error); }, DEBUG_LOCATION);
 }
 
-void CdsLb::ClusterWatcher::Notifier::RunInWorkSerializer(grpc_error* error) {
+void CdsLb::ClusterWatcher::Notifier::RunInWorkSerializer(
+    grpc_error_handle error) {
   switch (type_) {
     case kUpdate:
       parent_->OnClusterChanged(name_, std::move(update_));
@@ -434,7 +436,7 @@ void CdsLb::OnClusterChanged(const std::string& name,
   if (it == watchers_.end()) return;
   it->second.update = cluster_data;
   // Take care of integration with new certificate code.
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   error = UpdateXdsCertificateProvider(name, it->second.update.value());
   if (error != GRPC_ERROR_NONE) {
     return OnError(name, error);
@@ -541,9 +543,9 @@ void CdsLb::OnClusterChanged(const std::string& name,
   }
 }
 
-void CdsLb::OnError(const std::string& name, grpc_error* error) {
+void CdsLb::OnError(const std::string& name, grpc_error_handle error) {
   gpr_log(GPR_ERROR, "[cdslb %p] xds error obtaining data for cluster %s: %s",
-          this, name.c_str(), grpc_error_string(error));
+          this, name.c_str(), grpc_error_std_string(error).c_str());
   // Go into TRANSIENT_FAILURE if we have not yet created the child
   // policy (i.e., we have not yet received data from xds).  Otherwise,
   // we keep running with the data we had previously.
@@ -561,7 +563,7 @@ void CdsLb::OnResourceDoesNotExist(const std::string& name) {
           "[cdslb %p] CDS resource for %s does not exist -- reporting "
           "TRANSIENT_FAILURE",
           this, name.c_str());
-  grpc_error* error =
+  grpc_error_handle error =
       grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
                              absl::StrCat("CDS resource \"", config_->cluster(),
                                           "\" does not exist")
@@ -573,7 +575,7 @@ void CdsLb::OnResourceDoesNotExist(const std::string& name) {
   MaybeDestroyChildPolicyLocked();
 }
 
-grpc_error* CdsLb::UpdateXdsCertificateProvider(
+grpc_error_handle CdsLb::UpdateXdsCertificateProvider(
     const std::string& cluster_name, const XdsApi::CdsUpdate& cluster_data) {
   // Early out if channel is not configured to use xds security.
   grpc_channel_credentials* channel_credentials =
@@ -599,10 +601,12 @@ grpc_error* CdsLb::UpdateXdsCertificateProvider(
         xds_client_->certificate_provider_store()
             .CreateOrGetCertificateProvider(root_provider_instance_name);
     if (new_root_provider == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
-          absl::StrCat("Certificate provider instance name: \"",
-                       root_provider_instance_name, "\" not recognized.")
-              .c_str());
+      return grpc_error_set_int(
+          GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat("Certificate provider instance name: \"",
+                           root_provider_instance_name, "\" not recognized.")
+                  .c_str()),
+          GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
     }
   }
   if (root_certificate_provider_ != new_root_provider) {
@@ -637,10 +641,13 @@ grpc_error* CdsLb::UpdateXdsCertificateProvider(
         xds_client_->certificate_provider_store()
             .CreateOrGetCertificateProvider(identity_provider_instance_name);
     if (new_identity_provider == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
-          absl::StrCat("Certificate provider instance name: \"",
-                       identity_provider_instance_name, "\" not recognized.")
-              .c_str());
+      return grpc_error_set_int(
+          GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat("Certificate provider instance name: \"",
+                           identity_provider_instance_name,
+                           "\" not recognized.")
+                  .c_str()),
+          GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
     }
   }
   if (identity_certificate_provider_ != new_identity_provider) {
@@ -693,13 +700,12 @@ class CdsLbFactory : public LoadBalancingPolicyFactory {
  public:
   OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
       LoadBalancingPolicy::Args args) const override {
-    grpc_error* error = GRPC_ERROR_NONE;
-    RefCountedPtr<XdsClient> xds_client = XdsClient::GetOrCreate(&error);
-    if (error != GRPC_ERROR_NONE) {
+    RefCountedPtr<XdsClient> xds_client =
+        XdsClient::GetFromChannelArgs(*args.args);
+    if (xds_client == nullptr) {
       gpr_log(GPR_ERROR,
-              "cannot get XdsClient to instantiate cds LB policy: %s",
-              grpc_error_string(error));
-      GRPC_ERROR_UNREF(error);
+              "XdsClient not present in channel args -- cannot instantiate "
+              "cds LB policy");
       return nullptr;
     }
     return MakeOrphanable<CdsLb>(std::move(xds_client), std::move(args));
@@ -708,7 +714,7 @@ class CdsLbFactory : public LoadBalancingPolicyFactory {
   const char* name() const override { return kCds; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // xds was mentioned as a policy in the deprecated loadBalancingPolicy
@@ -718,7 +724,7 @@ class CdsLbFactory : public LoadBalancingPolicyFactory {
           "Please use loadBalancingConfig field of service config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     // cluster name.
     std::string cluster;
     auto it = json.object_value().find("cluster");
index 55948fc..7dbba64 100644 (file)
@@ -31,6 +31,7 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/atomic.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
@@ -56,6 +57,7 @@ class CircuitBreakerCallCounterMap {
     explicit CallCounter(Key key) : key_(std::move(key)) {}
     ~CallCounter() override;
 
+    uint32_t Load() { return concurrent_requests_.Load(MemoryOrder::SEQ_CST); }
     uint32_t Increment() { return concurrent_requests_.FetchAdd(1); }
     void Decrement() { concurrent_requests_.FetchSub(1); }
 
@@ -69,7 +71,7 @@ class CircuitBreakerCallCounterMap {
 
  private:
   Mutex mu_;
-  std::map<Key, CallCounter*> map_;
+  std::map<Key, CallCounter*> map_ ABSL_GUARDED_BY(mu_);
 };
 
 CircuitBreakerCallCounterMap* g_call_counter_map = nullptr;
@@ -287,15 +289,15 @@ LoadBalancingPolicy::PickResult XdsClusterImplLb::Picker::Pick(
     return result;
   }
   // Handle circuit breaking.
-  uint32_t current = call_counter_->Increment();
+  uint32_t current = call_counter_->Load();
   // Check and see if we exceeded the max concurrent requests count.
   if (current >= max_concurrent_requests_) {
-    call_counter_->Decrement();
     if (drop_stats_ != nullptr) drop_stats_->AddUncategorizedDrops();
     PickResult result;
     result.type = PickResult::PICK_COMPLETE;
     return result;
   }
+  call_counter_->Increment();
   // If we're not dropping the call, we should always have a child picker.
   if (picker_ == nullptr) {  // Should never happen.
     PickResult result;
@@ -329,7 +331,7 @@ LoadBalancingPolicy::PickResult XdsClusterImplLb::Picker::Pick(
         // Note: This callback does not run in either the control plane
         // work serializer or in the data plane mutex.
         [locality_stats, original_recv_trailing_metadata_ready, call_counter](
-            grpc_error* error, MetadataInterface* metadata,
+            grpc_error_handle error, MetadataInterface* metadata,
             CallState* call_state) {
           // Record call completion for load reporting.
           if (locality_stats != nullptr) {
@@ -594,14 +596,12 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
  public:
   OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
       LoadBalancingPolicy::Args args) const override {
-    grpc_error* error = GRPC_ERROR_NONE;
-    RefCountedPtr<XdsClient> xds_client = XdsClient::GetOrCreate(&error);
-    if (error != GRPC_ERROR_NONE) {
-      gpr_log(
-          GPR_ERROR,
-          "cannot get XdsClient to instantiate xds_cluster_impl LB policy: %s",
-          grpc_error_string(error));
-      GRPC_ERROR_UNREF(error);
+    RefCountedPtr<XdsClient> xds_client =
+        XdsClient::GetFromChannelArgs(*args.args);
+    if (xds_client == nullptr) {
+      gpr_log(GPR_ERROR,
+              "XdsClient not present in channel args -- cannot instantiate "
+              "xds_cluster_impl LB policy");
       return nullptr;
     }
     return MakeOrphanable<XdsClusterImplLb>(std::move(xds_client),
@@ -611,7 +611,7 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
   const char* name() const override { return kXdsClusterImpl; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // This policy was configured in the deprecated loadBalancingPolicy
@@ -622,7 +622,7 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
           "config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     // Child policy.
     RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
     auto it = json.object_value().find("childPolicy");
@@ -630,12 +630,12 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "field:childPolicy error:required field missing"));
     } else {
-      grpc_error* parse_error = GRPC_ERROR_NONE;
+      grpc_error_handle parse_error = GRPC_ERROR_NONE;
       child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
           it->second, &parse_error);
       if (child_policy == nullptr) {
         GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
-        std::vector<grpc_error*> child_errors;
+        std::vector<grpc_error_handle> child_errors;
         child_errors.push_back(parse_error);
         error_list.push_back(
             GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
@@ -694,7 +694,7 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "field:dropCategories error:required field missing"));
     } else {
-      std::vector<grpc_error*> child_errors =
+      std::vector<grpc_error_handle> child_errors =
           ParseDropCategories(it->second, drop_config.get());
       if (!child_errors.empty()) {
         error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -713,9 +713,9 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
   }
 
  private:
-  static std::vector<grpc_error*> ParseDropCategories(
+  static std::vector<grpc_error_handle> ParseDropCategories(
       const Json& json, XdsApi::EdsUpdate::DropConfig* drop_config) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::ARRAY) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "dropCategories field is not an array"));
@@ -723,10 +723,10 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
     }
     for (size_t i = 0; i < json.array_value().size(); ++i) {
       const Json& entry = json.array_value()[i];
-      std::vector<grpc_error*> child_errors =
+      std::vector<grpc_error_handle> child_errors =
           ParseDropCategory(entry, drop_config);
       if (!child_errors.empty()) {
-        grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrCat("errors parsing index ", i).c_str());
         for (size_t i = 0; i < child_errors.size(); ++i) {
           error = grpc_error_add_child(error, child_errors[i]);
@@ -737,9 +737,9 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
     return error_list;
   }
 
-  static std::vector<grpc_error*> ParseDropCategory(
+  static std::vector<grpc_error_handle> ParseDropCategory(
       const Json& json, XdsApi::EdsUpdate::DropConfig* drop_config) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "dropCategories entry is not an object"));
index f4fa1f4..1d4f143 100644 (file)
@@ -162,8 +162,8 @@ class XdsClusterManagerLb : public LoadBalancingPolicy {
     OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
         const grpc_channel_args* args);
 
-    static void OnDelayedRemovalTimer(void* arg, grpc_error* error);
-    void OnDelayedRemovalTimerLocked(grpc_error* error);
+    static void OnDelayedRemovalTimer(void* arg, grpc_error_handle error);
+    void OnDelayedRemovalTimerLocked(grpc_error_handle error);
 
     // The owning LB policy.
     RefCountedPtr<XdsClusterManagerLb> xds_cluster_manager_policy_;
@@ -337,44 +337,29 @@ void XdsClusterManagerLb::UpdateStateLocked() {
     gpr_log(GPR_INFO, "[xds_cluster_manager_lb %p] connectivity changed to %s",
             this, ConnectivityStateName(connectivity_state));
   }
-  std::unique_ptr<SubchannelPicker> picker;
-  absl::Status status;
-  switch (connectivity_state) {
-    case GRPC_CHANNEL_READY: {
-      ClusterPicker::ClusterMap cluster_map;
-      for (const auto& p : config_->cluster_map()) {
-        const std::string& cluster_name = p.first;
-        RefCountedPtr<ChildPickerWrapper>& child_picker =
-            cluster_map[cluster_name];
-        child_picker = children_[cluster_name]->picker_wrapper();
-        if (child_picker == nullptr) {
-          if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_manager_lb_trace)) {
-            gpr_log(
-                GPR_INFO,
+  ClusterPicker::ClusterMap cluster_map;
+  for (const auto& p : config_->cluster_map()) {
+    const std::string& cluster_name = p.first;
+    RefCountedPtr<ChildPickerWrapper>& child_picker = cluster_map[cluster_name];
+    child_picker = children_[cluster_name]->picker_wrapper();
+    if (child_picker == nullptr) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_manager_lb_trace)) {
+        gpr_log(GPR_INFO,
                 "[xds_cluster_manager_lb %p] child %s has not yet returned a "
                 "picker; creating a QueuePicker.",
                 this, cluster_name.c_str());
-          }
-          child_picker = MakeRefCounted<ChildPickerWrapper>(
-              cluster_name, absl::make_unique<QueuePicker>(
-                                Ref(DEBUG_LOCATION, "QueuePicker")));
-        }
       }
-      picker = absl::make_unique<ClusterPicker>(std::move(cluster_map));
-      break;
+      child_picker = MakeRefCounted<ChildPickerWrapper>(
+          cluster_name,
+          absl::make_unique<QueuePicker>(Ref(DEBUG_LOCATION, "QueuePicker")));
     }
-    case GRPC_CHANNEL_CONNECTING:
-    case GRPC_CHANNEL_IDLE:
-      picker =
-          absl::make_unique<QueuePicker>(Ref(DEBUG_LOCATION, "QueuePicker"));
-      break;
-    default:
-      grpc_error* error = grpc_error_set_int(
-          GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-              "TRANSIENT_FAILURE from XdsClusterManagerLb"),
-          GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
-      status = grpc_error_to_absl_status(error);
-      picker = absl::make_unique<TransientFailurePicker>(error);
+  }
+  std::unique_ptr<SubchannelPicker> picker =
+      absl::make_unique<ClusterPicker>(std::move(cluster_map));
+  absl::Status status;
+  if (connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+    status = absl::Status(absl::StatusCode::kUnavailable,
+                          "TRANSIENT_FAILURE from XdsClusterManagerLb");
   }
   channel_control_helper()->UpdateState(connectivity_state, status,
                                         std::move(picker));
@@ -513,7 +498,7 @@ void XdsClusterManagerLb::ClusterChild::DeactivateLocked() {
 }
 
 void XdsClusterManagerLb::ClusterChild::OnDelayedRemovalTimer(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   ClusterChild* self = static_cast<ClusterChild*>(arg);
   GRPC_ERROR_REF(error);  // Ref owned by the lambda
   self->xds_cluster_manager_policy_->work_serializer()->Run(
@@ -522,7 +507,7 @@ void XdsClusterManagerLb::ClusterChild::OnDelayedRemovalTimer(
 }
 
 void XdsClusterManagerLb::ClusterChild::OnDelayedRemovalTimerLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   delayed_removal_timer_callback_pending_ = false;
   if (error == GRPC_ERROR_NONE && !shutdown_) {
     xds_cluster_manager_policy_->children_.erase(name_);
@@ -616,7 +601,7 @@ class XdsClusterManagerLbFactory : public LoadBalancingPolicyFactory {
   const char* name() const override { return kXdsClusterManager; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // xds_cluster_manager was mentioned as a policy in the deprecated
@@ -627,7 +612,7 @@ class XdsClusterManagerLbFactory : public LoadBalancingPolicyFactory {
           "config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     XdsClusterManagerLbConfig::ClusterMap cluster_map;
     std::set<std::string /*cluster_name*/> clusters_to_be_used;
     auto it = json.object_value().find("children");
@@ -646,14 +631,14 @@ class XdsClusterManagerLbFactory : public LoadBalancingPolicyFactory {
           continue;
         }
         RefCountedPtr<LoadBalancingPolicy::Config> child_config;
-        std::vector<grpc_error*> child_errors =
+        std::vector<grpc_error_handle> child_errors =
             ParseChildConfig(p.second, &child_config);
         if (!child_errors.empty()) {
           // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
           // string is not static in this case.
-          grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
               absl::StrCat("field:children name:", child_name).c_str());
-          for (grpc_error* child_error : child_errors) {
+          for (grpc_error_handle child_error : child_errors) {
             error = grpc_error_add_child(error, child_error);
           }
           error_list.push_back(error);
@@ -676,10 +661,10 @@ class XdsClusterManagerLbFactory : public LoadBalancingPolicyFactory {
   }
 
  private:
-  static std::vector<grpc_error*> ParseChildConfig(
+  static std::vector<grpc_error_handle> ParseChildConfig(
       const Json& json,
       RefCountedPtr<LoadBalancingPolicy::Config>* child_config) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "value should be of type object"));
@@ -690,12 +675,12 @@ class XdsClusterManagerLbFactory : public LoadBalancingPolicyFactory {
       error_list.push_back(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("did not find childPolicy"));
     } else {
-      grpc_error* parse_error = GRPC_ERROR_NONE;
+      grpc_error_handle parse_error = GRPC_ERROR_NONE;
       *child_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
           it->second, &parse_error);
       if (*child_config == nullptr) {
         GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
-        std::vector<grpc_error*> child_errors;
+        std::vector<grpc_error_handle> child_errors;
         child_errors.push_back(parse_error);
         error_list.push_back(
             GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
index a6fa1ac..bcb8194 100644 (file)
@@ -101,7 +101,8 @@ class XdsClusterResolverLbConfig : public LoadBalancingPolicy::Config {
 // Xds Cluster Resolver LB policy.
 class XdsClusterResolverLb : public LoadBalancingPolicy {
  public:
-  XdsClusterResolverLb(RefCountedPtr<XdsClient> xds_client, Args args);
+  XdsClusterResolverLb(RefCountedPtr<XdsClient> xds_client, Args args,
+                       std::string server_name, bool is_xds_uri);
 
   const char* name() const override { return kXdsClusterResolver; }
 
@@ -184,7 +185,7 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
       void OnEndpointChanged(XdsApi::EdsUpdate update) override {
         new Notifier(discovery_mechanism_, std::move(update));
       }
-      void OnError(grpc_error* error) override {
+      void OnError(grpc_error_handle error) override {
         new Notifier(discovery_mechanism_, error);
       }
       void OnResourceDoesNotExist() override {
@@ -197,7 +198,7 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
         Notifier(RefCountedPtr<EdsDiscoveryMechanism> discovery_mechanism,
                  XdsApi::EdsUpdate update);
         Notifier(RefCountedPtr<EdsDiscoveryMechanism> discovery_mechanism,
-                 grpc_error* error);
+                 grpc_error_handle error);
         explicit Notifier(
             RefCountedPtr<EdsDiscoveryMechanism> discovery_mechanism);
         ~Notifier() { discovery_mechanism_.reset(DEBUG_LOCATION, "Notifier"); }
@@ -205,8 +206,8 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
        private:
         enum Type { kUpdate, kError, kDoesNotExist };
 
-        static void RunInExecCtx(void* arg, grpc_error* error);
-        void RunInWorkSerializer(grpc_error* error);
+        static void RunInExecCtx(void* arg, grpc_error_handle error);
+        void RunInWorkSerializer(grpc_error_handle error);
 
         RefCountedPtr<EdsDiscoveryMechanism> discovery_mechanism_;
         grpc_closure closure_;
@@ -249,7 +250,7 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
 
       void ReturnResult(Resolver::Result result) override;
 
-      void ReturnError(grpc_error* error) override;
+      void ReturnError(grpc_error_handle error) override;
 
      private:
       RefCountedPtr<LogicalDNSDiscoveryMechanism> discovery_mechanism_;
@@ -303,7 +304,7 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
   void ShutdownLocked() override;
 
   void OnEndpointChanged(size_t index, XdsApi::EdsUpdate update);
-  void OnError(size_t index, grpc_error* error);
+  void OnError(size_t index, grpc_error_handle error);
   void OnResourceDoesNotExist(size_t index);
 
   void MaybeDestroyChildPolicyLocked();
@@ -317,6 +318,9 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
   grpc_channel_args* CreateChildPolicyArgsLocked(
       const grpc_channel_args* args_in);
 
+  // The xds client and endpoint watcher.
+  RefCountedPtr<XdsClient> xds_client_;
+
   // Server name from target URI.
   std::string server_name_;
   bool is_xds_uri_;
@@ -328,9 +332,6 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
   // Internal state.
   bool shutting_down_ = false;
 
-  // The xds client and endpoint watcher.
-  RefCountedPtr<XdsClient> xds_client_;
-
   // Vector of discovery mechansism entries in priority order.
   std::vector<DiscoveryMechanismEntry> discovery_mechanisms_;
 
@@ -429,7 +430,7 @@ XdsClusterResolverLb::EdsDiscoveryMechanism::EndpointWatcher::Notifier::
 XdsClusterResolverLb::EdsDiscoveryMechanism::EndpointWatcher::Notifier::
     Notifier(RefCountedPtr<XdsClusterResolverLb::EdsDiscoveryMechanism>
                  discovery_mechanism,
-             grpc_error* error)
+             grpc_error_handle error)
     : discovery_mechanism_(std::move(discovery_mechanism)), type_(kError) {
   GRPC_CLOSURE_INIT(&closure_, &RunInExecCtx, this, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &closure_, error);
@@ -445,7 +446,7 @@ XdsClusterResolverLb::EdsDiscoveryMechanism::EndpointWatcher::Notifier::
 }
 
 void XdsClusterResolverLb::EdsDiscoveryMechanism::EndpointWatcher::Notifier::
-    RunInExecCtx(void* arg, grpc_error* error) {
+    RunInExecCtx(void* arg, grpc_error_handle error) {
   Notifier* self = static_cast<Notifier*>(arg);
   GRPC_ERROR_REF(error);
   self->discovery_mechanism_->parent()->work_serializer()->Run(
@@ -453,7 +454,7 @@ void XdsClusterResolverLb::EdsDiscoveryMechanism::EndpointWatcher::Notifier::
 }
 
 void XdsClusterResolverLb::EdsDiscoveryMechanism::EndpointWatcher::Notifier::
-    RunInWorkSerializer(grpc_error* error) {
+    RunInWorkSerializer(grpc_error_handle error) {
   switch (type_) {
     case kUpdate:
       discovery_mechanism_->parent()->OnEndpointChanged(
@@ -541,7 +542,7 @@ void XdsClusterResolverLb::LogicalDNSDiscoveryMechanism::ResolverResultHandler::
 }
 
 void XdsClusterResolverLb::LogicalDNSDiscoveryMechanism::ResolverResultHandler::
-    ReturnError(grpc_error* error) {
+    ReturnError(grpc_error_handle error) {
   discovery_mechanism_->parent()->OnError(discovery_mechanism_->index(), error);
 }
 
@@ -550,26 +551,17 @@ void XdsClusterResolverLb::LogicalDNSDiscoveryMechanism::ResolverResultHandler::
 //
 
 XdsClusterResolverLb::XdsClusterResolverLb(RefCountedPtr<XdsClient> xds_client,
-                                           Args args)
-    : LoadBalancingPolicy(std::move(args)), xds_client_(std::move(xds_client)) {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_cluster_resolver_trace)) {
-    gpr_log(GPR_INFO,
-            "[xds_cluster_resolver_lb %p] created -- using xds client %p", this,
-            xds_client_.get());
-  }
-  // Record server name.
-  const char* server_uri =
-      grpc_channel_args_find_string(args.args, GRPC_ARG_SERVER_URI);
-  GPR_ASSERT(server_uri != nullptr);
-  absl::StatusOr<URI> uri = URI::Parse(server_uri);
-  GPR_ASSERT(uri.ok() && !uri->path().empty());
-  server_name_ = std::string(absl::StripPrefix(uri->path(), "/"));
-  is_xds_uri_ = uri->scheme() == "xds";
+                                           Args args, std::string server_name,
+                                           bool is_xds_uri)
+    : LoadBalancingPolicy(std::move(args)),
+      xds_client_(std::move(xds_client)),
+      server_name_(std::move(server_name)),
+      is_xds_uri_(is_xds_uri) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_cluster_resolver_trace)) {
     gpr_log(GPR_INFO,
-            "[xds_cluster_resolver_lb %p] server name from channel "
-            "(is_xds_uri=%d): %s",
-            this, is_xds_uri_, server_name_.c_str());
+            "[xds_cluster_resolver_lb %p] created -- xds_client=%p, "
+            "server_name=%s, is_xds_uri=%d",
+            this, xds_client_.get(), server_name_.c_str(), is_xds_uri_);
   }
   // EDS-only flow.
   if (!is_xds_uri_) {
@@ -738,11 +730,11 @@ void XdsClusterResolverLb::OnEndpointChanged(size_t index,
   UpdatePriorityList(std::move(priority_list));
 }
 
-void XdsClusterResolverLb::OnError(size_t index, grpc_error* error) {
+void XdsClusterResolverLb::OnError(size_t index, grpc_error_handle error) {
   gpr_log(GPR_ERROR,
           "[xds_cluster_resolver_lb %p] discovery mechanism %" PRIuPTR
           " xds watcher reported error: %s",
-          this, index, grpc_error_string(error));
+          this, index, grpc_error_std_string(error).c_str());
   GRPC_ERROR_UNREF(error);
   if (shutting_down_) return;
   if (!discovery_mechanisms_[index].first_update_received) {
@@ -1010,7 +1002,7 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() {
         "[xds_cluster_resolver_lb %p] generated config for child policy: %s",
         this, json_str.c_str());
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   RefCountedPtr<LoadBalancingPolicy::Config> config =
       LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json, &error);
   if (error != GRPC_ERROR_NONE) {
@@ -1020,7 +1012,7 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() {
             "[xds_cluster_resolver_lb %p] error parsing generated child policy "
             "config -- "
             "will put channel in TRANSIENT_FAILURE: %s",
-            this, grpc_error_string(error));
+            this, grpc_error_std_string(error).c_str());
     error = grpc_error_set_int(
         grpc_error_add_child(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                  "xds_cluster_resolver LB policy: error "
@@ -1054,10 +1046,14 @@ void XdsClusterResolverLb::UpdateChildPolicyLocked() {
 
 grpc_channel_args* XdsClusterResolverLb::CreateChildPolicyArgsLocked(
     const grpc_channel_args* args) {
-  // Inhibit client-side health checking, since the balancer does this for us.
-  grpc_arg new_arg = grpc_channel_arg_integer_create(
-      const_cast<char*>(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1);
-  return grpc_channel_args_copy_and_add(args, &new_arg, 1);
+  absl::InlinedVector<grpc_arg, 2> new_args = {
+      // Inhibit client-side health checking, since the balancer does this
+      // for us.
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1),
+  };
+  if (!is_xds_uri_) new_args.push_back(xds_client_->MakeChannelArg());
+  return grpc_channel_args_copy_and_add(args, new_args.data(), new_args.size());
 }
 
 OrphanablePtr<LoadBalancingPolicy>
@@ -1096,24 +1092,45 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
  public:
   OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
       LoadBalancingPolicy::Args args) const override {
-    grpc_error* error = GRPC_ERROR_NONE;
-    RefCountedPtr<XdsClient> xds_client = XdsClient::GetOrCreate(&error);
-    if (error != GRPC_ERROR_NONE) {
-      gpr_log(GPR_ERROR,
-              "cannot get XdsClient to instantiate xds_cluster_resolver LB "
-              "policy: %s",
-              grpc_error_string(error));
-      GRPC_ERROR_UNREF(error);
-      return nullptr;
+    // Find server name.
+    const char* server_uri =
+        grpc_channel_args_find_string(args.args, GRPC_ARG_SERVER_URI);
+    GPR_ASSERT(server_uri != nullptr);
+    absl::StatusOr<URI> uri = URI::Parse(server_uri);
+    GPR_ASSERT(uri.ok() && !uri->path().empty());
+    absl::string_view server_name = absl::StripPrefix(uri->path(), "/");
+    // Determine if it's an xds URI.
+    bool is_xds_uri = uri->scheme() == "xds";
+    // Get XdsClient.
+    RefCountedPtr<XdsClient> xds_client =
+        XdsClient::GetFromChannelArgs(*args.args);
+    if (xds_client == nullptr) {
+      if (!is_xds_uri) {
+        grpc_error_handle error = GRPC_ERROR_NONE;
+        xds_client = XdsClient::GetOrCreate(args.args, &error);
+        if (error != GRPC_ERROR_NONE) {
+          gpr_log(GPR_ERROR,
+                  "cannot get or create XdsClient to instantiate "
+                  "xds_cluster_resolver LB policy: %s",
+                  grpc_error_std_string(error).c_str());
+          GRPC_ERROR_UNREF(error);
+          return nullptr;
+        }
+      } else {
+        gpr_log(GPR_ERROR,
+                "XdsClient not present in channel args -- cannot instantiate "
+                "xds_cluster_resolver LB policy");
+        return nullptr;
+      }
     }
-    return MakeOrphanable<XdsClusterResolverChildHandler>(std::move(xds_client),
-                                                          std::move(args));
+    return MakeOrphanable<XdsClusterResolverChildHandler>(
+        std::move(xds_client), std::move(args), server_name, is_xds_uri);
   }
 
   const char* name() const override { return kXdsClusterResolver; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // xds_cluster_resolver was mentioned as a policy in the deprecated
@@ -1124,7 +1141,7 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
           "Please use loadBalancingConfig field of service config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     std::vector<XdsClusterResolverLbConfig::DiscoveryMechanism>
         discovery_mechanisms;
     auto it = json.object_value().find("discoveryMechanisms");
@@ -1138,13 +1155,13 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
       const Json::Array& array = it->second.array_value();
       for (size_t i = 0; i < array.size(); ++i) {
         XdsClusterResolverLbConfig::DiscoveryMechanism discovery_mechanism;
-        std::vector<grpc_error*> discovery_mechanism_errors =
+        std::vector<grpc_error_handle> discovery_mechanism_errors =
             ParseDiscoveryMechanism(array[i], &discovery_mechanism);
         if (!discovery_mechanism_errors.empty()) {
-          grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
               absl::StrCat("field:discovery_mechanism element: ", i, " error")
                   .c_str());
-          for (grpc_error* discovery_mechanism_error :
+          for (grpc_error_handle discovery_mechanism_error :
                discovery_mechanism_errors) {
             error = grpc_error_add_child(error, discovery_mechanism_error);
           }
@@ -1259,10 +1276,10 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
   }
 
  private:
-  static std::vector<grpc_error*> ParseDiscoveryMechanism(
+  static std::vector<grpc_error_handle> ParseDiscoveryMechanism(
       const Json& json,
       XdsClusterResolverLbConfig::DiscoveryMechanism* discovery_mechanism) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "value should be of type object"));
@@ -1339,10 +1356,13 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
   class XdsClusterResolverChildHandler : public ChildPolicyHandler {
    public:
     XdsClusterResolverChildHandler(RefCountedPtr<XdsClient> xds_client,
-                                   Args args)
+                                   Args args, absl::string_view server_name,
+                                   bool is_xds_uri)
         : ChildPolicyHandler(std::move(args),
                              &grpc_lb_xds_cluster_resolver_trace),
-          xds_client_(std::move(xds_client)) {}
+          xds_client_(std::move(xds_client)),
+          server_name_(server_name),
+          is_xds_uri_(is_xds_uri) {}
 
     bool ConfigChangeRequiresNewPolicyInstance(
         LoadBalancingPolicy::Config* old_config,
@@ -1359,11 +1379,14 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
 
     OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
         const char* /*name*/, LoadBalancingPolicy::Args args) const override {
-      return MakeOrphanable<XdsClusterResolverLb>(xds_client_, std::move(args));
+      return MakeOrphanable<XdsClusterResolverLb>(xds_client_, std::move(args),
+                                                  server_name_, is_xds_uri_);
     }
 
    private:
     RefCountedPtr<XdsClient> xds_client_;
+    std::string server_name_;
+    bool is_xds_uri_;
   };
 };
 
index 9e4425f..a595c27 100644 (file)
@@ -39,7 +39,7 @@ class LoadBalancingPolicyFactory {
   virtual const char* name() const = 0;
 
   virtual RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const = 0;
+      const Json& json, grpc_error_handle* error) const = 0;
 };
 
 }  // namespace grpc_core
index d64a643..a3f0347 100644 (file)
@@ -109,7 +109,7 @@ bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
     return false;
   }
   if (requires_config != nullptr) {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     // Check if the load balancing policy allows an empty config
     *requires_config =
         factory->ParseLoadBalancingConfig(Json(), &error) == nullptr;
@@ -122,7 +122,7 @@ namespace {
 
 // Returns the JSON node of policy (with both policy name and config content)
 // given the JSON node of a LoadBalancingConfig array.
-grpc_error* ParseLoadBalancingConfigHelper(
+grpc_error_handle ParseLoadBalancingConfigHelper(
     const Json& lb_config_array, Json::Object::const_iterator* result) {
   if (lb_config_array.type() != Json::Type::ARRAY) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("type should be array");
@@ -163,8 +163,8 @@ grpc_error* ParseLoadBalancingConfigHelper(
 }  // namespace
 
 RefCountedPtr<LoadBalancingPolicy::Config>
-LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const Json& json,
-                                                      grpc_error** error) {
+LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
+    const Json& json, grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
   GPR_ASSERT(g_state != nullptr);
   Json::Object::const_iterator policy;
index 8d2e3e3..aba44a8 100644 (file)
@@ -57,7 +57,7 @@ class LoadBalancingPolicyRegistry {
   /// Returns a parsed object of the load balancing policy to be used from a
   /// LoadBalancingConfig array \a json.
   static RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error);
+      const Json& json, grpc_error_handle* error);
 };
 
 }  // namespace grpc_core
index bd556a6..2ab7409 100644 (file)
@@ -55,7 +55,7 @@ class Resolver : public InternallyRefCounted<Resolver> {
   struct Result {
     ServerAddressList addresses;
     RefCountedPtr<ServiceConfig> service_config;
-    grpc_error* service_config_error = GRPC_ERROR_NONE;
+    grpc_error_handle service_config_error = GRPC_ERROR_NONE;
     const grpc_channel_args* args = nullptr;
 
     // TODO(roth): Remove everything below once grpc_error and
@@ -81,7 +81,7 @@ class Resolver : public InternallyRefCounted<Resolver> {
     /// Returns a transient error to the channel.
     /// If the resolver does not set the GRPC_ERROR_INT_GRPC_STATUS
     /// attribute on the error, calls will be failed with status UNKNOWN.
-    virtual void ReturnError(grpc_error* error) = 0;
+    virtual void ReturnError(grpc_error_handle error) = 0;
 
     // TODO(yashkt): As part of the service config error handling
     // changes, add a method to parse the service config JSON string.
index 922ac45..2911eae 100644 (file)
@@ -80,10 +80,10 @@ class AresDnsResolver : public Resolver {
   void MaybeStartResolvingLocked();
   void StartResolvingLocked();
 
-  static void OnNextResolution(void* arg, grpc_error* error);
-  static void OnResolved(void* arg, grpc_error* error);
-  void OnNextResolutionLocked(grpc_error* error);
-  void OnResolvedLocked(grpc_error* error);
+  static void OnNextResolution(void* arg, grpc_error_handle error);
+  static void OnResolved(void* arg, grpc_error_handle error);
+  void OnNextResolutionLocked(grpc_error_handle error);
+  void OnResolvedLocked(grpc_error_handle error);
 
   /// DNS server to use (if not system default)
   std::string dns_server_;
@@ -193,18 +193,18 @@ void AresDnsResolver::ShutdownLocked() {
   }
 }
 
-void AresDnsResolver::OnNextResolution(void* arg, grpc_error* error) {
+void AresDnsResolver::OnNextResolution(void* arg, grpc_error_handle error) {
   AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   r->work_serializer_->Run([r, error]() { r->OnNextResolutionLocked(error); },
                            DEBUG_LOCATION);
 }
 
-void AresDnsResolver::OnNextResolutionLocked(grpc_error* error) {
+void AresDnsResolver::OnNextResolutionLocked(grpc_error_handle error) {
   GRPC_CARES_TRACE_LOG(
       "resolver:%p re-resolution timer fired. error: %s. shutdown_initiated_: "
       "%d",
-      this, grpc_error_string(error), shutdown_initiated_);
+      this, grpc_error_std_string(error).c_str(), shutdown_initiated_);
   have_next_resolution_timer_ = false;
   if (error == GRPC_ERROR_NONE && !shutdown_initiated_) {
     if (!resolving_) {
@@ -227,7 +227,7 @@ bool ValueInJsonArray(const Json::Array& array, const char* value) {
 }
 
 std::string ChooseServiceConfig(char* service_config_choice_json,
-                                grpc_error** error) {
+                                grpc_error_handle* error) {
   Json json = Json::Parse(service_config_choice_json, error);
   if (*error != GRPC_ERROR_NONE) return "";
   if (json.type() != Json::Type::ARRAY) {
@@ -236,7 +236,7 @@ std::string ChooseServiceConfig(char* service_config_choice_json,
     return "";
   }
   const Json* service_config = nullptr;
-  absl::InlinedVector<grpc_error*, 4> error_list;
+  absl::InlinedVector<grpc_error_handle, 4> error_list;
   for (const Json& choice : json.array_value()) {
     if (choice.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -305,14 +305,14 @@ std::string ChooseServiceConfig(char* service_config_choice_json,
   return service_config->Dump();
 }
 
-void AresDnsResolver::OnResolved(void* arg, grpc_error* error) {
+void AresDnsResolver::OnResolved(void* arg, grpc_error_handle error) {
   AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   r->work_serializer_->Run([r, error]() { r->OnResolvedLocked(error); },
                            DEBUG_LOCATION);
 }
 
-void AresDnsResolver::OnResolvedLocked(grpc_error* error) {
+void AresDnsResolver::OnResolvedLocked(grpc_error_handle error) {
   GPR_ASSERT(resolving_);
   resolving_ = false;
   gpr_free(pending_request_);
@@ -354,7 +354,7 @@ void AresDnsResolver::OnResolvedLocked(grpc_error* error) {
     backoff_.Reset();
   } else {
     GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed: %s", this,
-                         grpc_error_string(error));
+                         grpc_error_std_string(error).c_str());
     std::string error_message =
         absl::StrCat("DNS resolution failed for service: ", name_to_resolve_);
     result_handler_->ReturnError(grpc_error_set_int(
@@ -362,10 +362,14 @@ void AresDnsResolver::OnResolvedLocked(grpc_error* error) {
                                                          &error, 1),
         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
     // Set retry timer.
+    // InvalidateNow to avoid getting stuck re-initializing this timer
+    // in a loop while draining the currently-held WorkSerializer.
+    // Also see https://github.com/grpc/grpc/issues/26079.
+    ExecCtx::Get()->InvalidateNow();
     grpc_millis next_try = backoff_.NextAttemptTime();
     grpc_millis timeout = next_try - ExecCtx::Get()->Now();
     GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed (will retry): %s",
-                         this, grpc_error_string(error));
+                         this, grpc_error_std_string(error).c_str());
     GPR_ASSERT(!have_next_resolution_timer_);
     have_next_resolution_timer_ = true;
     // TODO(roth): We currently deal with this ref manually.  Once the
@@ -389,6 +393,10 @@ void AresDnsResolver::MaybeStartResolvingLocked() {
   // can start the next resolution.
   if (have_next_resolution_timer_) return;
   if (last_resolution_timestamp_ >= 0) {
+    // InvalidateNow to avoid getting stuck re-initializing this timer
+    // in a loop while draining the currently-held WorkSerializer.
+    // Also see https://github.com/grpc/grpc/issues/26079.
+    ExecCtx::Get()->InvalidateNow();
     const grpc_millis earliest_next_resolution =
         last_resolution_timestamp_ + min_time_between_resolutions_;
     const grpc_millis ms_until_next_resolution =
@@ -455,7 +463,7 @@ class AresDnsResolverFactory : public ResolverFactory {
 extern grpc_address_resolver_vtable* grpc_resolve_address_impl;
 static grpc_address_resolver_vtable* default_resolver;
 
-static grpc_error* blocking_resolve_address_ares(
+static grpc_error_handle blocking_resolve_address_ares(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   return default_resolver->blocking_resolve_address(name, default_port,
@@ -490,7 +498,7 @@ void grpc_resolver_dns_ares_init() {
     g_use_ares_dns_resolver = true;
     gpr_log(GPR_DEBUG, "Using ares dns resolver");
     address_sorting_init();
-    grpc_error* error = grpc_ares_init();
+    grpc_error_handle error = grpc_ares_init();
     if (error != GRPC_ERROR_NONE) {
       GRPC_LOG_IF_ERROR("grpc_ares_init() failed", error);
       return;
index cc88486..0806923 100644 (file)
@@ -42,7 +42,7 @@ class GrpcPolledFd {
   virtual bool IsFdStillReadableLocked() = 0;
   /* Called once and only once. Must cause cancellation of any pending
    * read/write callbacks. */
-  virtual void ShutdownLocked(grpc_error* error) = 0;
+  virtual void ShutdownLocked(grpc_error_handle error) = 0;
   /* Get the underlying ares_socket_t that this was created from */
   virtual ares_socket_t GetWrappedAresSocketLocked() = 0;
   /* A unique name, for logging */
index e5eea5c..5c4c535 100644 (file)
@@ -75,7 +75,7 @@ class GrpcPolledFdLibuv : public GrpcPolledFd {
     return false;
   }
 
-  void ShutdownInternalLocked(grpc_error* error) {
+  void ShutdownInternalLocked(grpc_error_handle error) {
     uv_poll_stop(handle_);
     uv_close(reinterpret_cast<uv_handle_t*>(handle_), ares_uv_poll_close_cb);
     if (read_closure_ != nullptr) {
@@ -88,7 +88,7 @@ class GrpcPolledFdLibuv : public GrpcPolledFd {
     }
   }
 
-  void ShutdownLocked(grpc_error* error) override {
+  void ShutdownLocked(grpc_error_handle error) override {
     if (grpc_core::ExecCtx::Get() == nullptr) {
       grpc_core::ExecCtx exec_ctx;
       ShutdownInternalLocked(error);
@@ -127,7 +127,7 @@ static void ares_uv_poll_cb_locked(AresUvPollCbArg* arg) {
   int events = arg_struct->events;
   GrpcPolledFdLibuv* polled_fd =
       reinterpret_cast<GrpcPolledFdLibuv*>(handle->data);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (status < 0) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("cares polling error");
     error =
index 07f38ba..31de679 100644 (file)
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 namespace grpc_core {
 
@@ -72,7 +72,7 @@ class GrpcPolledFdPosix : public GrpcPolledFd {
            bytes_available > 0;
   }
 
-  void ShutdownLocked(grpc_error* error) override {
+  void ShutdownLocked(grpc_error_handle error) override {
     grpc_fd_shutdown(fd_, error);
   }
 
index 8d4a0cb..0b4675f 100644 (file)
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include <string.h>
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/sockaddr_windows.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 #include "src/core/lib/iomgr/tcp_windows.h"
@@ -131,12 +131,12 @@ class GrpcPolledFdWindows {
     grpc_winsocket_destroy(winsocket_);
   }
 
-  void ScheduleAndNullReadClosure(grpc_error* error) {
+  void ScheduleAndNullReadClosure(grpc_error_handle error) {
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, read_closure_, error);
     read_closure_ = nullptr;
   }
 
-  void ScheduleAndNullWriteClosure(grpc_error* error) {
+  void ScheduleAndNullWriteClosure(grpc_error_handle error) {
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, write_closure_, error);
     write_closure_ = nullptr;
   }
@@ -253,7 +253,7 @@ class GrpcPolledFdWindows {
 
   bool IsFdStillReadableLocked() { return read_buf_has_data_; }
 
-  void ShutdownLocked(grpc_error* error) {
+  void ShutdownLocked(grpc_error_handle error) {
     grpc_winsocket_shutdown(winsocket_);
   }
 
@@ -420,7 +420,7 @@ class GrpcPolledFdWindows {
     abort();
   }
 
-  static void OnTcpConnect(void* arg, grpc_error* error) {
+  static void OnTcpConnect(void* arg, grpc_error_handle error) {
     GrpcPolledFdWindows* grpc_polled_fd =
         static_cast<GrpcPolledFdWindows*>(arg);
     GRPC_ERROR_REF(error);  // ref owned by lambda
@@ -431,12 +431,12 @@ class GrpcPolledFdWindows {
         DEBUG_LOCATION);
   }
 
-  void OnTcpConnectLocked(grpc_error* error) {
+  void OnTcpConnectLocked(grpc_error_handle error) {
     GRPC_CARES_TRACE_LOG(
         "fd:%s InnerOnTcpConnectLocked error:|%s| "
         "pending_register_for_readable:%d"
         " pending_register_for_writeable:%d",
-        GetName(), grpc_error_string(error),
+        GetName(), grpc_error_std_string(error).c_str(),
         pending_continue_register_for_on_readable_locked_,
         pending_continue_register_for_on_writeable_locked_);
     GPR_ASSERT(!connect_done_);
@@ -576,7 +576,7 @@ class GrpcPolledFdWindows {
     return out;
   }
 
-  static void OnIocpReadable(void* arg, grpc_error* error) {
+  static void OnIocpReadable(void* arg, grpc_error_handle error) {
     GrpcPolledFdWindows* polled_fd = static_cast<GrpcPolledFdWindows*>(arg);
     GRPC_ERROR_REF(error);  // ref owned by lambda
     polled_fd->work_serializer_->Run(
@@ -589,7 +589,7 @@ class GrpcPolledFdWindows {
   // c-ares reads from this socket later, but it shouldn't necessarily cancel
   // the entire resolution attempt. Doing so will allow the "inject broken
   // nameserver list" test to pass on Windows.
-  void OnIocpReadableLocked(grpc_error* error) {
+  void OnIocpReadableLocked(grpc_error_handle error) {
     if (error == GRPC_ERROR_NONE) {
       if (winsocket_->read_info.wsa_error != 0) {
         /* WSAEMSGSIZE would be due to receiving more data
@@ -603,7 +603,7 @@ class GrpcPolledFdWindows {
               "fd:|%s| OnIocpReadableInner winsocket_->read_info.wsa_error "
               "code:|%d| msg:|%s|",
               GetName(), winsocket_->read_info.wsa_error,
-              grpc_error_string(error));
+              grpc_error_std_string(error).c_str());
         }
       }
     }
@@ -621,7 +621,7 @@ class GrpcPolledFdWindows {
     ScheduleAndNullReadClosure(error);
   }
 
-  static void OnIocpWriteable(void* arg, grpc_error* error) {
+  static void OnIocpWriteable(void* arg, grpc_error_handle error) {
     GrpcPolledFdWindows* polled_fd = static_cast<GrpcPolledFdWindows*>(arg);
     GRPC_ERROR_REF(error);  // error owned by lambda
     polled_fd->work_serializer_->Run(
@@ -629,7 +629,7 @@ class GrpcPolledFdWindows {
         DEBUG_LOCATION);
   }
 
-  void OnIocpWriteableLocked(grpc_error* error) {
+  void OnIocpWriteableLocked(grpc_error_handle error) {
     GRPC_CARES_TRACE_LOG("OnIocpWriteableInner. fd:|%s|", GetName());
     GPR_ASSERT(socket_type_ == SOCK_STREAM);
     if (error == GRPC_ERROR_NONE) {
@@ -640,7 +640,7 @@ class GrpcPolledFdWindows {
             "fd:|%s| OnIocpWriteableInner. winsocket_->write_info.wsa_error "
             "code:|%d| msg:|%s|",
             GetName(), winsocket_->write_info.wsa_error,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
       }
     }
     GPR_ASSERT(tcp_write_state_ == WRITE_PENDING);
@@ -851,7 +851,7 @@ class GrpcPolledFdWindowsWrapper : public GrpcPolledFd {
     return wrapped_->IsFdStillReadableLocked();
   }
 
-  void ShutdownLocked(grpc_error* error) override {
+  void ShutdownLocked(grpc_error_handle error) override {
     wrapped_->ShutdownLocked(error);
   }
 
index fa3249e..82dbb00 100644 (file)
 
 #include <address_sorting/address_sorting.h>
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/nameser.h"
-#include "src/core/lib/iomgr/parse_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/transport/authority_override.h"
 
@@ -77,7 +77,7 @@ struct grpc_ares_request {
   size_t pending_queries;
 
   /** the errors explaining query failures, appended to in query callbacks */
-  grpc_error* error;
+  grpc_error_handle error;
 };
 
 typedef struct fd_node {
@@ -268,11 +268,13 @@ static grpc_millis calculate_next_ares_backup_poll_alarm_ms(
          grpc_core::ExecCtx::Get()->Now();
 }
 
-static void on_timeout_locked(grpc_ares_ev_driver* driver, grpc_error* error) {
+static void on_timeout_locked(grpc_ares_ev_driver* driver,
+                              grpc_error_handle error) {
   GRPC_CARES_TRACE_LOG(
       "request:%p ev_driver=%p on_timeout_locked. driver->shutting_down=%d. "
       "err=%s",
-      driver->request, driver, driver->shutting_down, grpc_error_string(error));
+      driver->request, driver, driver->shutting_down,
+      grpc_error_std_string(error).c_str());
   if (!driver->shutting_down && error == GRPC_ERROR_NONE) {
     grpc_ares_ev_driver_shutdown_locked(driver);
   }
@@ -280,7 +282,7 @@ static void on_timeout_locked(grpc_ares_ev_driver* driver, grpc_error* error) {
   GRPC_ERROR_UNREF(error);
 }
 
-static void on_timeout(void* arg, grpc_error* error) {
+static void on_timeout(void* arg, grpc_error_handle error) {
   grpc_ares_ev_driver* driver = static_cast<grpc_ares_ev_driver*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   driver->work_serializer->Run(
@@ -290,9 +292,9 @@ static void on_timeout(void* arg, grpc_error* error) {
 static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver);
 
 static void on_ares_backup_poll_alarm_locked(grpc_ares_ev_driver* driver,
-                                             grpc_error* error);
+                                             grpc_error_handle error);
 
-static void on_ares_backup_poll_alarm(void* arg, grpc_error* error) {
+static void on_ares_backup_poll_alarm(void* arg, grpc_error_handle error) {
   grpc_ares_ev_driver* driver = static_cast<grpc_ares_ev_driver*>(arg);
   GRPC_ERROR_REF(error);
   driver->work_serializer->Run(
@@ -309,12 +311,13 @@ static void on_ares_backup_poll_alarm(void* arg, grpc_error* error) {
  * For the latter, we use this backup poller. Also see
  * https://github.com/grpc/grpc/pull/17688 description for more details. */
 static void on_ares_backup_poll_alarm_locked(grpc_ares_ev_driver* driver,
-                                             grpc_error* error) {
+                                             grpc_error_handle error) {
   GRPC_CARES_TRACE_LOG(
       "request:%p ev_driver=%p on_ares_backup_poll_alarm_locked. "
       "driver->shutting_down=%d. "
       "err=%s",
-      driver->request, driver, driver->shutting_down, grpc_error_string(error));
+      driver->request, driver, driver->shutting_down,
+      grpc_error_std_string(error).c_str());
   if (!driver->shutting_down && error == GRPC_ERROR_NONE) {
     fd_node* fdn = driver->fds;
     while (fdn != nullptr) {
@@ -329,6 +332,10 @@ static void on_ares_backup_poll_alarm_locked(grpc_ares_ev_driver* driver,
       fdn = fdn->next;
     }
     if (!driver->shutting_down) {
+      // InvalidateNow to avoid getting stuck re-initializing this timer
+      // in a loop while draining the currently-held WorkSerializer.
+      // Also see https://github.com/grpc/grpc/issues/26079.
+      grpc_core::ExecCtx::Get()->InvalidateNow();
       grpc_millis next_ares_backup_poll_alarm =
           calculate_next_ares_backup_poll_alarm_ms(driver);
       grpc_ares_ev_driver_ref(driver);
@@ -345,7 +352,7 @@ static void on_ares_backup_poll_alarm_locked(grpc_ares_ev_driver* driver,
   GRPC_ERROR_UNREF(error);
 }
 
-static void on_readable_locked(fd_node* fdn, grpc_error* error) {
+static void on_readable_locked(fd_node* fdn, grpc_error_handle error) {
   GPR_ASSERT(fdn->readable_registered);
   grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
   const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
@@ -370,14 +377,14 @@ static void on_readable_locked(fd_node* fdn, grpc_error* error) {
   GRPC_ERROR_UNREF(error);
 }
 
-static void on_readable(void* arg, grpc_error* error) {
+static void on_readable(void* arg, grpc_error_handle error) {
   fd_node* fdn = static_cast<fd_node*>(arg);
   GRPC_ERROR_REF(error); /* ref owned by lambda */
   fdn->ev_driver->work_serializer->Run(
       [fdn, error]() { on_readable_locked(fdn, error); }, DEBUG_LOCATION);
 }
 
-static void on_writable_locked(fd_node* fdn, grpc_error* error) {
+static void on_writable_locked(fd_node* fdn, grpc_error_handle error) {
   GPR_ASSERT(fdn->writable_registered);
   grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
   const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
@@ -400,7 +407,7 @@ static void on_writable_locked(fd_node* fdn, grpc_error* error) {
   GRPC_ERROR_UNREF(error);
 }
 
-static void on_writable(void* arg, grpc_error* error) {
+static void on_writable(void* arg, grpc_error_handle error) {
   fd_node* fdn = static_cast<fd_node*>(arg);
   GRPC_ERROR_REF(error); /* ref owned by lambda */
   fdn->ev_driver->work_serializer->Run(
@@ -516,7 +523,7 @@ static void noop_inject_channel_config(ares_channel /*channel*/) {}
 void (*grpc_ares_test_only_inject_config)(ares_channel channel) =
     noop_inject_channel_config;
 
-grpc_error* grpc_ares_ev_driver_create_locked(
+grpc_error_handle grpc_ares_ev_driver_create_locked(
     grpc_ares_ev_driver** ev_driver, grpc_pollset_set* pollset_set,
     int query_timeout_ms,
     std::shared_ptr<grpc_core::WorkSerializer> work_serializer,
@@ -529,7 +536,7 @@ grpc_error* grpc_ares_ev_driver_create_locked(
   grpc_ares_test_only_inject_config((*ev_driver)->channel);
   GRPC_CARES_TRACE_LOG("request:%p grpc_ares_ev_driver_create_locked", request);
   if (status != ARES_SUCCESS) {
-    grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+    grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
         absl::StrCat("Failed to init ares channel. C-ares error: ",
                      ares_strerror(status))
             .c_str());
@@ -713,7 +720,8 @@ static void on_hostbyname_done_locked(void* arg, int status, int /*timeouts*/,
         hr->qtype, hr->host, hr->is_balancer, ares_strerror(status));
     GRPC_CARES_TRACE_LOG("request:%p on_hostbyname_done_locked: %s", r,
                          error_msg.c_str());
-    grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg.c_str());
+    grpc_error_handle error =
+        GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg.c_str());
     r->error = grpc_error_add_child(error, r->error);
   }
   destroy_hostbyname_request_locked(hr);
@@ -757,7 +765,8 @@ static void on_srv_query_done_locked(void* arg, int status, int /*timeouts*/,
         ares_strerror(status));
     GRPC_CARES_TRACE_LOG("request:%p on_srv_query_done_locked: %s", r,
                          error_msg.c_str());
-    grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg.c_str());
+    grpc_error_handle error =
+        GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg.c_str());
     r->error = grpc_error_add_child(error, r->error);
   }
   delete q;
@@ -773,7 +782,7 @@ static void on_txt_done_locked(void* arg, int status, int /*timeouts*/,
   const size_t prefix_len = sizeof(g_service_config_attribute_prefix) - 1;
   struct ares_txt_ext* result = nullptr;
   struct ares_txt_ext* reply = nullptr;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (status != ARES_SUCCESS) goto fail;
   GRPC_CARES_TRACE_LOG("request:%p on_txt_done_locked name=%s ARES_SUCCESS", r,
                        q->name().c_str());
@@ -825,7 +834,7 @@ void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
     const char* default_port, grpc_pollset_set* interested_parties,
     int query_timeout_ms,
     std::shared_ptr<grpc_core::WorkSerializer> work_serializer) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_ares_hostbyname_request* hr = nullptr;
   /* parse name, splitting it into host and port parts */
   std::string host;
@@ -1116,7 +1125,7 @@ void (*grpc_cancel_ares_request_locked)(grpc_ares_request* r) =
 // Windows. Calling them may cause race conditions when other parts of the
 // binary calls these functions concurrently.
 #ifdef GPR_WINDOWS
-grpc_error* grpc_ares_init(void) {
+grpc_error_handle grpc_ares_init(void) {
   int status = ares_library_init(ARES_LIB_INIT_ALL);
   if (status != ARES_SUCCESS) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -1128,7 +1137,7 @@ grpc_error* grpc_ares_init(void) {
 
 void grpc_ares_cleanup(void) { ares_library_cleanup(); }
 #else
-grpc_error* grpc_ares_init(void) { return GRPC_ERROR_NONE; }
+grpc_error_handle grpc_ares_init(void) { return GRPC_ERROR_NONE; }
 void grpc_ares_cleanup(void) {}
 #endif  // GPR_WINDOWS
 
@@ -1159,7 +1168,7 @@ typedef struct grpc_resolve_address_ares_request {
 } grpc_resolve_address_ares_request;
 
 static void on_dns_lookup_done_locked(grpc_resolve_address_ares_request* r,
-                                      grpc_error* error) {
+                                      grpc_error_handle error) {
   gpr_free(r->ares_request);
   grpc_resolved_addresses** resolved_addresses = r->addrs_out;
   if (r->addresses == nullptr || r->addresses->empty()) {
@@ -1180,7 +1189,7 @@ static void on_dns_lookup_done_locked(grpc_resolve_address_ares_request* r,
   delete r;
 }
 
-static void on_dns_lookup_done(void* arg, grpc_error* error) {
+static void on_dns_lookup_done(void* arg, grpc_error_handle error) {
   grpc_resolve_address_ares_request* r =
       static_cast<grpc_resolve_address_ares_request*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
index 6c29bb6..675dfc8 100644 (file)
@@ -76,7 +76,7 @@ extern void (*grpc_cancel_ares_request_locked)(grpc_ares_request* request);
 
 /* Initialize gRPC ares wrapper. Must be called at least once before
    grpc_resolve_address_ares(). */
-grpc_error* grpc_ares_init(void);
+grpc_error_handle grpc_ares_init(void);
 
 /* Uninitialized gRPC ares wrapper. If there was more than one previous call to
    grpc_ares_init(), this function uninitializes the gRPC ares wrapper only if
index 1d4a90f..8735aa8 100644 (file)
@@ -25,8 +25,8 @@
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/iomgr/parse_address.h"
 
 bool grpc_ares_query_ipv6() {
   /* The libuv grpc code currently does not have the code to probe for this,
index df11db3..f76c6a4 100644 (file)
@@ -25,8 +25,8 @@
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 
 bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); }
index e5ebd11..3265e29 100644 (file)
@@ -68,10 +68,10 @@ class NativeDnsResolver : public Resolver {
   void MaybeStartResolvingLocked();
   void StartResolvingLocked();
 
-  static void OnNextResolution(void* arg, grpc_error* error);
-  void OnNextResolutionLocked(grpc_error* error);
-  static void OnResolved(void* arg, grpc_error* error);
-  void OnResolvedLocked(grpc_error* error);
+  static void OnNextResolution(void* arg, grpc_error_handle error);
+  void OnNextResolutionLocked(grpc_error_handle error);
+  static void OnResolved(void* arg, grpc_error_handle error);
+  void OnResolvedLocked(grpc_error_handle error);
 
   /// name to resolve
   std::string name_to_resolve_;
@@ -148,14 +148,14 @@ void NativeDnsResolver::ShutdownLocked() {
   }
 }
 
-void NativeDnsResolver::OnNextResolution(void* arg, grpc_error* error) {
+void NativeDnsResolver::OnNextResolution(void* arg, grpc_error_handle error) {
   NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   r->work_serializer_->Run([r, error]() { r->OnNextResolutionLocked(error); },
                            DEBUG_LOCATION);
 }
 
-void NativeDnsResolver::OnNextResolutionLocked(grpc_error* error) {
+void NativeDnsResolver::OnNextResolutionLocked(grpc_error_handle error) {
   have_next_resolution_timer_ = false;
   if (error == GRPC_ERROR_NONE && !resolving_) {
     StartResolvingLocked();
@@ -164,14 +164,14 @@ void NativeDnsResolver::OnNextResolutionLocked(grpc_error* error) {
   GRPC_ERROR_UNREF(error);
 }
 
-void NativeDnsResolver::OnResolved(void* arg, grpc_error* error) {
+void NativeDnsResolver::OnResolved(void* arg, grpc_error_handle error) {
   NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
   GRPC_ERROR_REF(error);  // owned by lambda
   r->work_serializer_->Run([r, error]() { r->OnResolvedLocked(error); },
                            DEBUG_LOCATION);
 }
 
-void NativeDnsResolver::OnResolvedLocked(grpc_error* error) {
+void NativeDnsResolver::OnResolvedLocked(grpc_error_handle error) {
   GPR_ASSERT(resolving_);
   resolving_ = false;
   if (shutdown_) {
@@ -194,7 +194,7 @@ void NativeDnsResolver::OnResolvedLocked(grpc_error* error) {
     backoff_.Reset();
   } else {
     gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     // Return transient error.
     std::string error_message =
         absl::StrCat("DNS resolution failed for service: ", name_to_resolve_);
@@ -203,6 +203,10 @@ void NativeDnsResolver::OnResolvedLocked(grpc_error* error) {
                                                          &error, 1),
         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
     // Set up for retry.
+    // InvalidateNow to avoid getting stuck re-initializing this timer
+    // in a loop while draining the currently-held WorkSerializer.
+    // Also see https://github.com/grpc/grpc/issues/26079.
+    ExecCtx::Get()->InvalidateNow();
     grpc_millis next_try = backoff_.NextAttemptTime();
     grpc_millis timeout = next_try - ExecCtx::Get()->Now();
     GPR_ASSERT(!have_next_resolution_timer_);
@@ -229,6 +233,10 @@ void NativeDnsResolver::MaybeStartResolvingLocked() {
   // can start the next resolution.
   if (have_next_resolution_timer_) return;
   if (last_resolution_timestamp_ >= 0) {
+    // InvalidateNow to avoid getting stuck re-initializing this timer
+    // in a loop while draining the currently-held WorkSerializer.
+    // Also see https://github.com/grpc/grpc/issues/26079.
+    ExecCtx::Get()->InvalidateNow();
     const grpc_millis earliest_next_resolution =
         last_resolution_timestamp_ + min_time_between_resolutions_;
     const grpc_millis ms_until_next_resolution =
index 56c1682..7978d59 100644 (file)
 
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/closure.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 #include "src/core/lib/iomgr/work_serializer.h"
@@ -313,48 +313,40 @@ void FakeResolverResponseGenerator::SetFakeResolver(
 
 namespace {
 
-static void* response_generator_arg_copy(void* p) {
-  FakeResolverResponseGenerator* generator =
-      static_cast<FakeResolverResponseGenerator*>(p);
-  // TODO(roth): We currently deal with this ref manually.  Once the
-  // new channel args code is converted to C++, find a way to track this ref
-  // in a cleaner way.
-  RefCountedPtr<FakeResolverResponseGenerator> copy = generator->Ref();
-  copy.release();
+void* ResponseGeneratorChannelArgCopy(void* p) {
+  auto* generator = static_cast<FakeResolverResponseGenerator*>(p);
+  generator->Ref().release();
   return p;
 }
 
-static void response_generator_arg_destroy(void* p) {
-  FakeResolverResponseGenerator* generator =
-      static_cast<FakeResolverResponseGenerator*>(p);
+void ResponseGeneratorChannelArgDestroy(void* p) {
+  auto* generator = static_cast<FakeResolverResponseGenerator*>(p);
   generator->Unref();
 }
 
-static int response_generator_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
-
-static const grpc_arg_pointer_vtable response_generator_arg_vtable = {
-    response_generator_arg_copy, response_generator_arg_destroy,
-    response_generator_cmp};
+int ResponseGeneratorChannelArgCmp(void* a, void* b) { return GPR_ICMP(a, b); }
 
 }  // namespace
 
+const grpc_arg_pointer_vtable
+    FakeResolverResponseGenerator::kChannelArgPointerVtable = {
+        ResponseGeneratorChannelArgCopy, ResponseGeneratorChannelArgDestroy,
+        ResponseGeneratorChannelArgCmp};
+
 grpc_arg FakeResolverResponseGenerator::MakeChannelArg(
     FakeResolverResponseGenerator* generator) {
-  grpc_arg arg;
-  arg.type = GRPC_ARG_POINTER;
-  arg.key = const_cast<char*>(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
-  arg.value.pointer.p = generator;
-  arg.value.pointer.vtable = &response_generator_arg_vtable;
-  return arg;
+  return grpc_channel_arg_pointer_create(
+      const_cast<char*>(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR), generator,
+      &kChannelArgPointerVtable);
 }
 
 RefCountedPtr<FakeResolverResponseGenerator>
 FakeResolverResponseGenerator::GetFromArgs(const grpc_channel_args* args) {
-  const grpc_arg* arg =
-      grpc_channel_args_find(args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
-  if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return nullptr;
-  return static_cast<FakeResolverResponseGenerator*>(arg->value.pointer.p)
-      ->Ref();
+  auto* response_generator =
+      grpc_channel_args_find_pointer<FakeResolverResponseGenerator>(
+          args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
+  if (response_generator == nullptr) return nullptr;
+  return response_generator->Ref();
 }
 
 //
index b9ca69d..94d7c22 100644 (file)
@@ -42,6 +42,8 @@ class FakeResolver;
 class FakeResolverResponseGenerator
     : public RefCounted<FakeResolverResponseGenerator> {
  public:
+  static const grpc_arg_pointer_vtable kChannelArgPointerVtable;
+
   FakeResolverResponseGenerator();
   ~FakeResolverResponseGenerator() override;
 
@@ -69,6 +71,7 @@ class FakeResolverResponseGenerator
   void SetFailureOnReresolution();
 
   // Returns a channel arg containing \a generator.
+  // TODO(roth): When we have time, make this a non-static method.
   static grpc_arg MakeChannelArg(FakeResolverResponseGenerator* generator);
 
   // Returns the response generator in \a args, or null if not found.
@@ -82,12 +85,11 @@ class FakeResolverResponseGenerator
 
   // Mutex protecting the members below.
   Mutex mu_;
-  RefCountedPtr<FakeResolver> resolver_;
-  Resolver::Result result_;
-  bool has_result_ = false;
+  RefCountedPtr<FakeResolver> resolver_ ABSL_GUARDED_BY(mu_);
+  Resolver::Result result_ ABSL_GUARDED_BY(mu_);
+  bool has_result_ ABSL_GUARDED_BY(mu_) = false;
 };
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H \
-        */
+#endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H
index 3488ebc..208ec67 100644 (file)
@@ -48,15 +48,15 @@ class GoogleCloud2ProdResolver : public Resolver {
     void Orphan() override;
 
    private:
-    static void OnHttpRequestDone(void* arg, grpc_error* error);
+    static void OnHttpRequestDone(void* arg, grpc_error_handle error);
 
     // Calls OnDone() if not already called.  Releases a ref.
-    void MaybeCallOnDone(grpc_error* error);
+    void MaybeCallOnDone(grpc_error_handle error);
 
     // If error is not GRPC_ERROR_NONE, then it's not safe to look at response.
     virtual void OnDone(GoogleCloud2ProdResolver* resolver,
                         const grpc_http_response* response,
-                        grpc_error* error) = 0;
+                        grpc_error_handle error) = 0;
 
     RefCountedPtr<GoogleCloud2ProdResolver> resolver_;
     grpc_httpcli_context context_;
@@ -73,7 +73,8 @@ class GoogleCloud2ProdResolver : public Resolver {
 
    private:
     void OnDone(GoogleCloud2ProdResolver* resolver,
-                const grpc_http_response* response, grpc_error* error) override;
+                const grpc_http_response* response,
+                grpc_error_handle error) override;
   };
 
   // A metadata server query to get the IPv6 address.
@@ -84,7 +85,8 @@ class GoogleCloud2ProdResolver : public Resolver {
 
    private:
     void OnDone(GoogleCloud2ProdResolver* resolver,
-                const grpc_http_response* response, grpc_error* error) override;
+                const grpc_http_response* response,
+                grpc_error_handle error) override;
   };
 
   void ZoneQueryDone(std::string zone);
@@ -143,13 +145,13 @@ void GoogleCloud2ProdResolver::MetadataQuery::Orphan() {
 }
 
 void GoogleCloud2ProdResolver::MetadataQuery::OnHttpRequestDone(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   auto* self = static_cast<MetadataQuery*>(arg);
   self->MaybeCallOnDone(GRPC_ERROR_REF(error));
 }
 
 void GoogleCloud2ProdResolver::MetadataQuery::MaybeCallOnDone(
-    grpc_error* error) {
+    grpc_error_handle error) {
   bool expected = false;
   if (!on_done_called_.CompareExchangeStrong(
           &expected, true, MemoryOrder::RELAXED, MemoryOrder::RELAXED)) {
@@ -180,10 +182,10 @@ GoogleCloud2ProdResolver::ZoneQuery::ZoneQuery(
 
 void GoogleCloud2ProdResolver::ZoneQuery::OnDone(
     GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "error fetching zone from metadata server: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   std::string zone;
   if (error == GRPC_ERROR_NONE && response->status == 200) {
@@ -213,10 +215,10 @@ GoogleCloud2ProdResolver::IPv6Query::IPv6Query(
 
 void GoogleCloud2ProdResolver::IPv6Query::OnDone(
     GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "error fetching IPv6 address from metadata server: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   resolver->IPv6QueryDone(error == GRPC_ERROR_NONE && response->status == 200);
   GRPC_ERROR_UNREF(error);
index f50bb7e..46efbb0 100644 (file)
@@ -30,9 +30,9 @@
 
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 #include "src/core/lib/slice/slice_internal.h"
index a88c6a3..3a10a42 100644 (file)
@@ -28,6 +28,7 @@
 #include "src/core/ext/filters/client_channel/config_selector.h"
 #include "src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/ext/xds/xds_channel_args.h"
 #include "src/core/ext/xds/xds_client.h"
 #include "src/core/ext/xds/xds_http_filters.h"
 #include "src/core/lib/channel/channel_args.h"
@@ -73,19 +74,23 @@ class XdsResolver : public Resolver {
 
   void ShutdownLocked() override;
 
+  void ResetBackoffLocked() override {
+    if (xds_client_ != nullptr) xds_client_->ResetBackoff();
+  }
+
  private:
   class Notifier {
    public:
     Notifier(RefCountedPtr<XdsResolver> resolver, XdsApi::LdsUpdate update);
     Notifier(RefCountedPtr<XdsResolver> resolver, XdsApi::RdsUpdate update);
-    Notifier(RefCountedPtr<XdsResolver> resolver, grpc_error* error);
+    Notifier(RefCountedPtr<XdsResolver> resolver, grpc_error_handle error);
     explicit Notifier(RefCountedPtr<XdsResolver> resolver);
 
    private:
     enum Type { kLdsUpdate, kRdsUpdate, kError, kDoesNotExist };
 
-    static void RunInExecCtx(void* arg, grpc_error* error);
-    void RunInWorkSerializer(grpc_error* error);
+    static void RunInExecCtx(void* arg, grpc_error_handle error);
+    void RunInWorkSerializer(grpc_error_handle error);
 
     RefCountedPtr<XdsResolver> resolver_;
     grpc_closure closure_;
@@ -100,7 +105,9 @@ class XdsResolver : public Resolver {
     void OnListenerChanged(XdsApi::LdsUpdate listener) override {
       new Notifier(resolver_, std::move(listener));
     }
-    void OnError(grpc_error* error) override { new Notifier(resolver_, error); }
+    void OnError(grpc_error_handle error) override {
+      new Notifier(resolver_, error);
+    }
     void OnResourceDoesNotExist() override { new Notifier(resolver_); }
 
    private:
@@ -114,7 +121,9 @@ class XdsResolver : public Resolver {
     void OnRouteConfigChanged(XdsApi::RdsUpdate route_config) override {
       new Notifier(resolver_, std::move(route_config));
     }
-    void OnError(grpc_error* error) override { new Notifier(resolver_, error); }
+    void OnError(grpc_error_handle error) override {
+      new Notifier(resolver_, error);
+    }
     void OnResourceDoesNotExist() override { new Notifier(resolver_); }
 
    private:
@@ -122,7 +131,7 @@ class XdsResolver : public Resolver {
   };
 
   class ClusterState
-      : public RefCounted<ClusterState, PolymorphicRefCount, false> {
+      : public RefCounted<ClusterState, PolymorphicRefCount, kUnrefNoDelete> {
    public:
     using ClusterStateMap =
         std::map<std::string, std::unique_ptr<ClusterState>>;
@@ -140,7 +149,8 @@ class XdsResolver : public Resolver {
 
   class XdsConfigSelector : public ConfigSelector {
    public:
-    XdsConfigSelector(RefCountedPtr<XdsResolver> resolver, grpc_error** error);
+    XdsConfigSelector(RefCountedPtr<XdsResolver> resolver,
+                      grpc_error_handle* error);
     ~XdsConfigSelector() override;
 
     const char* name() const override { return "XdsConfigSelector"; }
@@ -179,7 +189,7 @@ class XdsResolver : public Resolver {
     using RouteTable = std::vector<Route>;
 
     void MaybeAddCluster(const std::string& name);
-    grpc_error* CreateMethodConfig(
+    grpc_error_handle CreateMethodConfig(
         const XdsApi::Route& route,
         const XdsApi::Route::ClusterWeight* cluster_weight,
         RefCountedPtr<ServiceConfig>* method_config);
@@ -188,15 +198,16 @@ class XdsResolver : public Resolver {
     RouteTable route_table_;
     std::map<absl::string_view, RefCountedPtr<ClusterState>> clusters_;
     std::vector<const grpc_channel_filter*> filters_;
-    grpc_error* filter_error_ = GRPC_ERROR_NONE;
+    grpc_error_handle filter_error_ = GRPC_ERROR_NONE;
   };
 
   void OnListenerUpdate(XdsApi::LdsUpdate listener);
   void OnRouteConfigUpdate(XdsApi::RdsUpdate rds_update);
-  void OnError(grpc_error* error);
+  void OnError(grpc_error_handle error);
   void OnResourceDoesNotExist();
 
-  grpc_error* CreateServiceConfig(RefCountedPtr<ServiceConfig>* service_config);
+  grpc_error_handle CreateServiceConfig(
+      RefCountedPtr<ServiceConfig>* service_config);
   void GenerateResult();
   void MaybeRemoveUnusedClusters();
 
@@ -243,7 +254,7 @@ XdsResolver::Notifier::Notifier(RefCountedPtr<XdsResolver> resolver,
 }
 
 XdsResolver::Notifier::Notifier(RefCountedPtr<XdsResolver> resolver,
-                                grpc_error* error)
+                                grpc_error_handle error)
     : resolver_(std::move(resolver)), type_(kError) {
   GRPC_CLOSURE_INIT(&closure_, &RunInExecCtx, this, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &closure_, error);
@@ -255,14 +266,14 @@ XdsResolver::Notifier::Notifier(RefCountedPtr<XdsResolver> resolver)
   ExecCtx::Run(DEBUG_LOCATION, &closure_, GRPC_ERROR_NONE);
 }
 
-void XdsResolver::Notifier::RunInExecCtx(void* arg, grpc_error* error) {
+void XdsResolver::Notifier::RunInExecCtx(void* arg, grpc_error_handle error) {
   Notifier* self = static_cast<Notifier*>(arg);
   GRPC_ERROR_REF(error);
   self->resolver_->work_serializer_->Run(
       [self, error]() { self->RunInWorkSerializer(error); }, DEBUG_LOCATION);
 }
 
-void XdsResolver::Notifier::RunInWorkSerializer(grpc_error* error) {
+void XdsResolver::Notifier::RunInWorkSerializer(grpc_error_handle error) {
   if (resolver_->xds_client_ == nullptr) {
     GRPC_ERROR_UNREF(error);
     delete this;
@@ -314,7 +325,7 @@ bool XdsResolver::XdsConfigSelector::Route::operator==(
 //
 
 XdsResolver::XdsConfigSelector::XdsConfigSelector(
-    RefCountedPtr<XdsResolver> resolver, grpc_error** error)
+    RefCountedPtr<XdsResolver> resolver, grpc_error_handle* error)
     : resolver_(std::move(resolver)) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
     gpr_log(GPR_INFO, "[xds_resolver %p] creating XdsConfigSelector %p",
@@ -425,7 +436,7 @@ const XdsHttpFilterImpl::FilterConfig* FindFilterConfigOverride(
   return nullptr;
 }
 
-grpc_error* XdsResolver::XdsConfigSelector::CreateMethodConfig(
+grpc_error_handle XdsResolver::XdsConfigSelector::CreateMethodConfig(
     const XdsApi::Route& route,
     const XdsApi::Route::ClusterWeight* cluster_weight,
     RefCountedPtr<ServiceConfig>* method_config) {
@@ -482,7 +493,7 @@ grpc_error* XdsResolver::XdsConfigSelector::CreateMethodConfig(
                                      "\n    ]"));
   }
   // Construct service config.
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (!fields.empty()) {
     std::string json = absl::StrCat(
         "{\n"
@@ -684,7 +695,7 @@ ConfigSelector::CallConfig XdsResolver::XdsConfigSelector::GetCallConfig(
           // the data plane mutex.
           DEBUG_LOCATION,
           GRPC_CLOSURE_CREATE(
-              [](void* arg, grpc_error* /*error*/) {
+              [](void* arg, grpc_error_handle /*error*/) {
                 auto* resolver = static_cast<XdsResolver*>(arg);
                 resolver->work_serializer_->Run(
                     [resolver]() {
@@ -706,13 +717,13 @@ ConfigSelector::CallConfig XdsResolver::XdsConfigSelector::GetCallConfig(
 //
 
 void XdsResolver::StartLocked() {
-  grpc_error* error = GRPC_ERROR_NONE;
-  xds_client_ = XdsClient::GetOrCreate(&error);
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  xds_client_ = XdsClient::GetOrCreate(args_, &error);
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "Failed to create xds client -- channel will remain in "
             "TRANSIENT_FAILURE: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     result_handler_->ReturnError(error);
     return;
   }
@@ -809,11 +820,12 @@ void XdsResolver::OnRouteConfigUpdate(XdsApi::RdsUpdate rds_update) {
   GenerateResult();
 }
 
-void XdsResolver::OnError(grpc_error* error) {
+void XdsResolver::OnError(grpc_error_handle error) {
   gpr_log(GPR_ERROR, "[xds_resolver %p] received error from XdsClient: %s",
-          this, grpc_error_string(error));
+          this, grpc_error_std_string(error).c_str());
   Result result;
-  result.args = grpc_channel_args_copy(args_);
+  grpc_arg new_arg = xds_client_->MakeChannelArg();
+  result.args = grpc_channel_args_copy_and_add(args_, &new_arg, 1);
   result.service_config_error = error;
   result_handler_->ReturnResult(std::move(result));
 }
@@ -832,7 +844,7 @@ void XdsResolver::OnResourceDoesNotExist() {
   result_handler_->ReturnResult(std::move(result));
 }
 
-grpc_error* XdsResolver::CreateServiceConfig(
+grpc_error_handle XdsResolver::CreateServiceConfig(
     RefCountedPtr<ServiceConfig>* service_config) {
   std::vector<std::string> clusters;
   for (const auto& cluster : cluster_state_map_) {
@@ -859,7 +871,7 @@ grpc_error* XdsResolver::CreateServiceConfig(
       "  ]\n"
       "}");
   std::string json = absl::StrJoin(config_parts, "");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   *service_config = ServiceConfig::Create(args_, json.c_str(), &error);
   return error;
 }
@@ -868,7 +880,7 @@ void XdsResolver::GenerateResult() {
   if (current_virtual_host_.routes.empty()) return;
   // First create XdsConfigSelector, which may add new entries to the cluster
   // state map, and then CreateServiceConfig for LB policies.
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto config_selector = MakeRefCounted<XdsConfigSelector>(Ref(), &error);
   if (error != GRPC_ERROR_NONE) {
     OnError(error);
@@ -884,8 +896,12 @@ void XdsResolver::GenerateResult() {
     gpr_log(GPR_INFO, "[xds_resolver %p] generated service config: %s", this,
             result.service_config->json_string().c_str());
   }
-  grpc_arg new_arg = config_selector->MakeChannelArg();
-  result.args = grpc_channel_args_copy_and_add(args_, &new_arg, 1);
+  grpc_arg new_args[] = {
+      xds_client_->MakeChannelArg(),
+      config_selector->MakeChannelArg(),
+  };
+  result.args =
+      grpc_channel_args_copy_and_add(args_, new_args, GPR_ARRAY_SIZE(new_args));
   result_handler_->ReturnResult(std::move(result));
 }
 
index 500c740..b0c8eeb 100644 (file)
@@ -1,20 +1,18 @@
-/*
- *
- * 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.
- *
- */
+//
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 
 #include <grpc/support/port_platform.h>
 
@@ -63,200 +61,15 @@ void ClientChannelServiceConfigParser::Register() {
 
 namespace {
 
-std::unique_ptr<ClientChannelMethodParsedConfig::RetryPolicy> ParseRetryPolicy(
-    const Json& json, grpc_error** error) {
-  GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
-  auto retry_policy =
-      absl::make_unique<ClientChannelMethodParsedConfig::RetryPolicy>();
-  if (json.type() != Json::Type::OBJECT) {
-    *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryPolicy error:should be of type object");
-    return nullptr;
-  }
-  std::vector<grpc_error*> error_list;
-  // Parse maxAttempts.
-  auto it = json.object_value().find("maxAttempts");
-  if (it != json.object_value().end()) {
-    if (it->second.type() != Json::Type::NUMBER) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:maxAttempts error:should be of type number"));
-    } else {
-      retry_policy->max_attempts =
-          gpr_parse_nonnegative_int(it->second.string_value().c_str());
-      if (retry_policy->max_attempts <= 1) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:maxAttempts error:should be at least 2"));
-      } else if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
-        gpr_log(GPR_ERROR,
-                "service config: clamped retryPolicy.maxAttempts at %d",
-                MAX_MAX_RETRY_ATTEMPTS);
-        retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS;
-      }
-    }
-  }
-  // Parse initialBackoff.
-  if (ParseJsonObjectFieldAsDuration(json.object_value(), "initialBackoff",
-                                     &retry_policy->initial_backoff,
-                                     &error_list) &&
-      retry_policy->initial_backoff == 0) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:initialBackoff error:must be greater than 0"));
-  }
-  // Parse maxBackoff.
-  if (ParseJsonObjectFieldAsDuration(json.object_value(), "maxBackoff",
-                                     &retry_policy->max_backoff, &error_list) &&
-      retry_policy->max_backoff == 0) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:maxBackoff error:should be greater than 0"));
-  }
-  // Parse backoffMultiplier.
-  it = json.object_value().find("backoffMultiplier");
-  if (it != json.object_value().end()) {
-    if (it->second.type() != Json::Type::NUMBER) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:backoffMultiplier error:should be of type number"));
-    } else {
-      if (sscanf(it->second.string_value().c_str(), "%f",
-                 &retry_policy->backoff_multiplier) != 1) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:backoffMultiplier error:failed to parse"));
-      } else if (retry_policy->backoff_multiplier <= 0) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:backoffMultiplier error:should be greater than 0"));
-      }
-    }
-  }
-  // Parse retryableStatusCodes.
-  it = json.object_value().find("retryableStatusCodes");
-  if (it != json.object_value().end()) {
-    if (it->second.type() != Json::Type::ARRAY) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryableStatusCodes error:should be of type array"));
-    } else {
-      for (const Json& element : it->second.array_value()) {
-        if (element.type() != Json::Type::STRING) {
-          error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-              "field:retryableStatusCodes error:status codes should be of type "
-              "string"));
-          continue;
-        }
-        grpc_status_code status;
-        if (!grpc_status_code_from_string(element.string_value().c_str(),
-                                          &status)) {
-          error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-              "field:retryableStatusCodes error:failed to parse status code"));
-          continue;
-        }
-        retry_policy->retryable_status_codes.Add(status);
-      }
-      if (retry_policy->retryable_status_codes.Empty()) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:retryableStatusCodes error:should be non-empty"));
-      };
-    }
-  }
-  // Make sure required fields are set.
-  if (error_list.empty()) {
-    if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 ||
-        retry_policy->max_backoff == 0 ||
-        retry_policy->backoff_multiplier == 0 ||
-        retry_policy->retryable_status_codes.Empty()) {
-      *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryPolicy error:Missing required field(s)");
-      return nullptr;
-    }
-  }
-  *error = GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
-  return *error == GRPC_ERROR_NONE ? std::move(retry_policy) : nullptr;
-}
-
-grpc_error* ParseRetryThrottling(
-    const Json& json,
-    ClientChannelGlobalParsedConfig::RetryThrottling* retry_throttling) {
-  if (json.type() != Json::Type::OBJECT) {
-    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling error:Type should be object");
-  }
-  std::vector<grpc_error*> error_list;
-  // Parse maxTokens.
-  auto it = json.object_value().find("maxTokens");
-  if (it == json.object_value().end()) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling field:maxTokens error:Not found"));
-  } else if (it->second.type() != Json::Type::NUMBER) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling field:maxTokens error:Type should be "
-        "number"));
-  } else {
-    retry_throttling->max_milli_tokens =
-        gpr_parse_nonnegative_int(it->second.string_value().c_str()) * 1000;
-    if (retry_throttling->max_milli_tokens <= 0) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryThrottling field:maxTokens error:should be "
-          "greater than zero"));
-    }
-  }
-  // Parse tokenRatio.
-  it = json.object_value().find("tokenRatio");
-  if (it == json.object_value().end()) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling field:tokenRatio error:Not found"));
-  } else if (it->second.type() != Json::Type::NUMBER) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling field:tokenRatio error:type should be "
-        "number"));
-  } else {
-    // We support up to 3 decimal digits.
-    size_t whole_len = it->second.string_value().size();
-    const char* value = it->second.string_value().c_str();
-    uint32_t multiplier = 1;
-    uint32_t decimal_value = 0;
-    const char* decimal_point = strchr(value, '.');
-    if (decimal_point != nullptr) {
-      whole_len = static_cast<size_t>(decimal_point - value);
-      multiplier = 1000;
-      size_t decimal_len = strlen(decimal_point + 1);
-      if (decimal_len > 3) decimal_len = 3;
-      if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
-                                     &decimal_value)) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:retryThrottling field:tokenRatio error:Failed "
-            "parsing"));
-        return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
-      }
-      uint32_t decimal_multiplier = 1;
-      for (size_t i = 0; i < (3 - decimal_len); ++i) {
-        decimal_multiplier *= 10;
-      }
-      decimal_value *= decimal_multiplier;
-    }
-    uint32_t whole_value;
-    if (!gpr_parse_bytes_to_uint32(value, whole_len, &whole_value)) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryThrottling field:tokenRatio error:Failed "
-          "parsing"));
-      return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
-    }
-    retry_throttling->milli_token_ratio =
-        static_cast<int>((whole_value * multiplier) + decimal_value);
-    if (retry_throttling->milli_token_ratio <= 0) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryThrottling field:tokenRatio error:value should "
-          "be greater than 0"));
-    }
-  }
-  return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
-}
-
 absl::optional<std::string> ParseHealthCheckConfig(const Json& field,
-                                                   grpc_error** error) {
+                                                   grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
   if (field.type() != Json::Type::OBJECT) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "field:healthCheckConfig error:should be of type object");
     return absl::nullopt;
   }
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   absl::optional<std::string> service_name;
   auto it = field.object_value().find("serviceName");
   if (it != field.object_value().end()) {
@@ -276,18 +89,19 @@ absl::optional<std::string> ParseHealthCheckConfig(const Json& field,
 
 std::unique_ptr<ServiceConfigParser::ParsedConfig>
 ClientChannelServiceConfigParser::ParseGlobalParams(
-    const grpc_channel_args* /*args*/, const Json& json, grpc_error** error) {
+    const grpc_channel_args* /*args*/, const Json& json,
+    grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   // Parse LB config.
   RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
   auto it = json.object_value().find("loadBalancingConfig");
   if (it != json.object_value().end()) {
-    grpc_error* parse_error = GRPC_ERROR_NONE;
+    grpc_error_handle parse_error = GRPC_ERROR_NONE;
     parsed_lb_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
         it->second, &parse_error);
     if (parsed_lb_config == nullptr) {
-      std::vector<grpc_error*> lb_errors;
+      std::vector<grpc_error_handle> lb_errors;
       lb_errors.push_back(parse_error);
       error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
           "field:loadBalancingConfig", &lb_errors));
@@ -319,24 +133,11 @@ ClientChannelServiceConfigParser::ParseGlobalParams(
       }
     }
   }
-  // Parse retry throttling.
-  absl::optional<ClientChannelGlobalParsedConfig::RetryThrottling>
-      retry_throttling;
-  it = json.object_value().find("retryThrottling");
-  if (it != json.object_value().end()) {
-    ClientChannelGlobalParsedConfig::RetryThrottling data;
-    grpc_error* parsing_error = ParseRetryThrottling(it->second, &data);
-    if (parsing_error != GRPC_ERROR_NONE) {
-      error_list.push_back(parsing_error);
-    } else {
-      retry_throttling.emplace(data);
-    }
-  }
   // Parse health check config.
   absl::optional<std::string> health_check_service_name;
   it = json.object_value().find("healthCheckConfig");
   if (it != json.object_value().end()) {
-    grpc_error* parsing_error = GRPC_ERROR_NONE;
+    grpc_error_handle parsing_error = GRPC_ERROR_NONE;
     health_check_service_name =
         ParseHealthCheckConfig(it->second, &parsing_error);
     if (parsing_error != GRPC_ERROR_NONE) {
@@ -348,20 +149,19 @@ ClientChannelServiceConfigParser::ParseGlobalParams(
   if (*error == GRPC_ERROR_NONE) {
     return absl::make_unique<ClientChannelGlobalParsedConfig>(
         std::move(parsed_lb_config), std::move(lb_policy_name),
-        retry_throttling, std::move(health_check_service_name));
+        std::move(health_check_service_name));
   }
   return nullptr;
 }
 
 std::unique_ptr<ServiceConfigParser::ParsedConfig>
 ClientChannelServiceConfigParser::ParsePerMethodParams(
-    const grpc_channel_args* /*args*/, const Json& json, grpc_error** error) {
+    const grpc_channel_args* /*args*/, const Json& json,
+    grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
-  std::vector<grpc_error*> error_list;
-  absl::optional<bool> wait_for_ready;
-  grpc_millis timeout = 0;
-  std::unique_ptr<ClientChannelMethodParsedConfig::RetryPolicy> retry_policy;
+  std::vector<grpc_error_handle> error_list;
   // Parse waitForReady.
+  absl::optional<bool> wait_for_ready;
   auto it = json.object_value().find("waitForReady");
   if (it != json.object_value().end()) {
     if (it->second.type() == Json::Type::JSON_TRUE) {
@@ -374,21 +174,14 @@ ClientChannelServiceConfigParser::ParsePerMethodParams(
     }
   }
   // Parse timeout.
+  grpc_millis timeout = 0;
   ParseJsonObjectFieldAsDuration(json.object_value(), "timeout", &timeout,
                                  &error_list, false);
-  // Parse retry policy.
-  it = json.object_value().find("retryPolicy");
-  if (it != json.object_value().end()) {
-    grpc_error* error = GRPC_ERROR_NONE;
-    retry_policy = ParseRetryPolicy(it->second, &error);
-    if (retry_policy == nullptr) {
-      error_list.push_back(error);
-    }
-  }
+  // Return result.
   *error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel parser", &error_list);
   if (*error == GRPC_ERROR_NONE) {
-    return absl::make_unique<ClientChannelMethodParsedConfig>(
-        timeout, wait_for_ready, std::move(retry_policy));
+    return absl::make_unique<ClientChannelMethodParsedConfig>(timeout,
+                                                              wait_for_ready);
   }
   return nullptr;
 }
index cdf89d3..b70068e 100644 (file)
@@ -1,20 +1,18 @@
-/*
- *
- * 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.
- *
- */
+//
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H
@@ -26,7 +24,6 @@
 #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"
-#include "src/core/ext/filters/client_channel/retry_throttle.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
 #include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/gprpp/ref_counted.h"
@@ -40,19 +37,12 @@ namespace internal {
 class ClientChannelGlobalParsedConfig
     : public ServiceConfigParser::ParsedConfig {
  public:
-  struct RetryThrottling {
-    intptr_t max_milli_tokens = 0;
-    intptr_t milli_token_ratio = 0;
-  };
-
   ClientChannelGlobalParsedConfig(
       RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config,
       std::string parsed_deprecated_lb_policy,
-      const absl::optional<RetryThrottling>& retry_throttling,
       absl::optional<std::string> health_check_service_name)
       : parsed_lb_config_(std::move(parsed_lb_config)),
         parsed_deprecated_lb_policy_(std::move(parsed_deprecated_lb_policy)),
-        retry_throttling_(retry_throttling),
         health_check_service_name_(std::move(health_check_service_name)) {}
 
   RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config() const {
@@ -63,10 +53,6 @@ class ClientChannelGlobalParsedConfig
     return parsed_deprecated_lb_policy_;
   }
 
-  absl::optional<RetryThrottling> retry_throttling() const {
-    return retry_throttling_;
-  }
-
   const absl::optional<std::string>& health_check_service_name() const {
     return health_check_service_name_;
   }
@@ -74,49 +60,34 @@ class ClientChannelGlobalParsedConfig
  private:
   RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_;
   std::string parsed_deprecated_lb_policy_;
-  absl::optional<RetryThrottling> retry_throttling_;
   absl::optional<std::string> health_check_service_name_;
 };
 
 class ClientChannelMethodParsedConfig
     : public ServiceConfigParser::ParsedConfig {
  public:
-  struct RetryPolicy {
-    int max_attempts = 0;
-    grpc_millis initial_backoff = 0;
-    grpc_millis max_backoff = 0;
-    float backoff_multiplier = 0;
-    StatusCodeSet retryable_status_codes;
-  };
-
   ClientChannelMethodParsedConfig(grpc_millis timeout,
-                                  const absl::optional<bool>& wait_for_ready,
-                                  std::unique_ptr<RetryPolicy> retry_policy)
-      : timeout_(timeout),
-        wait_for_ready_(wait_for_ready),
-        retry_policy_(std::move(retry_policy)) {}
+                                  const absl::optional<bool>& wait_for_ready)
+      : timeout_(timeout), wait_for_ready_(wait_for_ready) {}
 
   grpc_millis timeout() const { return timeout_; }
 
   absl::optional<bool> wait_for_ready() const { return wait_for_ready_; }
 
-  const RetryPolicy* retry_policy() const { return retry_policy_.get(); }
-
  private:
   grpc_millis timeout_ = 0;
   absl::optional<bool> wait_for_ready_;
-  std::unique_ptr<RetryPolicy> retry_policy_;
 };
 
 class ClientChannelServiceConfigParser : public ServiceConfigParser::Parser {
  public:
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
       const grpc_channel_args* /*args*/, const Json& json,
-      grpc_error** error) override;
+      grpc_error_handle* error) override;
 
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
       const grpc_channel_args* /*args*/, const Json& json,
-      grpc_error** error) override;
+      grpc_error_handle* error) override;
 
   static size_t ParserIndex();
   static void Register();
@@ -125,4 +96,4 @@ class ClientChannelServiceConfigParser : public ServiceConfigParser::Parser {
 }  // namespace internal
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H */
+#endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H
diff --git a/src/core/ext/filters/client_channel/retry_filter.cc b/src/core/ext/filters/client_channel/retry_filter.cc
new file mode 100644 (file)
index 0000000..a03d2da
--- /dev/null
@@ -0,0 +1,2188 @@
+//
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/filters/client_channel/retry_filter.h"
+
+#include "absl/container/inlined_vector.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/strip.h"
+
+#include <grpc/support/log.h>
+
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/retry_service_config.h"
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/service_config.h"
+#include "src/core/ext/filters/client_channel/service_config_call_data.h"
+#include "src/core/lib/backoff/backoff.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/iomgr/polling_entity.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/transport/error_utils.h"
+#include "src/core/lib/transport/metadata.h"
+#include "src/core/lib/transport/metadata_batch.h"
+#include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/status_metadata.h"
+#include "src/core/lib/uri/uri_parser.h"
+
+//
+// Retry filter
+//
+
+// This filter is intended to be used in the DynamicFilter stack in the
+// client channel, which is situated between the name resolver and the
+// LB policy.  Normally, the last filter in the DynamicFilter stack is
+// the DynamicTerminationFilter (see client_channel.cc), which creates a
+// LoadBalancedCall and delegates to it.  However, when retries are
+// enabled, this filter is used instead of the DynamicTerminationFilter.
+//
+// In order to support retries, we act as a proxy for stream op batches.
+// When we get a batch from the surface, we add it to our list of pending
+// batches, and we then use those batches to construct separate "child"
+// batches to be started on an LB call.  When the child batches return, we
+// then decide which pending batches have been completed and schedule their
+// callbacks accordingly.  If a call attempt fails and we want to retry it,
+// we create a new LB call and start again, constructing new "child" batches
+// for the new LB call.
+//
+// Note that retries are committed when receiving data from the server
+// (except for Trailers-Only responses).  However, there may be many
+// send ops started before receiving any data, so we may have already
+// completed some number of send ops (and returned the completions up to
+// the surface) by the time we realize that we need to retry.  To deal
+// with this, we cache data for send ops, so that we can replay them on a
+// different LB call even after we have completed the original batches.
+//
+// The code is structured as follows:
+// - In CallData (in the parent channel), we maintain a list of pending
+//   ops and cached data for send ops.
+// - There is a CallData::CallAttempt object for each retry attempt.
+//   This object contains the LB call for that attempt and state to indicate
+//   which ops from the CallData object have already been sent down to that
+//   LB call.
+// - There is a CallData::CallAttempt::BatchData object for each "child"
+//   batch sent on the LB call.
+//
+// When constructing the "child" batches, we compare the state in the
+// CallAttempt object against the state in the CallData object to see
+// which batches need to be sent on the LB call for a given attempt.
+
+// TODO(roth): In subsequent PRs:
+// - add support for transparent retries (including initial metadata)
+// - figure out how to record stats in census for retries
+//   (census filter is on top of this one)
+// - add census stats for retries
+
+// By default, we buffer 256 KiB per RPC for retries.
+// TODO(roth): Do we have any data to suggest a better value?
+#define DEFAULT_PER_RPC_RETRY_BUFFER_SIZE (256 << 10)
+
+// This value was picked arbitrarily.  It can be changed if there is
+// any even moderately compelling reason to do so.
+#define RETRY_BACKOFF_JITTER 0.2
+
+namespace grpc_core {
+
+namespace {
+
+using internal::RetryGlobalConfig;
+using internal::RetryMethodConfig;
+using internal::RetryServiceConfigParser;
+using internal::ServerRetryThrottleData;
+
+TraceFlag grpc_retry_trace(false, "retry");
+
+//
+// RetryFilter
+//
+
+class RetryFilter {
+ public:
+  class CallData;
+
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args) {
+    GPR_ASSERT(args->is_last);
+    GPR_ASSERT(elem->filter == &kRetryFilterVtable);
+    grpc_error_handle error = GRPC_ERROR_NONE;
+    new (elem->channel_data) RetryFilter(args->channel_args, &error);
+    return error;
+  }
+
+  static void Destroy(grpc_channel_element* elem) {
+    auto* chand = static_cast<RetryFilter*>(elem->channel_data);
+    chand->~RetryFilter();
+  }
+
+  // Will never be called.
+  static void StartTransportOp(grpc_channel_element* /*elem*/,
+                               grpc_transport_op* /*op*/) {}
+  static void GetChannelInfo(grpc_channel_element* /*elem*/,
+                             const grpc_channel_info* /*info*/) {}
+
+ private:
+  static size_t GetMaxPerRpcRetryBufferSize(const grpc_channel_args* args) {
+    return static_cast<size_t>(grpc_channel_args_find_integer(
+        args, GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE,
+        {DEFAULT_PER_RPC_RETRY_BUFFER_SIZE, 0, INT_MAX}));
+  }
+
+  RetryFilter(const grpc_channel_args* args, grpc_error_handle* error)
+      : client_channel_(grpc_channel_args_find_pointer<ClientChannel>(
+            args, GRPC_ARG_CLIENT_CHANNEL)),
+        per_rpc_retry_buffer_size_(GetMaxPerRpcRetryBufferSize(args)) {
+    // Get retry throttling parameters from service config.
+    auto* service_config = grpc_channel_args_find_pointer<ServiceConfig>(
+        args, GRPC_ARG_SERVICE_CONFIG_OBJ);
+    if (service_config == nullptr) return;
+    const auto* config = static_cast<const RetryGlobalConfig*>(
+        service_config->GetGlobalParsedConfig(
+            RetryServiceConfigParser::ParserIndex()));
+    if (config == nullptr) return;
+    // Get server name from target URI.
+    const char* server_uri =
+        grpc_channel_args_find_string(args, GRPC_ARG_SERVER_URI);
+    if (server_uri == nullptr) {
+      *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "server URI channel arg missing or wrong type in client channel "
+          "filter");
+      return;
+    }
+    absl::StatusOr<URI> uri = URI::Parse(server_uri);
+    if (!uri.ok() || uri->path().empty()) {
+      *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "could not extract server name from target URI");
+      return;
+    }
+    std::string server_name(absl::StripPrefix(uri->path(), "/"));
+    // Get throttling config for server_name.
+    retry_throttle_data_ = internal::ServerRetryThrottleMap::GetDataForServer(
+        server_name, config->max_milli_tokens(), config->milli_token_ratio());
+  }
+
+  ClientChannel* client_channel_;
+  size_t per_rpc_retry_buffer_size_;
+  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
+};
+
+//
+// RetryFilter::CallData
+//
+
+class RetryFilter::CallData {
+ public:
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args);
+  static void Destroy(grpc_call_element* elem,
+                      const grpc_call_final_info* /*final_info*/,
+                      grpc_closure* then_schedule_closure);
+  static void StartTransportStreamOpBatch(
+      grpc_call_element* elem, grpc_transport_stream_op_batch* batch);
+  static void SetPollent(grpc_call_element* elem, grpc_polling_entity* pollent);
+
+ private:
+  class Canceller;
+  class CallStackDestructionBarrier;
+
+  // Pending batches stored in call data.
+  struct PendingBatch {
+    // The pending batch.  If nullptr, this slot is empty.
+    grpc_transport_stream_op_batch* batch = nullptr;
+    // Indicates whether payload for send ops has been cached in CallData.
+    bool send_ops_cached = false;
+  };
+
+  // State associated with each call attempt.
+  // Allocated on the arena.
+  class CallAttempt
+      : public RefCounted<CallAttempt, PolymorphicRefCount, kUnrefCallDtor> {
+   public:
+    explicit CallAttempt(CallData* calld);
+
+    ClientChannel::LoadBalancedCall* lb_call() const { return lb_call_.get(); }
+
+    // Constructs and starts whatever batches are needed on this call
+    // attempt.
+    void StartRetriableBatches();
+
+    // Frees cached send ops that have already been completed after
+    // committing the call.
+    void FreeCachedSendOpDataAfterCommit();
+
+   private:
+    // State used for starting a retryable batch on the call attempt's LB call.
+    // This provides its own grpc_transport_stream_op_batch and other data
+    // structures needed to populate the ops in the batch.
+    // We allocate one struct on the arena for each attempt at starting a
+    // batch on a given LB call.
+    class BatchData
+        : public RefCounted<CallAttempt, PolymorphicRefCount, kUnrefCallDtor> {
+     public:
+      BatchData(RefCountedPtr<CallAttempt> call_attempt, int refcount,
+                bool set_on_complete);
+      ~BatchData() override;
+
+      grpc_transport_stream_op_batch* batch() { return &batch_; }
+
+      // Adds retriable send_initial_metadata op to batch_data.
+      void AddRetriableSendInitialMetadataOp();
+      // Adds retriable send_message op to batch_data.
+      void AddRetriableSendMessageOp();
+      // Adds retriable send_trailing_metadata op to batch_data.
+      void AddRetriableSendTrailingMetadataOp();
+      // Adds retriable recv_initial_metadata op to batch_data.
+      void AddRetriableRecvInitialMetadataOp();
+      // Adds retriable recv_message op to batch_data.
+      void AddRetriableRecvMessageOp();
+      // Adds retriable recv_trailing_metadata op to batch_data.
+      void AddRetriableRecvTrailingMetadataOp();
+
+     private:
+      // Returns true if the call is being retried.
+      bool MaybeRetry(grpc_status_code status, grpc_mdelem* server_pushback_md,
+                      bool is_lb_drop);
+
+      // Frees cached send ops that were completed by the completed batch in
+      // batch_data.  Used when batches are completed after the call is
+      // committed.
+      void FreeCachedSendOpDataForCompletedBatch();
+
+      // Invokes recv_initial_metadata_ready for a batch.
+      static void InvokeRecvInitialMetadataCallback(void* arg,
+                                                    grpc_error_handle error);
+      // Intercepts recv_initial_metadata_ready callback for retries.
+      // Commits the call and returns the initial metadata up the stack.
+      static void RecvInitialMetadataReady(void* arg, grpc_error_handle error);
+
+      // Invokes recv_message_ready for a batch.
+      static void InvokeRecvMessageCallback(void* arg, grpc_error_handle error);
+      // Intercepts recv_message_ready callback for retries.
+      // Commits the call and returns the message up the stack.
+      static void RecvMessageReady(void* arg, grpc_error_handle error);
+
+      // Adds recv_trailing_metadata_ready closure to closures.
+      void AddClosureForRecvTrailingMetadataReady(
+          grpc_error_handle error, CallCombinerClosureList* closures);
+      // Adds any necessary closures for deferred recv_initial_metadata and
+      // recv_message callbacks to closures.
+      void AddClosuresForDeferredRecvCallbacks(
+          CallCombinerClosureList* closures);
+      // For any pending batch containing an op that has not yet been started,
+      // adds the pending batch's completion closures to closures.
+      void AddClosuresToFailUnstartedPendingBatches(
+          grpc_error_handle error, CallCombinerClosureList* closures);
+      // Runs necessary closures upon completion of a call attempt.
+      void RunClosuresForCompletedCall(grpc_error_handle error);
+      // Intercepts recv_trailing_metadata_ready callback for retries.
+      // Commits the call and returns the trailing metadata up the stack.
+      static void RecvTrailingMetadataReady(void* arg, grpc_error_handle error);
+
+      // Adds the on_complete closure for the pending batch completed in
+      // batch_data to closures.
+      void AddClosuresForCompletedPendingBatch(
+          grpc_error_handle error, CallCombinerClosureList* closures);
+
+      // If there are any cached ops to replay or pending ops to start on the
+      // LB call, adds them to closures.
+      void AddClosuresForReplayOrPendingSendOps(
+          CallCombinerClosureList* closures);
+
+      // Callback used to intercept on_complete from LB calls.
+      static void OnComplete(void* arg, grpc_error_handle error);
+
+      RefCountedPtr<CallAttempt> call_attempt_;
+      // The batch to use in the LB call.
+      // Its payload field points to CallAttempt::batch_payload_.
+      grpc_transport_stream_op_batch batch_;
+      // For intercepting on_complete.
+      grpc_closure on_complete_;
+    };
+
+    // Creates a BatchData object on the call's arena with the
+    // specified refcount.  If set_on_complete is true, the batch's
+    // on_complete callback will be set to point to on_complete();
+    // otherwise, the batch's on_complete callback will be null.
+    BatchData* CreateBatch(int refcount, bool set_on_complete) {
+      return calld_->arena_->New<BatchData>(Ref(), refcount, set_on_complete);
+    }
+
+    // If there are any cached send ops that need to be replayed on this
+    // call attempt, creates and returns a new batch to replay those ops.
+    // Otherwise, returns nullptr.
+    BatchData* MaybeCreateBatchForReplay();
+
+    // Adds batches for pending batches to closures.
+    void AddBatchesForPendingBatches(CallCombinerClosureList* closures);
+
+    // Adds whatever batches are needed on this attempt to closures.
+    void AddRetriableBatches(CallCombinerClosureList* closures);
+
+    // Returns true if any op in the batch was not yet started on this attempt.
+    bool PendingBatchIsUnstarted(PendingBatch* pending);
+
+    // Helper function used to start a recv_trailing_metadata batch.  This
+    // is used in the case where a recv_initial_metadata or recv_message
+    // op fails in a way that we know the call is over but when the application
+    // has not yet started its own recv_trailing_metadata op.
+    void StartInternalRecvTrailingMetadata();
+
+    CallData* calld_;
+    RefCountedPtr<ClientChannel::LoadBalancedCall> lb_call_;
+
+    // BatchData.batch.payload points to this.
+    grpc_transport_stream_op_batch_payload batch_payload_;
+    // For send_initial_metadata.
+    // Note that we need to make a copy of the initial metadata for each
+    // call attempt instead of just referring to the copy in call_data,
+    // because filters in the subchannel stack may modify the metadata,
+    // so we need to start in a pristine state for each attempt of the call.
+    grpc_linked_mdelem* send_initial_metadata_storage_;
+    grpc_metadata_batch send_initial_metadata_;
+    // For send_message.
+    // TODO(roth): Restructure this to eliminate use of ManualConstructor.
+    ManualConstructor<ByteStreamCache::CachingByteStream> send_message_;
+    // For send_trailing_metadata.
+    grpc_linked_mdelem* send_trailing_metadata_storage_;
+    grpc_metadata_batch send_trailing_metadata_;
+    // For intercepting recv_initial_metadata.
+    grpc_metadata_batch recv_initial_metadata_;
+    grpc_closure recv_initial_metadata_ready_;
+    bool trailing_metadata_available_ = false;
+    // For intercepting recv_message.
+    grpc_closure recv_message_ready_;
+    OrphanablePtr<ByteStream> recv_message_;
+    // For intercepting recv_trailing_metadata.
+    grpc_metadata_batch recv_trailing_metadata_;
+    grpc_transport_stream_stats collect_stats_;
+    grpc_closure recv_trailing_metadata_ready_;
+    // These fields indicate which ops have been started and completed on
+    // this call attempt.
+    size_t started_send_message_count_ = 0;
+    size_t completed_send_message_count_ = 0;
+    size_t started_recv_message_count_ = 0;
+    size_t completed_recv_message_count_ = 0;
+    bool started_send_initial_metadata_ : 1;
+    bool completed_send_initial_metadata_ : 1;
+    bool started_send_trailing_metadata_ : 1;
+    bool completed_send_trailing_metadata_ : 1;
+    bool started_recv_initial_metadata_ : 1;
+    bool completed_recv_initial_metadata_ : 1;
+    bool started_recv_trailing_metadata_ : 1;
+    bool completed_recv_trailing_metadata_ : 1;
+    // State for callback processing.
+    BatchData* recv_initial_metadata_ready_deferred_batch_ = nullptr;
+    grpc_error_handle recv_initial_metadata_error_ = GRPC_ERROR_NONE;
+    BatchData* recv_message_ready_deferred_batch_ = nullptr;
+    grpc_error_handle recv_message_error_ = GRPC_ERROR_NONE;
+    BatchData* recv_trailing_metadata_internal_batch_ = nullptr;
+    // NOTE: Do not move this next to the metadata bitfields above. That would
+    //       save space but will also result in a data race because compiler
+    //       will generate a 2 byte store which overwrites the meta-data
+    //       fields upon setting this field.
+    bool retry_dispatched_ : 1;
+  };
+
+  CallData(RetryFilter* chand, const grpc_call_element_args& args);
+  ~CallData();
+
+  void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
+
+  // Returns the index into pending_batches_ to be used for batch.
+  static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
+  PendingBatch* PendingBatchesAdd(grpc_transport_stream_op_batch* batch);
+  void PendingBatchClear(PendingBatch* pending);
+  void MaybeClearPendingBatch(PendingBatch* pending);
+  static void FailPendingBatchInCallCombiner(void* arg,
+                                             grpc_error_handle error);
+  // Fails all pending batches.  Does NOT yield call combiner.
+  void PendingBatchesFail(grpc_error_handle error);
+  // Returns a pointer to the first pending batch for which predicate(batch)
+  // returns true, or null if not found.
+  template <typename Predicate>
+  PendingBatch* PendingBatchFind(const char* log_message, Predicate predicate);
+
+  // Caches data for send ops so that it can be retried later, if not
+  // already cached.
+  void MaybeCacheSendOpsForBatch(PendingBatch* pending);
+  void FreeCachedSendInitialMetadata();
+  // Frees cached send_message at index idx.
+  void FreeCachedSendMessage(size_t idx);
+  void FreeCachedSendTrailingMetadata();
+  void FreeAllCachedSendOpData();
+
+  // Commits the call so that no further retry attempts will be performed.
+  void RetryCommit(CallAttempt* call_attempt);
+
+  // Starts a retry after appropriate back-off.
+  void DoRetry(grpc_millis server_pushback_ms);
+  static void OnRetryTimer(void* arg, grpc_error_handle error);
+
+  RefCountedPtr<ClientChannel::LoadBalancedCall> CreateLoadBalancedCall();
+
+  void CreateCallAttempt();
+
+  // Adds a closure to closures that will execute batch in the call combiner.
+  void AddClosureForBatch(grpc_transport_stream_op_batch* batch,
+                          CallCombinerClosureList* closures);
+
+  RetryFilter* chand_;
+  grpc_polling_entity* pollent_;
+  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
+  const RetryMethodConfig* retry_policy_ = nullptr;
+  BackOff retry_backoff_;
+
+  grpc_slice path_;  // Request path.
+  gpr_cycle_counter call_start_time_;
+  grpc_millis deadline_;
+  Arena* arena_;
+  grpc_call_stack* owning_call_;
+  CallCombiner* call_combiner_;
+  grpc_call_context_element* call_context_;
+
+  RefCountedPtr<CallStackDestructionBarrier> call_stack_destruction_barrier_;
+
+  // TODO(roth): As part of implementing hedging, we will need to maintain a
+  // list of all pending attempts, so that we can cancel them all if the call
+  // gets cancelled.
+  RefCountedPtr<CallAttempt> call_attempt_;
+
+  // LB call used when the call is commited before any CallAttempt is
+  // created.
+  // TODO(roth): Change CallAttempt logic such that once we've committed
+  // and all cached send ops have been replayed, we move the LB call
+  // from the CallAttempt here, thus creating a fast path for the
+  // remainder of the streaming call.
+  RefCountedPtr<ClientChannel::LoadBalancedCall> committed_call_;
+
+  // When are are not yet fully committed to a particular call (i.e.,
+  // either we might still retry or we have committed to the call but
+  // there are still some cached ops to be replayed on the call),
+  // batches received from above will be added to this list, and they
+  // will not be removed until we have invoked their completion callbacks.
+  size_t bytes_buffered_for_retry_ = 0;
+  PendingBatch pending_batches_[MAX_PENDING_BATCHES];
+  bool pending_send_initial_metadata_ : 1;
+  bool pending_send_message_ : 1;
+  bool pending_send_trailing_metadata_ : 1;
+
+  // Retry state.
+  bool retry_committed_ : 1;
+  bool last_attempt_got_server_pushback_ : 1;
+  int num_attempts_completed_ = 0;
+  Mutex timer_mu_;
+  Canceller* canceller_ ABSL_GUARDED_BY(timer_mu_);
+  grpc_timer retry_timer_ ABSL_GUARDED_BY(timer_mu_);
+  grpc_closure retry_closure_;
+
+  // The number of batches containing send ops that are currently in-flight
+  // on any call attempt.
+  // We hold a ref to the call stack while this is non-zero, since replay
+  // batches may not complete until after all callbacks have been returned
+  // to the surface, and we need to make sure that the call is not destroyed
+  // until all of these batches have completed.
+  // Note that we actually only need to track replay batches, but it's
+  // easier to track all batches with send ops.
+  int num_in_flight_call_attempt_send_batches_ = 0;
+
+  // Cached data for retrying send ops.
+  // send_initial_metadata
+  bool seen_send_initial_metadata_ = false;
+  grpc_linked_mdelem* send_initial_metadata_storage_ = nullptr;
+  grpc_metadata_batch send_initial_metadata_;
+  uint32_t send_initial_metadata_flags_;
+  // TODO(roth): As part of implementing hedging, we'll probably need to
+  // have the LB call set a value in CallAttempt and then propagate it
+  // from CallAttempt to the parent call when we commit.  Otherwise, we
+  // may leave this with a value for a peer other than the one we
+  // actually commit to.
+  gpr_atm* peer_string_;
+  // send_message
+  // When we get a send_message op, we replace the original byte stream
+  // with a CachingByteStream that caches the slices to a local buffer for
+  // use in retries.
+  // Note: We inline the cache for the first 3 send_message ops and use
+  // dynamic allocation after that.  This number was essentially picked
+  // at random; it could be changed in the future to tune performance.
+  absl::InlinedVector<ByteStreamCache*, 3> send_messages_;
+  // send_trailing_metadata
+  bool seen_send_trailing_metadata_ = false;
+  grpc_linked_mdelem* send_trailing_metadata_storage_ = nullptr;
+  grpc_metadata_batch send_trailing_metadata_;
+};
+
+//
+// RetryFilter::CallData::CallStackDestructionBarrier
+//
+
+// A class to track the existence of LoadBalancedCall call stacks that
+// we've created.  We wait until all such call stacks have been
+// destroyed before we return the on_call_stack_destruction closure up
+// to the surface.
+//
+// The parent RetryFilter::CallData object holds a ref to this object.
+// When it is destroyed, it will store the on_call_stack_destruction
+// closure from the surface in this object and then release its ref.
+// We also take a ref to this object for each LB call we create, and
+// those refs are not released until the LB call stack is destroyed.
+// When this object is destroyed, it will invoke the
+// on_call_stack_destruction closure from the surface.
+class RetryFilter::CallData::CallStackDestructionBarrier
+    : public RefCounted<CallStackDestructionBarrier, PolymorphicRefCount,
+                        kUnrefCallDtor> {
+ public:
+  CallStackDestructionBarrier() {}
+
+  ~CallStackDestructionBarrier() override {
+    // TODO(yashkt) : This can potentially be a Closure::Run
+    ExecCtx::Run(DEBUG_LOCATION, on_call_stack_destruction_, GRPC_ERROR_NONE);
+  }
+
+  // Set the closure from the surface.  This closure will be invoked
+  // when this object is destroyed.
+  void set_on_call_stack_destruction(grpc_closure* on_call_stack_destruction) {
+    on_call_stack_destruction_ = on_call_stack_destruction;
+  }
+
+  // Invoked to get an on_call_stack_destruction closure for a new LB call.
+  grpc_closure* MakeLbCallDestructionClosure(CallData* calld) {
+    Ref().release();  // Ref held by callback.
+    grpc_closure* on_lb_call_destruction_complete =
+        calld->arena_->New<grpc_closure>();
+    GRPC_CLOSURE_INIT(on_lb_call_destruction_complete,
+                      OnLbCallDestructionComplete, this, nullptr);
+    return on_lb_call_destruction_complete;
+  }
+
+ private:
+  static void OnLbCallDestructionComplete(void* arg,
+                                          grpc_error_handle /*error*/) {
+    auto* self = static_cast<CallStackDestructionBarrier*>(arg);
+    self->Unref();
+  }
+
+  grpc_closure* on_call_stack_destruction_ = nullptr;
+};
+
+//
+// RetryFilter::CallData::Canceller
+//
+
+class RetryFilter::CallData::Canceller {
+ public:
+  explicit Canceller(CallData* calld) : calld_(calld) {
+    GRPC_CALL_STACK_REF(calld_->owning_call_, "RetryCanceller");
+    GRPC_CLOSURE_INIT(&closure_, &Cancel, this, nullptr);
+    calld_->call_combiner_->SetNotifyOnCancel(&closure_);
+  }
+
+ private:
+  static void Cancel(void* arg, grpc_error_handle error) {
+    auto* self = static_cast<Canceller*>(arg);
+    auto* calld = self->calld_;
+    {
+      MutexLock lock(&calld->timer_mu_);
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "calld=%p: cancelling retry timer: error=%s self=%p "
+                "calld->canceller_=%p",
+                calld, grpc_error_std_string(error).c_str(), self,
+                calld->canceller_);
+      }
+      if (calld->canceller_ == self && error != GRPC_ERROR_NONE) {
+        calld->canceller_ = nullptr;  // Checked by OnRetryTimer().
+        grpc_timer_cancel(&calld->retry_timer_);
+        calld->FreeAllCachedSendOpData();
+        GRPC_CALL_COMBINER_STOP(calld->call_combiner_, "Canceller");
+      }
+    }
+    GRPC_CALL_STACK_UNREF(calld->owning_call_, "RetryCanceller");
+    delete self;
+  }
+
+  CallData* calld_;
+  grpc_closure closure_;
+};
+
+//
+// RetryFilter::CallData::CallAttempt
+//
+
+RetryFilter::CallData::CallAttempt::CallAttempt(CallData* calld)
+    : calld_(calld),
+      batch_payload_(calld->call_context_),
+      started_send_initial_metadata_(false),
+      completed_send_initial_metadata_(false),
+      started_send_trailing_metadata_(false),
+      completed_send_trailing_metadata_(false),
+      started_recv_initial_metadata_(false),
+      completed_recv_initial_metadata_(false),
+      started_recv_trailing_metadata_(false),
+      completed_recv_trailing_metadata_(false),
+      retry_dispatched_(false) {
+  lb_call_ = calld->CreateLoadBalancedCall();
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: attempt=%p: create lb_call=%p",
+            calld->chand_, calld, this, lb_call_.get());
+  }
+}
+
+void RetryFilter::CallData::CallAttempt::FreeCachedSendOpDataAfterCommit() {
+  // TODO(roth): When we implement hedging, this logic will need to get
+  // a bit more complex, because there may be other (now abandoned) call
+  // attempts still using this data.  We may need to do some sort of
+  // ref-counting instead.
+  if (completed_send_initial_metadata_) {
+    calld_->FreeCachedSendInitialMetadata();
+  }
+  for (size_t i = 0; i < completed_send_message_count_; ++i) {
+    calld_->FreeCachedSendMessage(i);
+  }
+  if (completed_send_trailing_metadata_) {
+    calld_->FreeCachedSendTrailingMetadata();
+  }
+}
+
+bool RetryFilter::CallData::CallAttempt::PendingBatchIsUnstarted(
+    PendingBatch* pending) {
+  // Only look at batches containing send ops, since batches containing
+  // only recv ops are always started immediately.
+  if (pending->batch == nullptr || pending->batch->on_complete == nullptr) {
+    return false;
+  }
+  if (pending->batch->send_initial_metadata &&
+      !started_send_initial_metadata_) {
+    return true;
+  }
+  if (pending->batch->send_message &&
+      started_send_message_count_ < calld_->send_messages_.size()) {
+    return true;
+  }
+  if (pending->batch->send_trailing_metadata &&
+      !started_send_trailing_metadata_) {
+    return true;
+  }
+  return false;
+}
+
+void RetryFilter::CallData::CallAttempt::StartInternalRecvTrailingMetadata() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: call failed but recv_trailing_metadata not "
+            "started; starting it internally",
+            calld_->chand_, calld_);
+  }
+  // Create batch_data with 2 refs, since this batch will be unreffed twice:
+  // once for the recv_trailing_metadata_ready callback when the batch
+  // completes, and again when we actually get a recv_trailing_metadata
+  // op from the surface.
+  BatchData* batch_data = CreateBatch(2, false /* set_on_complete */);
+  batch_data->AddRetriableRecvTrailingMetadataOp();
+  recv_trailing_metadata_internal_batch_ = batch_data;
+  // Note: This will release the call combiner.
+  lb_call_->StartTransportStreamOpBatch(batch_data->batch());
+}
+
+// If there are any cached send ops that need to be replayed on the
+// current call attempt, creates and returns a new batch to replay those ops.
+// Otherwise, returns nullptr.
+RetryFilter::CallData::CallAttempt::BatchData*
+RetryFilter::CallData::CallAttempt::MaybeCreateBatchForReplay() {
+  BatchData* replay_batch_data = nullptr;
+  // send_initial_metadata.
+  if (calld_->seen_send_initial_metadata_ && !started_send_initial_metadata_ &&
+      !calld_->pending_send_initial_metadata_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: replaying previously completed "
+              "send_initial_metadata op",
+              calld_->chand_, calld_);
+    }
+    replay_batch_data = CreateBatch(1, true /* set_on_complete */);
+    replay_batch_data->AddRetriableSendInitialMetadataOp();
+  }
+  // send_message.
+  // Note that we can only have one send_message op in flight at a time.
+  if (started_send_message_count_ < calld_->send_messages_.size() &&
+      started_send_message_count_ == completed_send_message_count_ &&
+      !calld_->pending_send_message_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: replaying previously completed "
+              "send_message op",
+              calld_->chand_, calld_);
+    }
+    if (replay_batch_data == nullptr) {
+      replay_batch_data = CreateBatch(1, true /* set_on_complete */);
+    }
+    replay_batch_data->AddRetriableSendMessageOp();
+  }
+  // send_trailing_metadata.
+  // Note that we only add this op if we have no more send_message ops
+  // to start, since we can't send down any more send_message ops after
+  // send_trailing_metadata.
+  if (calld_->seen_send_trailing_metadata_ &&
+      started_send_message_count_ == calld_->send_messages_.size() &&
+      !started_send_trailing_metadata_ &&
+      !calld_->pending_send_trailing_metadata_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: replaying previously completed "
+              "send_trailing_metadata op",
+              calld_->chand_, calld_);
+    }
+    if (replay_batch_data == nullptr) {
+      replay_batch_data = CreateBatch(1, true /* set_on_complete */);
+    }
+    replay_batch_data->AddRetriableSendTrailingMetadataOp();
+  }
+  return replay_batch_data;
+}
+
+void RetryFilter::CallData::CallAttempt::AddBatchesForPendingBatches(
+    CallCombinerClosureList* closures) {
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld_->pending_batches_); ++i) {
+    PendingBatch* pending = &calld_->pending_batches_[i];
+    grpc_transport_stream_op_batch* batch = pending->batch;
+    if (batch == nullptr) continue;
+    // Skip any batch that either (a) has already been started on this
+    // call attempt or (b) we can't start yet because we're still
+    // replaying send ops that need to be completed first.
+    // TODO(roth): Note that if any one op in the batch can't be sent
+    // yet due to ops that we're replaying, we don't start any of the ops
+    // in the batch.  This is probably okay, but it could conceivably
+    // lead to increased latency in some cases -- e.g., we could delay
+    // starting a recv op due to it being in the same batch with a send
+    // op.  If/when we revamp the callback protocol in
+    // transport_stream_op_batch, we may be able to fix this.
+    if (batch->send_initial_metadata && started_send_initial_metadata_) {
+      continue;
+    }
+    if (batch->send_message &&
+        completed_send_message_count_ < started_send_message_count_) {
+      continue;
+    }
+    // Note that we only start send_trailing_metadata if we have no more
+    // send_message ops to start, since we can't send down any more
+    // send_message ops after send_trailing_metadata.
+    if (batch->send_trailing_metadata &&
+        (started_send_message_count_ + batch->send_message <
+             calld_->send_messages_.size() ||
+         started_send_trailing_metadata_)) {
+      continue;
+    }
+    if (batch->recv_initial_metadata && started_recv_initial_metadata_) {
+      continue;
+    }
+    if (batch->recv_message &&
+        completed_recv_message_count_ < started_recv_message_count_) {
+      continue;
+    }
+    if (batch->recv_trailing_metadata && started_recv_trailing_metadata_) {
+      // If we previously completed a recv_trailing_metadata op
+      // initiated by StartInternalRecvTrailingMetadata(), use the
+      // result of that instead of trying to re-start this op.
+      if (GPR_UNLIKELY(recv_trailing_metadata_internal_batch_ != nullptr)) {
+        // If the batch completed, then trigger the completion callback
+        // directly, so that we return the previously returned results to
+        // the application.  Otherwise, just unref the internally started
+        // batch, since we'll propagate the completion when it completes.
+        if (completed_recv_trailing_metadata_) {
+          // Batches containing recv_trailing_metadata always succeed.
+          closures->Add(
+              &recv_trailing_metadata_ready_, GRPC_ERROR_NONE,
+              "re-executing recv_trailing_metadata_ready to propagate "
+              "internally triggered result");
+        } else {
+          recv_trailing_metadata_internal_batch_->Unref();
+        }
+        recv_trailing_metadata_internal_batch_ = nullptr;
+      }
+      continue;
+    }
+    // If we're already committed, just send the batch as-is.
+    if (calld_->retry_committed_) {
+      calld_->AddClosureForBatch(batch, closures);
+      calld_->PendingBatchClear(pending);
+      continue;
+    }
+    // Create batch with the right number of callbacks.
+    const bool has_send_ops = batch->send_initial_metadata ||
+                              batch->send_message ||
+                              batch->send_trailing_metadata;
+    const int num_callbacks = has_send_ops + batch->recv_initial_metadata +
+                              batch->recv_message +
+                              batch->recv_trailing_metadata;
+    CallAttempt::BatchData* batch_data =
+        CreateBatch(num_callbacks, has_send_ops /* set_on_complete */);
+    // Cache send ops if needed.
+    calld_->MaybeCacheSendOpsForBatch(pending);
+    // send_initial_metadata.
+    if (batch->send_initial_metadata) {
+      batch_data->AddRetriableSendInitialMetadataOp();
+    }
+    // send_message.
+    if (batch->send_message) {
+      batch_data->AddRetriableSendMessageOp();
+    }
+    // send_trailing_metadata.
+    if (batch->send_trailing_metadata) {
+      batch_data->AddRetriableSendTrailingMetadataOp();
+    }
+    // recv_initial_metadata.
+    if (batch->recv_initial_metadata) {
+      // recv_flags is only used on the server side.
+      GPR_ASSERT(batch->payload->recv_initial_metadata.recv_flags == nullptr);
+      batch_data->AddRetriableRecvInitialMetadataOp();
+    }
+    // recv_message.
+    if (batch->recv_message) {
+      batch_data->AddRetriableRecvMessageOp();
+    }
+    // recv_trailing_metadata.
+    if (batch->recv_trailing_metadata) {
+      batch_data->AddRetriableRecvTrailingMetadataOp();
+    }
+    calld_->AddClosureForBatch(batch_data->batch(), closures);
+    // Track number of in-flight send batches.
+    // If this is the first one, take a ref to the call stack.
+    if (batch->send_initial_metadata || batch->send_message ||
+        batch->send_trailing_metadata) {
+      if (calld_->num_in_flight_call_attempt_send_batches_ == 0) {
+        GRPC_CALL_STACK_REF(calld_->owning_call_, "retriable_send_batches");
+      }
+      ++calld_->num_in_flight_call_attempt_send_batches_;
+    }
+  }
+}
+
+void RetryFilter::CallData::CallAttempt::AddRetriableBatches(
+    CallCombinerClosureList* closures) {
+  // Replay previously-returned send_* ops if needed.
+  BatchData* replay_batch_data = MaybeCreateBatchForReplay();
+  if (replay_batch_data != nullptr) {
+    calld_->AddClosureForBatch(replay_batch_data->batch(), closures);
+    // Track number of pending send batches.
+    // If this is the first one, take a ref to the call stack.
+    if (calld_->num_in_flight_call_attempt_send_batches_ == 0) {
+      GRPC_CALL_STACK_REF(calld_->owning_call_, "retriable_send_batches");
+    }
+    ++calld_->num_in_flight_call_attempt_send_batches_;
+  }
+  // Now add pending batches.
+  AddBatchesForPendingBatches(closures);
+}
+
+void RetryFilter::CallData::CallAttempt::StartRetriableBatches() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: constructing retriable batches",
+            calld_->chand_, calld_);
+  }
+  // Construct list of closures to execute, one for each pending batch.
+  CallCombinerClosureList closures;
+  AddRetriableBatches(&closures);
+  // Note: This will yield the call combiner.
+  // Start batches on LB call.
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: starting %" PRIuPTR
+            " retriable batches on lb_call=%p",
+            calld_->chand_, calld_, closures.size(), lb_call());
+  }
+  closures.RunClosures(calld_->call_combiner_);
+}
+
+//
+// RetryFilter::CallData::CallAttempt::BatchData
+//
+
+RetryFilter::CallData::CallAttempt::BatchData::BatchData(
+    RefCountedPtr<CallAttempt> attempt, int refcount, bool set_on_complete)
+    : RefCounted(nullptr, refcount), call_attempt_(std::move(attempt)) {
+  // TODO(roth): Consider holding this ref on the call stack in
+  // CallAttempt instead of here in BatchData.  This would eliminate the
+  // need for CallData::num_in_flight_call_attempt_send_batches_.
+  // But it would require having a way to unref CallAttempt when it is
+  // no longer needed (i.e., when the call is committed and all cached
+  // send ops have been replayed and the LB call is moved into
+  // CallData::committed_call_).
+  GRPC_CALL_STACK_REF(call_attempt_->calld_->owning_call_, "CallAttempt");
+  batch_.payload = &call_attempt_->batch_payload_;
+  if (set_on_complete) {
+    GRPC_CLOSURE_INIT(&on_complete_, OnComplete, this,
+                      grpc_schedule_on_exec_ctx);
+    batch_.on_complete = &on_complete_;
+  }
+}
+
+RetryFilter::CallData::CallAttempt::BatchData::~BatchData() {
+  if (batch_.send_initial_metadata) {
+    grpc_metadata_batch_destroy(&call_attempt_->send_initial_metadata_);
+  }
+  if (batch_.send_trailing_metadata) {
+    grpc_metadata_batch_destroy(&call_attempt_->send_trailing_metadata_);
+  }
+  if (batch_.recv_initial_metadata) {
+    grpc_metadata_batch_destroy(&call_attempt_->recv_initial_metadata_);
+  }
+  if (batch_.recv_trailing_metadata) {
+    grpc_metadata_batch_destroy(&call_attempt_->recv_trailing_metadata_);
+  }
+  GRPC_CALL_STACK_UNREF(call_attempt_->calld_->owning_call_, "CallAttempt");
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    FreeCachedSendOpDataForCompletedBatch() {
+  auto* calld = call_attempt_->calld_;
+  // TODO(roth): When we implement hedging, this logic will need to get
+  // a bit more complex, because there may be other (now abandoned) call
+  // attempts still using this data.  We may need to do some sort of
+  // ref-counting instead.
+  if (batch_.send_initial_metadata) {
+    calld->FreeCachedSendInitialMetadata();
+  }
+  if (batch_.send_message) {
+    calld->FreeCachedSendMessage(call_attempt_->completed_send_message_count_ -
+                                 1);
+  }
+  if (batch_.send_trailing_metadata) {
+    calld->FreeCachedSendTrailingMetadata();
+  }
+}
+
+bool RetryFilter::CallData::CallAttempt::BatchData::MaybeRetry(
+    grpc_status_code status, grpc_mdelem* server_pushback_md, bool is_lb_drop) {
+  auto* calld = call_attempt_->calld_;
+  // LB drops always inhibit retries.
+  if (is_lb_drop) return false;
+  // Get retry policy.
+  if (calld->retry_policy_ == nullptr) return false;
+  // If we've already dispatched a retry from this call, return true.
+  // This catches the case where the batch has multiple callbacks
+  // (i.e., it includes either recv_message or recv_initial_metadata).
+  if (call_attempt_->retry_dispatched_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: retry already dispatched",
+              calld->chand_, calld);
+    }
+    return true;
+  }
+  // Check status.
+  if (GPR_LIKELY(status == GRPC_STATUS_OK)) {
+    if (calld->retry_throttle_data_ != nullptr) {
+      calld->retry_throttle_data_->RecordSuccess();
+    }
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: call succeeded", calld->chand_,
+              calld);
+    }
+    return false;
+  }
+  // Status is not OK.  Check whether the status is retryable.
+  if (!calld->retry_policy_->retryable_status_codes().Contains(status)) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: status %s not configured as retryable",
+              calld->chand_, calld, grpc_status_code_to_string(status));
+    }
+    return false;
+  }
+  // Record the failure and check whether retries are throttled.
+  // Note that it's important for this check to come after the status
+  // code check above, since we should only record failures whose statuses
+  // match the configured retryable status codes, so that we don't count
+  // things like failures due to malformed requests (INVALID_ARGUMENT).
+  // Conversely, it's important for this to come before the remaining
+  // checks, so that we don't fail to record failures due to other factors.
+  if (calld->retry_throttle_data_ != nullptr &&
+      !calld->retry_throttle_data_->RecordFailure()) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: retries throttled", calld->chand_,
+              calld);
+    }
+    return false;
+  }
+  // Check whether the call is committed.
+  if (calld->retry_committed_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: retries already committed",
+              calld->chand_, calld);
+    }
+    return false;
+  }
+  // Check whether we have retries remaining.
+  ++calld->num_attempts_completed_;
+  if (calld->num_attempts_completed_ >= calld->retry_policy_->max_attempts()) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: exceeded %d retry attempts",
+              calld->chand_, calld, calld->retry_policy_->max_attempts());
+    }
+    return false;
+  }
+  // Check server push-back.
+  grpc_millis server_pushback_ms = -1;
+  if (server_pushback_md != nullptr) {
+    // If the value is "-1" or any other unparseable string, we do not retry.
+    uint32_t ms;
+    if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(*server_pushback_md), &ms)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: not retrying due to server push-back",
+                calld->chand_, calld);
+      }
+      return false;
+    } else {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO, "chand=%p calld=%p: server push-back: retry in %u ms",
+                calld->chand_, calld, ms);
+      }
+      server_pushback_ms = static_cast<grpc_millis>(ms);
+    }
+  }
+  // Do retry.
+  call_attempt_->retry_dispatched_ = true;
+  calld->DoRetry(server_pushback_ms);
+  return true;
+}
+
+//
+// recv_initial_metadata callback handling
+//
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    InvokeRecvInitialMetadataCallback(void* arg, grpc_error_handle error) {
+  auto* batch_data = static_cast<CallAttempt::BatchData*>(arg);
+  auto* call_attempt = batch_data->call_attempt_.get();
+  // Find pending batch.
+  PendingBatch* pending = call_attempt->calld_->PendingBatchFind(
+      "invoking recv_initial_metadata_ready for",
+      [](grpc_transport_stream_op_batch* batch) {
+        return batch->recv_initial_metadata &&
+               batch->payload->recv_initial_metadata
+                       .recv_initial_metadata_ready != nullptr;
+      });
+  GPR_ASSERT(pending != nullptr);
+  // Return metadata.
+  grpc_metadata_batch_move(
+      &call_attempt->recv_initial_metadata_,
+      pending->batch->payload->recv_initial_metadata.recv_initial_metadata);
+  // Update bookkeeping.
+  // Note: Need to do this before invoking the callback, since invoking
+  // the callback will result in yielding the call combiner.
+  grpc_closure* recv_initial_metadata_ready =
+      pending->batch->payload->recv_initial_metadata
+          .recv_initial_metadata_ready;
+  pending->batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
+      nullptr;
+  call_attempt->calld_->MaybeClearPendingBatch(pending);
+  batch_data->Unref();
+  // Invoke callback.
+  Closure::Run(DEBUG_LOCATION, recv_initial_metadata_ready,
+               GRPC_ERROR_REF(error));
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::RecvInitialMetadataReady(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: got recv_initial_metadata_ready, error=%s",
+            calld->chand_, calld, grpc_error_std_string(error).c_str());
+  }
+  call_attempt->completed_recv_initial_metadata_ = true;
+  // If a retry was already dispatched, then we're not going to use the
+  // result of this recv_initial_metadata op, so do nothing.
+  if (call_attempt->retry_dispatched_) {
+    GRPC_CALL_COMBINER_STOP(
+        calld->call_combiner_,
+        "recv_initial_metadata_ready after retry dispatched");
+    return;
+  }
+  if (!calld->retry_committed_) {
+    // If we got an error or a Trailers-Only response and have not yet gotten
+    // the recv_trailing_metadata_ready callback, then defer propagating this
+    // callback back to the surface.  We can evaluate whether to retry when
+    // recv_trailing_metadata comes back.
+    if (GPR_UNLIKELY((call_attempt->trailing_metadata_available_ ||
+                      error != GRPC_ERROR_NONE) &&
+                     !call_attempt->completed_recv_trailing_metadata_)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: deferring recv_initial_metadata_ready "
+                "(Trailers-Only)",
+                calld->chand_, calld);
+      }
+      call_attempt->recv_initial_metadata_ready_deferred_batch_ = batch_data;
+      call_attempt->recv_initial_metadata_error_ = GRPC_ERROR_REF(error);
+      if (!call_attempt->started_recv_trailing_metadata_) {
+        // recv_trailing_metadata not yet started by application; start it
+        // ourselves to get status.
+        call_attempt->StartInternalRecvTrailingMetadata();
+      } else {
+        GRPC_CALL_COMBINER_STOP(
+            calld->call_combiner_,
+            "recv_initial_metadata_ready trailers-only or error");
+      }
+      return;
+    }
+    // Received valid initial metadata, so commit the call.
+    calld->RetryCommit(call_attempt);
+  }
+  // Invoke the callback to return the result to the surface.
+  // Manually invoking a callback function; it does not take ownership of error.
+  InvokeRecvInitialMetadataCallback(batch_data, error);
+}
+
+//
+// recv_message callback handling
+//
+
+void RetryFilter::CallData::CallAttempt::BatchData::InvokeRecvMessageCallback(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  // Find pending op.
+  PendingBatch* pending = calld->PendingBatchFind(
+      "invoking recv_message_ready for",
+      [](grpc_transport_stream_op_batch* batch) {
+        return batch->recv_message &&
+               batch->payload->recv_message.recv_message_ready != nullptr;
+      });
+  GPR_ASSERT(pending != nullptr);
+  // Return payload.
+  *pending->batch->payload->recv_message.recv_message =
+      std::move(call_attempt->recv_message_);
+  // Update bookkeeping.
+  // Note: Need to do this before invoking the callback, since invoking
+  // the callback will result in yielding the call combiner.
+  grpc_closure* recv_message_ready =
+      pending->batch->payload->recv_message.recv_message_ready;
+  pending->batch->payload->recv_message.recv_message_ready = nullptr;
+  calld->MaybeClearPendingBatch(pending);
+  batch_data->Unref();
+  // Invoke callback.
+  Closure::Run(DEBUG_LOCATION, recv_message_ready, GRPC_ERROR_REF(error));
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::RecvMessageReady(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: got recv_message_ready, error=%s",
+            calld->chand_, calld, grpc_error_std_string(error).c_str());
+  }
+  ++call_attempt->completed_recv_message_count_;
+  // If a retry was already dispatched, then we're not going to use the
+  // result of this recv_message op, so do nothing.
+  if (call_attempt->retry_dispatched_) {
+    GRPC_CALL_COMBINER_STOP(calld->call_combiner_,
+                            "recv_message_ready after retry dispatched");
+    return;
+  }
+  if (!calld->retry_committed_) {
+    // If we got an error or the payload was nullptr and we have not yet gotten
+    // the recv_trailing_metadata_ready callback, then defer propagating this
+    // callback back to the surface.  We can evaluate whether to retry when
+    // recv_trailing_metadata comes back.
+    if (GPR_UNLIKELY((call_attempt->recv_message_ == nullptr ||
+                      error != GRPC_ERROR_NONE) &&
+                     !call_attempt->completed_recv_trailing_metadata_)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: deferring recv_message_ready (nullptr "
+                "message and recv_trailing_metadata pending)",
+                calld->chand_, calld);
+      }
+      call_attempt->recv_message_ready_deferred_batch_ = batch_data;
+      call_attempt->recv_message_error_ = GRPC_ERROR_REF(error);
+      if (!call_attempt->started_recv_trailing_metadata_) {
+        // recv_trailing_metadata not yet started by application; start it
+        // ourselves to get status.
+        call_attempt->StartInternalRecvTrailingMetadata();
+      } else {
+        GRPC_CALL_COMBINER_STOP(calld->call_combiner_,
+                                "recv_message_ready null");
+      }
+      return;
+    }
+    // Received a valid message, so commit the call.
+    calld->RetryCommit(call_attempt);
+  }
+  // Invoke the callback to return the result to the surface.
+  // Manually invoking a callback function; it does not take ownership of error.
+  InvokeRecvMessageCallback(batch_data, error);
+}
+
+//
+// recv_trailing_metadata handling
+//
+
+namespace {
+
+// Sets *status, *server_pushback_md, and *is_lb_drop based on md_batch
+// and error.
+void GetCallStatus(grpc_millis deadline, grpc_metadata_batch* md_batch,
+                   grpc_error_handle error, grpc_status_code* status,
+                   grpc_mdelem** server_pushback_md, bool* is_lb_drop) {
+  if (error != GRPC_ERROR_NONE) {
+    grpc_error_get_status(error, deadline, status, nullptr, nullptr, nullptr);
+    intptr_t value = 0;
+    if (grpc_error_get_int(error, GRPC_ERROR_INT_LB_POLICY_DROP, &value) &&
+        value != 0) {
+      *is_lb_drop = true;
+    }
+  } else {
+    GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
+    *status =
+        grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md);
+    if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
+      *server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+}  // namespace
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosureForRecvTrailingMetadataReady(grpc_error_handle error,
+                                           CallCombinerClosureList* closures) {
+  auto* calld = call_attempt_->calld_;
+  // Find pending batch.
+  PendingBatch* pending = calld->PendingBatchFind(
+      "invoking recv_trailing_metadata for",
+      [](grpc_transport_stream_op_batch* batch) {
+        return batch->recv_trailing_metadata &&
+               batch->payload->recv_trailing_metadata
+                       .recv_trailing_metadata_ready != nullptr;
+      });
+  // If we generated the recv_trailing_metadata op internally via
+  // StartInternalRecvTrailingMetadata(), then there will be no pending batch.
+  if (pending == nullptr) {
+    GRPC_ERROR_UNREF(error);
+    return;
+  }
+  // Return metadata.
+  grpc_metadata_batch_move(
+      &call_attempt_->recv_trailing_metadata_,
+      pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata);
+  // Add closure.
+  closures->Add(pending->batch->payload->recv_trailing_metadata
+                    .recv_trailing_metadata_ready,
+                error, "recv_trailing_metadata_ready for pending batch");
+  // Update bookkeeping.
+  pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+      nullptr;
+  calld->MaybeClearPendingBatch(pending);
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosuresForDeferredRecvCallbacks(CallCombinerClosureList* closures) {
+  if (batch_.recv_trailing_metadata) {
+    // Add closure for deferred recv_initial_metadata_ready.
+    if (GPR_UNLIKELY(
+            call_attempt_->recv_initial_metadata_ready_deferred_batch_ !=
+            nullptr)) {
+      GRPC_CLOSURE_INIT(
+          &call_attempt_->recv_initial_metadata_ready_,
+          InvokeRecvInitialMetadataCallback,
+          call_attempt_->recv_initial_metadata_ready_deferred_batch_,
+          grpc_schedule_on_exec_ctx);
+      closures->Add(&call_attempt_->recv_initial_metadata_ready_,
+                    call_attempt_->recv_initial_metadata_error_,
+                    "resuming recv_initial_metadata_ready");
+      call_attempt_->recv_initial_metadata_ready_deferred_batch_ = nullptr;
+    }
+    // Add closure for deferred recv_message_ready.
+    if (GPR_UNLIKELY(call_attempt_->recv_message_ready_deferred_batch_ !=
+                     nullptr)) {
+      GRPC_CLOSURE_INIT(&call_attempt_->recv_message_ready_,
+                        InvokeRecvMessageCallback,
+                        call_attempt_->recv_message_ready_deferred_batch_,
+                        grpc_schedule_on_exec_ctx);
+      closures->Add(&call_attempt_->recv_message_ready_,
+                    call_attempt_->recv_message_error_,
+                    "resuming recv_message_ready");
+      call_attempt_->recv_message_ready_deferred_batch_ = nullptr;
+    }
+  }
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosuresToFailUnstartedPendingBatches(
+        grpc_error_handle error, CallCombinerClosureList* closures) {
+  auto* calld = call_attempt_->calld_;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches_); ++i) {
+    PendingBatch* pending = &calld->pending_batches_[i];
+    if (call_attempt_->PendingBatchIsUnstarted(pending)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: failing unstarted pending batch at "
+                "index %" PRIuPTR,
+                calld->chand_, calld, i);
+      }
+      closures->Add(pending->batch->on_complete, GRPC_ERROR_REF(error),
+                    "failing on_complete for pending batch");
+      pending->batch->on_complete = nullptr;
+      calld->MaybeClearPendingBatch(pending);
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::RunClosuresForCompletedCall(
+    grpc_error_handle error) {
+  // Construct list of closures to execute.
+  CallCombinerClosureList closures;
+  // First, add closure for recv_trailing_metadata_ready.
+  AddClosureForRecvTrailingMetadataReady(GRPC_ERROR_REF(error), &closures);
+  // If there are deferred recv_initial_metadata_ready or recv_message_ready
+  // callbacks, add them to closures.
+  AddClosuresForDeferredRecvCallbacks(&closures);
+  // Add closures to fail any pending batches that have not yet been started.
+  AddClosuresToFailUnstartedPendingBatches(GRPC_ERROR_REF(error), &closures);
+  // Schedule all of the closures identified above.
+  // Note: This will release the call combiner.
+  closures.RunClosures(call_attempt_->calld_->call_combiner_);
+  // Don't need batch_data anymore.
+  Unref();
+  GRPC_ERROR_UNREF(error);
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::RecvTrailingMetadataReady(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: got recv_trailing_metadata_ready, error=%s",
+            calld->chand_, calld, grpc_error_std_string(error).c_str());
+  }
+  call_attempt->completed_recv_trailing_metadata_ = true;
+  // Get the call's status and check for server pushback metadata.
+  grpc_status_code status = GRPC_STATUS_OK;
+  grpc_mdelem* server_pushback_md = nullptr;
+  grpc_metadata_batch* md_batch =
+      batch_data->batch_.payload->recv_trailing_metadata.recv_trailing_metadata;
+  bool is_lb_drop = false;
+  GetCallStatus(calld->deadline_, md_batch, GRPC_ERROR_REF(error), &status,
+                &server_pushback_md, &is_lb_drop);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(
+        GPR_INFO, "chand=%p calld=%p: call finished, status=%s is_lb_drop=%d",
+        calld->chand_, calld, grpc_status_code_to_string(status), is_lb_drop);
+  }
+  // Check if we should retry.
+  if (batch_data->MaybeRetry(status, server_pushback_md, is_lb_drop)) {
+    // Unref batch_data for deferred recv_initial_metadata_ready or
+    // recv_message_ready callbacks, if any.
+    if (call_attempt->recv_initial_metadata_ready_deferred_batch_ != nullptr) {
+      GRPC_ERROR_UNREF(call_attempt->recv_initial_metadata_error_);
+      batch_data->Unref();
+    }
+    if (call_attempt->recv_message_ready_deferred_batch_ != nullptr) {
+      GRPC_ERROR_UNREF(call_attempt->recv_message_error_);
+      batch_data->Unref();
+    }
+    batch_data->Unref();
+    return;
+  }
+  // Not retrying, so commit the call.
+  calld->RetryCommit(call_attempt);
+  // Run any necessary closures.
+  batch_data->RunClosuresForCompletedCall(GRPC_ERROR_REF(error));
+}
+
+//
+// on_complete callback handling
+//
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosuresForCompletedPendingBatch(grpc_error_handle error,
+                                        CallCombinerClosureList* closures) {
+  auto* calld = call_attempt_->calld_;
+  PendingBatch* pending = calld->PendingBatchFind(
+      "completed", [this](grpc_transport_stream_op_batch* batch) {
+        // Match the pending batch with the same set of send ops as the
+        // batch we've just completed.
+        return batch->on_complete != nullptr &&
+               batch_.send_initial_metadata == batch->send_initial_metadata &&
+               batch_.send_message == batch->send_message &&
+               batch_.send_trailing_metadata == batch->send_trailing_metadata;
+      });
+  // If batch_data is a replay batch, then there will be no pending
+  // batch to complete.
+  if (pending == nullptr) {
+    GRPC_ERROR_UNREF(error);
+    return;
+  }
+  // Add closure.
+  closures->Add(pending->batch->on_complete, error,
+                "on_complete for pending batch");
+  pending->batch->on_complete = nullptr;
+  calld->MaybeClearPendingBatch(pending);
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosuresForReplayOrPendingSendOps(CallCombinerClosureList* closures) {
+  auto* calld = call_attempt_->calld_;
+  // We don't check send_initial_metadata here, because that op will always
+  // be started as soon as it is received from the surface, so it will
+  // never need to be started at this point.
+  bool have_pending_send_message_ops =
+      call_attempt_->started_send_message_count_ < calld->send_messages_.size();
+  bool have_pending_send_trailing_metadata_op =
+      calld->seen_send_trailing_metadata_ &&
+      !call_attempt_->started_send_trailing_metadata_;
+  if (!have_pending_send_message_ops &&
+      !have_pending_send_trailing_metadata_op) {
+    for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches_); ++i) {
+      PendingBatch* pending = &calld->pending_batches_[i];
+      grpc_transport_stream_op_batch* batch = pending->batch;
+      if (batch == nullptr || pending->send_ops_cached) continue;
+      if (batch->send_message) have_pending_send_message_ops = true;
+      if (batch->send_trailing_metadata) {
+        have_pending_send_trailing_metadata_op = true;
+      }
+    }
+  }
+  if (have_pending_send_message_ops || have_pending_send_trailing_metadata_op) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: starting next batch for pending send op(s)",
+              calld->chand_, calld);
+    }
+    call_attempt_->AddRetriableBatches(closures);
+  }
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::OnComplete(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: got on_complete, error=%s, batch=%s",
+            calld->chand_, calld, grpc_error_std_string(error).c_str(),
+            grpc_transport_stream_op_batch_string(&batch_data->batch_).c_str());
+  }
+  // Update bookkeeping in call_attempt.
+  if (batch_data->batch_.send_initial_metadata) {
+    call_attempt->completed_send_initial_metadata_ = true;
+  }
+  if (batch_data->batch_.send_message) {
+    ++call_attempt->completed_send_message_count_;
+  }
+  if (batch_data->batch_.send_trailing_metadata) {
+    call_attempt->completed_send_trailing_metadata_ = true;
+  }
+  // If the call is committed, free cached data for send ops that we've just
+  // completed.
+  if (calld->retry_committed_) {
+    batch_data->FreeCachedSendOpDataForCompletedBatch();
+  }
+  // Construct list of closures to execute.
+  CallCombinerClosureList closures;
+  // If a retry was already dispatched, that means we saw
+  // recv_trailing_metadata before this, so we do nothing here.
+  // Otherwise, invoke the callback to return the result to the surface.
+  if (!call_attempt->retry_dispatched_) {
+    // Add closure for the completed pending batch, if any.
+    batch_data->AddClosuresForCompletedPendingBatch(GRPC_ERROR_REF(error),
+                                                    &closures);
+    // If needed, add a callback to start any replay or pending send ops on
+    // the LB call.
+    if (!call_attempt->completed_recv_trailing_metadata_) {
+      batch_data->AddClosuresForReplayOrPendingSendOps(&closures);
+    }
+  }
+  // Track number of in-flight send batches and determine if this was the
+  // last one.
+  --calld->num_in_flight_call_attempt_send_batches_;
+  const bool last_send_batch_complete =
+      calld->num_in_flight_call_attempt_send_batches_ == 0;
+  // Don't need batch_data anymore.
+  batch_data->Unref();
+  // Schedule all of the closures identified above.
+  // Note: This yields the call combiner.
+  closures.RunClosures(calld->call_combiner_);
+  // If this was the last in-flight send batch, unref the call stack.
+  if (last_send_batch_complete) {
+    GRPC_CALL_STACK_UNREF(calld->owning_call_, "retriable_send_batches");
+  }
+}
+
+//
+// retriable batch construction
+//
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableSendInitialMetadataOp() {
+  auto* calld = call_attempt_->calld_;
+  // Maps the number of retries to the corresponding metadata value slice.
+  const grpc_slice* retry_count_strings[] = {&GRPC_MDSTR_1, &GRPC_MDSTR_2,
+                                             &GRPC_MDSTR_3, &GRPC_MDSTR_4};
+  // We need to make a copy of the metadata batch for each attempt, since
+  // the filters in the subchannel stack may modify this batch, and we don't
+  // want those modifications to be passed forward to subsequent attempts.
+  //
+  // If we've already completed one or more attempts, add the
+  // grpc-retry-attempts header.
+  call_attempt_->send_initial_metadata_storage_ =
+      static_cast<grpc_linked_mdelem*>(
+          calld->arena_->Alloc(sizeof(grpc_linked_mdelem) *
+                               (calld->send_initial_metadata_.list.count +
+                                (calld->num_attempts_completed_ > 0))));
+  grpc_metadata_batch_copy(&calld->send_initial_metadata_,
+                           &call_attempt_->send_initial_metadata_,
+                           call_attempt_->send_initial_metadata_storage_);
+  if (GPR_UNLIKELY(call_attempt_->send_initial_metadata_.idx.named
+                       .grpc_previous_rpc_attempts != nullptr)) {
+    grpc_metadata_batch_remove(&call_attempt_->send_initial_metadata_,
+                               GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS);
+  }
+  if (GPR_UNLIKELY(calld->num_attempts_completed_ > 0)) {
+    grpc_mdelem retry_md = grpc_mdelem_create(
+        GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS,
+        *retry_count_strings[calld->num_attempts_completed_ - 1], nullptr);
+    grpc_error_handle error = grpc_metadata_batch_add_tail(
+        &call_attempt_->send_initial_metadata_,
+        &call_attempt_->send_initial_metadata_storage_
+             [calld->send_initial_metadata_.list.count],
+        retry_md, GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS);
+    if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
+      gpr_log(GPR_ERROR, "error adding retry metadata: %s",
+              grpc_error_std_string(error).c_str());
+      GPR_ASSERT(false);
+    }
+  }
+  call_attempt_->started_send_initial_metadata_ = true;
+  batch_.send_initial_metadata = true;
+  batch_.payload->send_initial_metadata.send_initial_metadata =
+      &call_attempt_->send_initial_metadata_;
+  batch_.payload->send_initial_metadata.send_initial_metadata_flags =
+      calld->send_initial_metadata_flags_;
+  batch_.payload->send_initial_metadata.peer_string = calld->peer_string_;
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableSendMessageOp() {
+  auto* calld = call_attempt_->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: starting calld->send_messages[%" PRIuPTR "]",
+            calld->chand_, calld, call_attempt_->started_send_message_count_);
+  }
+  ByteStreamCache* cache =
+      calld->send_messages_[call_attempt_->started_send_message_count_];
+  ++call_attempt_->started_send_message_count_;
+  call_attempt_->send_message_.Init(cache);
+  batch_.send_message = true;
+  batch_.payload->send_message.send_message.reset(
+      call_attempt_->send_message_.get());
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableSendTrailingMetadataOp() {
+  auto* calld = call_attempt_->calld_;
+  // We need to make a copy of the metadata batch for each attempt, since
+  // the filters in the subchannel stack may modify this batch, and we don't
+  // want those modifications to be passed forward to subsequent attempts.
+  call_attempt_->send_trailing_metadata_storage_ =
+      static_cast<grpc_linked_mdelem*>(
+          calld->arena_->Alloc(sizeof(grpc_linked_mdelem) *
+                               calld->send_trailing_metadata_.list.count));
+  grpc_metadata_batch_copy(&calld->send_trailing_metadata_,
+                           &call_attempt_->send_trailing_metadata_,
+                           call_attempt_->send_trailing_metadata_storage_);
+  call_attempt_->started_send_trailing_metadata_ = true;
+  batch_.send_trailing_metadata = true;
+  batch_.payload->send_trailing_metadata.send_trailing_metadata =
+      &call_attempt_->send_trailing_metadata_;
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableRecvInitialMetadataOp() {
+  call_attempt_->started_recv_initial_metadata_ = true;
+  batch_.recv_initial_metadata = true;
+  grpc_metadata_batch_init(&call_attempt_->recv_initial_metadata_);
+  batch_.payload->recv_initial_metadata.recv_initial_metadata =
+      &call_attempt_->recv_initial_metadata_;
+  batch_.payload->recv_initial_metadata.trailing_metadata_available =
+      &call_attempt_->trailing_metadata_available_;
+  GRPC_CLOSURE_INIT(&call_attempt_->recv_initial_metadata_ready_,
+                    RecvInitialMetadataReady, this, grpc_schedule_on_exec_ctx);
+  batch_.payload->recv_initial_metadata.recv_initial_metadata_ready =
+      &call_attempt_->recv_initial_metadata_ready_;
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableRecvMessageOp() {
+  ++call_attempt_->started_recv_message_count_;
+  batch_.recv_message = true;
+  batch_.payload->recv_message.recv_message = &call_attempt_->recv_message_;
+  GRPC_CLOSURE_INIT(&call_attempt_->recv_message_ready_, RecvMessageReady, this,
+                    grpc_schedule_on_exec_ctx);
+  batch_.payload->recv_message.recv_message_ready =
+      &call_attempt_->recv_message_ready_;
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableRecvTrailingMetadataOp() {
+  call_attempt_->started_recv_trailing_metadata_ = true;
+  batch_.recv_trailing_metadata = true;
+  grpc_metadata_batch_init(&call_attempt_->recv_trailing_metadata_);
+  batch_.payload->recv_trailing_metadata.recv_trailing_metadata =
+      &call_attempt_->recv_trailing_metadata_;
+  batch_.payload->recv_trailing_metadata.collect_stats =
+      &call_attempt_->collect_stats_;
+  GRPC_CLOSURE_INIT(&call_attempt_->recv_trailing_metadata_ready_,
+                    RecvTrailingMetadataReady, this, grpc_schedule_on_exec_ctx);
+  batch_.payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+      &call_attempt_->recv_trailing_metadata_ready_;
+}
+
+//
+// CallData vtable functions
+//
+
+grpc_error_handle RetryFilter::CallData::Init(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
+  auto* chand = static_cast<RetryFilter*>(elem->channel_data);
+  new (elem->call_data) CallData(chand, *args);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p: created call=%p", chand, elem->call_data);
+  }
+  return GRPC_ERROR_NONE;
+}
+
+void RetryFilter::CallData::Destroy(grpc_call_element* elem,
+                                    const grpc_call_final_info* /*final_info*/,
+                                    grpc_closure* then_schedule_closure) {
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  // Save our ref to the CallStackDestructionBarrier until after our
+  // dtor is invoked.
+  RefCountedPtr<CallStackDestructionBarrier> call_stack_destruction_barrier =
+      std::move(calld->call_stack_destruction_barrier_);
+  calld->~CallData();
+  // Now set the callback in the CallStackDestructionBarrier object,
+  // right before we release our ref to it (implicitly upon returning).
+  // The callback will be invoked when the CallStackDestructionBarrier
+  // is destroyed.
+  call_stack_destruction_barrier->set_on_call_stack_destruction(
+      then_schedule_closure);
+}
+
+void RetryFilter::CallData::StartTransportStreamOpBatch(
+    grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  calld->StartTransportStreamOpBatch(batch);
+}
+
+void RetryFilter::CallData::SetPollent(grpc_call_element* elem,
+                                       grpc_polling_entity* pollent) {
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  calld->pollent_ = pollent;
+}
+
+//
+// CallData implementation
+//
+
+const RetryMethodConfig* GetRetryPolicy(
+    const grpc_call_context_element* context) {
+  if (context == nullptr) return nullptr;
+  auto* svc_cfg_call_data = static_cast<ServiceConfigCallData*>(
+      context[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value);
+  if (svc_cfg_call_data == nullptr) return nullptr;
+  return static_cast<const RetryMethodConfig*>(
+      svc_cfg_call_data->GetMethodParsedConfig(
+          RetryServiceConfigParser::ParserIndex()));
+}
+
+RetryFilter::CallData::CallData(RetryFilter* chand,
+                                const grpc_call_element_args& args)
+    : chand_(chand),
+      retry_throttle_data_(chand->retry_throttle_data_),
+      retry_policy_(GetRetryPolicy(args.context)),
+      retry_backoff_(
+          BackOff::Options()
+              .set_initial_backoff(retry_policy_ == nullptr
+                                       ? 0
+                                       : retry_policy_->initial_backoff())
+              .set_multiplier(retry_policy_ == nullptr
+                                  ? 0
+                                  : retry_policy_->backoff_multiplier())
+              .set_jitter(RETRY_BACKOFF_JITTER)
+              .set_max_backoff(
+                  retry_policy_ == nullptr ? 0 : retry_policy_->max_backoff())),
+      path_(grpc_slice_ref_internal(args.path)),
+      call_start_time_(args.start_time),
+      deadline_(args.deadline),
+      arena_(args.arena),
+      owning_call_(args.call_stack),
+      call_combiner_(args.call_combiner),
+      call_context_(args.context),
+      call_stack_destruction_barrier_(
+          arena_->New<CallStackDestructionBarrier>()),
+      pending_send_initial_metadata_(false),
+      pending_send_message_(false),
+      pending_send_trailing_metadata_(false),
+      retry_committed_(false),
+      last_attempt_got_server_pushback_(false) {}
+
+RetryFilter::CallData::~CallData() {
+  grpc_slice_unref_internal(path_);
+  // Make sure there are no remaining pending batches.
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
+    GPR_ASSERT(pending_batches_[i].batch == nullptr);
+  }
+}
+
+void RetryFilter::CallData::StartTransportStreamOpBatch(
+    grpc_transport_stream_op_batch* batch) {
+  // If we have an LB call, delegate to the LB call.
+  if (committed_call_ != nullptr) {
+    // Note: This will release the call combiner.
+    committed_call_->StartTransportStreamOpBatch(batch);
+    return;
+  }
+  // Handle cancellation.
+  if (GPR_UNLIKELY(batch->cancel_stream)) {
+    grpc_error_handle cancel_error = batch->payload->cancel_stream.cancel_error;
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: cancelled from surface: %s", chand_,
+              this, grpc_error_std_string(cancel_error).c_str());
+    }
+    // If we have a current call attempt, commit the call, then send
+    // the cancellation down to that attempt.  When the call fails, it
+    // will not be retried, because we have committed it here.
+    if (call_attempt_ != nullptr) {
+      RetryCommit(call_attempt_.get());
+      // Note: This will release the call combiner.
+      call_attempt_->lb_call()->StartTransportStreamOpBatch(batch);
+      return;
+    }
+    // Fail pending batches.
+    PendingBatchesFail(GRPC_ERROR_REF(cancel_error));
+    // Note: This will release the call combiner.
+    grpc_transport_stream_op_batch_finish_with_failure(
+        batch, GRPC_ERROR_REF(cancel_error), call_combiner_);
+    return;
+  }
+  // Add the batch to the pending list.
+  PendingBatch* pending = PendingBatchesAdd(batch);
+  if (call_attempt_ == nullptr) {
+    // If this is the first batch and retries are already committed
+    // (e.g., if this batch put the call above the buffer size limit), then
+    // immediately create an LB call and delegate the batch to it.  This
+    // avoids the overhead of unnecessarily allocating a CallAttempt
+    // object or caching any of the send op data.
+    if (num_attempts_completed_ == 0 && retry_committed_) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: retry committed before first attempt; "
+                "creating LB call",
+                chand_, this);
+      }
+      PendingBatchClear(pending);
+      committed_call_ = CreateLoadBalancedCall();
+      committed_call_->StartTransportStreamOpBatch(batch);
+      return;
+    }
+    // We do not yet have a call attempt, so create one.
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: creating call attempt", chand_,
+              this);
+    }
+    CreateCallAttempt();
+    return;
+  }
+  // Send batches to call attempt.
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: starting batch on attempt=%p lb_call=%p",
+            chand_, this, call_attempt_.get(), call_attempt_->lb_call());
+  }
+  call_attempt_->StartRetriableBatches();
+}
+
+RefCountedPtr<ClientChannel::LoadBalancedCall>
+RetryFilter::CallData::CreateLoadBalancedCall() {
+  grpc_call_element_args args = {owning_call_, nullptr,          call_context_,
+                                 path_,        call_start_time_, deadline_,
+                                 arena_,       call_combiner_};
+  return chand_->client_channel_->CreateLoadBalancedCall(
+      args, pollent_,
+      // This callback holds a ref to the CallStackDestructionBarrier
+      // object until the LB call is destroyed.
+      call_stack_destruction_barrier_->MakeLbCallDestructionClosure(this));
+}
+
+void RetryFilter::CallData::CreateCallAttempt() {
+  call_attempt_.reset(arena_->New<CallAttempt>(this));
+  call_attempt_->StartRetriableBatches();
+  // TODO(roth): When implementing hedging, change this to start a timer
+  // for the next hedging attempt.
+}
+
+namespace {
+
+void StartBatchInCallCombiner(void* arg, grpc_error_handle /*ignored*/) {
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
+  auto* lb_call = static_cast<ClientChannel::LoadBalancedCall*>(
+      batch->handler_private.extra_arg);
+  // Note: This will release the call combiner.
+  lb_call->StartTransportStreamOpBatch(batch);
+}
+
+}  // namespace
+
+void RetryFilter::CallData::AddClosureForBatch(
+    grpc_transport_stream_op_batch* batch, CallCombinerClosureList* closures) {
+  batch->handler_private.extra_arg = call_attempt_->lb_call();
+  GRPC_CLOSURE_INIT(&batch->handler_private.closure, StartBatchInCallCombiner,
+                    batch, grpc_schedule_on_exec_ctx);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: starting batch on LB call: %s",
+            chand_, this, grpc_transport_stream_op_batch_string(batch).c_str());
+  }
+  closures->Add(&batch->handler_private.closure, GRPC_ERROR_NONE,
+                "start_batch_on_lb_call");
+}
+
+//
+// send op data caching
+//
+
+void RetryFilter::CallData::MaybeCacheSendOpsForBatch(PendingBatch* pending) {
+  if (pending->send_ops_cached) return;
+  pending->send_ops_cached = true;
+  grpc_transport_stream_op_batch* batch = pending->batch;
+  // Save a copy of metadata for send_initial_metadata ops.
+  if (batch->send_initial_metadata) {
+    seen_send_initial_metadata_ = true;
+    GPR_ASSERT(send_initial_metadata_storage_ == nullptr);
+    grpc_metadata_batch* send_initial_metadata =
+        batch->payload->send_initial_metadata.send_initial_metadata;
+    send_initial_metadata_storage_ =
+        static_cast<grpc_linked_mdelem*>(arena_->Alloc(
+            sizeof(grpc_linked_mdelem) * send_initial_metadata->list.count));
+    grpc_metadata_batch_copy(send_initial_metadata, &send_initial_metadata_,
+                             send_initial_metadata_storage_);
+    send_initial_metadata_flags_ =
+        batch->payload->send_initial_metadata.send_initial_metadata_flags;
+    peer_string_ = batch->payload->send_initial_metadata.peer_string;
+  }
+  // Set up cache for send_message ops.
+  if (batch->send_message) {
+    ByteStreamCache* cache = arena_->New<ByteStreamCache>(
+        std::move(batch->payload->send_message.send_message));
+    send_messages_.push_back(cache);
+  }
+  // Save metadata batch for send_trailing_metadata ops.
+  if (batch->send_trailing_metadata) {
+    seen_send_trailing_metadata_ = true;
+    GPR_ASSERT(send_trailing_metadata_storage_ == nullptr);
+    grpc_metadata_batch* send_trailing_metadata =
+        batch->payload->send_trailing_metadata.send_trailing_metadata;
+    send_trailing_metadata_storage_ =
+        static_cast<grpc_linked_mdelem*>(arena_->Alloc(
+            sizeof(grpc_linked_mdelem) * send_trailing_metadata->list.count));
+    grpc_metadata_batch_copy(send_trailing_metadata, &send_trailing_metadata_,
+                             send_trailing_metadata_storage_);
+  }
+}
+
+void RetryFilter::CallData::FreeCachedSendInitialMetadata() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: destroying send_initial_metadata",
+            chand_, this);
+  }
+  grpc_metadata_batch_destroy(&send_initial_metadata_);
+}
+
+void RetryFilter::CallData::FreeCachedSendMessage(size_t idx) {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: destroying send_messages[%" PRIuPTR "]", chand_,
+            this, idx);
+  }
+  send_messages_[idx]->Destroy();
+}
+
+void RetryFilter::CallData::FreeCachedSendTrailingMetadata() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand_=%p calld=%p: destroying send_trailing_metadata",
+            chand_, this);
+  }
+  grpc_metadata_batch_destroy(&send_trailing_metadata_);
+}
+
+void RetryFilter::CallData::FreeAllCachedSendOpData() {
+  if (seen_send_initial_metadata_) {
+    FreeCachedSendInitialMetadata();
+  }
+  for (size_t i = 0; i < send_messages_.size(); ++i) {
+    FreeCachedSendMessage(i);
+  }
+  if (seen_send_trailing_metadata_) {
+    FreeCachedSendTrailingMetadata();
+  }
+}
+
+//
+// pending_batches management
+//
+
+size_t RetryFilter::CallData::GetBatchIndex(
+    grpc_transport_stream_op_batch* batch) {
+  if (batch->send_initial_metadata) return 0;
+  if (batch->send_message) return 1;
+  if (batch->send_trailing_metadata) return 2;
+  if (batch->recv_initial_metadata) return 3;
+  if (batch->recv_message) return 4;
+  if (batch->recv_trailing_metadata) return 5;
+  GPR_UNREACHABLE_CODE(return (size_t)-1);
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+RetryFilter::CallData::PendingBatch* RetryFilter::CallData::PendingBatchesAdd(
+    grpc_transport_stream_op_batch* batch) {
+  const size_t idx = GetBatchIndex(batch);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand_=%p calld=%p: adding pending batch at index %" PRIuPTR,
+            chand_, this, idx);
+  }
+  PendingBatch* pending = &pending_batches_[idx];
+  GPR_ASSERT(pending->batch == nullptr);
+  pending->batch = batch;
+  pending->send_ops_cached = false;
+  // Update state in calld about pending batches.
+  // Also check if the batch takes us over the retry buffer limit.
+  // Note: We don't check the size of trailing metadata here, because
+  // gRPC clients do not send trailing metadata.
+  if (batch->send_initial_metadata) {
+    pending_send_initial_metadata_ = true;
+    bytes_buffered_for_retry_ += grpc_metadata_batch_size(
+        batch->payload->send_initial_metadata.send_initial_metadata);
+  }
+  if (batch->send_message) {
+    pending_send_message_ = true;
+    bytes_buffered_for_retry_ +=
+        batch->payload->send_message.send_message->length();
+  }
+  if (batch->send_trailing_metadata) {
+    pending_send_trailing_metadata_ = true;
+  }
+  if (GPR_UNLIKELY(bytes_buffered_for_retry_ >
+                   chand_->per_rpc_retry_buffer_size_)) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: exceeded retry buffer size, committing",
+              chand_, this);
+    }
+    RetryCommit(call_attempt_.get());
+  }
+  return pending;
+}
+
+void RetryFilter::CallData::PendingBatchClear(PendingBatch* pending) {
+  if (pending->batch->send_initial_metadata) {
+    pending_send_initial_metadata_ = false;
+  }
+  if (pending->batch->send_message) {
+    pending_send_message_ = false;
+  }
+  if (pending->batch->send_trailing_metadata) {
+    pending_send_trailing_metadata_ = false;
+  }
+  pending->batch = nullptr;
+}
+
+void RetryFilter::CallData::MaybeClearPendingBatch(PendingBatch* pending) {
+  grpc_transport_stream_op_batch* batch = pending->batch;
+  // We clear the pending batch if all of its callbacks have been
+  // scheduled and reset to nullptr.
+  if (batch->on_complete == nullptr &&
+      (!batch->recv_initial_metadata ||
+       batch->payload->recv_initial_metadata.recv_initial_metadata_ready ==
+           nullptr) &&
+      (!batch->recv_message ||
+       batch->payload->recv_message.recv_message_ready == nullptr) &&
+      (!batch->recv_trailing_metadata ||
+       batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready ==
+           nullptr)) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: clearing pending batch", chand_,
+              this);
+    }
+    PendingBatchClear(pending);
+  }
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+void RetryFilter::CallData::FailPendingBatchInCallCombiner(
+    void* arg, grpc_error_handle error) {
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
+  CallData* call = static_cast<CallData*>(batch->handler_private.extra_arg);
+  // Note: This will release the call combiner.
+  grpc_transport_stream_op_batch_finish_with_failure(
+      batch, GRPC_ERROR_REF(error), call->call_combiner_);
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+void RetryFilter::CallData::PendingBatchesFail(grpc_error_handle error) {
+  GPR_ASSERT(error != GRPC_ERROR_NONE);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    size_t num_batches = 0;
+    for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
+      if (pending_batches_[i].batch != nullptr) ++num_batches;
+    }
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s",
+            chand_, this, num_batches, grpc_error_std_string(error).c_str());
+  }
+  CallCombinerClosureList closures;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
+    PendingBatch* pending = &pending_batches_[i];
+    grpc_transport_stream_op_batch* batch = pending->batch;
+    if (batch != nullptr) {
+      batch->handler_private.extra_arg = this;
+      GRPC_CLOSURE_INIT(&batch->handler_private.closure,
+                        FailPendingBatchInCallCombiner, batch,
+                        grpc_schedule_on_exec_ctx);
+      closures.Add(&batch->handler_private.closure, GRPC_ERROR_REF(error),
+                   "PendingBatchesFail");
+      PendingBatchClear(pending);
+    }
+  }
+  closures.RunClosuresWithoutYielding(call_combiner_);
+  GRPC_ERROR_UNREF(error);
+}
+
+template <typename Predicate>
+RetryFilter::CallData::PendingBatch* RetryFilter::CallData::PendingBatchFind(
+    const char* log_message, Predicate predicate) {
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
+    PendingBatch* pending = &pending_batches_[i];
+    grpc_transport_stream_op_batch* batch = pending->batch;
+    if (batch != nullptr && predicate(batch)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: %s pending batch at index %" PRIuPTR,
+                chand_, this, log_message, i);
+      }
+      return pending;
+    }
+  }
+  return nullptr;
+}
+
+//
+// retry code
+//
+
+void RetryFilter::CallData::RetryCommit(CallAttempt* call_attempt) {
+  if (retry_committed_) return;
+  retry_committed_ = true;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: committing retries", chand_, this);
+  }
+  if (call_attempt != nullptr) {
+    call_attempt->FreeCachedSendOpDataAfterCommit();
+  }
+}
+
+void RetryFilter::CallData::DoRetry(grpc_millis server_pushback_ms) {
+  // Reset call attempt.
+  call_attempt_.reset();
+  // Compute backoff delay.
+  grpc_millis next_attempt_time;
+  if (server_pushback_ms >= 0) {
+    next_attempt_time = ExecCtx::Get()->Now() + server_pushback_ms;
+    last_attempt_got_server_pushback_ = true;
+  } else {
+    if (num_attempts_completed_ == 1 || last_attempt_got_server_pushback_) {
+      last_attempt_got_server_pushback_ = false;
+    }
+    next_attempt_time = retry_backoff_.NextAttemptTime();
+  }
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: retrying failed call in %" PRId64 " ms", chand_,
+            this, next_attempt_time - ExecCtx::Get()->Now());
+  }
+  // Schedule retry after computed delay.
+  GRPC_CLOSURE_INIT(&retry_closure_, OnRetryTimer, this, nullptr);
+  GRPC_CALL_STACK_REF(owning_call_, "OnRetryTimer");
+  MutexLock lock(&timer_mu_);
+  canceller_ = new Canceller(this);
+  grpc_timer_init(&retry_timer_, next_attempt_time, &retry_closure_);
+}
+
+void RetryFilter::CallData::OnRetryTimer(void* arg, grpc_error_handle error) {
+  auto* calld = static_cast<CallData*>(arg);
+  if (error == GRPC_ERROR_NONE) {
+    bool start_attempt = false;
+    {
+      MutexLock lock(&calld->timer_mu_);
+      if (calld->canceller_ != nullptr) {
+        calld->canceller_ = nullptr;
+        start_attempt = true;
+      }
+    }
+    if (start_attempt) calld->CreateCallAttempt();
+  }
+  GRPC_CALL_STACK_UNREF(calld->owning_call_, "OnRetryTimer");
+}
+
+}  // namespace
+
+const grpc_channel_filter kRetryFilterVtable = {
+    RetryFilter::CallData::StartTransportStreamOpBatch,
+    RetryFilter::StartTransportOp,
+    sizeof(RetryFilter::CallData),
+    RetryFilter::CallData::Init,
+    RetryFilter::CallData::SetPollent,
+    RetryFilter::CallData::Destroy,
+    sizeof(RetryFilter),
+    RetryFilter::Init,
+    RetryFilter::Destroy,
+    RetryFilter::GetChannelInfo,
+    "retry_filter",
+};
+
+}  // namespace grpc_core
@@ -1,4 +1,5 @@
-// Copyright 2020 gRPC authors.
+//
+// Copyright 2021 gRPC authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+//
 
-#ifndef GRPC_TEST_CORE_UTIL_EVAL_ARGS_MOCK_ENDPOINT_H
-#define GRPC_TEST_CORE_UTIL_EVAL_ARGS_MOCK_ENDPOINT_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_FILTER_H
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/channel/channel_stack.h"
 
 namespace grpc_core {
 
-grpc_endpoint* CreateEvalArgsMockEndpoint(const char* local_address,
-                                          const int local_port,
-                                          const char* peer_address,
-                                          const int peer_port);
+extern const grpc_channel_filter kRetryFilterVtable;
 
 }  // namespace grpc_core
 
-#endif  // GRPC_TEST_CORE_UTIL_EVAL_ARGS_MOCK_ENDPOINT_H
+#endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_FILTER_H
diff --git a/src/core/ext/filters/client_channel/retry_service_config.cc b/src/core/ext/filters/client_channel/retry_service_config.cc
new file mode 100644 (file)
index 0000000..fc066e6
--- /dev/null
@@ -0,0 +1,287 @@
+//
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/filters/client_channel/retry_service_config.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "absl/strings/str_cat.h"
+#include "absl/types/optional.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/json/json_util.h"
+#include "src/core/lib/uri/uri_parser.h"
+
+// As per the retry design, we do not allow more than 5 retry attempts.
+#define MAX_MAX_RETRY_ATTEMPTS 5
+
+namespace grpc_core {
+namespace internal {
+
+namespace {
+size_t g_retry_service_config_parser_index;
+}
+
+size_t RetryServiceConfigParser::ParserIndex() {
+  return g_retry_service_config_parser_index;
+}
+
+void RetryServiceConfigParser::Register() {
+  g_retry_service_config_parser_index = ServiceConfigParser::RegisterParser(
+      absl::make_unique<RetryServiceConfigParser>());
+}
+
+namespace {
+
+grpc_error_handle ParseRetryThrottling(const Json& json,
+                                       intptr_t* max_milli_tokens,
+                                       intptr_t* milli_token_ratio) {
+  if (json.type() != Json::Type::OBJECT) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling error:Type should be object");
+  }
+  std::vector<grpc_error_handle> error_list;
+  // Parse maxTokens.
+  auto it = json.object_value().find("maxTokens");
+  if (it == json.object_value().end()) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling field:maxTokens error:Not found"));
+  } else if (it->second.type() != Json::Type::NUMBER) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling field:maxTokens error:Type should be "
+        "number"));
+  } else {
+    *max_milli_tokens =
+        gpr_parse_nonnegative_int(it->second.string_value().c_str()) * 1000;
+    if (*max_milli_tokens <= 0) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryThrottling field:maxTokens error:should be "
+          "greater than zero"));
+    }
+  }
+  // Parse tokenRatio.
+  it = json.object_value().find("tokenRatio");
+  if (it == json.object_value().end()) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling field:tokenRatio error:Not found"));
+  } else if (it->second.type() != Json::Type::NUMBER) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling field:tokenRatio error:type should be "
+        "number"));
+  } else {
+    // We support up to 3 decimal digits.
+    size_t whole_len = it->second.string_value().size();
+    const char* value = it->second.string_value().c_str();
+    uint32_t multiplier = 1;
+    uint32_t decimal_value = 0;
+    const char* decimal_point = strchr(value, '.');
+    if (decimal_point != nullptr) {
+      whole_len = static_cast<size_t>(decimal_point - value);
+      multiplier = 1000;
+      size_t decimal_len = strlen(decimal_point + 1);
+      if (decimal_len > 3) decimal_len = 3;
+      if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
+                                     &decimal_value)) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:retryThrottling field:tokenRatio error:Failed "
+            "parsing"));
+        return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
+      }
+      uint32_t decimal_multiplier = 1;
+      for (size_t i = 0; i < (3 - decimal_len); ++i) {
+        decimal_multiplier *= 10;
+      }
+      decimal_value *= decimal_multiplier;
+    }
+    uint32_t whole_value;
+    if (!gpr_parse_bytes_to_uint32(value, whole_len, &whole_value)) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryThrottling field:tokenRatio error:Failed "
+          "parsing"));
+      return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
+    }
+    *milli_token_ratio =
+        static_cast<int>((whole_value * multiplier) + decimal_value);
+    if (*milli_token_ratio <= 0) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryThrottling field:tokenRatio error:value should "
+          "be greater than 0"));
+    }
+  }
+  return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
+}
+
+}  // namespace
+
+std::unique_ptr<ServiceConfigParser::ParsedConfig>
+RetryServiceConfigParser::ParseGlobalParams(const grpc_channel_args* /*args*/,
+                                            const Json& json,
+                                            grpc_error_handle* error) {
+  GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
+  auto it = json.object_value().find("retryThrottling");
+  if (it == json.object_value().end()) return nullptr;
+  intptr_t max_milli_tokens = 0;
+  intptr_t milli_token_ratio = 0;
+  *error =
+      ParseRetryThrottling(it->second, &max_milli_tokens, &milli_token_ratio);
+  if (*error != GRPC_ERROR_NONE) return nullptr;
+  return absl::make_unique<RetryGlobalConfig>(max_milli_tokens,
+                                              milli_token_ratio);
+}
+
+namespace {
+
+grpc_error_handle ParseRetryPolicy(const Json& json, int* max_attempts,
+                                   grpc_millis* initial_backoff,
+                                   grpc_millis* max_backoff,
+                                   float* backoff_multiplier,
+                                   StatusCodeSet* retryable_status_codes) {
+  if (json.type() != Json::Type::OBJECT) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryPolicy error:should be of type object");
+  }
+  std::vector<grpc_error_handle> error_list;
+  // Parse maxAttempts.
+  auto it = json.object_value().find("maxAttempts");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::NUMBER) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:maxAttempts error:should be of type number"));
+    } else {
+      *max_attempts =
+          gpr_parse_nonnegative_int(it->second.string_value().c_str());
+      if (*max_attempts <= 1) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:maxAttempts error:should be at least 2"));
+      } else if (*max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
+        gpr_log(GPR_ERROR,
+                "service config: clamped retryPolicy.maxAttempts at %d",
+                MAX_MAX_RETRY_ATTEMPTS);
+        *max_attempts = MAX_MAX_RETRY_ATTEMPTS;
+      }
+    }
+  }
+  // Parse initialBackoff.
+  if (ParseJsonObjectFieldAsDuration(json.object_value(), "initialBackoff",
+                                     initial_backoff, &error_list) &&
+      *initial_backoff == 0) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:initialBackoff error:must be greater than 0"));
+  }
+  // Parse maxBackoff.
+  if (ParseJsonObjectFieldAsDuration(json.object_value(), "maxBackoff",
+                                     max_backoff, &error_list) &&
+      *max_backoff == 0) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:maxBackoff error:should be greater than 0"));
+  }
+  // Parse backoffMultiplier.
+  it = json.object_value().find("backoffMultiplier");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::NUMBER) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:backoffMultiplier error:should be of type number"));
+    } else {
+      if (sscanf(it->second.string_value().c_str(), "%f", backoff_multiplier) !=
+          1) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:backoffMultiplier error:failed to parse"));
+      } else if (*backoff_multiplier <= 0) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:backoffMultiplier error:should be greater than 0"));
+      }
+    }
+  }
+  // Parse retryableStatusCodes.
+  it = json.object_value().find("retryableStatusCodes");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::ARRAY) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryableStatusCodes error:should be of type array"));
+    } else {
+      for (const Json& element : it->second.array_value()) {
+        if (element.type() != Json::Type::STRING) {
+          error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+              "field:retryableStatusCodes error:status codes should be of type "
+              "string"));
+          continue;
+        }
+        grpc_status_code status;
+        if (!grpc_status_code_from_string(element.string_value().c_str(),
+                                          &status)) {
+          error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+              "field:retryableStatusCodes error:failed to parse status code"));
+          continue;
+        }
+        retryable_status_codes->Add(status);
+      }
+      if (retryable_status_codes->Empty()) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:retryableStatusCodes error:should be non-empty"));
+      };
+    }
+  }
+  // Make sure required fields are set.
+  if (error_list.empty()) {
+    if (*max_attempts == 0 || *initial_backoff == 0 || *max_backoff == 0 ||
+        *backoff_multiplier == 0 || retryable_status_codes->Empty()) {
+      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryPolicy error:Missing required field(s)");
+    }
+  }
+  return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
+}
+
+}  // namespace
+
+std::unique_ptr<ServiceConfigParser::ParsedConfig>
+RetryServiceConfigParser::ParsePerMethodParams(
+    const grpc_channel_args* /*args*/, const Json& json,
+    grpc_error_handle* error) {
+  GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
+  // Parse retry policy.
+  auto it = json.object_value().find("retryPolicy");
+  if (it == json.object_value().end()) return nullptr;
+  int max_attempts = 0;
+  grpc_millis initial_backoff = 0;
+  grpc_millis max_backoff = 0;
+  float backoff_multiplier = 0;
+  StatusCodeSet retryable_status_codes;
+  *error = ParseRetryPolicy(it->second, &max_attempts, &initial_backoff,
+                            &max_backoff, &backoff_multiplier,
+                            &retryable_status_codes);
+  if (*error != GRPC_ERROR_NONE) return nullptr;
+  return absl::make_unique<RetryMethodConfig>(max_attempts, initial_backoff,
+                                              max_backoff, backoff_multiplier,
+                                              retryable_status_codes);
+}
+
+}  // namespace internal
+}  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/retry_service_config.h b/src/core/ext/filters/client_channel/retry_service_config.h
new file mode 100644 (file)
index 0000000..256183f
--- /dev/null
@@ -0,0 +1,90 @@
+//
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_SERVICE_CONFIG_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_SERVICE_CONFIG_H
+
+#include <grpc/support/port_platform.h>
+
+#include <memory>
+
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/service_config_parser.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/iomgr/exec_ctx.h"  // for grpc_millis
+
+namespace grpc_core {
+namespace internal {
+
+class RetryGlobalConfig : public ServiceConfigParser::ParsedConfig {
+ public:
+  RetryGlobalConfig(intptr_t max_milli_tokens, intptr_t milli_token_ratio)
+      : max_milli_tokens_(max_milli_tokens),
+        milli_token_ratio_(milli_token_ratio) {}
+
+  intptr_t max_milli_tokens() const { return max_milli_tokens_; }
+  intptr_t milli_token_ratio() const { return milli_token_ratio_; }
+
+ private:
+  intptr_t max_milli_tokens_ = 0;
+  intptr_t milli_token_ratio_ = 0;
+};
+
+class RetryMethodConfig : public ServiceConfigParser::ParsedConfig {
+ public:
+  RetryMethodConfig(int max_attempts, grpc_millis initial_backoff,
+                    grpc_millis max_backoff, float backoff_multiplier,
+                    StatusCodeSet retryable_status_codes)
+      : max_attempts_(max_attempts),
+        initial_backoff_(initial_backoff),
+        max_backoff_(max_backoff),
+        backoff_multiplier_(backoff_multiplier),
+        retryable_status_codes_(retryable_status_codes) {}
+
+  int max_attempts() const { return max_attempts_; }
+  grpc_millis initial_backoff() const { return initial_backoff_; }
+  grpc_millis max_backoff() const { return max_backoff_; }
+  float backoff_multiplier() const { return backoff_multiplier_; }
+  StatusCodeSet retryable_status_codes() const {
+    return retryable_status_codes_;
+  }
+
+ private:
+  int max_attempts_ = 0;
+  grpc_millis initial_backoff_ = 0;
+  grpc_millis max_backoff_ = 0;
+  float backoff_multiplier_ = 0;
+  StatusCodeSet retryable_status_codes_;
+};
+
+class RetryServiceConfigParser : public ServiceConfigParser::Parser {
+ public:
+  std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
+      const grpc_channel_args* /*args*/, const Json& json,
+      grpc_error_handle* error) override;
+
+  std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
+      const grpc_channel_args* /*args*/, const Json& json,
+      grpc_error_handle* error) override;
+
+  static size_t ParserIndex();
+  static void Register();
+};
+
+}  // namespace internal
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_SERVICE_CONFIG_H
index bd8af27..e082256 100644 (file)
@@ -27,7 +27,7 @@
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_join.h"
 
-#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 
 namespace grpc_core {
 
index a2794f1..b87226c 100644 (file)
@@ -32,7 +32,7 @@ namespace grpc_core {
 
 RefCountedPtr<ServiceConfig> ServiceConfig::Create(
     const grpc_channel_args* args, absl::string_view json_string,
-    grpc_error** error) {
+    grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr);
   Json json = Json::Parse(json_string, error);
   if (*error != GRPC_ERROR_NONE) return nullptr;
@@ -42,7 +42,7 @@ RefCountedPtr<ServiceConfig> ServiceConfig::Create(
 
 ServiceConfig::ServiceConfig(const grpc_channel_args* args,
                              std::string json_string, Json json,
-                             grpc_error** error)
+                             grpc_error_handle* error)
     : json_string_(std::move(json_string)), json_(std::move(json)) {
   GPR_DEBUG_ASSERT(error != nullptr);
   if (json_.type() != Json::Type::OBJECT) {
@@ -50,12 +50,12 @@ ServiceConfig::ServiceConfig(const grpc_channel_args* args,
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON value is not an object");
     return;
   }
-  std::vector<grpc_error*> error_list;
-  grpc_error* global_error = GRPC_ERROR_NONE;
+  std::vector<grpc_error_handle> error_list;
+  grpc_error_handle global_error = GRPC_ERROR_NONE;
   parsed_global_configs_ =
       ServiceConfigParser::ParseGlobalParameters(args, json_, &global_error);
   if (global_error != GRPC_ERROR_NONE) error_list.push_back(global_error);
-  grpc_error* local_error = ParsePerMethodParams(args);
+  grpc_error_handle local_error = ParsePerMethodParams(args);
   if (local_error != GRPC_ERROR_NONE) error_list.push_back(local_error);
   if (!error_list.empty()) {
     *error = GRPC_ERROR_CREATE_FROM_VECTOR("Service config parsing error",
@@ -69,13 +69,13 @@ ServiceConfig::~ServiceConfig() {
   }
 }
 
-grpc_error* ServiceConfig::ParseJsonMethodConfig(const grpc_channel_args* args,
-                                                 const Json& json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle ServiceConfig::ParseJsonMethodConfig(
+    const grpc_channel_args* args, const Json& json) {
+  std::vector<grpc_error_handle> error_list;
   // Parse method config with each registered parser.
   auto parsed_configs =
       absl::make_unique<ServiceConfigParser::ParsedConfigVector>();
-  grpc_error* parser_error = GRPC_ERROR_NONE;
+  grpc_error_handle parser_error = GRPC_ERROR_NONE;
   *parsed_configs =
       ServiceConfigParser::ParsePerMethodParameters(args, json, &parser_error);
   if (parser_error != GRPC_ERROR_NONE) {
@@ -94,7 +94,7 @@ grpc_error* ServiceConfig::ParseJsonMethodConfig(const grpc_channel_args* args,
     }
     const Json::Array& name_array = it->second.array_value();
     for (const Json& name : name_array) {
-      grpc_error* parse_error = GRPC_ERROR_NONE;
+      grpc_error_handle parse_error = GRPC_ERROR_NONE;
       std::string path = ParseJsonMethodName(name, &parse_error);
       if (parse_error != GRPC_ERROR_NONE) {
         error_list.push_back(parse_error);
@@ -130,8 +130,9 @@ grpc_error* ServiceConfig::ParseJsonMethodConfig(const grpc_channel_args* args,
   return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list);
 }
 
-grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_channel_args* args) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle ServiceConfig::ParsePerMethodParams(
+    const grpc_channel_args* args) {
+  std::vector<grpc_error_handle> error_list;
   auto it = json_.object_value().find("methodConfig");
   if (it != json_.object_value().end()) {
     if (it->second.type() != Json::Type::ARRAY) {
@@ -144,7 +145,7 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_channel_args* args) {
             "field:methodConfig error:not of type Object"));
         continue;
       }
-      grpc_error* error = ParseJsonMethodConfig(args, method_config);
+      grpc_error_handle error = ParseJsonMethodConfig(args, method_config);
       if (error != GRPC_ERROR_NONE) {
         error_list.push_back(error);
       }
@@ -154,7 +155,7 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_channel_args* args) {
 }
 
 std::string ServiceConfig::ParseJsonMethodName(const Json& json,
-                                               grpc_error** error) {
+                                               grpc_error_handle* error) {
   if (json.type() != Json::Type::OBJECT) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "field:name error:type is not object");
index 2dfd45d..a06ae16 100644 (file)
@@ -67,10 +67,10 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
   /// Returns null on parse error.
   static RefCountedPtr<ServiceConfig> Create(const grpc_channel_args* args,
                                              absl::string_view json_string,
-                                             grpc_error** error);
+                                             grpc_error_handle* error);
 
   ServiceConfig(const grpc_channel_args* args, std::string json_string,
-                Json json, grpc_error** error);
+                Json json, grpc_error_handle* error);
   ~ServiceConfig() override;
 
   const std::string& json_string() const { return json_string_; }
@@ -91,13 +91,14 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
 
  private:
   // Helper functions for parsing the method configs.
-  grpc_error* ParsePerMethodParams(const grpc_channel_args* args);
-  grpc_error* ParseJsonMethodConfig(const grpc_channel_args* args,
-                                    const Json& json);
+  grpc_error_handle ParsePerMethodParams(const grpc_channel_args* args);
+  grpc_error_handle ParseJsonMethodConfig(const grpc_channel_args* args,
+                                          const Json& json);
 
   // Returns a path string for the JSON name object specified by json.
   // Sets *error on error.
-  static std::string ParseJsonMethodName(const Json& json, grpc_error** error);
+  static std::string ParseJsonMethodName(const Json& json,
+                                         grpc_error_handle* error);
 
   std::string json_string_;
   Json json_;
index 679c0f5..5763e17 100644 (file)
@@ -36,13 +36,14 @@ class ServiceConfigChannelArgChannelData {
     const char* service_config_str = grpc_channel_args_find_string(
         args->channel_args, GRPC_ARG_SERVICE_CONFIG);
     if (service_config_str != nullptr) {
-      grpc_error* service_config_error = GRPC_ERROR_NONE;
+      grpc_error_handle service_config_error = GRPC_ERROR_NONE;
       auto service_config = ServiceConfig::Create(
           args->channel_args, service_config_str, &service_config_error);
       if (service_config_error == GRPC_ERROR_NONE) {
         service_config_ = std::move(service_config);
       } else {
-        gpr_log(GPR_ERROR, "%s", grpc_error_string(service_config_error));
+        gpr_log(GPR_ERROR, "%s",
+                grpc_error_std_string(service_config_error).c_str());
       }
       GRPC_ERROR_UNREF(service_config_error);
     }
@@ -73,7 +74,7 @@ class ServiceConfigChannelArgCallData {
   }
 };
 
-grpc_error* ServiceConfigChannelArgInitCallElem(
+grpc_error_handle ServiceConfigChannelArgInitCallElem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   ServiceConfigChannelArgCallData* calld =
       static_cast<ServiceConfigChannelArgCallData*>(elem->call_data);
@@ -89,7 +90,7 @@ void ServiceConfigChannelArgDestroyCallElem(
   calld->~ServiceConfigChannelArgCallData();
 }
 
-grpc_error* ServiceConfigChannelArgInitChannelElem(
+grpc_error_handle ServiceConfigChannelArgInitChannelElem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   ServiceConfigChannelArgChannelData* chand =
       static_cast<ServiceConfigChannelArgChannelData*>(elem->channel_data);
index d116f31..fa8fbea 100644 (file)
@@ -47,11 +47,11 @@ size_t ServiceConfigParser::RegisterParser(std::unique_ptr<Parser> parser) {
 ServiceConfigParser::ParsedConfigVector
 ServiceConfigParser::ParseGlobalParameters(const grpc_channel_args* args,
                                            const Json& json,
-                                           grpc_error** error) {
+                                           grpc_error_handle* error) {
   ParsedConfigVector parsed_global_configs;
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < g_registered_parsers->size(); i++) {
-    grpc_error* parser_error = GRPC_ERROR_NONE;
+    grpc_error_handle parser_error = GRPC_ERROR_NONE;
     auto parsed_config = (*g_registered_parsers)[i]->ParseGlobalParams(
         args, json, &parser_error);
     if (parser_error != GRPC_ERROR_NONE) {
@@ -68,11 +68,11 @@ ServiceConfigParser::ParseGlobalParameters(const grpc_channel_args* args,
 ServiceConfigParser::ParsedConfigVector
 ServiceConfigParser::ParsePerMethodParameters(const grpc_channel_args* args,
                                               const Json& json,
-                                              grpc_error** error) {
+                                              grpc_error_handle* error) {
   ParsedConfigVector parsed_method_configs;
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < g_registered_parsers->size(); i++) {
-    grpc_error* parser_error = GRPC_ERROR_NONE;
+    grpc_error_handle parser_error = GRPC_ERROR_NONE;
     auto parsed_config = (*g_registered_parsers)[i]->ParsePerMethodParams(
         args, json, &parser_error);
     if (parser_error != GRPC_ERROR_NONE) {
index 692a920..ebd3166 100644 (file)
@@ -47,7 +47,8 @@ class ServiceConfigParser {
     virtual ~Parser() = default;
 
     virtual std::unique_ptr<ParsedConfig> ParseGlobalParams(
-        const grpc_channel_args*, const Json& /* json */, grpc_error** error) {
+        const grpc_channel_args*, const Json& /* json */,
+        grpc_error_handle* error) {
       // Avoid unused parameter warning on debug-only parameter
       (void)error;
       GPR_DEBUG_ASSERT(error != nullptr);
@@ -55,7 +56,8 @@ class ServiceConfigParser {
     }
 
     virtual std::unique_ptr<ParsedConfig> ParsePerMethodParams(
-        const grpc_channel_args*, const Json& /* json */, grpc_error** error) {
+        const grpc_channel_args*, const Json& /* json */,
+        grpc_error_handle* error) {
       // Avoid unused parameter warning on debug-only parameter
       (void)error;
       GPR_DEBUG_ASSERT(error != nullptr);
@@ -81,10 +83,11 @@ class ServiceConfigParser {
 
   static ParsedConfigVector ParseGlobalParameters(const grpc_channel_args* args,
                                                   const Json& json,
-                                                  grpc_error** error);
+                                                  grpc_error_handle* error);
 
   static ParsedConfigVector ParsePerMethodParameters(
-      const grpc_channel_args* args, const Json& json, grpc_error** error);
+      const grpc_channel_args* args, const Json& json,
+      grpc_error_handle* error);
 };
 
 }  // namespace grpc_core
index 5a75301..a3db609 100644 (file)
@@ -36,6 +36,8 @@
 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
 #include "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
@@ -45,8 +47,6 @@
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
-#include "src/core/lib/iomgr/parse_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/channel.h"
@@ -131,7 +131,7 @@ size_t ConnectedSubchannel::GetInitialCallSizeEstimate() const {
 //
 
 RefCountedPtr<SubchannelCall> SubchannelCall::Create(Args args,
-                                                     grpc_error** error) {
+                                                     grpc_error_handle* error) {
   const size_t allocation_size =
       args.connected_subchannel->GetInitialCallSizeEstimate();
   Arena* arena = args.arena;
@@ -139,7 +139,7 @@ RefCountedPtr<SubchannelCall> SubchannelCall::Create(Args args,
       arena->Alloc(allocation_size)) SubchannelCall(std::move(args), error));
 }
 
-SubchannelCall::SubchannelCall(Args args, grpc_error** error)
+SubchannelCall::SubchannelCall(Args args, grpc_error_handle* error)
     : connected_subchannel_(std::move(args.connected_subchannel)),
       deadline_(args.deadline) {
   grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(this);
@@ -156,8 +156,7 @@ SubchannelCall::SubchannelCall(Args args, grpc_error** error)
   *error = grpc_call_stack_init(connected_subchannel_->channel_stack(), 1,
                                 SubchannelCall::Destroy, this, &call_args);
   if (GPR_UNLIKELY(*error != GRPC_ERROR_NONE)) {
-    const char* error_string = grpc_error_string(*error);
-    gpr_log(GPR_ERROR, "error: %s", error_string);
+    gpr_log(GPR_ERROR, "error: %s", grpc_error_std_string(*error).c_str());
     return;
   }
   grpc_call_stack_set_pollset_or_pollset_set(callstk, args.pollent);
@@ -207,7 +206,7 @@ void SubchannelCall::Unref(const DebugLocation& /*location*/,
   GRPC_CALL_STACK_UNREF(SUBCHANNEL_CALL_TO_CALL_STACK(this), reason);
 }
 
-void SubchannelCall::Destroy(void* arg, grpc_error* /*error*/) {
+void SubchannelCall::Destroy(void* arg, grpc_error_handle /*error*/) {
   GPR_TIMER_SCOPE("subchannel_call_destroy", 0);
   SubchannelCall* self = static_cast<SubchannelCall*>(arg);
   // Keep some members before destroying the subchannel call.
@@ -252,7 +251,7 @@ namespace {
 
 // Sets *status based on the rest of the parameters.
 void GetCallStatus(grpc_status_code* status, grpc_millis deadline,
-                   grpc_metadata_batch* md_batch, grpc_error* error) {
+                   grpc_metadata_batch* md_batch, grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     grpc_error_get_status(error, deadline, status, nullptr, nullptr, nullptr);
   } else {
@@ -268,7 +267,8 @@ void GetCallStatus(grpc_status_code* status, grpc_millis deadline,
 
 }  // namespace
 
-void SubchannelCall::RecvTrailingMetadataReady(void* arg, grpc_error* error) {
+void SubchannelCall::RecvTrailingMetadataReady(void* arg,
+                                               grpc_error_handle error) {
   SubchannelCall* call = static_cast<SubchannelCall*>(arg);
   GPR_ASSERT(call->recv_trailing_metadata_ != nullptr);
   grpc_status_code status = GRPC_STATUS_OK;
@@ -375,7 +375,7 @@ class Subchannel::AsyncWatcherNotifierLocked {
     ExecCtx::Run(DEBUG_LOCATION,
                  GRPC_CLOSURE_INIT(
                      &closure_,
-                     [](void* arg, grpc_error* /*error*/) {
+                     [](void* arg, grpc_error_handle /*error*/) {
                        auto* self =
                            static_cast<AsyncWatcherNotifierLocked*>(arg);
                        self->watcher_->OnConnectivityStateChange();
@@ -963,7 +963,7 @@ void Subchannel::MaybeStartConnectingLocked() {
   }
 }
 
-void Subchannel::OnRetryAlarm(void* arg, grpc_error* error) {
+void Subchannel::OnRetryAlarm(void* arg, grpc_error_handle error) {
   WeakRefCountedPtr<Subchannel> c(static_cast<Subchannel*>(arg));
   MutexLock lock(&c->mu_);
   c->have_retry_alarm_ = false;
@@ -998,7 +998,7 @@ void Subchannel::ContinueConnectingLocked() {
   connector_->Connect(args, &connecting_result_, &on_connecting_finished_);
 }
 
-void Subchannel::OnConnectingFinished(void* arg, grpc_error* error) {
+void Subchannel::OnConnectingFinished(void* arg, grpc_error_handle error) {
   WeakRefCountedPtr<Subchannel> c(static_cast<Subchannel*>(arg));
   const grpc_channel_args* delete_channel_args =
       c->connecting_result_.channel_args;
@@ -1009,7 +1009,8 @@ void Subchannel::OnConnectingFinished(void* arg, grpc_error* error) {
         c->PublishTransportLocked()) {
       // Do nothing, transport was published.
     } else if (!c->disconnected_) {
-      gpr_log(GPR_INFO, "Connect failed: %s", grpc_error_string(error));
+      gpr_log(GPR_INFO, "Connect failed: %s",
+              grpc_error_std_string(error).c_str());
       c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE,
                                     grpc_error_to_absl_status(error));
     }
@@ -1020,7 +1021,7 @@ void Subchannel::OnConnectingFinished(void* arg, grpc_error* error) {
 
 namespace {
 
-void ConnectionDestroy(void* arg, grpc_error* /*error*/) {
+void ConnectionDestroy(void* arg, grpc_error_handle /*error*/) {
   grpc_channel_stack* stk = static_cast<grpc_channel_stack*>(arg);
   grpc_channel_stack_destroy(stk);
   gpr_free(stk);
@@ -1040,13 +1041,13 @@ bool Subchannel::PublishTransportLocked() {
     return false;
   }
   grpc_channel_stack* stk;
-  grpc_error* error = grpc_channel_stack_builder_finish(
+  grpc_error_handle error = grpc_channel_stack_builder_finish(
       builder, 0, 1, ConnectionDestroy, nullptr,
       reinterpret_cast<void**>(&stk));
   if (error != GRPC_ERROR_NONE) {
     grpc_transport_destroy(connecting_result_.transport);
     gpr_log(GPR_ERROR, "error initializing subchannel stack: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return false;
   }
index ebf1712..9667fe7 100644 (file)
@@ -87,7 +87,8 @@ class SubchannelCall {
     grpc_call_context_element* context;
     CallCombiner* call_combiner;
   };
-  static RefCountedPtr<SubchannelCall> Create(Args args, grpc_error** error);
+  static RefCountedPtr<SubchannelCall> Create(Args args,
+                                              grpc_error_handle* error);
 
   // Continues processing a transport stream op batch.
   void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
@@ -113,20 +114,20 @@ class SubchannelCall {
   template <typename T>
   friend class RefCountedPtr;
 
-  SubchannelCall(Args args, grpc_error** error);
+  SubchannelCall(Args args, grpc_error_handle* error);
 
   // If channelz is enabled, intercepts recv_trailing so that we may check the
   // status and associate it to a subchannel.
   void MaybeInterceptRecvTrailingMetadata(
       grpc_transport_stream_op_batch* batch);
 
-  static void RecvTrailingMetadataReady(void* arg, grpc_error* error);
+  static void RecvTrailingMetadataReady(void* arg, grpc_error_handle error);
 
   // Interface of RefCounted<>.
   void IncrementRefCount();
   void IncrementRefCount(const DebugLocation& location, const char* reason);
 
-  static void Destroy(void* arg, grpc_error* error);
+  static void Destroy(void* arg, grpc_error_handle error);
 
   RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
   grpc_closure* after_call_stack_destroy_ = nullptr;
@@ -340,10 +341,10 @@ class Subchannel : public DualRefCounted<Subchannel> {
 
   // Methods for connection.
   void MaybeStartConnectingLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
-  static void OnRetryAlarm(void* arg, grpc_error* error)
+  static void OnRetryAlarm(void* arg, grpc_error_handle error)
       ABSL_LOCKS_EXCLUDED(mu_);
   void ContinueConnectingLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
-  static void OnConnectingFinished(void* arg, grpc_error* error)
+  static void OnConnectingFinished(void* arg, grpc_error_handle error)
       ABSL_LOCKS_EXCLUDED(mu_);
   bool PublishTransportLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
index e39dda4..01abaab 100644 (file)
@@ -126,8 +126,8 @@ grpc_millis GetClientIdleTimeout(const grpc_channel_args* args) {
 
 class ChannelData {
  public:
-  static grpc_error* Init(grpc_channel_element* elem,
-                          grpc_channel_element_args* args);
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args);
   static void Destroy(grpc_channel_element* elem);
 
   static void StartTransportOp(grpc_channel_element* elem,
@@ -139,11 +139,12 @@ class ChannelData {
 
  private:
   ChannelData(grpc_channel_element* elem, grpc_channel_element_args* args,
-              grpc_error** error);
+              grpc_error_handle* error);
   ~ChannelData() = default;
 
-  static void IdleTimerCallback(void* arg, grpc_error* error);
-  static void IdleTransportOpCompleteCallback(void* arg, grpc_error* error);
+  static void IdleTimerCallback(void* arg, grpc_error_handle error);
+  static void IdleTransportOpCompleteCallback(void* arg,
+                                              grpc_error_handle error);
 
   void StartIdleTimer();
 
@@ -170,9 +171,9 @@ class ChannelData {
   grpc_closure idle_transport_op_complete_callback_;
 };
 
-grpc_error* ChannelData::Init(grpc_channel_element* elem,
-                              grpc_channel_element_args* args) {
-  grpc_error* error = GRPC_ERROR_NONE;
+grpc_error_handle ChannelData::Init(grpc_channel_element* elem,
+                                    grpc_channel_element_args* args) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   new (elem->channel_data) ChannelData(elem, args, &error);
   return error;
 }
@@ -283,7 +284,7 @@ void ChannelData::DecreaseCallCount() {
 
 ChannelData::ChannelData(grpc_channel_element* elem,
                          grpc_channel_element_args* args,
-                         grpc_error** /*error*/)
+                         grpc_error_handle* /*error*/)
     : elem_(elem),
       channel_stack_(args->channel_stack),
       client_idle_timeout_(GetClientIdleTimeout(args->channel_args)) {
@@ -303,7 +304,7 @@ ChannelData::ChannelData(grpc_channel_element* elem,
                     grpc_schedule_on_exec_ctx);
 }
 
-void ChannelData::IdleTimerCallback(void* arg, grpc_error* error) {
+void ChannelData::IdleTimerCallback(void* arg, grpc_error_handle error) {
   GRPC_IDLE_FILTER_LOG("timer alarms");
   ChannelData* chand = static_cast<ChannelData*>(arg);
   if (error != GRPC_ERROR_NONE) {
@@ -352,7 +353,7 @@ void ChannelData::IdleTimerCallback(void* arg, grpc_error* error) {
 }
 
 void ChannelData::IdleTransportOpCompleteCallback(void* arg,
-                                                  grpc_error* /*error*/) {
+                                                  grpc_error_handle /*error*/) {
   ChannelData* chand = static_cast<ChannelData*>(arg);
   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack_, "idle transport op");
 }
@@ -381,15 +382,15 @@ void ChannelData::EnterIdle() {
 
 class CallData {
  public:
-  static grpc_error* Init(grpc_call_element* elem,
-                          const grpc_call_element_args* args);
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args);
   static void Destroy(grpc_call_element* elem,
                       const grpc_call_final_info* final_info,
                       grpc_closure* then_schedule_closure);
 };
 
-grpc_error* CallData::Init(grpc_call_element* elem,
-                           const grpc_call_element_args* /*args*/) {
+grpc_error_handle CallData::Init(grpc_call_element* elem,
+                                 const grpc_call_element_args* /*args*/) {
   ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
   chand->IncreaseCallCount();
   return GRPC_ERROR_NONE;
index 837e337..8944f5d 100644 (file)
@@ -51,7 +51,7 @@ class TimerState {
  private:
   // The on_complete callback used when sending a cancel_error batch down the
   // filter stack.  Yields the call combiner when the batch returns.
-  static void YieldCallCombiner(void* arg, grpc_error* /*ignored*/) {
+  static void YieldCallCombiner(void* arg, grpc_error_handle /*ignored*/) {
     TimerState* self = static_cast<TimerState*>(arg);
     grpc_deadline_state* deadline_state =
         static_cast<grpc_deadline_state*>(self->elem_->call_data);
@@ -62,7 +62,7 @@ class TimerState {
 
   // This is called via the call combiner, so access to deadline_state is
   // synchronized.
-  static void SendCancelOpInCallCombiner(void* arg, grpc_error* error) {
+  static void SendCancelOpInCallCombiner(void* arg, grpc_error_handle error) {
     TimerState* self = static_cast<TimerState*>(arg);
     grpc_transport_stream_op_batch* batch = grpc_make_transport_stream_op(
         GRPC_CLOSURE_INIT(&self->closure_, YieldCallCombiner, self, nullptr));
@@ -72,7 +72,7 @@ class TimerState {
   }
 
   // Timer callback.
-  static void TimerCallback(void* arg, grpc_error* error) {
+  static void TimerCallback(void* arg, grpc_error_handle error) {
     TimerState* self = static_cast<TimerState*>(arg);
     grpc_deadline_state* deadline_state =
         static_cast<grpc_deadline_state*>(self->elem_->call_data);
@@ -135,7 +135,7 @@ static void cancel_timer_if_needed(grpc_deadline_state* deadline_state) {
 }
 
 // Callback run when we receive trailing metadata.
-static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
+static void recv_trailing_metadata_ready(void* arg, grpc_error_handle error) {
   grpc_deadline_state* deadline_state = static_cast<grpc_deadline_state*>(arg);
   cancel_timer_if_needed(deadline_state);
   // Invoke the original callback.
@@ -168,7 +168,7 @@ struct start_timer_after_init_state {
   grpc_millis deadline;
   grpc_closure closure;
 };
-static void start_timer_after_init(void* arg, grpc_error* error) {
+static void start_timer_after_init(void* arg, grpc_error_handle error) {
   struct start_timer_after_init_state* state =
       static_cast<struct start_timer_after_init_state*>(arg);
   grpc_deadline_state* deadline_state =
@@ -241,8 +241,8 @@ void grpc_deadline_state_client_start_transport_stream_op_batch(
 //
 
 // Constructor for channel_data.  Used for both client and server filters.
-static grpc_error* deadline_init_channel_elem(grpc_channel_element* /*elem*/,
-                                              grpc_channel_element_args* args) {
+static grpc_error_handle deadline_init_channel_elem(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   return GRPC_ERROR_NONE;
 }
@@ -268,8 +268,8 @@ typedef struct server_call_data {
 } server_call_data;
 
 // Constructor for call_data.  Used for both client and server filters.
-static grpc_error* deadline_init_call_elem(grpc_call_element* elem,
-                                           const grpc_call_element_args* args) {
+static grpc_error_handle deadline_init_call_elem(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   new (elem->call_data) grpc_deadline_state(elem, *args, args->deadline);
   return GRPC_ERROR_NONE;
 }
@@ -292,7 +292,7 @@ static void deadline_client_start_transport_stream_op_batch(
 }
 
 // Callback for receiving initial metadata on the server.
-static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
+static void recv_initial_metadata_ready(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   server_call_data* calld = static_cast<server_call_data*>(elem->call_data);
   start_timer_if_needed(elem, calld->recv_initial_metadata->deadline);
index a412488..5f8d779 100644 (file)
@@ -83,8 +83,8 @@ inline bool UnderFraction(const uint32_t numerator,
 
 class ChannelData {
  public:
-  static grpc_error* Init(grpc_channel_element* elem,
-                          grpc_channel_element_args* args);
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args);
   static void Destroy(grpc_channel_element* elem);
 
   int index() const { return index_; }
@@ -99,8 +99,8 @@ class ChannelData {
 
 class CallData {
  public:
-  static grpc_error* Init(grpc_call_element* elem,
-                          const grpc_call_element_args* args);
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args);
 
   static void Destroy(grpc_call_element* elem,
                       const grpc_call_final_info* /*final_info*/,
@@ -129,7 +129,7 @@ class CallData {
   // GRPC_ERROR_NONE.
   // If this call is already been delay injected, skip the active faults
   // quota check.
-  grpc_error* MaybeAbort();
+  grpc_error_handle MaybeAbort();
 
   // Delays the stream operations batch.
   void DelayBatch(grpc_call_element* elem,
@@ -144,11 +144,11 @@ class CallData {
   }
 
   // This is a callback that will be invoked after the delay timer is up.
-  static void ResumeBatch(void* arg, grpc_error* error);
+  static void ResumeBatch(void* arg, grpc_error_handle error);
 
   // This is a callback invoked upon completion of recv_trailing_metadata.
   // Injects the abort_error_ to the recv_trailing_metadata batch if needed.
-  static void HijackedRecvTrailingMetadataReady(void* arg, grpc_error*);
+  static void HijackedRecvTrailingMetadataReady(void* arg, grpc_error_handle);
 
   // Used to track the policy structs that needs to be destroyed in dtor.
   bool fi_policy_owned_ = false;
@@ -166,7 +166,7 @@ class CallData {
   ResumeBatchCanceller* resume_batch_canceller_ ABSL_GUARDED_BY(delay_mu_);
   grpc_transport_stream_op_batch* delayed_batch_ ABSL_GUARDED_BY(delay_mu_);
   // Abort states
-  grpc_error* abort_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle abort_error_ = GRPC_ERROR_NONE;
   grpc_closure recv_trailing_metadata_ready_;
   grpc_closure* original_recv_trailing_metadata_ready_;
   // Protects the asynchronous delay, resume, and cancellation.
@@ -175,8 +175,8 @@ class CallData {
 
 // ChannelData
 
-grpc_error* ChannelData::Init(grpc_channel_element* elem,
-                              grpc_channel_element_args* args) {
+grpc_error_handle ChannelData::Init(grpc_channel_element* elem,
+                                    grpc_channel_element_args* args) {
   GPR_ASSERT(elem->filter == &FaultInjectionFilterVtable);
   new (elem->channel_data) ChannelData(elem, args);
   return GRPC_ERROR_NONE;
@@ -204,7 +204,7 @@ class CallData::ResumeBatchCanceller {
   }
 
  private:
-  static void Cancel(void* arg, grpc_error* error) {
+  static void Cancel(void* arg, grpc_error_handle error) {
     auto* self = static_cast<ResumeBatchCanceller*>(arg);
     auto* chand = static_cast<ChannelData*>(self->elem_->channel_data);
     auto* calld = static_cast<CallData*>(self->elem_->call_data);
@@ -214,7 +214,7 @@ class CallData::ResumeBatchCanceller {
         gpr_log(GPR_INFO,
                 "chand=%p calld=%p: cancelling schdueled pick: "
                 "error=%s self=%p calld->resume_batch_canceller_=%p",
-                chand, calld, grpc_error_string(error), self,
+                chand, calld, grpc_error_std_string(error).c_str(), self,
                 calld->resume_batch_canceller_);
       }
       if (error != GRPC_ERROR_NONE && calld->resume_batch_canceller_ == self) {
@@ -237,8 +237,8 @@ class CallData::ResumeBatchCanceller {
 
 // CallData
 
-grpc_error* CallData::Init(grpc_call_element* elem,
-                           const grpc_call_element_args* args) {
+grpc_error_handle CallData::Init(grpc_call_element* elem,
+                                 const grpc_call_element_args* args) {
   auto* calld = new (elem->call_data) CallData(elem, args);
   if (calld->fi_policy_ == nullptr) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -273,7 +273,7 @@ void CallData::StartTransportStreamOpBatch(
       calld->DelayBatch(elem, batch);
       return;
     }
-    grpc_error* abort_error = calld->MaybeAbort();
+    grpc_error_handle abort_error = calld->MaybeAbort();
     if (abort_error != GRPC_ERROR_NONE) {
       calld->abort_error_ = abort_error;
       grpc_transport_stream_op_batch_finish_with_failure(
@@ -414,7 +414,7 @@ bool CallData::MaybeDelay() {
   return false;
 }
 
-grpc_error* CallData::MaybeAbort() {
+grpc_error_handle CallData::MaybeAbort() {
   if (abort_request_ && (delay_request_ || HaveActiveFaultsQuota(false))) {
     return grpc_error_set_int(
         GRPC_ERROR_CREATE_FROM_COPIED_STRING(fi_policy_->abort_message.c_str()),
@@ -434,7 +434,7 @@ void CallData::DelayBatch(grpc_call_element* elem,
   grpc_timer_init(&delay_timer_, resume_time, &batch->handler_private.closure);
 }
 
-void CallData::ResumeBatch(void* arg, grpc_error* error) {
+void CallData::ResumeBatch(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   auto* calld = static_cast<CallData*>(elem->call_data);
   MutexLock lock(&calld->delay_mu_);
@@ -462,7 +462,8 @@ void CallData::ResumeBatch(void* arg, grpc_error* error) {
   grpc_call_next_op(elem, calld->delayed_batch_);
 }
 
-void CallData::HijackedRecvTrailingMetadataReady(void* arg, grpc_error* error) {
+void CallData::HijackedRecvTrailingMetadataReady(void* arg,
+                                                 grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   auto* calld = static_cast<CallData*>(elem->call_data);
   if (calld->abort_error_ != GRPC_ERROR_NONE) {
index c2628a0..e8c23e1 100644 (file)
@@ -37,12 +37,12 @@ size_t g_fault_injection_parser_index;
 
 std::vector<FaultInjectionMethodParsedConfig::FaultInjectionPolicy>
 ParseFaultInjectionPolicy(const Json::Array& policies_json_array,
-                          std::vector<grpc_error*>* error_list) {
+                          std::vector<grpc_error_handle>* error_list) {
   std::vector<FaultInjectionMethodParsedConfig::FaultInjectionPolicy> policies;
   for (size_t i = 0; i < policies_json_array.size(); i++) {
     FaultInjectionMethodParsedConfig::FaultInjectionPolicy
         fault_injection_policy;
-    std::vector<grpc_error*> sub_error_list;
+    std::vector<grpc_error_handle> sub_error_list;
     if (policies_json_array[i].type() != Json::Type::OBJECT) {
       error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("faultInjectionPolicy index ", i,
@@ -135,7 +135,7 @@ ParseFaultInjectionPolicy(const Json::Array& policies_json_array,
     if (!sub_error_list.empty()) {
       // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
       // string is not static in this case.
-      grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+      grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("failed to parse faultInjectionPolicy index ", i)
               .c_str());
       for (size_t i = 0; i < sub_error_list.size(); ++i) {
@@ -152,7 +152,7 @@ ParseFaultInjectionPolicy(const Json::Array& policies_json_array,
 
 std::unique_ptr<ServiceConfigParser::ParsedConfig>
 FaultInjectionServiceConfigParser::ParsePerMethodParams(
-    const grpc_channel_args* args, const Json& json, grpc_error** error) {
+    const grpc_channel_args* args, const Json& json, grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
   // Only parse fault injection policy if the following channel arg is present.
   if (!grpc_channel_args_find_bool(
@@ -162,7 +162,7 @@ FaultInjectionServiceConfigParser::ParsePerMethodParams(
   // Parse fault injection policy from given Json
   std::vector<FaultInjectionMethodParsedConfig::FaultInjectionPolicy>
       fault_injection_policies;
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   const Json::Array* policies_json_array;
   if (ParseJsonObjectField(json.object_value(), "faultInjectionPolicy",
                            &policies_json_array, &error_list)) {
index 2921467..a885539 100644 (file)
@@ -73,7 +73,7 @@ class FaultInjectionServiceConfigParser : public ServiceConfigParser::Parser {
   // Parses the per-method service config for fault injection filter.
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
       const grpc_channel_args* args, const Json& json,
-      grpc_error** error) override;
+      grpc_error_handle* error) override;
   // Returns the parser index for FaultInjectionServiceConfigParser.
   static size_t ParserIndex();
   // Registers FaultInjectionServiceConfigParser to ServiceConfigParser.
index 3a4825f..ef737f0 100644 (file)
 /* default maximum size of payload eligible for GET request */
 static constexpr size_t kMaxPayloadSizeForGet = 2048;
 
-static void recv_initial_metadata_ready(void* user_data, grpc_error* error);
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
-static void on_send_message_next_done(void* arg, grpc_error* error);
-static void send_message_on_complete(void* arg, grpc_error* error);
+static void recv_initial_metadata_ready(void* user_data,
+                                        grpc_error_handle error);
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error);
+static void on_send_message_next_done(void* arg, grpc_error_handle error);
+static void send_message_on_complete(void* arg, grpc_error_handle error);
 
 namespace {
 struct call_data {
@@ -81,14 +83,14 @@ struct call_data {
   grpc_linked_mdelem user_agent;
   // State for handling recv_initial_metadata ops.
   grpc_metadata_batch* recv_initial_metadata;
-  grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
+  grpc_error_handle recv_initial_metadata_error = GRPC_ERROR_NONE;
   grpc_closure* original_recv_initial_metadata_ready = nullptr;
   grpc_closure recv_initial_metadata_ready;
   // State for handling recv_trailing_metadata ops.
   grpc_metadata_batch* recv_trailing_metadata;
   grpc_closure* original_recv_trailing_metadata_ready;
   grpc_closure recv_trailing_metadata_ready;
-  grpc_error* recv_trailing_metadata_error = GRPC_ERROR_NONE;
+  grpc_error_handle recv_trailing_metadata_error = GRPC_ERROR_NONE;
   bool seen_recv_trailing_metadata_ready = false;
   // State for handling send_message ops.
   grpc_transport_stream_op_batch* send_message_batch;
@@ -108,7 +110,8 @@ struct channel_data {
 };
 }  // namespace
 
-static grpc_error* client_filter_incoming_metadata(grpc_metadata_batch* b) {
+static grpc_error_handle client_filter_incoming_metadata(
+    grpc_metadata_batch* b) {
   if (b->idx.named.status != nullptr) {
     /* If both gRPC status and HTTP status are provided in the response, we
      * should prefer the gRPC status code, as mentioned in
@@ -123,7 +126,7 @@ static grpc_error* client_filter_incoming_metadata(grpc_metadata_batch* b) {
                                   GPR_DUMP_ASCII);
       std::string msg =
           absl::StrCat("Received http2 header with status: ", val);
-      grpc_error* e = grpc_error_set_str(
+      grpc_error_handle e = grpc_error_set_str(
           grpc_error_set_int(
               grpc_error_set_str(
                   GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -182,7 +185,8 @@ static grpc_error* client_filter_incoming_metadata(grpc_metadata_batch* b) {
   return GRPC_ERROR_NONE;
 }
 
-static void recv_initial_metadata_ready(void* user_data, grpc_error* error) {
+static void recv_initial_metadata_ready(void* user_data,
+                                        grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error == GRPC_ERROR_NONE) {
@@ -201,7 +205,8 @@ static void recv_initial_metadata_ready(void* user_data, grpc_error* error) {
   grpc_core::Closure::Run(DEBUG_LOCATION, closure, error);
 }
 
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) {
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (calld->original_recv_initial_metadata_ready != nullptr) {
@@ -223,7 +228,7 @@ static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) {
                           calld->original_recv_trailing_metadata_ready, error);
 }
 
-static void send_message_on_complete(void* arg, grpc_error* error) {
+static void send_message_on_complete(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->send_message_cache.Destroy();
@@ -234,9 +239,10 @@ static void send_message_on_complete(void* arg, grpc_error* error) {
 
 // Pulls a slice from the send_message byte stream, updating
 // calld->send_message_bytes_read.
-static grpc_error* pull_slice_from_send_message(call_data* calld) {
+static grpc_error_handle pull_slice_from_send_message(call_data* calld) {
   grpc_slice incoming_slice;
-  grpc_error* error = calld->send_message_caching_stream->Pull(&incoming_slice);
+  grpc_error_handle error =
+      calld->send_message_caching_stream->Pull(&incoming_slice);
   if (error == GRPC_ERROR_NONE) {
     calld->send_message_bytes_read += GRPC_SLICE_LENGTH(incoming_slice);
     grpc_slice_unref_internal(incoming_slice);
@@ -249,10 +255,11 @@ static grpc_error* pull_slice_from_send_message(call_data* calld) {
 // calld->send_message_caching_stream->length(), then we have completed
 // reading from the byte stream; otherwise, an async read has been dispatched
 // and on_send_message_next_done() will be invoked when it is complete.
-static grpc_error* read_all_available_send_message_data(call_data* calld) {
+static grpc_error_handle read_all_available_send_message_data(
+    call_data* calld) {
   while (calld->send_message_caching_stream->Next(
       SIZE_MAX, &calld->on_send_message_next_done)) {
-    grpc_error* error = pull_slice_from_send_message(calld);
+    grpc_error_handle error = pull_slice_from_send_message(calld);
     if (error != GRPC_ERROR_NONE) return error;
     if (calld->send_message_bytes_read ==
         calld->send_message_caching_stream->length()) {
@@ -263,7 +270,7 @@ static grpc_error* read_all_available_send_message_data(call_data* calld) {
 }
 
 // Async callback for ByteStream::Next().
-static void on_send_message_next_done(void* arg, grpc_error* error) {
+static void on_send_message_next_done(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
@@ -301,8 +308,8 @@ static char* slice_buffer_to_string(grpc_slice_buffer* slice_buffer) {
 
 // Modifies the path entry in the batch's send_initial_metadata to
 // append the base64-encoded query for a GET request.
-static grpc_error* update_path_for_get(grpc_call_element* elem,
-                                       grpc_transport_stream_op_batch* batch) {
+static grpc_error_handle update_path_for_get(
+    grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_slice path_slice =
       GRPC_MDVALUE(batch->payload->send_initial_metadata.send_initial_metadata
@@ -376,7 +383,7 @@ static void http_client_start_transport_stream_op_batch(
         &calld->recv_trailing_metadata_ready;
   }
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   bool batch_will_be_handled_asynchronously = false;
   if (batch->send_initial_metadata) {
     // Decide which HTTP VERB to use. We use GET if the request is marked
@@ -475,7 +482,7 @@ done:
 }
 
 /* Constructor for call_data */
-static grpc_error* http_client_init_call_elem(
+static grpc_error_handle http_client_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   new (elem->call_data) call_data(elem, *args);
   return GRPC_ERROR_NONE;
@@ -561,7 +568,7 @@ static grpc_core::ManagedMemorySlice user_agent_from_args(
 }
 
 /* Constructor for channel_data */
-static grpc_error* http_client_init_channel_elem(
+static grpc_error_handle http_client_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(!args->is_last);
index 9511d25..f44ef85 100644 (file)
@@ -57,7 +57,7 @@ void client_authority_start_transport_stream_op_batch(
   if (batch->send_initial_metadata &&
       batch->payload->send_initial_metadata.send_initial_metadata->idx.named
               .authority == nullptr) {
-    grpc_error* error = grpc_metadata_batch_add_head(
+    grpc_error_handle error = grpc_metadata_batch_add_head(
         batch->payload->send_initial_metadata.send_initial_metadata,
         &calld->authority_storage,
         GRPC_MDELEM_REF(chand->default_authority_mdelem), GRPC_BATCH_AUTHORITY);
@@ -72,7 +72,7 @@ void client_authority_start_transport_stream_op_batch(
 }
 
 /* Constructor for call_data */
-grpc_error* client_authority_init_call_elem(
+grpc_error_handle client_authority_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->call_combiner = args->call_combiner;
@@ -85,7 +85,7 @@ void client_authority_destroy_call_elem(
     grpc_closure* /*ignored*/) {}
 
 /* Constructor for channel_data */
-grpc_error* client_authority_init_channel_elem(
+grpc_error_handle client_authority_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   const grpc_arg* default_authority_arg =
index 09c914f..0fc85b1 100644 (file)
@@ -131,25 +131,25 @@ class CallData {
   bool SkipMessageCompression();
   void InitializeState(grpc_call_element* elem);
 
-  grpc_error* ProcessSendInitialMetadata(grpc_call_element* elem,
-                                         grpc_metadata_batch* initial_metadata);
+  grpc_error_handle ProcessSendInitialMetadata(
+      grpc_call_element* elem, grpc_metadata_batch* initial_metadata);
 
   // Methods for processing a send_message batch
-  static void StartSendMessageBatch(void* elem_arg, grpc_error* unused);
-  static void OnSendMessageNextDone(void* elem_arg, grpc_error* error);
-  grpc_error* PullSliceFromSendMessage();
+  static void StartSendMessageBatch(void* elem_arg, grpc_error_handle unused);
+  static void OnSendMessageNextDone(void* elem_arg, grpc_error_handle error);
+  grpc_error_handle PullSliceFromSendMessage();
   void ContinueReadingSendMessage(grpc_call_element* elem);
   void FinishSendMessage(grpc_call_element* elem);
   void SendMessageBatchContinue(grpc_call_element* elem);
   static void FailSendMessageBatchInCallCombiner(void* calld_arg,
-                                                 grpc_error* error);
+                                                 grpc_error_handle error);
 
-  static void SendMessageOnComplete(void* calld_arg, grpc_error* error);
+  static void SendMessageOnComplete(void* calld_arg, grpc_error_handle error);
 
   grpc_core::CallCombiner* call_combiner_;
   grpc_message_compression_algorithm message_compression_algorithm_ =
       GRPC_MESSAGE_COMPRESS_NONE;
-  grpc_error* cancel_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle cancel_error_ = GRPC_ERROR_NONE;
   grpc_transport_stream_op_batch* send_message_batch_ = nullptr;
   bool seen_initial_metadata_ = false;
   /* Set to true, if the fields below are initialized. */
@@ -232,7 +232,7 @@ void CallData::InitializeState(grpc_call_element* elem) {
                     grpc_schedule_on_exec_ctx);
 }
 
-grpc_error* CallData::ProcessSendInitialMetadata(
+grpc_error_handle CallData::ProcessSendInitialMetadata(
     grpc_call_element* elem, grpc_metadata_batch* initial_metadata) {
   ChannelData* channeld = static_cast<ChannelData*>(elem->channel_data);
   // Find the compression algorithm.
@@ -246,7 +246,7 @@ grpc_error* CallData::ProcessSendInitialMetadata(
       grpc_compression_algorithm_to_stream_compression_algorithm(
           compression_algorithm);
   // Hint compression algorithm.
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (message_compression_algorithm_ != GRPC_MESSAGE_COMPRESS_NONE) {
     InitializeState(elem);
     error = grpc_metadata_batch_add_tail(
@@ -281,7 +281,7 @@ grpc_error* CallData::ProcessSendInitialMetadata(
   return error;
 }
 
-void CallData::SendMessageOnComplete(void* calld_arg, grpc_error* error) {
+void CallData::SendMessageOnComplete(void* calld_arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(calld_arg);
   grpc_slice_buffer_reset_and_unref_internal(&calld->slices_);
   grpc_core::Closure::Run(DEBUG_LOCATION,
@@ -348,7 +348,7 @@ void CallData::FinishSendMessage(grpc_call_element* elem) {
 }
 
 void CallData::FailSendMessageBatchInCallCombiner(void* calld_arg,
-                                                  grpc_error* error) {
+                                                  grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(calld_arg);
   if (calld->send_message_batch_ != nullptr) {
     grpc_transport_stream_op_batch_finish_with_failure(
@@ -359,9 +359,9 @@ void CallData::FailSendMessageBatchInCallCombiner(void* calld_arg,
 }
 
 // Pulls a slice from the send_message byte stream and adds it to slices_.
-grpc_error* CallData::PullSliceFromSendMessage() {
+grpc_error_handle CallData::PullSliceFromSendMessage() {
   grpc_slice incoming_slice;
-  grpc_error* error =
+  grpc_error_handle error =
       send_message_batch_->payload->send_message.send_message->Pull(
           &incoming_slice);
   if (error == GRPC_ERROR_NONE) {
@@ -382,7 +382,7 @@ void CallData::ContinueReadingSendMessage(grpc_call_element* elem) {
   }
   while (send_message_batch_->payload->send_message.send_message->Next(
       ~static_cast<size_t>(0), &on_send_message_next_done_)) {
-    grpc_error* error = PullSliceFromSendMessage();
+    grpc_error_handle error = PullSliceFromSendMessage();
     if (error != GRPC_ERROR_NONE) {
       // Closure callback; does not take ownership of error.
       FailSendMessageBatchInCallCombiner(this, error);
@@ -398,7 +398,7 @@ void CallData::ContinueReadingSendMessage(grpc_call_element* elem) {
 }
 
 // Async callback for ByteStream::Next().
-void CallData::OnSendMessageNextDone(void* elem_arg, grpc_error* error) {
+void CallData::OnSendMessageNextDone(void* elem_arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(elem_arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
@@ -421,7 +421,8 @@ void CallData::OnSendMessageNextDone(void* elem_arg, grpc_error* error) {
   }
 }
 
-void CallData::StartSendMessageBatch(void* elem_arg, grpc_error* /*unused*/) {
+void CallData::StartSendMessageBatch(void* elem_arg,
+                                     grpc_error_handle /*unused*/) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(elem_arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   if (calld->SkipMessageCompression()) {
@@ -458,7 +459,7 @@ void CallData::CompressStartTransportStreamOpBatch(
   // Handle send_initial_metadata.
   if (batch->send_initial_metadata) {
     GPR_ASSERT(!seen_initial_metadata_);
-    grpc_error* error = ProcessSendInitialMetadata(
+    grpc_error_handle error = ProcessSendInitialMetadata(
         elem, batch->payload->send_initial_metadata.send_initial_metadata);
     if (error != GRPC_ERROR_NONE) {
       grpc_transport_stream_op_batch_finish_with_failure(batch, error,
@@ -503,8 +504,8 @@ void CompressStartTransportStreamOpBatch(
 }
 
 /* Constructor for call_data */
-grpc_error* CompressInitCallElem(grpc_call_element* elem,
-                                 const grpc_call_element_args* args) {
+grpc_error_handle CompressInitCallElem(grpc_call_element* elem,
+                                       const grpc_call_element_args* args) {
   new (elem->call_data) CallData(elem, *args);
   return GRPC_ERROR_NONE;
 }
@@ -518,8 +519,8 @@ void CompressDestroyCallElem(grpc_call_element* elem,
 }
 
 /* Constructor for ChannelData */
-grpc_error* CompressInitChannelElem(grpc_channel_element* elem,
-                                    grpc_channel_element_args* args) {
+grpc_error_handle CompressInitChannelElem(grpc_channel_element* elem,
+                                          grpc_channel_element_args* args) {
   new (elem->channel_data) ChannelData(args);
   return GRPC_ERROR_NONE;
 }
index 4ab8a56..426dd90 100644 (file)
@@ -89,24 +89,24 @@ class CallData {
       grpc_call_element* elem, grpc_transport_stream_op_batch* batch);
 
  private:
-  static void OnRecvInitialMetadataReady(void* arg, grpc_error* error);
+  static void OnRecvInitialMetadataReady(void* arg, grpc_error_handle error);
 
   // Methods for processing a receive message event
   void MaybeResumeOnRecvMessageReady();
-  static void OnRecvMessageReady(void* arg, grpc_error* error);
-  static void OnRecvMessageNextDone(void* arg, grpc_error* error);
-  grpc_error* PullSliceFromRecvMessage();
+  static void OnRecvMessageReady(void* arg, grpc_error_handle error);
+  static void OnRecvMessageNextDone(void* arg, grpc_error_handle error);
+  grpc_error_handle PullSliceFromRecvMessage();
   void ContinueReadingRecvMessage();
   void FinishRecvMessage();
-  void ContinueRecvMessageReadyCallback(grpc_error* error);
+  void ContinueRecvMessageReadyCallback(grpc_error_handle error);
 
   // Methods for processing a recv_trailing_metadata event
   void MaybeResumeOnRecvTrailingMetadataReady();
-  static void OnRecvTrailingMetadataReady(void* arg, grpc_error* error);
+  static void OnRecvTrailingMetadataReady(void* arg, grpc_error_handle error);
 
   CallCombiner* call_combiner_;
   // Overall error for the call
-  grpc_error* error_ = GRPC_ERROR_NONE;
+  grpc_error_handle error_ = GRPC_ERROR_NONE;
   // Fields for handling recv_initial_metadata_ready callback
   grpc_closure on_recv_initial_metadata_ready_;
   grpc_closure* original_recv_initial_metadata_ready_ = nullptr;
@@ -130,7 +130,7 @@ class CallData {
   bool seen_recv_trailing_metadata_ready_ = false;
   grpc_closure on_recv_trailing_metadata_ready_;
   grpc_closure* original_recv_trailing_metadata_ready_ = nullptr;
-  grpc_error* on_recv_trailing_metadata_ready_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle on_recv_trailing_metadata_ready_error_ = GRPC_ERROR_NONE;
 };
 
 grpc_message_compression_algorithm DecodeMessageCompressionAlgorithm(
@@ -149,7 +149,7 @@ grpc_message_compression_algorithm DecodeMessageCompressionAlgorithm(
   return algorithm;
 }
 
-void CallData::OnRecvInitialMetadataReady(void* arg, grpc_error* error) {
+void CallData::OnRecvInitialMetadataReady(void* arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(arg);
   if (error == GRPC_ERROR_NONE) {
     grpc_linked_mdelem* grpc_encoding =
@@ -174,7 +174,7 @@ void CallData::MaybeResumeOnRecvMessageReady() {
   }
 }
 
-void CallData::OnRecvMessageReady(void* arg, grpc_error* error) {
+void CallData::OnRecvMessageReady(void* arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(arg);
   if (error == GRPC_ERROR_NONE) {
     if (calld->original_recv_initial_metadata_ready_ != nullptr) {
@@ -218,7 +218,7 @@ void CallData::ContinueReadingRecvMessage() {
   while ((*recv_message_)
              ->Next((*recv_message_)->length() - recv_slices_.length,
                     &on_recv_message_next_done_)) {
-    grpc_error* error = PullSliceFromRecvMessage();
+    grpc_error_handle error = PullSliceFromRecvMessage();
     if (error != GRPC_ERROR_NONE) {
       return ContinueRecvMessageReadyCallback(error);
     }
@@ -229,16 +229,16 @@ void CallData::ContinueReadingRecvMessage() {
   }
 }
 
-grpc_error* CallData::PullSliceFromRecvMessage() {
+grpc_error_handle CallData::PullSliceFromRecvMessage() {
   grpc_slice incoming_slice;
-  grpc_error* error = (*recv_message_)->Pull(&incoming_slice);
+  grpc_error_handle error = (*recv_message_)->Pull(&incoming_slice);
   if (error == GRPC_ERROR_NONE) {
     grpc_slice_buffer_add(&recv_slices_, incoming_slice);
   }
   return error;
 }
 
-void CallData::OnRecvMessageNextDone(void* arg, grpc_error* error) {
+void CallData::OnRecvMessageNextDone(void* arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(arg);
   if (error != GRPC_ERROR_NONE) {
     return calld->ContinueRecvMessageReadyCallback(GRPC_ERROR_REF(error));
@@ -283,7 +283,7 @@ void CallData::FinishRecvMessage() {
   ContinueRecvMessageReadyCallback(GRPC_ERROR_REF(error_));
 }
 
-void CallData::ContinueRecvMessageReadyCallback(grpc_error* error) {
+void CallData::ContinueRecvMessageReadyCallback(grpc_error_handle error) {
   MaybeResumeOnRecvTrailingMetadataReady();
   // The surface will clean up the receiving stream if there is an error.
   grpc_closure* closure = original_recv_message_ready_;
@@ -294,14 +294,14 @@ void CallData::ContinueRecvMessageReadyCallback(grpc_error* error) {
 void CallData::MaybeResumeOnRecvTrailingMetadataReady() {
   if (seen_recv_trailing_metadata_ready_) {
     seen_recv_trailing_metadata_ready_ = false;
-    grpc_error* error = on_recv_trailing_metadata_ready_error_;
+    grpc_error_handle error = on_recv_trailing_metadata_ready_error_;
     on_recv_trailing_metadata_ready_error_ = GRPC_ERROR_NONE;
     GRPC_CALL_COMBINER_START(call_combiner_, &on_recv_trailing_metadata_ready_,
                              error, "Continuing OnRecvTrailingMetadataReady");
   }
 }
 
-void CallData::OnRecvTrailingMetadataReady(void* arg, grpc_error* error) {
+void CallData::OnRecvTrailingMetadataReady(void* arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(arg);
   if (calld->original_recv_initial_metadata_ready_ != nullptr ||
       calld->original_recv_message_ready_ != nullptr) {
@@ -356,8 +356,8 @@ void DecompressStartTransportStreamOpBatch(
   calld->DecompressStartTransportStreamOpBatch(elem, batch);
 }
 
-grpc_error* DecompressInitCallElem(grpc_call_element* elem,
-                                   const grpc_call_element_args* args) {
+grpc_error_handle DecompressInitCallElem(grpc_call_element* elem,
+                                         const grpc_call_element_args* args) {
   ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
   new (elem->call_data) CallData(*args, chand);
   return GRPC_ERROR_NONE;
@@ -370,8 +370,8 @@ void DecompressDestroyCallElem(grpc_call_element* elem,
   calld->~CallData();
 }
 
-grpc_error* DecompressInitChannelElem(grpc_channel_element* elem,
-                                      grpc_channel_element_args* args) {
+grpc_error_handle DecompressInitChannelElem(grpc_channel_element* elem,
+                                            grpc_channel_element_args* args) {
   ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
   new (chand) ChannelData(args);
   return GRPC_ERROR_NONE;
index e4ece54..226ba02 100644 (file)
 #define EXPECTED_CONTENT_TYPE "application/grpc"
 #define EXPECTED_CONTENT_TYPE_LENGTH (sizeof(EXPECTED_CONTENT_TYPE) - 1)
 
-static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err);
-static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err);
-static void hs_recv_message_ready(void* user_data, grpc_error* err);
+static void hs_recv_initial_metadata_ready(void* user_data,
+                                           grpc_error_handle err);
+static void hs_recv_trailing_metadata_ready(void* user_data,
+                                            grpc_error_handle err);
+static void hs_recv_message_ready(void* user_data, grpc_error_handle err);
 
 namespace {
 
@@ -74,7 +76,7 @@ struct call_data {
 
   // State for intercepting recv_initial_metadata.
   grpc_closure recv_initial_metadata_ready;
-  grpc_error* recv_initial_metadata_ready_error = GRPC_ERROR_NONE;
+  grpc_error_handle recv_initial_metadata_ready_error = GRPC_ERROR_NONE;
   grpc_closure* original_recv_initial_metadata_ready;
   grpc_metadata_batch* recv_initial_metadata = nullptr;
   uint32_t* recv_initial_metadata_flags;
@@ -89,7 +91,7 @@ struct call_data {
   // State for intercepting recv_trailing_metadata
   grpc_closure recv_trailing_metadata_ready;
   grpc_closure* original_recv_trailing_metadata_ready;
-  grpc_error* recv_trailing_metadata_ready_error;
+  grpc_error_handle recv_trailing_metadata_ready_error;
   bool seen_recv_trailing_metadata_ready = false;
 };
 
@@ -99,7 +101,7 @@ struct channel_data {
 
 }  // namespace
 
-static grpc_error* hs_filter_outgoing_metadata(grpc_metadata_batch* b) {
+static grpc_error_handle hs_filter_outgoing_metadata(grpc_metadata_batch* b) {
   if (b->idx.named.grpc_message != nullptr) {
     grpc_slice pct_encoded_msg = grpc_percent_encode_slice(
         GRPC_MDVALUE(b->idx.named.grpc_message->md),
@@ -114,8 +116,8 @@ static grpc_error* hs_filter_outgoing_metadata(grpc_metadata_batch* b) {
   return GRPC_ERROR_NONE;
 }
 
-static void hs_add_error(const char* error_name, grpc_error** cumulative,
-                         grpc_error* new_err) {
+static void hs_add_error(const char* error_name, grpc_error_handle* cumulative,
+                         grpc_error_handle new_err) {
   if (new_err == GRPC_ERROR_NONE) return;
   if (*cumulative == GRPC_ERROR_NONE) {
     *cumulative = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_name);
@@ -149,10 +151,10 @@ static bool md_strict_equal(grpc_mdelem a, grpc_mdelem b_static) {
   }
 }
 
-static grpc_error* hs_filter_incoming_metadata(grpc_call_element* elem,
-                                               grpc_metadata_batch* b) {
+static grpc_error_handle hs_filter_incoming_metadata(grpc_call_element* elem,
+                                                     grpc_metadata_batch* b) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* error_name = "Failed processing incoming headers";
 
   if (b->idx.named.method != nullptr) {
@@ -330,7 +332,8 @@ static grpc_error* hs_filter_incoming_metadata(grpc_call_element* elem,
   return error;
 }
 
-static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err) {
+static void hs_recv_initial_metadata_ready(void* user_data,
+                                           grpc_error_handle err) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->seen_recv_initial_metadata_ready = true;
@@ -367,7 +370,7 @@ static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err) {
                           calld->original_recv_initial_metadata_ready, err);
 }
 
-static void hs_recv_message_ready(void* user_data, grpc_error* err) {
+static void hs_recv_message_ready(void* user_data, grpc_error_handle err) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->seen_recv_message_ready = true;
@@ -392,7 +395,8 @@ static void hs_recv_message_ready(void* user_data, grpc_error* err) {
   }
 }
 
-static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err) {
+static void hs_recv_trailing_metadata_ready(void* user_data,
+                                            grpc_error_handle err) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (!calld->seen_recv_initial_metadata_ready) {
@@ -410,13 +414,13 @@ static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err) {
                           calld->original_recv_trailing_metadata_ready, err);
 }
 
-static grpc_error* hs_mutate_op(grpc_call_element* elem,
-                                grpc_transport_stream_op_batch* op) {
+static grpc_error_handle hs_mutate_op(grpc_call_element* elem,
+                                      grpc_transport_stream_op_batch* op) {
   /* grab pointers to our data from the call element */
   call_data* calld = static_cast<call_data*>(elem->call_data);
 
   if (op->send_initial_metadata) {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     static const char* error_name = "Failed sending initial metadata";
     hs_add_error(
         error_name, &error,
@@ -463,7 +467,7 @@ static grpc_error* hs_mutate_op(grpc_call_element* elem,
   }
 
   if (op->send_trailing_metadata) {
-    grpc_error* error = hs_filter_outgoing_metadata(
+    grpc_error_handle error = hs_filter_outgoing_metadata(
         op->payload->send_trailing_metadata.send_trailing_metadata);
     if (error != GRPC_ERROR_NONE) return error;
   }
@@ -475,7 +479,7 @@ static void hs_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
   GPR_TIMER_SCOPE("hs_start_transport_stream_op_batch", 0);
   call_data* calld = static_cast<call_data*>(elem->call_data);
-  grpc_error* error = hs_mutate_op(elem, op);
+  grpc_error_handle error = hs_mutate_op(elem, op);
   if (error != GRPC_ERROR_NONE) {
     grpc_transport_stream_op_batch_finish_with_failure(op, error,
                                                        calld->call_combiner);
@@ -485,8 +489,8 @@ static void hs_start_transport_stream_op_batch(
 }
 
 /* Constructor for call_data */
-static grpc_error* hs_init_call_elem(grpc_call_element* elem,
-                                     const grpc_call_element_args* args) {
+static grpc_error_handle hs_init_call_elem(grpc_call_element* elem,
+                                           const grpc_call_element_args* args) {
   new (elem->call_data) call_data(elem, *args);
   return GRPC_ERROR_NONE;
 }
@@ -500,8 +504,8 @@ static void hs_destroy_call_elem(grpc_call_element* elem,
 }
 
 /* Constructor for channel_data */
-static grpc_error* hs_init_channel_elem(grpc_channel_element* elem,
-                                        grpc_channel_element_args* args) {
+static grpc_error_handle hs_init_channel_elem(grpc_channel_element* elem,
+                                              grpc_channel_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(!args->is_last);
   chand->surface_user_agent = grpc_channel_arg_get_bool(
index 6c7b42a..46af805 100644 (file)
@@ -32,9 +32,9 @@
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h"
 #include "src/core/ext/filters/load_reporting/registered_opencensus_objects.h"
 #include "src/core/ext/filters/load_reporting/server_load_reporting_filter.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/context.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/socket_utils.h"
@@ -50,7 +50,7 @@ constexpr char kEncodedIpv6AddressLengthString[] = "32";
 constexpr char kEmptyAddressLengthString[] = "00";
 constexpr size_t kLengthPrefixSize = 2;
 
-grpc_error* ServerLoadReportingChannelData::Init(
+grpc_error_handle ServerLoadReportingChannelData::Init(
     grpc_channel_element* /* elem */, grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   // Find and record the peer_identity.
@@ -232,8 +232,8 @@ grpc_filtered_mdelem ServerLoadReportingCallData::RecvInitialMetadataFilter(
   return GRPC_FILTERED_MDELEM(md);
 }
 
-void ServerLoadReportingCallData::RecvInitialMetadataReady(void* arg,
-                                                           grpc_error* err) {
+void ServerLoadReportingCallData::RecvInitialMetadataReady(
+    void* arg, grpc_error_handle err) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(arg);
   ServerLoadReportingCallData* calld =
       reinterpret_cast<ServerLoadReportingCallData*>(elem->call_data);
@@ -264,7 +264,7 @@ void ServerLoadReportingCallData::RecvInitialMetadataReady(void* arg,
                           GRPC_ERROR_REF(err));
 }
 
-grpc_error* ServerLoadReportingCallData::Init(
+grpc_error_handle ServerLoadReportingCallData::Init(
     grpc_call_element* elem, const grpc_call_element_args* /*args*/) {
   service_method_ = grpc_empty_slice();
   GRPC_CLOSURE_INIT(&recv_initial_metadata_ready_, RecvInitialMetadataReady,
index 3bfdc98..47390fa 100644 (file)
@@ -30,8 +30,8 @@ namespace grpc {
 
 class ServerLoadReportingChannelData : public ChannelData {
  public:
-  grpc_error* Init(grpc_channel_element* elem,
-                   grpc_channel_element_args* args) override;
+  grpc_error_handle Init(grpc_channel_element* elem,
+                         grpc_channel_element_args* args) override;
 
   // Getters.
   const char* peer_identity() { return peer_identity_; }
@@ -45,8 +45,8 @@ class ServerLoadReportingChannelData : public ChannelData {
 
 class ServerLoadReportingCallData : public CallData {
  public:
-  grpc_error* Init(grpc_call_element* elem,
-                   const grpc_call_element_args* args) override;
+  grpc_error_handle Init(grpc_call_element* elem,
+                         const grpc_call_element_args* args) override;
 
   void Destroy(grpc_call_element* elem, const grpc_call_final_info* final_info,
                grpc_closure* then_call_closure) override;
@@ -68,7 +68,7 @@ class ServerLoadReportingCallData : public CallData {
   static const char* GetStatusTagForStatus(grpc_status_code status);
 
   // Records the call start.
-  static void RecvInitialMetadataReady(void* arg, grpc_error* err);
+  static void RecvInitialMetadataReady(void* arg, grpc_error_handle err);
 
   // From the initial metadata, extracts the service_method_, target_host_, and
   // client_ip_and_lr_token_.
index ee89272..97a4dc2 100644 (file)
@@ -206,7 +206,8 @@ static void decrease_call_count(channel_data* chand) {
   }
 }
 
-static void start_max_idle_timer_after_init(void* arg, grpc_error* /*error*/) {
+static void start_max_idle_timer_after_init(void* arg,
+                                            grpc_error_handle /*error*/) {
   channel_data* chand = static_cast<channel_data*>(arg);
   /* Decrease call_count. If there are no active calls at this time,
      max_idle_timer will start here. If the number of active calls is not 0,
@@ -258,7 +259,8 @@ class ConnectivityWatcher : public AsyncConnectivityStateWatcherInterface {
 
 }  // namespace grpc_core
 
-static void start_max_age_timer_after_init(void* arg, grpc_error* /*error*/) {
+static void start_max_age_timer_after_init(void* arg,
+                                           grpc_error_handle /*error*/) {
   channel_data* chand = static_cast<channel_data*>(arg);
   {
     grpc_core::MutexLock lock(&chand->max_age_timer_mu);
@@ -277,8 +279,8 @@ static void start_max_age_timer_after_init(void* arg, grpc_error* /*error*/) {
                            "max_age start_max_age_timer_after_init");
 }
 
-static void start_max_age_grace_timer_after_goaway_op(void* arg,
-                                                      grpc_error* /*error*/) {
+static void start_max_age_grace_timer_after_goaway_op(
+    void* arg, grpc_error_handle /*error*/) {
   channel_data* chand = static_cast<channel_data*>(arg);
   {
     grpc_core::MutexLock lock(&chand->max_age_timer_mu);
@@ -307,7 +309,7 @@ static void close_max_idle_channel(channel_data* chand) {
   elem->filter->start_transport_op(elem, op);
 }
 
-static void max_idle_timer_cb(void* arg, grpc_error* error) {
+static void max_idle_timer_cb(void* arg, grpc_error_handle error) {
   channel_data* chand = static_cast<channel_data*>(arg);
   if (error == GRPC_ERROR_NONE) {
     bool try_again = true;
@@ -351,7 +353,7 @@ static void max_idle_timer_cb(void* arg, grpc_error* error) {
   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack, "max_age max_idle_timer");
 }
 
-static void close_max_age_channel(void* arg, grpc_error* error) {
+static void close_max_age_channel(void* arg, grpc_error_handle error) {
   channel_data* chand = static_cast<channel_data*>(arg);
   {
     grpc_core::MutexLock lock(&chand->max_age_timer_mu);
@@ -374,7 +376,7 @@ static void close_max_age_channel(void* arg, grpc_error* error) {
   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack, "max_age max_age_timer");
 }
 
-static void force_close_max_age_channel(void* arg, grpc_error* error) {
+static void force_close_max_age_channel(void* arg, grpc_error_handle error) {
   channel_data* chand = static_cast<channel_data*>(arg);
   {
     grpc_core::MutexLock lock(&chand->max_age_timer_mu);
@@ -412,7 +414,7 @@ add_random_max_connection_age_jitter_and_convert_to_grpc_millis(int value) {
 }
 
 /* Constructor for call_data. */
-static grpc_error* max_age_init_call_elem(
+static grpc_error_handle max_age_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* /*args*/) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   increase_call_count(chand);
@@ -428,8 +430,8 @@ static void max_age_destroy_call_elem(
 }
 
 /* Constructor for channel_data. */
-static grpc_error* max_age_init_channel_elem(grpc_channel_element* elem,
-                                             grpc_channel_element_args* args) {
+static grpc_error_handle max_age_init_channel_elem(
+    grpc_channel_element* elem, grpc_channel_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   new (chand) channel_data();
   chand->channel_stack = args->channel_stack;
index 10a58d9..3c921e2 100644 (file)
@@ -37,8 +37,9 @@
 #include "src/core/lib/surface/call.h"
 #include "src/core/lib/surface/channel_init.h"
 
-static void recv_message_ready(void* user_data, grpc_error* error);
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
+static void recv_message_ready(void* user_data, grpc_error_handle error);
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error);
 
 namespace grpc_core {
 
@@ -67,9 +68,10 @@ const MessageSizeParsedConfig* MessageSizeParsedConfig::GetFromCallContext(
 
 std::unique_ptr<ServiceConfigParser::ParsedConfig>
 MessageSizeParser::ParsePerMethodParams(const grpc_channel_args* /*args*/,
-                                        const Json& json, grpc_error** error) {
+                                        const Json& json,
+                                        grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   // Max request size.
   int max_request_message_bytes = -1;
   auto it = json.object_value().find("maxRequestMessageBytes");
@@ -179,7 +181,7 @@ struct call_data {
   grpc_closure recv_message_ready;
   grpc_closure recv_trailing_metadata_ready;
   // The error caused by a message that is too large, or GRPC_ERROR_NONE
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   // Used by recv_message_ready.
   grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message = nullptr;
   // Original recv_message_ready callback, invoked after our own.
@@ -187,20 +189,20 @@ struct call_data {
   // Original recv_trailing_metadata callback, invoked after our own.
   grpc_closure* original_recv_trailing_metadata_ready;
   bool seen_recv_trailing_metadata = false;
-  grpc_error* recv_trailing_metadata_error;
+  grpc_error_handle recv_trailing_metadata_error;
 };
 
 }  // namespace
 
 // Callback invoked when we receive a message.  Here we check the max
 // receive message size.
-static void recv_message_ready(void* user_data, grpc_error* error) {
+static void recv_message_ready(void* user_data, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (*calld->recv_message != nullptr && calld->limits.max_recv_size >= 0 &&
       (*calld->recv_message)->length() >
           static_cast<size_t>(calld->limits.max_recv_size)) {
-    grpc_error* new_error = grpc_error_set_int(
+    grpc_error_handle new_error = grpc_error_set_int(
         GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrFormat("Received message larger than max (%u vs. %d)",
                             (*calld->recv_message)->length(),
@@ -233,7 +235,8 @@ static void recv_message_ready(void* user_data, grpc_error* error) {
 
 // Callback invoked on completion of recv_trailing_metadata
 // Notifies the recv_trailing_metadata batch of any message size failures
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) {
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (calld->next_recv_message_ready != nullptr) {
@@ -291,7 +294,7 @@ static void message_size_start_transport_stream_op_batch(
 }
 
 // Constructor for call_data.
-static grpc_error* message_size_init_call_elem(
+static grpc_error_handle message_size_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   new (elem->call_data) call_data(elem, *chand, *args);
@@ -315,7 +318,7 @@ grpc_core::MessageSizeParsedConfig::message_size_limits get_message_size_limits(
 }
 
 // Constructor for channel_data.
-static grpc_error* message_size_init_channel_elem(
+static grpc_error_handle message_size_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
index 0583a78..6629803 100644 (file)
@@ -51,7 +51,7 @@ class MessageSizeParser : public ServiceConfigParser::Parser {
  public:
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
       const grpc_channel_args* /*args*/, const Json& json,
-      grpc_error** error) override;
+      grpc_error_handle* error) override;
 
   static void Register();
 
index 40239d6..b2e8f3f 100644 (file)
@@ -54,7 +54,8 @@ static bool get_user_agent_mdelem(const grpc_metadata_batch* batch,
 }
 
 // Callback invoked when we receive an initial metadata.
-static void recv_initial_metadata_ready(void* user_data, grpc_error* error) {
+static void recv_initial_metadata_ready(void* user_data,
+                                        grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
 
@@ -105,7 +106,7 @@ static void cronet_compression_start_transport_stream_op_batch(
 }
 
 // Constructor for call_data.
-static grpc_error* cronet_compression_init_call_elem(
+static grpc_error_handle cronet_compression_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* /*args*/) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->next_recv_initial_metadata_ready = nullptr;
@@ -122,7 +123,7 @@ static void cronet_compression_destroy_call_elem(
     grpc_closure* /*ignored*/) {}
 
 // Constructor for channel_data.
-static grpc_error* cronet_compression_init_channel_elem(
+static grpc_error_handle cronet_compression_init_channel_elem(
     grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
index 345663a..8b3d5d7 100644 (file)
@@ -75,7 +75,7 @@ void Chttp2Connector::Connect(const Args& args, Result* result,
                           args.channel_args, &addr, args.deadline);
 }
 
-void Chttp2Connector::Shutdown(grpc_error* error) {
+void Chttp2Connector::Shutdown(grpc_error_handle error) {
   MutexLock lock(&mu_);
   shutdown_ = true;
   if (handshake_mgr_ != nullptr) {
@@ -89,7 +89,7 @@ void Chttp2Connector::Shutdown(grpc_error* error) {
   GRPC_ERROR_UNREF(error);
 }
 
-void Chttp2Connector::Connected(void* arg, grpc_error* error) {
+void Chttp2Connector::Connected(void* arg, grpc_error_handle error) {
   Chttp2Connector* self = static_cast<Chttp2Connector*>(arg);
   bool unref = false;
   {
@@ -131,14 +131,14 @@ void Chttp2Connector::StartHandshakeLocked() {
 
 namespace {
 void NullThenSchedClosure(const DebugLocation& location, grpc_closure** closure,
-                          grpc_error* error) {
+                          grpc_error_handle error) {
   grpc_closure* c = *closure;
   *closure = nullptr;
   ExecCtx::Run(location, c, error);
 }
 }  // namespace
 
-void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error* error) {
+void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error_handle error) {
   auto* args = static_cast<HandshakerArgs*>(arg);
   Chttp2Connector* self = static_cast<Chttp2Connector*>(args->user_data);
   {
@@ -194,7 +194,7 @@ void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error* error) {
   self->Unref();
 }
 
-void Chttp2Connector::OnReceiveSettings(void* arg, grpc_error* error) {
+void Chttp2Connector::OnReceiveSettings(void* arg, grpc_error_handle error) {
   Chttp2Connector* self = static_cast<Chttp2Connector*>(arg);
   {
     MutexLock lock(&self->mu_);
@@ -220,7 +220,7 @@ void Chttp2Connector::OnReceiveSettings(void* arg, grpc_error* error) {
   self->Unref();
 }
 
-void Chttp2Connector::OnTimeout(void* arg, grpc_error* /*error*/) {
+void Chttp2Connector::OnTimeout(void* arg, grpc_error_handle /*error*/) {
   Chttp2Connector* self = static_cast<Chttp2Connector*>(arg);
   {
     MutexLock lock(&self->mu_);
@@ -245,7 +245,7 @@ void Chttp2Connector::OnTimeout(void* arg, grpc_error* /*error*/) {
   self->Unref();
 }
 
-void Chttp2Connector::MaybeNotify(grpc_error* error) {
+void Chttp2Connector::MaybeNotify(grpc_error_handle error) {
   if (notify_error_.has_value()) {
     GRPC_ERROR_UNREF(error);
     NullThenSchedClosure(DEBUG_LOCATION, &notify_, notify_error_.value());
index 7624b7f..59db078 100644 (file)
@@ -33,14 +33,14 @@ class Chttp2Connector : public SubchannelConnector {
   ~Chttp2Connector() override;
 
   void Connect(const Args& args, Result* result, grpc_closure* notify) override;
-  void Shutdown(grpc_error* error) override;
+  void Shutdown(grpc_error_handle error) override;
 
  private:
-  static void Connected(void* arg, grpc_error* error);
+  static void Connected(void* arg, grpc_error_handle error);
   void StartHandshakeLocked();
-  static void OnHandshakeDone(void* arg, grpc_error* error);
-  static void OnReceiveSettings(void* arg, grpc_error* error);
-  static void OnTimeout(void* arg, grpc_error* error);
+  static void OnHandshakeDone(void* arg, grpc_error_handle error);
+  static void OnReceiveSettings(void* arg, grpc_error_handle error);
+  static void OnTimeout(void* arg, grpc_error_handle error);
 
   // We cannot invoke notify_ until both OnTimeout() and OnReceiveSettings()
   // have been called since that is an indicator to the upper layer that we are
@@ -51,7 +51,7 @@ class Chttp2Connector : public SubchannelConnector {
   // invoked, we call MaybeNotify() again to actually invoke the notify_
   // callback. Note that this only happens if the handshake is done and the
   // connector is waiting on the SETTINGS frame.
-  void MaybeNotify(grpc_error* error);
+  void MaybeNotify(grpc_error_handle error);
 
   Mutex mu_;
   Args args_;
@@ -66,7 +66,7 @@ class Chttp2Connector : public SubchannelConnector {
   grpc_closure on_receive_settings_;
   grpc_timer timer_;
   grpc_closure on_timeout_;
-  absl::optional<grpc_error*> notify_error_;
+  absl::optional<grpc_error_handle> notify_error_;
   RefCountedPtr<HandshakeManager> handshake_mgr_;
 };
 
index d82cc1d..58f2742 100644 (file)
@@ -51,7 +51,7 @@ class Chttp2InsecureClientChannelFactory : public ClientChannelFactory {
 namespace {
 
 grpc_channel* CreateChannel(const char* target, const grpc_channel_args* args,
-                            grpc_error** error) {
+                            grpc_error_handle* error) {
   if (target == nullptr) {
     gpr_log(GPR_ERROR, "cannot create channel with NULL target name");
     if (error != nullptr) {
@@ -106,7 +106,7 @@ grpc_channel* grpc_insecure_channel_create(const char* target,
   const char* arg_to_remove = arg.key;
   grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
       args, &arg_to_remove, 1, &arg, 1);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   // Create channel.
   grpc_channel* channel = grpc_core::CreateChannel(target, new_args, &error);
   // Clean up.
index 1360047..4700093 100644 (file)
@@ -56,7 +56,7 @@ grpc_channel* grpc_insecure_channel_create_from_fd(
   grpc_transport* transport =
       grpc_create_chttp2_transport(final_args, client, true);
   GPR_ASSERT(transport);
-  grpc_error* error = nullptr;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_channel* channel =
       grpc_channel_create(target, final_args, GRPC_CLIENT_DIRECT_CHANNEL,
                           transport, nullptr, &error);
index 225628c..5b00098 100644 (file)
@@ -28,9 +28,9 @@
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/memory.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/security_connector/security_connector.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -129,7 +129,7 @@ class Chttp2SecureClientChannelFactory : public ClientChannelFactory {
 namespace {
 
 grpc_channel* CreateChannel(const char* target, const grpc_channel_args* args,
-                            grpc_error** error) {
+                            grpc_error_handle* error) {
   if (target == nullptr) {
     gpr_log(GPR_ERROR, "cannot create channel with NULL target name");
     if (error != nullptr) {
@@ -181,7 +181,7 @@ grpc_channel* grpc_secure_channel_create(grpc_channel_credentials* creds,
       4, ((void*)creds, target, (void*)args, (void*)reserved));
   GPR_ASSERT(reserved == nullptr);
   grpc_channel* channel = nullptr;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (creds != nullptr) {
     // Add channel args containing the client channel factory and channel
     // credentials.
index ee01add..911af03 100644 (file)
@@ -38,6 +38,7 @@
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
 #include "src/core/lib/channel/handshaker_registry.h"
@@ -46,7 +47,6 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/resource_quota.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -61,14 +61,14 @@ const char kUnixAbstractUriPrefix[] = "unix-abstract:";
 
 class Chttp2ServerListener : public Server::ListenerInterface {
  public:
-  static grpc_error* Create(Server* server, grpc_resolved_address* addr,
-                            grpc_channel_args* args,
-                            Chttp2ServerArgsModifier args_modifier,
-                            int* port_num);
+  static grpc_error_handle Create(Server* server, grpc_resolved_address* addr,
+                                  grpc_channel_args* args,
+                                  Chttp2ServerArgsModifier args_modifier,
+                                  int* port_num);
 
-  static grpc_error* CreateWithAcceptor(Server* server, const char* name,
-                                        grpc_channel_args* args,
-                                        Chttp2ServerArgsModifier args_modifier);
+  static grpc_error_handle CreateWithAcceptor(
+      Server* server, const char* name, grpc_channel_args* args,
+      Chttp2ServerArgsModifier args_modifier);
 
   // Do not instantiate directly.  Use one of the factory methods above.
   Chttp2ServerListener(Server* server, grpc_channel_args* args,
@@ -122,9 +122,9 @@ class Chttp2ServerListener : public Server::ListenerInterface {
       using InternallyRefCounted<HandshakingState>::Ref;
 
      private:
-      static void OnTimeout(void* arg, grpc_error* error);
-      static void OnReceiveSettings(void* arg, grpc_error* /* error */);
-      static void OnHandshakeDone(void* arg, grpc_error* error);
+      static void OnTimeout(void* arg, grpc_error_handle error);
+      static void OnReceiveSettings(void* arg, grpc_error_handle /* error */);
+      static void OnHandshakeDone(void* arg, grpc_error_handle error);
       RefCountedPtr<ActiveConnection> const connection_;
       grpc_pollset* const accepting_pollset_;
       grpc_tcp_server_acceptor* const acceptor_;
@@ -155,7 +155,7 @@ class Chttp2ServerListener : public Server::ListenerInterface {
     using InternallyRefCounted<ActiveConnection>::Ref;
 
    private:
-    static void OnClose(void* arg, grpc_error* error);
+    static void OnClose(void* arg, grpc_error_handle error);
 
     RefCountedPtr<Chttp2ServerListener> listener_;
     Mutex mu_ ABSL_ACQUIRED_AFTER(&listener_->mu_);
@@ -179,7 +179,7 @@ class Chttp2ServerListener : public Server::ListenerInterface {
                        grpc_pollset* accepting_pollset,
                        grpc_tcp_server_acceptor* acceptor);
 
-  static void TcpServerShutdownComplete(void* arg, grpc_error* error);
+  static void TcpServerShutdownComplete(void* arg, grpc_error_handle error);
 
   static void DestroyListener(Server* /*server*/, void* arg,
                               grpc_closure* destroy_done);
@@ -259,12 +259,12 @@ void Chttp2ServerListener::ConfigFetcherWatcher::UpdateConnectionManager(
     if (listener_->started_) return;
   }
   int port_temp;
-  grpc_error* error = grpc_tcp_server_add_port(
+  grpc_error_handle error = grpc_tcp_server_add_port(
       listener_->tcp_server_, &listener_->resolved_address_, &port_temp);
   if (error != GRPC_ERROR_NONE) {
     GRPC_ERROR_UNREF(error);
     gpr_log(GPR_ERROR, "Error adding port to server: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     // TODO(yashykt): We wouldn't need to assert here if we bound to the
     // port earlier during AddPort.
     GPR_ASSERT(0);
@@ -347,7 +347,7 @@ void Chttp2ServerListener::ActiveConnection::HandshakingState::Start(
 }
 
 void Chttp2ServerListener::ActiveConnection::HandshakingState::OnTimeout(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   HandshakingState* self = static_cast<HandshakingState*>(arg);
   // Note that we may be called with GRPC_ERROR_NONE when the timer fires
   // or with an error indicating that the timer system is being shut down.
@@ -366,14 +366,14 @@ void Chttp2ServerListener::ActiveConnection::HandshakingState::OnTimeout(
 }
 
 void Chttp2ServerListener::ActiveConnection::HandshakingState::
-    OnReceiveSettings(void* arg, grpc_error* /* error */) {
+    OnReceiveSettings(void* arg, grpc_error_handle /* error */) {
   HandshakingState* self = static_cast<HandshakingState*>(arg);
   grpc_timer_cancel(&self->timer_);
   self->Unref();
 }
 
 void Chttp2ServerListener::ActiveConnection::HandshakingState::OnHandshakeDone(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   auto* args = static_cast<HandshakerArgs*>(arg);
   HandshakingState* self = static_cast<HandshakingState*>(args->user_data);
   OrphanablePtr<HandshakingState> handshaking_state_ref;
@@ -385,8 +385,8 @@ void Chttp2ServerListener::ActiveConnection::HandshakingState::OnHandshakeDone(
   {
     MutexLock connection_lock(&self->connection_->mu_);
     if (error != GRPC_ERROR_NONE || self->connection_->shutdown_) {
-      const char* error_str = grpc_error_string(error);
-      gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str);
+      std::string error_str = grpc_error_std_string(error);
+      gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str.c_str());
       cleanup_connection = true;
       free_resource_quota = true;
       if (error == GRPC_ERROR_NONE && args->endpoint != nullptr) {
@@ -409,7 +409,7 @@ void Chttp2ServerListener::ActiveConnection::HandshakingState::OnHandshakeDone(
       if (args->endpoint != nullptr) {
         grpc_transport* transport = grpc_create_chttp2_transport(
             args->args, args->endpoint, false, resource_user);
-        grpc_error* channel_init_err =
+        grpc_error_handle channel_init_err =
             self->connection_->listener_->server_->SetupTransport(
                 transport, self->accepting_pollset_, args->args,
                 grpc_chttp2_transport_get_socket_node(transport),
@@ -455,7 +455,7 @@ void Chttp2ServerListener::ActiveConnection::HandshakingState::OnHandshakeDone(
         } else {
           // Failed to create channel from transport. Clean up.
           gpr_log(GPR_ERROR, "Failed to create channel: %s",
-                  grpc_error_string(channel_init_err));
+                  grpc_error_std_string(channel_init_err).c_str());
           GRPC_ERROR_UNREF(channel_init_err);
           grpc_transport_destroy(transport);
           grpc_slice_buffer_destroy_internal(args->read_buffer);
@@ -553,8 +553,8 @@ void Chttp2ServerListener::ActiveConnection::Start(
   handshaking_state_ref->Start(endpoint, args);
 }
 
-void Chttp2ServerListener::ActiveConnection::OnClose(void* arg,
-                                                     grpc_error* /* error */) {
+void Chttp2ServerListener::ActiveConnection::OnClose(
+    void* arg, grpc_error_handle /* error */) {
   ActiveConnection* self = static_cast<ActiveConnection*>(arg);
   OrphanablePtr<ActiveConnection> connection;
   {
@@ -577,15 +577,13 @@ void Chttp2ServerListener::ActiveConnection::OnClose(void* arg,
 // Chttp2ServerListener
 //
 
-grpc_error* Chttp2ServerListener::Create(Server* server,
-                                         grpc_resolved_address* addr,
-                                         grpc_channel_args* args,
-                                         Chttp2ServerArgsModifier args_modifier,
-                                         int* port_num) {
+grpc_error_handle Chttp2ServerListener::Create(
+    Server* server, grpc_resolved_address* addr, grpc_channel_args* args,
+    Chttp2ServerArgsModifier args_modifier, int* port_num) {
   Chttp2ServerListener* listener = nullptr;
   // The bulk of this method is inside of a lambda to make cleanup
   // easier without using goto.
-  grpc_error* error = [&]() {
+  grpc_error_handle error = [&]() {
     // Create Chttp2ServerListener.
     listener = new Chttp2ServerListener(server, args, args_modifier);
     error = grpc_tcp_server_create(&listener->tcp_server_shutdown_complete_,
@@ -627,12 +625,12 @@ grpc_error* Chttp2ServerListener::Create(Server* server,
   return error;
 }
 
-grpc_error* Chttp2ServerListener::CreateWithAcceptor(
+grpc_error_handle Chttp2ServerListener::CreateWithAcceptor(
     Server* server, const char* name, grpc_channel_args* args,
     Chttp2ServerArgsModifier args_modifier) {
   Chttp2ServerListener* listener =
       new Chttp2ServerListener(server, args, args_modifier);
-  grpc_error* error = grpc_tcp_server_create(
+  grpc_error_handle error = grpc_tcp_server_create(
       &listener->tcp_server_shutdown_complete_, args, &listener->tcp_server_);
   if (error != GRPC_ERROR_NONE) {
     delete listener;
@@ -710,14 +708,14 @@ void Chttp2ServerListener::OnAccept(void* arg, grpc_endpoint* tcp,
     args = grpc_channel_args_copy(self->args_);
     connection_manager = self->connection_manager_;
   }
-  auto endpoint_cleanup = [&](grpc_error* error) {
+  auto endpoint_cleanup = [&](grpc_error_handle error) {
     grpc_endpoint_shutdown(tcp, error);
     grpc_endpoint_destroy(tcp);
     gpr_free(acceptor);
   };
   if (self->server_->config_fetcher() != nullptr) {
     if (connection_manager == nullptr) {
-      grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+      grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "No ConnectionManager configured. Closing connection.");
       endpoint_cleanup(error);
       grpc_channel_args_destroy(args);
@@ -734,10 +732,11 @@ void Chttp2ServerListener::OnAccept(void* arg, grpc_endpoint* tcp,
           args_result.status().ToString().c_str()));
       return;
     }
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     args = self->args_modifier_(*args_result, &error);
     if (error != GRPC_ERROR_NONE) {
-      gpr_log(GPR_DEBUG, "Closing connection: %s", grpc_error_string(error));
+      gpr_log(GPR_DEBUG, "Closing connection: %s",
+              grpc_error_std_string(error).c_str());
       endpoint_cleanup(error);
       grpc_channel_args_destroy(args);
       return;
@@ -781,7 +780,7 @@ void Chttp2ServerListener::OnAccept(void* arg, grpc_endpoint* tcp,
 }
 
 void Chttp2ServerListener::TcpServerShutdownComplete(void* arg,
-                                                     grpc_error* error) {
+                                                     grpc_error_handle error) {
   Chttp2ServerListener* self = static_cast<Chttp2ServerListener*>(arg);
   self->channelz_listen_socket_.reset();
   GRPC_ERROR_UNREF(error);
@@ -822,19 +821,19 @@ void Chttp2ServerListener::Orphan() {
 // Chttp2ServerAddPort()
 //
 
-grpc_error* Chttp2ServerAddPort(Server* server, const char* addr,
-                                grpc_channel_args* args,
-                                Chttp2ServerArgsModifier args_modifier,
-                                int* port_num) {
+grpc_error_handle Chttp2ServerAddPort(Server* server, const char* addr,
+                                      grpc_channel_args* args,
+                                      Chttp2ServerArgsModifier args_modifier,
+                                      int* port_num) {
   if (strncmp(addr, "external:", 9) == 0) {
     return grpc_core::Chttp2ServerListener::CreateWithAcceptor(
         server, addr, args, args_modifier);
   }
   *port_num = -1;
   grpc_resolved_addresses* resolved = nullptr;
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   // Using lambda to avoid use of goto.
-  grpc_error* error = [&]() {
+  grpc_error_handle error = [&]() {
     if (absl::StartsWith(addr, kUnixUriPrefix)) {
       error = grpc_resolve_unix_domain_address(
           addr + sizeof(kUnixUriPrefix) - 1, &resolved);
@@ -879,13 +878,13 @@ grpc_error* Chttp2ServerAddPort(Server* server, const char* addr,
           resolved->naddrs - error_list.size(), resolved->naddrs);
       error = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(
           msg.c_str(), error_list.data(), error_list.size());
-      gpr_log(GPR_INFO, "WARNING: %s", grpc_error_string(error));
+      gpr_log(GPR_INFO, "WARNING: %s", grpc_error_std_string(error).c_str());
       GRPC_ERROR_UNREF(error);
       // we managed to bind some addresses: continue without error
     }
     return GRPC_ERROR_NONE;
   }();  // lambda end
-  for (grpc_error* error : error_list) {
+  for (grpc_error_handle error : error_list) {
     GRPC_ERROR_UNREF(error);
   }
   grpc_channel_args_destroy(args);
index 10322e9..e4e6b7c 100644 (file)
@@ -34,11 +34,11 @@ namespace grpc_core {
 // added to the server. Takes ownership of the args.  Caller takes ownership of
 // returned args. On failure, the error parameter will be set.
 using Chttp2ServerArgsModifier =
-    std::function<grpc_channel_args*(grpc_channel_args*, grpc_error**)>;
+    std::function<grpc_channel_args*(grpc_channel_args*, grpc_error_handle*)>;
 
 /// Adds a port to \a server.  Sets \a port_num to the port number.
 /// Takes ownership of \a args.
-grpc_error* Chttp2ServerAddPort(
+grpc_error_handle Chttp2ServerAddPort(
     Server* server, const char* addr, grpc_channel_args* args,
     Chttp2ServerArgsModifier connection_args_modifier, int* port_num);
 
index 3a3d6f3..e00bc92 100644 (file)
@@ -30,7 +30,7 @@
 namespace {
 
 grpc_channel_args* ModifyArgsForConnection(grpc_channel_args* args,
-                                           grpc_error** /*error*/) {
+                                           grpc_error_handle* /*error*/) {
   return args;
 }
 
@@ -41,13 +41,12 @@ int grpc_server_add_insecure_http2_port(grpc_server* server, const char* addr) {
   int port_num = 0;
   GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
                  (server, addr));
-  grpc_error* err = grpc_core::Chttp2ServerAddPort(
+  grpc_error_handle err = grpc_core::Chttp2ServerAddPort(
       server->core_server.get(), addr,
       grpc_channel_args_copy(server->core_server->channel_args()),
       ModifyArgsForConnection, &port_num);
   if (err != GRPC_ERROR_NONE) {
-    const char* msg = grpc_error_string(err);
-    gpr_log(GPR_ERROR, "%s", msg);
+    gpr_log(GPR_ERROR, "%s", grpc_error_std_string(err).c_str());
 
     GRPC_ERROR_UNREF(err);
   }
index 0ee9eee..fd57939 100644 (file)
@@ -51,7 +51,7 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server,
   grpc_transport* transport = grpc_create_chttp2_transport(
       server_args, server_endpoint, false /* is_client */);
 
-  grpc_error* error =
+  grpc_error_handle error =
       core_server->SetupTransport(transport, nullptr, server_args, nullptr);
   if (error == GRPC_ERROR_NONE) {
     for (grpc_pollset* pollset : core_server->pollsets()) {
@@ -60,7 +60,7 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server,
     grpc_chttp2_transport_start_reading(transport, nullptr, nullptr, nullptr);
   } else {
     gpr_log(GPR_ERROR, "Failed to create channel: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     grpc_transport_destroy(transport);
   }
index 563c303..f0a0eed 100644 (file)
@@ -40,7 +40,7 @@
 namespace {
 
 grpc_channel_args* ModifyArgsForConnection(grpc_channel_args* args,
-                                           grpc_error** error) {
+                                           grpc_error_handle* error) {
   grpc_server_credentials* server_credentials =
       grpc_find_server_credentials_in_args(args);
   if (server_credentials == nullptr) {
@@ -69,7 +69,7 @@ grpc_channel_args* ModifyArgsForConnection(grpc_channel_args* args,
 int grpc_server_add_secure_http2_port(grpc_server* server, const char* addr,
                                       grpc_server_credentials* creds) {
   grpc_core::ExecCtx exec_ctx;
-  grpc_error* err = GRPC_ERROR_NONE;
+  grpc_error_handle err = GRPC_ERROR_NONE;
   grpc_core::RefCountedPtr<grpc_server_security_connector> sc;
   int port_num = 0;
   grpc_channel_args* args = nullptr;
@@ -121,8 +121,7 @@ int grpc_server_add_secure_http2_port(grpc_server* server, const char* addr,
 done:
   sc.reset(DEBUG_LOCATION, "server");
   if (err != GRPC_ERROR_NONE) {
-    const char* msg = grpc_error_string(err);
-    gpr_log(GPR_ERROR, "%s", msg);
+    gpr_log(GPR_ERROR, "%s", grpc_error_std_string(err).c_str());
 
     GRPC_ERROR_UNREF(err);
   }
index 1bc6941..1ff6475 100644 (file)
@@ -100,23 +100,23 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_chttp2_refcount(false,
                                                          "chttp2_refcount");
 
 // forward declarations of various callbacks that we'll build closures around
-static void write_action_begin_locked(void* t, grpc_error* error);
-static void write_action(void* t, grpc_error* error);
-static void write_action_end(void* t, grpc_error* error);
-static void write_action_end_locked(void* t, grpc_error* error);
+static void write_action_begin_locked(void* t, grpc_error_handle error);
+static void write_action(void* t, grpc_error_handle error);
+static void write_action_end(void* t, grpc_error_handle error);
+static void write_action_end_locked(void* t, grpc_error_handle error);
 
-static void read_action(void* t, grpc_error* error);
-static void read_action_locked(void* t, grpc_error* error);
+static void read_action(void* t, grpc_error_handle error);
+static void read_action_locked(void* t, grpc_error_handle error);
 static void continue_read_action_locked(grpc_chttp2_transport* t);
 
-static void complete_fetch(void* gs, grpc_error* error);
-static void complete_fetch_locked(void* gs, grpc_error* error);
+static void complete_fetch(void* gs, grpc_error_handle error);
+static void complete_fetch_locked(void* gs, grpc_error_handle error);
 // Set a transport level setting, and push it to our peer
 static void queue_setting_update(grpc_chttp2_transport* t,
                                  grpc_chttp2_setting_id id, uint32_t value);
 
 static void close_from_api(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                           grpc_error* error);
+                           grpc_error_handle error);
 
 // Start new streams that have been created if we can
 static void maybe_start_some_streams(grpc_chttp2_transport* t);
@@ -126,40 +126,43 @@ static void connectivity_state_set(grpc_chttp2_transport* t,
                                    const absl::Status& status,
                                    const char* reason);
 
-static void benign_reclaimer(void* arg, grpc_error* error);
-static void destructive_reclaimer(void* arg, grpc_error* error);
-static void benign_reclaimer_locked(void* arg, grpc_error* error);
-static void destructive_reclaimer_locked(void* arg, grpc_error* error);
+static void benign_reclaimer(void* arg, grpc_error_handle error);
+static void destructive_reclaimer(void* arg, grpc_error_handle error);
+static void benign_reclaimer_locked(void* arg, grpc_error_handle error);
+static void destructive_reclaimer_locked(void* arg, grpc_error_handle error);
 
 static void post_benign_reclaimer(grpc_chttp2_transport* t);
 static void post_destructive_reclaimer(grpc_chttp2_transport* t);
 
-static void close_transport_locked(grpc_chttp2_transport* t, grpc_error* error);
-static void end_all_the_calls(grpc_chttp2_transport* t, grpc_error* error);
-
-static void start_bdp_ping(void* tp, grpc_error* error);
-static void finish_bdp_ping(void* tp, grpc_error* error);
-static void start_bdp_ping_locked(void* tp, grpc_error* error);
-static void finish_bdp_ping_locked(void* tp, grpc_error* error);
-static void next_bdp_ping_timer_expired(void* tp, grpc_error* error);
-static void next_bdp_ping_timer_expired_locked(void* tp, grpc_error* error);
-
-static void cancel_pings(grpc_chttp2_transport* t, grpc_error* error);
+static void close_transport_locked(grpc_chttp2_transport* t,
+                                   grpc_error_handle error);
+static void end_all_the_calls(grpc_chttp2_transport* t,
+                              grpc_error_handle error);
+
+static void start_bdp_ping(void* tp, grpc_error_handle error);
+static void finish_bdp_ping(void* tp, grpc_error_handle error);
+static void start_bdp_ping_locked(void* tp, grpc_error_handle error);
+static void finish_bdp_ping_locked(void* tp, grpc_error_handle error);
+static void next_bdp_ping_timer_expired(void* tp, grpc_error_handle error);
+static void next_bdp_ping_timer_expired_locked(void* tp,
+                                               grpc_error_handle error);
+
+static void cancel_pings(grpc_chttp2_transport* t, grpc_error_handle error);
 static void send_ping_locked(grpc_chttp2_transport* t,
                              grpc_closure* on_initiate, grpc_closure* on_ack);
-static void retry_initiate_ping_locked(void* tp, grpc_error* error);
+static void retry_initiate_ping_locked(void* tp, grpc_error_handle error);
 
 // keepalive-relevant functions
-static void init_keepalive_ping(void* arg, grpc_error* error);
-static void init_keepalive_ping_locked(void* arg, grpc_error* error);
-static void start_keepalive_ping(void* arg, grpc_error* error);
-static void finish_keepalive_ping(void* arg, grpc_error* error);
-static void start_keepalive_ping_locked(void* arg, grpc_error* error);
-static void finish_keepalive_ping_locked(void* arg, grpc_error* error);
-static void keepalive_watchdog_fired(void* arg, grpc_error* error);
-static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error);
+static void init_keepalive_ping(void* arg, grpc_error_handle error);
+static void init_keepalive_ping_locked(void* arg, grpc_error_handle error);
+static void start_keepalive_ping(void* arg, grpc_error_handle error);
+static void finish_keepalive_ping(void* arg, grpc_error_handle error);
+static void start_keepalive_ping_locked(void* arg, grpc_error_handle error);
+static void finish_keepalive_ping_locked(void* arg, grpc_error_handle error);
+static void keepalive_watchdog_fired(void* arg, grpc_error_handle error);
+static void keepalive_watchdog_fired_locked(void* arg, grpc_error_handle error);
 
-static void reset_byte_stream(void* arg, grpc_error* error);
+static void reset_byte_stream(void* arg, grpc_error_handle error);
 
 // Flow control default enabled. Can be disabled by setting
 // GRPC_EXPERIMENTAL_DISABLE_FLOW_CONTROL
@@ -203,7 +206,7 @@ grpc_chttp2_transport::~grpc_chttp2_transport() {
   grpc_slice_buffer_destroy_internal(&outbuf);
   grpc_chttp2_hpack_compressor_destroy(&hpack_compressor);
 
-  grpc_error* error =
+  grpc_error_handle error =
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed");
   // ContextList::Execute follows semantics of a callback function and does not
   // take a ref on error
@@ -534,7 +537,7 @@ grpc_chttp2_transport::grpc_chttp2_transport(
   }
 }
 
-static void destroy_transport_locked(void* tp, grpc_error* /*error*/) {
+static void destroy_transport_locked(void* tp, grpc_error_handle /*error*/) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->destroying = 1;
   close_transport_locked(
@@ -552,7 +555,7 @@ static void destroy_transport(grpc_transport* gt) {
 }
 
 static void close_transport_locked(grpc_chttp2_transport* t,
-                                   grpc_error* error) {
+                                   grpc_error_handle error) {
   end_all_the_calls(t, GRPC_ERROR_REF(error));
   cancel_pings(t, GRPC_ERROR_REF(error));
   if (t->closed_with_error == GRPC_ERROR_NONE) {
@@ -731,7 +734,7 @@ static int init_stream(grpc_transport* gt, grpc_stream* gs,
   return 0;
 }
 
-static void destroy_stream_locked(void* sp, grpc_error* /*error*/) {
+static void destroy_stream_locked(void* sp, grpc_error_handle /*error*/) {
   GPR_TIMER_SCOPE("destroy_stream", 0);
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp);
   s->~grpc_chttp2_stream();
@@ -819,7 +822,7 @@ static void set_write_state(grpc_chttp2_transport* t,
   if (st == GRPC_CHTTP2_WRITE_STATE_IDLE) {
     grpc_core::ExecCtx::RunList(DEBUG_LOCATION, &t->run_after_write);
     if (t->close_transport_on_writes_finished != nullptr) {
-      grpc_error* err = t->close_transport_on_writes_finished;
+      grpc_error_handle err = t->close_transport_on_writes_finished;
       t->close_transport_on_writes_finished = nullptr;
       close_transport_locked(t, err);
     }
@@ -951,7 +954,8 @@ static const char* begin_writing_desc(bool partial) {
   }
 }
 
-static void write_action_begin_locked(void* gt, grpc_error* /*error_ignored*/) {
+static void write_action_begin_locked(void* gt,
+                                      grpc_error_handle /*error_ignored*/) {
   GPR_TIMER_SCOPE("write_action_begin_locked", 0);
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(gt);
   GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE);
@@ -990,7 +994,7 @@ static void write_action_begin_locked(void* gt, grpc_error* /*error_ignored*/) {
   }
 }
 
-static void write_action(void* gt, grpc_error* /*error*/) {
+static void write_action(void* gt, grpc_error_handle /*error*/) {
   GPR_TIMER_SCOPE("write_action", 0);
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(gt);
   void* cl = t->cl;
@@ -1002,7 +1006,7 @@ static void write_action(void* gt, grpc_error* /*error*/) {
       cl);
 }
 
-static void write_action_end(void* tp, grpc_error* error) {
+static void write_action_end(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->write_action_end_locked,
                                      write_action_end_locked, t, nullptr),
@@ -1011,7 +1015,7 @@ static void write_action_end(void* tp, grpc_error* error) {
 
 // Callback from the grpc_endpoint after bytes have been written by calling
 // sendmsg
-static void write_action_end_locked(void* tp, grpc_error* error) {
+static void write_action_end_locked(void* tp, grpc_error_handle error) {
   GPR_TIMER_SCOPE("terminate_writing_with_lock", 0);
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 
@@ -1100,7 +1104,7 @@ void grpc_chttp2_add_incoming_goaway(grpc_chttp2_transport* t,
   // received a GOAWAY with a non NO_ERROR code.
   if (goaway_error != GRPC_HTTP2_NO_ERROR) {
     gpr_log(GPR_INFO, "%s: Got goaway [%d] err=%s", t->peer_string.c_str(),
-            goaway_error, grpc_error_string(t->goaway_error));
+            goaway_error, grpc_error_std_string(t->goaway_error).c_str());
   }
   absl::Status status = grpc_error_to_absl_status(t->goaway_error);
   // When a client receives a GOAWAY with error code ENHANCE_YOUR_CALM and debug
@@ -1206,7 +1210,8 @@ static void null_then_sched_closure(grpc_closure** closure) {
 void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
                                        grpc_chttp2_stream* /*s*/,
                                        grpc_closure** pclosure,
-                                       grpc_error* error, const char* desc) {
+                                       grpc_error_handle error,
+                                       const char* desc) {
   grpc_closure* closure = *pclosure;
   *pclosure = nullptr;
   if (closure == nullptr) {
@@ -1215,7 +1220,6 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
   }
   closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
-    const char* errstr = grpc_error_string(error);
     gpr_log(
         GPR_INFO,
         "complete_closure_step: t=%p %p refs=%d flags=0x%04x desc=%s err=%s "
@@ -1225,7 +1229,8 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
                          CLOSURE_BARRIER_FIRST_REF_BIT),
         static_cast<int>(closure->next_data.scratch %
                          CLOSURE_BARRIER_FIRST_REF_BIT),
-        desc, errstr, write_state_name(t->write_state));
+        desc, grpc_error_std_string(error).c_str(),
+        write_state_name(t->write_state));
   }
   if (error != GRPC_ERROR_NONE) {
     if (closure->error_data.error == GRPC_ERROR_NONE) {
@@ -1314,7 +1319,8 @@ static void continue_fetching_send_locked(grpc_chttp2_transport* t,
                    UINT32_MAX, GRPC_CLOSURE_INIT(&s->complete_fetch_locked,
                                                  ::complete_fetch, s,
                                                  grpc_schedule_on_exec_ctx))) {
-      grpc_error* error = s->fetching_send_message->Pull(&s->fetching_slice);
+      grpc_error_handle error =
+          s->fetching_send_message->Pull(&s->fetching_slice);
       if (error != GRPC_ERROR_NONE) {
         s->fetching_send_message.reset();
         grpc_chttp2_cancel_stream(t, s, error);
@@ -1325,14 +1331,14 @@ static void continue_fetching_send_locked(grpc_chttp2_transport* t,
   }
 }
 
-static void complete_fetch(void* gs, grpc_error* error) {
+static void complete_fetch(void* gs, grpc_error_handle error) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(gs);
   s->t->combiner->Run(GRPC_CLOSURE_INIT(&s->complete_fetch_locked,
                                         ::complete_fetch_locked, s, nullptr),
                       GRPC_ERROR_REF(error));
 }
 
-static void complete_fetch_locked(void* gs, grpc_error* error) {
+static void complete_fetch_locked(void* gs, grpc_error_handle error) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(gs);
   grpc_chttp2_transport* t = s->t;
   if (error == GRPC_ERROR_NONE) {
@@ -1362,7 +1368,7 @@ static void log_metadata(const grpc_metadata_batch* md_batch, uint32_t id,
 }
 
 static void perform_stream_op_locked(void* stream_op,
-                                     grpc_error* /*error_ignored*/) {
+                                     grpc_error_handle /*error_ignored*/) {
   GPR_TIMER_SCOPE("perform_stream_op_locked", 0);
 
   grpc_transport_stream_op_batch* op =
@@ -1646,7 +1652,7 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
                    GRPC_ERROR_NONE);
 }
 
-static void cancel_pings(grpc_chttp2_transport* t, grpc_error* error) {
+static void cancel_pings(grpc_chttp2_transport* t, grpc_error_handle error) {
   // 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;
@@ -1713,14 +1719,14 @@ static void send_keepalive_ping_locked(grpc_chttp2_transport* t) {
       GRPC_ERROR_NONE);
 }
 
-void grpc_chttp2_retry_initiate_ping(void* tp, grpc_error* error) {
+void grpc_chttp2_retry_initiate_ping(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->retry_initiate_ping_locked,
                                      retry_initiate_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void retry_initiate_ping_locked(void* tp, grpc_error* error) {
+static void retry_initiate_ping_locked(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->ping_state.is_delayed_ping_timer_set = false;
   if (error == GRPC_ERROR_NONE) {
@@ -1743,10 +1749,10 @@ void grpc_chttp2_ack_ping(grpc_chttp2_transport* t, uint64_t id) {
   }
 }
 
-static void send_goaway(grpc_chttp2_transport* t, grpc_error* error) {
+static void send_goaway(grpc_chttp2_transport* t, grpc_error_handle error) {
   // We want to log this irrespective of whether http tracing is enabled
   gpr_log(GPR_INFO, "%s: Sending goaway err=%s", t->peer_string.c_str(),
-          grpc_error_string(error));
+          grpc_error_std_string(error).c_str());
   t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED;
   grpc_http2_error_code http_error;
   grpc_slice slice;
@@ -1784,7 +1790,7 @@ void grpc_chttp2_reset_ping_clock(grpc_chttp2_transport* t) {
 }
 
 static void perform_transport_op_locked(void* stream_op,
-                                        grpc_error* /*error_ignored*/) {
+                                        grpc_error_handle /*error_ignored*/) {
   grpc_transport_op* op = static_cast<grpc_transport_op*>(stream_op);
   grpc_chttp2_transport* t =
       static_cast<grpc_chttp2_transport*>(op->handler_private.extra_arg);
@@ -1864,7 +1870,7 @@ void grpc_chttp2_maybe_complete_recv_initial_metadata(
 
 void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* /*t*/,
                                              grpc_chttp2_stream* s) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (s->recv_message_ready != nullptr) {
     *s->recv_message = nullptr;
     if (s->final_metadata_requested && s->seen_error) {
@@ -2014,7 +2020,7 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_chttp2_transport* t,
 }
 
 static void remove_stream(grpc_chttp2_transport* t, uint32_t id,
-                          grpc_error* error) {
+                          grpc_error_handle error) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(
       grpc_chttp2_stream_map_delete(&t->stream_map, id));
   GPR_DEBUG_ASSERT(s);
@@ -2057,7 +2063,7 @@ static void remove_stream(grpc_chttp2_transport* t, uint32_t id,
 }
 
 void grpc_chttp2_cancel_stream(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                               grpc_error* due_to_error) {
+                               grpc_error_handle due_to_error) {
   if (!t->is_client && !s->sent_trailing_metadata &&
       grpc_error_has_clear_grpc_status(due_to_error)) {
     close_from_api(t, s, due_to_error);
@@ -2081,7 +2087,7 @@ void grpc_chttp2_cancel_stream(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
 }
 
 void grpc_chttp2_fake_status(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                             grpc_error* error) {
+                             grpc_error_handle error) {
   grpc_status_code status;
   grpc_slice slice;
   grpc_error_get_status(error, s->deadline, &status, &slice, nullptr, nullptr);
@@ -2118,7 +2124,8 @@ void grpc_chttp2_fake_status(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
   GRPC_ERROR_UNREF(error);
 }
 
-static void add_error(grpc_error* error, grpc_error** refs, size_t* nrefs) {
+static void add_error(grpc_error_handle error, grpc_error_handle* refs,
+                      size_t* nrefs) {
   if (error == GRPC_ERROR_NONE) return;
   for (size_t i = 0; i < *nrefs; i++) {
     if (error == refs[i]) {
@@ -2129,14 +2136,15 @@ static void add_error(grpc_error* error, grpc_error** refs, size_t* nrefs) {
   ++*nrefs;
 }
 
-static grpc_error* removal_error(grpc_error* extra_error, grpc_chttp2_stream* s,
-                                 const char* main_error_msg) {
-  grpc_error* refs[3];
+static grpc_error_handle removal_error(grpc_error_handle extra_error,
+                                       grpc_chttp2_stream* s,
+                                       const char* main_error_msg) {
+  grpc_error_handle refs[3];
   size_t nrefs = 0;
   add_error(s->read_closed_error, refs, &nrefs);
   add_error(s->write_closed_error, refs, &nrefs);
   add_error(extra_error, refs, &nrefs);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (nrefs > 0) {
     error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(main_error_msg,
                                                              refs, nrefs);
@@ -2146,7 +2154,8 @@ static grpc_error* removal_error(grpc_error* extra_error, grpc_chttp2_stream* s,
 }
 
 static void flush_write_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                             grpc_chttp2_write_cb** list, grpc_error* error) {
+                             grpc_chttp2_write_cb** list,
+                             grpc_error_handle error) {
   while (*list) {
     grpc_chttp2_write_cb* cb = *list;
     *list = cb->next;
@@ -2159,7 +2168,8 @@ static void flush_write_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
 }
 
 void grpc_chttp2_fail_pending_writes(grpc_chttp2_transport* t,
-                                     grpc_chttp2_stream* s, grpc_error* error) {
+                                     grpc_chttp2_stream* s,
+                                     grpc_error_handle error) {
   error =
       removal_error(error, s, "Pending writes failed due to stream closure");
   s->send_initial_metadata = nullptr;
@@ -2183,10 +2193,10 @@ void grpc_chttp2_fail_pending_writes(grpc_chttp2_transport* t,
 
 void grpc_chttp2_mark_stream_closed(grpc_chttp2_transport* t,
                                     grpc_chttp2_stream* s, int close_reads,
-                                    int close_writes, grpc_error* error) {
+                                    int close_writes, grpc_error_handle error) {
   if (s->read_closed && s->write_closed) {
     // already closed, but we should still fake the status if needed.
-    grpc_error* overall_error = removal_error(error, s, "Stream removed");
+    grpc_error_handle overall_error = removal_error(error, s, "Stream removed");
     if (overall_error != GRPC_ERROR_NONE) {
       grpc_chttp2_fake_status(t, s, overall_error);
     }
@@ -2207,7 +2217,7 @@ void grpc_chttp2_mark_stream_closed(grpc_chttp2_transport* t,
   }
   if (s->read_closed && s->write_closed) {
     became_closed = true;
-    grpc_error* overall_error =
+    grpc_error_handle overall_error =
         removal_error(GRPC_ERROR_REF(error), s, "Stream removed");
     if (s->id != 0) {
       remove_stream(t, s->id, GRPC_ERROR_REF(overall_error));
@@ -2236,7 +2246,7 @@ void grpc_chttp2_mark_stream_closed(grpc_chttp2_transport* t,
 }
 
 static void close_from_api(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                           grpc_error* error) {
+                           grpc_error_handle error) {
   grpc_slice hdr;
   grpc_slice status_hdr;
   grpc_slice http_status_hdr;
@@ -2394,7 +2404,7 @@ static void close_from_api(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
 }
 
 struct cancel_stream_cb_args {
-  grpc_error* error;
+  grpc_error_handle error;
   grpc_chttp2_transport* t;
 };
 
@@ -2404,7 +2414,8 @@ static void cancel_stream_cb(void* user_data, uint32_t /*key*/, void* stream) {
   grpc_chttp2_cancel_stream(args->t, s, GRPC_ERROR_REF(args->error));
 }
 
-static void end_all_the_calls(grpc_chttp2_transport* t, grpc_error* error) {
+static void end_all_the_calls(grpc_chttp2_transport* t,
+                              grpc_error_handle error) {
   intptr_t http2_error;
   // If there is no explicit grpc or HTTP/2 error, set to UNAVAILABLE on server.
   if (!t->is_client && !grpc_error_has_clear_grpc_status(error) &&
@@ -2458,15 +2469,15 @@ void grpc_chttp2_act_on_flowctl_action(
               });
 }
 
-static grpc_error* try_http_parsing(grpc_chttp2_transport* t) {
+static grpc_error_handle try_http_parsing(grpc_chttp2_transport* t) {
   grpc_http_parser parser;
   size_t i = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_http_response response;
 
   grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response);
 
-  grpc_error* parse_error = GRPC_ERROR_NONE;
+  grpc_error_handle parse_error = GRPC_ERROR_NONE;
   for (; i < t->read_buffer.count && parse_error == GRPC_ERROR_NONE; i++) {
     parse_error =
         grpc_http_parser_parse(&parser, t->read_buffer.slices[i], nullptr);
@@ -2487,34 +2498,34 @@ static grpc_error* try_http_parsing(grpc_chttp2_transport* t) {
   return error;
 }
 
-static void read_action(void* tp, grpc_error* error) {
+static void read_action(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(
       GRPC_CLOSURE_INIT(&t->read_action_locked, read_action_locked, t, nullptr),
       GRPC_ERROR_REF(error));
 }
 
-static void read_action_locked(void* tp, grpc_error* error) {
+static void read_action_locked(void* tp, grpc_error_handle error) {
   GPR_TIMER_SCOPE("reading_action_locked", 0);
 
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 
   GRPC_ERROR_REF(error);
 
-  grpc_error* err = error;
+  grpc_error_handle err = error;
   if (err != GRPC_ERROR_NONE) {
     err = grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                                  "Endpoint read failed", &err, 1),
                              GRPC_ERROR_INT_OCCURRED_DURING_WRITE,
                              t->write_state);
   }
-  GPR_SWAP(grpc_error*, err, error);
+  GPR_SWAP(grpc_error_handle, err, error);
   GRPC_ERROR_UNREF(err);
   if (t->closed_with_error == GRPC_ERROR_NONE) {
     GPR_TIMER_SCOPE("reading_action.parse", 0);
     size_t i = 0;
-    grpc_error* errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
-                             GRPC_ERROR_NONE};
+    grpc_error_handle errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
+                                   GRPC_ERROR_NONE};
     for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
       errors[1] = grpc_chttp2_perform_read(t, t->read_buffer.slices[i]);
     }
@@ -2605,18 +2616,18 @@ void schedule_bdp_ping_locked(grpc_chttp2_transport* t) {
   grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_BDP_PING);
 }
 
-static void start_bdp_ping(void* tp, grpc_error* error) {
+static void start_bdp_ping(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->start_bdp_ping_locked,
                                      start_bdp_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void start_bdp_ping_locked(void* tp, grpc_error* error) {
+static void start_bdp_ping_locked(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
     gpr_log(GPR_INFO, "%s: Start BDP ping err=%s", t->peer_string.c_str(),
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   if (error != GRPC_ERROR_NONE || t->closed_with_error != GRPC_ERROR_NONE) {
     return;
@@ -2629,18 +2640,18 @@ static void start_bdp_ping_locked(void* tp, grpc_error* error) {
   t->bdp_ping_started = true;
 }
 
-static void finish_bdp_ping(void* tp, grpc_error* error) {
+static void finish_bdp_ping(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked,
                                      finish_bdp_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void finish_bdp_ping_locked(void* tp, grpc_error* error) {
+static void finish_bdp_ping_locked(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
     gpr_log(GPR_INFO, "%s: Complete BDP ping err=%s", t->peer_string.c_str(),
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   if (error != GRPC_ERROR_NONE || t->closed_with_error != GRPC_ERROR_NONE) {
     GRPC_CHTTP2_UNREF_TRANSPORT(t, "bdp_ping");
@@ -2666,7 +2677,7 @@ static void finish_bdp_ping_locked(void* tp, grpc_error* error) {
                   &t->next_bdp_ping_timer_expired_locked);
 }
 
-static void next_bdp_ping_timer_expired(void* tp, grpc_error* error) {
+static void next_bdp_ping_timer_expired(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(
       GRPC_CLOSURE_INIT(&t->next_bdp_ping_timer_expired_locked,
@@ -2674,7 +2685,8 @@ static void next_bdp_ping_timer_expired(void* tp, grpc_error* error) {
       GRPC_ERROR_REF(error));
 }
 
-static void next_bdp_ping_timer_expired_locked(void* tp, grpc_error* error) {
+static void next_bdp_ping_timer_expired_locked(void* tp,
+                                               grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   GPR_ASSERT(t->have_next_bdp_ping_timer);
   t->have_next_bdp_ping_timer = false;
@@ -2750,14 +2762,14 @@ void grpc_chttp2_config_default_keepalive_args(grpc_channel_args* args,
   }
 }
 
-static void init_keepalive_ping(void* arg, grpc_error* error) {
+static void init_keepalive_ping(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked,
                                      init_keepalive_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
+static void init_keepalive_ping_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING);
   if (t->destroying || t->closed_with_error != GRPC_ERROR_NONE) {
@@ -2790,14 +2802,14 @@ static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
   GRPC_CHTTP2_UNREF_TRANSPORT(t, "init keepalive ping");
 }
 
-static void start_keepalive_ping(void* arg, grpc_error* error) {
+static void start_keepalive_ping(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked,
                                      start_keepalive_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void start_keepalive_ping_locked(void* arg, grpc_error* error) {
+static void start_keepalive_ping_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (error != GRPC_ERROR_NONE) {
     return;
@@ -2818,14 +2830,14 @@ static void start_keepalive_ping_locked(void* arg, grpc_error* error) {
   t->keepalive_ping_started = true;
 }
 
-static void finish_keepalive_ping(void* arg, grpc_error* error) {
+static void finish_keepalive_ping(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->finish_keepalive_ping_locked,
                                      finish_keepalive_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void finish_keepalive_ping_locked(void* arg, grpc_error* error) {
+static void finish_keepalive_ping_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
     if (error == GRPC_ERROR_NONE) {
@@ -2856,7 +2868,7 @@ static void finish_keepalive_ping_locked(void* arg, grpc_error* error) {
   GRPC_CHTTP2_UNREF_TRANSPORT(t, "keepalive ping end");
 }
 
-static void keepalive_watchdog_fired(void* arg, grpc_error* error) {
+static void keepalive_watchdog_fired(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(
       GRPC_CLOSURE_INIT(&t->keepalive_watchdog_fired_locked,
@@ -2864,7 +2876,8 @@ static void keepalive_watchdog_fired(void* arg, grpc_error* error) {
       GRPC_ERROR_REF(error));
 }
 
-static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error) {
+static void keepalive_watchdog_fired_locked(void* arg,
+                                            grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
     if (error == GRPC_ERROR_NONE) {
@@ -2921,7 +2934,7 @@ static void set_pollset_set(grpc_transport* gt, grpc_stream* /*gs*/,
 // BYTE STREAM
 //
 
-static void reset_byte_stream(void* arg, grpc_error* error) {
+static void reset_byte_stream(void* arg, grpc_error_handle error) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(arg);
   s->pending_byte_stream = false;
   if (error == GRPC_ERROR_NONE) {
@@ -2952,8 +2965,8 @@ Chttp2IncomingByteStream::Chttp2IncomingByteStream(
   stream->byte_stream_error = GRPC_ERROR_NONE;
 }
 
-void Chttp2IncomingByteStream::OrphanLocked(void* arg,
-                                            grpc_error* /*error_ignored*/) {
+void Chttp2IncomingByteStream::OrphanLocked(
+    void* arg, grpc_error_handle /*error_ignored*/) {
   Chttp2IncomingByteStream* bs = static_cast<Chttp2IncomingByteStream*>(arg);
   grpc_chttp2_stream* s = bs->stream_;
   grpc_chttp2_transport* t = s->t;
@@ -2972,7 +2985,7 @@ void Chttp2IncomingByteStream::Orphan() {
 }
 
 void Chttp2IncomingByteStream::NextLocked(void* arg,
-                                          grpc_error* /*error_ignored*/) {
+                                          grpc_error_handle /*error_ignored*/) {
   Chttp2IncomingByteStream* bs = static_cast<Chttp2IncomingByteStream*>(arg);
   grpc_chttp2_transport* t = bs->transport_;
   grpc_chttp2_stream* s = bs->stream_;
@@ -3042,9 +3055,9 @@ void Chttp2IncomingByteStream::MaybeCreateStreamDecompressionCtx() {
   }
 }
 
-grpc_error* Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
+grpc_error_handle Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
   GPR_TIMER_SCOPE("incoming_byte_stream_pull", 0);
-  grpc_error* error;
+  grpc_error_handle error;
   if (stream_->unprocessed_incoming_frames_buffer.length > 0) {
     if (!stream_->unprocessed_incoming_frames_decompressed &&
         stream_->stream_decompression_method !=
@@ -3087,7 +3100,7 @@ grpc_error* Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
   return GRPC_ERROR_NONE;
 }
 
-void Chttp2IncomingByteStream::PublishError(grpc_error* error) {
+void Chttp2IncomingByteStream::PublishError(grpc_error_handle error) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, stream_->on_next,
                           GRPC_ERROR_REF(error));
@@ -3097,10 +3110,10 @@ void Chttp2IncomingByteStream::PublishError(grpc_error* error) {
   grpc_chttp2_cancel_stream(transport_, stream_, GRPC_ERROR_REF(error));
 }
 
-grpc_error* Chttp2IncomingByteStream::Push(const grpc_slice& slice,
-                                           grpc_slice* slice_out) {
+grpc_error_handle Chttp2IncomingByteStream::Push(const grpc_slice& slice,
+                                                 grpc_slice* slice_out) {
   if (remaining_bytes_ < GRPC_SLICE_LENGTH(slice)) {
-    grpc_error* error =
+    grpc_error_handle error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many bytes in stream");
     transport_->combiner->Run(&stream_->reset_byte_stream,
                               GRPC_ERROR_REF(error));
@@ -3115,8 +3128,8 @@ grpc_error* Chttp2IncomingByteStream::Push(const grpc_slice& slice,
   }
 }
 
-grpc_error* Chttp2IncomingByteStream::Finished(grpc_error* error,
-                                               bool reset_on_error) {
+grpc_error_handle Chttp2IncomingByteStream::Finished(grpc_error_handle error,
+                                                     bool reset_on_error) {
   if (error == GRPC_ERROR_NONE) {
     if (remaining_bytes_ != 0) {
       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
@@ -3130,7 +3143,7 @@ grpc_error* Chttp2IncomingByteStream::Finished(grpc_error* error,
   return error;
 }
 
-void Chttp2IncomingByteStream::Shutdown(grpc_error* error) {
+void Chttp2IncomingByteStream::Shutdown(grpc_error_handle error) {
   GRPC_ERROR_UNREF(Finished(error, true /* reset_on_error */));
 }
 
@@ -3162,14 +3175,14 @@ static void post_destructive_reclaimer(grpc_chttp2_transport* t) {
   }
 }
 
-static void benign_reclaimer(void* arg, grpc_error* error) {
+static void benign_reclaimer(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->benign_reclaimer_locked,
                                      benign_reclaimer_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void benign_reclaimer_locked(void* arg, grpc_error* error) {
+static void benign_reclaimer_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (error == GRPC_ERROR_NONE &&
       grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
@@ -3199,14 +3212,14 @@ static void benign_reclaimer_locked(void* arg, grpc_error* error) {
   GRPC_CHTTP2_UNREF_TRANSPORT(t, "benign_reclaimer");
 }
 
-static void destructive_reclaimer(void* arg, grpc_error* error) {
+static void destructive_reclaimer(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->destructive_reclaimer_locked,
                                      destructive_reclaimer_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void destructive_reclaimer_locked(void* arg, grpc_error* error) {
+static void destructive_reclaimer_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   size_t n = grpc_chttp2_stream_map_size(&t->stream_map);
   t->destructive_reclaimer_registered = false;
index a0473ea..afb18ab 100644 (file)
@@ -22,7 +22,7 @@
 
 namespace {
 void (*write_timestamps_callback_g)(void*, grpc_core::Timestamps*,
-                                    grpc_error* error) = nullptr;
+                                    grpc_error_handle error) = nullptr;
 void* (*get_copied_context_fn_g)(void*) = nullptr;
 }  // namespace
 
@@ -41,7 +41,7 @@ void ContextList::Append(ContextList** head, grpc_chttp2_stream* s) {
 }
 
 void ContextList::Execute(void* arg, grpc_core::Timestamps* ts,
-                          grpc_error* error) {
+                          grpc_error_handle error) {
   ContextList* head = static_cast<ContextList*>(arg);
   ContextList* to_be_freed;
   while (head != nullptr) {
@@ -57,9 +57,8 @@ void ContextList::Execute(void* arg, grpc_core::Timestamps* ts,
   }
 }
 
-void grpc_http2_set_write_timestamps_callback(void (*fn)(void*,
-                                                         grpc_core::Timestamps*,
-                                                         grpc_error* error)) {
+void grpc_http2_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error)) {
   write_timestamps_callback_g = fn;
 }
 
index 5b9d2ab..54ec87c 100644 (file)
@@ -36,7 +36,8 @@ class ContextList {
   /* Executes a function \a fn with each context in the list and \a ts. It also
    * frees up the entire list after this operation. It is intended as a callback
    * and hence does not take a ref on \a error */
-  static void Execute(void* arg, grpc_core::Timestamps* ts, grpc_error* error);
+  static void Execute(void* arg, grpc_core::Timestamps* ts,
+                      grpc_error_handle error);
 
  private:
   void* trace_context_ = nullptr;
@@ -44,9 +45,8 @@ class ContextList {
   size_t byte_offset_ = 0;
 };
 
-void grpc_http2_set_write_timestamps_callback(void (*fn)(void*,
-                                                         grpc_core::Timestamps*,
-                                                         grpc_error* error));
+void grpc_http2_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error));
 void grpc_http2_set_fn_get_copied_context(void* (*fn)(void*));
 } /* namespace grpc_core */
 
index 09bd7ab..5f5e551 100644 (file)
@@ -203,7 +203,7 @@ uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) {
   return 0;
 }
 
-grpc_error* TransportFlowControl::ValidateRecvData(
+grpc_error_handle TransportFlowControl::ValidateRecvData(
     int64_t incoming_frame_size) {
   if (incoming_frame_size > announced_window_) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -219,10 +219,10 @@ StreamFlowControl::StreamFlowControl(TransportFlowControl* tfc,
                                      const grpc_chttp2_stream* s)
     : tfc_(tfc), s_(s) {}
 
-grpc_error* StreamFlowControl::RecvData(int64_t incoming_frame_size) {
+grpc_error_handle StreamFlowControl::RecvData(int64_t incoming_frame_size) {
   FlowControlTrace trace("  data recv", tfc_, this);
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   error = tfc_->ValidateRecvData(incoming_frame_size);
   if (error != GRPC_ERROR_NONE) return error;
 
index 7e05358..e508896 100644 (file)
@@ -168,7 +168,7 @@ class TransportFlowControlBase {
 
   // Called to do bookkeeping when a stream owned by this transport receives
   // data from the wire. Also does error checking for frame size.
-  virtual grpc_error* RecvData(int64_t /* incoming_frame_size */) = 0;
+  virtual grpc_error_handle RecvData(int64_t /* incoming_frame_size */) = 0;
 
   // Called to do bookkeeping when we receive a WINDOW_UPDATE frame.
   virtual void RecvUpdate(uint32_t /* size */) = 0;
@@ -210,7 +210,7 @@ class TransportFlowControlDisabled final : public TransportFlowControlBase {
   FlowControlAction MakeAction() override { return FlowControlAction(); }
   FlowControlAction PeriodicUpdate() override { return FlowControlAction(); }
   void StreamSentData(int64_t /* size */) override {}
-  grpc_error* RecvData(int64_t /* incoming_frame_size */) override {
+  grpc_error_handle RecvData(int64_t /* incoming_frame_size */) override {
     return GRPC_ERROR_NONE;
   }
   void RecvUpdate(uint32_t /* size */) override {}
@@ -246,14 +246,14 @@ class TransportFlowControl final : public TransportFlowControlBase {
 
   void StreamSentData(int64_t size) override { remote_window_ -= size; }
 
-  grpc_error* ValidateRecvData(int64_t incoming_frame_size);
+  grpc_error_handle ValidateRecvData(int64_t incoming_frame_size);
   void CommitRecvData(int64_t incoming_frame_size) {
     announced_window_ -= incoming_frame_size;
   }
 
-  grpc_error* RecvData(int64_t incoming_frame_size) override {
+  grpc_error_handle RecvData(int64_t incoming_frame_size) override {
     FlowControlTrace trace("  data recv", this, nullptr);
-    grpc_error* error = ValidateRecvData(incoming_frame_size);
+    grpc_error_handle error = ValidateRecvData(incoming_frame_size);
     if (error != GRPC_ERROR_NONE) return error;
     CommitRecvData(incoming_frame_size);
     return GRPC_ERROR_NONE;
@@ -352,7 +352,7 @@ class StreamFlowControlBase {
   virtual void SentData(int64_t /* outgoing_frame_size */) = 0;
 
   // Bookkeeping and error checking for when data is received by this stream.
-  virtual grpc_error* RecvData(int64_t /* incoming_frame_size */) = 0;
+  virtual grpc_error_handle RecvData(int64_t /* incoming_frame_size */) = 0;
 
   // Called to check if this stream needs to send a WINDOW_UPDATE frame.
   virtual uint32_t MaybeSendUpdate() = 0;
@@ -395,7 +395,7 @@ class StreamFlowControlDisabled : public StreamFlowControlBase {
   }
   FlowControlAction MakeAction() override { return FlowControlAction(); }
   void SentData(int64_t /* outgoing_frame_size */) override {}
-  grpc_error* RecvData(int64_t /* incoming_frame_size */) override {
+  grpc_error_handle RecvData(int64_t /* incoming_frame_size */) override {
     return GRPC_ERROR_NONE;
   }
   uint32_t MaybeSendUpdate() override { return 0; }
@@ -427,7 +427,7 @@ class StreamFlowControl final : public StreamFlowControlBase {
   }
 
   // we have received data from the wire
-  grpc_error* RecvData(int64_t incoming_frame_size) override;
+  grpc_error_handle RecvData(int64_t incoming_frame_size) override;
 
   // returns an announce if we should send a stream update to our peer, else
   // returns zero
index ccb28bb..745f32a 100644 (file)
@@ -41,7 +41,7 @@ grpc_chttp2_data_parser::~grpc_chttp2_data_parser() {
   GRPC_ERROR_UNREF(error);
 }
 
-grpc_error* grpc_chttp2_data_parser_begin_frame(
+grpc_error_handle grpc_chttp2_data_parser_begin_frame(
     grpc_chttp2_data_parser* /*parser*/, uint8_t flags, uint32_t stream_id,
     grpc_chttp2_stream* s) {
   if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
@@ -89,11 +89,11 @@ void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer* inbuf,
   stats->data_bytes += write_bytes;
 }
 
-grpc_error* grpc_deframe_unprocessed_incoming_frames(
+grpc_error_handle grpc_deframe_unprocessed_incoming_frames(
     grpc_chttp2_data_parser* p, grpc_chttp2_stream* s,
     grpc_slice_buffer* slices, grpc_slice* slice_out,
     grpc_core::OrphanablePtr<grpc_core::ByteStream>* stream_out) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_chttp2_transport* t = s->t;
 
   while (slices->count > 0) {
@@ -275,11 +275,11 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_data_parser_parse(void* /*parser*/,
-                                          grpc_chttp2_transport* t,
-                                          grpc_chttp2_stream* s,
-                                          const grpc_slice& slice,
-                                          int is_last) {
+grpc_error_handle grpc_chttp2_data_parser_parse(void* /*parser*/,
+                                                grpc_chttp2_transport* t,
+                                                grpc_chttp2_stream* s,
+                                                const grpc_slice& slice,
+                                                int is_last) {
   if (!s->pending_byte_stream) {
     grpc_slice_ref_internal(slice);
     grpc_slice_buffer_add(&s->frame_storage, slice);
index ec38900..5aa4a3e 100644 (file)
@@ -50,31 +50,31 @@ struct grpc_chttp2_data_parser {
   grpc_chttp2_stream_state state = GRPC_CHTTP2_DATA_FH_0;
   uint8_t frame_type = 0;
   uint32_t frame_size = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   bool is_frame_compressed = false;
   grpc_core::Chttp2IncomingByteStream* parsing_frame = nullptr;
 };
 
 /* start processing a new data frame */
-grpc_error* grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser* parser,
-                                                uint8_t flags,
-                                                uint32_t stream_id,
-                                                grpc_chttp2_stream* s);
+grpc_error_handle grpc_chttp2_data_parser_begin_frame(
+    grpc_chttp2_data_parser* parser, uint8_t flags, uint32_t stream_id,
+    grpc_chttp2_stream* s);
 
 /* handle a slice of a data frame - is_last indicates the last slice of a
    frame */
-grpc_error* grpc_chttp2_data_parser_parse(void* parser,
-                                          grpc_chttp2_transport* t,
-                                          grpc_chttp2_stream* s,
-                                          const grpc_slice& slice, int is_last);
+grpc_error_handle grpc_chttp2_data_parser_parse(void* parser,
+                                                grpc_chttp2_transport* t,
+                                                grpc_chttp2_stream* s,
+                                                const grpc_slice& slice,
+                                                int is_last);
 
 void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer* inbuf,
                              uint32_t write_bytes, int is_eof,
                              grpc_transport_one_way_stats* stats,
                              grpc_slice_buffer* outbuf);
 
-grpc_error* grpc_deframe_unprocessed_incoming_frames(
+grpc_error_handle grpc_deframe_unprocessed_incoming_frames(
     grpc_chttp2_data_parser* p, grpc_chttp2_stream* s,
     grpc_slice_buffer* slices, grpc_slice* slice_out,
     grpc_core::OrphanablePtr<grpc_core::ByteStream>* stream_out);
index 3831b80..a139bea 100644 (file)
@@ -36,9 +36,8 @@ void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser* p) {
   gpr_free(p->debug_data);
 }
 
-grpc_error* grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser* p,
-                                                  uint32_t length,
-                                                  uint8_t /*flags*/) {
+grpc_error_handle grpc_chttp2_goaway_parser_begin_frame(
+    grpc_chttp2_goaway_parser* p, uint32_t length, uint8_t /*flags*/) {
   if (length < 8) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
         absl::StrFormat("goaway frame too short (%d bytes)", length).c_str());
@@ -52,11 +51,11 @@ grpc_error* grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser* p,
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_goaway_parser_parse(void* parser,
-                                            grpc_chttp2_transport* t,
-                                            grpc_chttp2_stream* /*s*/,
-                                            const grpc_slice& slice,
-                                            int is_last) {
+grpc_error_handle grpc_chttp2_goaway_parser_parse(void* parser,
+                                                  grpc_chttp2_transport* t,
+                                                  grpc_chttp2_stream* /*s*/,
+                                                  const grpc_slice& slice,
+                                                  int is_last) {
   const uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
index df6274d..674f742 100644 (file)
@@ -47,13 +47,13 @@ struct grpc_chttp2_goaway_parser {
 };
 void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser* p);
 void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser* p);
-grpc_error* grpc_chttp2_goaway_parser_begin_frame(
+grpc_error_handle grpc_chttp2_goaway_parser_begin_frame(
     grpc_chttp2_goaway_parser* parser, uint32_t length, uint8_t flags);
-grpc_error* grpc_chttp2_goaway_parser_parse(void* parser,
-                                            grpc_chttp2_transport* t,
-                                            grpc_chttp2_stream* s,
-                                            const grpc_slice& slice,
-                                            int is_last);
+grpc_error_handle grpc_chttp2_goaway_parser_parse(void* parser,
+                                                  grpc_chttp2_transport* t,
+                                                  grpc_chttp2_stream* s,
+                                                  const grpc_slice& slice,
+                                                  int is_last);
 
 void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
                                const grpc_slice& debug_data,
index 9841232..9da4a72 100644 (file)
@@ -55,9 +55,8 @@ grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) {
   return slice;
 }
 
-grpc_error* grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser* parser,
-                                                uint32_t length,
-                                                uint8_t flags) {
+grpc_error_handle grpc_chttp2_ping_parser_begin_frame(
+    grpc_chttp2_ping_parser* parser, uint32_t length, uint8_t flags) {
   if (flags & 0xfe || length != 8) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
         absl::StrFormat("invalid ping: length=%d, flags=%02x", length, flags)
@@ -69,11 +68,11 @@ grpc_error* grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser* parser,
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_ping_parser_parse(void* parser,
-                                          grpc_chttp2_transport* t,
-                                          grpc_chttp2_stream* /*s*/,
-                                          const grpc_slice& slice,
-                                          int is_last) {
+grpc_error_handle grpc_chttp2_ping_parser_parse(void* parser,
+                                                grpc_chttp2_transport* t,
+                                                grpc_chttp2_stream* /*s*/,
+                                                const grpc_slice& slice,
+                                                int is_last) {
   const uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
index e356bf4..6b5318e 100644 (file)
@@ -31,12 +31,13 @@ struct grpc_chttp2_ping_parser {
 };
 grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes);
 
-grpc_error* grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser* parser,
-                                                uint32_t length, uint8_t flags);
-grpc_error* grpc_chttp2_ping_parser_parse(void* parser,
-                                          grpc_chttp2_transport* t,
-                                          grpc_chttp2_stream* s,
-                                          const grpc_slice& slice, int is_last);
+grpc_error_handle grpc_chttp2_ping_parser_begin_frame(
+    grpc_chttp2_ping_parser* parser, uint32_t length, uint8_t flags);
+grpc_error_handle grpc_chttp2_ping_parser_parse(void* parser,
+                                                grpc_chttp2_transport* t,
+                                                grpc_chttp2_stream* s,
+                                                const grpc_slice& slice,
+                                                int is_last);
 
 /* Test-only function for disabling ping ack */
 void grpc_set_disable_ping_ack(bool disable_ping_ack);
index bcfcb17..03a7c61 100644 (file)
@@ -68,7 +68,7 @@ void grpc_chttp2_add_rst_stream_to_next_write(
                         grpc_chttp2_rst_stream_create(id, code, stats));
 }
 
-grpc_error* grpc_chttp2_rst_stream_parser_begin_frame(
+grpc_error_handle grpc_chttp2_rst_stream_parser_begin_frame(
     grpc_chttp2_rst_stream_parser* parser, uint32_t length, uint8_t flags) {
   if (length != 4) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -80,11 +80,11 @@ grpc_error* grpc_chttp2_rst_stream_parser_begin_frame(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_rst_stream_parser_parse(void* parser,
-                                                grpc_chttp2_transport* t,
-                                                grpc_chttp2_stream* s,
-                                                const grpc_slice& slice,
-                                                int is_last) {
+grpc_error_handle grpc_chttp2_rst_stream_parser_parse(void* parser,
+                                                      grpc_chttp2_transport* t,
+                                                      grpc_chttp2_stream* s,
+                                                      const grpc_slice& slice,
+                                                      int is_last) {
   const uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
@@ -104,7 +104,7 @@ grpc_error* grpc_chttp2_rst_stream_parser_parse(void* parser,
                       ((static_cast<uint32_t>(p->reason_bytes[1])) << 16) |
                       ((static_cast<uint32_t>(p->reason_bytes[2])) << 8) |
                       ((static_cast<uint32_t>(p->reason_bytes[3])));
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     if (reason != GRPC_HTTP2_NO_ERROR || s->metadata_buffer[1].size == 0) {
       error = grpc_error_set_int(
           grpc_error_set_str(
index e324ee2..865e74d 100644 (file)
@@ -39,12 +39,12 @@ void grpc_chttp2_add_rst_stream_to_next_write(
     grpc_chttp2_transport* t, uint32_t id, uint32_t code,
     grpc_transport_one_way_stats* stats);
 
-grpc_error* grpc_chttp2_rst_stream_parser_begin_frame(
+grpc_error_handle grpc_chttp2_rst_stream_parser_begin_frame(
     grpc_chttp2_rst_stream_parser* parser, uint32_t length, uint8_t flags);
-grpc_error* grpc_chttp2_rst_stream_parser_parse(void* parser,
-                                                grpc_chttp2_transport* t,
-                                                grpc_chttp2_stream* s,
-                                                const grpc_slice& slice,
-                                                int is_last);
+grpc_error_handle grpc_chttp2_rst_stream_parser_parse(void* parser,
+                                                      grpc_chttp2_transport* t,
+                                                      grpc_chttp2_stream* s,
+                                                      const grpc_slice& slice,
+                                                      int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H */
index 7dbfc69..576f815 100644 (file)
@@ -84,7 +84,7 @@ grpc_slice grpc_chttp2_settings_ack_create(void) {
   return output;
 }
 
-grpc_error* grpc_chttp2_settings_parser_begin_frame(
+grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
     grpc_chttp2_settings_parser* parser, uint32_t length, uint8_t flags,
     uint32_t* settings) {
   parser->target_settings = settings;
@@ -110,10 +110,11 @@ grpc_error* grpc_chttp2_settings_parser_begin_frame(
   }
 }
 
-grpc_error* grpc_chttp2_settings_parser_parse(void* p, grpc_chttp2_transport* t,
-                                              grpc_chttp2_stream* /*s*/,
-                                              const grpc_slice& slice,
-                                              int is_last) {
+grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
+                                                    grpc_chttp2_transport* t,
+                                                    grpc_chttp2_stream* /*s*/,
+                                                    const grpc_slice& slice,
+                                                    int is_last) {
   grpc_chttp2_settings_parser* parser =
       static_cast<grpc_chttp2_settings_parser*>(p);
   const uint8_t* cur = GRPC_SLICE_START_PTR(slice);
index 147d5ea..7268277 100644 (file)
@@ -49,13 +49,13 @@ grpc_slice grpc_chttp2_settings_create(uint32_t* old_settings,
 /* Create an ack settings frame */
 grpc_slice grpc_chttp2_settings_ack_create(void);
 
-grpc_error* grpc_chttp2_settings_parser_begin_frame(
+grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
     grpc_chttp2_settings_parser* parser, uint32_t length, uint8_t flags,
     uint32_t* settings);
-grpc_error* grpc_chttp2_settings_parser_parse(void* parser,
-                                              grpc_chttp2_transport* t,
-                                              grpc_chttp2_stream* s,
-                                              const grpc_slice& slice,
-                                              int is_last);
+grpc_error_handle grpc_chttp2_settings_parser_parse(void* parser,
+                                                    grpc_chttp2_transport* t,
+                                                    grpc_chttp2_stream* s,
+                                                    const grpc_slice& slice,
+                                                    int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H */
index 943ea17..37e69ff 100644 (file)
@@ -53,7 +53,7 @@ grpc_slice grpc_chttp2_window_update_create(
   return slice;
 }
 
-grpc_error* grpc_chttp2_window_update_parser_begin_frame(
+grpc_error_handle grpc_chttp2_window_update_parser_begin_frame(
     grpc_chttp2_window_update_parser* parser, uint32_t length, uint8_t flags) {
   if (flags || length != 4) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -66,11 +66,9 @@ grpc_error* grpc_chttp2_window_update_parser_begin_frame(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_window_update_parser_parse(void* parser,
-                                                   grpc_chttp2_transport* t,
-                                                   grpc_chttp2_stream* s,
-                                                   const grpc_slice& slice,
-                                                   int is_last) {
+grpc_error_handle grpc_chttp2_window_update_parser_parse(
+    void* parser, grpc_chttp2_transport* t, grpc_chttp2_stream* s,
+    const grpc_slice& slice, int is_last) {
   const uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
index 340445d..5a07b9e 100644 (file)
@@ -33,12 +33,10 @@ struct grpc_chttp2_window_update_parser {
 grpc_slice grpc_chttp2_window_update_create(
     uint32_t id, uint32_t window_delta, grpc_transport_one_way_stats* stats);
 
-grpc_error* grpc_chttp2_window_update_parser_begin_frame(
+grpc_error_handle grpc_chttp2_window_update_parser_begin_frame(
     grpc_chttp2_window_update_parser* parser, uint32_t length, uint8_t flags);
-grpc_error* grpc_chttp2_window_update_parser_parse(void* parser,
-                                                   grpc_chttp2_transport* t,
-                                                   grpc_chttp2_stream* s,
-                                                   const grpc_slice& slice,
-                                                   int is_last);
+grpc_error_handle grpc_chttp2_window_update_parser_parse(
+    void* parser, grpc_chttp2_transport* t, grpc_chttp2_stream* s,
+    const grpc_slice& slice, int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H */
index 668c2cb..99c308f 100644 (file)
@@ -67,71 +67,82 @@ typedef enum {
    a set of indirect jumps, and so not waste stack space. */
 
 /* forward declarations for parsing states */
-static grpc_error* parse_begin(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                               const uint8_t* end);
-static grpc_error* parse_error(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                               const uint8_t* end, grpc_error* error);
-static grpc_error* still_parse_error(grpc_chttp2_hpack_parser* p,
+static grpc_error_handle parse_begin(grpc_chttp2_hpack_parser* p,
                                      const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_illegal_op(grpc_chttp2_hpack_parser* p,
-                                    const uint8_t* cur, const uint8_t* end);
-
-static grpc_error* parse_string_prefix(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_key_string(grpc_chttp2_hpack_parser* p,
-                                    const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_value_string_with_indexed_key(
+static grpc_error_handle parse_error(grpc_chttp2_hpack_parser* p,
+                                     const uint8_t* cur, const uint8_t* end,
+                                     grpc_error_handle error);
+static grpc_error_handle still_parse_error(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end);
+static grpc_error_handle parse_illegal_op(grpc_chttp2_hpack_parser* p,
+                                          const uint8_t* cur,
+                                          const uint8_t* end);
+
+static grpc_error_handle parse_string_prefix(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_key_string(grpc_chttp2_hpack_parser* p,
+                                          const uint8_t* cur,
+                                          const uint8_t* end);
+static grpc_error_handle parse_value_string_with_indexed_key(
     grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_value_string_with_literal_key(
+static grpc_error_handle parse_value_string_with_literal_key(
     grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end);
 
-static grpc_error* parse_value0(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value1(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value2(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value3(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value4(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value5up(grpc_chttp2_hpack_parser* p,
-                                  const uint8_t* cur, const uint8_t* end);
-
-static grpc_error* parse_indexed_field(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_indexed_field_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_incidx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_lithdr_incidx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_notidx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_lithdr_notidx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_max_tbl_size(grpc_chttp2_hpack_parser* p,
+static grpc_error_handle parse_value0(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end);
+static grpc_error_handle parse_value1(grpc_chttp2_hpack_parser* p,
                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_max_tbl_size_x(grpc_chttp2_hpack_parser* p,
+static grpc_error_handle parse_value2(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end);
+static grpc_error_handle parse_value3(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end);
+static grpc_error_handle parse_value4(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end);
+static grpc_error_handle parse_value5up(grpc_chttp2_hpack_parser* p,
                                         const uint8_t* cur, const uint8_t* end);
 
+static grpc_error_handle parse_indexed_field(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_indexed_field_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_incidx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_lithdr_incidx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_notidx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_lithdr_notidx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_max_tbl_size(grpc_chttp2_hpack_parser* p,
+                                            const uint8_t* cur,
+                                            const uint8_t* end);
+static grpc_error_handle parse_max_tbl_size_x(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end);
+
 /* we translate the first byte of a hpack field into one of these decoding
    cases, then use a lookup table to jump directly to the appropriate parser.
 
@@ -647,14 +658,14 @@ static void GPR_ATTRIBUTE_NOINLINE on_hdr_log(grpc_mdelem md) {
 
 /* emission helpers */
 template <bool do_add>
-static grpc_error* on_hdr(grpc_chttp2_hpack_parser* p, grpc_mdelem md) {
+static grpc_error_handle on_hdr(grpc_chttp2_hpack_parser* p, grpc_mdelem md) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_chttp2_hpack_parser)) {
     on_hdr_log(md);
   }
   if (do_add) {
     GPR_DEBUG_ASSERT(GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_INTERNED ||
                      GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC);
-    grpc_error* err = grpc_chttp2_hptbl_add(&p->table, md);
+    grpc_error_handle err = grpc_chttp2_hptbl_add(&p->table, md);
     if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) return err;
   }
   return p->on_header(p->on_header_user_data, md);
@@ -693,16 +704,16 @@ static grpc_core::ManagedMemorySlice take_string_intern(
 }
 
 /* jump to the next state */
-static grpc_error* parse_next(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                              const uint8_t* end) {
+static grpc_error_handle parse_next(grpc_chttp2_hpack_parser* p,
+                                    const uint8_t* cur, const uint8_t* end) {
   p->state = *p->next_state++;
   return p->state(p, cur, end);
 }
 
 /* begin parsing a header: all functionality is encoded into lookup tables
    above */
-static grpc_error* parse_begin(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                               const uint8_t* end) {
+static grpc_error_handle parse_begin(grpc_chttp2_hpack_parser* p,
+                                     const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_begin;
     return GRPC_ERROR_NONE;
@@ -712,8 +723,9 @@ static grpc_error* parse_begin(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
 }
 
 /* stream dependency and prioritization data: we just skip it */
-static grpc_error* parse_stream_weight(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_weight(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_weight;
     return GRPC_ERROR_NONE;
@@ -722,8 +734,9 @@ static grpc_error* parse_stream_weight(grpc_chttp2_hpack_parser* p,
   return p->after_prioritization(p, cur + 1, end);
 }
 
-static grpc_error* parse_stream_dep3(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_dep3(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_dep3;
     return GRPC_ERROR_NONE;
@@ -732,8 +745,9 @@ static grpc_error* parse_stream_dep3(grpc_chttp2_hpack_parser* p,
   return parse_stream_weight(p, cur + 1, end);
 }
 
-static grpc_error* parse_stream_dep2(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_dep2(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_dep2;
     return GRPC_ERROR_NONE;
@@ -742,8 +756,9 @@ static grpc_error* parse_stream_dep2(grpc_chttp2_hpack_parser* p,
   return parse_stream_dep3(p, cur + 1, end);
 }
 
-static grpc_error* parse_stream_dep1(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_dep1(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_dep1;
     return GRPC_ERROR_NONE;
@@ -752,8 +767,9 @@ static grpc_error* parse_stream_dep1(grpc_chttp2_hpack_parser* p,
   return parse_stream_dep2(p, cur + 1, end);
 }
 
-static grpc_error* parse_stream_dep0(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_dep0(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_dep0;
     return GRPC_ERROR_NONE;
@@ -762,7 +778,7 @@ static grpc_error* parse_stream_dep0(grpc_chttp2_hpack_parser* p,
   return parse_stream_dep1(p, cur + 1, end);
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
 on_invalid_hpack_idx(grpc_chttp2_hpack_parser* p) {
   return grpc_error_set_int(
       grpc_error_set_int(
@@ -772,22 +788,23 @@ on_invalid_hpack_idx(grpc_chttp2_hpack_parser* p) {
 }
 
 /* emit an indexed field; jumps to begin the next field on completion */
-static grpc_error* finish_indexed_field(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle finish_indexed_field(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   grpc_mdelem md = grpc_chttp2_hptbl_lookup<true>(&p->table, p->index);
   if (GPR_UNLIKELY(GRPC_MDISNULL(md))) {
     return on_invalid_hpack_idx(p);
   }
   GRPC_STATS_INC_HPACK_RECV_INDEXED();
-  grpc_error* err = on_hdr<false>(p, md);
+  grpc_error_handle err = on_hdr<false>(p, md);
   if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) return err;
   return parse_begin(p, cur, end);
 }
 
 /* parse an indexed field with index < 127 */
-static grpc_error* parse_indexed_field(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_indexed_field(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   p->dynamic_table_update_allowed = 0;
   p->index = (*cur) & 0x7f;
   p->md_for_index.payload = 0; /* Invalidate cached md when index changes. */
@@ -795,9 +812,9 @@ static grpc_error* parse_indexed_field(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse an indexed field with index >= 127 */
-static grpc_error* parse_indexed_field_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_indexed_field_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       finish_indexed_field};
   p->dynamic_table_update_allowed = 0;
@@ -830,12 +847,12 @@ static const grpc_core::ManagedMemorySlice& get_indexed_key(grpc_mdelem md) {
 }
 
 /* finish a literal header with incremental indexing */
-static grpc_error* finish_lithdr_incidx(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle finish_lithdr_incidx(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_INCIDX();
   grpc_mdelem md = get_precomputed_md_for_idx(p);
-  grpc_error* err = on_hdr<true>(
+  grpc_error_handle err = on_hdr<true>(
       p, grpc_mdelem_from_slices(get_indexed_key(md),
                                  take_string_intern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -843,11 +860,11 @@ static grpc_error* finish_lithdr_incidx(grpc_chttp2_hpack_parser* p,
 }
 
 /* finish a literal header with incremental indexing with no index */
-static grpc_error* finish_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
-                                          const uint8_t* cur,
-                                          const uint8_t* end) {
+static grpc_error_handle finish_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
+                                                const uint8_t* cur,
+                                                const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_INCIDX_V();
-  grpc_error* err = on_hdr<true>(
+  grpc_error_handle err = on_hdr<true>(
       p, grpc_mdelem_from_slices(take_string_intern(p, &p->key),
                                  take_string_intern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -855,8 +872,9 @@ static grpc_error* finish_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a literal header with incremental indexing; index < 63 */
-static grpc_error* parse_lithdr_incidx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_lithdr_incidx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_incidx};
   p->dynamic_table_update_allowed = 0;
@@ -867,9 +885,9 @@ static grpc_error* parse_lithdr_incidx(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a literal header with incremental indexing; index >= 63 */
-static grpc_error* parse_lithdr_incidx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_incidx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_string_prefix, parse_value_string_with_indexed_key,
       finish_lithdr_incidx};
@@ -882,9 +900,9 @@ static grpc_error* parse_lithdr_incidx_x(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a literal header with incremental indexing; index = 0 */
-static grpc_error* parse_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_key_string, parse_string_prefix,
       parse_value_string_with_literal_key, finish_lithdr_incidx_v};
@@ -894,12 +912,12 @@ static grpc_error* parse_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
 }
 
 /* finish a literal header without incremental indexing */
-static grpc_error* finish_lithdr_notidx(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle finish_lithdr_notidx(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_NOTIDX();
   grpc_mdelem md = get_precomputed_md_for_idx(p);
-  grpc_error* err = on_hdr<false>(
+  grpc_error_handle err = on_hdr<false>(
       p, grpc_mdelem_from_slices(get_indexed_key(md),
                                  take_string_extern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -907,11 +925,11 @@ static grpc_error* finish_lithdr_notidx(grpc_chttp2_hpack_parser* p,
 }
 
 /* finish a literal header without incremental indexing with index = 0 */
-static grpc_error* finish_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
-                                          const uint8_t* cur,
-                                          const uint8_t* end) {
+static grpc_error_handle finish_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
+                                                const uint8_t* cur,
+                                                const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_NOTIDX_V();
-  grpc_error* err = on_hdr<false>(
+  grpc_error_handle err = on_hdr<false>(
       p, grpc_mdelem_from_slices(take_string_intern(p, &p->key),
                                  take_string_extern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -919,8 +937,9 @@ static grpc_error* finish_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a literal header without incremental indexing; index < 15 */
-static grpc_error* parse_lithdr_notidx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_lithdr_notidx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_notidx};
   p->dynamic_table_update_allowed = 0;
@@ -931,9 +950,9 @@ static grpc_error* parse_lithdr_notidx(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a literal header without incremental indexing; index >= 15 */
-static grpc_error* parse_lithdr_notidx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_notidx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_string_prefix, parse_value_string_with_indexed_key,
       finish_lithdr_notidx};
@@ -946,9 +965,9 @@ static grpc_error* parse_lithdr_notidx_x(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a literal header without incremental indexing; index == 0 */
-static grpc_error* parse_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_key_string, parse_string_prefix,
       parse_value_string_with_literal_key, finish_lithdr_notidx_v};
@@ -958,12 +977,12 @@ static grpc_error* parse_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
 }
 
 /* finish a literal header that is never indexed */
-static grpc_error* finish_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle finish_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_NVRIDX();
   grpc_mdelem md = get_precomputed_md_for_idx(p);
-  grpc_error* err = on_hdr<false>(
+  grpc_error_handle err = on_hdr<false>(
       p, grpc_mdelem_from_slices(get_indexed_key(md),
                                  take_string_extern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -971,11 +990,11 @@ static grpc_error* finish_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
 }
 
 /* finish a literal header that is never indexed with an extra value */
-static grpc_error* finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
-                                          const uint8_t* cur,
-                                          const uint8_t* end) {
+static grpc_error_handle finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
+                                                const uint8_t* cur,
+                                                const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_NVRIDX_V();
-  grpc_error* err = on_hdr<false>(
+  grpc_error_handle err = on_hdr<false>(
       p, grpc_mdelem_from_slices(take_string_intern(p, &p->key),
                                  take_string_extern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -983,8 +1002,9 @@ static grpc_error* finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a literal header that is never indexed; index < 15 */
-static grpc_error* parse_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_nvridx};
   p->dynamic_table_update_allowed = 0;
@@ -995,9 +1015,9 @@ static grpc_error* parse_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a literal header that is never indexed; index >= 15 */
-static grpc_error* parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_string_prefix, parse_value_string_with_indexed_key,
       finish_lithdr_nvridx};
@@ -1010,9 +1030,9 @@ static grpc_error* parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a literal header that is never indexed; index == 0 */
-static grpc_error* parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_key_string, parse_string_prefix,
       parse_value_string_with_literal_key, finish_lithdr_nvridx_v};
@@ -1022,20 +1042,22 @@ static grpc_error* parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
 }
 
 /* finish parsing a max table size change */
-static grpc_error* finish_max_tbl_size(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle finish_max_tbl_size(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_chttp2_hpack_parser)) {
     gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
   }
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index);
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
   return parse_begin(p, cur, end);
 }
 
 /* parse a max table size change, max size < 15 */
-static grpc_error* parse_max_tbl_size(grpc_chttp2_hpack_parser* p,
-                                      const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_max_tbl_size(grpc_chttp2_hpack_parser* p,
+                                            const uint8_t* cur,
+                                            const uint8_t* end) {
   if (p->dynamic_table_update_allowed == 0) {
     return parse_error(
         p, cur, end,
@@ -1049,9 +1071,9 @@ static grpc_error* parse_max_tbl_size(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a max table size change, max size >= 15 */
-static grpc_error* parse_max_tbl_size_x(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle parse_max_tbl_size_x(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       finish_max_tbl_size};
   if (p->dynamic_table_update_allowed == 0) {
@@ -1069,9 +1091,10 @@ static grpc_error* parse_max_tbl_size_x(grpc_chttp2_hpack_parser* p,
 }
 
 /* a parse error: jam the parse state into parse_error, and return error */
-static grpc_error* parse_error(grpc_chttp2_hpack_parser* p,
-                               const uint8_t* /*cur*/, const uint8_t* /*end*/,
-                               grpc_error* err) {
+static grpc_error_handle parse_error(grpc_chttp2_hpack_parser* p,
+                                     const uint8_t* /*cur*/,
+                                     const uint8_t* /*end*/,
+                                     grpc_error_handle err) {
   GPR_ASSERT(err != GRPC_ERROR_NONE);
   if (p->last_error == GRPC_ERROR_NONE) {
     p->last_error = GRPC_ERROR_REF(err);
@@ -1080,24 +1103,25 @@ static grpc_error* parse_error(grpc_chttp2_hpack_parser* p,
   return err;
 }
 
-static grpc_error* still_parse_error(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* /*cur*/,
-                                     const uint8_t* /*end*/) {
+static grpc_error_handle still_parse_error(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* /*cur*/,
+                                           const uint8_t* /*end*/) {
   return GRPC_ERROR_REF(p->last_error);
 }
 
-static grpc_error* parse_illegal_op(grpc_chttp2_hpack_parser* p,
-                                    const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_illegal_op(grpc_chttp2_hpack_parser* p,
+                                          const uint8_t* cur,
+                                          const uint8_t* end) {
   GPR_ASSERT(cur != end);
-  grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrCat("Illegal hpack op code ", *cur).c_str());
   return parse_error(p, cur, end, err);
 }
 
 /* parse the 1st byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error* parse_value0(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value0(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_value0;
     return GRPC_ERROR_NONE;
@@ -1114,8 +1138,8 @@ static grpc_error* parse_value0(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
 
 /* parse the 2nd byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error* parse_value1(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value1(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_value1;
     return GRPC_ERROR_NONE;
@@ -1132,8 +1156,8 @@ static grpc_error* parse_value1(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
 
 /* parse the 3rd byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error* parse_value2(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value2(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_value2;
     return GRPC_ERROR_NONE;
@@ -1150,8 +1174,8 @@ static grpc_error* parse_value2(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
 
 /* parse the 4th byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error* parse_value3(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value3(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_value3;
     return GRPC_ERROR_NONE;
@@ -1168,8 +1192,8 @@ static grpc_error* parse_value3(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
 
 /* parse the 5th byte of a varint into p->parsing.value
    depending on the byte, we may overflow, and care must be taken */
-static grpc_error* parse_value4(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value4(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   uint8_t c;
   uint32_t cur_value;
   uint32_t add_value;
@@ -1199,7 +1223,7 @@ static grpc_error* parse_value4(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
   }
 
 error:
-  grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrFormat(
           "integer overflow in hpack integer decoding: have 0x%08x, "
           "got byte 0x%02x on byte 5",
@@ -1211,8 +1235,9 @@ error:
 /* parse any trailing bytes in a varint: it's possible to append an arbitrary
    number of 0x80's and not affect the value - a zero will terminate - and
    anything else will overflow */
-static grpc_error* parse_value5up(grpc_chttp2_hpack_parser* p,
-                                  const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_value5up(grpc_chttp2_hpack_parser* p,
+                                        const uint8_t* cur,
+                                        const uint8_t* end) {
   while (cur != end && *cur == 0x80) {
     ++cur;
   }
@@ -1226,7 +1251,7 @@ static grpc_error* parse_value5up(grpc_chttp2_hpack_parser* p,
     return parse_next(p, cur + 1, end);
   }
 
-  grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrFormat(
           "integer overflow in hpack integer decoding: have 0x%08x, "
           "got byte 0x%02x sometime after byte 5",
@@ -1236,8 +1261,9 @@ static grpc_error* parse_value5up(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a string prefix */
-static grpc_error* parse_string_prefix(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_string_prefix(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   if (cur == end) {
     p->state = parse_string_prefix;
     return GRPC_ERROR_NONE;
@@ -1269,8 +1295,8 @@ static void append_bytes(grpc_chttp2_hpack_parser_string* str,
   str->data.copied.length += static_cast<uint32_t>(length);
 }
 
-static grpc_error* append_string(grpc_chttp2_hpack_parser* p,
-                                 const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle append_string(grpc_chttp2_hpack_parser* p,
+                                       const uint8_t* cur, const uint8_t* end) {
   grpc_chttp2_hpack_parser_string* str = p->parsing.str;
   uint32_t bits;
   uint8_t decoded[3];
@@ -1372,8 +1398,8 @@ static grpc_error* append_string(grpc_chttp2_hpack_parser* p,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here")));
 }
 
-static grpc_error* finish_str(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                              const uint8_t* end) {
+static grpc_error_handle finish_str(grpc_chttp2_hpack_parser* p,
+                                    const uint8_t* cur, const uint8_t* end) {
   uint8_t decoded[2];
   uint32_t bits;
   grpc_chttp2_hpack_parser_string* str = p->parsing.str;
@@ -1391,7 +1417,7 @@ static grpc_error* finish_str(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
     case B64_BYTE2:
       bits = p->base64_buffer;
       if (bits & 0xffff) {
-        grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrFormat("trailing bits in base64 encoding: 0x%04x",
                             bits & 0xffff)
                 .c_str());
@@ -1403,7 +1429,7 @@ static grpc_error* finish_str(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
     case B64_BYTE3:
       bits = p->base64_buffer;
       if (bits & 0xff) {
-        grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrFormat("trailing bits in base64 encoding: 0x%02x",
                             bits & 0xff)
                 .c_str());
@@ -1418,13 +1444,14 @@ static grpc_error* finish_str(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
 }
 
 /* decode a nibble from a huffman encoded stream */
-static grpc_error* huff_nibble(grpc_chttp2_hpack_parser* p, uint8_t nibble) {
+static grpc_error_handle huff_nibble(grpc_chttp2_hpack_parser* p,
+                                     uint8_t nibble) {
   int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble];
   int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
   if (emit != -1) {
     if (emit >= 0 && emit < 256) {
       uint8_t c = static_cast<uint8_t>(emit);
-      grpc_error* err = append_string(p, &c, (&c) + 1);
+      grpc_error_handle err = append_string(p, &c, (&c) + 1);
       if (err != GRPC_ERROR_NONE) return err;
     } else {
       assert(emit == 256);
@@ -1435,10 +1462,11 @@ static grpc_error* huff_nibble(grpc_chttp2_hpack_parser* p, uint8_t nibble) {
 }
 
 /* decode full bytes from a huffman encoded stream */
-static grpc_error* add_huff_bytes(grpc_chttp2_hpack_parser* p,
-                                  const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle add_huff_bytes(grpc_chttp2_hpack_parser* p,
+                                        const uint8_t* cur,
+                                        const uint8_t* end) {
   for (; cur != end; ++cur) {
-    grpc_error* err = huff_nibble(p, *cur >> 4);
+    grpc_error_handle err = huff_nibble(p, *cur >> 4);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
     err = huff_nibble(p, *cur & 0xf);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -1448,8 +1476,8 @@ static grpc_error* add_huff_bytes(grpc_chttp2_hpack_parser* p,
 
 /* decode some string bytes based on the current decoding mode
    (huffman or not) */
-static grpc_error* add_str_bytes(grpc_chttp2_hpack_parser* p,
-                                 const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle add_str_bytes(grpc_chttp2_hpack_parser* p,
+                                       const uint8_t* cur, const uint8_t* end) {
   if (p->huff) {
     return add_huff_bytes(p, cur, end);
   } else {
@@ -1458,18 +1486,18 @@ static grpc_error* add_str_bytes(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse a string - tries to do large chunks at a time */
-static grpc_error* parse_string(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_string(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   size_t remaining = p->strlen - p->strgot;
   size_t given = static_cast<size_t>(end - cur);
   if (remaining <= given) {
-    grpc_error* err = add_str_bytes(p, cur, cur + remaining);
+    grpc_error_handle err = add_str_bytes(p, cur, cur + remaining);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
     err = finish_str(p, cur + remaining, end);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
     return parse_next(p, cur + remaining, end);
   } else {
-    grpc_error* err = add_str_bytes(p, cur, cur + given);
+    grpc_error_handle err = add_str_bytes(p, cur, cur + given);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
     GPR_ASSERT(given <= UINT32_MAX - p->strgot);
     p->strgot += static_cast<uint32_t>(given);
@@ -1479,10 +1507,9 @@ static grpc_error* parse_string(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
 }
 
 /* begin parsing a string - performs setup, calls parse_string */
-static grpc_error* begin_parse_string(grpc_chttp2_hpack_parser* p,
-                                      const uint8_t* cur, const uint8_t* end,
-                                      uint8_t binary,
-                                      grpc_chttp2_hpack_parser_string* str) {
+static grpc_error_handle begin_parse_string(
+    grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end,
+    uint8_t binary, grpc_chttp2_hpack_parser_string* str) {
   if (!p->huff && binary == NOT_BINARY &&
       static_cast<uint32_t>(end - cur) >= p->strlen &&
       p->current_slice_refcount != nullptr) {
@@ -1518,8 +1545,9 @@ static grpc_error* begin_parse_string(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse the key string */
-static grpc_error* parse_key_string(grpc_chttp2_hpack_parser* p,
-                                    const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_key_string(grpc_chttp2_hpack_parser* p,
+                                          const uint8_t* cur,
+                                          const uint8_t* end) {
   return begin_parse_string(p, cur, end, NOT_BINARY, &p->key);
 }
 
@@ -1554,8 +1582,8 @@ static void set_precomputed_md_idx(grpc_chttp2_hpack_parser* p,
    is a binary indexed header during string parsing. We'll need to revisit this
    metadata when we're done parsing, so we cache the metadata for this index
    here using set_precomputed_md_idx(). */
-static grpc_error* is_binary_indexed_header(grpc_chttp2_hpack_parser* p,
-                                            bool* is) {
+static grpc_error_handle is_binary_indexed_header(grpc_chttp2_hpack_parser* p,
+                                                  bool* is) {
   grpc_mdelem elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   if (GPR_UNLIKELY(GRPC_MDISNULL(elem))) {
     return on_invalid_hpack_idx(p);
@@ -1574,29 +1602,30 @@ static grpc_error* is_binary_indexed_header(grpc_chttp2_hpack_parser* p,
 }
 
 /* parse the value string */
-static grpc_error* parse_value_string(grpc_chttp2_hpack_parser* p,
-                                      const uint8_t* cur, const uint8_t* end,
-                                      bool is_binary) {
+static grpc_error_handle parse_value_string(grpc_chttp2_hpack_parser* p,
+                                            const uint8_t* cur,
+                                            const uint8_t* end,
+                                            bool is_binary) {
   return begin_parse_string(p, cur, end, is_binary ? BINARY_BEGIN : NOT_BINARY,
                             &p->value);
 }
 
-static grpc_error* parse_value_string_with_indexed_key(
+static grpc_error_handle parse_value_string_with_indexed_key(
     grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end) {
   bool is_binary = false;
-  grpc_error* err = is_binary_indexed_header(p, &is_binary);
+  grpc_error_handle err = is_binary_indexed_header(p, &is_binary);
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
   return parse_value_string(p, cur, end, is_binary);
 }
 
-static grpc_error* parse_value_string_with_literal_key(
+static grpc_error_handle parse_value_string_with_literal_key(
     grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end) {
   return parse_value_string(p, cur, end, is_binary_literal_header(p));
 }
 
 /* "Uninitialized" header parser to save us a branch in on_hdr().  */
-static grpc_error* on_header_uninitialized(void* /*user_data*/,
-                                           grpc_mdelem md) {
+static grpc_error_handle on_header_uninitialized(void* /*user_data*/,
+                                                 grpc_mdelem md) {
   GRPC_MDELEM_UNREF(md);
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING("on_header callback not set");
 }
@@ -1645,15 +1674,15 @@ void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser* p) {
   gpr_free(p->value.data.copied.str);
 }
 
-grpc_error* grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser* p,
-                                           const grpc_slice& slice) {
+grpc_error_handle grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser* p,
+                                                 const grpc_slice& slice) {
 /* max number of bytes to parse at a time... limits call stack depth on
  * compilers without TCO */
 #define MAX_PARSE_LENGTH 1024
   p->current_slice_refcount = slice.refcount;
   const uint8_t* start = GRPC_SLICE_START_PTR(slice);
   const uint8_t* end = GRPC_SLICE_END_PTR(slice);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   while (start != end && error == GRPC_ERROR_NONE) {
     const uint8_t* target = start + GPR_MIN(MAX_PARSE_LENGTH, end - start);
     error = p->state(p, start, target);
@@ -1669,7 +1698,7 @@ static const maybe_complete_func_type maybe_complete_funcs[] = {
     grpc_chttp2_maybe_complete_recv_initial_metadata,
     grpc_chttp2_maybe_complete_recv_trailing_metadata};
 
-static void force_client_rst_stream(void* sp, grpc_error* /*error*/) {
+static void force_client_rst_stream(void* sp, grpc_error_handle /*error*/) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp);
   grpc_chttp2_transport* t = s->t;
   if (!s->write_closed) {
@@ -1699,18 +1728,18 @@ static void parse_stream_compression_md(grpc_chttp2_transport* /*t*/,
   }
 }
 
-grpc_error* grpc_chttp2_header_parser_parse(void* hpack_parser,
-                                            grpc_chttp2_transport* t,
-                                            grpc_chttp2_stream* s,
-                                            const grpc_slice& slice,
-                                            int is_last) {
+grpc_error_handle grpc_chttp2_header_parser_parse(void* hpack_parser,
+                                                  grpc_chttp2_transport* t,
+                                                  grpc_chttp2_stream* s,
+                                                  const grpc_slice& slice,
+                                                  int is_last) {
   GPR_TIMER_SCOPE("grpc_chttp2_header_parser_parse", 0);
   grpc_chttp2_hpack_parser* parser =
       static_cast<grpc_chttp2_hpack_parser*>(hpack_parser);
   if (s != nullptr) {
     s->stats.incoming.header_bytes += GRPC_SLICE_LENGTH(slice);
   }
-  grpc_error* error = grpc_chttp2_hpack_parser_parse(parser, slice);
+  grpc_error_handle error = grpc_chttp2_hpack_parser_parse(parser, slice);
   if (error != GRPC_ERROR_NONE) {
     return error;
   }
index 1b859c4..71aa194 100644 (file)
@@ -29,7 +29,7 @@
 
 typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
 
-typedef grpc_error* (*grpc_chttp2_hpack_parser_state)(
+typedef grpc_error_handle (*grpc_chttp2_hpack_parser_state)(
     grpc_chttp2_hpack_parser* p, const uint8_t* beg, const uint8_t* end);
 
 struct grpc_chttp2_hpack_parser_string {
@@ -45,10 +45,10 @@ struct grpc_chttp2_hpack_parser_string {
 };
 struct grpc_chttp2_hpack_parser {
   /* user specified callback for each header output */
-  grpc_error* (*on_header)(void* user_data, grpc_mdelem md);
+  grpc_error_handle (*on_header)(void* user_data, grpc_mdelem md);
   void* on_header_user_data;
 
-  grpc_error* last_error;
+  grpc_error_handle last_error;
 
   /* current parse state - or a function that implements it */
   grpc_chttp2_hpack_parser_state state;
@@ -103,15 +103,15 @@ void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser* p);
 
 void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser* p);
 
-grpc_error* grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser* p,
-                                           const grpc_slice& slice);
+grpc_error_handle grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser* p,
+                                                 const grpc_slice& slice);
 
 /* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
    the transport */
-grpc_error* grpc_chttp2_header_parser_parse(void* hpack_parser,
-                                            grpc_chttp2_transport* t,
-                                            grpc_chttp2_stream* s,
-                                            const grpc_slice& slice,
-                                            int is_last);
+grpc_error_handle grpc_chttp2_header_parser_parse(void* hpack_parser,
+                                                  grpc_chttp2_transport* t,
+                                                  grpc_chttp2_stream* s,
+                                                  const grpc_slice& slice,
+                                                  int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H */
index 78ee207..696176b 100644 (file)
@@ -114,8 +114,8 @@ void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl* tbl,
   tbl->max_bytes = max_bytes;
 }
 
-grpc_error* grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl* tbl,
-                                                     uint32_t bytes) {
+grpc_error_handle grpc_chttp2_hptbl_set_current_table_size(
+    grpc_chttp2_hptbl* tbl, uint32_t bytes) {
   if (tbl->current_table_bytes == bytes) {
     return GRPC_ERROR_NONE;
   }
@@ -145,7 +145,8 @@ grpc_error* grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl* tbl,
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl, grpc_mdelem md) {
+grpc_error_handle grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl,
+                                        grpc_mdelem md) {
   /* determine how many bytes of buffer this entry represents */
   size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(md)) +
                       GRPC_SLICE_LENGTH(GRPC_MDVALUE(md)) +
index 34c3dce..14a7793 100644 (file)
@@ -89,8 +89,8 @@ struct grpc_chttp2_hptbl {
 void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl* tbl);
 void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl* tbl,
                                      uint32_t max_bytes);
-grpc_error* grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl* tbl,
-                                                     uint32_t bytes);
+grpc_error_handle grpc_chttp2_hptbl_set_current_table_size(
+    grpc_chttp2_hptbl* tbl, uint32_t bytes);
 
 /* lookup a table entry based on its hpack index */
 grpc_mdelem grpc_chttp2_hptbl_lookup_dynamic_index(const grpc_chttp2_hptbl* tbl,
@@ -117,8 +117,8 @@ inline grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl* tbl,
   }
 }
 /* add a table entry to the index */
-grpc_error* grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl,
-                                  grpc_mdelem md) GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl,
+                                        grpc_mdelem md) GRPC_MUST_USE_RESULT;
 
 size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
                                            bool use_true_binary_metadata);
index d04630d..361b7b7 100644 (file)
@@ -27,7 +27,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-grpc_error* grpc_chttp2_incoming_metadata_buffer_add(
+grpc_error_handle grpc_chttp2_incoming_metadata_buffer_add(
     grpc_chttp2_incoming_metadata_buffer* buffer, grpc_mdelem elem) {
   buffer->size += GRPC_MDELEM_LENGTH(elem);
   grpc_linked_mdelem* storage;
@@ -42,7 +42,7 @@ grpc_error* grpc_chttp2_incoming_metadata_buffer_add(
   return grpc_metadata_batch_link_tail(&buffer->batch, storage);
 }
 
-grpc_error* grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+grpc_error_handle grpc_chttp2_incoming_metadata_buffer_replace_or_add(
     grpc_chttp2_incoming_metadata_buffer* buffer, grpc_mdelem elem) {
   for (grpc_linked_mdelem* l = buffer->batch.list.head; l != nullptr;
        l = l->next) {
index b63caa1..68413b0 100644 (file)
@@ -46,10 +46,10 @@ struct grpc_chttp2_incoming_metadata_buffer {
 void grpc_chttp2_incoming_metadata_buffer_publish(
     grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch);
 
-grpc_error* grpc_chttp2_incoming_metadata_buffer_add(
+grpc_error_handle grpc_chttp2_incoming_metadata_buffer_add(
     grpc_chttp2_incoming_metadata_buffer* buffer,
     grpc_mdelem elem) GRPC_MUST_USE_RESULT;
-grpc_error* grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+grpc_error_handle grpc_chttp2_incoming_metadata_buffer_replace_or_add(
     grpc_chttp2_incoming_metadata_buffer* buffer,
     grpc_mdelem elem) GRPC_MUST_USE_RESULT;
 void grpc_chttp2_incoming_metadata_buffer_set_deadline(
index 30a963d..9c7f5fc 100644 (file)
@@ -217,8 +217,8 @@ class Chttp2IncomingByteStream : public ByteStream {
   void Orphan() override;
 
   bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
-  grpc_error* Pull(grpc_slice* slice) override;
-  void Shutdown(grpc_error* error) override;
+  grpc_error_handle Pull(grpc_slice* slice) override;
+  void Shutdown(grpc_error_handle error) override;
 
   // TODO(roth): When I converted this class to C++, I wanted to make it
   // inherit from RefCounted or InternallyRefCounted instead of continuing
@@ -241,17 +241,17 @@ class Chttp2IncomingByteStream : public ByteStream {
     }
   }
 
-  void PublishError(grpc_error* error);
+  void PublishError(grpc_error_handle error);
 
-  grpc_error* Push(const grpc_slice& slice, grpc_slice* slice_out);
+  grpc_error_handle Push(const grpc_slice& slice, grpc_slice* slice_out);
 
-  grpc_error* Finished(grpc_error* error, bool reset_on_error);
+  grpc_error_handle Finished(grpc_error_handle error, bool reset_on_error);
 
   uint32_t remaining_bytes() const { return remaining_bytes_; }
 
  private:
-  static void NextLocked(void* arg, grpc_error* error_ignored);
-  static void OrphanLocked(void* arg, grpc_error* error_ignored);
+  static void NextLocked(void* arg, grpc_error_handle error_ignored);
+  static void OrphanLocked(void* arg, grpc_error_handle error_ignored);
 
   void MaybeCreateStreamDecompressionCtx();
 
@@ -309,7 +309,7 @@ struct grpc_chttp2_transport {
   /** is the transport destroying itself? */
   uint8_t destroying = false;
   /** has the upper layer closed the transport? */
-  grpc_error* closed_with_error = GRPC_ERROR_NONE;
+  grpc_error_handle closed_with_error = GRPC_ERROR_NONE;
 
   /** is there a read request to the endpoint outstanding? */
   uint8_t endpoint_reading = 1;
@@ -358,7 +358,7 @@ struct grpc_chttp2_transport {
 
   /** Set to a grpc_error object if a goaway frame is received. By default, set
    * to GRPC_ERROR_NONE */
-  grpc_error* goaway_error = GRPC_ERROR_NONE;
+  grpc_error_handle goaway_error = GRPC_ERROR_NONE;
 
   grpc_chttp2_sent_goaway_state sent_goaway_state = GRPC_CHTTP2_NO_GOAWAY_SEND;
 
@@ -428,9 +428,9 @@ struct grpc_chttp2_transport {
   /* active parser */
   void* parser_data = nullptr;
   grpc_chttp2_stream* incoming_stream = nullptr;
-  grpc_error* (*parser)(void* parser_user_data, grpc_chttp2_transport* t,
-                        grpc_chttp2_stream* s, const grpc_slice& slice,
-                        int is_last);
+  grpc_error_handle (*parser)(void* parser_user_data, grpc_chttp2_transport* t,
+                              grpc_chttp2_stream* s, const grpc_slice& slice,
+                              int is_last);
 
   grpc_chttp2_write_cb* write_cb_pool = nullptr;
 
@@ -443,7 +443,7 @@ struct grpc_chttp2_transport {
 
   /* if non-NULL, close the transport with this error when writes are finished
    */
-  grpc_error* close_transport_on_writes_finished = GRPC_ERROR_NONE;
+  grpc_error_handle close_transport_on_writes_finished = GRPC_ERROR_NONE;
 
   /* a list of closures to run after writes are finished */
   grpc_closure_list run_after_write = GRPC_CLOSURE_LIST_INIT;
@@ -581,9 +581,9 @@ struct grpc_chttp2_stream {
   bool eos_sent = false;
 
   /** the error that resulted in this stream being read-closed */
-  grpc_error* read_closed_error = GRPC_ERROR_NONE;
+  grpc_error_handle read_closed_error = GRPC_ERROR_NONE;
   /** the error that resulted in this stream being write-closed */
-  grpc_error* write_closed_error = GRPC_ERROR_NONE;
+  grpc_error_handle write_closed_error = GRPC_ERROR_NONE;
 
   grpc_published_metadata_method published_metadata[2] = {};
   bool final_metadata_requested = false;
@@ -604,13 +604,14 @@ struct grpc_chttp2_stream {
    * true */
   grpc_slice_buffer unprocessed_incoming_frames_buffer;
   grpc_closure reset_byte_stream;
-  grpc_error* byte_stream_error = GRPC_ERROR_NONE; /* protected by t combiner */
-  bool received_last_frame = false;                /* protected by t combiner */
+  grpc_error_handle byte_stream_error =
+      GRPC_ERROR_NONE;              /* protected by t combiner */
+  bool received_last_frame = false; /* protected by t combiner */
 
   grpc_millis deadline = GRPC_MILLIS_INF_FUTURE;
 
   /** saw some stream level error */
-  grpc_error* forced_close_error = GRPC_ERROR_NONE;
+  grpc_error_handle forced_close_error = GRPC_ERROR_NONE;
   /** how many header frames have we received? */
   uint8_t header_frames_received = 0;
   /** parsing state for data frames */
@@ -696,12 +697,12 @@ struct grpc_chttp2_begin_write_result {
 };
 grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
     grpc_chttp2_transport* t);
-void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error* error);
+void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error_handle error);
 
 /** Process one slice of incoming data; return 1 if the connection is still
     viable after reading, or 0 if the connection should be torn down */
-grpc_error* grpc_chttp2_perform_read(grpc_chttp2_transport* t,
-                                     const grpc_slice& slice);
+grpc_error_handle grpc_chttp2_perform_read(grpc_chttp2_transport* t,
+                                           const grpc_slice& slice);
 
 bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport* t,
                                           grpc_chttp2_stream* s);
@@ -771,7 +772,8 @@ void grpc_chttp2_parsing_become_skip_parser(grpc_chttp2_transport* t);
 void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
                                        grpc_chttp2_stream* s,
                                        grpc_closure** pclosure,
-                                       grpc_error* error, const char* desc);
+                                       grpc_error_handle error,
+                                       const char* desc);
 
 #define GRPC_HEADER_SIZE_IN_BYTES 5
 #define MAX_SIZE_T (~(size_t)0)
@@ -791,10 +793,11 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
   } while (0)
 
 void grpc_chttp2_fake_status(grpc_chttp2_transport* t,
-                             grpc_chttp2_stream* stream, grpc_error* error);
+                             grpc_chttp2_stream* stream,
+                             grpc_error_handle error);
 void grpc_chttp2_mark_stream_closed(grpc_chttp2_transport* t,
                                     grpc_chttp2_stream* s, int close_reads,
-                                    int close_writes, grpc_error* error);
+                                    int close_writes, grpc_error_handle error);
 void grpc_chttp2_start_writing(grpc_chttp2_transport* t);
 
 #ifndef NDEBUG
@@ -862,7 +865,7 @@ void grpc_chttp2_mark_stream_writable(grpc_chttp2_transport* t,
                                       grpc_chttp2_stream* s);
 
 void grpc_chttp2_cancel_stream(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                               grpc_error* due_to_error);
+                               grpc_error_handle due_to_error);
 
 void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_chttp2_transport* t,
                                                       grpc_chttp2_stream* s);
@@ -872,14 +875,15 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_chttp2_transport* t,
                                                        grpc_chttp2_stream* s);
 
 void grpc_chttp2_fail_pending_writes(grpc_chttp2_transport* t,
-                                     grpc_chttp2_stream* s, grpc_error* error);
+                                     grpc_chttp2_stream* s,
+                                     grpc_error_handle error);
 
 /** Set the default keepalive configurations, must only be called at
     initialization */
 void grpc_chttp2_config_default_keepalive_args(grpc_channel_args* args,
                                                bool is_client);
 
-void grpc_chttp2_retry_initiate_ping(void* tp, grpc_error* error);
+void grpc_chttp2_retry_initiate_ping(void* tp, grpc_error_handle error);
 
 void schedule_bdp_ping_locked(grpc_chttp2_transport* t);
 
index f4b02bb..68e7c69 100644 (file)
 #include "src/core/lib/transport/status_conversion.h"
 #include "src/core/lib/transport/timeout_encoding.h"
 
-static grpc_error* init_frame_parser(grpc_chttp2_transport* t);
-static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t,
-                                            int is_continuation);
-static grpc_error* init_data_frame_parser(grpc_chttp2_transport* t);
-static grpc_error* init_rst_stream_parser(grpc_chttp2_transport* t);
-static grpc_error* init_settings_frame_parser(grpc_chttp2_transport* t);
-static grpc_error* init_window_update_frame_parser(grpc_chttp2_transport* t);
-static grpc_error* init_ping_parser(grpc_chttp2_transport* t);
-static grpc_error* init_goaway_parser(grpc_chttp2_transport* t);
-static grpc_error* init_skip_frame_parser(grpc_chttp2_transport* t,
-                                          int is_header);
-
-static grpc_error* parse_frame_slice(grpc_chttp2_transport* t,
-                                     const grpc_slice& slice, int is_last);
-
-grpc_error* grpc_chttp2_perform_read(grpc_chttp2_transport* t,
-                                     const grpc_slice& slice) {
+static grpc_error_handle init_frame_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
+                                                  int is_continuation);
+static grpc_error_handle init_data_frame_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_rst_stream_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_settings_frame_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_window_update_frame_parser(
+    grpc_chttp2_transport* t);
+static grpc_error_handle init_ping_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_goaway_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_skip_frame_parser(grpc_chttp2_transport* t,
+                                                int is_header);
+
+static grpc_error_handle parse_frame_slice(grpc_chttp2_transport* t,
+                                           const grpc_slice& slice,
+                                           int is_last);
+
+grpc_error_handle grpc_chttp2_perform_read(grpc_chttp2_transport* t,
+                                           const grpc_slice& slice) {
   const uint8_t* beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
-  grpc_error* err;
+  grpc_error_handle err;
 
   if (cur == end) return GRPC_ERROR_NONE;
 
@@ -250,7 +252,7 @@ grpc_error* grpc_chttp2_perform_read(grpc_chttp2_transport* t,
   GPR_UNREACHABLE_CODE(return nullptr);
 }
 
-static grpc_error* init_frame_parser(grpc_chttp2_transport* t) {
+static grpc_error_handle init_frame_parser(grpc_chttp2_transport* t) {
   if (t->is_first_frame &&
       t->incoming_frame_type != GRPC_CHTTP2_FRAME_SETTINGS) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -303,19 +305,21 @@ static grpc_error* init_frame_parser(grpc_chttp2_transport* t) {
   }
 }
 
-static grpc_error* skip_parser(void* /*parser*/, grpc_chttp2_transport* /*t*/,
-                               grpc_chttp2_stream* /*s*/,
-                               const grpc_slice& /*slice*/, int /*is_last*/) {
+static grpc_error_handle skip_parser(void* /*parser*/,
+                                     grpc_chttp2_transport* /*t*/,
+                                     grpc_chttp2_stream* /*s*/,
+                                     const grpc_slice& /*slice*/,
+                                     int /*is_last*/) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* skip_header(void* /*tp*/, grpc_mdelem md) {
+static grpc_error_handle skip_header(void* /*tp*/, grpc_mdelem md) {
   GRPC_MDELEM_UNREF(md);
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_skip_frame_parser(grpc_chttp2_transport* t,
-                                          int is_header) {
+static grpc_error_handle init_skip_frame_parser(grpc_chttp2_transport* t,
+                                                int is_header) {
   if (is_header) {
     uint8_t is_eoh = t->expect_continuation_stream_id != 0;
     t->parser = grpc_chttp2_header_parser_parse;
@@ -334,7 +338,7 @@ void grpc_chttp2_parsing_become_skip_parser(grpc_chttp2_transport* t) {
   init_skip_frame_parser(t, t->parser == grpc_chttp2_header_parser_parse);
 }
 
-static grpc_error* init_data_frame_parser(grpc_chttp2_transport* t) {
+static grpc_error_handle init_data_frame_parser(grpc_chttp2_transport* t) {
   // Update BDP accounting since we have received a data frame.
   grpc_core::BdpEstimator* bdp_est = t->flow_control->bdp_estimator();
   if (bdp_est) {
@@ -347,7 +351,7 @@ static grpc_error* init_data_frame_parser(grpc_chttp2_transport* t) {
   }
   grpc_chttp2_stream* s =
       grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
-  grpc_error* err = GRPC_ERROR_NONE;
+  grpc_error_handle err = GRPC_ERROR_NONE;
   grpc_core::chttp2::FlowControlAction action;
   if (s == nullptr) {
     err = t->flow_control->RecvData(t->incoming_frame_size);
@@ -413,8 +417,8 @@ static void GPR_ATTRIBUTE_NOINLINE on_initial_header_log(
   gpr_free(value);
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE handle_timeout(grpc_chttp2_stream* s,
-                                                         grpc_mdelem md) {
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
+handle_timeout(grpc_chttp2_stream* s, grpc_mdelem md) {
   grpc_millis* cached_timeout =
       static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
   grpc_millis timeout;
@@ -443,9 +447,11 @@ static grpc_error* GPR_ATTRIBUTE_NOINLINE handle_timeout(grpc_chttp2_stream* s,
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE handle_metadata_size_limit_exceeded(
-    grpc_chttp2_transport* t, grpc_chttp2_stream* s, grpc_mdelem md,
-    size_t new_size, size_t metadata_size_limit) {
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
+handle_metadata_size_limit_exceeded(grpc_chttp2_transport* t,
+                                    grpc_chttp2_stream* s, grpc_mdelem md,
+                                    size_t new_size,
+                                    size_t metadata_size_limit) {
   gpr_log(GPR_DEBUG,
           "received initial metadata size exceeds limit (%" PRIuPTR
           " vs. %" PRIuPTR
@@ -463,9 +469,9 @@ static grpc_error* GPR_ATTRIBUTE_NOINLINE handle_metadata_size_limit_exceeded(
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
 handle_metadata_add_failure(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                            grpc_mdelem md, grpc_error* error) {
+                            grpc_mdelem md, grpc_error_handle error) {
   grpc_chttp2_cancel_stream(t, s, error);
   grpc_chttp2_parsing_become_skip_parser(t);
   s->seen_error = true;
@@ -473,7 +479,7 @@ handle_metadata_add_failure(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* on_initial_header(void* tp, grpc_mdelem md) {
+static grpc_error_handle on_initial_header(void* tp, grpc_mdelem md) {
   GPR_TIMER_SCOPE("on_initial_header", 0);
 
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
@@ -496,7 +502,7 @@ static grpc_error* on_initial_header(void* tp, grpc_mdelem md) {
     return handle_metadata_size_limit_exceeded(t, s, md, new_size,
                                                metadata_size_limit);
   } else {
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
     if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
       return handle_metadata_add_failure(t, s, md, error);
@@ -506,7 +512,7 @@ static grpc_error* on_initial_header(void* tp, grpc_mdelem md) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* on_trailing_header(void* tp, grpc_mdelem md) {
+static grpc_error_handle on_trailing_header(void* tp, grpc_mdelem md) {
   GPR_TIMER_SCOPE("on_trailing_header", 0);
 
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
@@ -545,7 +551,7 @@ static grpc_error* on_trailing_header(void* tp, grpc_mdelem md) {
     s->seen_error = true;
     GRPC_MDELEM_UNREF(md);
   } else {
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[1], md);
     if (error != GRPC_ERROR_NONE) {
       grpc_chttp2_cancel_stream(t, s, error);
@@ -557,8 +563,8 @@ static grpc_error* on_trailing_header(void* tp, grpc_mdelem md) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t,
-                                            int is_continuation) {
+static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
+                                                  int is_continuation) {
   uint8_t is_eoh =
       (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
   grpc_chttp2_stream* s;
@@ -595,7 +601,7 @@ static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t,
         GRPC_CHTTP2_IF_TRACING(gpr_log(
             GPR_ERROR, "ignoring new grpc_chttp2_stream creation on client"));
       }
-      grpc_error* err = init_skip_frame_parser(t, 1);
+      grpc_error_handle err = init_skip_frame_parser(t, 1);
       if (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_HAS_PRIORITY) {
         grpc_chttp2_hpack_parser_set_has_priority(&t->hpack_parser);
       }
@@ -678,8 +684,9 @@ static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t,
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_window_update_frame_parser(grpc_chttp2_transport* t) {
-  grpc_error* err = grpc_chttp2_window_update_parser_begin_frame(
+static grpc_error_handle init_window_update_frame_parser(
+    grpc_chttp2_transport* t) {
+  grpc_error_handle err = grpc_chttp2_window_update_parser_begin_frame(
       &t->simple.window_update, t->incoming_frame_size,
       t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
@@ -696,8 +703,8 @@ static grpc_error* init_window_update_frame_parser(grpc_chttp2_transport* t) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_ping_parser(grpc_chttp2_transport* t) {
-  grpc_error* err = grpc_chttp2_ping_parser_begin_frame(
+static grpc_error_handle init_ping_parser(grpc_chttp2_transport* t) {
+  grpc_error_handle err = grpc_chttp2_ping_parser_begin_frame(
       &t->simple.ping, t->incoming_frame_size, t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
   t->parser = grpc_chttp2_ping_parser_parse;
@@ -705,8 +712,8 @@ static grpc_error* init_ping_parser(grpc_chttp2_transport* t) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_rst_stream_parser(grpc_chttp2_transport* t) {
-  grpc_error* err = grpc_chttp2_rst_stream_parser_begin_frame(
+static grpc_error_handle init_rst_stream_parser(grpc_chttp2_transport* t) {
+  grpc_error_handle err = grpc_chttp2_rst_stream_parser_begin_frame(
       &t->simple.rst_stream, t->incoming_frame_size, t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
   grpc_chttp2_stream* s = t->incoming_stream =
@@ -720,8 +727,8 @@ static grpc_error* init_rst_stream_parser(grpc_chttp2_transport* t) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_goaway_parser(grpc_chttp2_transport* t) {
-  grpc_error* err = grpc_chttp2_goaway_parser_begin_frame(
+static grpc_error_handle init_goaway_parser(grpc_chttp2_transport* t) {
+  grpc_error_handle err = grpc_chttp2_goaway_parser_begin_frame(
       &t->goaway_parser, t->incoming_frame_size, t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
   t->parser = grpc_chttp2_goaway_parser_parse;
@@ -729,13 +736,13 @@ static grpc_error* init_goaway_parser(grpc_chttp2_transport* t) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_settings_frame_parser(grpc_chttp2_transport* t) {
+static grpc_error_handle init_settings_frame_parser(grpc_chttp2_transport* t) {
   if (t->incoming_stream_id != 0) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Settings frame received for grpc_chttp2_stream");
   }
 
-  grpc_error* err = grpc_chttp2_settings_parser_begin_frame(
+  grpc_error_handle err = grpc_chttp2_settings_parser_begin_frame(
       &t->simple.settings, t->incoming_frame_size, t->incoming_frame_flags,
       t->settings[GRPC_PEER_SETTINGS]);
   if (err != GRPC_ERROR_NONE) {
@@ -755,17 +762,17 @@ static grpc_error* init_settings_frame_parser(grpc_chttp2_transport* t) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* parse_frame_slice(grpc_chttp2_transport* t,
-                                     const grpc_slice& slice, int is_last) {
+static grpc_error_handle parse_frame_slice(grpc_chttp2_transport* t,
+                                           const grpc_slice& slice,
+                                           int is_last) {
   grpc_chttp2_stream* s = t->incoming_stream;
-  grpc_error* err = t->parser(t->parser_data, t, s, slice, is_last);
+  grpc_error_handle err = t->parser(t->parser_data, t, s, slice, is_last);
   intptr_t unused;
   if (GPR_LIKELY(err == GRPC_ERROR_NONE)) {
     return err;
   } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, &unused)) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
-      const char* msg = grpc_error_string(err);
-      gpr_log(GPR_ERROR, "%s", msg);
+      gpr_log(GPR_ERROR, "%s", grpc_error_std_string(err).c_str());
     }
     grpc_chttp2_parsing_become_skip_parser(t);
     if (s) {
index 317afcc..e34856c 100644 (file)
@@ -39,7 +39,7 @@ static void add_to_write_list(grpc_chttp2_write_cb** list,
 }
 
 static void finish_write_cb(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                            grpc_chttp2_write_cb* cb, grpc_error* error) {
+                            grpc_chttp2_write_cb* cb, grpc_error_handle error) {
   grpc_chttp2_complete_closure_step(t, s, &cb->closure, error,
                                     "finish_write_cb");
   cb->next = t->write_cb_pool;
@@ -75,6 +75,10 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) {
     }
     return;
   }
+  // InvalidateNow to avoid getting stuck re-initializing the ping timer
+  // in a loop while draining the currently-held combiner. Also see
+  // https://github.com/grpc/grpc/issues/26079.
+  grpc_core::ExecCtx::Get()->InvalidateNow();
   grpc_millis now = grpc_core::ExecCtx::Get()->Now();
 
   grpc_millis next_allowed_ping_interval =
@@ -134,7 +138,7 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) {
 
 static bool update_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
                         int64_t send_bytes, grpc_chttp2_write_cb** list,
-                        int64_t* ctr, grpc_error* error) {
+                        int64_t* ctr, grpc_error_handle error) {
   bool sched_any = false;
   grpc_chttp2_write_cb* cb = *list;
   *list = nullptr;
@@ -678,7 +682,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
   return ctx.Result();
 }
 
-void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error* error) {
+void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error_handle error) {
   GPR_TIMER_SCOPE("grpc_chttp2_end_write", 0);
   grpc_chttp2_stream* s;
 
index f904aee..9c047b3 100644 (file)
@@ -491,3 +491,37 @@ const char* cronet_net_error_as_string(cronet_net_error_code net_error) {
   }
   return "UNAVAILABLE.";
 }
+
+grpc_status_code cronet_net_error_to_grpc_error(
+    cronet_net_error_code net_error) {
+  switch (net_error) {
+    case OK:
+      return GRPC_STATUS_OK;
+    case CRONET_NET_ERROR_ABORTED:
+      return GRPC_STATUS_ABORTED;
+    case CRONET_NET_ERROR_ACCESS_DENIED:
+    case CRONET_NET_ERROR_NETWORK_ACCESS_DENIED:
+      return GRPC_STATUS_PERMISSION_DENIED;
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_CERT_NEEDED:
+    case CRONET_NET_ERROR_PROXY_AUTH_UNSUPPORTED:
+    case CRONET_NET_ERROR_BAD_SSL_CLIENT_AUTH_CERT:
+    case CRONET_NET_ERROR_PROXY_AUTH_REQUESTED:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_SIGNATURE_FAILED:
+    case CRONET_NET_ERROR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_NO_COMMON_ALGORITHMS:
+    case CRONET_NET_ERROR_CERT_AUTHORITY_INVALID:
+    case CRONET_NET_ERROR_UNEXPECTED_PROXY_AUTH:
+    case CRONET_NET_ERROR_MALFORMED_IDENTITY:
+    case CRONET_NET_ERROR_INVALID_AUTH_CREDENTIALS:
+    case CRONET_NET_ERROR_UNSUPPORTED_AUTH_SCHEME:
+    case CRONET_NET_ERROR_MISSING_AUTH_CREDENTIALS:
+      return GRPC_STATUS_UNAUTHENTICATED;
+    default:
+      return GRPC_STATUS_UNAVAILABLE;
+  }
+
+  return GRPC_STATUS_UNAVAILABLE;
+}
index d6d1ed8..ee1262a 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <grpc/impl/codegen/port_platform.h>
 
+#include <grpc/status.h>
+
 enum cronet_net_error_code {
   //
   // Ranges:
@@ -1037,5 +1039,7 @@ enum cronet_net_error_code {
 };
 
 const char* cronet_net_error_as_string(cronet_net_error_code net_error);
+grpc_status_code cronet_net_error_to_grpc_error(
+    cronet_net_error_code net_error);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CRONET_TRANSPORT_CRONET_STATUS_H */
index 9ecca85..061b2e0 100644 (file)
@@ -165,7 +165,7 @@ struct op_state {
   /* User requested RECV_TRAILING_METADATA */
   bool pending_recv_trailing_metadata = false;
   cronet_net_error_code net_error = OK;
-  grpc_error* cancel_error = GRPC_ERROR_NONE;
+  grpc_error_handle cancel_error = GRPC_ERROR_NONE;
   /* data structure for storing data coming from server */
   struct read_state rs;
   /* data structure for storing data going to the server */
@@ -306,13 +306,13 @@ static void read_grpc_header(stream_obj* s) {
                             s->state.rs.remaining_bytes);
 }
 
-static grpc_error* make_error_with_desc(int error_code,
-                                        int cronet_internal_error_code,
-                                        const char* desc) {
+static grpc_error_handle make_error_with_desc(int error_code,
+                                              int cronet_internal_error_code,
+                                              const char* desc) {
   std::string error_message =
       absl::StrFormat("Cronet error code:%d, Cronet error detail:%s",
                       cronet_internal_error_code, desc);
-  grpc_error* error =
+  grpc_error_handle error =
       GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_message.c_str());
   error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, error_code);
   return error;
@@ -1317,13 +1317,15 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
              op_can_be_run(stream_op, s, &oas->state,
                            OP_RECV_TRAILING_METADATA)) {
     CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_TRAILING_METADATA", oas);
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
       error = GRPC_ERROR_REF(stream_state->cancel_error);
     } else if (stream_state->state_callback_received[OP_FAILED]) {
+      grpc_status_code grpc_error_code =
+          cronet_net_error_to_grpc_error(stream_state->net_error);
       const char* desc = cronet_net_error_as_string(stream_state->net_error);
-      error = make_error_with_desc(GRPC_STATUS_UNAVAILABLE,
-                                   stream_state->net_error, desc);
+      error =
+          make_error_with_desc(grpc_error_code, stream_state->net_error, desc);
     } else if (oas->s->state.rs.trailing_metadata_valid) {
       grpc_chttp2_incoming_metadata_buffer_publish(
           &oas->s->state.rs.trailing_metadata,
@@ -1362,10 +1364,12 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
       if (stream_op->on_complete) {
         const char* error_message =
             cronet_net_error_as_string(stream_state->net_error);
+        grpc_status_code grpc_error_code =
+            cronet_net_error_to_grpc_error(stream_state->net_error);
         grpc_core::ExecCtx::Run(
             DEBUG_LOCATION, stream_op->on_complete,
-            make_error_with_desc(GRPC_STATUS_UNAVAILABLE,
-                                 stream_state->net_error, error_message));
+            make_error_with_desc(grpc_error_code, stream_state->net_error,
+                                 error_message));
       }
     } else {
       /* All actions in this stream_op are complete. Call the on_complete
index 213c142..0c21db7 100644 (file)
@@ -50,15 +50,15 @@ grpc_slice g_fake_auth_key;
 grpc_slice g_fake_auth_value;
 
 struct inproc_stream;
-bool cancel_stream_locked(inproc_stream* s, grpc_error* error);
-void maybe_process_ops_locked(inproc_stream* s, grpc_error* error);
-void op_state_machine_locked(inproc_stream* s, grpc_error* error);
+bool cancel_stream_locked(inproc_stream* s, grpc_error_handle error);
+void maybe_process_ops_locked(inproc_stream* s, grpc_error_handle error);
+void op_state_machine_locked(inproc_stream* s, grpc_error_handle error);
 void log_metadata(const grpc_metadata_batch* md_batch, bool is_client,
                   bool is_initial);
-grpc_error* fill_in_metadata(inproc_stream* s,
-                             const grpc_metadata_batch* metadata,
-                             uint32_t flags, grpc_metadata_batch* out_md,
-                             uint32_t* outflags, bool* markfilled);
+grpc_error_handle fill_in_metadata(inproc_stream* s,
+                                   const grpc_metadata_batch* metadata,
+                                   uint32_t flags, grpc_metadata_batch* out_md,
+                                   uint32_t* outflags, bool* markfilled);
 
 struct shared_mu {
   shared_mu() {
@@ -239,7 +239,7 @@ struct inproc_stream {
   grpc_millis write_buffer_deadline = GRPC_MILLIS_INF_FUTURE;
   grpc_metadata_batch write_buffer_trailing_md;
   bool write_buffer_trailing_md_filled = false;
-  grpc_error* write_buffer_cancel_error = GRPC_ERROR_NONE;
+  grpc_error_handle write_buffer_cancel_error = GRPC_ERROR_NONE;
 
   struct inproc_stream* other_side;
   bool other_side_closed = false;               // won't talk anymore
@@ -270,8 +270,8 @@ struct inproc_stream {
 
   bool closed = false;
 
-  grpc_error* cancel_self_error = GRPC_ERROR_NONE;
-  grpc_error* cancel_other_error = GRPC_ERROR_NONE;
+  grpc_error_handle cancel_self_error = GRPC_ERROR_NONE;
+  grpc_error_handle cancel_other_error = GRPC_ERROR_NONE;
 
   grpc_millis deadline = GRPC_MILLIS_INF_FUTURE;
 
@@ -293,10 +293,10 @@ void log_metadata(const grpc_metadata_batch* md_batch, bool is_client,
   }
 }
 
-grpc_error* fill_in_metadata(inproc_stream* s,
-                             const grpc_metadata_batch* metadata,
-                             uint32_t flags, grpc_metadata_batch* out_md,
-                             uint32_t* outflags, bool* markfilled) {
+grpc_error_handle fill_in_metadata(inproc_stream* s,
+                                   const grpc_metadata_batch* metadata,
+                                   uint32_t flags, grpc_metadata_batch* out_md,
+                                   uint32_t* outflags, bool* markfilled) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_inproc_trace)) {
     log_metadata(metadata, s->t->is_client, outflags != nullptr);
   }
@@ -307,7 +307,7 @@ grpc_error* fill_in_metadata(inproc_stream* s,
   if (markfilled != nullptr) {
     *markfilled = true;
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   for (grpc_linked_mdelem* elem = metadata->list.head;
        (elem != nullptr) && (error == GRPC_ERROR_NONE); elem = elem->next) {
     grpc_linked_mdelem* nelem =
@@ -374,7 +374,7 @@ void close_other_side_locked(inproc_stream* s, const char* reason) {
 // this stream_op_batch is only one of the pending operations for this
 // stream. This is called when one of the pending operations for the stream
 // is done and about to be NULLed out
-void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error,
+void complete_if_batch_end_locked(inproc_stream* s, grpc_error_handle error,
                                   grpc_transport_stream_op_batch* op,
                                   const char* msg) {
   int is_sm = static_cast<int>(op == s->send_message_op);
@@ -394,14 +394,14 @@ void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error,
   }
 }
 
-void maybe_process_ops_locked(inproc_stream* s, grpc_error* error) {
+void maybe_process_ops_locked(inproc_stream* s, grpc_error_handle error) {
   if (s && (error != GRPC_ERROR_NONE || s->ops_needed)) {
     s->ops_needed = false;
     op_state_machine_locked(s, error);
   }
 }
 
-void fail_helper_locked(inproc_stream* s, grpc_error* error) {
+void fail_helper_locked(inproc_stream* s, grpc_error_handle error) {
   INPROC_LOG(GPR_INFO, "op_state_machine %p fail_helper", s);
   // If we're failing this side, we need to make sure that
   // we also send or have already sent trailing metadata
@@ -431,7 +431,7 @@ void fail_helper_locked(inproc_stream* s, grpc_error* error) {
     }
   }
   if (s->recv_initial_md_op) {
-    grpc_error* err;
+    grpc_error_handle err;
     if (!s->t->is_client) {
       // If this is a server, provide initial metadata with a path and authority
       // since it expects that as well as no error yet
@@ -550,7 +550,7 @@ void message_transfer_locked(inproc_stream* sender, inproc_stream* receiver) {
     GPR_ASSERT(
         sender->send_message_op->payload->send_message.send_message->Next(
             SIZE_MAX, &unused));
-    grpc_error* error =
+    grpc_error_handle error =
         sender->send_message_op->payload->send_message.send_message->Pull(
             &message_slice);
     if (error != GRPC_ERROR_NONE) {
@@ -583,13 +583,13 @@ void message_transfer_locked(inproc_stream* sender, inproc_stream* receiver) {
   sender->send_message_op = nullptr;
 }
 
-void op_state_machine_locked(inproc_stream* s, grpc_error* error) {
+void op_state_machine_locked(inproc_stream* s, grpc_error_handle error) {
   // This function gets called when we have contents in the unprocessed reads
   // Get what we want based on our ops wanted
   // Schedule our appropriate closures
   // and then return to ops_needed state if still needed
 
-  grpc_error* new_err = GRPC_ERROR_NONE;
+  grpc_error_handle new_err = GRPC_ERROR_NONE;
 
   bool needs_close = false;
 
@@ -887,9 +887,10 @@ done:
   GRPC_ERROR_UNREF(new_err);
 }
 
-bool cancel_stream_locked(inproc_stream* s, grpc_error* error) {
+bool cancel_stream_locked(inproc_stream* s, grpc_error_handle error) {
   bool ret = false;  // was the cancel accepted
-  INPROC_LOG(GPR_INFO, "cancel_stream %p with %s", s, grpc_error_string(error));
+  INPROC_LOG(GPR_INFO, "cancel_stream %p with %s", s,
+             grpc_error_std_string(error).c_str());
   if (s->cancel_self_error == GRPC_ERROR_NONE) {
     ret = true;
     s->cancel_self_error = GRPC_ERROR_REF(error);
@@ -943,7 +944,7 @@ bool cancel_stream_locked(inproc_stream* s, grpc_error* error) {
   return ret;
 }
 
-void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
+void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
                        grpc_transport_stream_op_batch* op) {
@@ -962,7 +963,7 @@ void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
                    s->t->is_client, false);
     }
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_closure* on_complete = op->on_complete;
   // TODO(roth): This is a hack needed because we use data inside of the
   // closure itself to do the barrier calculation (i.e., to ensure that
@@ -1293,7 +1294,7 @@ grpc_channel* grpc_inproc_channel_create(grpc_server* server,
                            client_args);
 
   // TODO(ncteisen): design and support channelz GetSocket for inproc.
-  grpc_error* error = server->core_server->SetupTransport(
+  grpc_error_handle error = server->core_server->SetupTransport(
       server_transport, nullptr, server_args, nullptr);
   grpc_channel* channel = nullptr;
   if (error == GRPC_ERROR_NONE) {
@@ -1303,7 +1304,7 @@ grpc_channel* grpc_inproc_channel_create(grpc_server* server,
     if (error != GRPC_ERROR_NONE) {
       GPR_ASSERT(!channel);
       gpr_log(GPR_ERROR, "Failed to create client channel: %s",
-              grpc_error_string(error));
+              grpc_error_std_string(error).c_str());
       intptr_t integer;
       grpc_status_code status = GRPC_STATUS_INTERNAL;
       if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &integer)) {
@@ -1318,7 +1319,7 @@ grpc_channel* grpc_inproc_channel_create(grpc_server* server,
   } else {
     GPR_ASSERT(!channel);
     gpr_log(GPR_ERROR, "Failed to create server channel: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     intptr_t integer;
     grpc_status_code status = GRPC_STATUS_INTERNAL;
     if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &integer)) {
index 84c219e..e9bba79 100644 (file)
@@ -49,7 +49,7 @@ class CertificateProviderFactory {
   virtual const char* name() const = 0;
 
   virtual RefCountedPtr<Config> CreateCertificateProviderConfig(
-      const Json& config_json, grpc_error** error) = 0;
+      const Json& config_json, grpc_error_handle* error) = 0;
 
   // Create a CertificateProvider instance from config.
   virtual RefCountedPtr<grpc_tls_certificate_provider>
index 0954bc5..fb6ca72 100644 (file)
@@ -92,7 +92,7 @@ class CertificateProviderStore
   };
 
   RefCountedPtr<CertificateProviderWrapper> CreateCertificateProviderLocked(
-      absl::string_view key);
+      absl::string_view key) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   // Releases a previously created certificate provider from the certificate
   // provider map if the value matches \a wrapper.
@@ -101,10 +101,10 @@ class CertificateProviderStore
 
   Mutex mu_;
   // Map of plugin configurations
-  PluginDefinitionMap plugin_config_map_;
+  PluginDefinitionMap plugin_config_map_ ABSL_GUARDED_BY(mu_);
   // Underlying map for the providers.
   std::map<absl::string_view, CertificateProviderWrapper*>
-      certificate_providers_map_;
+      certificate_providers_map_ ABSL_GUARDED_BY(mu_);
 };
 
 }  // namespace grpc_core
index a5250eb..7a793b0 100644 (file)
@@ -64,14 +64,14 @@ std::string FileWatcherCertificateProviderFactory::Config::ToString() const {
 
 RefCountedPtr<FileWatcherCertificateProviderFactory::Config>
 FileWatcherCertificateProviderFactory::Config::Parse(const Json& config_json,
-                                                     grpc_error** error) {
+                                                     grpc_error_handle* error) {
   auto config = MakeRefCounted<FileWatcherCertificateProviderFactory::Config>();
   if (config_json.type() != Json::Type::OBJECT) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "error:config type should be OBJECT.");
     return nullptr;
   }
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   ParseJsonObjectField(config_json.object_value(), "certificate_file",
                        &config->identity_cert_file_, &error_list, false);
   ParseJsonObjectField(config_json.object_value(), "private_key_file",
@@ -112,7 +112,7 @@ const char* FileWatcherCertificateProviderFactory::name() const {
 
 RefCountedPtr<CertificateProviderFactory::Config>
 FileWatcherCertificateProviderFactory::CreateCertificateProviderConfig(
-    const Json& config_json, grpc_error** error) {
+    const Json& config_json, grpc_error_handle* error) {
   return FileWatcherCertificateProviderFactory::Config::Parse(config_json,
                                                               error);
 }
index c570062..13e10de 100644 (file)
@@ -31,7 +31,7 @@ class FileWatcherCertificateProviderFactory
   class Config : public CertificateProviderFactory::Config {
    public:
     static RefCountedPtr<Config> Parse(const Json& config_json,
-                                       grpc_error** error);
+                                       grpc_error_handle* error);
 
     const char* name() const override;
 
@@ -58,7 +58,7 @@ class FileWatcherCertificateProviderFactory
 
   RefCountedPtr<CertificateProviderFactory::Config>
   CreateCertificateProviderConfig(const Json& config_json,
-                                  grpc_error** error) override;
+                                  grpc_error_handle* error) override;
 
   RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
       RefCountedPtr<CertificateProviderFactory::Config> config) override;
index c1b7b84..6e63ae4 100644 (file)
@@ -52,10 +52,10 @@ std::string GoogleMeshCaCertificateProviderFactory::Config::ToString() const {
   return "{}";
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectStsService(
     const Json::Object& sts_service) {
-  std::vector<grpc_error*> error_list_sts_service;
+  std::vector<grpc_error_handle> error_list_sts_service;
   if (!ParseJsonObjectField(sts_service, "token_exchange_service_uri",
                             &sts_config_.token_exchange_service_uri,
                             &error_list_sts_service, false)) {
@@ -89,14 +89,14 @@ GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectStsService(
   return error_list_sts_service;
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectCallCredentials(
     const Json::Object& call_credentials) {
-  std::vector<grpc_error*> error_list_call_credentials;
+  std::vector<grpc_error_handle> error_list_call_credentials;
   const Json::Object* sts_service = nullptr;
   if (ParseJsonObjectField(call_credentials, "sts_service", &sts_service,
                            &error_list_call_credentials)) {
-    std::vector<grpc_error*> error_list_sts_service =
+    std::vector<grpc_error_handle> error_list_sts_service =
         ParseJsonObjectStsService(*sts_service);
     if (!error_list_sts_service.empty()) {
       error_list_call_credentials.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -106,10 +106,10 @@ GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectCallCredentials(
   return error_list_call_credentials;
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGoogleGrpc(
     const Json::Object& google_grpc) {
-  std::vector<grpc_error*> error_list_google_grpc;
+  std::vector<grpc_error_handle> error_list_google_grpc;
   if (!ParseJsonObjectField(google_grpc, "target_uri", &endpoint_,
                             &error_list_google_grpc, false)) {
     endpoint_ = "meshca.googleapis.com";  // Default target
@@ -124,7 +124,7 @@ GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGoogleGrpc(
       const Json::Object* call_credentials = nullptr;
       if (ExtractJsonType((*call_credentials_array)[0], "call_credentials[0]",
                           &call_credentials, &error_list_google_grpc)) {
-        std::vector<grpc_error*> error_list_call_credentials =
+        std::vector<grpc_error_handle> error_list_call_credentials =
             ParseJsonObjectCallCredentials(*call_credentials);
         if (!error_list_call_credentials.empty()) {
           error_list_google_grpc.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -137,14 +137,14 @@ GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGoogleGrpc(
   return error_list_google_grpc;
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGrpcServices(
     const Json::Object& grpc_service) {
-  std::vector<grpc_error*> error_list_grpc_services;
+  std::vector<grpc_error_handle> error_list_grpc_services;
   const Json::Object* google_grpc = nullptr;
   if (ParseJsonObjectField(grpc_service, "google_grpc", &google_grpc,
                            &error_list_grpc_services)) {
-    std::vector<grpc_error*> error_list_google_grpc =
+    std::vector<grpc_error_handle> error_list_google_grpc =
         ParseJsonObjectGoogleGrpc(*google_grpc);
     if (!error_list_google_grpc.empty()) {
       error_list_grpc_services.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -158,10 +158,10 @@ GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGrpcServices(
   return error_list_grpc_services;
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectServer(
     const Json::Object& server) {
-  std::vector<grpc_error*> error_list_server;
+  std::vector<grpc_error_handle> error_list_server;
   std::string api_type;
   if (ParseJsonObjectField(server, "api_type", &api_type, &error_list_server,
                            false)) {
@@ -180,7 +180,7 @@ GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectServer(
       const Json::Object* grpc_service = nullptr;
       if (ExtractJsonType((*grpc_services)[0], "grpc_services[0]",
                           &grpc_service, &error_list_server)) {
-        std::vector<grpc_error*> error_list_grpc_services =
+        std::vector<grpc_error_handle> error_list_grpc_services =
             ParseJsonObjectGrpcServices(*grpc_service);
         if (!error_list_grpc_services.empty()) {
           error_list_server.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -193,8 +193,8 @@ GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectServer(
 }
 
 RefCountedPtr<GoogleMeshCaCertificateProviderFactory::Config>
-GoogleMeshCaCertificateProviderFactory::Config::Parse(const Json& config_json,
-                                                      grpc_error** error) {
+GoogleMeshCaCertificateProviderFactory::Config::Parse(
+    const Json& config_json, grpc_error_handle* error) {
   auto config =
       MakeRefCounted<GoogleMeshCaCertificateProviderFactory::Config>();
   if (config_json.type() != Json::Type::OBJECT) {
@@ -202,11 +202,11 @@ GoogleMeshCaCertificateProviderFactory::Config::Parse(const Json& config_json,
         "error:config type should be OBJECT.");
     return nullptr;
   }
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   const Json::Object* server = nullptr;
   if (ParseJsonObjectField(config_json.object_value(), "server", &server,
                            &error_list)) {
-    std::vector<grpc_error*> error_list_server =
+    std::vector<grpc_error_handle> error_list_server =
         config->ParseJsonObjectServer(*server);
     if (!error_list_server.empty()) {
       error_list.push_back(
@@ -257,7 +257,7 @@ const char* GoogleMeshCaCertificateProviderFactory::name() const {
 
 RefCountedPtr<CertificateProviderFactory::Config>
 GoogleMeshCaCertificateProviderFactory::CreateCertificateProviderConfig(
-    const Json& config_json, grpc_error** error) {
+    const Json& config_json, grpc_error_handle* error) {
   return GoogleMeshCaCertificateProviderFactory::Config::Parse(config_json,
                                                                error);
 }
index 31bf427..7a33f97 100644 (file)
@@ -63,19 +63,20 @@ class GoogleMeshCaCertificateProviderFactory
     const std::string& location() const { return location_; }
 
     static RefCountedPtr<Config> Parse(const Json& config_json,
-                                       grpc_error** error);
+                                       grpc_error_handle* error);
 
    private:
     // Helpers for parsing the config
-    std::vector<grpc_error*> ParseJsonObjectStsService(
+    std::vector<grpc_error_handle> ParseJsonObjectStsService(
         const Json::Object& sts_service);
-    std::vector<grpc_error*> ParseJsonObjectCallCredentials(
+    std::vector<grpc_error_handle> ParseJsonObjectCallCredentials(
         const Json::Object& call_credentials);
-    std::vector<grpc_error*> ParseJsonObjectGoogleGrpc(
+    std::vector<grpc_error_handle> ParseJsonObjectGoogleGrpc(
         const Json::Object& google_grpc);
-    std::vector<grpc_error*> ParseJsonObjectGrpcServices(
+    std::vector<grpc_error_handle> ParseJsonObjectGrpcServices(
         const Json::Object& grpc_service);
-    std::vector<grpc_error*> ParseJsonObjectServer(const Json::Object& server);
+    std::vector<grpc_error_handle> ParseJsonObjectServer(
+        const Json::Object& server);
 
     std::string endpoint_;
     StsConfig sts_config_;
@@ -90,7 +91,7 @@ class GoogleMeshCaCertificateProviderFactory
 
   RefCountedPtr<CertificateProviderFactory::Config>
   CreateCertificateProviderConfig(const Json& config_json,
-                                  grpc_error** error) override;
+                                  grpc_error_handle* error) override;
 
   RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
       RefCountedPtr<CertificateProviderFactory::Config> /*config*/) override {
index 4357b17..e51bc07 100644 (file)
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/xds/xds_api.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_utils.h"
 #include "src/core/lib/slice/slice_utils.h"
 
@@ -1068,8 +1068,8 @@ absl::string_view TypeUrlExternalToInternal(bool use_v3,
 grpc_slice XdsApi::CreateAdsRequest(
     const XdsBootstrap::XdsServer& server, const std::string& type_url,
     const std::set<absl::string_view>& resource_names,
-    const std::string& version, const std::string& nonce, grpc_error* error,
-    bool populate_node) {
+    const std::string& version, const std::string& nonce,
+    grpc_error_handle error, bool populate_node) {
   upb::Arena arena;
   const EncodingContext context = {client_, tracer_, symtab_.ptr(), arena.ptr(),
                                    server.ShouldUseV3()};
@@ -1092,6 +1092,7 @@ grpc_slice XdsApi::CreateAdsRequest(
         request, StdStringToUpbString(nonce));
   }
   // Set error_detail if it's a NACK.
+  std::string error_string_storage;
   if (error != GRPC_ERROR_NONE) {
     google_rpc_Status* error_detail =
         envoy_service_discovery_v3_DiscoveryRequest_mutable_error_detail(
@@ -1102,8 +1103,8 @@ grpc_slice XdsApi::CreateAdsRequest(
     // generate them in the parsing code, and then use that here.
     google_rpc_Status_set_code(error_detail, GRPC_STATUS_INVALID_ARGUMENT);
     // Error description comes from the error that was passed in.
-    upb_strview error_description =
-        StdStringToUpbString(absl::string_view(grpc_error_string(error)));
+    error_string_storage = grpc_error_std_string(error);
+    upb_strview error_description = StdStringToUpbString(error_string_storage);
     google_rpc_Status_set_message(error_detail, error_description);
     GRPC_ERROR_UNREF(error);
   }
@@ -1197,8 +1198,9 @@ void MaybeLogClusterLoadAssignment(
   }
 }
 
-grpc_error* RoutePathMatchParse(const envoy_config_route_v3_RouteMatch* match,
-                                XdsApi::Route* route, bool* ignore_route) {
+grpc_error_handle RoutePathMatchParse(
+    const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route,
+    bool* ignore_route) {
   auto* case_sensitive_ptr =
       envoy_config_route_v3_RouteMatch_case_sensitive(match);
   bool case_sensitive = true;
@@ -1231,7 +1233,7 @@ grpc_error* RoutePathMatchParse(const envoy_config_route_v3_RouteMatch* match,
         return GRPC_ERROR_NONE;
       }
     }
-    type = StringMatcher::Type::PREFIX;
+    type = StringMatcher::Type::kPrefix;
     match_string = std::string(prefix);
   } else if (envoy_config_route_v3_RouteMatch_has_path(match)) {
     absl::string_view path =
@@ -1265,13 +1267,13 @@ grpc_error* RoutePathMatchParse(const envoy_config_route_v3_RouteMatch* match,
       *ignore_route = true;
       return GRPC_ERROR_NONE;
     }
-    type = StringMatcher::Type::EXACT;
+    type = StringMatcher::Type::kExact;
     match_string = std::string(path);
   } else if (envoy_config_route_v3_RouteMatch_has_safe_regex(match)) {
     const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
         envoy_config_route_v3_RouteMatch_safe_regex(match);
     GPR_ASSERT(regex_matcher != nullptr);
-    type = StringMatcher::Type::SAFE_REGEX;
+    type = StringMatcher::Type::kSafeRegex;
     match_string = UpbStringToStdString(
         envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
   } else {
@@ -1290,7 +1292,7 @@ grpc_error* RoutePathMatchParse(const envoy_config_route_v3_RouteMatch* match,
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* RouteHeaderMatchersParse(
+grpc_error_handle RouteHeaderMatchersParse(
     const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route) {
   size_t size;
   const envoy_config_route_v3_HeaderMatcher* const* headers =
@@ -1305,7 +1307,7 @@ grpc_error* RouteHeaderMatchersParse(
     int64_t range_end = 0;
     bool present_match = false;
     if (envoy_config_route_v3_HeaderMatcher_has_exact_match(header)) {
-      type = HeaderMatcher::Type::EXACT;
+      type = HeaderMatcher::Type::kExact;
       match_string = UpbStringToStdString(
           envoy_config_route_v3_HeaderMatcher_exact_match(header));
     } else if (envoy_config_route_v3_HeaderMatcher_has_safe_regex_match(
@@ -1313,28 +1315,28 @@ grpc_error* RouteHeaderMatchersParse(
       const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
           envoy_config_route_v3_HeaderMatcher_safe_regex_match(header);
       GPR_ASSERT(regex_matcher != nullptr);
-      type = HeaderMatcher::Type::SAFE_REGEX;
+      type = HeaderMatcher::Type::kSafeRegex;
       match_string = UpbStringToStdString(
           envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
     } else if (envoy_config_route_v3_HeaderMatcher_has_range_match(header)) {
-      type = HeaderMatcher::Type::RANGE;
+      type = HeaderMatcher::Type::kRange;
       const envoy_type_v3_Int64Range* range_matcher =
           envoy_config_route_v3_HeaderMatcher_range_match(header);
       range_start = envoy_type_v3_Int64Range_start(range_matcher);
       range_end = envoy_type_v3_Int64Range_end(range_matcher);
     } else if (envoy_config_route_v3_HeaderMatcher_has_present_match(header)) {
-      type = HeaderMatcher::Type::PRESENT;
+      type = HeaderMatcher::Type::kPresent;
       present_match = envoy_config_route_v3_HeaderMatcher_present_match(header);
     } else if (envoy_config_route_v3_HeaderMatcher_has_prefix_match(header)) {
-      type = HeaderMatcher::Type::PREFIX;
+      type = HeaderMatcher::Type::kPrefix;
       match_string = UpbStringToStdString(
           envoy_config_route_v3_HeaderMatcher_prefix_match(header));
     } else if (envoy_config_route_v3_HeaderMatcher_has_suffix_match(header)) {
-      type = HeaderMatcher::Type::SUFFIX;
+      type = HeaderMatcher::Type::kSuffix;
       match_string = UpbStringToStdString(
           envoy_config_route_v3_HeaderMatcher_suffix_match(header));
     } else if (envoy_config_route_v3_HeaderMatcher_has_contains_match(header)) {
-      type = HeaderMatcher::Type::CONTAINS;
+      type = HeaderMatcher::Type::kContains;
       match_string = UpbStringToStdString(
           envoy_config_route_v3_HeaderMatcher_contains_match(header));
     } else {
@@ -1357,7 +1359,7 @@ grpc_error* RouteHeaderMatchersParse(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* RouteRuntimeFractionParse(
+grpc_error_handle RouteRuntimeFractionParse(
     const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route) {
   const envoy_config_core_v3_RuntimeFractionalPercent* runtime_fraction =
       envoy_config_route_v3_RouteMatch_runtime_fraction(match);
@@ -1390,9 +1392,9 @@ grpc_error* RouteRuntimeFractionParse(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* ExtractHttpFilterTypeName(const EncodingContext& context,
-                                      const google_protobuf_Any* any,
-                                      absl::string_view* filter_type) {
+grpc_error_handle ExtractHttpFilterTypeName(const EncodingContext& context,
+                                            const google_protobuf_Any* any,
+                                            absl::string_view* filter_type) {
   *filter_type = UpbStringToAbsl(google_protobuf_Any_type_url(any));
   if (*filter_type == "type.googleapis.com/udpa.type.v1.TypedStruct") {
     upb_strview any_value = google_protobuf_Any_value(any);
@@ -1410,7 +1412,7 @@ grpc_error* ExtractHttpFilterTypeName(const EncodingContext& context,
 }
 
 template <typename ParentType, typename EntryType>
-grpc_error* ParseTypedPerFilterConfig(
+grpc_error_handle ParseTypedPerFilterConfig(
     const EncodingContext& context, const ParentType* parent,
     const EntryType* (*entry_func)(const ParentType*, size_t*),
     upb_strview (*key_func)(const EntryType*),
@@ -1454,7 +1456,8 @@ grpc_error* ParseTypedPerFilterConfig(
                 .c_str());
       }
     }
-    grpc_error* error = ExtractHttpFilterTypeName(context, any, &filter_type);
+    grpc_error_handle error =
+        ExtractHttpFilterTypeName(context, any, &filter_type);
     if (error != GRPC_ERROR_NONE) return error;
     const XdsHttpFilterImpl* filter_impl =
         XdsHttpFilterRegistry::GetFilterForType(filter_type);
@@ -1478,9 +1481,9 @@ grpc_error* ParseTypedPerFilterConfig(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* RouteActionParse(const EncodingContext& context,
-                             const envoy_config_route_v3_Route* route_msg,
-                             XdsApi::Route* route, bool* ignore_route) {
+grpc_error_handle RouteActionParse(const EncodingContext& context,
+                                   const envoy_config_route_v3_Route* route_msg,
+                                   XdsApi::Route* route, bool* ignore_route) {
   if (!envoy_config_route_v3_Route_has_route(route_msg)) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "No RouteAction found in route.");
@@ -1533,7 +1536,7 @@ grpc_error* RouteActionParse(const EncodingContext& context,
       if (cluster.weight == 0) continue;
       sum_of_weights += cluster.weight;
       if (context.use_v3) {
-        grpc_error* error = ParseTypedPerFilterConfig<
+        grpc_error_handle error = ParseTypedPerFilterConfig<
             envoy_config_route_v3_WeightedCluster_ClusterWeight,
             envoy_config_route_v3_WeightedCluster_ClusterWeight_TypedPerFilterConfigEntry>(
             context, cluster_weight,
@@ -1663,7 +1666,7 @@ grpc_error* RouteActionParse(const EncodingContext& context,
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* RouteConfigParse(
+grpc_error_handle RouteConfigParse(
     const EncodingContext& context,
     const envoy_config_route_v3_RouteConfiguration* route_config,
     XdsApi::RdsUpdate* rds_update) {
@@ -1695,7 +1698,7 @@ grpc_error* RouteConfigParse(
     }
     // Parse typed_per_filter_config.
     if (context.use_v3) {
-      grpc_error* error = ParseTypedPerFilterConfig<
+      grpc_error_handle error = ParseTypedPerFilterConfig<
           envoy_config_route_v3_VirtualHost,
           envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry>(
           context, virtual_hosts[i],
@@ -1728,7 +1731,8 @@ grpc_error* RouteConfigParse(
       }
       XdsApi::Route route;
       bool ignore_route = false;
-      grpc_error* error = RoutePathMatchParse(match, &route, &ignore_route);
+      grpc_error_handle error =
+          RoutePathMatchParse(match, &route, &ignore_route);
       if (error != GRPC_ERROR_NONE) return error;
       if (ignore_route) continue;
       error = RouteHeaderMatchersParse(match, &route);
@@ -1739,7 +1743,7 @@ grpc_error* RouteConfigParse(
       if (error != GRPC_ERROR_NONE) return error;
       if (ignore_route) continue;
       if (context.use_v3) {
-        grpc_error* error = ParseTypedPerFilterConfig<
+        grpc_error_handle error = ParseTypedPerFilterConfig<
             envoy_config_route_v3_Route,
             envoy_config_route_v3_Route_TypedPerFilterConfigEntry>(
             context, routes[j],
@@ -1771,11 +1775,11 @@ CertificateProviderInstanceParse(
               certificate_provider_instance_proto))};
 }
 
-grpc_error* CommonTlsContextParse(
+grpc_error_handle CommonTlsContextParse(
     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
         common_tls_context_proto,
     XdsApi::CommonTlsContext* common_tls_context) GRPC_MUST_USE_RESULT;
-grpc_error* CommonTlsContextParse(
+grpc_error_handle CommonTlsContextParse(
     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
         common_tls_context_proto,
     XdsApi::CommonTlsContext* common_tls_context) {
@@ -1796,31 +1800,31 @@ grpc_error* CommonTlsContextParse(
         std::string matcher;
         if (envoy_type_matcher_v3_StringMatcher_has_exact(
                 subject_alt_names_matchers[i])) {
-          type = StringMatcher::Type::EXACT;
+          type = StringMatcher::Type::kExact;
           matcher =
               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_exact(
                   subject_alt_names_matchers[i]));
         } else if (envoy_type_matcher_v3_StringMatcher_has_prefix(
                        subject_alt_names_matchers[i])) {
-          type = StringMatcher::Type::PREFIX;
+          type = StringMatcher::Type::kPrefix;
           matcher =
               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_prefix(
                   subject_alt_names_matchers[i]));
         } else if (envoy_type_matcher_v3_StringMatcher_has_suffix(
                        subject_alt_names_matchers[i])) {
-          type = StringMatcher::Type::SUFFIX;
+          type = StringMatcher::Type::kSuffix;
           matcher =
               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_suffix(
                   subject_alt_names_matchers[i]));
         } else if (envoy_type_matcher_v3_StringMatcher_has_contains(
                        subject_alt_names_matchers[i])) {
-          type = StringMatcher::Type::CONTAINS;
+          type = StringMatcher::Type::kContains;
           matcher =
               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_contains(
                   subject_alt_names_matchers[i]));
         } else if (envoy_type_matcher_v3_StringMatcher_has_safe_regex(
                        subject_alt_names_matchers[i])) {
-          type = StringMatcher::Type::SAFE_REGEX;
+          type = StringMatcher::Type::kSafeRegex;
           auto* regex_matcher = envoy_type_matcher_v3_StringMatcher_safe_regex(
               subject_alt_names_matchers[i]);
           matcher = UpbStringToStdString(
@@ -1840,7 +1844,7 @@ grpc_error* CommonTlsContextParse(
                            string_matcher.status().message())
                   .c_str());
         }
-        if (type == StringMatcher::Type::SAFE_REGEX && ignore_case) {
+        if (type == StringMatcher::Type::kSafeRegex && ignore_case) {
           return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "StringMatcher: ignore_case has no effect for SAFE_REGEX.");
         }
@@ -1870,7 +1874,7 @@ grpc_error* CommonTlsContextParse(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* HttpConnectionManagerParse(
+grpc_error_handle HttpConnectionManagerParse(
     bool is_client, const EncodingContext& context,
     const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager*
         http_connection_manager_proto,
@@ -1925,7 +1929,8 @@ grpc_error* HttpConnectionManagerParse(
                 .c_str());
       }
       absl::string_view filter_type;
-      grpc_error* error = ExtractHttpFilterTypeName(context, any, &filter_type);
+      grpc_error_handle error =
+          ExtractHttpFilterTypeName(context, any, &filter_type);
       if (error != GRPC_ERROR_NONE) return error;
       const XdsHttpFilterImpl* filter_impl =
           XdsHttpFilterRegistry::GetFilterForType(filter_type);
@@ -1974,7 +1979,8 @@ grpc_error* HttpConnectionManagerParse(
           envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_config(
               http_connection_manager_proto);
       XdsApi::RdsUpdate rds_update;
-      grpc_error* error = RouteConfigParse(context, route_config, &rds_update);
+      grpc_error_handle error =
+          RouteConfigParse(context, route_config, &rds_update);
       if (error != GRPC_ERROR_NONE) return error;
       http_connection_manager->rds_update = std::move(rds_update);
       return GRPC_ERROR_NONE;
@@ -2007,7 +2013,7 @@ grpc_error* HttpConnectionManagerParse(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* LdsResponseParseClient(
+grpc_error_handle LdsResponseParseClient(
     const EncodingContext& context,
     const envoy_config_listener_v3_ApiListener* api_listener, bool is_v2,
     XdsApi::LdsUpdate* lds_update) {
@@ -2026,7 +2032,7 @@ grpc_error* LdsResponseParseClient(
                                     &lds_update->http_connection_manager);
 }
 
-grpc_error* DownstreamTlsContextParse(
+grpc_error_handle DownstreamTlsContextParse(
     const EncodingContext& context,
     const envoy_config_core_v3_TransportSocket* transport_socket,
     XdsApi::DownstreamTlsContext* downstream_tls_context) {
@@ -2050,7 +2056,7 @@ grpc_error* DownstreamTlsContextParse(
           envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_common_tls_context(
               downstream_tls_context_proto);
       if (common_tls_context != nullptr) {
-        grpc_error* error = CommonTlsContextParse(
+        grpc_error_handle error = CommonTlsContextParse(
             common_tls_context, &downstream_tls_context->common_tls_context);
         if (error != GRPC_ERROR_NONE) return error;
       }
@@ -2073,13 +2079,13 @@ grpc_error* DownstreamTlsContextParse(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* CidrRangeParse(
+grpc_error_handle CidrRangeParse(
     const envoy_config_core_v3_CidrRange* cidr_range_proto,
     XdsApi::LdsUpdate::FilterChainMap::CidrRange* cidr_range) {
   std::string address_prefix = UpbStringToStdString(
       envoy_config_core_v3_CidrRange_address_prefix(cidr_range_proto));
-  grpc_error* error = grpc_string_to_sockaddr_new(&cidr_range->address,
-                                                  address_prefix.c_str(), 0);
+  grpc_error_handle error =
+      grpc_string_to_sockaddr(&cidr_range->address, address_prefix.c_str(), 0);
   if (error != GRPC_ERROR_NONE) return error;
   cidr_range->prefix_len = 0;
   auto* prefix_len_proto =
@@ -2097,7 +2103,7 @@ grpc_error* CidrRangeParse(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* FilterChainMatchParse(
+grpc_error_handle FilterChainMatchParse(
     const envoy_config_listener_v3_FilterChainMatch* filter_chain_match_proto,
     FilterChain::FilterChainMatch* filter_chain_match) {
   auto* destination_port =
@@ -2113,7 +2119,7 @@ grpc_error* FilterChainMatchParse(
   filter_chain_match->prefix_ranges.reserve(size);
   for (size_t i = 0; i < size; i++) {
     XdsApi::LdsUpdate::FilterChainMap::CidrRange cidr_range;
-    grpc_error* error = CidrRangeParse(prefix_ranges[i], &cidr_range);
+    grpc_error_handle error = CidrRangeParse(prefix_ranges[i], &cidr_range);
     if (error != GRPC_ERROR_NONE) return error;
     filter_chain_match->prefix_ranges.push_back(cidr_range);
   }
@@ -2127,7 +2133,8 @@ grpc_error* FilterChainMatchParse(
   filter_chain_match->source_prefix_ranges.reserve(size);
   for (size_t i = 0; i < size; i++) {
     XdsApi::LdsUpdate::FilterChainMap::CidrRange cidr_range;
-    grpc_error* error = CidrRangeParse(source_prefix_ranges[i], &cidr_range);
+    grpc_error_handle error =
+        CidrRangeParse(source_prefix_ranges[i], &cidr_range);
     if (error != GRPC_ERROR_NONE) return error;
     filter_chain_match->source_prefix_ranges.push_back(cidr_range);
   }
@@ -2156,11 +2163,11 @@ grpc_error* FilterChainMatchParse(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* FilterChainParse(
+grpc_error_handle FilterChainParse(
     const EncodingContext& context,
     const envoy_config_listener_v3_FilterChain* filter_chain_proto, bool is_v2,
     FilterChain* filter_chain) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto* filter_chain_match =
       envoy_config_listener_v3_FilterChain_filter_chain_match(
           filter_chain_proto);
@@ -2223,8 +2230,8 @@ grpc_error* FilterChainParse(
   return error;
 }
 
-grpc_error* AddressParse(const envoy_config_core_v3_Address* address_proto,
-                         std::string* address) {
+grpc_error_handle AddressParse(
+    const envoy_config_core_v3_Address* address_proto, std::string* address) {
   const auto* socket_address =
       envoy_config_core_v3_Address_socket_address(address_proto);
   if (socket_address == nullptr) {
@@ -2263,7 +2270,7 @@ struct InternalFilterChainMap {
   DestinationIpMap destination_ip_map;
 };
 
-grpc_error* AddFilterChainDataForSourcePort(
+grpc_error_handle AddFilterChainDataForSourcePort(
     const FilterChain& filter_chain,
     XdsApi::LdsUpdate::FilterChainMap::SourcePortsMap* ports_map,
     uint32_t port) {
@@ -2280,14 +2287,14 @@ grpc_error* AddFilterChainDataForSourcePort(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* AddFilterChainDataForSourcePorts(
+grpc_error_handle AddFilterChainDataForSourcePorts(
     const FilterChain& filter_chain,
     XdsApi::LdsUpdate::FilterChainMap::SourcePortsMap* ports_map) {
   if (filter_chain.filter_chain_match.source_ports.empty()) {
     return AddFilterChainDataForSourcePort(filter_chain, ports_map, 0);
   } else {
     for (uint32_t port : filter_chain.filter_chain_match.source_ports) {
-      grpc_error* error =
+      grpc_error_handle error =
           AddFilterChainDataForSourcePort(filter_chain, ports_map, port);
       if (error != GRPC_ERROR_NONE) return error;
     }
@@ -2295,7 +2302,7 @@ grpc_error* AddFilterChainDataForSourcePorts(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* AddFilterChainDataForSourceIpRange(
+grpc_error_handle AddFilterChainDataForSourceIpRange(
     const FilterChain& filter_chain,
     InternalFilterChainMap::SourceIpMap* source_ip_map) {
   if (filter_chain.filter_chain_match.source_prefix_ranges.empty()) {
@@ -2313,7 +2320,7 @@ grpc_error* AddFilterChainDataForSourceIpRange(
       if (insert_result.second) {
         insert_result.first->second.prefix_range.emplace(prefix_range);
       }
-      grpc_error* error = AddFilterChainDataForSourcePorts(
+      grpc_error_handle error = AddFilterChainDataForSourcePorts(
           filter_chain, &insert_result.first->second.ports_map);
       if (error != GRPC_ERROR_NONE) return error;
     }
@@ -2321,7 +2328,7 @@ grpc_error* AddFilterChainDataForSourceIpRange(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* AddFilterChainDataForSourceType(
+grpc_error_handle AddFilterChainDataForSourceType(
     const FilterChain& filter_chain,
     InternalFilterChainMap::DestinationIp* destination_ip) {
   GPR_ASSERT(static_cast<unsigned int>(
@@ -2331,7 +2338,7 @@ grpc_error* AddFilterChainDataForSourceType(
                         filter_chain.filter_chain_match.source_type)]);
 }
 
-grpc_error* AddFilterChainDataForApplicationProtocols(
+grpc_error_handle AddFilterChainDataForApplicationProtocols(
     const FilterChain& filter_chain,
     InternalFilterChainMap::DestinationIp* destination_ip) {
   // Only allow filter chains that do not mention application protocols
@@ -2341,7 +2348,7 @@ grpc_error* AddFilterChainDataForApplicationProtocols(
   return AddFilterChainDataForSourceType(filter_chain, destination_ip);
 }
 
-grpc_error* AddFilterChainDataForTransportProtocol(
+grpc_error_handle AddFilterChainDataForTransportProtocol(
     const FilterChain& filter_chain,
     InternalFilterChainMap::DestinationIp* destination_ip) {
   const std::string& transport_protocol =
@@ -2369,7 +2376,7 @@ grpc_error* AddFilterChainDataForTransportProtocol(
                                                    destination_ip);
 }
 
-grpc_error* AddFilterChainDataForServerNames(
+grpc_error_handle AddFilterChainDataForServerNames(
     const FilterChain& filter_chain,
     InternalFilterChainMap::DestinationIp* destination_ip) {
   // Don't continue adding filter chains with server names mentioned
@@ -2379,7 +2386,7 @@ grpc_error* AddFilterChainDataForServerNames(
   return AddFilterChainDataForTransportProtocol(filter_chain, destination_ip);
 }
 
-grpc_error* AddFilterChainDataForDestinationIpRange(
+grpc_error_handle AddFilterChainDataForDestinationIpRange(
     const FilterChain& filter_chain,
     InternalFilterChainMap::DestinationIpMap* destination_ip_map) {
   if (filter_chain.filter_chain_match.prefix_ranges.empty()) {
@@ -2397,7 +2404,7 @@ grpc_error* AddFilterChainDataForDestinationIpRange(
       if (insert_result.second) {
         insert_result.first->second.prefix_range.emplace(prefix_range);
       }
-      grpc_error* error = AddFilterChainDataForServerNames(
+      grpc_error_handle error = AddFilterChainDataForServerNames(
           filter_chain, &insert_result.first->second);
       if (error != GRPC_ERROR_NONE) return error;
     }
@@ -2424,14 +2431,14 @@ XdsApi::LdsUpdate::FilterChainMap BuildFromInternalFilterChainMap(
   return filter_chain_map;
 }
 
-grpc_error* BuildFilterChainMap(
+grpc_error_handle BuildFilterChainMap(
     const std::vector<FilterChain>& filter_chains,
     XdsApi::LdsUpdate::FilterChainMap* filter_chain_map) {
   InternalFilterChainMap internal_filter_chain_map;
   for (const auto& filter_chain : filter_chains) {
     // Discard filter chain entries that specify destination port
     if (filter_chain.filter_chain_match.destination_port != 0) continue;
-    grpc_error* error = AddFilterChainDataForDestinationIpRange(
+    grpc_error_handle error = AddFilterChainDataForDestinationIpRange(
         filter_chain, &internal_filter_chain_map.destination_ip_map);
     if (error != GRPC_ERROR_NONE) return error;
   }
@@ -2440,12 +2447,12 @@ grpc_error* BuildFilterChainMap(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* LdsResponseParseServer(
+grpc_error_handle LdsResponseParseServer(
     const EncodingContext& context,
     const envoy_config_listener_v3_Listener* listener, bool is_v2,
     XdsApi::LdsUpdate* lds_update) {
   lds_update->type = XdsApi::LdsUpdate::ListenerType::kTcpListener;
-  grpc_error* error =
+  grpc_error_handle error =
       AddressParse(envoy_config_listener_v3_Listener_address(listener),
                    &lds_update->address);
   if (error != GRPC_ERROR_NONE) return error;
@@ -2489,13 +2496,13 @@ grpc_error* LdsResponseParseServer(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* LdsResponseParse(
+grpc_error_handle LdsResponseParse(
     const EncodingContext& context,
     const envoy_service_discovery_v3_DiscoveryResponse* response,
     const std::set<absl::string_view>& expected_listener_names,
     XdsApi::LdsUpdateMap* lds_update_map,
     std::set<std::string>* resource_names_failed) {
-  std::vector<grpc_error*> errors;
+  std::vector<grpc_error_handle> errors;
   // Get the resources from the response.
   size_t size;
   const google_protobuf_Any* const* resources =
@@ -2564,7 +2571,7 @@ grpc_error* LdsResponseParse(
       resource_names_failed->insert(listener_name);
       continue;
     }
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     if (api_listener != nullptr) {
       error = LdsResponseParseClient(context, api_listener, is_v2, &lds_update);
     } else {
@@ -2581,13 +2588,13 @@ grpc_error* LdsResponseParse(
   return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing LDS response", &errors);
 }
 
-grpc_error* RdsResponseParse(
+grpc_error_handle RdsResponseParse(
     const EncodingContext& context,
     const envoy_service_discovery_v3_DiscoveryResponse* response,
     const std::set<absl::string_view>& expected_route_configuration_names,
     XdsApi::RdsUpdateMap* rds_update_map,
     std::set<std::string>* resource_names_failed) {
-  std::vector<grpc_error*> errors;
+  std::vector<grpc_error_handle> errors;
   // Get the resources from the response.
   size_t size;
   const google_protobuf_Any* const* resources =
@@ -2638,7 +2645,8 @@ grpc_error* RdsResponseParse(
     rds_resource_data.serialized_proto =
         UpbStringToStdString(encoded_route_config);
     // Parse the route_config.
-    grpc_error* error = RouteConfigParse(context, route_config, &rds_update);
+    grpc_error_handle error =
+        RouteConfigParse(context, route_config, &rds_update);
     if (error != GRPC_ERROR_NONE) {
       errors.push_back(grpc_error_add_child(
           GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -2650,13 +2658,13 @@ grpc_error* RdsResponseParse(
   return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing RDS response", &errors);
 }
 
-grpc_error* CdsResponseParse(
+grpc_error_handle CdsResponseParse(
     const EncodingContext& context,
     const envoy_service_discovery_v3_DiscoveryResponse* response,
     const std::set<absl::string_view>& expected_cluster_names,
     XdsApi::CdsUpdateMap* cds_update_map,
     std::set<std::string>* resource_names_failed) {
-  std::vector<grpc_error*> errors;
+  std::vector<grpc_error_handle> errors;
   // Get the resources from the response.
   size_t size;
   const google_protobuf_Any* const* resources =
@@ -2912,7 +2920,7 @@ grpc_error* CdsResponseParse(
                 envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_common_tls_context(
                     upstream_tls_context);
             if (common_tls_context != nullptr) {
-              grpc_error* error = CommonTlsContextParse(
+              grpc_error_handle error = CommonTlsContextParse(
                   common_tls_context, &cds_update.common_tls_context);
               if (error != GRPC_ERROR_NONE) {
                 errors.push_back(grpc_error_add_child(
@@ -2983,7 +2991,7 @@ grpc_error* CdsResponseParse(
   return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing CDS response", &errors);
 }
 
-grpc_error* ServerAddressParseAndAppend(
+grpc_error_handle ServerAddressParseAndAppend(
     const envoy_config_endpoint_v3_LbEndpoint* lb_endpoint,
     ServerAddressList* list) {
   // If health_status is not HEALTHY or UNKNOWN, skip this endpoint.
@@ -3008,15 +3016,15 @@ grpc_error* ServerAddressParseAndAppend(
   }
   // Populate grpc_resolved_address.
   grpc_resolved_address addr;
-  grpc_error* error =
-      grpc_string_to_sockaddr_new(&addr, address_str.c_str(), port);
+  grpc_error_handle error =
+      grpc_string_to_sockaddr(&addr, address_str.c_str(), port);
   if (error != GRPC_ERROR_NONE) return error;
   // Append the address to the list.
   list->emplace_back(addr, nullptr);
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* LocalityParse(
+grpc_error_handle LocalityParse(
     const envoy_config_endpoint_v3_LocalityLbEndpoints* locality_lb_endpoints,
     XdsApi::EdsUpdate::Priority::Locality* output_locality, size_t* priority) {
   // Parse LB weight.
@@ -3050,7 +3058,7 @@ grpc_error* LocalityParse(
       envoy_config_endpoint_v3_LocalityLbEndpoints_lb_endpoints(
           locality_lb_endpoints, &size);
   for (size_t i = 0; i < size; ++i) {
-    grpc_error* error = ServerAddressParseAndAppend(
+    grpc_error_handle error = ServerAddressParseAndAppend(
         lb_endpoints[i], &output_locality->endpoints);
     if (error != GRPC_ERROR_NONE) return error;
   }
@@ -3060,7 +3068,7 @@ grpc_error* LocalityParse(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* DropParseAndAppend(
+grpc_error_handle DropParseAndAppend(
     const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload*
         drop_overload,
     XdsApi::EdsUpdate::DropConfig* drop_config) {
@@ -3099,13 +3107,13 @@ grpc_error* DropParseAndAppend(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* EdsResponseParse(
+grpc_error_handle EdsResponseParse(
     const EncodingContext& context,
     const envoy_service_discovery_v3_DiscoveryResponse* response,
     const std::set<absl::string_view>& expected_eds_service_names,
     XdsApi::EdsUpdateMap* eds_update_map,
     std::set<std::string>* resource_names_failed) {
-  std::vector<grpc_error*> errors;
+  std::vector<grpc_error_handle> errors;
   // Get the resources from the response.
   size_t size;
   const google_protobuf_Any* const* resources =
@@ -3162,7 +3170,7 @@ grpc_error* EdsResponseParse(
     const envoy_config_endpoint_v3_LocalityLbEndpoints* const* endpoints =
         envoy_config_endpoint_v3_ClusterLoadAssignment_endpoints(
             cluster_load_assignment, &locality_size);
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     for (size_t j = 0; j < locality_size; ++j) {
       size_t priority;
       XdsApi::EdsUpdate::Priority::Locality locality;
@@ -3476,10 +3484,10 @@ grpc_slice XdsApi::CreateLrsRequest(
   return SerializeLrsRequest(context, request);
 }
 
-grpc_error* XdsApi::ParseLrsResponse(const grpc_slice& encoded_response,
-                                     bool* send_all_clusters,
-                                     std::set<std::string>* cluster_names,
-                                     grpc_millis* load_reporting_interval) {
+grpc_error_handle XdsApi::ParseLrsResponse(
+    const grpc_slice& encoded_response, bool* send_all_clusters,
+    std::set<std::string>* cluster_names,
+    grpc_millis* load_reporting_interval) {
   upb::Arena arena;
   // Decode the response.
   const envoy_service_load_stats_v3_LoadStatsResponse* decoded_response =
index b8e46da..e7bf1cd 100644 (file)
@@ -609,7 +609,7 @@ class XdsApi {
   // Otherwise, one of the *_update_map fields will be populated, based
   // on the type_url field.
   struct AdsParseResult {
-    grpc_error* parse_error = GRPC_ERROR_NONE;
+    grpc_error_handle parse_error = GRPC_ERROR_NONE;
     std::string version;
     std::string nonce;
     std::string type_url;
@@ -628,7 +628,7 @@ class XdsApi {
                               const std::string& type_url,
                               const std::set<absl::string_view>& resource_names,
                               const std::string& version,
-                              const std::string& nonce, grpc_error* error,
+                              const std::string& nonce, grpc_error_handle error,
                               bool populate_node);
 
   // Parses an ADS response.
@@ -648,10 +648,10 @@ class XdsApi {
   // Parses the LRS response and returns \a
   // load_reporting_interval for client-side load reporting. If there is any
   // error, the output config is invalid.
-  grpc_error* ParseLrsResponse(const grpc_slice& encoded_response,
-                               bool* send_all_clusters,
-                               std::set<std::string>* cluster_names,
-                               grpc_millis* load_reporting_interval);
+  grpc_error_handle ParseLrsResponse(const grpc_slice& encoded_response,
+                                     bool* send_all_clusters,
+                                     std::set<std::string>* cluster_names,
+                                     grpc_millis* load_reporting_interval);
 
   // Assemble the client config proto message and return the serialized result.
   std::string AssembleClientConfig(
index 9cb819a..33cf276 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "src/core/ext/xds/certificate_provider_registry.h"
 #include "src/core/ext/xds/xds_api.h"
-#include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "src/core/lib/security/credentials/credentials.h"
@@ -81,142 +80,27 @@ bool XdsBootstrap::XdsServer::ShouldUseV3() const {
 // XdsBootstrap
 //
 
-namespace {
-
-std::string BootstrapString(const XdsBootstrap& bootstrap) {
-  std::vector<std::string> parts;
-  if (bootstrap.node() != nullptr) {
-    parts.push_back(absl::StrFormat(
-        "node={\n"
-        "  id=\"%s\",\n"
-        "  cluster=\"%s\",\n"
-        "  locality={\n"
-        "    region=\"%s\",\n"
-        "    zone=\"%s\",\n"
-        "    sub_zone=\"%s\"\n"
-        "  },\n"
-        "  metadata=%s,\n"
-        "},\n",
-        bootstrap.node()->id, bootstrap.node()->cluster,
-        bootstrap.node()->locality_region, bootstrap.node()->locality_zone,
-        bootstrap.node()->locality_sub_zone,
-        bootstrap.node()->metadata.Dump()));
-  }
-  parts.push_back(absl::StrFormat(
-      "servers=[\n"
-      "  {\n"
-      "    uri=\"%s\",\n"
-      "    creds_type=%s,\n",
-      bootstrap.server().server_uri, bootstrap.server().channel_creds_type));
-  if (bootstrap.server().channel_creds_config.type() != Json::Type::JSON_NULL) {
-    parts.push_back(
-        absl::StrFormat("    creds_config=%s,",
-                        bootstrap.server().channel_creds_config.Dump()));
-  }
-  if (!bootstrap.server().server_features.empty()) {
-    parts.push_back(absl::StrCat(
-        "    server_features=[",
-        absl::StrJoin(bootstrap.server().server_features, ", "), "],\n"));
-  }
-  parts.push_back("  }\n],\n");
-  if (!bootstrap.server_listener_resource_name_template().empty()) {
-    parts.push_back(
-        absl::StrFormat("server_listener_resource_name_template=\"%s\",\n",
-                        bootstrap.server_listener_resource_name_template()));
-  }
-  parts.push_back("certificate_providers={\n");
-  for (const auto& entry : bootstrap.certificate_providers()) {
-    parts.push_back(
-        absl::StrFormat("  %s={\n"
-                        "    plugin_name=%s\n"
-                        "    config=%s\n"
-                        "  },\n",
-                        entry.first, entry.second.plugin_name,
-                        entry.second.config->ToString()));
-  }
-  parts.push_back("}");
-  return absl::StrJoin(parts, "");
-}
-
-std::unique_ptr<XdsBootstrap> ParseJsonAndCreate(
-    XdsClient* client, TraceFlag* tracer, absl::string_view json_string,
-    absl::string_view bootstrap_source, grpc_error** error) {
+std::unique_ptr<XdsBootstrap> XdsBootstrap::Create(
+    absl::string_view json_string, grpc_error_handle* error) {
   Json json = Json::Parse(json_string, error);
   if (*error != GRPC_ERROR_NONE) {
-    grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(
-        absl::StrCat("Failed to parse bootstrap from ", bootstrap_source)
-            .c_str(),
-        error, 1);
+    grpc_error_handle error_out =
+        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+            "Failed to parse bootstrap JSON string", error, 1);
     GRPC_ERROR_UNREF(*error);
     *error = error_out;
     return nullptr;
   }
-  std::unique_ptr<XdsBootstrap> result =
-      absl::make_unique<XdsBootstrap>(std::move(json), error);
-  if (*error == GRPC_ERROR_NONE && GRPC_TRACE_FLAG_ENABLED(*tracer)) {
-    gpr_log(GPR_INFO,
-            "[xds_client %p] Bootstrap config for creating xds client:\n%s",
-            client, BootstrapString(*result).c_str());
-  }
-  return result;
-}
-
-}  // namespace
-
-std::unique_ptr<XdsBootstrap> XdsBootstrap::Create(XdsClient* client,
-                                                   TraceFlag* tracer,
-                                                   const char* fallback_config,
-                                                   grpc_error** error) {
-  // First, try GRPC_XDS_BOOTSTRAP env var.
-  grpc_core::UniquePtr<char> path(gpr_getenv("GRPC_XDS_BOOTSTRAP"));
-  if (path != nullptr) {
-    if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
-      gpr_log(GPR_INFO,
-              "[xds_client %p] Got bootstrap file location from "
-              "GRPC_XDS_BOOTSTRAP environment variable: %s",
-              client, path.get());
-    }
-    grpc_slice contents;
-    *error =
-        grpc_load_file(path.get(), /*add_null_terminator=*/true, &contents);
-    if (*error != GRPC_ERROR_NONE) return nullptr;
-    absl::string_view contents_str_view = StringViewFromSlice(contents);
-    if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
-      gpr_log(GPR_DEBUG, "[xds_client %p] Bootstrap file contents: %s", client,
-              std::string(contents_str_view).c_str());
-    }
-    std::string bootstrap_source = absl::StrCat("file ", path.get());
-    auto result = ParseJsonAndCreate(client, tracer, contents_str_view,
-                                     bootstrap_source, error);
-    grpc_slice_unref_internal(contents);
-    return result;
-  }
-  // Next, try GRPC_XDS_BOOTSTRAP_CONFIG env var.
-  grpc_core::UniquePtr<char> env_config(
-      gpr_getenv("GRPC_XDS_BOOTSTRAP_CONFIG"));
-  if (env_config != nullptr) {
-    return ParseJsonAndCreate(client, tracer, env_config.get(),
-                              "GRPC_XDS_BOOTSTRAP_CONFIG env var", error);
-  }
-  // Finally, try fallback config.
-  if (fallback_config != nullptr) {
-    return ParseJsonAndCreate(client, tracer, fallback_config,
-                              "fallback config", error);
-  }
-  // No bootstrap config found.
-  *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-      "Environment variables GRPC_XDS_BOOTSTRAP or GRPC_XDS_BOOTSTRAP_CONFIG "
-      "not defined");
-  return nullptr;
+  return absl::make_unique<XdsBootstrap>(std::move(json), error);
 }
 
-XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) {
+XdsBootstrap::XdsBootstrap(Json json, grpc_error_handle* error) {
   if (json.type() != Json::Type::OBJECT) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "malformed JSON in bootstrap file");
     return;
   }
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   auto it = json.mutable_object()->find("xds_servers");
   if (it == json.mutable_object()->end()) {
     error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -225,7 +109,7 @@ XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) {
     error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "\"xds_servers\" field is not an array"));
   } else {
-    grpc_error* parse_error = ParseXdsServerList(&it->second);
+    grpc_error_handle parse_error = ParseXdsServerList(&it->second);
     if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
   }
   it = json.mutable_object()->find("node");
@@ -234,7 +118,7 @@ XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "\"node\" field is not an object"));
     } else {
-      grpc_error* parse_error = ParseNode(&it->second);
+      grpc_error_handle parse_error = ParseNode(&it->second);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
@@ -255,7 +139,7 @@ XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) {
         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
             "\"certificate_providers\" field is not an object"));
       } else {
-        grpc_error* parse_error = ParseCertificateProviders(&it->second);
+        grpc_error_handle parse_error = ParseCertificateProviders(&it->second);
         if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
       }
     }
@@ -264,15 +148,15 @@ XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) {
                                          &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseXdsServerList(Json* json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseXdsServerList(Json* json) {
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < json->mutable_array()->size(); ++i) {
     Json& child = json->mutable_array()->at(i);
     if (child.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("array element ", i, " is not an object").c_str()));
     } else {
-      grpc_error* parse_error = ParseXdsServer(&child, i);
+      grpc_error_handle parse_error = ParseXdsServer(&child, i);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
@@ -280,8 +164,8 @@ grpc_error* XdsBootstrap::ParseXdsServerList(Json* json) {
                                        &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseXdsServer(Json* json, size_t idx) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseXdsServer(Json* json, size_t idx) {
+  std::vector<grpc_error_handle> error_list;
   servers_.emplace_back();
   XdsServer& server = servers_[servers_.size() - 1];
   auto it = json->mutable_object()->find("server_uri");
@@ -302,7 +186,8 @@ grpc_error* XdsBootstrap::ParseXdsServer(Json* json, size_t idx) {
     error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "\"channel_creds\" field is not an array"));
   } else {
-    grpc_error* parse_error = ParseChannelCredsArray(&it->second, &server);
+    grpc_error_handle parse_error =
+        ParseChannelCredsArray(&it->second, &server);
     if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
   }
   it = json->mutable_object()->find("server_features");
@@ -311,14 +196,15 @@ grpc_error* XdsBootstrap::ParseXdsServer(Json* json, size_t idx) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "\"server_features\" field is not an array"));
     } else {
-      grpc_error* parse_error = ParseServerFeaturesArray(&it->second, &server);
+      grpc_error_handle parse_error =
+          ParseServerFeaturesArray(&it->second, &server);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
   // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
   // string is not static in this case.
   if (error_list.empty()) return GRPC_ERROR_NONE;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrCat("errors parsing index ", idx).c_str());
   for (size_t i = 0; i < error_list.size(); ++i) {
     error = grpc_error_add_child(error, error_list[i]);
@@ -326,16 +212,16 @@ grpc_error* XdsBootstrap::ParseXdsServer(Json* json, size_t idx) {
   return error;
 }
 
-grpc_error* XdsBootstrap::ParseChannelCredsArray(Json* json,
-                                                 XdsServer* server) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseChannelCredsArray(Json* json,
+                                                       XdsServer* server) {
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < json->mutable_array()->size(); ++i) {
     Json& child = json->mutable_array()->at(i);
     if (child.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("array element ", i, " is not an object").c_str()));
     } else {
-      grpc_error* parse_error = ParseChannelCreds(&child, i, server);
+      grpc_error_handle parse_error = ParseChannelCreds(&child, i, server);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
@@ -347,9 +233,9 @@ grpc_error* XdsBootstrap::ParseChannelCredsArray(Json* json,
                                        &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseChannelCreds(Json* json, size_t idx,
-                                            XdsServer* server) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseChannelCreds(Json* json, size_t idx,
+                                                  XdsServer* server) {
+  std::vector<grpc_error_handle> error_list;
   std::string type;
   auto it = json->mutable_object()->find("type");
   if (it == json->mutable_object()->end()) {
@@ -385,7 +271,7 @@ grpc_error* XdsBootstrap::ParseChannelCreds(Json* json, size_t idx,
   // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
   // string is not static in this case.
   if (error_list.empty()) return GRPC_ERROR_NONE;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrCat("errors parsing index ", idx).c_str());
   for (size_t i = 0; i < error_list.size(); ++i) {
     error = grpc_error_add_child(error, error_list[i]);
@@ -393,9 +279,9 @@ grpc_error* XdsBootstrap::ParseChannelCreds(Json* json, size_t idx,
   return error;
 }
 
-grpc_error* XdsBootstrap::ParseServerFeaturesArray(Json* json,
-                                                   XdsServer* server) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseServerFeaturesArray(Json* json,
+                                                         XdsServer* server) {
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < json->mutable_array()->size(); ++i) {
     Json& child = json->mutable_array()->at(i);
     if (child.type() == Json::Type::STRING &&
@@ -407,8 +293,8 @@ grpc_error* XdsBootstrap::ParseServerFeaturesArray(Json* json,
       "errors parsing \"server_features\" array", &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseNode(Json* json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseNode(Json* json) {
+  std::vector<grpc_error_handle> error_list;
   node_ = absl::make_unique<Node>();
   auto it = json->mutable_object()->find("id");
   if (it != json->mutable_object()->end()) {
@@ -434,7 +320,7 @@ grpc_error* XdsBootstrap::ParseNode(Json* json) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "\"locality\" field is not an object"));
     } else {
-      grpc_error* parse_error = ParseLocality(&it->second);
+      grpc_error_handle parse_error = ParseLocality(&it->second);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
@@ -451,8 +337,8 @@ grpc_error* XdsBootstrap::ParseNode(Json* json) {
                                        &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseLocality(Json* json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseLocality(Json* json) {
+  std::vector<grpc_error_handle> error_list;
   auto it = json->mutable_object()->find("region");
   if (it != json->mutable_object()->end()) {
     if (it->second.type() != Json::Type::STRING) {
@@ -484,8 +370,8 @@ grpc_error* XdsBootstrap::ParseLocality(Json* json) {
                                        &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseCertificateProviders(Json* json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseCertificateProviders(Json* json) {
+  std::vector<grpc_error_handle> error_list;
   for (auto& certificate_provider : *(json->mutable_object())) {
     if (certificate_provider.second.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -493,7 +379,7 @@ grpc_error* XdsBootstrap::ParseCertificateProviders(Json* json) {
                        "\" is not an object")
               .c_str()));
     } else {
-      grpc_error* parse_error = ParseCertificateProvider(
+      grpc_error_handle parse_error = ParseCertificateProvider(
           certificate_provider.first, &certificate_provider.second);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
@@ -502,9 +388,9 @@ grpc_error* XdsBootstrap::ParseCertificateProviders(Json* json) {
       "errors parsing \"certificate_providers\" object", &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseCertificateProvider(
+grpc_error_handle XdsBootstrap::ParseCertificateProvider(
     const std::string& instance_name, Json* certificate_provider_json) {
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   auto it = certificate_provider_json->mutable_object()->find("plugin_name");
   if (it == certificate_provider_json->mutable_object()->end()) {
     error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -525,14 +411,14 @@ grpc_error* XdsBootstrap::ParseCertificateProvider(
           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "\"config\" field is not an object"));
         } else {
-          grpc_error* parse_error = GRPC_ERROR_NONE;
+          grpc_error_handle parse_error = GRPC_ERROR_NONE;
           config = factory->CreateCertificateProviderConfig(it->second,
                                                             &parse_error);
           if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
         }
       } else {
         // "config" is an optional field, so create an empty JSON object.
-        grpc_error* parse_error = GRPC_ERROR_NONE;
+        grpc_error_handle parse_error = GRPC_ERROR_NONE;
         config = factory->CreateCertificateProviderConfig(Json::Object(),
                                                           &parse_error);
         if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
@@ -544,7 +430,7 @@ grpc_error* XdsBootstrap::ParseCertificateProvider(
   // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
   // string is not static in this case.
   if (error_list.empty()) return GRPC_ERROR_NONE;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrCat("errors parsing element \"", instance_name, "\"").c_str());
   for (size_t i = 0; i < error_list.size(); ++i) {
     error = grpc_error_add_child(error, error_list[i]);
@@ -552,4 +438,56 @@ grpc_error* XdsBootstrap::ParseCertificateProvider(
   return error;
 }
 
+std::string XdsBootstrap::ToString() const {
+  std::vector<std::string> parts;
+  if (node_ != nullptr) {
+    parts.push_back(absl::StrFormat(
+        "node={\n"
+        "  id=\"%s\",\n"
+        "  cluster=\"%s\",\n"
+        "  locality={\n"
+        "    region=\"%s\",\n"
+        "    zone=\"%s\",\n"
+        "    sub_zone=\"%s\"\n"
+        "  },\n"
+        "  metadata=%s,\n"
+        "},\n",
+        node_->id, node_->cluster, node_->locality_region, node_->locality_zone,
+        node_->locality_sub_zone, node_->metadata.Dump()));
+  }
+  parts.push_back(
+      absl::StrFormat("servers=[\n"
+                      "  {\n"
+                      "    uri=\"%s\",\n"
+                      "    creds_type=%s,\n",
+                      server().server_uri, server().channel_creds_type));
+  if (server().channel_creds_config.type() != Json::Type::JSON_NULL) {
+    parts.push_back(absl::StrFormat("    creds_config=%s,",
+                                    server().channel_creds_config.Dump()));
+  }
+  if (!server().server_features.empty()) {
+    parts.push_back(absl::StrCat("    server_features=[",
+                                 absl::StrJoin(server().server_features, ", "),
+                                 "],\n"));
+  }
+  parts.push_back("  }\n],\n");
+  if (!server_listener_resource_name_template_.empty()) {
+    parts.push_back(
+        absl::StrFormat("server_listener_resource_name_template=\"%s\",\n",
+                        server_listener_resource_name_template_));
+  }
+  parts.push_back("certificate_providers={\n");
+  for (const auto& entry : certificate_providers_) {
+    parts.push_back(
+        absl::StrFormat("  %s={\n"
+                        "    plugin_name=%s\n"
+                        "    config=%s\n"
+                        "  },\n",
+                        entry.first, entry.second.plugin_name,
+                        entry.second.config->ToString()));
+  }
+  parts.push_back("}");
+  return absl::StrJoin(parts, "");
+}
+
 }  // namespace grpc_core
index d69650d..eff5e7a 100644 (file)
@@ -67,22 +67,16 @@ class XdsBootstrap {
     bool ShouldUseV3() const;
   };
 
-  // Creates bootstrap object, obtaining the bootstrap JSON as appropriate
-  // for the environment:
-  // - If the GRPC_XDS_BOOTSTRAP env var is set, reads the file it specifies
-  //   to obtain the bootstrap JSON.
-  // - Otherwise, if the GRPC_XDS_BOOTSTRAP_CONFIG env var is set, reads the
-  //   content of that env var to obtain the bootstrap JSON.
-  // - Otherwise, the JSON will be read from fallback_config (if non-null).
+  // Creates bootstrap object from json_string.
   // If *error is not GRPC_ERROR_NONE after returning, then there was an
-  // error (e.g., no config found or error reading the file).
-  static std::unique_ptr<XdsBootstrap> Create(XdsClient* client,
-                                              TraceFlag* tracer,
-                                              const char* fallback_config,
-                                              grpc_error** error);
+  // error parsing the contents.
+  static std::unique_ptr<XdsBootstrap> Create(absl::string_view json_string,
+                                              grpc_error_handle* error);
 
-  // Do not instantiate directly -- use ReadFromFile() above instead.
-  XdsBootstrap(Json json, grpc_error** error);
+  // Do not instantiate directly -- use Create() above instead.
+  XdsBootstrap(Json json, grpc_error_handle* error);
+
+  std::string ToString() const;
 
   // TODO(roth): We currently support only one server. Fix this when we
   // add support for fallback for the xds channel.
@@ -98,16 +92,17 @@ class XdsBootstrap {
   }
 
  private:
-  grpc_error* ParseXdsServerList(Json* json);
-  grpc_error* ParseXdsServer(Json* json, size_t idx);
-  grpc_error* ParseChannelCredsArray(Json* json, XdsServer* server);
-  grpc_error* ParseChannelCreds(Json* json, size_t idx, XdsServer* server);
-  grpc_error* ParseServerFeaturesArray(Json* json, XdsServer* server);
-  grpc_error* ParseNode(Json* json);
-  grpc_error* ParseLocality(Json* json);
-  grpc_error* ParseCertificateProviders(Json* json);
-  grpc_error* ParseCertificateProvider(const std::string& instance_name,
-                                       Json* certificate_provider_json);
+  grpc_error_handle ParseXdsServerList(Json* json);
+  grpc_error_handle ParseXdsServer(Json* json, size_t idx);
+  grpc_error_handle ParseChannelCredsArray(Json* json, XdsServer* server);
+  grpc_error_handle ParseChannelCreds(Json* json, size_t idx,
+                                      XdsServer* server);
+  grpc_error_handle ParseServerFeaturesArray(Json* json, XdsServer* server);
+  grpc_error_handle ParseNode(Json* json);
+  grpc_error_handle ParseLocality(Json* json);
+  grpc_error_handle ParseCertificateProviders(Json* json);
+  grpc_error_handle ParseCertificateProvider(const std::string& instance_name,
+                                             Json* certificate_provider_json);
 
   absl::InlinedVector<XdsServer, 1> servers_;
   std::unique_ptr<Node> node_;
index 7e84d5f..ce1ba67 100644 (file)
@@ -51,8 +51,8 @@ class RootCertificatesWatcher
     }
   }
 
-  void OnError(grpc_error* root_cert_error,
-               grpc_error* identity_cert_error) override {
+  void OnError(grpc_error_handle root_cert_error,
+               grpc_error_handle identity_cert_error) override {
     if (root_cert_error != GRPC_ERROR_NONE) {
       parent_->SetErrorForCert(cert_name_, root_cert_error /* pass the ref */,
                                absl::nullopt);
@@ -86,8 +86,8 @@ class IdentityCertificatesWatcher
     }
   }
 
-  void OnError(grpc_error* root_cert_error,
-               grpc_error* identity_cert_error) override {
+  void OnError(grpc_error_handle root_cert_error,
+               grpc_error_handle identity_cert_error) override {
     if (identity_cert_error != GRPC_ERROR_NONE) {
       parent_->SetErrorForCert(cert_name_, absl::nullopt,
                                identity_cert_error /* pass the ref */);
index 6b190ca..2f50883 100644 (file)
@@ -127,9 +127,11 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider {
   void WatchStatusCallback(std::string cert_name, bool root_being_watched,
                            bool identity_being_watched);
 
+  RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
+
   Mutex mu_;
   std::map<std::string /*cert_name*/, std::unique_ptr<ClusterCertificateState>>
-      certificate_state_map_;
+      certificate_state_map_ ABSL_GUARDED_BY(mu_);
 
   // Use a separate mutex for san_matchers_ to avoid deadlocks since
   // san_matchers_ needs to be accessed when a handshake is being done and we
@@ -141,9 +143,7 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider {
   // subject_alternative_names_matchers()
   Mutex san_matchers_mu_;
   std::map<std::string /*cluster_name*/, std::vector<StringMatcher>>
-      san_matcher_map_;
-
-  RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
+      san_matcher_map_ ABSL_GUARDED_BY(san_matchers_mu_);
 };
 
 }  // namespace grpc_core
index a258940..ea6c862 100644 (file)
 #ifndef GRPC_CORE_EXT_XDS_XDS_CHANNEL_ARGS_H
 #define GRPC_CORE_EXT_XDS_XDS_CHANNEL_ARGS_H
 
-// Pointer channel arg containing a ref to the XdsClient object.
-#define GRPC_ARG_XDS_CLIENT "grpc.xds_client"
+// Specifies channel args for the xDS client.
+// Used only when GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG
+// is set.
+#define GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS \
+  "grpc.xds_client_channel_args"
 
 // Timeout in milliseconds to wait for a resource to be returned from
 // the xds server before assuming that it does not exist.
index f0b5762..d354999 100644 (file)
@@ -1,20 +1,18 @@
-/*
- *
- * 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.
- *
- */
+//
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 
 #include <grpc/support/port_platform.h>
 
 #include "src/core/ext/xds/xds_client.h"
 #include "src/core/ext/xds/xds_client_stats.h"
 #include "src/core/ext/xds/xds_http_filters.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
@@ -72,9 +71,9 @@ TraceFlag grpc_xds_client_refcount_trace(false, "xds_client_refcount");
 namespace {
 
 Mutex* g_mu = nullptr;
-const grpc_channel_args* g_channel_args = nullptr;
-XdsClient* g_xds_client = nullptr;
-char* g_fallback_bootstrap_config = nullptr;
+const grpc_channel_args* g_channel_args ABSL_GUARDED_BY(*g_mu) = nullptr;
+XdsClient* g_xds_client ABSL_GUARDED_BY(*g_mu) = nullptr;
+char* g_fallback_bootstrap_config ABSL_GUARDED_BY(*g_mu) = nullptr;
 
 }  // namespace
 
@@ -102,8 +101,8 @@ class XdsClient::ChannelState::RetryableCall
  private:
   void StartNewCallLocked();
   void StartRetryTimerLocked();
-  static void OnRetryTimer(void* arg, grpc_error* error);
-  void OnRetryTimerLocked(grpc_error* error);
+  static void OnRetryTimer(void* arg, grpc_error_handle error);
+  void OnRetryTimerLocked(grpc_error_handle error);
 
   // The wrapped xds call that talks to the xds server. It's instantiated
   // every time we start a new call. It's null during call retry backoff.
@@ -135,9 +134,11 @@ class XdsClient::ChannelState::AdsCallState
   XdsClient* xds_client() const { return chand()->xds_client(); }
   bool seen_response() const { return seen_response_; }
 
-  void Subscribe(const std::string& type_url, const std::string& name);
-  void Unsubscribe(const std::string& type_url, const std::string& name,
-                   bool delay_unsubscription);
+  void SubscribeLocked(const std::string& type_url, const std::string& name)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  void UnsubscribeLocked(const std::string& type_url, const std::string& name,
+                         bool delay_unsubscription)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
   bool HasSubscribedResources() const;
 
@@ -178,7 +179,7 @@ class XdsClient::ChannelState::AdsCallState
     }
 
    private:
-    static void OnTimer(void* arg, grpc_error* error) {
+    static void OnTimer(void* arg, grpc_error_handle error) {
       ResourceState* self = static_cast<ResourceState*>(arg);
       {
         MutexLock lock(&self->ads_calld_->xds_client()->mu_);
@@ -188,10 +189,11 @@ class XdsClient::ChannelState::AdsCallState
       self->Unref(DEBUG_LOCATION, "timer");
     }
 
-    void OnTimerLocked(grpc_error* error) {
+    void OnTimerLocked(grpc_error_handle error)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_) {
       if (error == GRPC_ERROR_NONE && timer_pending_) {
         timer_pending_ = false;
-        grpc_error* watcher_error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        grpc_error_handle watcher_error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrFormat(
                 "timeout obtaining resource {type=%s name=%s} from xds server",
                 type_url_, name_)
@@ -200,7 +202,7 @@ class XdsClient::ChannelState::AdsCallState
             watcher_error, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
         if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
           gpr_log(GPR_INFO, "[xds_client %p] %s", ads_calld_->xds_client(),
-                  grpc_error_string(watcher_error));
+                  grpc_error_std_string(watcher_error).c_str());
         }
         if (type_url_ == XdsApi::kLdsTypeUrl) {
           ListenerState& state = ads_calld_->xds_client()->listener_map_[name_];
@@ -250,30 +252,38 @@ class XdsClient::ChannelState::AdsCallState
 
     // Nonce and error for this resource type.
     std::string nonce;
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
 
     // Subscribed resources of this type.
     std::map<std::string /* name */, OrphanablePtr<ResourceState>>
         subscribed_resources;
   };
 
-  void SendMessageLocked(const std::string& type_url);
-
-  void AcceptLdsUpdate(std::string version, grpc_millis update_time,
-                       XdsApi::LdsUpdateMap lds_update_map);
-  void AcceptRdsUpdate(std::string version, grpc_millis update_time,
-                       XdsApi::RdsUpdateMap rds_update_map);
-  void AcceptCdsUpdate(std::string version, grpc_millis update_time,
-                       XdsApi::CdsUpdateMap cds_update_map);
-  void AcceptEdsUpdate(std::string version, grpc_millis update_time,
-                       XdsApi::EdsUpdateMap eds_update_map);
-
-  static void OnRequestSent(void* arg, grpc_error* error);
-  void OnRequestSentLocked(grpc_error* error);
-  static void OnResponseReceived(void* arg, grpc_error* error);
-  bool OnResponseReceivedLocked();
-  static void OnStatusReceived(void* arg, grpc_error* error);
-  void OnStatusReceivedLocked(grpc_error* error);
+  void SendMessageLocked(const std::string& type_url)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+
+  void AcceptLdsUpdateLocked(std::string version, grpc_millis update_time,
+                             XdsApi::LdsUpdateMap lds_update_map)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  void AcceptRdsUpdateLocked(std::string version, grpc_millis update_time,
+                             XdsApi::RdsUpdateMap rds_update_map)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  void AcceptCdsUpdateLocked(std::string version, grpc_millis update_time,
+                             XdsApi::CdsUpdateMap cds_update_map)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  void AcceptEdsUpdateLocked(std::string version, grpc_millis update_time,
+                             XdsApi::EdsUpdateMap eds_update_map)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+
+  static void OnRequestSent(void* arg, grpc_error_handle error);
+  void OnRequestSentLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  static void OnResponseReceived(void* arg, grpc_error_handle error);
+  bool OnResponseReceivedLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  static void OnStatusReceived(void* arg, grpc_error_handle error);
+  void OnStatusReceivedLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
   bool IsCurrentCallOnChannel() const;
 
@@ -346,12 +356,15 @@ class XdsClient::ChannelState::LrsCallState
     void Orphan() override;
 
    private:
-    void ScheduleNextReportLocked();
-    static void OnNextReportTimer(void* arg, grpc_error* error);
-    bool OnNextReportTimerLocked(grpc_error* error);
-    bool SendReportLocked();
-    static void OnReportDone(void* arg, grpc_error* error);
-    bool OnReportDoneLocked(grpc_error* error);
+    void ScheduleNextReportLocked()
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+    static void OnNextReportTimer(void* arg, grpc_error_handle error);
+    bool OnNextReportTimerLocked(grpc_error_handle error)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+    bool SendReportLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+    static void OnReportDone(void* arg, grpc_error_handle error);
+    bool OnReportDoneLocked(grpc_error_handle error)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
     bool IsCurrentReporterOnCall() const {
       return this == parent_->reporter_.get();
@@ -370,12 +383,15 @@ class XdsClient::ChannelState::LrsCallState
     grpc_closure on_report_done_;
   };
 
-  static void OnInitialRequestSent(void* arg, grpc_error* error);
-  void OnInitialRequestSentLocked();
-  static void OnResponseReceived(void* arg, grpc_error* error);
-  bool OnResponseReceivedLocked();
-  static void OnStatusReceived(void* arg, grpc_error* error);
-  void OnStatusReceivedLocked(grpc_error* error);
+  static void OnInitialRequestSent(void* arg, grpc_error_handle error);
+  void OnInitialRequestSentLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  static void OnResponseReceived(void* arg, grpc_error_handle error);
+  bool OnResponseReceivedLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  static void OnStatusReceived(void* arg, grpc_error_handle error);
+  void OnStatusReceivedLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
   bool IsCurrentCallOnChannel() const;
 
@@ -431,7 +447,7 @@ class XdsClient::ChannelState::StateWatcher
               "[xds_client %p] xds channel in state:TRANSIENT_FAILURE "
               "status_message:(%s)",
               parent_->xds_client(), status.ToString().c_str());
-      parent_->xds_client()->NotifyOnErrorLocked(
+      parent_->xds_client_->NotifyOnErrorLocked(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "xds channel in TRANSIENT_FAILURE"));
     }
@@ -446,26 +462,13 @@ class XdsClient::ChannelState::StateWatcher
 
 namespace {
 
-grpc_channel* CreateXdsChannel(const XdsBootstrap::XdsServer& server) {
-  // Build channel args.
-  absl::InlinedVector<grpc_arg, 2> args_to_add = {
-      grpc_channel_arg_integer_create(
-          const_cast<char*>(GRPC_ARG_KEEPALIVE_TIME_MS),
-          5 * 60 * GPR_MS_PER_SEC),
-      grpc_channel_arg_integer_create(
-          const_cast<char*>(GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL), 1),
-  };
-  grpc_channel_args* new_args = grpc_channel_args_copy_and_add(
-      g_channel_args, args_to_add.data(), args_to_add.size());
-  // Create channel creds.
+grpc_channel* CreateXdsChannel(grpc_channel_args* args,
+                               const XdsBootstrap::XdsServer& server) {
   RefCountedPtr<grpc_channel_credentials> channel_creds =
       XdsChannelCredsRegistry::MakeChannelCreds(server.channel_creds_type,
                                                 server.channel_creds_config);
-  // Create channel.
-  grpc_channel* channel = grpc_secure_channel_create(
-      channel_creds.get(), server.server_uri.c_str(), new_args, nullptr);
-  grpc_channel_args_destroy(new_args);
-  return channel;
+  return grpc_secure_channel_create(channel_creds.get(),
+                                    server.server_uri.c_str(), args, nullptr);
 }
 
 }  // namespace
@@ -482,7 +485,7 @@ XdsClient::ChannelState::ChannelState(WeakRefCountedPtr<XdsClient> xds_client,
     gpr_log(GPR_INFO, "[xds_client %p] creating channel to %s",
             xds_client_.get(), server.server_uri.c_str());
   }
-  channel_ = CreateXdsChannel(server);
+  channel_ = CreateXdsChannel(xds_client_->args_, server);
   GPR_ASSERT(channel_ != nullptr);
   StartConnectivityWatchLocked();
 }
@@ -527,24 +530,22 @@ void XdsClient::ChannelState::MaybeStartLrsCall() {
 void XdsClient::ChannelState::StopLrsCall() { lrs_calld_.reset(); }
 
 void XdsClient::ChannelState::StartConnectivityWatchLocked() {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel_));
-  GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
+  ClientChannel* client_channel = ClientChannel::GetFromChannel(channel_);
+  GPR_ASSERT(client_channel != nullptr);
   watcher_ = new StateWatcher(Ref(DEBUG_LOCATION, "ChannelState+watch"));
-  grpc_client_channel_start_connectivity_watch(
-      client_channel_elem, GRPC_CHANNEL_IDLE,
+  client_channel->AddConnectivityWatcher(
+      GRPC_CHANNEL_IDLE,
       OrphanablePtr<AsyncConnectivityStateWatcherInterface>(watcher_));
 }
 
 void XdsClient::ChannelState::CancelConnectivityWatchLocked() {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel_));
-  GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
-  grpc_client_channel_stop_connectivity_watch(client_channel_elem, watcher_);
+  ClientChannel* client_channel = ClientChannel::GetFromChannel(channel_);
+  GPR_ASSERT(client_channel != nullptr);
+  client_channel->RemoveConnectivityWatcher(watcher_);
 }
 
-void XdsClient::ChannelState::Subscribe(const std::string& type_url,
-                                        const std::string& name) {
+void XdsClient::ChannelState::SubscribeLocked(const std::string& type_url,
+                                              const std::string& name) {
   if (ads_calld_ == nullptr) {
     // Start the ADS call if this is the first request.
     ads_calld_.reset(new RetryableCall<AdsCallState>(
@@ -558,16 +559,16 @@ void XdsClient::ChannelState::Subscribe(const std::string& type_url,
   // because when the call is restarted it will resend all necessary requests.
   if (ads_calld() == nullptr) return;
   // Subscribe to this resource if the ADS call is active.
-  ads_calld()->Subscribe(type_url, name);
+  ads_calld()->SubscribeLocked(type_url, name);
 }
 
-void XdsClient::ChannelState::Unsubscribe(const std::string& type_url,
-                                          const std::string& name,
-                                          bool delay_unsubscription) {
+void XdsClient::ChannelState::UnsubscribeLocked(const std::string& type_url,
+                                                const std::string& name,
+                                                bool delay_unsubscription) {
   if (ads_calld_ != nullptr) {
     auto* calld = ads_calld_->calld();
     if (calld != nullptr) {
-      calld->Unsubscribe(type_url, name, delay_unsubscription);
+      calld->UnsubscribeLocked(type_url, name, delay_unsubscription);
       if (!calld->HasSubscribedResources()) ads_calld_.reset();
     }
   }
@@ -650,7 +651,7 @@ void XdsClient::ChannelState::RetryableCall<T>::StartRetryTimerLocked() {
 
 template <typename T>
 void XdsClient::ChannelState::RetryableCall<T>::OnRetryTimer(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   RetryableCall* calld = static_cast<RetryableCall*>(arg);
   {
     MutexLock lock(&calld->chand_->xds_client()->mu_);
@@ -661,7 +662,7 @@ void XdsClient::ChannelState::RetryableCall<T>::OnRetryTimer(
 
 template <typename T>
 void XdsClient::ChannelState::RetryableCall<T>::OnRetryTimerLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   retry_timer_callback_pending_ = false;
   if (!shutting_down_ && error == GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -729,16 +730,16 @@ XdsClient::ChannelState::AdsCallState::AdsCallState(
   GRPC_CLOSURE_INIT(&on_request_sent_, OnRequestSent, this,
                     grpc_schedule_on_exec_ctx);
   for (const auto& p : xds_client()->listener_map_) {
-    Subscribe(XdsApi::kLdsTypeUrl, std::string(p.first));
+    SubscribeLocked(XdsApi::kLdsTypeUrl, std::string(p.first));
   }
   for (const auto& p : xds_client()->route_config_map_) {
-    Subscribe(XdsApi::kRdsTypeUrl, std::string(p.first));
+    SubscribeLocked(XdsApi::kRdsTypeUrl, std::string(p.first));
   }
   for (const auto& p : xds_client()->cluster_map_) {
-    Subscribe(XdsApi::kCdsTypeUrl, std::string(p.first));
+    SubscribeLocked(XdsApi::kCdsTypeUrl, std::string(p.first));
   }
   for (const auto& p : xds_client()->endpoint_map_) {
-    Subscribe(XdsApi::kEdsTypeUrl, std::string(p.first));
+    SubscribeLocked(XdsApi::kEdsTypeUrl, std::string(p.first));
   }
   // Op: recv initial metadata.
   op = ops;
@@ -802,7 +803,8 @@ void XdsClient::ChannelState::AdsCallState::Orphan() {
 }
 
 void XdsClient::ChannelState::AdsCallState::SendMessageLocked(
-    const std::string& type_url) {
+    const std::string& type_url)
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_) {
   // Buffer message sending if an existing message is in flight.
   if (send_message_payload_ != nullptr) {
     buffered_requests_.insert(type_url);
@@ -827,7 +829,7 @@ void XdsClient::ChannelState::AdsCallState::SendMessageLocked(
             "error=%s resources=%s",
             xds_client(), type_url.c_str(),
             xds_client()->resource_version_map_[type_url].c_str(),
-            state.nonce.c_str(), grpc_error_string(state.error),
+            state.nonce.c_str(), grpc_error_std_string(state.error).c_str(),
             absl::StrJoin(resource_names, " ").c_str());
   }
   GRPC_ERROR_UNREF(state.error);
@@ -854,7 +856,7 @@ void XdsClient::ChannelState::AdsCallState::SendMessageLocked(
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::Subscribe(
+void XdsClient::ChannelState::AdsCallState::SubscribeLocked(
     const std::string& type_url, const std::string& name) {
   auto& state = state_map_[type_url].subscribed_resources[name];
   if (state == nullptr) {
@@ -864,7 +866,7 @@ void XdsClient::ChannelState::AdsCallState::Subscribe(
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::Unsubscribe(
+void XdsClient::ChannelState::AdsCallState::UnsubscribeLocked(
     const std::string& type_url, const std::string& name,
     bool delay_unsubscription) {
   state_map_[type_url].subscribed_resources.erase(name);
@@ -894,7 +896,7 @@ XdsApi::ResourceMetadata CreateResourceMetadataAcked(
 
 }  // namespace
 
-void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate(
+void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdateLocked(
     std::string version, grpc_millis update_time,
     XdsApi::LdsUpdateMap lds_update_map) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -978,7 +980,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate(
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate(
+void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdateLocked(
     std::string version, grpc_millis update_time,
     XdsApi::RdsUpdateMap rds_update_map) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -1020,7 +1022,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate(
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate(
+void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdateLocked(
     std::string version, grpc_millis update_time,
     XdsApi::CdsUpdateMap cds_update_map) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -1101,7 +1103,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate(
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
+void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdateLocked(
     std::string version, grpc_millis update_time,
     XdsApi::EdsUpdateMap eds_update_map) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -1143,8 +1145,8 @@ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::OnRequestSent(void* arg,
-                                                          grpc_error* error) {
+void XdsClient::ChannelState::AdsCallState::OnRequestSent(
+    void* arg, grpc_error_handle error) {
   AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
   {
     MutexLock lock(&ads_calld->xds_client()->mu_);
@@ -1154,7 +1156,7 @@ void XdsClient::ChannelState::AdsCallState::OnRequestSent(void* arg,
 }
 
 void XdsClient::ChannelState::AdsCallState::OnRequestSentLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (IsCurrentCallOnChannel() && error == GRPC_ERROR_NONE) {
     // Clean up the sent message.
     grpc_byte_buffer_destroy(send_message_payload_);
@@ -1178,7 +1180,7 @@ void XdsClient::ChannelState::AdsCallState::OnRequestSentLocked(
 }
 
 void XdsClient::ChannelState::AdsCallState::OnResponseReceived(
-    void* arg, grpc_error* /* error */) {
+    void* arg, grpc_error_handle /* error */) {
   AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
   bool done;
   {
@@ -1212,7 +1214,7 @@ bool XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked() {
     // Ignore unparsable response.
     gpr_log(GPR_ERROR,
             "[xds_client %p] Error parsing ADS response (%s) -- ignoring",
-            xds_client(), grpc_error_string(result.parse_error));
+            xds_client(), grpc_error_std_string(result.parse_error).c_str());
     GRPC_ERROR_UNREF(result.parse_error);
   } else {
     grpc_millis update_time = grpc_core::ExecCtx::Get()->Now();
@@ -1221,8 +1223,8 @@ bool XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked() {
     state.nonce = std::move(result.nonce);
     // NACK or ACK the response.
     if (result.parse_error != GRPC_ERROR_NONE) {
-      xds_client()->UpdateResourceMetadataWithFailedParseResult(update_time,
-                                                                result);
+      xds_client()->UpdateResourceMetadataWithFailedParseResultLocked(
+          update_time, result);
       GRPC_ERROR_UNREF(state.error);
       state.error = result.parse_error;
       // NACK unacceptable update.
@@ -1230,23 +1232,24 @@ bool XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked() {
               "[xds_client %p] ADS response invalid for resource type %s "
               "version %s, will NACK: nonce=%s error=%s",
               xds_client(), result.type_url.c_str(), result.version.c_str(),
-              state.nonce.c_str(), grpc_error_string(result.parse_error));
+              state.nonce.c_str(),
+              grpc_error_std_string(result.parse_error).c_str());
       SendMessageLocked(result.type_url);
     } else {
       seen_response_ = true;
       // Accept the ADS response according to the type_url.
       if (result.type_url == XdsApi::kLdsTypeUrl) {
-        AcceptLdsUpdate(result.version, update_time,
-                        std::move(result.lds_update_map));
+        AcceptLdsUpdateLocked(result.version, update_time,
+                              std::move(result.lds_update_map));
       } else if (result.type_url == XdsApi::kRdsTypeUrl) {
-        AcceptRdsUpdate(result.version, update_time,
-                        std::move(result.rds_update_map));
+        AcceptRdsUpdateLocked(result.version, update_time,
+                              std::move(result.rds_update_map));
       } else if (result.type_url == XdsApi::kCdsTypeUrl) {
-        AcceptCdsUpdate(result.version, update_time,
-                        std::move(result.cds_update_map));
+        AcceptCdsUpdateLocked(result.version, update_time,
+                              std::move(result.cds_update_map));
       } else if (result.type_url == XdsApi::kEdsTypeUrl) {
-        AcceptEdsUpdate(result.version, update_time,
-                        std::move(result.eds_update_map));
+        AcceptEdsUpdateLocked(result.version, update_time,
+                              std::move(result.eds_update_map));
       }
       xds_client()->resource_version_map_[result.type_url] =
           std::move(result.version);
@@ -1277,7 +1280,7 @@ bool XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked() {
 }
 
 void XdsClient::ChannelState::AdsCallState::OnStatusReceived(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
   {
     MutexLock lock(&ads_calld->xds_client()->mu_);
@@ -1287,14 +1290,14 @@ void XdsClient::ChannelState::AdsCallState::OnStatusReceived(
 }
 
 void XdsClient::ChannelState::AdsCallState::OnStatusReceivedLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     char* status_details = grpc_slice_to_c_string(status_details_);
     gpr_log(GPR_INFO,
             "[xds_client %p] ADS call status received. Status = %d, details "
             "= '%s', (chand: %p, ads_calld: %p, call: %p), error '%s'",
             xds_client(), status_code_, status_details, chand(), this, call_,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     gpr_free(status_details);
   }
   // Ignore status from a stale call.
@@ -1349,7 +1352,7 @@ void XdsClient::ChannelState::LrsCallState::Reporter::
 }
 
 void XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimer(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   Reporter* self = static_cast<Reporter*>(arg);
   bool done;
   {
@@ -1360,7 +1363,7 @@ void XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimer(
 }
 
 bool XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimerLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   next_report_timer_callback_pending_ = false;
   if (error != GRPC_ERROR_NONE || !IsCurrentReporterOnCall()) {
     GRPC_ERROR_UNREF(error);
@@ -1425,7 +1428,7 @@ bool XdsClient::ChannelState::LrsCallState::Reporter::SendReportLocked() {
 }
 
 void XdsClient::ChannelState::LrsCallState::Reporter::OnReportDone(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   Reporter* self = static_cast<Reporter*>(arg);
   bool done;
   {
@@ -1436,7 +1439,7 @@ void XdsClient::ChannelState::LrsCallState::Reporter::OnReportDone(
 }
 
 bool XdsClient::ChannelState::LrsCallState::Reporter::OnReportDoneLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   grpc_byte_buffer_destroy(parent_->send_message_payload_);
   parent_->send_message_payload_ = nullptr;
   // If there are no more registered stats to report, cancel the call.
@@ -1606,7 +1609,7 @@ void XdsClient::ChannelState::LrsCallState::MaybeStartReportingLocked() {
 }
 
 void XdsClient::ChannelState::LrsCallState::OnInitialRequestSent(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
   {
     MutexLock lock(&lrs_calld->xds_client()->mu_);
@@ -1623,7 +1626,7 @@ void XdsClient::ChannelState::LrsCallState::OnInitialRequestSentLocked() {
 }
 
 void XdsClient::ChannelState::LrsCallState::OnResponseReceived(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
   bool done;
   {
@@ -1651,13 +1654,13 @@ bool XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked() {
     bool send_all_clusters = false;
     std::set<std::string> new_cluster_names;
     grpc_millis new_load_reporting_interval;
-    grpc_error* parse_error = xds_client()->api_.ParseLrsResponse(
+    grpc_error_handle parse_error = xds_client()->api_.ParseLrsResponse(
         response_slice, &send_all_clusters, &new_cluster_names,
         &new_load_reporting_interval);
     if (parse_error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR,
               "[xds_client %p] LRS response parsing failed. error=%s",
-              xds_client(), grpc_error_string(parse_error));
+              xds_client(), grpc_error_std_string(parse_error).c_str());
       GRPC_ERROR_UNREF(parse_error);
       return;
     }
@@ -1726,7 +1729,7 @@ bool XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked() {
 }
 
 void XdsClient::ChannelState::LrsCallState::OnStatusReceived(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
   {
     MutexLock lock(&lrs_calld->xds_client()->mu_);
@@ -1736,7 +1739,7 @@ void XdsClient::ChannelState::LrsCallState::OnStatusReceived(
 }
 
 void XdsClient::ChannelState::LrsCallState::OnStatusReceivedLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   GPR_ASSERT(call_ != nullptr);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     char* status_details = grpc_slice_to_c_string(status_details_);
@@ -1744,7 +1747,7 @@ void XdsClient::ChannelState::LrsCallState::OnStatusReceivedLocked(
             "[xds_client %p] LRS call status received. Status = %d, details "
             "= '%s', (chand: %p, calld: %p, call: %p), error '%s'",
             xds_client(), status_code_, status_details, chand(), this, call_,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     gpr_free(status_details);
   }
   // Ignore status from a stale call.
@@ -1769,36 +1772,41 @@ bool XdsClient::ChannelState::LrsCallState::IsCurrentCallOnChannel() const {
 
 namespace {
 
-grpc_millis GetRequestTimeout() {
+grpc_millis GetRequestTimeout(const grpc_channel_args* args) {
   return grpc_channel_args_find_integer(
-      g_channel_args, GRPC_ARG_XDS_RESOURCE_DOES_NOT_EXIST_TIMEOUT_MS,
+      args, GRPC_ARG_XDS_RESOURCE_DOES_NOT_EXIST_TIMEOUT_MS,
       {15000, 0, INT_MAX});
 }
 
+grpc_channel_args* ModifyChannelArgs(const grpc_channel_args* args) {
+  absl::InlinedVector<grpc_arg, 2> args_to_add = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_KEEPALIVE_TIME_MS),
+          5 * 60 * GPR_MS_PER_SEC),
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL), 1),
+  };
+  return grpc_channel_args_copy_and_add(args, args_to_add.data(),
+                                        args_to_add.size());
+}
+
 }  // namespace
 
-XdsClient::XdsClient(grpc_error** error)
+XdsClient::XdsClient(std::unique_ptr<XdsBootstrap> bootstrap,
+                     const grpc_channel_args* args)
     : DualRefCounted<XdsClient>(
           GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_refcount_trace) ? "XdsClient"
                                                                   : nullptr),
-      request_timeout_(GetRequestTimeout()),
+      bootstrap_(std::move(bootstrap)),
+      args_(ModifyChannelArgs(args)),
+      request_timeout_(GetRequestTimeout(args)),
       interested_parties_(grpc_pollset_set_create()),
-      bootstrap_(XdsBootstrap::Create(this, &grpc_xds_client_trace,
-                                      g_fallback_bootstrap_config, error)),
       certificate_provider_store_(MakeOrphanable<CertificateProviderStore>(
-          bootstrap_ == nullptr
-              ? CertificateProviderStore::PluginDefinitionMap()
-              : bootstrap_->certificate_providers())),
-      api_(this, &grpc_xds_client_trace,
-           bootstrap_ == nullptr ? nullptr : bootstrap_->node()) {
+          bootstrap_->certificate_providers())),
+      api_(this, &grpc_xds_client_trace, bootstrap_->node()) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     gpr_log(GPR_INFO, "[xds_client %p] creating xds client", this);
   }
-  if (*error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "[xds_client %p] failed to read bootstrap file: %s",
-            this, grpc_error_string(*error));
-    return;
-  }
   // Create ChannelState object.
   chand_ = MakeOrphanable<ChannelState>(
       WeakRef(DEBUG_LOCATION, "XdsClient+ChannelState"), bootstrap_->server());
@@ -1808,11 +1816,13 @@ XdsClient::~XdsClient() {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     gpr_log(GPR_INFO, "[xds_client %p] destroying xds client", this);
   }
+  grpc_channel_args_destroy(args_);
   grpc_pollset_set_destroy(interested_parties_);
 }
 
 void XdsClient::AddChannelzLinkage(
     channelz::ChannelNode* parent_channelz_node) {
+  MutexLock lock(&mu_);
   channelz::ChannelNode* xds_channelz_node =
       grpc_channel_get_channelz_node(chand_->channel());
   if (xds_channelz_node != nullptr) {
@@ -1822,6 +1832,7 @@ void XdsClient::AddChannelzLinkage(
 
 void XdsClient::RemoveChannelzLinkage(
     channelz::ChannelNode* parent_channelz_node) {
+  MutexLock lock(&mu_);
   channelz::ChannelNode* xds_channelz_node =
       grpc_channel_get_channelz_node(chand_->channel());
   if (xds_channelz_node != nullptr) {
@@ -1872,7 +1883,7 @@ void XdsClient::WatchListenerData(
     }
     w->OnListenerChanged(*listener_state.update);
   }
-  chand_->Subscribe(XdsApi::kLdsTypeUrl, listener_name_str);
+  chand_->SubscribeLocked(XdsApi::kLdsTypeUrl, listener_name_str);
 }
 
 void XdsClient::CancelListenerDataWatch(absl::string_view listener_name,
@@ -1887,8 +1898,8 @@ void XdsClient::CancelListenerDataWatch(absl::string_view listener_name,
     listener_state.watchers.erase(it);
     if (listener_state.watchers.empty()) {
       listener_map_.erase(listener_name_str);
-      chand_->Unsubscribe(XdsApi::kLdsTypeUrl, listener_name_str,
-                          delay_unsubscription);
+      chand_->UnsubscribeLocked(XdsApi::kLdsTypeUrl, listener_name_str,
+                                delay_unsubscription);
     }
   }
 }
@@ -1912,7 +1923,7 @@ void XdsClient::WatchRouteConfigData(
     }
     w->OnRouteConfigChanged(*route_config_state.update);
   }
-  chand_->Subscribe(XdsApi::kRdsTypeUrl, route_config_name_str);
+  chand_->SubscribeLocked(XdsApi::kRdsTypeUrl, route_config_name_str);
 }
 
 void XdsClient::CancelRouteConfigDataWatch(absl::string_view route_config_name,
@@ -1928,8 +1939,8 @@ void XdsClient::CancelRouteConfigDataWatch(absl::string_view route_config_name,
     route_config_state.watchers.erase(it);
     if (route_config_state.watchers.empty()) {
       route_config_map_.erase(route_config_name_str);
-      chand_->Unsubscribe(XdsApi::kRdsTypeUrl, route_config_name_str,
-                          delay_unsubscription);
+      chand_->UnsubscribeLocked(XdsApi::kRdsTypeUrl, route_config_name_str,
+                                delay_unsubscription);
     }
   }
 }
@@ -1951,7 +1962,7 @@ void XdsClient::WatchClusterData(
     }
     w->OnClusterChanged(cluster_state.update.value());
   }
-  chand_->Subscribe(XdsApi::kCdsTypeUrl, cluster_name_str);
+  chand_->SubscribeLocked(XdsApi::kCdsTypeUrl, cluster_name_str);
 }
 
 void XdsClient::CancelClusterDataWatch(absl::string_view cluster_name,
@@ -1966,8 +1977,8 @@ void XdsClient::CancelClusterDataWatch(absl::string_view cluster_name,
     cluster_state.watchers.erase(it);
     if (cluster_state.watchers.empty()) {
       cluster_map_.erase(cluster_name_str);
-      chand_->Unsubscribe(XdsApi::kCdsTypeUrl, cluster_name_str,
-                          delay_unsubscription);
+      chand_->UnsubscribeLocked(XdsApi::kCdsTypeUrl, cluster_name_str,
+                                delay_unsubscription);
     }
   }
 }
@@ -1989,7 +2000,7 @@ void XdsClient::WatchEndpointData(
     }
     w->OnEndpointChanged(endpoint_state.update.value());
   }
-  chand_->Subscribe(XdsApi::kEdsTypeUrl, eds_service_name_str);
+  chand_->SubscribeLocked(XdsApi::kEdsTypeUrl, eds_service_name_str);
 }
 
 void XdsClient::CancelEndpointDataWatch(absl::string_view eds_service_name,
@@ -2004,8 +2015,8 @@ void XdsClient::CancelEndpointDataWatch(absl::string_view eds_service_name,
     endpoint_state.watchers.erase(it);
     if (endpoint_state.watchers.empty()) {
       endpoint_map_.erase(eds_service_name_str);
-      chand_->Unsubscribe(XdsApi::kEdsTypeUrl, eds_service_name_str,
-                          delay_unsubscription);
+      chand_->UnsubscribeLocked(XdsApi::kEdsTypeUrl, eds_service_name_str,
+                                delay_unsubscription);
     }
   }
 }
@@ -2132,7 +2143,7 @@ void XdsClient::ResetBackoff() {
   }
 }
 
-void XdsClient::NotifyOnErrorLocked(grpc_error* error) {
+void XdsClient::NotifyOnErrorLocked(grpc_error_handle error) {
   for (const auto& p : listener_map_) {
     const ListenerState& listener_state = p.second;
     for (const auto& p : listener_state.watchers) {
@@ -2241,11 +2252,11 @@ XdsApi::ClusterLoadReportMap XdsClient::BuildLoadReportSnapshotLocked(
   return snapshot_map;
 }
 
-void XdsClient::UpdateResourceMetadataWithFailedParseResult(
+void XdsClient::UpdateResourceMetadataWithFailedParseResultLocked(
     grpc_millis update_time, const XdsApi::AdsParseResult& result) {
   // ADS update is rejected and the resource names in the failed update is
   // available.
-  absl::string_view details = grpc_error_string(result.parse_error);
+  std::string details = grpc_error_std_string(result.parse_error);
   for (auto& name : result.resource_names_failed) {
     XdsApi::ResourceMetadata* resource_metadata = nullptr;
     if (result.type_url == XdsApi::kLdsTypeUrl) {
@@ -2274,7 +2285,7 @@ void XdsClient::UpdateResourceMetadataWithFailedParseResult(
     }
     resource_metadata->client_status = XdsApi::ResourceMetadata::NACKED;
     resource_metadata->failed_version = result.version;
-    resource_metadata->failed_details = std::string(details);
+    resource_metadata->failed_details = details;
     resource_metadata->failed_update_time = update_time;
   }
 }
@@ -2324,24 +2335,105 @@ void XdsClientGlobalInit() {
   XdsHttpFilterRegistry::Init();
 }
 
-void XdsClientGlobalShutdown() {
-  delete g_mu;
-  g_mu = nullptr;
+// TODO(roth): Find a better way to clear the fallback config that does
+// not require using ABSL_NO_THREAD_SAFETY_ANALYSIS.
+void XdsClientGlobalShutdown() ABSL_NO_THREAD_SAFETY_ANALYSIS {
   gpr_free(g_fallback_bootstrap_config);
   g_fallback_bootstrap_config = nullptr;
+  delete g_mu;
+  g_mu = nullptr;
   XdsHttpFilterRegistry::Shutdown();
 }
 
-RefCountedPtr<XdsClient> XdsClient::GetOrCreate(grpc_error** error) {
+namespace {
+
+std::string GetBootstrapContents(const char* fallback_config,
+                                 grpc_error_handle* error) {
+  // First, try GRPC_XDS_BOOTSTRAP env var.
+  grpc_core::UniquePtr<char> path(gpr_getenv("GRPC_XDS_BOOTSTRAP"));
+  if (path != nullptr) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
+      gpr_log(GPR_INFO,
+              "Got bootstrap file location from GRPC_XDS_BOOTSTRAP "
+              "environment variable: %s",
+              path.get());
+    }
+    grpc_slice contents;
+    *error =
+        grpc_load_file(path.get(), /*add_null_terminator=*/true, &contents);
+    if (*error != GRPC_ERROR_NONE) return "";
+    std::string contents_str(StringViewFromSlice(contents));
+    grpc_slice_unref_internal(contents);
+    return contents_str;
+  }
+  // Next, try GRPC_XDS_BOOTSTRAP_CONFIG env var.
+  grpc_core::UniquePtr<char> env_config(
+      gpr_getenv("GRPC_XDS_BOOTSTRAP_CONFIG"));
+  if (env_config != nullptr) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
+      gpr_log(GPR_INFO,
+              "Got bootstrap contents from GRPC_XDS_BOOTSTRAP_CONFIG "
+              "environment variable");
+    }
+    return env_config.get();
+  }
+  // Finally, try fallback config.
+  if (fallback_config != nullptr) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
+      gpr_log(GPR_INFO, "Got bootstrap contents from fallback config");
+    }
+    return fallback_config;
+  }
+  // No bootstrap config found.
+  *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+      "Environment variables GRPC_XDS_BOOTSTRAP or GRPC_XDS_BOOTSTRAP_CONFIG "
+      "not defined");
+  return "";
+}
+
+}  // namespace
+
+RefCountedPtr<XdsClient> XdsClient::GetOrCreate(const grpc_channel_args* args,
+                                                grpc_error_handle* error) {
   RefCountedPtr<XdsClient> xds_client;
+  // If getting bootstrap from channel args, create a local XdsClient
+  // instance for the channel or server instead of using the global instance.
+  const char* bootstrap_config = grpc_channel_args_find_string(
+      args, GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG);
+  if (bootstrap_config != nullptr) {
+    std::unique_ptr<XdsBootstrap> bootstrap =
+        XdsBootstrap::Create(bootstrap_config, error);
+    if (*error == GRPC_ERROR_NONE) {
+      grpc_channel_args* xds_channel_args =
+          grpc_channel_args_find_pointer<grpc_channel_args>(
+              args,
+              GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS);
+      return MakeRefCounted<XdsClient>(std::move(bootstrap), xds_channel_args);
+    }
+    return nullptr;
+  }
+  // Otherwise, use the global instance.
   {
     MutexLock lock(g_mu);
     if (g_xds_client != nullptr) {
       auto xds_client = g_xds_client->RefIfNonZero();
       if (xds_client != nullptr) return xds_client;
     }
-    xds_client = MakeRefCounted<XdsClient>(error);
+    // Find bootstrap contents.
+    std::string bootstrap_contents =
+        GetBootstrapContents(g_fallback_bootstrap_config, error);
     if (*error != GRPC_ERROR_NONE) return nullptr;
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
+      gpr_log(GPR_INFO, "xDS bootstrap contents: %s",
+              bootstrap_contents.c_str());
+    }
+    // Parse bootstrap.
+    std::unique_ptr<XdsBootstrap> bootstrap =
+        XdsBootstrap::Create(bootstrap_contents, error);
+    if (*error != GRPC_ERROR_NONE) return nullptr;
+    // Instantiate XdsClient.
+    xds_client =
+        MakeRefCounted<XdsClient>(std::move(bootstrap), g_channel_args);
     g_xds_client = xds_client.get();
   }
   return xds_client;
@@ -2367,14 +2459,54 @@ void SetXdsFallbackBootstrapConfig(const char* config) {
 
 }  // namespace internal
 
+//
+// embedding XdsClient in channel args
+//
+
+#define GRPC_ARG_XDS_CLIENT "grpc.internal.xds_client"
+
+namespace {
+
+void* XdsClientArgCopy(void* p) {
+  XdsClient* xds_client = static_cast<XdsClient*>(p);
+  xds_client->Ref(DEBUG_LOCATION, "channel arg").release();
+  return p;
+}
+
+void XdsClientArgDestroy(void* p) {
+  XdsClient* xds_client = static_cast<XdsClient*>(p);
+  xds_client->Unref(DEBUG_LOCATION, "channel arg");
+}
+
+int XdsClientArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
+
+const grpc_arg_pointer_vtable kXdsClientArgVtable = {
+    XdsClientArgCopy, XdsClientArgDestroy, XdsClientArgCmp};
+
+}  // namespace
+
+grpc_arg XdsClient::MakeChannelArg() const {
+  return grpc_channel_arg_pointer_create(const_cast<char*>(GRPC_ARG_XDS_CLIENT),
+                                         const_cast<XdsClient*>(this),
+                                         &kXdsClientArgVtable);
+}
+
+RefCountedPtr<XdsClient> XdsClient::GetFromChannelArgs(
+    const grpc_channel_args& args) {
+  XdsClient* xds_client =
+      grpc_channel_args_find_pointer<XdsClient>(&args, GRPC_ARG_XDS_CLIENT);
+  if (xds_client == nullptr) return nullptr;
+  return xds_client->Ref(DEBUG_LOCATION, "GetFromChannelArgs");
+}
+
 }  // namespace grpc_core
 
 // The returned bytes may contain NULL(0), so we can't use c-string.
 grpc_slice grpc_dump_xds_configs() {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
-  grpc_error* error = GRPC_ERROR_NONE;
-  auto xds_client = grpc_core::XdsClient::GetOrCreate(&error);
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto xds_client = grpc_core::XdsClient::GetOrCreate(nullptr, &error);
   if (error != GRPC_ERROR_NONE) {
     // If we isn't using xDS, just return an empty string.
     GRPC_ERROR_UNREF(error);
index 41e0a37..0ee84e7 100644 (file)
@@ -48,7 +48,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
    public:
     virtual ~ListenerWatcherInterface() = default;
     virtual void OnListenerChanged(XdsApi::LdsUpdate listener) = 0;
-    virtual void OnError(grpc_error* error) = 0;
+    virtual void OnError(grpc_error_handle error) = 0;
     virtual void OnResourceDoesNotExist() = 0;
   };
 
@@ -57,7 +57,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
    public:
     virtual ~RouteConfigWatcherInterface() = default;
     virtual void OnRouteConfigChanged(XdsApi::RdsUpdate route_config) = 0;
-    virtual void OnError(grpc_error* error) = 0;
+    virtual void OnError(grpc_error_handle error) = 0;
     virtual void OnResourceDoesNotExist() = 0;
   };
 
@@ -66,7 +66,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
    public:
     virtual ~ClusterWatcherInterface() = default;
     virtual void OnClusterChanged(XdsApi::CdsUpdate cluster_data) = 0;
-    virtual void OnError(grpc_error* error) = 0;
+    virtual void OnError(grpc_error_handle error) = 0;
     virtual void OnResourceDoesNotExist() = 0;
   };
 
@@ -75,17 +75,19 @@ class XdsClient : public DualRefCounted<XdsClient> {
    public:
     virtual ~EndpointWatcherInterface() = default;
     virtual void OnEndpointChanged(XdsApi::EdsUpdate update) = 0;
-    virtual void OnError(grpc_error* error) = 0;
+    virtual void OnError(grpc_error_handle error) = 0;
     virtual void OnResourceDoesNotExist() = 0;
   };
 
   // Factory function to get or create the global XdsClient instance.
   // If *error is not GRPC_ERROR_NONE upon return, then there was
   // an error initializing the client.
-  static RefCountedPtr<XdsClient> GetOrCreate(grpc_error** error);
+  static RefCountedPtr<XdsClient> GetOrCreate(const grpc_channel_args* args,
+                                              grpc_error_handle* error);
 
-  // Callers should not instantiate directly.  Use GetOrCreate() instead.
-  explicit XdsClient(grpc_error** error);
+  // Most callers should not instantiate directly.  Use GetOrCreate() instead.
+  XdsClient(std::unique_ptr<XdsBootstrap> bootstrap,
+            const grpc_channel_args* args);
   ~XdsClient() override;
 
   const XdsBootstrap& bootstrap() const {
@@ -200,6 +202,11 @@ class XdsClient : public DualRefCounted<XdsClient> {
   // implementation.
   std::string DumpClientConfigBinary();
 
+  // Helpers for encoding the XdsClient object in channel args.
+  grpc_arg MakeChannelArg() const;
+  static RefCountedPtr<XdsClient> GetFromChannelArgs(
+      const grpc_channel_args& args);
+
  private:
   // Contains a channel to the xds server and all the data related to the
   // channel.  Holds a ref to the xds client object.
@@ -236,9 +243,11 @@ class XdsClient : public DualRefCounted<XdsClient> {
     void StartConnectivityWatchLocked();
     void CancelConnectivityWatchLocked();
 
-    void Subscribe(const std::string& type_url, const std::string& name);
-    void Unsubscribe(const std::string& type_url, const std::string& name,
-                     bool delay_unsubscription);
+    void SubscribeLocked(const std::string& type_url, const std::string& name)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+    void UnsubscribeLocked(const std::string& type_url, const std::string& name,
+                           bool delay_unsubscription)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
    private:
     class StateWatcher;
@@ -308,48 +317,53 @@ class XdsClient : public DualRefCounted<XdsClient> {
   };
 
   // Sends an error notification to all watchers.
-  void NotifyOnErrorLocked(grpc_error* error);
+  void NotifyOnErrorLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   XdsApi::ClusterLoadReportMap BuildLoadReportSnapshotLocked(
-      bool send_all_clusters, const std::set<std::string>& clusters);
+      bool send_all_clusters, const std::set<std::string>& clusters)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
-  void UpdateResourceMetadataWithFailedParseResult(
-      grpc_millis update_time, const XdsApi::AdsParseResult& result);
-  void UpdatePendingResources(
-      const std::string& type_url,
-      XdsApi::ResourceMetadataMap* resource_metadata_map);
+  void UpdateResourceMetadataWithFailedParseResultLocked(
+      grpc_millis update_time, const XdsApi::AdsParseResult& result)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
+  std::unique_ptr<XdsBootstrap> bootstrap_;
+  grpc_channel_args* args_;
   const grpc_millis request_timeout_;
   grpc_pollset_set* interested_parties_;
-  std::unique_ptr<XdsBootstrap> bootstrap_;
   OrphanablePtr<CertificateProviderStore> certificate_provider_store_;
   XdsApi api_;
 
   Mutex mu_;
 
   // The channel for communicating with the xds server.
-  OrphanablePtr<ChannelState> chand_;
+  OrphanablePtr<ChannelState> chand_ ABSL_GUARDED_BY(mu_);
 
   // One entry for each watched LDS resource.
-  std::map<std::string /*listener_name*/, ListenerState> listener_map_;
+  std::map<std::string /*listener_name*/, ListenerState> listener_map_
+      ABSL_GUARDED_BY(mu_);
   // One entry for each watched RDS resource.
   std::map<std::string /*route_config_name*/, RouteConfigState>
-      route_config_map_;
+      route_config_map_ ABSL_GUARDED_BY(mu_);
   // One entry for each watched CDS resource.
-  std::map<std::string /*cluster_name*/, ClusterState> cluster_map_;
+  std::map<std::string /*cluster_name*/, ClusterState> cluster_map_
+      ABSL_GUARDED_BY(mu_);
   // One entry for each watched EDS resource.
-  std::map<std::string /*eds_service_name*/, EndpointState> endpoint_map_;
+  std::map<std::string /*eds_service_name*/, EndpointState> endpoint_map_
+      ABSL_GUARDED_BY(mu_);
 
   // Load report data.
   std::map<
       std::pair<std::string /*cluster_name*/, std::string /*eds_service_name*/>,
       LoadReportState>
-      load_report_map_;
+      load_report_map_ ABSL_GUARDED_BY(mu_);
 
   // Stores the most recent accepted resource version for each resource type.
-  std::map<std::string /*type*/, std::string /*version*/> resource_version_map_;
+  std::map<std::string /*type*/, std::string /*version*/> resource_version_map_
+      ABSL_GUARDED_BY(mu_);
 
-  bool shutting_down_ = false;
+  bool shutting_down_ ABSL_GUARDED_BY(mu_) = false;
 };
 
 namespace internal {
@@ -362,4 +376,4 @@ void SetXdsFallbackBootstrapConfig(const char* config);
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_EXT_XDS_XDS_CLIENT_H */
+#endif  // GRPC_CORE_EXT_XDS_XDS_CLIENT_H
index 852dda2..b300fc5 100644 (file)
@@ -149,7 +149,7 @@ class XdsClusterDropStats : public RefCounted<XdsClusterDropStats> {
   // dropped_requests can be accessed by both the picker (from data plane
   // mutex) and the load reporting thread (from the control plane combiner).
   Mutex mu_;
-  CategorizedDropsMap categorized_drops_;
+  CategorizedDropsMap categorized_drops_ ABSL_GUARDED_BY(mu_);
 };
 
 // Locality stats for an xds cluster.
@@ -231,7 +231,8 @@ class XdsClusterLocalityStats : public RefCounted<XdsClusterLocalityStats> {
   // call's recv_trailing_metadata (not from the control plane work serializer)
   // and the load reporting thread (from the control plane work serializer).
   Mutex backend_metrics_mu_;
-  std::map<std::string, BackendMetric> backend_metrics_;
+  std::map<std::string, BackendMetric> backend_metrics_
+      ABSL_GUARDED_BY(backend_metrics_mu_);
 };
 
 }  // namespace grpc_core
index 5e7aba6..962731f 100644 (file)
 
 #include "src/core/ext/xds/xds_certificate_provider.h"
 #include "src/core/ext/xds/xds_client.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_utils.h"
 #include "src/core/lib/security/credentials/xds/xds_credentials.h"
 #include "src/core/lib/surface/api_trace.h"
@@ -163,8 +163,14 @@ const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourceType(
     return nullptr;
   }
   grpc_resolved_address source_addr;
-  grpc_string_to_sockaddr(&source_addr, host.c_str(),
-                          0 /* port doesn't matter here */);
+  grpc_error_handle error = grpc_string_to_sockaddr(
+      &source_addr, host.c_str(), 0 /* port doesn't matter here */);
+  if (error != GRPC_ERROR_NONE) {
+    gpr_log(GPR_DEBUG, "Could not parse string to socket address: %s",
+            host.c_str());
+    GRPC_ERROR_UNREF(error);
+    return nullptr;
+  }
   // Use kAny only if kSameIporLoopback and kExternal are empty
   if (source_types_array[static_cast<int>(
                              XdsApi::LdsUpdate::FilterChainMap::
@@ -208,8 +214,14 @@ const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForDestinationIp(
     return nullptr;
   }
   grpc_resolved_address destination_addr;
-  grpc_string_to_sockaddr(&destination_addr, host.c_str(),
-                          0 /* port doesn't matter here */);
+  grpc_error_handle error = grpc_string_to_sockaddr(
+      &destination_addr, host.c_str(), 0 /* port doesn't matter here */);
+  if (error != GRPC_ERROR_NONE) {
+    gpr_log(GPR_DEBUG, "Could not parse string to socket address: %s",
+            host.c_str());
+    GRPC_ERROR_UNREF(error);
+    return nullptr;
+  }
   const XdsApi::LdsUpdate::FilterChainMap::DestinationIp* best_match = nullptr;
   for (const auto& entry : destination_ip_vector) {
     // Special case for catch-all
@@ -413,8 +425,8 @@ class XdsServerConfigFetcher : public grpc_server_config_fetcher {
         return;
       }
       if (filter_chain_match_manager_ == nullptr) {
-        if (serving_status_notifier_.on_serving_status_change != nullptr) {
-          serving_status_notifier_.on_serving_status_change(
+        if (serving_status_notifier_.on_serving_status_update != nullptr) {
+          serving_status_notifier_.on_serving_status_update(
               serving_status_notifier_.user_data, listening_address_.c_str(),
               GRPC_STATUS_OK, "");
         } else {
@@ -436,23 +448,25 @@ class XdsServerConfigFetcher : public grpc_server_config_fetcher {
       }
     }
 
-    void OnError(grpc_error* error) override {
+    void OnError(grpc_error_handle error) override {
       if (filter_chain_match_manager_ != nullptr) {
         gpr_log(GPR_ERROR,
                 "ListenerWatcher:%p XdsClient reports error: %s for %s; "
                 "ignoring in favor of existing resource",
-                this, grpc_error_string(error), listening_address_.c_str());
+                this, grpc_error_std_string(error).c_str(),
+                listening_address_.c_str());
       } else {
-        if (serving_status_notifier_.on_serving_status_change != nullptr) {
-          serving_status_notifier_.on_serving_status_change(
+        if (serving_status_notifier_.on_serving_status_update != nullptr) {
+          serving_status_notifier_.on_serving_status_update(
               serving_status_notifier_.user_data, listening_address_.c_str(),
-              GRPC_STATUS_UNAVAILABLE, grpc_error_string(error));
+              GRPC_STATUS_UNAVAILABLE, grpc_error_std_string(error).c_str());
         } else {
           gpr_log(
               GPR_ERROR,
               "ListenerWatcher:%p error obtaining xDS Listener resource: %s; "
               "not serving on %s",
-              this, grpc_error_string(error), listening_address_.c_str());
+              this, grpc_error_std_string(error).c_str(),
+              listening_address_.c_str());
         }
       }
       GRPC_ERROR_UNREF(error);
@@ -469,8 +483,8 @@ class XdsServerConfigFetcher : public grpc_server_config_fetcher {
         server_config_watcher_->StopServing();
         filter_chain_match_manager_.reset();
       }
-      if (serving_status_notifier_.on_serving_status_change != nullptr) {
-        serving_status_notifier_.on_serving_status_change(
+      if (serving_status_notifier_.on_serving_status_update != nullptr) {
+        serving_status_notifier_.on_serving_status_update(
             serving_status_notifier_.user_data, listening_address_.c_str(),
             static_cast<grpc_status_code>(status.raw_code()),
             std::string(status.message()).c_str());
@@ -500,23 +514,23 @@ class XdsServerConfigFetcher : public grpc_server_config_fetcher {
   grpc_server_xds_status_notifier serving_status_notifier_;
   Mutex mu_;
   std::map<grpc_server_config_fetcher::WatcherInterface*, WatcherState>
-      watchers_;
+      watchers_ ABSL_GUARDED_BY(mu_);
 };
 
 }  // namespace
 }  // namespace grpc_core
 
 grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create(
-    grpc_server_xds_status_notifier notifier) {
+    grpc_server_xds_status_notifier notifier, const grpc_channel_args* args) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
   GRPC_API_TRACE("grpc_server_config_fetcher_xds_create()", 0, ());
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::RefCountedPtr<grpc_core::XdsClient> xds_client =
-      grpc_core::XdsClient::GetOrCreate(&error);
+      grpc_core::XdsClient::GetOrCreate(args, &error);
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "Failed to create xds client: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return nullptr;
   }
similarity index 90%
rename from src/core/lib/iomgr/parse_address.cc
rename to src/core/lib/address_utils/parse_address.cc
index 9afac74..98dd1bc 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/lib/iomgr/parse_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -52,10 +52,10 @@ bool grpc_parse_unix(const grpc_core::URI& uri,
             uri.scheme().c_str());
     return false;
   }
-  grpc_error* error =
+  grpc_error_handle error =
       grpc_core::UnixSockaddrPopulate(uri.path(), resolved_addr);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "%s", grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return false;
   }
@@ -69,10 +69,10 @@ bool grpc_parse_unix_abstract(const grpc_core::URI& uri,
             uri.scheme().c_str());
     return false;
   }
-  grpc_error* error =
+  grpc_error_handle error =
       grpc_core::UnixAbstractSockaddrPopulate(uri.path(), resolved_addr);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "%s", grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return false;
   }
@@ -81,8 +81,8 @@ bool grpc_parse_unix_abstract(const grpc_core::URI& uri,
 
 namespace grpc_core {
 
-grpc_error* UnixSockaddrPopulate(absl::string_view path,
-                                 grpc_resolved_address* resolved_addr) {
+grpc_error_handle UnixSockaddrPopulate(absl::string_view path,
+                                       grpc_resolved_address* resolved_addr) {
   struct sockaddr_un* un =
       reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
   const size_t maxlen = sizeof(un->sun_path) - 1;
@@ -99,8 +99,8 @@ grpc_error* UnixSockaddrPopulate(absl::string_view path,
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* UnixAbstractSockaddrPopulate(absl::string_view path,
-                                         grpc_resolved_address* resolved_addr) {
+grpc_error_handle UnixAbstractSockaddrPopulate(
+    absl::string_view path, grpc_resolved_address* resolved_addr) {
   struct sockaddr_un* un =
       reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
   const size_t maxlen = sizeof(un->sun_path) - 1;
@@ -122,25 +122,25 @@ grpc_error* UnixAbstractSockaddrPopulate(absl::string_view path,
 
 #else  /* GRPC_HAVE_UNIX_SOCKET */
 
-bool grpc_parse_unix(const grpc_core::URI& uri,
-                     grpc_resolved_address* resolved_addr) {
+bool grpc_parse_unix(const grpc_core::URI& /* uri */,
+                     grpc_resolved_address* /* resolved_addr */) {
   abort();
 }
 
-bool grpc_parse_unix_abstract(const grpc_core::URI& uri,
-                              grpc_resolved_address* resolved_addr) {
+bool grpc_parse_unix_abstract(const grpc_core::URI& /* uri */,
+                              grpc_resolved_address* /* resolved_addr */) {
   abort();
 }
 
 namespace grpc_core {
 
-grpc_error* UnixSockaddrPopulate(absl::string_view path,
-                                 grpc_resolved_address* resolved_addr) {
+grpc_error_handle UnixSockaddrPopulate(
+    absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
   abort();
 }
 
-grpc_error* UnixAbstractSockaddrPopulate(absl::string_view path,
-                                         grpc_resolved_address* resolved_addr) {
+grpc_error_handle UnixAbstractSockaddrPopulate(
+    absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
   abort();
 }
 
similarity index 86%
rename from src/core/lib/iomgr/parse_address.h
rename to src/core/lib/address_utils/parse_address.h
index 870afef..92409b7 100644 (file)
@@ -16,8 +16,8 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_IOMGR_PARSE_ADDRESS_H
-#define GRPC_CORE_LIB_IOMGR_PARSE_ADDRESS_H
+#ifndef GRPC_CORE_LIB_ADDRESS_UTILS_PARSE_ADDRESS_H
+#define GRPC_CORE_LIB_ADDRESS_UTILS_PARSE_ADDRESS_H
 
 #include <grpc/support/port_platform.h>
 
@@ -64,14 +64,14 @@ uint16_t grpc_strhtons(const char* port);
 namespace grpc_core {
 
 /** Populate \a resolved_addr to be a unix socket at |path| */
-grpc_error* UnixSockaddrPopulate(absl::string_view path,
-                                 grpc_resolved_address* resolved_addr);
+grpc_error_handle UnixSockaddrPopulate(absl::string_view path,
+                                       grpc_resolved_address* resolved_addr);
 
 /** Populate \a resolved_addr to be a unix socket in the abstract namespace
  * at |path| */
-grpc_error* UnixAbstractSockaddrPopulate(absl::string_view path,
-                                         grpc_resolved_address* resolved_addr);
+grpc_error_handle UnixAbstractSockaddrPopulate(
+    absl::string_view path, grpc_resolved_address* resolved_addr);
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_LIB_IOMGR_PARSE_ADDRESS_H */
+#endif /* GRPC_CORE_LIB_ADDRESS_UTILS_PARSE_ADDRESS_H */
similarity index 94%
rename from src/core/lib/iomgr/sockaddr_utils.cc
rename to src/core/lib/address_utils/sockaddr_utils.cc
index 4c36a0c..888cd1a 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 
 #include <errno.h>
 #include <inttypes.h>
@@ -198,25 +198,8 @@ std::string grpc_sockaddr_to_string(const grpc_resolved_address* resolved_addr,
   return out;
 }
 
-void grpc_string_to_sockaddr(grpc_resolved_address* out, const char* addr,
-                             int port) {
-  memset(out, 0, sizeof(grpc_resolved_address));
-  grpc_sockaddr_in6* addr6 = reinterpret_cast<grpc_sockaddr_in6*>(out->addr);
-  grpc_sockaddr_in* addr4 = reinterpret_cast<grpc_sockaddr_in*>(out->addr);
-  if (grpc_inet_pton(GRPC_AF_INET6, addr, &addr6->sin6_addr) == 1) {
-    addr6->sin6_family = GRPC_AF_INET6;
-    out->len = sizeof(grpc_sockaddr_in6);
-  } else if (grpc_inet_pton(GRPC_AF_INET, addr, &addr4->sin_addr) == 1) {
-    addr4->sin_family = GRPC_AF_INET;
-    out->len = sizeof(grpc_sockaddr_in);
-  } else {
-    GPR_ASSERT(0);
-  }
-  grpc_sockaddr_set_port(out, port);
-}
-
-grpc_error* grpc_string_to_sockaddr_new(grpc_resolved_address* out,
-                                        const char* addr, int port) {
+grpc_error_handle grpc_string_to_sockaddr(grpc_resolved_address* out,
+                                          const char* addr, int port) {
   memset(out, 0, sizeof(grpc_resolved_address));
   grpc_sockaddr_in6* addr6 = reinterpret_cast<grpc_sockaddr_in6*>(out->addr);
   grpc_sockaddr_in* addr4 = reinterpret_cast<grpc_sockaddr_in*>(out->addr);
similarity index 87%
rename from src/core/lib/iomgr/sockaddr_utils.h
rename to src/core/lib/address_utils/sockaddr_utils.h
index f009692..e8bf79f 100644 (file)
@@ -16,8 +16,8 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H
-#define GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H
+#ifndef GRPC_CORE_LIB_ADDRESS_UTILS_SOCKADDR_UTILS_H
+#define GRPC_CORE_LIB_ADDRESS_UTILS_SOCKADDR_UTILS_H
 
 #include <grpc/support/port_platform.h>
 
@@ -64,17 +64,12 @@ int grpc_sockaddr_set_port(grpc_resolved_address* addr, int port);
 // If the normalize flag is enabled, ::ffff:0.0.0.0/96 IPv6 addresses are
 // displayed as plain IPv4.
 std::string grpc_sockaddr_to_string(const grpc_resolved_address* addr,
-                                    bool normalize);
-
-// TODO(yashykt): Remove this function and replace usages with
-// `grpc_string_to_sockaddr_new`
-void grpc_string_to_sockaddr(grpc_resolved_address* out, const char* addr,
-                             int port);
+                                    bool normalize) GRPC_MUST_USE_RESULT;
 
 // Newer form of grpc_string_to_sockaddr which returns an error instead of
 // crashing if \a addr is not IPv6/IPv6
-grpc_error* grpc_string_to_sockaddr_new(grpc_resolved_address* out,
-                                        const char* addr, int port);
+grpc_error_handle grpc_string_to_sockaddr(grpc_resolved_address* out,
+                                          const char* addr, int port);
 
 /* Returns the URI string corresponding to \a addr */
 std::string grpc_sockaddr_to_uri(const grpc_resolved_address* addr);
@@ -102,4 +97,4 @@ bool grpc_sockaddr_match_subnet(const grpc_resolved_address* address,
                                 const grpc_resolved_address* subnet_address,
                                 uint32_t mask_bits);
 
-#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H */
+#endif /* GRPC_CORE_LIB_ADDRESS_UTILS_SOCKADDR_UTILS_H */
index 60b8366..122d7a9 100644 (file)
@@ -98,7 +98,7 @@ grpc_call_element* grpc_call_stack_element(grpc_call_stack* call_stack,
   return CALL_ELEMS_FROM_STACK(call_stack) + index;
 }
 
-grpc_error* grpc_channel_stack_init(
+grpc_error_handle grpc_channel_stack_init(
     int initial_refs, grpc_iomgr_cb_func destroy, void* destroy_arg,
     const grpc_channel_filter** filters, size_t filter_count,
     const grpc_channel_args* channel_args, grpc_transport* optional_transport,
@@ -120,7 +120,7 @@ grpc_error* grpc_channel_stack_init(
                                              sizeof(grpc_channel_element));
 
   /* init per-filter data */
-  grpc_error* first_error = GRPC_ERROR_NONE;
+  grpc_error_handle first_error = GRPC_ERROR_NONE;
   for (i = 0; i < filter_count; i++) {
     args.channel_stack = stack;
     args.channel_args = channel_args;
@@ -129,7 +129,8 @@ grpc_error* grpc_channel_stack_init(
     args.is_last = i == (filter_count - 1);
     elems[i].filter = filters[i];
     elems[i].channel_data = user_data;
-    grpc_error* error = elems[i].filter->init_channel_elem(&elems[i], &args);
+    grpc_error_handle error =
+        elems[i].filter->init_channel_elem(&elems[i], &args);
     if (error != GRPC_ERROR_NONE) {
       if (first_error == GRPC_ERROR_NONE) {
         first_error = error;
@@ -161,10 +162,10 @@ void grpc_channel_stack_destroy(grpc_channel_stack* stack) {
   }
 }
 
-grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
-                                 int initial_refs, grpc_iomgr_cb_func destroy,
-                                 void* destroy_arg,
-                                 const grpc_call_element_args* elem_args) {
+grpc_error_handle grpc_call_stack_init(
+    grpc_channel_stack* channel_stack, int initial_refs,
+    grpc_iomgr_cb_func destroy, void* destroy_arg,
+    const grpc_call_element_args* elem_args) {
   grpc_channel_element* channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
   size_t count = channel_stack->count;
   grpc_call_element* call_elems;
@@ -178,7 +179,7 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
               GPR_ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
 
   /* init per-filter data */
-  grpc_error* first_error = GRPC_ERROR_NONE;
+  grpc_error_handle first_error = GRPC_ERROR_NONE;
   for (size_t i = 0; i < count; i++) {
     call_elems[i].filter = channel_elems[i].filter;
     call_elems[i].channel_data = channel_elems[i].channel_data;
@@ -187,7 +188,7 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
         GPR_ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
   }
   for (size_t i = 0; i < count; i++) {
-    grpc_error* error =
+    grpc_error_handle error =
         call_elems[i].filter->init_call_elem(&call_elems[i], elem_args);
     if (error != GRPC_ERROR_NONE) {
       if (first_error == GRPC_ERROR_NONE) {
index 1573ae1..4832303 100644 (file)
@@ -125,8 +125,8 @@ struct grpc_channel_filter {
      transport and is on the server. Most filters want to ignore this
      argument.
      Implementations may assume that elem->call_data is all zeros. */
-  grpc_error* (*init_call_elem)(grpc_call_element* elem,
-                                const grpc_call_element_args* args);
+  grpc_error_handle (*init_call_elem)(grpc_call_element* elem,
+                                      const grpc_call_element_args* args);
   void (*set_pollset_or_pollset_set)(grpc_call_element* elem,
                                      grpc_polling_entity* pollent);
   /* Destroy per call data.
@@ -148,8 +148,8 @@ struct grpc_channel_filter {
      useful for asserting correct configuration by upper layer code.
      The filter does not need to do any chaining.
      Implementations may assume that elem->channel_data is all zeros. */
-  grpc_error* (*init_channel_elem)(grpc_channel_element* elem,
-                                   grpc_channel_element_args* args);
+  grpc_error_handle (*init_channel_elem)(grpc_channel_element* elem,
+                                         grpc_channel_element_args* args);
   /* Destroy per channel data.
      The filter does not need to do any chaining */
   void (*destroy_channel_elem)(grpc_channel_element* elem);
@@ -218,7 +218,7 @@ grpc_call_element* grpc_call_stack_element(grpc_call_stack* stack, size_t i);
 size_t grpc_channel_stack_size(const grpc_channel_filter** filters,
                                size_t filter_count);
 /* Initialize a channel stack given some filters */
-grpc_error* grpc_channel_stack_init(
+grpc_error_handle grpc_channel_stack_init(
     int initial_refs, grpc_iomgr_cb_func destroy, void* destroy_arg,
     const grpc_channel_filter** filters, size_t filter_count,
     const grpc_channel_args* args, grpc_transport* optional_transport,
@@ -229,10 +229,11 @@ void grpc_channel_stack_destroy(grpc_channel_stack* stack);
 /* Initialize a call stack given a channel stack. transport_server_data is
    expected to be NULL on a client, or an opaque transport owned pointer on the
    server. */
-grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
-                                 int initial_refs, grpc_iomgr_cb_func destroy,
-                                 void* destroy_arg,
-                                 const grpc_call_element_args* elem_args);
+grpc_error_handle grpc_call_stack_init(grpc_channel_stack* channel_stack,
+                                       int initial_refs,
+                                       grpc_iomgr_cb_func destroy,
+                                       void* destroy_arg,
+                                       const grpc_call_element_args* elem_args);
 /* Set a pollset or a pollset_set for a call stack: must occur before the first
  * op is started */
 void grpc_call_stack_set_pollset_or_pollset_set(grpc_call_stack* call_stack,
index 8b3008f..7f7cf75 100644 (file)
@@ -267,7 +267,7 @@ void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder* builder) {
   gpr_free(builder);
 }
 
-grpc_error* grpc_channel_stack_builder_finish(
+grpc_error_handle grpc_channel_stack_builder_finish(
     grpc_channel_stack_builder* builder, size_t prefix_bytes, int initial_refs,
     grpc_iomgr_cb_func destroy, void* destroy_arg, void** result) {
   // count the number of filters
@@ -294,7 +294,7 @@ grpc_error* grpc_channel_stack_builder_finish(
   grpc_channel_stack* channel_stack = reinterpret_cast<grpc_channel_stack*>(
       static_cast<char*>(*result) + prefix_bytes);
   // and initialize it
-  grpc_error* error = grpc_channel_stack_init(
+  grpc_error_handle error = grpc_channel_stack_init(
       initial_refs, destroy, destroy_arg == nullptr ? *result : destroy_arg,
       filters, num_filters, builder->args, builder->transport, builder->name,
       channel_stack);
index 89c30e0..6782a14 100644 (file)
@@ -156,7 +156,7 @@ void grpc_channel_stack_builder_iterator_destroy(
 /// Returns the base pointer of the allocated block
 /// \a initial_refs, \a destroy, \a destroy_arg are as per
 /// grpc_channel_stack_init
-grpc_error* grpc_channel_stack_builder_finish(
+grpc_error_handle grpc_channel_stack_builder_finish(
     grpc_channel_stack_builder* builder, size_t prefix_bytes, int initial_refs,
     grpc_iomgr_cb_func destroy, void* destroy_arg, void** result);
 
index d360239..452d664 100644 (file)
 #include <grpc/impl/codegen/port_platform.h>
 
 #include "src/core/lib/channel/channelz.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "absl/strings/escaping.h"
 #include "absl/strings/strip.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channelz_registry.h"
 #include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/gpr/string.h"
@@ -42,6 +42,7 @@
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/slice/b64.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/channel.h"
@@ -437,14 +438,21 @@ void PopulateSocketAddressJson(Json::Object* json, const char* name,
       port_num = atoi(port.data());
     }
     grpc_resolved_address resolved_host;
-    grpc_string_to_sockaddr(&resolved_host, host.c_str(), port_num);
-    std::string packed_host = grpc_sockaddr_get_packed_host(&resolved_host);
-    std::string b64_host = absl::Base64Escape(packed_host);
-    data["tcpip_address"] = Json::Object{
-        {"port", port_num},
-        {"ip_address", b64_host},
-    };
-  } else if (uri.ok() && uri->scheme() == "unix") {
+    grpc_error_handle error =
+        grpc_string_to_sockaddr(&resolved_host, host.c_str(), port_num);
+    if (error == GRPC_ERROR_NONE) {
+      std::string packed_host = grpc_sockaddr_get_packed_host(&resolved_host);
+      std::string b64_host = absl::Base64Escape(packed_host);
+      data["tcpip_address"] = Json::Object{
+          {"port", port_num},
+          {"ip_address", b64_host},
+      };
+      (*json)[name] = std::move(data);
+      return;
+    }
+    GRPC_ERROR_UNREF(error);
+  }
+  if (uri.ok() && uri->scheme() == "unix") {
     data["uds_address"] = Json::Object{
         {"filename", uri->path()},
     };
index be74d9e..12b3d78 100644 (file)
@@ -53,13 +53,13 @@ typedef struct connected_channel_call_data {
   callback_state recv_trailing_metadata_ready;
 } call_data;
 
-static void run_in_call_combiner(void* arg, grpc_error* error) {
+static void run_in_call_combiner(void* arg, grpc_error_handle error) {
   callback_state* state = static_cast<callback_state*>(arg);
   GRPC_CALL_COMBINER_START(state->call_combiner, state->original_closure,
                            GRPC_ERROR_REF(error), state->reason);
 }
 
-static void run_cancel_in_call_combiner(void* arg, grpc_error* error) {
+static void run_cancel_in_call_combiner(void* arg, grpc_error_handle error) {
   run_in_call_combiner(arg, error);
   gpr_free(arg);
 }
@@ -146,7 +146,7 @@ static void connected_channel_start_transport_op(grpc_channel_element* elem,
 }
 
 /* Constructor for call_data */
-static grpc_error* connected_channel_init_call_elem(
+static grpc_error_handle connected_channel_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
@@ -179,7 +179,7 @@ static void connected_channel_destroy_call_elem(
 }
 
 /* Constructor for channel_data */
-static grpc_error* connected_channel_init_channel_elem(
+static grpc_error_handle connected_channel_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   channel_data* cd = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(args->is_last);
index e3ba3fc..632d286 100644 (file)
@@ -68,7 +68,7 @@ void HandshakeManager::Add(RefCountedPtr<Handshaker> handshaker) {
 
 HandshakeManager::~HandshakeManager() { handshakers_.clear(); }
 
-void HandshakeManager::Shutdown(grpc_error* why) {
+void HandshakeManager::Shutdown(grpc_error_handle why) {
   {
     MutexLock lock(&mu_);
     // Shutdown the handshaker that's currently in progress, if any.
@@ -83,12 +83,12 @@ void HandshakeManager::Shutdown(grpc_error* why) {
 // Helper function to call either the next handshaker or the
 // on_handshake_done callback.
 // Returns true if we've scheduled the on_handshake_done callback.
-bool HandshakeManager::CallNextHandshakerLocked(grpc_error* error) {
+bool HandshakeManager::CallNextHandshakerLocked(grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_handshaker_trace)) {
     gpr_log(GPR_INFO,
             "handshake_manager %p: error=%s shutdown=%d index=%" PRIuPTR
             ", args=%s",
-            this, grpc_error_string(error), is_shutdown_, index_,
+            this, grpc_error_std_string(error).c_str(), is_shutdown_, index_,
             HandshakerArgsString(&args_).c_str());
   }
   GPR_ASSERT(index_ <= handshakers_.size());
@@ -121,7 +121,7 @@ bool HandshakeManager::CallNextHandshakerLocked(grpc_error* error) {
       gpr_log(GPR_INFO,
               "handshake_manager %p: handshaking complete -- scheduling "
               "on_handshake_done with error=%s",
-              this, grpc_error_string(error));
+              this, grpc_error_std_string(error).c_str());
     }
     // Cancel deadline timer, since we're invoking the on_handshake_done
     // callback now.
@@ -142,7 +142,8 @@ bool HandshakeManager::CallNextHandshakerLocked(grpc_error* error) {
   return is_shutdown_;
 }
 
-void HandshakeManager::CallNextHandshakerFn(void* arg, grpc_error* error) {
+void HandshakeManager::CallNextHandshakerFn(void* arg,
+                                            grpc_error_handle error) {
   auto* mgr = static_cast<HandshakeManager*>(arg);
   bool done;
   {
@@ -157,7 +158,7 @@ void HandshakeManager::CallNextHandshakerFn(void* arg, grpc_error* error) {
   }
 }
 
-void HandshakeManager::OnTimeoutFn(void* arg, grpc_error* error) {
+void HandshakeManager::OnTimeoutFn(void* arg, grpc_error_handle error) {
   auto* mgr = static_cast<HandshakeManager*>(arg);
   if (error == GRPC_ERROR_NONE) {  // Timer fired, rather than being cancelled
     mgr->Shutdown(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake timed out"));
index 942b5fe..b6b69da 100644 (file)
@@ -78,7 +78,7 @@ struct HandshakerArgs {
 class Handshaker : public RefCounted<Handshaker> {
  public:
   ~Handshaker() override = default;
-  virtual void Shutdown(grpc_error* why) = 0;
+  virtual void Shutdown(grpc_error_handle why) = 0;
   virtual void DoHandshake(grpc_tcp_server_acceptor* acceptor,
                            grpc_closure* on_handshake_done,
                            HandshakerArgs* args) = 0;
@@ -100,7 +100,7 @@ class HandshakeManager : public RefCounted<HandshakeManager> {
 
   /// Shuts down the handshake manager (e.g., to clean up when the operation is
   /// aborted in the middle).
-  void Shutdown(grpc_error* why);
+  void Shutdown(grpc_error_handle why);
 
   /// Invokes handshakers in the order they were added.
   /// Takes ownership of \a endpoint, and then passes that ownership to
@@ -120,14 +120,14 @@ class HandshakeManager : public RefCounted<HandshakeManager> {
                    grpc_iomgr_cb_func on_handshake_done, void* user_data);
 
  private:
-  bool CallNextHandshakerLocked(grpc_error* error);
+  bool CallNextHandshakerLocked(grpc_error_handle error);
 
   // A function used as the handshaker-done callback when chaining
   // handshakers together.
-  static void CallNextHandshakerFn(void* arg, grpc_error* error);
+  static void CallNextHandshakerFn(void* arg, grpc_error_handle error);
 
   // Callback invoked when deadline is exceeded.
-  static void OnTimeoutFn(void* arg, grpc_error* error);
+  static void OnTimeoutFn(void* arg, grpc_error_handle error);
 
   static const size_t HANDSHAKERS_INIT_SIZE = 2;
 
diff --git a/src/core/lib/event_engine/slice_allocator.cc b/src/core/lib/event_engine/slice_allocator.cc
new file mode 100644 (file)
index 0000000..3ea615a
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2021 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 <grpc/support/port_platform.h>
+
+#include "grpc/event_engine/slice_allocator.h"
+
+#include <functional>
+
+#include "absl/status/status.h"
+
+#include "src/core/lib/iomgr/resource_quota.h"
+
+namespace grpc_event_engine {
+namespace experimental {
+
+SliceAllocator::SliceAllocator(grpc_resource_user* user)
+    : resource_user_(user) {
+  grpc_resource_user_ref(resource_user_);
+};
+
+SliceAllocator::~SliceAllocator() { grpc_resource_user_unref(resource_user_); };
+
+absl::Status SliceAllocator::Allocate(size_t size, SliceBuffer* dest,
+                                      SliceAllocator::AllocateCallback cb) {
+  // TODO(hork): implement
+  (void)size;
+  (void)dest;
+  (void)cb;
+  return absl::OkStatus();
+};
+
+SliceAllocatorFactory::SliceAllocatorFactory(grpc_resource_quota* quota)
+    : resource_quota_(quota) {
+  grpc_resource_quota_ref_internal(resource_quota_);
+};
+
+SliceAllocatorFactory::~SliceAllocatorFactory() {
+  grpc_resource_quota_unref_internal(resource_quota_);
+}
+
+SliceAllocator SliceAllocatorFactory::CreateSliceAllocator(
+    absl::string_view peer_name) {
+  return SliceAllocator(
+      grpc_resource_user_create(resource_quota_, peer_name.data()));
+}
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
diff --git a/src/core/lib/event_engine/sockaddr.cc b/src/core/lib/event_engine/sockaddr.cc
new file mode 100644 (file)
index 0000000..811d351
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2021 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 <grpc/support/port_platform.h>
+
+#include <string.h>
+
+#include "grpc/event_engine/event_engine.h"
+#include "grpc/event_engine/port.h"
+#include "grpc/support/log.h"
+
+namespace grpc_event_engine {
+namespace experimental {
+
+EventEngine::ResolvedAddress::ResolvedAddress(const sockaddr* address,
+                                              socklen_t size) {
+  GPR_ASSERT(size <= sizeof(address_));
+  memcpy(&address_, address, size);
+}
+
+const struct sockaddr* EventEngine::ResolvedAddress::address() const {
+  return reinterpret_cast<const struct sockaddr*>(address_);
+}
+
+socklen_t EventEngine::ResolvedAddress::size() const { return size_; }
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
index 47e2aad..a8def8c 100644 (file)
@@ -215,31 +215,45 @@ class NonPolymorphicRefCount {
   ~NonPolymorphicRefCount() = default;
 };
 
+// Behavior of RefCounted<> upon ref count reaching 0.
+enum UnrefBehavior {
+  // Default behavior: Delete the object.
+  kUnrefDelete,
+  // Do not delete the object upon unref.  This is useful in cases where all
+  // existing objects must be tracked in a registry but the object's entry in
+  // the registry cannot be removed from the object's dtor due to
+  // synchronization issues.  In this case, the registry can be cleaned up
+  // later by identifying entries for which RefIfNonZero() returns null.
+  kUnrefNoDelete,
+  // Call the object's dtor but do not delete it.  This is useful for cases
+  // where the object is stored in memory allocated elsewhere (e.g., the call
+  // arena).
+  kUnrefCallDtor,
+};
+
 namespace internal {
-template <typename T, bool DoDelete>
+template <typename T, UnrefBehavior UnrefBehaviorArg>
 class Delete;
 template <typename T>
-class Delete<T, true> {
+class Delete<T, kUnrefDelete> {
  public:
   explicit Delete(T* t) { delete t; }
 };
 template <typename T>
-class Delete<T, false> {
+class Delete<T, kUnrefNoDelete> {
  public:
   explicit Delete(T* /*t*/) {}
 };
+template <typename T>
+class Delete<T, kUnrefCallDtor> {
+ public:
+  explicit Delete(T* t) { t->~T(); }
+};
 }  // namespace internal
 
 // A base class for reference-counted objects.
 // New objects should be created via new and start with a refcount of 1.
-// When the refcount reaches 0, the object will be deleted via delete.
-//
-// If DeleteUponUnref is false, deletion will not occur when the ref
-// count reaches 0.  This is useful in cases where all existing objects
-// must be tracked in a registry but the object's entry in the registry
-// cannot be removed from the object's dtor due to synchronization issues.
-// In this case, the registry can be cleaned up later by identifying
-// entries for which RefIfNonZero() returns null.
+// When the refcount reaches 0, executes the specified UnrefBehavior.
 //
 // This will commonly be used by CRTP (curiously-recurring template pattern)
 // e.g., class MyClass : public RefCounted<MyClass>
@@ -264,7 +278,7 @@ class Delete<T, false> {
 //    ch->Unref();
 //
 template <typename Child, typename Impl = PolymorphicRefCount,
-          bool DeleteUponUnref = true>
+          UnrefBehavior UnrefBehaviorArg = kUnrefDelete>
 class RefCounted : public Impl {
  public:
   // Note: Depending on the Impl used, this dtor can be implicitly virtual.
@@ -287,12 +301,12 @@ class RefCounted : public Impl {
   // friend of this class.
   void Unref() {
     if (GPR_UNLIKELY(refs_.Unref())) {
-      internal::Delete<Child, DeleteUponUnref>(static_cast<Child*>(this));
+      internal::Delete<Child, UnrefBehaviorArg>(static_cast<Child*>(this));
     }
   }
   void Unref(const DebugLocation& location, const char* reason) {
     if (GPR_UNLIKELY(refs_.Unref(location, reason))) {
-      internal::Delete<Child, DeleteUponUnref>(static_cast<Child*>(this));
+      internal::Delete<Child, UnrefBehaviorArg>(static_cast<Child*>(this));
     }
   }
 
diff --git a/src/core/lib/gprpp/status_helper.cc b/src/core/lib/gprpp/status_helper.cc
new file mode 100644 (file)
index 0000000..8266e16
--- /dev/null
@@ -0,0 +1,407 @@
+//
+//
+// Copyright 2021 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/gprpp/status_helper.h"
+#include "src/core/lib/gprpp/time_util.h"
+
+#include <grpc/support/log.h>
+
+#include "absl/strings/cord.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/match.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+#include "absl/time/clock.h"
+
+#include "google/protobuf/any.upb.h"
+#include "google/rpc/status.upb.h"
+#include "upb/upb.hpp"
+
+namespace grpc_core {
+
+namespace {
+
+#define TYPE_URL_PREFIX "type.googleapis.com/grpc.status."
+#define TYPE_INT_TAG "int."
+#define TYPE_STR_TAG "str."
+#define TYPE_TIME_TAG "time."
+#define TYPE_CHILDREN_TAG "children"
+#define TYPE_URL(name) (TYPE_URL_PREFIX name)
+const absl::string_view kTypeUrlPrefix = TYPE_URL_PREFIX;
+const absl::string_view kTypeIntTag = TYPE_INT_TAG;
+const absl::string_view kTypeStrTag = TYPE_STR_TAG;
+const absl::string_view kTypeTimeTag = TYPE_TIME_TAG;
+const absl::string_view kTypeChildrenTag = TYPE_CHILDREN_TAG;
+const absl::string_view kChildrenPropertyUrl = TYPE_URL(TYPE_CHILDREN_TAG);
+
+const char* GetStatusIntPropertyUrl(StatusIntProperty key) {
+  switch (key) {
+    case StatusIntProperty::kErrorNo:
+      return TYPE_URL(TYPE_INT_TAG "errno");
+    case StatusIntProperty::kFileLine:
+      return TYPE_URL(TYPE_INT_TAG "file_line");
+    case StatusIntProperty::kStreamId:
+      return TYPE_URL(TYPE_INT_TAG "stream_id");
+    case StatusIntProperty::kRpcStatus:
+      return TYPE_URL(TYPE_INT_TAG "grpc_status");
+    case StatusIntProperty::kOffset:
+      return TYPE_URL(TYPE_INT_TAG "offset");
+    case StatusIntProperty::kIndex:
+      return TYPE_URL(TYPE_INT_TAG "index");
+    case StatusIntProperty::kSize:
+      return TYPE_URL(TYPE_INT_TAG "size");
+    case StatusIntProperty::kHttp2Error:
+      return TYPE_URL(TYPE_INT_TAG "http2_error");
+    case StatusIntProperty::kTsiCode:
+      return TYPE_URL(TYPE_INT_TAG "tsi_code");
+    case StatusIntProperty::kWsaError:
+      return TYPE_URL(TYPE_INT_TAG "wsa_error");
+    case StatusIntProperty::kFd:
+      return TYPE_URL(TYPE_INT_TAG "fd");
+    case StatusIntProperty::kHttpStatus:
+      return TYPE_URL(TYPE_INT_TAG "http_status");
+    case StatusIntProperty::kOccurredDuringWrite:
+      return TYPE_URL(TYPE_INT_TAG "occurred_during_write");
+    case StatusIntProperty::ChannelConnectivityState:
+      return TYPE_URL(TYPE_INT_TAG "channel_connectivity_state");
+    case StatusIntProperty::kLbPolicyDrop:
+      return TYPE_URL(TYPE_INT_TAG "lb_policy_drop");
+  }
+  GPR_UNREACHABLE_CODE(return "unknown");
+}
+
+const char* GetStatusStrPropertyUrl(StatusStrProperty key) {
+  switch (key) {
+    case StatusStrProperty::kDescription:
+      return TYPE_URL(TYPE_STR_TAG "description");
+    case StatusStrProperty::kFile:
+      return TYPE_URL(TYPE_STR_TAG "file");
+    case StatusStrProperty::kOsError:
+      return TYPE_URL(TYPE_STR_TAG "os_error");
+    case StatusStrProperty::kSyscall:
+      return TYPE_URL(TYPE_STR_TAG "syscall");
+    case StatusStrProperty::kTargetAddress:
+      return TYPE_URL(TYPE_STR_TAG "target_address");
+    case StatusStrProperty::kGrpcMessage:
+      return TYPE_URL(TYPE_STR_TAG "grpc_message");
+    case StatusStrProperty::kRawBytes:
+      return TYPE_URL(TYPE_STR_TAG "raw_bytes");
+    case StatusStrProperty::kTsiError:
+      return TYPE_URL(TYPE_STR_TAG "tsi_error");
+    case StatusStrProperty::kFilename:
+      return TYPE_URL(TYPE_STR_TAG "filename");
+    case StatusStrProperty::kKey:
+      return TYPE_URL(TYPE_STR_TAG "key");
+    case StatusStrProperty::kValue:
+      return TYPE_URL(TYPE_STR_TAG "value");
+  }
+  GPR_UNREACHABLE_CODE(return "unknown");
+}
+
+const char* GetStatusTimePropertyUrl(StatusTimeProperty key) {
+  switch (key) {
+    case StatusTimeProperty::kCreated:
+      return TYPE_URL(TYPE_TIME_TAG "created_time");
+  }
+  GPR_UNREACHABLE_CODE(return "unknown");
+}
+
+void EncodeUInt32ToBytes(uint32_t v, char* buf) {
+  buf[0] = v & 0xFF;
+  buf[1] = (v >> 8) & 0xFF;
+  buf[2] = (v >> 16) & 0xFF;
+  buf[3] = (v >> 24) & 0xFF;
+}
+
+uint32_t DecodeUInt32FromBytes(const char* buf) {
+  return buf[0] | (uint32_t(buf[1]) << 8) | (uint32_t(buf[2]) << 16) |
+         (uint32_t(buf[3]) << 24);
+}
+
+std::vector<absl::Status> ParseChildren(absl::Cord children) {
+  std::vector<absl::Status> result;
+  upb::Arena arena;
+  // Cord is flattened to iterate the buffer easily at the cost of memory copy.
+  // TODO(veblush): Optimize this once CordReader is introduced.
+  absl::string_view buf = children.Flatten();
+  size_t cur = 0;
+  while (buf.size() - cur >= sizeof(uint32_t)) {
+    size_t msg_size = DecodeUInt32FromBytes(buf.data() + cur);
+    cur += sizeof(uint32_t);
+    GPR_ASSERT(buf.size() - cur >= msg_size);
+    google_rpc_Status* msg =
+        google_rpc_Status_parse(buf.data() + cur, msg_size, arena.ptr());
+    cur += msg_size;
+    result.push_back(internal::StatusFromProto(msg));
+  }
+  return result;
+}
+
+}  // namespace
+
+absl::Status StatusCreate(absl::StatusCode code, absl::string_view msg,
+                          const DebugLocation& location,
+                          std::initializer_list<absl::Status> children) {
+  absl::Status s(code, msg);
+  if (location.file() != nullptr) {
+    StatusSetStr(&s, StatusStrProperty::kFile, location.file());
+  }
+  if (location.line() != -1) {
+    StatusSetInt(&s, StatusIntProperty::kFileLine, location.line());
+  }
+  StatusSetTime(&s, StatusTimeProperty::kCreated, absl::Now());
+  for (const absl::Status& child : children) {
+    if (!child.ok()) {
+      StatusAddChild(&s, child);
+    }
+  }
+  return s;
+}
+
+void StatusSetInt(absl::Status* status, StatusIntProperty key, intptr_t value) {
+  status->SetPayload(GetStatusIntPropertyUrl(key),
+                     absl::Cord(std::to_string(value)));
+}
+
+absl::optional<intptr_t> StatusGetInt(const absl::Status& status,
+                                      StatusIntProperty key) {
+  absl::optional<absl::Cord> p =
+      status.GetPayload(GetStatusIntPropertyUrl(key));
+  if (p.has_value()) {
+    absl::optional<absl::string_view> sv = p->TryFlat();
+    intptr_t value;
+    if (sv.has_value()) {
+      if (absl::SimpleAtoi(*sv, &value)) {
+        return value;
+      }
+    } else {
+      if (absl::SimpleAtoi(std::string(*p), &value)) {
+        return value;
+      }
+    }
+  }
+  return {};
+}
+
+void StatusSetStr(absl::Status* status, StatusStrProperty key,
+                  absl::string_view value) {
+  status->SetPayload(GetStatusStrPropertyUrl(key), absl::Cord(value));
+}
+
+absl::optional<std::string> StatusGetStr(const absl::Status& status,
+                                         StatusStrProperty key) {
+  absl::optional<absl::Cord> p =
+      status.GetPayload(GetStatusStrPropertyUrl(key));
+  if (p.has_value()) {
+    return std::string(*p);
+  }
+  return {};
+}
+
+void StatusSetTime(absl::Status* status, StatusTimeProperty key,
+                   absl::Time time) {
+  status->SetPayload(GetStatusTimePropertyUrl(key),
+                     absl::Cord(absl::string_view(
+                         reinterpret_cast<const char*>(&time), sizeof(time))));
+}
+
+absl::optional<absl::Time> StatusGetTime(const absl::Status& status,
+                                         StatusTimeProperty key) {
+  absl::optional<absl::Cord> p =
+      status.GetPayload(GetStatusTimePropertyUrl(key));
+  if (p.has_value()) {
+    absl::optional<absl::string_view> sv = p->TryFlat();
+    if (sv.has_value()) {
+      return *reinterpret_cast<const absl::Time*>(sv->data());
+    } else {
+      std::string s = std::string(*p);
+      return *reinterpret_cast<const absl::Time*>(s.c_str());
+    }
+  }
+  return {};
+}
+
+void StatusAddChild(absl::Status* status, absl::Status child) {
+  upb::Arena arena;
+  // Serialize msg to buf
+  google_rpc_Status* msg = internal::StatusToProto(child, arena.ptr());
+  size_t buf_len = 0;
+  char* buf = google_rpc_Status_serialize(msg, arena.ptr(), &buf_len);
+  // Append (msg-length and msg) to children payload
+  absl::optional<absl::Cord> old_children =
+      status->GetPayload(kChildrenPropertyUrl);
+  absl::Cord children;
+  if (old_children.has_value()) {
+    children = *old_children;
+  }
+  char head_buf[sizeof(uint32_t)];
+  EncodeUInt32ToBytes(buf_len, head_buf);
+  children.Append(absl::string_view(head_buf, sizeof(uint32_t)));
+  children.Append(absl::string_view(buf, buf_len));
+  status->SetPayload(kChildrenPropertyUrl, std::move(children));
+}
+
+std::vector<absl::Status> StatusGetChildren(absl::Status status) {
+  absl::optional<absl::Cord> children = status.GetPayload(kChildrenPropertyUrl);
+  return children.has_value() ? ParseChildren(*children)
+                              : std::vector<absl::Status>();
+}
+
+std::string StatusToString(const absl::Status& status) {
+  if (status.ok()) {
+    return "OK";
+  }
+  std::string head;
+  absl::StrAppend(&head, absl::StatusCodeToString(status.code()));
+  if (!status.message().empty()) {
+    absl::StrAppend(&head, ":", status.message());
+  }
+  std::vector<std::string> kvs;
+  absl::optional<absl::Cord> children;
+  status.ForEachPayload([&](absl::string_view type_url,
+                            const absl::Cord& payload) {
+    if (absl::StartsWith(type_url, kTypeUrlPrefix)) {
+      type_url.remove_prefix(kTypeUrlPrefix.size());
+      if (type_url == kTypeChildrenTag) {
+        children = payload;
+        return;
+      }
+      absl::string_view payload_view;
+      std::string payload_storage;
+      if (payload.TryFlat().has_value()) {
+        payload_view = payload.TryFlat().value();
+      } else {
+        payload_storage = std::string(payload);
+        payload_view = payload_storage;
+      }
+      if (absl::StartsWith(type_url, kTypeIntTag)) {
+        type_url.remove_prefix(kTypeIntTag.size());
+        kvs.push_back(absl::StrCat(type_url, ":", payload_view));
+      } else if (absl::StartsWith(type_url, kTypeStrTag)) {
+        type_url.remove_prefix(kTypeStrTag.size());
+        kvs.push_back(absl::StrCat(type_url, ":\"",
+                                   absl::CHexEscape(payload_view), "\""));
+      } else if (absl::StartsWith(type_url, kTypeTimeTag)) {
+        type_url.remove_prefix(kTypeTimeTag.size());
+        absl::Time t =
+            *reinterpret_cast<const absl::Time*>(payload_view.data());
+        kvs.push_back(absl::StrCat(type_url, ":\"", absl::FormatTime(t), "\""));
+      } else {
+        kvs.push_back(absl::StrCat(type_url, ":\"",
+                                   absl::CHexEscape(payload_view), "\""));
+      }
+    } else {
+      absl::optional<absl::string_view> payload_view = payload.TryFlat();
+      std::string payload_str = absl::CHexEscape(
+          payload_view.has_value() ? *payload_view : std::string(payload));
+      kvs.push_back(absl::StrCat(type_url, ":\"", payload_str, "\""));
+    }
+  });
+  if (children.has_value()) {
+    std::vector<absl::Status> children_status = ParseChildren(*children);
+    std::vector<std::string> children_text;
+    children_text.reserve(children_status.size());
+    for (const absl::Status& child_status : children_status) {
+      children_text.push_back(StatusToString(child_status));
+    }
+    kvs.push_back(
+        absl::StrCat("children:[", absl::StrJoin(children_text, ", "), "]"));
+  }
+  return kvs.empty() ? head
+                     : absl::StrCat(head, " {", absl::StrJoin(kvs, ", "), "}");
+}
+
+namespace internal {
+
+google_rpc_Status* StatusToProto(absl::Status status, upb_arena* arena) {
+  google_rpc_Status* msg = google_rpc_Status_new(arena);
+  google_rpc_Status_set_code(msg, int32_t(status.code()));
+  google_rpc_Status_set_message(
+      msg, upb_strview_make(status.message().data(), status.message().size()));
+  status.ForEachPayload([&](absl::string_view type_url,
+                            const absl::Cord& payload) {
+    google_protobuf_Any* any = google_rpc_Status_add_details(msg, arena);
+    char* type_url_buf =
+        reinterpret_cast<char*>(upb_arena_malloc(arena, type_url.size()));
+    memcpy(type_url_buf, type_url.data(), type_url.size());
+    google_protobuf_Any_set_type_url(
+        any, upb_strview_make(type_url_buf, type_url.size()));
+    absl::optional<absl::string_view> v_view = payload.TryFlat();
+    if (v_view.has_value()) {
+      google_protobuf_Any_set_value(
+          any, upb_strview_make(v_view->data(), v_view->size()));
+    } else {
+      char* buf =
+          reinterpret_cast<char*>(upb_arena_malloc(arena, payload.size()));
+      char* cur = buf;
+      for (absl::string_view chunk : payload.Chunks()) {
+        memcpy(cur, chunk.data(), chunk.size());
+        cur += chunk.size();
+      }
+      google_protobuf_Any_set_value(any, upb_strview_make(buf, payload.size()));
+    }
+  });
+  return msg;
+}
+
+absl::Status StatusFromProto(google_rpc_Status* msg) {
+  int32_t code = google_rpc_Status_code(msg);
+  upb_strview message = google_rpc_Status_message(msg);
+  absl::Status status(static_cast<absl::StatusCode>(code),
+                      absl::string_view(message.data, message.size));
+  size_t detail_len;
+  const google_protobuf_Any* const* details =
+      google_rpc_Status_details(msg, &detail_len);
+  for (size_t i = 0; i < detail_len; i++) {
+    upb_strview type_url = google_protobuf_Any_type_url(details[i]);
+    upb_strview value = google_protobuf_Any_value(details[i]);
+    status.SetPayload(absl::string_view(type_url.data, type_url.size),
+                      absl::Cord(absl::string_view(value.data, value.size)));
+  }
+  return status;
+}
+
+uintptr_t StatusAllocPtr(absl::Status s) {
+  // This relies the fact that absl::Status has only one member, StatusRep*
+  // so the sizeof(absl::Status) has the same size of intptr_t and StatusRep*
+  // can be stolen using placement allocation.
+  static_assert(sizeof(intptr_t) == sizeof(absl::Status),
+                "absl::Status should be as big as intptr_t");
+  // This does two things;
+  // 1. Copies StatusRep* of absl::Status to ptr
+  // 2. Increases the counter of StatusRep if it's not inlined
+  uintptr_t ptr;
+  new (&ptr) absl::Status(s);
+  return ptr;
+}
+
+void StatusFreePtr(uintptr_t ptr) {
+  // Decreases the counter of StatusRep if it's not inlined.
+  reinterpret_cast<absl::Status*>(&ptr)->~Status();
+}
+
+absl::Status StatusGetFromPtr(uintptr_t ptr) {
+  // Constructs Status from ptr having the address of StatusRep.
+  return *reinterpret_cast<absl::Status*>(&ptr);
+}
+
+}  // namespace internal
+
+}  // namespace grpc_core
diff --git a/src/core/lib/gprpp/status_helper.h b/src/core/lib/gprpp/status_helper.h
new file mode 100644 (file)
index 0000000..50bcdff
--- /dev/null
@@ -0,0 +1,180 @@
+//
+//
+// Copyright 2021 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.
+//
+//
+
+#ifndef GRPC_CORE_LIB_GPRPP_STATUS_HELPER_H
+#define GRPC_CORE_LIB_GPRPP_STATUS_HELPER_H
+
+#include <grpc/support/port_platform.h>
+
+#include "absl/status/status.h"
+#include "absl/time/time.h"
+
+#include "src/core/lib/gprpp/debug_location.h"
+
+extern "C" {
+struct google_rpc_Status;
+struct upb_arena;
+}
+
+namespace grpc_core {
+
+/// This enum should have the same value of grpc_error_ints
+// TODO(veblush): Use camel-case names once migration to absl::Status is done.
+enum class StatusIntProperty {
+  /// 'errno' from the operating system
+  kErrorNo,
+  /// __LINE__ from the call site creating the error
+  kFileLine,
+  /// stream identifier: for errors that are associated with an individual
+  /// wire stream
+  kStreamId,
+  /// grpc status code representing this error
+  // TODO(veblush): Remove this after grpc_error is replaced with absl::Status
+  kRpcStatus,
+  /// offset into some binary blob (usually represented by
+  /// RAW_BYTES) where the error occurred
+  kOffset,
+  /// context sensitive index associated with the error
+  kIndex,
+  /// context sensitive size associated with the error
+  kSize,
+  /// http2 error code associated with the error (see the HTTP2 RFC)
+  kHttp2Error,
+  /// TSI status code associated with the error
+  kTsiCode,
+  /// WSAGetLastError() reported when this error occurred
+  kWsaError,
+  /// File descriptor associated with this error
+  kFd,
+  /// HTTP status (i.e. 404)
+  kHttpStatus,
+  /// chttp2: did the error occur while a write was in progress
+  kOccurredDuringWrite,
+  /// channel connectivity state associated with the error
+  ChannelConnectivityState,
+  /// LB policy drop
+  kLbPolicyDrop,
+};
+
+/// This enum should have the same value of grpc_error_strs
+// TODO(veblush): Use camel-case names once migration to absl::Status is done.
+enum class StatusStrProperty {
+  /// top-level textual description of this error
+  kDescription,
+  /// source file in which this error occurred
+  kFile,
+  /// operating system description of this error
+  kOsError,
+  /// syscall that generated this error
+  kSyscall,
+  /// peer that we were trying to communicate when this error occurred
+  kTargetAddress,
+  /// grpc status message associated with this error
+  kGrpcMessage,
+  /// hex dump (or similar) with the data that generated this error
+  kRawBytes,
+  /// tsi error string associated with this error
+  kTsiError,
+  /// filename that we were trying to read/write when this error occurred
+  kFilename,
+  /// key associated with the error
+  kKey,
+  /// value associated with the error
+  kValue,
+};
+
+/// This enum should have the same value of grpc_error_times
+enum class StatusTimeProperty {
+  /// timestamp of error creation
+  kCreated,
+};
+
+/// Creates a status with given additional information
+absl::Status StatusCreate(
+    absl::StatusCode code, absl::string_view msg, const DebugLocation& location,
+    std::initializer_list<absl::Status> children) GRPC_MUST_USE_RESULT;
+
+/// Sets the int property to the status
+void StatusSetInt(absl::Status* status, StatusIntProperty key, intptr_t value);
+
+/// Gets the int property from the status
+absl::optional<intptr_t> StatusGetInt(
+    const absl::Status& status, StatusIntProperty key) GRPC_MUST_USE_RESULT;
+
+/// Sets the str property to the status
+void StatusSetStr(absl::Status* status, StatusStrProperty key,
+                  absl::string_view value);
+
+/// Gets the str property from the status
+absl::optional<std::string> StatusGetStr(
+    const absl::Status& status, StatusStrProperty key) GRPC_MUST_USE_RESULT;
+
+/// Sets the time property to the status
+void StatusSetTime(absl::Status* status, StatusTimeProperty key,
+                   absl::Time time);
+
+/// Gets the time property from the status
+absl::optional<absl::Time> StatusGetTime(
+    const absl::Status& status, StatusTimeProperty key) GRPC_MUST_USE_RESULT;
+
+/// Adds a child status to status
+void StatusAddChild(absl::Status* status, absl::Status child);
+
+/// Returns all children status from a status
+std::vector<absl::Status> StatusGetChildren(absl::Status status)
+    GRPC_MUST_USE_RESULT;
+
+/// Returns a string representation from status
+/// Error status will be like
+///   STATUS[:MESSAGE] [{PAYLOADS[, children:[CHILDREN-STATUS-LISTS]]}]
+/// e.g.
+///   CANCELLATION:SampleMessage {errno:'2021', line:'54', children:[ABORTED]}
+std::string StatusToString(const absl::Status& status) GRPC_MUST_USE_RESULT;
+
+namespace internal {
+
+/// Builds a upb message, google_rpc_Status from a status
+/// This is for internal implementation & test only
+google_rpc_Status* StatusToProto(absl::Status status,
+                                 upb_arena* arena) GRPC_MUST_USE_RESULT;
+
+/// Builds a status from a upb message, google_rpc_Status
+/// This is for internal implementation & test only
+absl::Status StatusFromProto(google_rpc_Status* msg) GRPC_MUST_USE_RESULT;
+
+/// The same value of grpc_core::internal::StatusAllocPtr(absl::OkStatus())
+static constexpr uintptr_t kOkStatusPtr = 0;
+
+/// Returns ptr where the given status is copied into.
+/// This ptr can be used to get Status later and should be freed by
+/// StatusFreePtr. This shouldn't be used except migration purpose.
+uintptr_t StatusAllocPtr(absl::Status s);
+
+/// Frees the allocated status at ptr.
+/// This shouldn't be used except migration purpose.
+void StatusFreePtr(uintptr_t ptr);
+
+/// Get the status from ptr.
+/// This shouldn't be used except migration purpose.
+absl::Status StatusGetFromPtr(uintptr_t ptr);
+
+}  // namespace internal
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_LIB_GPRPP_STATUS_HELPER_H
index 8d024dd..e3d2fbe 100644 (file)
@@ -30,6 +30,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
@@ -38,7 +39,6 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/slice/slice_internal.h"
 
@@ -62,7 +62,7 @@ struct internal_request {
   grpc_closure on_read;
   grpc_closure done_write;
   grpc_closure connected;
-  grpc_error* overall_error;
+  grpc_error_handle overall_error;
   grpc_resource_quota* resource_quota;
 };
 static grpc_httpcli_get_override g_get_override = nullptr;
@@ -86,9 +86,9 @@ void grpc_httpcli_context_destroy(grpc_httpcli_context* context) {
   grpc_pollset_set_destroy(context->pollset_set);
 }
 
-static void next_address(internal_request* req, grpc_error* due_to_error);
+static void next_address(internal_request* req, grpc_error_handle due_to_error);
 
-static void finish(internal_request* req, grpc_error* error) {
+static void finish(internal_request* req, grpc_error_handle error) {
   grpc_polling_entity_del_from_pollset_set(req->pollent,
                                            req->context->pollset_set);
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, req->on_done, error);
@@ -110,7 +110,7 @@ static void finish(internal_request* req, grpc_error* error) {
   gpr_free(req);
 }
 
-static void append_error(internal_request* req, grpc_error* error) {
+static void append_error(internal_request* req, grpc_error_handle error) {
   if (req->overall_error == GRPC_ERROR_NONE) {
     req->overall_error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed HTTP/1 client request");
@@ -127,14 +127,14 @@ static void do_read(internal_request* req) {
   grpc_endpoint_read(req->ep, &req->incoming, &req->on_read, /*urgent=*/true);
 }
 
-static void on_read(void* user_data, grpc_error* error) {
+static void on_read(void* user_data, grpc_error_handle error) {
   internal_request* req = static_cast<internal_request*>(user_data);
   size_t i;
 
   for (i = 0; i < req->incoming.count; i++) {
     if (GRPC_SLICE_LENGTH(req->incoming.slices[i])) {
       req->have_read_byte = 1;
-      grpc_error* err = grpc_http_parser_parse(
+      grpc_error_handle err = grpc_http_parser_parse(
           &req->parser, req->incoming.slices[i], nullptr);
       if (err != GRPC_ERROR_NONE) {
         finish(req, err);
@@ -154,7 +154,7 @@ static void on_read(void* user_data, grpc_error* error) {
 
 static void on_written(internal_request* req) { do_read(req); }
 
-static void done_write(void* arg, grpc_error* error) {
+static void done_write(void* arg, grpc_error_handle error) {
   internal_request* req = static_cast<internal_request*>(arg);
   if (error == GRPC_ERROR_NONE) {
     on_written(req);
@@ -182,7 +182,7 @@ static void on_handshake_done(void* arg, grpc_endpoint* ep) {
   start_write(req);
 }
 
-static void on_connected(void* arg, grpc_error* error) {
+static void on_connected(void* arg, grpc_error_handle error) {
   internal_request* req = static_cast<internal_request*>(arg);
 
   if (!req->ep) {
@@ -194,7 +194,7 @@ static void on_connected(void* arg, grpc_error* error) {
       req->deadline, on_handshake_done);
 }
 
-static void next_address(internal_request* req, grpc_error* error) {
+static void next_address(internal_request* req, grpc_error_handle error) {
   grpc_resolved_address* addr;
   if (error != GRPC_ERROR_NONE) {
     append_error(req, error);
@@ -216,7 +216,7 @@ static void next_address(internal_request* req, grpc_error* error) {
                           &args, addr, req->deadline);
 }
 
-static void on_resolved(void* arg, grpc_error* error) {
+static void on_resolved(void* arg, grpc_error_handle error) {
   internal_request* req = static_cast<internal_request*>(arg);
   if (error != GRPC_ERROR_NONE) {
     finish(req, GRPC_ERROR_REF(error));
index 3ef4a4d..e26f99b 100644 (file)
@@ -91,7 +91,7 @@ class grpc_httpcli_ssl_channel_security_connector final
   void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
                   grpc_core::RefCountedPtr<grpc_auth_context>* /*auth_context*/,
                   grpc_closure* on_peer_checked) override {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
 
     /* Check the peer name. */
     if (secure_peer_name_ != nullptr &&
@@ -105,6 +105,11 @@ class grpc_httpcli_ssl_channel_security_connector final
     tsi_peer_destruct(&peer);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override {
     auto* other =
         reinterpret_cast<const grpc_httpcli_ssl_channel_security_connector*>(
@@ -115,13 +120,13 @@ class grpc_httpcli_ssl_channel_security_connector final
   bool check_call_host(absl::string_view /*host*/,
                        grpc_auth_context* /*auth_context*/,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** error) override {
+                       grpc_error_handle* error) override {
     *error = GRPC_ERROR_NONE;
     return true;
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -160,13 +165,12 @@ struct on_done_closure {
   void* arg;
   grpc_core::RefCountedPtr<grpc_core::HandshakeManager> handshake_mgr;
 };
-static void on_handshake_done(void* arg, grpc_error* error) {
+static void on_handshake_done(void* arg, grpc_error_handle error) {
   auto* args = static_cast<grpc_core::HandshakerArgs*>(arg);
   on_done_closure* c = static_cast<on_done_closure*>(args->user_data);
   if (error != GRPC_ERROR_NONE) {
-    const char* msg = grpc_error_string(error);
-    gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg);
-
+    gpr_log(GPR_ERROR, "Secure transport setup failed: %s",
+            grpc_error_std_string(error).c_str());
     c->func(c->arg, nullptr);
   } else {
     grpc_channel_args_destroy(args->args);
index 3a0b2be..c47a017 100644 (file)
@@ -37,7 +37,7 @@ static char* buf2str(void* buffer, size_t length) {
   return out;
 }
 
-static grpc_error* handle_response_line(grpc_http_parser* parser) {
+static grpc_error_handle handle_response_line(grpc_http_parser* parser) {
   uint8_t* beg = parser->cur_line;
   uint8_t* cur = beg;
   uint8_t* end = beg + parser->cur_line_length;
@@ -90,7 +90,7 @@ static grpc_error* handle_response_line(grpc_http_parser* parser) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* handle_request_line(grpc_http_parser* parser) {
+static grpc_error_handle handle_request_line(grpc_http_parser* parser) {
   uint8_t* beg = parser->cur_line;
   uint8_t* cur = beg;
   uint8_t* end = beg + parser->cur_line_length;
@@ -161,7 +161,7 @@ static grpc_error* handle_request_line(grpc_http_parser* parser) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* handle_first_line(grpc_http_parser* parser) {
+static grpc_error_handle handle_first_line(grpc_http_parser* parser) {
   switch (parser->type) {
     case GRPC_HTTP_REQUEST:
       return handle_request_line(parser);
@@ -172,14 +172,14 @@ static grpc_error* handle_first_line(grpc_http_parser* parser) {
       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
 }
 
-static grpc_error* add_header(grpc_http_parser* parser) {
+static grpc_error_handle add_header(grpc_http_parser* parser) {
   uint8_t* beg = parser->cur_line;
   uint8_t* cur = beg;
   uint8_t* end = beg + parser->cur_line_length;
   size_t* hdr_count = nullptr;
   grpc_http_header** hdrs = nullptr;
   grpc_http_header hdr = {nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   GPR_ASSERT(cur != end);
 
@@ -235,9 +235,9 @@ done:
   return error;
 }
 
-static grpc_error* finish_line(grpc_http_parser* parser,
-                               bool* found_body_start) {
-  grpc_error* err;
+static grpc_error_handle finish_line(grpc_http_parser* parser,
+                                     bool* found_body_start) {
+  grpc_error_handle err;
   switch (parser->state) {
     case GRPC_HTTP_FIRST_LINE:
       err = handle_first_line(parser);
@@ -264,7 +264,7 @@ static grpc_error* finish_line(grpc_http_parser* parser,
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* addbyte_body(grpc_http_parser* parser, uint8_t byte) {
+static grpc_error_handle addbyte_body(grpc_http_parser* parser, uint8_t byte) {
   size_t* body_length = nullptr;
   char** body = nullptr;
 
@@ -313,8 +313,8 @@ static bool check_line(grpc_http_parser* parser) {
   return false;
 }
 
-static grpc_error* addbyte(grpc_http_parser* parser, uint8_t byte,
-                           bool* found_body_start) {
+static grpc_error_handle addbyte(grpc_http_parser* parser, uint8_t byte,
+                                 bool* found_body_start) {
   switch (parser->state) {
     case GRPC_HTTP_FIRST_LINE:
     case GRPC_HTTP_HEADERS:
@@ -371,12 +371,12 @@ void grpc_http_response_destroy(grpc_http_response* response) {
   gpr_free(response->hdrs);
 }
 
-grpc_error* grpc_http_parser_parse(grpc_http_parser* parser,
-                                   const grpc_slice& slice,
-                                   size_t* start_of_body) {
+grpc_error_handle grpc_http_parser_parse(grpc_http_parser* parser,
+                                         const grpc_slice& slice,
+                                         size_t* start_of_body) {
   for (size_t i = 0; i < GRPC_SLICE_LENGTH(slice); i++) {
     bool found_body_start = false;
-    grpc_error* err =
+    grpc_error_handle err =
         addbyte(parser, GRPC_SLICE_START_PTR(slice)[i], &found_body_start);
     if (err != GRPC_ERROR_NONE) return err;
     if (found_body_start && start_of_body != nullptr) *start_of_body = i + 1;
@@ -384,7 +384,7 @@ grpc_error* grpc_http_parser_parse(grpc_http_parser* parser,
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_http_parser_eof(grpc_http_parser* parser) {
+grpc_error_handle grpc_http_parser_eof(grpc_http_parser* parser) {
   if (parser->state != GRPC_HTTP_BODY) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Did not finish headers");
   }
index 2da2190..613b972 100644 (file)
@@ -100,10 +100,10 @@ void grpc_http_parser_init(grpc_http_parser* parser, grpc_http_type type,
 void grpc_http_parser_destroy(grpc_http_parser* parser);
 
 /* Sets \a start_of_body to the offset in \a slice of the start of the body. */
-grpc_error* grpc_http_parser_parse(grpc_http_parser* parser,
-                                   const grpc_slice& slice,
-                                   size_t* start_of_body);
-grpc_error* grpc_http_parser_eof(grpc_http_parser* parser);
+grpc_error_handle grpc_http_parser_parse(grpc_http_parser* parser,
+                                         const grpc_slice& slice,
+                                         size_t* start_of_body);
+grpc_error_handle grpc_http_parser_eof(grpc_http_parser* parser);
 
 void grpc_http_request_destroy(grpc_http_request* request);
 void grpc_http_response_destroy(grpc_http_response* response);
index e1b87da..f92fc9b 100644 (file)
@@ -40,14 +40,14 @@ void fill_gpr_from_timestamp(gpr_timespec* gts, const struct timespec* ts) {
 }
 
 void default_timestamps_callback(void* /*arg*/, grpc_core::Timestamps* /*ts*/,
-                                 grpc_error* /*shudown_err*/) {
+                                 grpc_error_handle /*shudown_err*/) {
   gpr_log(GPR_DEBUG, "Timestamps callback has not been registered");
 }
 
 /** The saved callback function that will be invoked when we get all the
  * timestamps that we are going to get for a TracedBuffer. */
 void (*timestamps_callback)(void*, grpc_core::Timestamps*,
-                            grpc_error* shutdown_err) =
+                            grpc_error_handle shutdown_err) =
     default_timestamps_callback;
 
 /* Used to extract individual opt stats from cmsg, so as to avoid troubles with
@@ -268,7 +268,7 @@ void TracedBuffer::ProcessTimestamp(TracedBuffer** head,
 }
 
 void TracedBuffer::Shutdown(TracedBuffer** head, void* remaining,
-                            grpc_error* shutdown_err) {
+                            grpc_error_handle shutdown_err) {
   GPR_DEBUG_ASSERT(head != nullptr);
   TracedBuffer* elem = *head;
   while (elem != nullptr) {
@@ -284,9 +284,8 @@ void TracedBuffer::Shutdown(TracedBuffer** head, void* remaining,
   GRPC_ERROR_UNREF(shutdown_err);
 }
 
-void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*,
-                                                       grpc_core::Timestamps*,
-                                                       grpc_error* error)) {
+void grpc_tcp_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error)) {
   timestamps_callback = fn;
 }
 } /* namespace grpc_core */
@@ -294,9 +293,8 @@ void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*,
 #else /* GRPC_LINUX_ERRQUEUE */
 
 namespace grpc_core {
-void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*,
-                                                       grpc_core::Timestamps*,
-                                                       grpc_error* error)) {
+void grpc_tcp_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error)) {
   // Cast value of fn to void to avoid unused parameter warning.
   // Can't comment out the name because some compilers and formatters don't
   // like the sequence */* , which would arise from */*fn*/.
index f8faf7c..982c4c6 100644 (file)
@@ -135,7 +135,7 @@ class TracedBuffer {
   /** Cleans the list by calling the callback for each traced buffer in the list
    * with timestamps that it has. */
   static void Shutdown(grpc_core::TracedBuffer** head, void* remaining,
-                       grpc_error* shutdown_err);
+                       grpc_error_handle shutdown_err);
 
  private:
   uint32_t seq_no_; /* The sequence number for the last byte in the buffer */
@@ -148,7 +148,7 @@ class TracedBuffer {
  public:
   /* Phony shutdown function */
   static void Shutdown(grpc_core::TracedBuffer** /*head*/, void* /*remaining*/,
-                       grpc_error* shutdown_err) {
+                       grpc_error_handle shutdown_err) {
     GRPC_ERROR_UNREF(shutdown_err);
   }
 };
@@ -156,9 +156,8 @@ class TracedBuffer {
 
 /** Sets the callback function to call when timestamps for a write are
  *  collected. The callback does not own a reference to error. */
-void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*,
-                                                       grpc_core::Timestamps*,
-                                                       grpc_error* error));
+void grpc_tcp_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error));
 
 } /* namespace grpc_core */
 
index 043b3bb..44ffb12 100644 (file)
@@ -32,15 +32,15 @@ DebugOnlyTraceFlag grpc_call_combiner_trace(false, "call_combiner");
 
 namespace {
 
-grpc_error* DecodeCancelStateError(gpr_atm cancel_state) {
+grpc_error_handle DecodeCancelStateError(gpr_atm cancel_state) {
   if (cancel_state & 1) {
-    return reinterpret_cast<grpc_error*>(cancel_state &
-                                         ~static_cast<gpr_atm>(1));
+    return reinterpret_cast<grpc_error_handle>(cancel_state &
+                                               ~static_cast<gpr_atm>(1));
   }
   return GRPC_ERROR_NONE;
 }
 
-gpr_atm EncodeCancelStateError(grpc_error* error) {
+gpr_atm EncodeCancelStateError(grpc_error_handle error) {
   return static_cast<gpr_atm>(1) | reinterpret_cast<gpr_atm>(error);
 }
 
@@ -60,7 +60,7 @@ CallCombiner::~CallCombiner() {
 }
 
 #ifdef GRPC_TSAN_ENABLED
-void CallCombiner::TsanClosure(void* arg, grpc_error* error) {
+void CallCombiner::TsanClosure(void* arg, grpc_error_handle error) {
   CallCombiner* self = static_cast<CallCombiner*>(arg);
   // We ref-count the lock, and check if it's already taken.
   // If it was taken, we should do nothing. Otherwise, we will mark it as
@@ -91,7 +91,8 @@ void CallCombiner::TsanClosure(void* arg, grpc_error* error) {
 }
 #endif
 
-void CallCombiner::ScheduleClosure(grpc_closure* closure, grpc_error* error) {
+void CallCombiner::ScheduleClosure(grpc_closure* closure,
+                                   grpc_error_handle error) {
 #ifdef GRPC_TSAN_ENABLED
   original_closure_ = closure;
   ExecCtx::Run(DEBUG_LOCATION, &tsan_closure_, error);
@@ -110,14 +111,15 @@ void CallCombiner::ScheduleClosure(grpc_closure* closure, grpc_error* error) {
 #define DEBUG_FMT_ARGS
 #endif
 
-void CallCombiner::Start(grpc_closure* closure, grpc_error* error,
+void CallCombiner::Start(grpc_closure* closure, grpc_error_handle error,
                          DEBUG_ARGS const char* reason) {
   GPR_TIMER_SCOPE("CallCombiner::Start", 0);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) {
     gpr_log(GPR_INFO,
             "==> CallCombiner::Start() [%p] closure=%p [" DEBUG_FMT_STR
             "%s] error=%s",
-            this, closure DEBUG_FMT_ARGS, reason, grpc_error_string(error));
+            this, closure DEBUG_FMT_ARGS, reason,
+            grpc_error_std_string(error).c_str());
   }
   size_t prev_size =
       static_cast<size_t>(gpr_atm_full_fetch_add(&size_, (gpr_atm)1));
@@ -176,7 +178,8 @@ void CallCombiner::Stop(DEBUG_ARGS const char* reason) {
       }
       if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) {
         gpr_log(GPR_INFO, "  EXECUTING FROM QUEUE: closure=%p error=%s",
-                closure, grpc_error_string(closure->error_data.error));
+                closure,
+                grpc_error_std_string(closure->error_data.error).c_str());
       }
       ScheduleClosure(closure, closure->error_data.error);
       break;
@@ -191,7 +194,7 @@ void CallCombiner::SetNotifyOnCancel(grpc_closure* closure) {
   while (true) {
     // Decode original state.
     gpr_atm original_state = gpr_atm_acq_load(&cancel_state_);
-    grpc_error* original_error = DecodeCancelStateError(original_state);
+    grpc_error_handle original_error = DecodeCancelStateError(original_state);
     // If error is set, invoke the cancellation closure immediately.
     // Otherwise, store the new closure.
     if (original_error != GRPC_ERROR_NONE) {
@@ -229,11 +232,11 @@ void CallCombiner::SetNotifyOnCancel(grpc_closure* closure) {
   }
 }
 
-void CallCombiner::Cancel(grpc_error* error) {
+void CallCombiner::Cancel(grpc_error_handle error) {
   GRPC_STATS_INC_CALL_COMBINER_CANCELLED();
   while (true) {
     gpr_atm original_state = gpr_atm_acq_load(&cancel_state_);
-    grpc_error* original_error = DecodeCancelStateError(original_state);
+    grpc_error_handle original_error = DecodeCancelStateError(original_state);
     if (original_error != GRPC_ERROR_NONE) {
       GRPC_ERROR_UNREF(error);
       break;
index 44acd9f..e5429cc 100644 (file)
@@ -58,7 +58,7 @@ class CallCombiner {
 #define GRPC_CALL_COMBINER_STOP(call_combiner, reason) \
   (call_combiner)->Stop(__FILE__, __LINE__, (reason))
   /// Starts processing \a closure.
-  void Start(grpc_closure* closure, grpc_error* error, const char* file,
+  void Start(grpc_closure* closure, grpc_error_handle error, const char* file,
              int line, const char* reason);
   /// Yields the call combiner to the next closure in the queue, if any.
   void Stop(const char* file, int line, const char* reason);
@@ -68,7 +68,8 @@ class CallCombiner {
 #define GRPC_CALL_COMBINER_STOP(call_combiner, reason) \
   (call_combiner)->Stop((reason))
   /// Starts processing \a closure.
-  void Start(grpc_closure* closure, grpc_error* error, const char* reason);
+  void Start(grpc_closure* closure, grpc_error_handle error,
+             const char* reason);
   /// Yields the call combiner to the next closure in the queue, if any.
   void Stop(const char* reason);
 #endif
@@ -94,26 +95,22 @@ class CallCombiner {
   /// cancellation; this effectively unregisters the previously set closure.
   /// However, most filters will not need to explicitly unregister their
   /// callbacks, as this is done automatically when the call is destroyed.
-  /// Filters that schedule the cancellation closure on ExecCtx do not need
-  /// to take a ref on the call stack to guarantee closure liveness. This is
-  /// done by explicitly flushing ExecCtx after the unregistration during
-  /// call destruction.
   void SetNotifyOnCancel(grpc_closure* closure);
 
   /// Indicates that the call has been cancelled.
-  void Cancel(grpc_error* error);
+  void Cancel(grpc_error_handle error);
 
  private:
-  void ScheduleClosure(grpc_closure* closure, grpc_error* error);
+  void ScheduleClosure(grpc_closure* closure, grpc_error_handle error);
 #ifdef GRPC_TSAN_ENABLED
-  static void TsanClosure(void* arg, grpc_error* error);
+  static void TsanClosure(void* arg, grpc_error_handle error);
 #endif
 
   gpr_atm size_ = 0;  // size_t, num closures in queue or currently executing
   MultiProducerSingleConsumerQueue queue_;
   // Either 0 (if not cancelled and no cancellation closure set),
   // a grpc_closure* (if the lowest bit is 0),
-  // or a grpc_error* (if the lowest bit is 1).
+  // or a grpc_error_handle (if the lowest bit is 1).
   gpr_atm cancel_state_ = 0;
 #ifdef GRPC_TSAN_ENABLED
   // A fake ref-counted lock that is kept alive after the destruction of
@@ -150,7 +147,7 @@ class CallCombinerClosureList {
 
   // Adds a closure to the list.  The closure must eventually result in
   // the call combiner being yielded.
-  void Add(grpc_closure* closure, grpc_error* error, const char* reason) {
+  void Add(grpc_closure* closure, grpc_error_handle error, const char* reason) {
     closures_.emplace_back(closure, error, reason);
   }
 
@@ -176,7 +173,8 @@ class CallCombinerClosureList {
               "CallCombinerClosureList executing closure while already "
               "holding call_combiner %p: closure=%p error=%s reason=%s",
               call_combiner, closures_[0].closure,
-              grpc_error_string(closures_[0].error), closures_[0].reason);
+              grpc_error_std_string(closures_[0].error).c_str(),
+              closures_[0].reason);
     }
     // This will release the call combiner.
     ExecCtx::Run(DEBUG_LOCATION, closures_[0].closure, closures_[0].error);
@@ -199,10 +197,10 @@ class CallCombinerClosureList {
  private:
   struct CallCombinerClosure {
     grpc_closure* closure;
-    grpc_error* error;
+    grpc_error_handle error;
     const char* reason;
 
-    CallCombinerClosure(grpc_closure* closure, grpc_error* error,
+    CallCombinerClosure(grpc_closure* closure, grpc_error_handle error,
                         const char* reason)
         : closure(closure), error(error), reason(reason) {}
   };
index 2f70a29..fb11231 100644 (file)
@@ -62,7 +62,7 @@ void CFStreamHandle::ReadCallback(CFReadStreamRef stream,
                                   void* client_callback_info) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
-  grpc_error* error;
+  grpc_error_handle error;
   CFErrorRef stream_error;
   CFStreamHandle* handle = static_cast<CFStreamHandle*>(client_callback_info);
   if (grpc_tcp_trace.enabled()) {
@@ -97,7 +97,7 @@ void CFStreamHandle::WriteCallback(CFWriteStreamRef stream,
                                    void* clientCallBackInfo) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
-  grpc_error* error;
+  grpc_error_handle error;
   CFErrorRef stream_error;
   CFStreamHandle* handle = static_cast<CFStreamHandle*>(clientCallBackInfo);
   if (grpc_tcp_trace.enabled()) {
@@ -171,7 +171,7 @@ void CFStreamHandle::NotifyOnWrite(grpc_closure* closure) {
   write_event_.NotifyOn(closure);
 }
 
-void CFStreamHandle::Shutdown(grpc_error* error) {
+void CFStreamHandle::Shutdown(grpc_error_handle error) {
   open_event_.SetShutdown(GRPC_ERROR_REF(error));
   read_event_.SetShutdown(GRPC_ERROR_REF(error));
   write_event_.SetShutdown(GRPC_ERROR_REF(error));
index b0f0664..2358758 100644 (file)
@@ -53,7 +53,7 @@ class CFStreamHandle : public GrpcLibraryInitHolder {
   void NotifyOnOpen(grpc_closure* closure);
   void NotifyOnRead(grpc_closure* closure);
   void NotifyOnWrite(grpc_closure* closure);
-  void Shutdown(grpc_error* error);
+  void Shutdown(grpc_error_handle error);
 
   void Ref(const char* file = "", int line = 0, const char* reason = nullptr);
   void Unref(const char* file = "", int line = 0, const char* reason = nullptr);
index 6bb6534..b429c9e 100644 (file)
@@ -50,7 +50,7 @@ typedef struct grpc_closure_list {
  *              describing what went wrong.
  *              Error contract: it is not the cb's job to unref this error;
  *              the closure scheduler will do that after the cb returns */
-typedef void (*grpc_iomgr_cb_func)(void* arg, grpc_error* error);
+typedef void (*grpc_iomgr_cb_func)(void* arg, grpc_error_handle error);
 
 /** A closure over a grpc_iomgr_cb_func. */
 struct grpc_closure {
@@ -72,7 +72,7 @@ struct grpc_closure {
 
   /** Once queued, the result of the closure. Before then: scratch space */
   union {
-    grpc_error* error;
+    grpc_error_handle error;
     uintptr_t scratch;
   } error_data;
 
@@ -126,7 +126,7 @@ struct wrapped_closure {
   void* cb_arg;
   grpc_closure wrapper;
 };
-inline void closure_wrapper(void* arg, grpc_error* error) {
+inline void closure_wrapper(void* arg, grpc_error_handle error) {
   wrapped_closure* wc = static_cast<wrapped_closure*>(arg);
   grpc_iomgr_cb_func cb = wc->cb;
   void* cb_arg = wc->cb_arg;
@@ -175,7 +175,8 @@ inline void grpc_closure_list_init(grpc_closure_list* closure_list) {
     and set \a closure's result to \a error
     Returns true if \a list becomes non-empty */
 inline bool grpc_closure_list_append(grpc_closure_list* closure_list,
-                                     grpc_closure* closure, grpc_error* error) {
+                                     grpc_closure* closure,
+                                     grpc_error_handle error) {
   if (closure == nullptr) {
     GRPC_ERROR_UNREF(error);
     return false;
@@ -194,7 +195,7 @@ inline bool grpc_closure_list_append(grpc_closure_list* closure_list,
 
 /** force all success bits in \a list to false */
 inline void grpc_closure_list_fail_all(grpc_closure_list* list,
-                                       grpc_error* forced_failure) {
+                                       grpc_error_handle forced_failure) {
   for (grpc_closure* c = list->head; c != nullptr; c = c->next_data.next) {
     if (c->error_data.error == GRPC_ERROR_NONE) {
       c->error_data.error = GRPC_ERROR_REF(forced_failure);
@@ -227,7 +228,7 @@ namespace grpc_core {
 class Closure {
  public:
   static void Run(const DebugLocation& location, grpc_closure* closure,
-                  grpc_error* error) {
+                  grpc_error_handle error) {
     (void)location;
     if (closure == nullptr) {
       GRPC_ERROR_UNREF(error);
index aa5a2ea..48237e5 100644 (file)
@@ -46,11 +46,12 @@ grpc_core::DebugOnlyTraceFlag grpc_combiner_trace(false, "combiner");
 #define STATE_ELEM_COUNT_LOW_BIT 2
 
 static void combiner_exec(grpc_core::Combiner* lock, grpc_closure* closure,
-                          grpc_error* error);
+                          grpc_error_handle error);
 static void combiner_finally_exec(grpc_core::Combiner* lock,
-                                  grpc_closure* closure, grpc_error* error);
+                                  grpc_closure* closure,
+                                  grpc_error_handle error);
 
-static void offload(void* arg, grpc_error* error);
+static void offload(void* arg, grpc_error_handle error);
 
 grpc_core::Combiner* grpc_combiner_create(void) {
   grpc_core::Combiner* lock = new grpc_core::Combiner();
@@ -126,7 +127,7 @@ static void push_first_on_exec_ctx(grpc_core::Combiner* lock) {
 }
 
 static void combiner_exec(grpc_core::Combiner* lock, grpc_closure* cl,
-                          grpc_error* error) {
+                          grpc_error_handle error) {
   GPR_TIMER_SCOPE("combiner.execute", 0);
   GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_ITEMS();
   gpr_atm last = gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT);
@@ -167,7 +168,7 @@ static void move_next() {
   }
 }
 
-static void offload(void* arg, grpc_error* /*error*/) {
+static void offload(void* arg, grpc_error_handle /*error*/) {
   grpc_core::Combiner* lock = static_cast<grpc_core::Combiner*>(arg);
   push_last_on_exec_ctx(lock);
 }
@@ -230,7 +231,7 @@ bool grpc_combiner_continue_exec_ctx() {
     }
     GPR_TIMER_SCOPE("combiner.exec1", 0);
     grpc_closure* cl = reinterpret_cast<grpc_closure*>(n);
-    grpc_error* cl_err = cl->error_data.error;
+    grpc_error_handle cl_err = cl->error_data.error;
 #ifndef NDEBUG
     cl->scheduled = false;
 #endif
@@ -246,7 +247,7 @@ bool grpc_combiner_continue_exec_ctx() {
       GRPC_COMBINER_TRACE(
           gpr_log(GPR_INFO, "C:%p execute_final[%d] c=%p", lock, loops, c));
       grpc_closure* next = c->next_data.next;
-      grpc_error* error = c->error_data.error;
+      grpc_error_handle error = c->error_data.error;
 #ifndef NDEBUG
       c->scheduled = false;
 #endif
@@ -297,10 +298,11 @@ bool grpc_combiner_continue_exec_ctx() {
   return true;
 }
 
-static void enqueue_finally(void* closure, grpc_error* error);
+static void enqueue_finally(void* closure, grpc_error_handle error);
 
 static void combiner_finally_exec(grpc_core::Combiner* lock,
-                                  grpc_closure* closure, grpc_error* error) {
+                                  grpc_closure* closure,
+                                  grpc_error_handle error) {
   GPR_ASSERT(lock != nullptr);
   GPR_TIMER_SCOPE("combiner.execute_finally", 0);
   GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_FINAL_ITEMS();
@@ -322,7 +324,7 @@ static void combiner_finally_exec(grpc_core::Combiner* lock,
   grpc_closure_list_append(&lock->final_list, closure, error);
 }
 
-static void enqueue_finally(void* closure, grpc_error* error) {
+static void enqueue_finally(void* closure, grpc_error_handle error) {
   grpc_closure* cl = static_cast<grpc_closure*>(closure);
   combiner_finally_exec(
       reinterpret_cast<grpc_core::Combiner*>(cl->error_data.scratch), cl,
@@ -330,11 +332,11 @@ static void enqueue_finally(void* closure, grpc_error* error) {
 }
 
 namespace grpc_core {
-void Combiner::Run(grpc_closure* closure, grpc_error* error) {
+void Combiner::Run(grpc_closure* closure, grpc_error_handle error) {
   combiner_exec(this, closure, error);
 }
 
-void Combiner::FinallyRun(grpc_closure* closure, grpc_error* error) {
+void Combiner::FinallyRun(grpc_closure* closure, grpc_error_handle error) {
   combiner_finally_exec(this, closure, error);
 }
 }  // namespace grpc_core
index 3271206..efa2bce 100644 (file)
@@ -32,9 +32,9 @@ namespace grpc_core {
 // use ExecCtx
 class Combiner {
  public:
-  void Run(grpc_closure* closure, grpc_error* error);
+  void Run(grpc_closure* closure, grpc_error_handle error);
   // TODO(yashkt) : Remove this method
-  void FinallyRun(grpc_closure* closure, grpc_error* error);
+  void FinallyRun(grpc_closure* closure, grpc_error_handle error);
   Combiner* next_combiner_on_this_exec_ctx = nullptr;
   MultiProducerSingleConsumerQueue queue;
   // either:
index 8954f9d..4c84501 100644 (file)
@@ -46,7 +46,7 @@ void grpc_endpoint_delete_from_pollset_set(grpc_endpoint* ep,
   ep->vtable->delete_from_pollset_set(ep, pollset_set);
 }
 
-void grpc_endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) {
+void grpc_endpoint_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   ep->vtable->shutdown(ep, why);
 }
 
index b6e6086..4db5e3d 100644 (file)
@@ -44,7 +44,7 @@ struct grpc_endpoint_vtable {
   void (*add_to_pollset)(grpc_endpoint* ep, grpc_pollset* pollset);
   void (*add_to_pollset_set)(grpc_endpoint* ep, grpc_pollset_set* pollset);
   void (*delete_from_pollset_set)(grpc_endpoint* ep, grpc_pollset_set* pollset);
-  void (*shutdown)(grpc_endpoint* ep, grpc_error* why);
+  void (*shutdown)(grpc_endpoint* ep, grpc_error_handle why);
   void (*destroy)(grpc_endpoint* ep);
   grpc_resource_user* (*get_resource_user)(grpc_endpoint* ep);
   absl::string_view (*get_peer)(grpc_endpoint* ep);
@@ -86,7 +86,7 @@ void grpc_endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
 
 /* Causes any pending and future read/write callbacks to run immediately with
    success==0 */
-void grpc_endpoint_shutdown(grpc_endpoint* ep, grpc_error* why);
+void grpc_endpoint_shutdown(grpc_endpoint* ep, grpc_error_handle why);
 void grpc_endpoint_destroy(grpc_endpoint* ep);
 
 /* Add an endpoint to a pollset or pollset_set, so that when the pollset is
index 75cd0f0..6394506 100644 (file)
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/cfstream_handle.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/error_cfstream.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 
@@ -106,8 +106,8 @@ static void CFStreamUnref(CFStreamEndpoint* ep) {
 static void CFStreamRef(CFStreamEndpoint* ep) { gpr_ref(&ep->refcount); }
 #endif
 
-static grpc_error* CFStreamAnnotateError(grpc_error* src_error,
-                                         CFStreamEndpoint* ep) {
+static grpc_error_handle CFStreamAnnotateError(grpc_error_handle src_error,
+                                               CFStreamEndpoint* ep) {
   return grpc_error_set_str(
       grpc_error_set_int(src_error, GRPC_ERROR_INT_GRPC_STATUS,
                          GRPC_STATUS_UNAVAILABLE),
@@ -115,13 +115,12 @@ static grpc_error* CFStreamAnnotateError(grpc_error* src_error,
       grpc_slice_from_copied_string(ep->peer_string.c_str()));
 }
 
-static void CallReadCb(CFStreamEndpoint* ep, grpc_error* error) {
+static void CallReadCb(CFStreamEndpoint* ep, grpc_error_handle error) {
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CFStream endpoint:%p call_read_cb %p %p:%p", ep,
             ep->read_cb, ep->read_cb->cb, ep->read_cb->cb_arg);
     size_t i;
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "read: error=%s", str);
+    gpr_log(GPR_DEBUG, "read: error=%s", grpc_error_std_string(error).c_str());
 
     for (i = 0; i < ep->read_slices->count; i++) {
       char* dump = grpc_dump_slice(ep->read_slices->slices[i],
@@ -137,12 +136,11 @@ static void CallReadCb(CFStreamEndpoint* ep, grpc_error* error) {
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
 }
 
-static void CallWriteCb(CFStreamEndpoint* ep, grpc_error* error) {
+static void CallWriteCb(CFStreamEndpoint* ep, grpc_error_handle error) {
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CFStream endpoint:%p call_write_cb %p %p:%p", ep,
             ep->write_cb, ep->write_cb->cb, ep->write_cb->cb_arg);
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "write: error=%s", str);
+    gpr_log(GPR_DEBUG, "write: error=%s", grpc_error_std_string(error).c_str());
   }
   grpc_closure* cb = ep->write_cb;
   ep->write_cb = nullptr;
@@ -150,7 +148,7 @@ static void CallWriteCb(CFStreamEndpoint* ep, grpc_error* error) {
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
 }
 
-static void ReadAction(void* arg, grpc_error* error) {
+static void ReadAction(void* arg, grpc_error_handle error) {
   CFStreamEndpoint* ep = static_cast<CFStreamEndpoint*>(arg);
   GPR_ASSERT(ep->read_cb != nullptr);
   if (error) {
@@ -192,7 +190,7 @@ static void ReadAction(void* arg, grpc_error* error) {
   }
 }
 
-static void WriteAction(void* arg, grpc_error* error) {
+static void WriteAction(void* arg, grpc_error_handle error) {
   CFStreamEndpoint* ep = static_cast<CFStreamEndpoint*>(arg);
   GPR_ASSERT(ep->write_cb != nullptr);
   if (error) {
@@ -242,7 +240,7 @@ static void WriteAction(void* arg, grpc_error* error) {
   grpc_slice_unref_internal(slice);
 }
 
-static void CFStreamReadAllocationDone(void* arg, grpc_error* error) {
+static void CFStreamReadAllocationDone(void* arg, grpc_error_handle error) {
   CFStreamEndpoint* ep = static_cast<CFStreamEndpoint*>(arg);
   if (error == GRPC_ERROR_NONE) {
     ep->stream_sync->NotifyOnRead(&ep->read_action);
@@ -286,7 +284,7 @@ static void CFStreamWrite(grpc_endpoint* ep, grpc_slice_buffer* slices,
   ep_impl->stream_sync->NotifyOnWrite(&ep_impl->write_action);
 }
 
-void CFStreamShutdown(grpc_endpoint* ep, grpc_error* why) {
+void CFStreamShutdown(grpc_endpoint* ep, grpc_error_handle why) {
   CFStreamEndpoint* ep_impl = reinterpret_cast<CFStreamEndpoint*>(ep);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CFStream endpoint:%p shutdown (%p)", ep_impl, why);
index 9962809..c1113e1 100644 (file)
@@ -21,9 +21,9 @@
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 #include <errno.h>
 #include <fcntl.h>
index 0910145..378bdf7 100644 (file)
@@ -41,6 +41,114 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount(false,
                                                         "error_refcount");
 grpc_core::DebugOnlyTraceFlag grpc_trace_closure(false, "closure");
 
+static gpr_atm g_error_creation_allowed = true;
+
+void grpc_disable_error_creation() {
+  gpr_atm_no_barrier_store(&g_error_creation_allowed, false);
+}
+
+void grpc_enable_error_creation() {
+  gpr_atm_no_barrier_store(&g_error_creation_allowed, true);
+}
+
+#ifdef GRPC_ERROR_IS_ABSEIL_STATUS
+
+absl::Status grpc_status_create(absl::StatusCode code, absl::string_view msg,
+                                const grpc_core::DebugLocation& location,
+                                size_t children_count, absl::Status* children) {
+  absl::Status s = StatusCreate(code, msg, location, {});
+  for (size_t i = 0; i < children_count; ++i) {
+    if (!children[i].ok()) {
+      StatusAddChild(&s, children[i]);
+    }
+  }
+  return s;
+}
+
+std::string grpc_error_std_string(const absl::Status& error) {
+  return grpc_core::StatusToString(error);
+}
+
+absl::Status grpc_os_error(const grpc_core::DebugLocation& location, int err,
+                           const char* call_name) {
+  absl::Status s =
+      StatusCreate(absl::StatusCode::kUnknown, "OS Error", location, {});
+  grpc_core::StatusSetInt(&s, grpc_core::StatusIntProperty::ERRNO, err);
+  grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::OS_ERROR,
+                          strerror(err));
+  grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::SYSCALL, call_name);
+  return s;
+}
+
+#ifdef GPR_WINDOWS
+absl::Status grpc_wsa_error(const grpc_core::DebugLocation& location, int err,
+                            const char* call_name) {
+  char* utf8_message = gpr_format_message(err);
+  absl::Status s =
+      StatusCreate(absl::StatusCode::kUnknown, "WSA Error", location, {});
+  StatusSetInt(&s, StatusIntProperty::WSA_ERROR, err);
+  StatusSetStr(&s, StatusStrProperty::OS_ERROR, utf8_message);
+  StatusSetStr(&s, StatusStrProperty::SYSCALL, call_name);
+}
+#endif
+
+grpc_error_handle grpc_error_set_int(grpc_error_handle src,
+                                     grpc_error_ints which, intptr_t value) {
+  grpc_core::StatusSetInt(
+      &src, static_cast<grpc_core::StatusIntProperty>(which), value);
+  return src;
+}
+
+bool grpc_error_get_int(grpc_error_handle error, grpc_error_ints which,
+                        intptr_t* p) {
+  absl::optional<intptr_t> value = grpc_core::StatusGetInt(
+      error, static_cast<grpc_core::StatusIntProperty>(which));
+  if (value.has_value()) {
+    *p = *value;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+grpc_error_handle grpc_error_set_str(grpc_error_handle src,
+                                     grpc_error_strs which,
+                                     const grpc_slice& str) {
+  grpc_core::StatusSetStr(
+      &src, static_cast<grpc_core::StatusStrProperty>(which),
+      std::string(reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(str)),
+                  GRPC_SLICE_LENGTH(str)));
+  return src;
+}
+
+bool grpc_error_get_str(grpc_error_handle error, grpc_error_strs which,
+                        grpc_slice* s) {
+  absl::optional<std::string> value = grpc_core::StatusGetStr(
+      error, static_cast<grpc_core::StatusStrProperty>(which));
+  if (value.has_value()) {
+    *s = grpc_slice_from_copied_buffer(value->c_str(), value->size());
+    return true;
+  } else {
+    return false;
+  }
+}
+
+grpc_error_handle grpc_error_add_child(grpc_error_handle src,
+                                       grpc_error_handle child) {
+  grpc_core::StatusAddChild(&src, child);
+  return src;
+}
+
+bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
+                    int line) {
+  GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
+  gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what,
+          grpc_core::StatusToString(error).c_str());
+  return false;
+}
+
+#else  // GRPC_ERROR_IS_ABSEIL_STATUS
+
 static const char* error_int_name(grpc_error_ints key) {
   switch (key) {
     case GRPC_ERROR_INT_ERRNO:
@@ -61,20 +169,18 @@ static const char* error_int_name(grpc_error_ints key) {
       return "http2_error";
     case GRPC_ERROR_INT_TSI_CODE:
       return "tsi_code";
-    case GRPC_ERROR_INT_SECURITY_STATUS:
-      return "security_status";
     case GRPC_ERROR_INT_FD:
       return "fd";
     case GRPC_ERROR_INT_WSA_ERROR:
       return "wsa_error";
     case GRPC_ERROR_INT_HTTP_STATUS:
       return "http_status";
-    case GRPC_ERROR_INT_LIMIT:
-      return "limit";
     case GRPC_ERROR_INT_OCCURRED_DURING_WRITE:
       return "occurred_during_write";
     case GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE:
       return "channel_connectivity_state";
+    case GRPC_ERROR_INT_LB_POLICY_DROP:
+      return "lb_policy_drop";
     case GRPC_ERROR_INT_MAX:
       GPR_UNREACHABLE_CODE(return "unknown");
   }
@@ -105,8 +211,6 @@ static const char* error_str_name(grpc_error_strs key) {
       return "tsi_error";
     case GRPC_ERROR_STR_FILENAME:
       return "filename";
-    case GRPC_ERROR_STR_QUEUED_BUFFERS:
-      return "queued_buffers";
     case GRPC_ERROR_STR_MAX:
       GPR_UNREACHABLE_CODE(return "unknown");
   }
@@ -124,7 +228,8 @@ static const char* error_time_name(grpc_error_times key) {
 }
 
 #ifndef NDEBUG
-grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line) {
+grpc_error_handle grpc_error_do_ref(grpc_error_handle err, const char* file,
+                                    int line) {
   if (grpc_trace_error_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
             gpr_atm_no_barrier_load(&err->atomics.refs.count),
@@ -134,13 +239,13 @@ grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line) {
   return err;
 }
 #else
-grpc_error* grpc_error_do_ref(grpc_error* err) {
+grpc_error_handle grpc_error_do_ref(grpc_error_handle err) {
   gpr_ref(&err->atomics.refs);
   return err;
 }
 #endif
 
-static void unref_errs(grpc_error* err) {
+static void unref_errs(grpc_error_handle err) {
   uint8_t slot = err->first_err;
   while (slot != UINT8_MAX) {
     grpc_linked_error* lerr =
@@ -152,7 +257,7 @@ static void unref_errs(grpc_error* err) {
   }
 }
 
-static void unref_strs(grpc_error* err) {
+static void unref_strs(grpc_error_handle err) {
   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
     uint8_t slot = err->strs[which];
     if (slot != UINT8_MAX) {
@@ -162,7 +267,7 @@ static void unref_strs(grpc_error* err) {
   }
 }
 
-static void error_destroy(grpc_error* err) {
+static void error_destroy(grpc_error_handle err) {
   GPR_ASSERT(!grpc_error_is_special(err));
   unref_errs(err);
   unref_strs(err);
@@ -172,7 +277,7 @@ static void error_destroy(grpc_error* err) {
 }
 
 #ifndef NDEBUG
-void grpc_error_do_unref(grpc_error* err, const char* file, int line) {
+void grpc_error_do_unref(grpc_error_handle err, const char* file, int line) {
   if (grpc_trace_error_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
             gpr_atm_no_barrier_load(&err->atomics.refs.count),
@@ -183,14 +288,14 @@ void grpc_error_do_unref(grpc_error* err, const char* file, int line) {
   }
 }
 #else
-void grpc_error_do_unref(grpc_error* err) {
+void grpc_error_do_unref(grpc_error_handle err) {
   if (gpr_unref(&err->atomics.refs)) {
     error_destroy(err);
   }
 }
 #endif
 
-static uint8_t get_placement(grpc_error** err, size_t size) {
+static uint8_t get_placement(grpc_error_handle* err, size_t size) {
   GPR_ASSERT(*err);
   uint8_t slots = static_cast<uint8_t>(size / sizeof(intptr_t));
   if ((*err)->arena_size + slots > (*err)->arena_capacity) {
@@ -200,9 +305,9 @@ static uint8_t get_placement(grpc_error** err, size_t size) {
       return UINT8_MAX;
     }
 #ifndef NDEBUG
-    grpc_error* orig = *err;
+    grpc_error_handle orig = *err;
 #endif
-    *err = static_cast<grpc_error*>(gpr_realloc(
+    *err = static_cast<grpc_error_handle>(gpr_realloc(
         *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t)));
 #ifndef NDEBUG
     if (grpc_trace_error_refcount.enabled()) {
@@ -217,7 +322,7 @@ static uint8_t get_placement(grpc_error** err, size_t size) {
   return placement;
 }
 
-static void internal_set_int(grpc_error** err, grpc_error_ints which,
+static void internal_set_int(grpc_error_handle* err, grpc_error_ints which,
                              intptr_t value) {
   uint8_t slot = (*err)->ints[which];
   if (slot == UINT8_MAX) {
@@ -232,7 +337,7 @@ static void internal_set_int(grpc_error** err, grpc_error_ints which,
   (*err)->arena[slot] = value;
 }
 
-static void internal_set_str(grpc_error** err, grpc_error_strs which,
+static void internal_set_str(grpc_error_handle* err, grpc_error_strs which,
                              const grpc_slice& value) {
   uint8_t slot = (*err)->strs[which];
   if (slot == UINT8_MAX) {
@@ -253,7 +358,7 @@ static void internal_set_str(grpc_error** err, grpc_error_strs which,
 }
 
 static char* fmt_time(gpr_timespec tm);
-static void internal_set_time(grpc_error** err, grpc_error_times which,
+static void internal_set_time(grpc_error_handle* err, grpc_error_times which,
                               gpr_timespec value) {
   uint8_t slot = (*err)->times[which];
   if (slot == UINT8_MAX) {
@@ -270,7 +375,8 @@ static void internal_set_time(grpc_error** err, grpc_error_times which,
   memcpy((*err)->arena + slot, &value, sizeof(value));
 }
 
-static void internal_add_error(grpc_error** err, grpc_error* new_err) {
+static void internal_add_error(grpc_error_handle* err,
+                               grpc_error_handle new_err) {
   grpc_linked_error new_last = {new_err, UINT8_MAX};
   uint8_t slot = get_placement(err, sizeof(grpc_linked_error));
   if (slot == UINT8_MAX) {
@@ -306,25 +412,16 @@ static void internal_add_error(grpc_error** err, grpc_error* new_err) {
 // It is very common to include and extra int and string in an error
 #define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
 
-static gpr_atm g_error_creation_allowed = true;
-
-void grpc_disable_error_creation() {
-  gpr_atm_no_barrier_store(&g_error_creation_allowed, false);
-}
-
-void grpc_enable_error_creation() {
-  gpr_atm_no_barrier_store(&g_error_creation_allowed, true);
-}
-
-grpc_error* grpc_error_create(const char* file, int line,
-                              const grpc_slice& desc, grpc_error** referencing,
-                              size_t num_referencing) {
+grpc_error_handle grpc_error_create(const char* file, int line,
+                                    const grpc_slice& desc,
+                                    grpc_error_handle* referencing,
+                                    size_t num_referencing) {
   GPR_TIMER_SCOPE("grpc_error_create", 0);
   uint8_t initial_arena_capacity = static_cast<uint8_t>(
       DEFAULT_ERROR_CAPACITY +
       static_cast<uint8_t>(num_referencing * SLOTS_PER_LINKED_ERROR) +
       SURPLUS_CAPACITY);
-  grpc_error* err = static_cast<grpc_error*>(
+  grpc_error_handle err = static_cast<grpc_error_handle>(
       gpr_malloc(sizeof(*err) + initial_arena_capacity * sizeof(intptr_t)));
   if (err == nullptr) {  // TODO(ctiller): make gpr_malloc return NULL
     return GRPC_ERROR_OOM;
@@ -370,7 +467,7 @@ grpc_error* grpc_error_create(const char* file, int line,
   return err;
 }
 
-static void ref_strs(grpc_error* err) {
+static void ref_strs(grpc_error_handle err) {
   for (size_t i = 0; i < GRPC_ERROR_STR_MAX; ++i) {
     uint8_t slot = err->strs[i];
     if (slot != UINT8_MAX) {
@@ -380,7 +477,7 @@ static void ref_strs(grpc_error* err) {
   }
 }
 
-static void ref_errs(grpc_error* err) {
+static void ref_errs(grpc_error_handle err) {
   uint8_t slot = err->first_err;
   while (slot != UINT8_MAX) {
     grpc_linked_error* lerr =
@@ -390,9 +487,9 @@ static void ref_errs(grpc_error* err) {
   }
 }
 
-static grpc_error* copy_error_and_unref(grpc_error* in) {
+static grpc_error_handle copy_error_and_unref(grpc_error_handle in) {
   GPR_TIMER_SCOPE("copy_error_and_unref", 0);
-  grpc_error* out;
+  grpc_error_handle out;
   if (grpc_error_is_special(in)) {
     out = GRPC_ERROR_CREATE_FROM_STATIC_STRING("unknown");
     if (in == GRPC_ERROR_NONE) {
@@ -417,7 +514,7 @@ static grpc_error* copy_error_and_unref(grpc_error* in) {
         static_cast<uint8_t> SLOTS_PER_STR) {
       new_arena_capacity = static_cast<uint8_t>(3 * new_arena_capacity / 2);
     }
-    out = static_cast<grpc_error*>(
+    out = static_cast<grpc_error_handle>(
         gpr_malloc(sizeof(*in) + new_arena_capacity * sizeof(intptr_t)));
 #ifndef NDEBUG
     if (grpc_trace_error_refcount.enabled()) {
@@ -441,10 +538,10 @@ static grpc_error* copy_error_and_unref(grpc_error* in) {
   return out;
 }
 
-grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
-                               intptr_t value) {
+grpc_error_handle grpc_error_set_int(grpc_error_handle src,
+                                     grpc_error_ints which, intptr_t value) {
   GPR_TIMER_SCOPE("grpc_error_set_int", 0);
-  grpc_error* new_err = copy_error_and_unref(src);
+  grpc_error_handle new_err = copy_error_and_unref(src);
   internal_set_int(&new_err, which, value);
   return new_err;
 }
@@ -464,7 +561,8 @@ const special_error_status_map error_status_map[] = {
      strlen("Cancelled")},  // GRPC_ERROR_CANCELLED
 };
 
-bool grpc_error_get_int(grpc_error* err, grpc_error_ints which, intptr_t* p) {
+bool grpc_error_get_int(grpc_error_handle err, grpc_error_ints which,
+                        intptr_t* p) {
   GPR_TIMER_SCOPE("grpc_error_get_int", 0);
   if (grpc_error_is_special(err)) {
     if (which != GRPC_ERROR_INT_GRPC_STATUS) return false;
@@ -479,15 +577,16 @@ bool grpc_error_get_int(grpc_error* err, grpc_error_ints which, intptr_t* p) {
   return false;
 }
 
-grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which,
-                               const grpc_slice& str) {
+grpc_error_handle grpc_error_set_str(grpc_error_handle src,
+                                     grpc_error_strs which,
+                                     const grpc_slice& str) {
   GPR_TIMER_SCOPE("grpc_error_set_str", 0);
-  grpc_error* new_err = copy_error_and_unref(src);
+  grpc_error_handle new_err = copy_error_and_unref(src);
   internal_set_str(&new_err, which, str);
   return new_err;
 }
 
-bool grpc_error_get_str(grpc_error* err, grpc_error_strs which,
+bool grpc_error_get_str(grpc_error_handle err, grpc_error_strs which,
                         grpc_slice* str) {
   if (grpc_error_is_special(err)) {
     if (which != GRPC_ERROR_STR_GRPC_MESSAGE) return false;
@@ -508,14 +607,15 @@ bool grpc_error_get_str(grpc_error* err, grpc_error_strs which,
   }
 }
 
-grpc_error* grpc_error_add_child(grpc_error* src, grpc_error* child) {
+grpc_error_handle grpc_error_add_child(grpc_error_handle src,
+                                       grpc_error_handle child) {
   GPR_TIMER_SCOPE("grpc_error_add_child", 0);
   if (src != GRPC_ERROR_NONE) {
     if (child == GRPC_ERROR_NONE) {
       /* \a child is empty. Simply return the ref to \a src */
       return src;
     } else if (child != src) {
-      grpc_error* new_err = copy_error_and_unref(src);
+      grpc_error_handle new_err = copy_error_and_unref(src);
       internal_add_error(&new_err, child);
       return new_err;
     } else {
@@ -616,7 +716,7 @@ static char* fmt_int(intptr_t p) {
   return s;
 }
 
-static void collect_ints_kvs(grpc_error* err, kv_pairs* kvs) {
+static void collect_ints_kvs(grpc_error_handle err, kv_pairs* kvs) {
   for (size_t which = 0; which < GRPC_ERROR_INT_MAX; ++which) {
     uint8_t slot = err->ints[which];
     if (slot != UINT8_MAX) {
@@ -640,7 +740,7 @@ static char* fmt_str(const grpc_slice& slice) {
   return s;
 }
 
-static void collect_strs_kvs(grpc_error* err, kv_pairs* kvs) {
+static void collect_strs_kvs(grpc_error_handle err, kv_pairs* kvs) {
   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
     uint8_t slot = err->strs[which];
     if (slot != UINT8_MAX) {
@@ -675,7 +775,7 @@ static char* fmt_time(gpr_timespec tm) {
   return out;
 }
 
-static void collect_times_kvs(grpc_error* err, kv_pairs* kvs) {
+static void collect_times_kvs(grpc_error_handle err, kv_pairs* kvs) {
   for (size_t which = 0; which < GRPC_ERROR_TIME_MAX; ++which) {
     uint8_t slot = err->times[which];
     if (slot != UINT8_MAX) {
@@ -685,7 +785,7 @@ static void collect_times_kvs(grpc_error* err, kv_pairs* kvs) {
   }
 }
 
-static void add_errs(grpc_error* err, char** s, size_t* sz, size_t* cap) {
+static void add_errs(grpc_error_handle err, char** s, size_t* sz, size_t* cap) {
   uint8_t slot = err->first_err;
   bool first = true;
   while (slot != UINT8_MAX) {
@@ -701,7 +801,7 @@ static void add_errs(grpc_error* err, char** s, size_t* sz, size_t* cap) {
   }
 }
 
-static char* errs_string(grpc_error* err) {
+static char* errs_string(grpc_error_handle err) {
   char* s = nullptr;
   size_t sz = 0;
   size_t cap = 0;
@@ -740,7 +840,7 @@ static char* finish_kvs(kv_pairs* kvs) {
   return s;
 }
 
-const char* grpc_error_string(grpc_error* err) {
+const char* grpc_error_string(grpc_error_handle err) {
   GPR_TIMER_SCOPE("grpc_error_string", 0);
   if (err == GRPC_ERROR_NONE) return no_error_string;
   if (err == GRPC_ERROR_OOM) return oom_error_string;
@@ -775,8 +875,12 @@ const char* grpc_error_string(grpc_error* err) {
   return out;
 }
 
-grpc_error* grpc_os_error(const char* file, int line, int err,
-                          const char* call_name) {
+std::string grpc_error_std_string(grpc_error_handle error) {
+  return std::string(grpc_error_string(error));
+}
+
+grpc_error_handle grpc_os_error(const char* file, int line, int err,
+                                const char* call_name) {
   return grpc_error_set_str(
       grpc_error_set_str(
           grpc_error_set_int(
@@ -790,10 +894,10 @@ grpc_error* grpc_os_error(const char* file, int line, int err,
 }
 
 #ifdef GPR_WINDOWS
-grpc_error* grpc_wsa_error(const char* file, int line, int err,
-                           const char* call_name) {
+grpc_error_handle grpc_wsa_error(const char* file, int line, int err,
+                                 const char* call_name) {
   char* utf8_message = gpr_format_message(err);
-  grpc_error* error = grpc_error_set_str(
+  grpc_error_handle error = grpc_error_set_str(
       grpc_error_set_str(
           grpc_error_set_int(
               grpc_error_create(file, line,
@@ -807,7 +911,7 @@ grpc_error* grpc_wsa_error(const char* file, int line, int err,
 }
 #endif
 
-bool grpc_log_error(const char* what, grpc_error* error, const char* file,
+bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
                     int line) {
   GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
   const char* msg = grpc_error_string(error);
@@ -815,3 +919,5 @@ bool grpc_log_error(const char* what, grpc_error* error, const char* file,
   GRPC_ERROR_UNREF(error);
   return false;
 }
+
+#endif  // GRPC_ERROR_IS_ABSEIL_STATUS
index ca520fa..aecd1e9 100644 (file)
 #include <grpc/support/time.h>
 
 #include "src/core/lib/debug/trace.h"
+#include "src/core/lib/gprpp/status_helper.h"
+
+#include "absl/status/status.h"
 
 /// Opaque representation of an error.
 /// See https://github.com/grpc/grpc/blob/master/doc/core/grpc-error.md for a
 /// full write up of this object.
 
+#ifdef GRPC_ERROR_IS_ABSEIL_STATUS
+
+typedef absl::Status grpc_error_handle;
+
+#else  // GRPC_ERROR_IS_ABSEIL_STATUS
+
 typedef struct grpc_error grpc_error;
+typedef grpc_error* grpc_error_handle;
 
-extern grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount;
+#endif  // GRPC_ERROR_IS_ABSEIL_STATUS
 
 typedef enum {
   /// 'errno' from the operating system
-  GRPC_ERROR_INT_ERRNO,
+  GRPC_ERROR_INT_ERRNO =
+      static_cast<int>(grpc_core::StatusIntProperty::kErrorNo),
   /// __LINE__ from the call site creating the error
-  GRPC_ERROR_INT_FILE_LINE,
+  GRPC_ERROR_INT_FILE_LINE =
+      static_cast<int>(grpc_core::StatusIntProperty::kFileLine),
   /// stream identifier: for errors that are associated with an individual
   /// wire stream
-  GRPC_ERROR_INT_STREAM_ID,
+  GRPC_ERROR_INT_STREAM_ID =
+      static_cast<int>(grpc_core::StatusIntProperty::kStreamId),
   /// grpc status code representing this error
-  GRPC_ERROR_INT_GRPC_STATUS,
+  GRPC_ERROR_INT_GRPC_STATUS =
+      static_cast<int>(grpc_core::StatusIntProperty::kRpcStatus),
   /// offset into some binary blob (usually represented by
   /// GRPC_ERROR_STR_RAW_BYTES) where the error occurred
-  GRPC_ERROR_INT_OFFSET,
+  GRPC_ERROR_INT_OFFSET =
+      static_cast<int>(grpc_core::StatusIntProperty::kOffset),
   /// context sensitive index associated with the error
-  GRPC_ERROR_INT_INDEX,
+  GRPC_ERROR_INT_INDEX = static_cast<int>(grpc_core::StatusIntProperty::kIndex),
   /// context sensitive size associated with the error
-  GRPC_ERROR_INT_SIZE,
+  GRPC_ERROR_INT_SIZE = static_cast<int>(grpc_core::StatusIntProperty::kSize),
   /// http2 error code associated with the error (see the HTTP2 RFC)
-  GRPC_ERROR_INT_HTTP2_ERROR,
+  GRPC_ERROR_INT_HTTP2_ERROR =
+      static_cast<int>(grpc_core::StatusIntProperty::kHttp2Error),
   /// TSI status code associated with the error
-  GRPC_ERROR_INT_TSI_CODE,
-  /// grpc_security_status associated with the error
-  GRPC_ERROR_INT_SECURITY_STATUS,
+  GRPC_ERROR_INT_TSI_CODE =
+      static_cast<int>(grpc_core::StatusIntProperty::kTsiCode),
   /// WSAGetLastError() reported when this error occurred
-  GRPC_ERROR_INT_WSA_ERROR,
+  GRPC_ERROR_INT_WSA_ERROR =
+      static_cast<int>(grpc_core::StatusIntProperty::kWsaError),
   /// File descriptor associated with this error
-  GRPC_ERROR_INT_FD,
+  GRPC_ERROR_INT_FD = static_cast<int>(grpc_core::StatusIntProperty::kFd),
   /// HTTP status (i.e. 404)
-  GRPC_ERROR_INT_HTTP_STATUS,
-  /// context sensitive limit associated with the error
-  GRPC_ERROR_INT_LIMIT,
+  GRPC_ERROR_INT_HTTP_STATUS =
+      static_cast<int>(grpc_core::StatusIntProperty::kHttpStatus),
   /// chttp2: did the error occur while a write was in progress
-  GRPC_ERROR_INT_OCCURRED_DURING_WRITE,
+  GRPC_ERROR_INT_OCCURRED_DURING_WRITE =
+      static_cast<int>(grpc_core::StatusIntProperty::kOccurredDuringWrite),
   /// channel connectivity state associated with the error
-  GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE,
+  GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE =
+      static_cast<int>(grpc_core::StatusIntProperty::ChannelConnectivityState),
+  /// LB policy drop
+  GRPC_ERROR_INT_LB_POLICY_DROP =
+      static_cast<int>(grpc_core::StatusIntProperty::kLbPolicyDrop),
 
   /// Must always be last
   GRPC_ERROR_INT_MAX,
@@ -81,29 +101,35 @@ typedef enum {
 
 typedef enum {
   /// top-level textual description of this error
-  GRPC_ERROR_STR_DESCRIPTION,
+  GRPC_ERROR_STR_DESCRIPTION =
+      static_cast<int>(grpc_core::StatusStrProperty::kDescription),
   /// source file in which this error occurred
-  GRPC_ERROR_STR_FILE,
+  GRPC_ERROR_STR_FILE = static_cast<int>(grpc_core::StatusStrProperty::kFile),
   /// operating system description of this error
-  GRPC_ERROR_STR_OS_ERROR,
+  GRPC_ERROR_STR_OS_ERROR =
+      static_cast<int>(grpc_core::StatusStrProperty::kOsError),
   /// syscall that generated this error
-  GRPC_ERROR_STR_SYSCALL,
+  GRPC_ERROR_STR_SYSCALL =
+      static_cast<int>(grpc_core::StatusStrProperty::kSyscall),
   /// peer that we were trying to communicate when this error occurred
-  GRPC_ERROR_STR_TARGET_ADDRESS,
+  GRPC_ERROR_STR_TARGET_ADDRESS =
+      static_cast<int>(grpc_core::StatusStrProperty::kTargetAddress),
   /// grpc status message associated with this error
-  GRPC_ERROR_STR_GRPC_MESSAGE,
+  GRPC_ERROR_STR_GRPC_MESSAGE =
+      static_cast<int>(grpc_core::StatusStrProperty::kGrpcMessage),
   /// hex dump (or similar) with the data that generated this error
-  GRPC_ERROR_STR_RAW_BYTES,
+  GRPC_ERROR_STR_RAW_BYTES =
+      static_cast<int>(grpc_core::StatusStrProperty::kRawBytes),
   /// tsi error string associated with this error
-  GRPC_ERROR_STR_TSI_ERROR,
+  GRPC_ERROR_STR_TSI_ERROR =
+      static_cast<int>(grpc_core::StatusStrProperty::kTsiError),
   /// filename that we were trying to read/write when this error occurred
-  GRPC_ERROR_STR_FILENAME,
-  /// which data was queued for writing when the error occurred
-  GRPC_ERROR_STR_QUEUED_BUFFERS,
+  GRPC_ERROR_STR_FILENAME =
+      static_cast<int>(grpc_core::StatusStrProperty::kFilename),
   /// key associated with the error
-  GRPC_ERROR_STR_KEY,
+  GRPC_ERROR_STR_KEY = static_cast<int>(grpc_core::StatusStrProperty::kKey),
   /// value associated with the error
-  GRPC_ERROR_STR_VALUE,
+  GRPC_ERROR_STR_VALUE = static_cast<int>(grpc_core::StatusStrProperty::kValue),
 
   /// Must always be last
   GRPC_ERROR_STR_MAX,
@@ -117,32 +143,135 @@ typedef enum {
   GRPC_ERROR_TIME_MAX,
 } grpc_error_times;
 
+// DEPRECATED: Use grpc_error_std_string instead
+const char* grpc_error_string(grpc_error_handle error);
+std::string grpc_error_std_string(grpc_error_handle error);
+
+// debug only toggles that allow for a sanity to check that ensures we will
+// never create any errors in the per-RPC hotpath.
+void grpc_disable_error_creation();
+void grpc_enable_error_creation();
+
+#ifdef GRPC_ERROR_IS_ABSEIL_STATUS
+
+#define GRPC_ERROR_NONE absl::OkStatus()
+#define GRPC_ERROR_OOM absl::Status(absl::ResourceExhaustedError)
+#define GRPC_ERROR_CANCELLED absl::CancelledError()
+
+#define GRPC_ERROR_REF(err) (err)
+#define GRPC_ERROR_UNREF(err)
+
+#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc) \
+  StatusCreate(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, {})
+#define GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc) \
+  StatusCreate(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, {})
+#define GRPC_ERROR_CREATE_FROM_STRING_VIEW(desc) \
+  StatusCreate(ababsl::StatusCode::kUnknown, desc, DEBUG_LOCATION, {})
+
+absl::Status grpc_status_create(absl::StatusCode code, absl::string_view msg,
+                                const grpc_core::DebugLocation& location,
+                                size_t children_count,
+                                absl::Status* children) GRPC_MUST_USE_RESULT;
+
+// Create an error that references some other errors. This function adds a
+// reference to each error in errs - it does not consume an existing reference
+#define GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(desc, errs, count)   \
+  grpc_status_create(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, count, \
+                     errs)
+#define GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(desc, errs, count)   \
+  grpc_status_create(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, count, \
+                     errs)
+
+// Consumes all the errors in the vector and forms a referencing error from
+// them. If the vector is empty, return GRPC_ERROR_NONE.
+template <typename VectorType>
+static absl::Status grpc_status_create_from_vector(
+    const grpc_core::DebugLocation& location, const char* desc,
+    VectorType* error_list) {
+  absl::Status error = GRPC_ERROR_NONE;
+  if (error_list->size() != 0) {
+    error = grpc_status_create(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION,
+                               error_list->size(), error_list->data());
+    error_list->clear();
+  }
+  return error;
+}
+
+#define GRPC_ERROR_CREATE_FROM_VECTOR(desc, error_list) \
+  grpc_status_create_from_vector(DEBUG_LOCATION, desc, error_list)
+
+absl::Status grpc_os_error(const grpc_core::DebugLocation& location, int err,
+                           const char* call_name) GRPC_MUST_USE_RESULT;
+
+inline absl::Status grpc_assert_never_ok(absl::Status error) {
+  GPR_ASSERT(error != GRPC_ERROR_NONE);
+  return error;
+}
+
+/// create an error associated with errno!=0 (an 'operating system' error)
+#define GRPC_OS_ERROR(err, call_name) \
+  grpc_assert_never_ok(grpc_os_error(DEBUG_LOCATION, err, call_name))
+
+absl::Status grpc_wsa_error(const grpc_core::DebugLocation& location, int err,
+                            const char* call_name) GRPC_MUST_USE_RESULT;
+
+/// windows only: create an error associated with WSAGetLastError()!=0
+#define GRPC_WSA_ERROR(err, call_name) \
+  grpc_wsa_error(DEBUG_LOCATION, err, call_name)
+
+#else  // GRPC_ERROR_IS_ABSEIL_STATUS
+
 /// The following "special" errors can be propagated without allocating memory.
 /// They are always even so that other code (particularly combiner locks,
 /// polling engines) can safely use the lower bit for themselves.
 
-#define GRPC_ERROR_NONE ((grpc_error*)NULL)
-#define GRPC_ERROR_RESERVED_1 ((grpc_error*)1)
-#define GRPC_ERROR_OOM ((grpc_error*)2)
-#define GRPC_ERROR_RESERVED_2 ((grpc_error*)3)
-#define GRPC_ERROR_CANCELLED ((grpc_error*)4)
+#define GRPC_ERROR_NONE ((grpc_error_handle)NULL)
+#define GRPC_ERROR_RESERVED_1 ((grpc_error_handle)1)
+#define GRPC_ERROR_OOM ((grpc_error_handle)2)
+#define GRPC_ERROR_RESERVED_2 ((grpc_error_handle)3)
+#define GRPC_ERROR_CANCELLED ((grpc_error_handle)4)
 #define GRPC_ERROR_SPECIAL_MAX GRPC_ERROR_CANCELLED
 
-inline bool grpc_error_is_special(struct grpc_error* err) {
+inline bool grpc_error_is_special(grpc_error_handle err) {
   return err <= GRPC_ERROR_SPECIAL_MAX;
 }
 
-// debug only toggles that allow for a sanity to check that ensures we will
-// never create any errors in the per-RPC hotpath.
-void grpc_disable_error_creation();
-void grpc_enable_error_creation();
-
-const char* grpc_error_string(grpc_error* error);
+#ifndef NDEBUG
+grpc_error_handle grpc_error_do_ref(grpc_error_handle err, const char* file,
+                                    int line);
+void grpc_error_do_unref(grpc_error_handle err, const char* file, int line);
+inline grpc_error_handle grpc_error_ref(grpc_error_handle err, const char* file,
+                                        int line) {
+  if (grpc_error_is_special(err)) return err;
+  return grpc_error_do_ref(err, file, line);
+}
+inline void grpc_error_unref(grpc_error_handle err, const char* file,
+                             int line) {
+  if (grpc_error_is_special(err)) return;
+  grpc_error_do_unref(err, file, line);
+}
+#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__)
+#define GRPC_ERROR_UNREF(err) grpc_error_unref(err, __FILE__, __LINE__)
+#else
+grpc_error_handle grpc_error_do_ref(grpc_error_handle err);
+void grpc_error_do_unref(grpc_error_handle err);
+inline grpc_error_handle grpc_error_ref(grpc_error_handle err) {
+  if (grpc_error_is_special(err)) return err;
+  return grpc_error_do_ref(err);
+}
+inline void grpc_error_unref(grpc_error_handle err) {
+  if (grpc_error_is_special(err)) return;
+  grpc_error_do_unref(err);
+}
+#define GRPC_ERROR_REF(err) grpc_error_ref(err)
+#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
+#endif
 
 /// Create an error - but use GRPC_ERROR_CREATE instead
-grpc_error* grpc_error_create(const char* file, int line,
-                              const grpc_slice& desc, grpc_error** referencing,
-                              size_t num_referencing);
+grpc_error_handle grpc_error_create(const char* file, int line,
+                                    const grpc_slice& desc,
+                                    grpc_error_handle* referencing,
+                                    size_t num_referencing);
 /// Create an error (this is the preferred way of generating an error that is
 ///   not due to a system call - for system calls, use GRPC_OS_ERROR or
 ///   GRPC_WSA_ERROR as appropriate)
@@ -157,6 +286,10 @@ grpc_error* grpc_error_create(const char* file, int line,
 #define GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc)                           \
   grpc_error_create(__FILE__, __LINE__, grpc_slice_from_copied_string(desc), \
                     NULL, 0)
+#define GRPC_ERROR_CREATE_FROM_STRING_VIEW(desc) \
+  grpc_error_create(                             \
+      __FILE__, __LINE__,                        \
+      grpc_slice_from_copied_buffer((desc).data(), (desc).size()), NULL, 0)
 
 // Create an error that references some other errors. This function adds a
 // reference to each error in errs - it does not consume an existing reference
@@ -170,41 +303,14 @@ grpc_error* grpc_error_create(const char* file, int line,
 #define GRPC_ERROR_CREATE_FROM_VECTOR(desc, error_list) \
   grpc_error_create_from_vector(__FILE__, __LINE__, desc, error_list)
 
-#ifndef NDEBUG
-grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line);
-void grpc_error_do_unref(grpc_error* err, const char* file, int line);
-inline grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
-  if (grpc_error_is_special(err)) return err;
-  return grpc_error_do_ref(err, file, line);
-}
-inline void grpc_error_unref(grpc_error* err, const char* file, int line) {
-  if (grpc_error_is_special(err)) return;
-  grpc_error_do_unref(err, file, line);
-}
-#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__)
-#define GRPC_ERROR_UNREF(err) grpc_error_unref(err, __FILE__, __LINE__)
-#else
-grpc_error* grpc_error_do_ref(grpc_error* err);
-void grpc_error_do_unref(grpc_error* err);
-inline grpc_error* grpc_error_ref(grpc_error* err) {
-  if (grpc_error_is_special(err)) return err;
-  return grpc_error_do_ref(err);
-}
-inline void grpc_error_unref(grpc_error* err) {
-  if (grpc_error_is_special(err)) return;
-  grpc_error_do_unref(err);
-}
-#define GRPC_ERROR_REF(err) grpc_error_ref(err)
-#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
-#endif
-
 // Consumes all the errors in the vector and forms a referencing error from
 // them. If the vector is empty, return GRPC_ERROR_NONE.
 template <typename VectorType>
-static grpc_error* grpc_error_create_from_vector(const char* file, int line,
-                                                 const char* desc,
-                                                 VectorType* error_list) {
-  grpc_error* error = GRPC_ERROR_NONE;
+static grpc_error_handle grpc_error_create_from_vector(const char* file,
+                                                       int line,
+                                                       const char* desc,
+                                                       VectorType* error_list) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (error_list->size() != 0) {
     error = grpc_error_create(file, line, grpc_slice_from_static_string(desc),
                               error_list->data(), error_list->size());
@@ -217,18 +323,40 @@ static grpc_error* grpc_error_create_from_vector(const char* file, int line,
   return error;
 }
 
-grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
-                               intptr_t value) GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_os_error(const char* file, int line, int err,
+                                const char* call_name) GRPC_MUST_USE_RESULT;
+
+inline grpc_error_handle grpc_assert_never_ok(grpc_error_handle error) {
+  GPR_ASSERT(error != GRPC_ERROR_NONE);
+  return error;
+}
+
+/// create an error associated with errno!=0 (an 'operating system' error)
+#define GRPC_OS_ERROR(err, call_name) \
+  grpc_assert_never_ok(grpc_os_error(__FILE__, __LINE__, err, call_name))
+grpc_error_handle grpc_wsa_error(const char* file, int line, int err,
+                                 const char* call_name) GRPC_MUST_USE_RESULT;
+/// windows only: create an error associated with WSAGetLastError()!=0
+#define GRPC_WSA_ERROR(err, call_name) \
+  grpc_wsa_error(__FILE__, __LINE__, err, call_name)
+
+#endif  // GRPC_ERROR_IS_ABSEIL_STATUS
+
+grpc_error_handle grpc_error_set_int(grpc_error_handle src,
+                                     grpc_error_ints which,
+                                     intptr_t value) GRPC_MUST_USE_RESULT;
 /// It is an error to pass nullptr as `p`. Caller should allocate a phony
 /// intptr_t for `p`, even if the value of `p` is not used.
-bool grpc_error_get_int(grpc_error* error, grpc_error_ints which, intptr_t* p);
+bool grpc_error_get_int(grpc_error_handle error, grpc_error_ints which,
+                        intptr_t* p);
 /// This call takes ownership of the slice; the error is responsible for
 /// eventually unref-ing it.
-grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which,
-                               const grpc_slice& str) GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_error_set_str(
+    grpc_error_handle src, grpc_error_strs which,
+    const grpc_slice& str) GRPC_MUST_USE_RESULT;
 /// Returns false if the specified string is not set.
 /// Caller does NOT own the slice.
-bool grpc_error_get_str(grpc_error* error, grpc_error_strs which,
+bool grpc_error_get_str(grpc_error_handle error, grpc_error_strs which,
                         grpc_slice* s);
 
 /// Add a child error: an error that is believed to have contributed to this
@@ -242,29 +370,12 @@ bool grpc_error_get_str(grpc_error* error, grpc_error_strs which,
 /// returns GRPC_ERROR_NONE. 3) If \a src and \a child point to the same error,
 /// returns a single reference. (Note that, 2 references should have been
 /// received to the error in this case.)
-grpc_error* grpc_error_add_child(grpc_error* src,
-                                 grpc_error* child) GRPC_MUST_USE_RESULT;
-
-grpc_error* grpc_os_error(const char* file, int line, int err,
-                          const char* call_name) GRPC_MUST_USE_RESULT;
-
-inline grpc_error* grpc_assert_never_ok(grpc_error* error) {
-  GPR_ASSERT(error != GRPC_ERROR_NONE);
-  return error;
-}
-
-/// create an error associated with errno!=0 (an 'operating system' error)
-#define GRPC_OS_ERROR(err, call_name) \
-  grpc_assert_never_ok(grpc_os_error(__FILE__, __LINE__, err, call_name))
-grpc_error* grpc_wsa_error(const char* file, int line, int err,
-                           const char* call_name) GRPC_MUST_USE_RESULT;
-/// windows only: create an error associated with WSAGetLastError()!=0
-#define GRPC_WSA_ERROR(err, call_name) \
-  grpc_wsa_error(__FILE__, __LINE__, err, call_name)
+grpc_error_handle grpc_error_add_child(
+    grpc_error_handle src, grpc_error_handle child) GRPC_MUST_USE_RESULT;
 
-bool grpc_log_error(const char* what, grpc_error* error, const char* file,
+bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
                     int line);
-inline bool grpc_log_if_error(const char* what, grpc_error* error,
+inline bool grpc_log_if_error(const char* what, grpc_error_handle error,
                               const char* file, int line) {
   return error == GRPC_ERROR_NONE ? true
                                   : grpc_log_error(what, error, file, line);
index 7bf2865..114b3f2 100644 (file)
@@ -31,8 +31,9 @@
 
 #define MAX_ERROR_DESCRIPTION 256
 
-grpc_error* grpc_error_create_from_cferror(const char* file, int line,
-                                           void* arg, const char* custom_desc) {
+grpc_error_handle grpc_error_create_from_cferror(const char* file, int line,
+                                                 void* arg,
+                                                 const char* custom_desc) {
   CFErrorRef error = static_cast<CFErrorRef>(arg);
   char buf_domain[MAX_ERROR_DESCRIPTION];
   char buf_desc[MAX_ERROR_DESCRIPTION];
index 06ab751..2d5b744 100644 (file)
@@ -24,8 +24,8 @@
 #define GRPC_ERROR_CREATE_FROM_CFERROR(error, desc)  \
   grpc_error_create_from_cferror(__FILE__, __LINE__, \
                                  static_cast<void*>((error)), (desc))
-grpc_error* grpc_error_create_from_cferror(const char* file, int line,
-                                           void* arg, const char* desc);
+grpc_error_handle grpc_error_create_from_cferror(const char* file, int line,
+                                                 void* arg, const char* desc);
 #endif /* GRPC_CFSTREAM */
 
 #endif /* GRPC_CORE_LIB_IOMGR_ERROR_CFSTREAM_H */
index 33c233b..50c1dde 100644 (file)
 #include <grpc/support/sync.h>
 #include "src/core/lib/iomgr/error.h"
 
+#ifndef GRPC_ERROR_IS_ABSEIL_STATUS
+
 typedef struct grpc_linked_error grpc_linked_error;
 
 struct grpc_linked_error {
-  grpc_error* err;
+  grpc_error_handle err;
   uint8_t next;
 };
 
@@ -58,4 +60,6 @@ struct grpc_error {
   intptr_t arena[0];
 };
 
+#endif  // GRPC_ERROR_IS_ABSEIL_STATUS
+
 #endif /* GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H */
index 1264866..2580582 100644 (file)
@@ -219,9 +219,9 @@ static void pollset_global_shutdown(void) {
 /// The Apple pollset simply waits on a condition variable until it is kicked.
 /// The network events are handled in the global run loop thread. Processing of
 /// these events will eventually trigger the kick.
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker,
+                                      grpc_millis deadline) {
   GRPC_POLLING_TRACE("pollset work: %p, worker: %p, deadline: %" PRIu64,
                      pollset, worker, deadline);
   GrpcApplePollset* apple_pollset =
@@ -272,8 +272,8 @@ static void kick_worker(GrpcAppleWorker* worker) {
 /// The caller must acquire the lock GrpcApplePollset.mu before calling this
 /// function. The kick action simply signals the condition variable of the
 /// worker.
-static grpc_error* pollset_kick(grpc_pollset* pollset,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* pollset,
+                                      grpc_pollset_worker* specific_worker) {
   GrpcApplePollset* apple_pollset =
       reinterpret_cast<GrpcApplePollset*>(pollset);
 
index a850870..f09cd78 100644 (file)
@@ -241,7 +241,7 @@ struct grpc_pollset_set {
  * Common helpers
  */
 
-static bool append_error(grpc_error** composite, grpc_error* error,
+static bool append_error(grpc_error_handle* composite, grpc_error_handle error,
                          const char* desc) {
   if (error == GRPC_ERROR_NONE) return true;
   if (*composite == GRPC_ERROR_NONE) {
@@ -382,7 +382,7 @@ static int fd_wrapped_fd(grpc_fd* fd) { return fd->fd; }
 /* if 'releasing_fd' is true, it means that we are going to detach the internal
  * fd from grpc_fd structure (i.e which means we should not be calling
  * shutdown() syscall on that fd) */
-static void fd_shutdown_internal(grpc_fd* fd, grpc_error* why,
+static void fd_shutdown_internal(grpc_fd* fd, grpc_error_handle why,
                                  bool releasing_fd) {
   if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
     if (!releasing_fd) {
@@ -402,13 +402,13 @@ static void fd_shutdown_internal(grpc_fd* fd, grpc_error* why,
 }
 
 /* Might be called multiple times */
-static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
+static void fd_shutdown(grpc_fd* fd, grpc_error_handle why) {
   fd_shutdown_internal(fd, why, false);
 }
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
                       const char* reason) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   bool is_release_fd = (release_fd != nullptr);
 
   if (!fd->read_closure->IsShutdown()) {
@@ -514,12 +514,12 @@ static size_t choose_neighborhood(void) {
   return static_cast<size_t>(gpr_cpu_current_cpu()) % g_num_neighborhoods;
 }
 
-static grpc_error* pollset_global_init(void) {
+static grpc_error_handle pollset_global_init(void) {
   gpr_tls_init(&g_current_thread_pollset);
   gpr_tls_init(&g_current_thread_worker);
   gpr_atm_no_barrier_store(&g_active_poller, 0);
   global_wakeup_fd.read_fd = -1;
-  grpc_error* err = grpc_wakeup_fd_init(&global_wakeup_fd);
+  grpc_error_handle err = grpc_wakeup_fd_init(&global_wakeup_fd);
   if (err != GRPC_ERROR_NONE) return err;
   struct epoll_event ev;
   ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLET);
@@ -589,9 +589,9 @@ static void pollset_destroy(grpc_pollset* pollset) {
   gpr_mu_destroy(&pollset->mu);
 }
 
-static grpc_error* pollset_kick_all(grpc_pollset* pollset) {
+static grpc_error_handle pollset_kick_all(grpc_pollset* pollset) {
   GPR_TIMER_SCOPE("pollset_kick_all", 0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (pollset->root_worker != nullptr) {
     grpc_pollset_worker* worker = pollset->root_worker;
     do {
@@ -663,11 +663,11 @@ static int poll_deadline_to_millis_timeout(grpc_millis millis) {
    NOTE ON SYNCRHONIZATION: Similar to do_epoll_wait(), this function is only
    called by g_active_poller thread. So there is no need for synchronization
    when accessing fields in g_epoll_set */
-static grpc_error* process_epoll_events(grpc_pollset* /*pollset*/) {
+static grpc_error_handle process_epoll_events(grpc_pollset* /*pollset*/) {
   GPR_TIMER_SCOPE("process_epoll_events", 0);
 
   static const char* err_desc = "process_events";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   long num_events = gpr_atm_acq_load(&g_epoll_set.num_events);
   long cursor = gpr_atm_acq_load(&g_epoll_set.cursor);
   for (int idx = 0;
@@ -715,7 +715,7 @@ static grpc_error* process_epoll_events(grpc_pollset* /*pollset*/) {
    NOTE ON SYNCHRONIZATION: At any point of time, only the g_active_poller
    (i.e the designated poller thread) will be calling this function. So there is
    no need for any synchronization when accesing fields in g_epoll_set */
-static grpc_error* do_epoll_wait(grpc_pollset* ps, grpc_millis deadline) {
+static grpc_error_handle do_epoll_wait(grpc_pollset* ps, grpc_millis deadline) {
   GPR_TIMER_SCOPE("do_epoll_wait", 0);
 
   int r;
@@ -1014,12 +1014,12 @@ static void end_worker(grpc_pollset* pollset, grpc_pollset_worker* worker,
    The function pollset_work() may temporarily release the lock (pollset->po.mu)
    during the course of its execution but it will always re-acquire the lock and
    ensure that it is held by the time the function returns */
-static grpc_error* pollset_work(grpc_pollset* ps,
-                                grpc_pollset_worker** worker_hdl,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* ps,
+                                      grpc_pollset_worker** worker_hdl,
+                                      grpc_millis deadline) {
   GPR_TIMER_SCOPE("pollset_work", 0);
   grpc_pollset_worker worker;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollset_work";
   if (ps->kicked_without_poller) {
     ps->kicked_without_poller = false;
@@ -1065,11 +1065,11 @@ static grpc_error* pollset_work(grpc_pollset* ps,
   return error;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* pollset,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* pollset,
+                                      grpc_pollset_worker* specific_worker) {
   GPR_TIMER_SCOPE("pollset_kick", 0);
   GRPC_STATS_INC_POLLSET_KICK();
-  grpc_error* ret_err = GRPC_ERROR_NONE;
+  grpc_error_handle ret_err = GRPC_ERROR_NONE;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     std::vector<std::string> log;
     log.push_back(absl::StrFormat(
@@ -1260,7 +1260,7 @@ static bool is_any_background_poller_thread(void) { return false; }
 static void shutdown_background_closure(void) {}
 
 static bool add_closure_to_background_poller(grpc_closure* /*closure*/,
-                                             grpc_error* /*error*/) {
+                                             grpc_error_handle /*error*/) {
   return false;
 }
 
index f26a992..72d7da7 100644 (file)
@@ -134,7 +134,7 @@ static std::string pollable_desc(pollable* p) {
 /// added
 static pollable* g_empty_pollable;
 
-static grpc_error* pollable_create(pollable_type type, pollable** p);
+static grpc_error_handle pollable_create(pollable_type type, pollable** p);
 static pollable* pollable_ref(pollable* p,
                               const grpc_core::DebugLocation& dbg_loc,
                               const char* reason) {
@@ -314,7 +314,7 @@ struct grpc_pollset_set {
  * Common helpers
  */
 
-static bool append_error(grpc_error** composite, grpc_error* error,
+static bool append_error(grpc_error_handle* composite, grpc_error_handle error,
                          const char* desc) {
   if (error == GRPC_ERROR_NONE) return true;
   if (*composite == GRPC_ERROR_NONE) {
@@ -372,7 +372,7 @@ static void ref_by(grpc_fd* fd, int n) {
 }
 
 /* Uninitialize and add to the freelist */
-static void fd_destroy(void* arg, grpc_error* /*error*/) {
+static void fd_destroy(void* arg, grpc_error_handle /*error*/) {
   grpc_fd* fd = static_cast<grpc_fd*>(arg);
   fd->destroy();
 
@@ -509,7 +509,7 @@ static bool fd_is_shutdown(grpc_fd* fd) {
 }
 
 /* Might be called multiple times */
-static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
+static void fd_shutdown(grpc_fd* fd, grpc_error_handle why) {
   if (fd->read_closure.SetShutdown(GRPC_ERROR_REF(why))) {
     if (shutdown(fd->fd, SHUT_RDWR)) {
       if (errno != ENOTCONN) {
@@ -556,7 +556,7 @@ static void fd_add_pollset(grpc_fd* fd, grpc_pollset* pollset) {
  * Pollable Definitions
  */
 
-static grpc_error* pollable_create(pollable_type type, pollable** p) {
+static grpc_error_handle pollable_create(pollable_type type, pollable** p) {
   *p = nullptr;
 
   int epfd = epoll_create1(EPOLL_CLOEXEC);
@@ -565,7 +565,7 @@ static grpc_error* pollable_create(pollable_type type, pollable** p) {
   }
   GRPC_FD_TRACE("Pollable_create: created epfd: %d (type: %d)", epfd, type);
   *p = static_cast<pollable*>(gpr_malloc(sizeof(**p)));
-  grpc_error* err = grpc_wakeup_fd_init(&(*p)->wakeup);
+  grpc_error_handle err = grpc_wakeup_fd_init(&(*p)->wakeup);
   if (err != GRPC_ERROR_NONE) {
     GRPC_FD_TRACE(
         "Pollable_create: closed epfd: %d (type: %d). wakeupfd_init error",
@@ -609,8 +609,8 @@ static grpc_error* pollable_create(pollable_type type, pollable** p) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pollable_add_fd(pollable* p, grpc_fd* fd) {
-  grpc_error* error = GRPC_ERROR_NONE;
+static grpc_error_handle pollable_add_fd(pollable* p, grpc_fd* fd) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollable_add_fd";
   const int epfd = p->epfd;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
@@ -647,7 +647,7 @@ GPR_TLS_DECL(g_current_thread_pollset);
 GPR_TLS_DECL(g_current_thread_worker);
 
 /* Global state management */
-static grpc_error* pollset_global_init(void) {
+static grpc_error_handle pollset_global_init(void) {
   gpr_tls_init(&g_current_thread_pollset);
   gpr_tls_init(&g_current_thread_worker);
   return pollable_create(PO_EMPTY, &g_empty_pollable);
@@ -681,7 +681,7 @@ static void pollset_maybe_finish_shutdown(grpc_pollset* pollset) {
 /* pollset->mu must be held before calling this function,
  * pollset->active_pollable->mu & specific_worker->pollable_obj->mu must not be
  * held */
-static grpc_error* kick_one_worker(grpc_pollset_worker* specific_worker) {
+static grpc_error_handle kick_one_worker(grpc_pollset_worker* specific_worker) {
   GPR_TIMER_SCOPE("kick_one_worker", 0);
   pollable* p = specific_worker->pollable_obj;
   grpc_core::MutexLockForGprMu lock(&p->mu);
@@ -708,7 +708,7 @@ static grpc_error* kick_one_worker(grpc_pollset_worker* specific_worker) {
       gpr_log(GPR_INFO, "PS:%p kicked_specific_via_wakeup_fd", p);
     }
     specific_worker->kicked = true;
-    grpc_error* error = grpc_wakeup_fd_wakeup(&p->wakeup);
+    grpc_error_handle error = grpc_wakeup_fd_wakeup(&p->wakeup);
     return error;
   }
   if (specific_worker->initialized_cv) {
@@ -725,8 +725,8 @@ static grpc_error* kick_one_worker(grpc_pollset_worker* specific_worker) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* pollset,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* pollset,
+                                      grpc_pollset_worker* specific_worker) {
   GPR_TIMER_SCOPE("pollset_kick", 0);
   GRPC_STATS_INC_POLLSET_KICK();
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
@@ -777,9 +777,9 @@ static grpc_error* pollset_kick(grpc_pollset* pollset,
   }
 }
 
-static grpc_error* pollset_kick_all(grpc_pollset* pollset) {
+static grpc_error_handle pollset_kick_all(grpc_pollset* pollset) {
   GPR_TIMER_SCOPE("pollset_kick_all", 0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   const char* err_desc = "pollset_kick_all";
   grpc_pollset_worker* w = pollset->root_worker;
   if (w != nullptr) {
@@ -828,9 +828,9 @@ static void fd_has_errors(grpc_fd* fd) { fd->error_closure.SetReady(); }
  *
  * Note that if a pollable object is already attached to the fd, it may be of
  * either PO_FD or PO_MULTI type */
-static grpc_error* get_fd_pollable(grpc_fd* fd, pollable** p) {
+static grpc_error_handle get_fd_pollable(grpc_fd* fd, pollable** p) {
   gpr_mu_lock(&fd->pollable_mu);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "get_fd_pollable";
   if (fd->pollable_obj == nullptr) {
     if (append_error(&error, pollable_create(PO_FD, &fd->pollable_obj),
@@ -863,8 +863,9 @@ static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
   pollset_maybe_finish_shutdown(pollset);
 }
 
-static grpc_error* pollable_process_events(grpc_pollset* pollset,
-                                           pollable* pollable_obj, bool drain) {
+static grpc_error_handle pollable_process_events(grpc_pollset* pollset,
+                                                 pollable* pollable_obj,
+                                                 bool drain) {
   GPR_TIMER_SCOPE("pollable_process_events", 0);
   static const char* err_desc = "pollset_process_events";
   // Use a simple heuristic to determine how many fd events to process
@@ -877,7 +878,7 @@ static grpc_error* pollable_process_events(grpc_pollset* pollset,
   if (handle_count == 0) {
     handle_count = 1;
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   for (int i = 0; (drain || i < handle_count) &&
                   pollable_obj->event_cursor != pollable_obj->event_count;
        i++) {
@@ -932,7 +933,7 @@ static void pollset_destroy(grpc_pollset* pollset) {
   gpr_mu_destroy(&pollset->mu);
 }
 
-static grpc_error* pollable_epoll(pollable* p, grpc_millis deadline) {
+static grpc_error_handle pollable_epoll(pollable* p, grpc_millis deadline) {
   GPR_TIMER_SCOPE("pollable_epoll", 0);
   int timeout = poll_deadline_to_millis_timeout(deadline);
 
@@ -1103,9 +1104,9 @@ static long sys_gettid(void) { return syscall(__NR_gettid); }
    The function pollset_work() may temporarily release the lock (pollset->po.mu)
    during the course of its execution but it will always re-acquire the lock and
    ensure that it is held by the time the function returns */
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker_hdl,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker_hdl,
+                                      grpc_millis deadline) {
   GPR_TIMER_SCOPE("pollset_work", 0);
 #ifdef GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP
   grpc_pollset_worker* worker =
@@ -1126,7 +1127,7 @@ static grpc_error* pollset_work(grpc_pollset* pollset,
             deadline, pollset->kicked_without_poller, pollset->active_pollable);
   }
   static const char* err_desc = "pollset_work";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (pollset->kicked_without_poller) {
     pollset->kicked_without_poller = false;
   } else {
@@ -1155,10 +1156,10 @@ static grpc_error* pollset_work(grpc_pollset* pollset,
   return error;
 }
 
-static grpc_error* pollset_transition_pollable_from_empty_to_fd_locked(
+static grpc_error_handle pollset_transition_pollable_from_empty_to_fd_locked(
     grpc_pollset* pollset, grpc_fd* fd) {
   static const char* err_desc = "pollset_transition_pollable_from_empty_to_fd";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(GPR_INFO,
             "PS:%p add fd %p (%d); transition pollable from empty to fd",
@@ -1171,10 +1172,10 @@ static grpc_error* pollset_transition_pollable_from_empty_to_fd_locked(
   return error;
 }
 
-static grpc_error* pollset_transition_pollable_from_fd_to_multi_locked(
+static grpc_error_handle pollset_transition_pollable_from_fd_to_multi_locked(
     grpc_pollset* pollset, grpc_fd* and_add_fd) {
   static const char* err_desc = "pollset_transition_pollable_from_fd_to_multi";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(
         GPR_INFO,
@@ -1200,8 +1201,9 @@ static grpc_error* pollset_transition_pollable_from_fd_to_multi_locked(
 }
 
 /* expects pollsets locked, flag whether fd is locked or not */
-static grpc_error* pollset_add_fd_locked(grpc_pollset* pollset, grpc_fd* fd) {
-  grpc_error* error = GRPC_ERROR_NONE;
+static grpc_error_handle pollset_add_fd_locked(grpc_pollset* pollset,
+                                               grpc_fd* fd) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   pollable* po_at_start =
       POLLABLE_REF(pollset->active_pollable, "pollset_add_fd");
   switch (pollset->active_pollable->type) {
@@ -1236,9 +1238,9 @@ static grpc_error* pollset_add_fd_locked(grpc_pollset* pollset, grpc_fd* fd) {
   return error;
 }
 
-static grpc_error* pollset_as_multipollable_locked(grpc_pollset* pollset,
-                                                   pollable** pollable_obj) {
-  grpc_error* error = GRPC_ERROR_NONE;
+static grpc_error_handle pollset_as_multipollable_locked(
+    grpc_pollset* pollset, pollable** pollable_obj) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   pollable* po_at_start =
       POLLABLE_REF(pollset->active_pollable, "pollset_as_multipollable");
   switch (pollset->active_pollable->type) {
@@ -1297,7 +1299,7 @@ static void pollset_add_fd(grpc_pollset* pollset, grpc_fd* fd) {
   }
 
   grpc_core::MutexLockForGprMu lock(&pollset->mu);
-  grpc_error* error = pollset_add_fd_locked(pollset, fd);
+  grpc_error_handle error = pollset_add_fd_locked(pollset, fd);
 
   // If we are in PO_MULTI mode, we should update the pollsets of the FD.
   if (gpr_atm_no_barrier_load(&pollset->active_pollable_type) == PO_MULTI) {
@@ -1354,7 +1356,7 @@ static void pollset_set_add_fd(grpc_pollset_set* pss, grpc_fd* fd) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(GPR_INFO, "PSS:%p: add fd %p (%d)", pss, fd, fd->fd);
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollset_set_add_fd";
   pss = pss_lock_adam(pss);
   for (size_t i = 0; i < pss->pollset_count; i++) {
@@ -1421,13 +1423,14 @@ static void pollset_set_del_pollset(grpc_pollset_set* pss, grpc_pollset* ps) {
 
 // add all fds to pollables, and output a new array of unorphaned out_fds
 // assumes pollsets are multipollable
-static grpc_error* add_fds_to_pollsets(grpc_fd** fds, size_t fd_count,
-                                       grpc_pollset** pollsets,
-                                       size_t pollset_count,
-                                       const char* err_desc, grpc_fd** out_fds,
-                                       size_t* out_fd_count) {
+static grpc_error_handle add_fds_to_pollsets(grpc_fd** fds, size_t fd_count,
+                                             grpc_pollset** pollsets,
+                                             size_t pollset_count,
+                                             const char* err_desc,
+                                             grpc_fd** out_fds,
+                                             size_t* out_fd_count) {
   GPR_TIMER_SCOPE("add_fds_to_pollsets", 0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   for (size_t i = 0; i < fd_count; i++) {
     gpr_mu_lock(&fds[i]->orphan_mu);
     if ((gpr_atm_no_barrier_load(&fds[i]->refst) & 1) == 0) {
@@ -1451,7 +1454,7 @@ static void pollset_set_add_pollset(grpc_pollset_set* pss, grpc_pollset* ps) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(GPR_INFO, "PSS:%p: add pollset %p", pss, ps);
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollset_set_add_pollset";
   pollable* pollable_obj = nullptr;
   gpr_mu_lock(&ps->mu);
@@ -1488,7 +1491,7 @@ static void pollset_set_add_pollset_set(grpc_pollset_set* a,
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(GPR_INFO, "PSS: merge (%p, %p)", a, b);
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollset_set_add_fd";
   for (;;) {
     if (a == b) {
@@ -1573,7 +1576,7 @@ static bool is_any_background_poller_thread(void) { return false; }
 static void shutdown_background_closure(void) {}
 
 static bool add_closure_to_background_poller(grpc_closure* /*closure*/,
-                                             grpc_error* /*error*/) {
+                                             grpc_error_handle /*error*/) {
   return false;
 }
 
index e58d1d3..fa4242f 100644 (file)
@@ -89,7 +89,7 @@ struct grpc_fd {
   int closed;
   int released;
   gpr_atm pollhup;
-  grpc_error* shutdown_error;
+  grpc_error_handle shutdown_error;
 
   /* The watcher list.
 
@@ -230,9 +230,9 @@ static int poll_deadline_to_millis_timeout(grpc_millis deadline);
 #define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2
 /* As per pollset_kick, with an extended set of flags (defined above)
    -- mostly for fd_posix's use. */
-static grpc_error* pollset_kick_ext(grpc_pollset* p,
-                                    grpc_pollset_worker* specific_worker,
-                                    uint32_t flags) GRPC_MUST_USE_RESULT;
+static grpc_error_handle pollset_kick_ext(grpc_pollset* p,
+                                          grpc_pollset_worker* specific_worker,
+                                          uint32_t flags) GRPC_MUST_USE_RESULT;
 
 /* Return 1 if the pollset has active threads in pollset_work (pollset must
  * be locked) */
@@ -394,11 +394,12 @@ static bool fd_is_orphaned(grpc_fd* fd) {
   return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
 }
 
-static grpc_error* pollset_kick_locked(grpc_fd_watcher* watcher) {
+static grpc_error_handle pollset_kick_locked(grpc_fd_watcher* watcher) {
   gpr_mu_lock(&watcher->pollset->mu);
   GPR_ASSERT(watcher->worker);
-  grpc_error* err = pollset_kick_ext(watcher->pollset, watcher->worker,
-                                     GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
+  grpc_error_handle err =
+      pollset_kick_ext(watcher->pollset, watcher->worker,
+                       GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
   gpr_mu_unlock(&watcher->pollset->mu);
   return err;
 }
@@ -484,7 +485,7 @@ static void fd_ref(grpc_fd* fd) { ref_by(fd, 2); }
 static void fd_unref(grpc_fd* fd) { unref_by(fd, 2); }
 #endif
 
-static grpc_error* fd_shutdown_error(grpc_fd* fd) {
+static grpc_error_handle fd_shutdown_error(grpc_fd* fd) {
   if (!fd->shutdown) {
     return GRPC_ERROR_NONE;
   } else {
@@ -537,7 +538,7 @@ static int set_ready_locked(grpc_fd* fd, grpc_closure** st) {
   }
 }
 
-static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
+static void fd_shutdown(grpc_fd* fd, grpc_error_handle why) {
   gpr_mu_lock(&fd->mu);
   /* only shutdown once */
   if (!fd->shutdown) {
@@ -747,7 +748,8 @@ static void push_front_worker(grpc_pollset* p, grpc_pollset_worker* worker) {
   worker->prev->next = worker->next->prev = worker;
 }
 
-static void kick_append_error(grpc_error** composite, grpc_error* error) {
+static void kick_append_error(grpc_error_handle* composite,
+                              grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) return;
   if (*composite == GRPC_ERROR_NONE) {
     *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Kick Failure");
@@ -755,11 +757,11 @@ static void kick_append_error(grpc_error** composite, grpc_error* error) {
   *composite = grpc_error_add_child(*composite, error);
 }
 
-static grpc_error* pollset_kick_ext(grpc_pollset* p,
-                                    grpc_pollset_worker* specific_worker,
-                                    uint32_t flags) {
+static grpc_error_handle pollset_kick_ext(grpc_pollset* p,
+                                          grpc_pollset_worker* specific_worker,
+                                          uint32_t flags) {
   GPR_TIMER_SCOPE("pollset_kick_ext", 0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   GRPC_STATS_INC_POLLSET_KICK();
 
   /* pollset->mu already held */
@@ -826,14 +828,14 @@ static grpc_error* pollset_kick_ext(grpc_pollset* p,
   return error;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* p,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* p,
+                                      grpc_pollset_worker* specific_worker) {
   return pollset_kick_ext(p, specific_worker, 0);
 }
 
 /* global state management */
 
-static grpc_error* pollset_global_init(void) {
+static grpc_error_handle pollset_global_init(void) {
   gpr_tls_init(&g_current_thread_poller);
   gpr_tls_init(&g_current_thread_worker);
   return GRPC_ERROR_NONE;
@@ -904,7 +906,8 @@ static void finish_shutdown(grpc_pollset* pollset) {
                           GRPC_ERROR_NONE);
 }
 
-static void work_combine_error(grpc_error** composite, grpc_error* error) {
+static void work_combine_error(grpc_error_handle* composite,
+                               grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) return;
   if (*composite == GRPC_ERROR_NONE) {
     *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("pollset_work");
@@ -912,13 +915,13 @@ static void work_combine_error(grpc_error** composite, grpc_error* error) {
   *composite = grpc_error_add_child(*composite, error);
 }
 
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker_hdl,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker_hdl,
+                                      grpc_millis deadline) {
   GPR_TIMER_SCOPE("pollset_work", 0);
   grpc_pollset_worker worker;
   if (worker_hdl) *worker_hdl = &worker;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   /* Avoid malloc for small number of elements. */
   enum { inline_elements = 96 };
@@ -1336,7 +1339,7 @@ static bool is_any_background_poller_thread(void) { return false; }
 static void shutdown_background_closure(void) {}
 
 static bool add_closure_to_background_poller(grpc_closure* /*closure*/,
-                                             grpc_error* /*error*/) {
+                                             grpc_error_handle /*error*/) {
   return false;
 }
 
index 07aeb7f..dfb250f 100644 (file)
@@ -270,7 +270,7 @@ void grpc_fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
   g_event_engine->fd_orphan(fd, on_done, release_fd, reason);
 }
 
-void grpc_fd_shutdown(grpc_fd* fd, grpc_error* why) {
+void grpc_fd_shutdown(grpc_fd* fd, grpc_error_handle why) {
   GRPC_POLLING_API_TRACE("fd_shutdown(%d)", grpc_fd_wrapped_fd(fd));
   GRPC_FD_TRACE("fd_shutdown(%d)", grpc_fd_wrapped_fd(fd));
   g_event_engine->fd_shutdown(fd, why);
@@ -315,19 +315,20 @@ static void pollset_destroy(grpc_pollset* pollset) {
   g_event_engine->pollset_destroy(pollset);
 }
 
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker,
+                                      grpc_millis deadline) {
   GRPC_POLLING_API_TRACE("pollset_work(%p, %" PRId64 ") begin", pollset,
                          deadline);
-  grpc_error* err = g_event_engine->pollset_work(pollset, worker, deadline);
+  grpc_error_handle err =
+      g_event_engine->pollset_work(pollset, worker, deadline);
   GRPC_POLLING_API_TRACE("pollset_work(%p, %" PRId64 ") end", pollset,
                          deadline);
   return err;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* pollset,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* pollset,
+                                      grpc_pollset_worker* specific_worker) {
   GRPC_POLLING_API_TRACE("pollset_kick(%p, %p)", pollset, specific_worker);
   return g_event_engine->pollset_kick(pollset, specific_worker);
 }
@@ -406,7 +407,7 @@ bool grpc_is_any_background_poller_thread(void) {
 }
 
 bool grpc_add_closure_to_background_poller(grpc_closure* closure,
-                                           grpc_error* error) {
+                                           grpc_error_handle error) {
   return g_event_engine->add_closure_to_background_poller(closure, error);
 }
 
index 84edabc..479921a 100644 (file)
@@ -52,7 +52,7 @@ typedef struct grpc_event_engine_vtable {
   int (*fd_wrapped_fd)(grpc_fd* fd);
   void (*fd_orphan)(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
                     const char* reason);
-  void (*fd_shutdown)(grpc_fd* fd, grpc_error* why);
+  void (*fd_shutdown)(grpc_fd* fd, grpc_error_handle why);
   void (*fd_notify_on_read)(grpc_fd* fd, grpc_closure* closure);
   void (*fd_notify_on_write)(grpc_fd* fd, grpc_closure* closure);
   void (*fd_notify_on_error)(grpc_fd* fd, grpc_closure* closure);
@@ -64,11 +64,11 @@ typedef struct grpc_event_engine_vtable {
   void (*pollset_init)(grpc_pollset* pollset, gpr_mu** mu);
   void (*pollset_shutdown)(grpc_pollset* pollset, grpc_closure* closure);
   void (*pollset_destroy)(grpc_pollset* pollset);
-  grpc_error* (*pollset_work)(grpc_pollset* pollset,
-                              grpc_pollset_worker** worker,
-                              grpc_millis deadline);
-  grpc_error* (*pollset_kick)(grpc_pollset* pollset,
-                              grpc_pollset_worker* specific_worker);
+  grpc_error_handle (*pollset_work)(grpc_pollset* pollset,
+                                    grpc_pollset_worker** worker,
+                                    grpc_millis deadline);
+  grpc_error_handle (*pollset_kick)(grpc_pollset* pollset,
+                                    grpc_pollset_worker* specific_worker);
   void (*pollset_add_fd)(grpc_pollset* pollset, struct grpc_fd* fd);
 
   grpc_pollset_set* (*pollset_set_create)(void);
@@ -88,7 +88,7 @@ typedef struct grpc_event_engine_vtable {
   void (*shutdown_background_closure)(void);
   void (*shutdown_engine)(void);
   bool (*add_closure_to_background_poller)(grpc_closure* closure,
-                                           grpc_error* error);
+                                           grpc_error_handle error);
 } grpc_event_engine_vtable;
 
 /* register a new event engine factory */
@@ -139,7 +139,7 @@ void grpc_fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
 bool grpc_fd_is_shutdown(grpc_fd* fd);
 
 /* Cause any current and future callbacks to fail. */
-void grpc_fd_shutdown(grpc_fd* fd, grpc_error* why);
+void grpc_fd_shutdown(grpc_fd* fd, grpc_error_handle why);
 
 /* Register read interest, causing read_cb to be called once when fd becomes
    readable, on deadline specified by deadline, or on shutdown triggered by
@@ -195,7 +195,7 @@ bool grpc_is_any_background_poller_thread();
  * that the closure may or may not run yet when this function returns, and the
  * closure should not be blocking or long-running. */
 bool grpc_add_closure_to_background_poller(grpc_closure* closure,
-                                           grpc_error* error);
+                                           grpc_error_handle error);
 
 /* Shut down all the closures registered in the background poller. */
 void grpc_shutdown_background_closure();
index a2b6e7b..54ab9fd 100644 (file)
@@ -27,7 +27,7 @@
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/profiling/timers.h"
 
-static void exec_ctx_run(grpc_closure* closure, grpc_error* error) {
+static void exec_ctx_run(grpc_closure* closure, grpc_error_handle error) {
 #ifndef NDEBUG
   closure->scheduled = false;
   if (grpc_trace_closure.enabled()) {
@@ -46,7 +46,7 @@ static void exec_ctx_run(grpc_closure* closure, grpc_error* error) {
   GRPC_ERROR_UNREF(error);
 }
 
-static void exec_ctx_sched(grpc_closure* closure, grpc_error* error) {
+static void exec_ctx_sched(grpc_closure* closure, grpc_error_handle error) {
   grpc_closure_list_append(grpc_core::ExecCtx::Get()->closure_list(), closure,
                            error);
 }
@@ -152,7 +152,7 @@ bool ExecCtx::Flush() {
       closure_list_.head = closure_list_.tail = nullptr;
       while (c != nullptr) {
         grpc_closure* next = c->next_data.next;
-        grpc_error* error = c->error_data.error;
+        grpc_error_handle error = c->error_data.error;
         did_something = true;
         exec_ctx_run(c, error);
         c = next;
@@ -174,7 +174,7 @@ grpc_millis ExecCtx::Now() {
 }
 
 void ExecCtx::Run(const DebugLocation& location, grpc_closure* closure,
-                  grpc_error* error) {
+                  grpc_error_handle error) {
   (void)location;
   if (closure == nullptr) {
     GRPC_ERROR_UNREF(error);
index c993133..9cb5257 100644 (file)
@@ -228,7 +228,7 @@ class ExecCtx {
   }
 
   static void Run(const DebugLocation& location, grpc_closure* closure,
-                  grpc_error* error);
+                  grpc_error_handle error);
 
   static void RunList(const DebugLocation& location, grpc_closure_list* list);
 
index b1d21bc..3d8d757 100644 (file)
@@ -57,27 +57,27 @@ GPR_TLS_DECL(g_this_thread_state);
 
 Executor* executors[static_cast<size_t>(ExecutorType::NUM_EXECUTORS)];
 
-void default_enqueue_short(grpc_closure* closure, grpc_error* error) {
+void default_enqueue_short(grpc_closure* closure, grpc_error_handle error) {
   executors[static_cast<size_t>(ExecutorType::DEFAULT)]->Enqueue(
       closure, error, true /* is_short */);
 }
 
-void default_enqueue_long(grpc_closure* closure, grpc_error* error) {
+void default_enqueue_long(grpc_closure* closure, grpc_error_handle error) {
   executors[static_cast<size_t>(ExecutorType::DEFAULT)]->Enqueue(
       closure, error, false /* is_short */);
 }
 
-void resolver_enqueue_short(grpc_closure* closure, grpc_error* error) {
+void resolver_enqueue_short(grpc_closure* closure, grpc_error_handle error) {
   executors[static_cast<size_t>(ExecutorType::RESOLVER)]->Enqueue(
       closure, error, true /* is_short */);
 }
 
-void resolver_enqueue_long(grpc_closure* closure, grpc_error* error) {
+void resolver_enqueue_long(grpc_closure* closure, grpc_error_handle error) {
   executors[static_cast<size_t>(ExecutorType::RESOLVER)]->Enqueue(
       closure, error, false /* is_short */);
 }
 
-using EnqueueFunc = void (*)(grpc_closure* closure, grpc_error* error);
+using EnqueueFunc = void (*)(grpc_closure* closure, grpc_error_handle error);
 
 const EnqueueFunc
     executor_enqueue_fns_[static_cast<size_t>(ExecutorType::NUM_EXECUTORS)]
@@ -115,7 +115,7 @@ size_t Executor::RunClosures(const char* executor_name,
   grpc_closure* c = list.head;
   while (c != nullptr) {
     grpc_closure* next = c->next_data.next;
-    grpc_error* error = c->error_data.error;
+    grpc_error_handle error = c->error_data.error;
 #ifndef NDEBUG
     EXECUTOR_TRACE("(%s) run %p [created by %s:%d]", executor_name, c,
                    c->file_created, c->line_created);
@@ -251,7 +251,7 @@ void Executor::ThreadMain(void* arg) {
   gpr_tls_set(&g_this_thread_state, reinterpret_cast<intptr_t>(nullptr));
 }
 
-void Executor::Enqueue(grpc_closure* closure, grpc_error* error,
+void Executor::Enqueue(grpc_closure* closure, grpc_error_handle error,
                        bool is_short) {
   bool retry_push;
   if (is_short) {
@@ -404,7 +404,7 @@ void Executor::InitAll() {
   EXECUTOR_TRACE0("Executor::InitAll() done");
 }
 
-void Executor::Run(grpc_closure* closure, grpc_error* error,
+void Executor::Run(grpc_closure* closure, grpc_error_handle error,
                    ExecutorType executor_type, ExecutorJobType job_type) {
   executor_enqueue_fns_[static_cast<size_t>(executor_type)]
                        [static_cast<size_t>(job_type)](closure, error);
index 7a5d16b..37e5c1e 100644 (file)
@@ -70,7 +70,7 @@ class Executor {
 
   /** Enqueue the closure onto the executor. is_short is true if the closure is
    * a short job (i.e expected to not block and complete quickly) */
-  void Enqueue(grpc_closure* closure, grpc_error* error, bool is_short);
+  void Enqueue(grpc_closure* closure, grpc_error_handle error, bool is_short);
 
   // TODO(sreek): Currently we have two executors (available globally): The
   // default executor and the resolver executor.
@@ -83,7 +83,7 @@ class Executor {
   // Initialize ALL the executors
   static void InitAll();
 
-  static void Run(grpc_closure* closure, grpc_error* error,
+  static void Run(grpc_closure* closure, grpc_error_handle error,
                   ExecutorType executor_type = ExecutorType::DEFAULT,
                   ExecutorJobType job_type = ExecutorJobType::SHORT);
 
index 02646db..1210bd7 100644 (file)
@@ -169,7 +169,7 @@ bool grpc_iomgr_is_any_background_poller_thread() {
 }
 
 bool grpc_iomgr_add_closure_to_background_poller(grpc_closure* closure,
-                                                 grpc_error* error) {
+                                                 grpc_error_handle error) {
   return grpc_iomgr_platform_add_closure_to_background_poller(closure, error);
 }
 
index e02f15e..9af0557 100644 (file)
@@ -52,7 +52,7 @@ bool grpc_iomgr_is_any_background_poller_thread();
  * that the closure may or may not run yet when this function returns, and the
  * closure should not be blocking or long-running. */
 bool grpc_iomgr_add_closure_to_background_poller(grpc_closure* closure,
-                                                 grpc_error* error);
+                                                 grpc_error_handle error);
 
 /* Exposed only for testing */
 size_t grpc_iomgr_count_objects_for_testing();
index 684044a..9a9f06a 100644 (file)
@@ -45,7 +45,7 @@ static bool iomgr_platform_is_any_background_poller_thread(void) {
   return false;
 }
 static bool iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* /*closure*/, grpc_error* /*error*/) {
+    grpc_closure* /*closure*/, grpc_error_handle /*error*/) {
   return false;
 }
 
index 896d9fc..e5ce8ab 100644 (file)
@@ -50,8 +50,8 @@ bool grpc_iomgr_platform_is_any_background_poller_thread() {
   return iomgr_platform_vtable->is_any_background_poller_thread();
 }
 
-bool grpc_iomgr_platform_add_closure_to_background_poller(grpc_closure* closure,
-                                                          grpc_error* error) {
+bool grpc_iomgr_platform_add_closure_to_background_poller(
+    grpc_closure* closure, grpc_error_handle error) {
   return iomgr_platform_vtable->add_closure_to_background_poller(closure,
                                                                  error);
 }
index 17607f9..01cd248 100644 (file)
@@ -38,7 +38,7 @@ typedef struct grpc_iomgr_platform_vtable {
   void (*shutdown_background_closure)(void);
   bool (*is_any_background_poller_thread)(void);
   bool (*add_closure_to_background_poller)(grpc_closure* closure,
-                                           grpc_error* error);
+                                           grpc_error_handle error);
 } grpc_iomgr_platform_vtable;
 
 void grpc_iomgr_register_object(grpc_iomgr_object* obj, const char* name);
@@ -65,8 +65,8 @@ bool grpc_iomgr_platform_is_any_background_poller_thread(void);
 /** Return true if the closure is registered into the background poller. Note
  * that the closure may or may not run yet when this function returns, and the
  * closure should not be blocking or long-running. */
-bool grpc_iomgr_platform_add_closure_to_background_poller(grpc_closure* closure,
-                                                          grpc_error* error);
+bool grpc_iomgr_platform_add_closure_to_background_poller(
+    grpc_closure* closure, grpc_error_handle error);
 
 bool grpc_iomgr_abort_on_leaks(void);
 
index 5e77881..0407e30 100644 (file)
@@ -59,7 +59,7 @@ static bool iomgr_platform_is_any_background_poller_thread(void) {
 }
 
 static bool iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* closure, grpc_error* error) {
+    grpc_closure* closure, grpc_error_handle error) {
   return grpc_add_closure_to_background_poller(closure, error);
 }
 
index 9db5e22..78b2985 100644 (file)
@@ -72,7 +72,7 @@ static bool apple_iomgr_platform_is_any_background_poller_thread(void) {
 }
 
 static bool apple_iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* closure, grpc_error* error) {
+    grpc_closure* closure, grpc_error_handle error) {
   return false;
 }
 
@@ -105,7 +105,7 @@ static bool iomgr_platform_is_any_background_poller_thread(void) {
 }
 
 static bool iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* closure, grpc_error* error) {
+    grpc_closure* closure, grpc_error_handle error) {
   return grpc_add_closure_to_background_poller(closure, error);
 }
 
index 728d404..df1207a 100644 (file)
@@ -79,7 +79,7 @@ static bool iomgr_platform_is_any_background_poller_thread(void) {
 }
 
 static bool iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* closure, grpc_error* error) {
+    grpc_closure* closure, grpc_error_handle error) {
   return false;
 }
 
index 4bed627..a187822 100644 (file)
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 
-grpc_error* grpc_load_file(const char* filename, int add_null_terminator,
-                           grpc_slice* output) {
+grpc_error_handle grpc_load_file(const char* filename, int add_null_terminator,
+                                 grpc_slice* output) {
   unsigned char* contents = nullptr;
   size_t contents_size = 0;
   grpc_slice result = grpc_empty_slice();
   FILE* file;
   size_t bytes_read = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   GRPC_SCHEDULING_START_BLOCKING_REGION;
   file = fopen(filename, "rb");
@@ -67,7 +67,7 @@ end:
   *output = result;
   if (file != nullptr) fclose(file);
   if (error != GRPC_ERROR_NONE) {
-    grpc_error* error_out =
+    grpc_error_handle error_out =
         grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                                "Failed to load file", &error, 1),
                            GRPC_ERROR_STR_FILENAME,
index d7f8175..a0206e2 100644 (file)
@@ -29,7 +29,7 @@
 
 /* Loads the content of a file into a slice. add_null_terminator will add
    a NULL terminator if non-zero. */
-grpc_error* grpc_load_file(const char* filename, int add_null_terminator,
-                           grpc_slice* output);
+grpc_error_handle grpc_load_file(const char* filename, int add_null_terminator,
+                                 grpc_slice* output);
 
 #endif /* GRPC_CORE_LIB_IOMGR_LOAD_FILE_H */
index b3fd8e0..fa21406 100644 (file)
@@ -77,7 +77,7 @@ void LockfreeEvent::DestroyEvent() {
   do {
     curr = gpr_atm_no_barrier_load(&state_);
     if (curr & kShutdownBit) {
-      GRPC_ERROR_UNREF((grpc_error*)(curr & ~kShutdownBit));
+      GRPC_ERROR_UNREF((grpc_error_handle)(curr & ~kShutdownBit));
     } else {
       GPR_ASSERT(curr == kClosureNotReady || curr == kClosureReady);
     }
@@ -139,8 +139,8 @@ void LockfreeEvent::NotifyOn(grpc_closure* closure) {
            contains a pointer to the shutdown-error). If the fd is shutdown,
            schedule the closure with the shutdown error */
         if ((curr & kShutdownBit) > 0) {
-          grpc_error* shutdown_err =
-              reinterpret_cast<grpc_error*>(curr & ~kShutdownBit);
+          grpc_error_handle shutdown_err =
+              reinterpret_cast<grpc_error_handle>(curr & ~kShutdownBit);
           ExecCtx::Run(DEBUG_LOCATION, closure,
                        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                            "FD Shutdown", &shutdown_err, 1));
@@ -159,7 +159,7 @@ void LockfreeEvent::NotifyOn(grpc_closure* closure) {
   GPR_UNREACHABLE_CODE(return );
 }
 
-bool LockfreeEvent::SetShutdown(grpc_error* shutdown_error) {
+bool LockfreeEvent::SetShutdown(grpc_error_handle shutdown_error) {
   gpr_atm new_state = reinterpret_cast<gpr_atm>(shutdown_error) | kShutdownBit;
 
   while (true) {
@@ -167,7 +167,7 @@ bool LockfreeEvent::SetShutdown(grpc_error* shutdown_error) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
       gpr_log(GPR_DEBUG,
               "LockfreeEvent::SetShutdown: %p curr=%" PRIxPTR " err=%s",
-              &state_, curr, grpc_error_string(shutdown_error));
+              &state_, curr, grpc_error_std_string(shutdown_error).c_str());
     }
     switch (curr) {
       case kClosureReady:
index f7e8554..944f364 100644 (file)
@@ -56,7 +56,7 @@ class LockfreeEvent {
 
   // Sets the shutdown state. If a closure had been provided by NotifyOn and has
   // not yet been scheduled, it will be scheduled with \a shutdown_error.
-  bool SetShutdown(grpc_error* shutdown_error);
+  bool SetShutdown(grpc_error_handle shutdown_error);
 
   // Signals that the event has been received.
   void SetReady();
diff --git a/src/core/lib/iomgr/poller/eventmanager_interface.h b/src/core/lib/iomgr/poller/eventmanager_interface.h
deleted file mode 100644 (file)
index b4fbaeb..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- * 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_IOMGR_POLLER_EVENTMANAGER_INTERFACE_H
-#define GRPC_CORE_LIB_IOMGR_POLLER_EVENTMANAGER_INTERFACE_H
-
-namespace grpc {
-namespace experimental {
-
-class BaseEventManagerInterface {
- public:
-  virtual ~BaseEventManagerInterface() {}
-};
-
-class EpollEventManagerInterface : public BaseEventManagerInterface {};
-
-}  // namespace experimental
-}  // namespace grpc
-
-#endif /* GRPC_CORE_LIB_IOMGR_POLLER_EVENTMANAGER_INTERFACE_H */
diff --git a/src/core/lib/iomgr/poller/eventmanager_libuv.cc b/src/core/lib/iomgr/poller/eventmanager_libuv.cc
deleted file mode 100644 (file)
index c34430a..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- *
- * 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/support/port_platform.h>
-
-#include "src/core/lib/iomgr/poller/eventmanager_libuv.h"
-
-#include <grpc/support/time.h>
-
-grpc::experimental::LibuvEventManager::Options::Options() : num_workers_(-1) {}
-grpc::experimental::LibuvEventManager::Options::Options(int num_workers)
-    : num_workers_(num_workers) {}
-
-grpc::experimental::LibuvEventManager::LibuvEventManager(const Options& options)
-    : options_(options) {
-  int num_workers = options_.num_workers();
-  // Number of workers can't be 0 if we do not accept thread donation.
-  // TODO(guantaol): replaces the hard-coded number with a flag.
-  if (num_workers <= 0) num_workers = 32;
-
-  for (int i = 0; i < num_workers; i++) {
-    workers_.emplace_back(
-        options_.thread_name_prefix().c_str(),
-        [](void* em) { static_cast<LibuvEventManager*>(em)->RunWorkerLoop(); },
-        this);
-    workers_.back().Start();
-  }
-}
-
-grpc::experimental::LibuvEventManager::~LibuvEventManager() {
-  Shutdown();
-  for (auto& th : workers_) {
-    th.Join();
-  }
-}
-
-void grpc::experimental::LibuvEventManager::RunWorkerLoop() {
-  while (true) {
-    // TODO(guantaol): extend the worker loop with real work.
-    if (ShouldStop()) return;
-    gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                                 gpr_time_from_micros(10, GPR_TIMESPAN)));
-  }
-}
-
-bool grpc::experimental::LibuvEventManager::ShouldStop() {
-  return should_stop_.Load(grpc_core::MemoryOrder::ACQUIRE) != 0;
-}
-
-void grpc::experimental::LibuvEventManager::Shutdown() {
-  if (should_stop_.Load(grpc_core::MemoryOrder::ACQUIRE)) {
-    return;  // Already shut down.
-  }
-
-  {
-    grpc_core::MutexLock lock(&shutdown_mu_);
-    while (shutdown_refcount_.Load(grpc_core::MemoryOrder::ACQUIRE) > 0) {
-      shutdown_cv_.Wait(&shutdown_mu_);
-    }
-  }
-  should_stop_.Store(true, grpc_core::MemoryOrder::RELEASE);
-}
-
-void grpc::experimental::LibuvEventManager::ShutdownRef() {
-  shutdown_refcount_.FetchAdd(1, grpc_core::MemoryOrder::RELAXED);
-}
-
-void grpc::experimental::LibuvEventManager::ShutdownUnref() {
-  if (shutdown_refcount_.FetchSub(1, grpc_core::MemoryOrder::ACQ_REL) == 1) {
-    grpc_core::MutexLock lock(&shutdown_mu_);
-    shutdown_cv_.Signal();
-  }
-}
diff --git a/src/core/lib/iomgr/poller/eventmanager_libuv.h b/src/core/lib/iomgr/poller/eventmanager_libuv.h
deleted file mode 100644 (file)
index 0bd0ecc..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- *
- * 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_IOMGR_POLLER_EVENTMANAGER_LIBUV_H
-#define GRPC_CORE_LIB_IOMGR_POLLER_EVENTMANAGER_LIBUV_H
-
-#include <grpc/support/port_platform.h>
-
-#include <string>
-#include <vector>
-
-#include "src/core/lib/gprpp/atomic.h"
-#include "src/core/lib/gprpp/sync.h"
-#include "src/core/lib/gprpp/thd.h"
-
-namespace grpc {
-namespace experimental {
-
-class LibuvEventManager {
- public:
-  class Options {
-   public:
-    Options();
-    explicit Options(int num_workers);
-
-    int num_workers() const { return num_workers_; }
-    void set_num_workers(int num) { num_workers_ = num; }
-
-    const std::string& thread_name_prefix() const {
-      return thread_name_prefix_;
-    }
-    void set_thread_name_prefix(const std::string& name) {
-      thread_name_prefix_ = name;
-    }
-
-   private:
-    // Number of worker threads to create at startup. If less than 0, uses the
-    // default value of 32.
-    int num_workers_;
-    // Name prefix used for worker.
-    std::string thread_name_prefix_;
-  };
-
-  explicit LibuvEventManager(const Options& options);
-  virtual ~LibuvEventManager();
-
-  void Shutdown();
-  void ShutdownRef();
-  void ShutdownUnref();
-
- private:
-  // Function run by the worker threads.
-  void RunWorkerLoop();
-
-  // Whether the EventManager has been shut down.
-  bool ShouldStop();
-
-  const Options options_;
-  // Whether the EventManager workers should be stopped.
-  grpc_core::Atomic<bool> should_stop_{false};
-  // A refcount preventing the EventManager from shutdown.
-  grpc_core::Atomic<int> shutdown_refcount_{0};
-  // Worker threads of the EventManager.
-  std::vector<grpc_core::Thread> workers_;
-  // Mutex and condition variable used for shutdown.
-  grpc_core::Mutex shutdown_mu_;
-  grpc_core::CondVar shutdown_cv_;
-};
-
-}  // namespace experimental
-}  // namespace grpc
-
-#endif /* GRPC_CORE_LIB_IOMGR_POLLER_EVENTMANAGER_LIBUV_H */
index ebfef1d..ba2a58d 100644 (file)
@@ -42,14 +42,14 @@ void grpc_pollset_destroy(grpc_pollset* pollset) {
   grpc_pollset_impl->destroy(pollset);
 }
 
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
-                              grpc_pollset_worker** worker,
-                              grpc_millis deadline) {
+grpc_error_handle grpc_pollset_work(grpc_pollset* pollset,
+                                    grpc_pollset_worker** worker,
+                                    grpc_millis deadline) {
   return grpc_pollset_impl->work(pollset, worker, deadline);
 }
 
-grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
-                              grpc_pollset_worker* specific_worker) {
+grpc_error_handle grpc_pollset_kick(grpc_pollset* pollset,
+                                    grpc_pollset_worker* specific_worker) {
   return grpc_pollset_impl->kick(pollset, specific_worker);
 }
 
index 28472b3..7c87a82 100644 (file)
@@ -44,10 +44,10 @@ typedef struct grpc_pollset_vtable {
   void (*init)(grpc_pollset* pollset, gpr_mu** mu);
   void (*shutdown)(grpc_pollset* pollset, grpc_closure* closure);
   void (*destroy)(grpc_pollset* pollset);
-  grpc_error* (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
-                      grpc_millis deadline);
-  grpc_error* (*kick)(grpc_pollset* pollset,
-                      grpc_pollset_worker* specific_worker);
+  grpc_error_handle (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
+                            grpc_millis deadline);
+  grpc_error_handle (*kick)(grpc_pollset* pollset,
+                            grpc_pollset_worker* specific_worker);
   size_t (*pollset_size)(void);
 } grpc_pollset_vtable;
 
@@ -86,14 +86,14 @@ void grpc_pollset_destroy(grpc_pollset* pollset);
    May call grpc_closure_list_run on grpc_closure_list, without holding the
    pollset
    lock */
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
-                              grpc_pollset_worker** worker,
-                              grpc_millis deadline) GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_pollset_work(grpc_pollset* pollset,
+                                    grpc_pollset_worker** worker,
+                                    grpc_millis deadline) GRPC_MUST_USE_RESULT;
 
 /* Break one polling thread out of polling work for this pollset.
    If specific_worker is non-NULL, then kick that worker. */
-grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
-                              grpc_pollset_worker* specific_worker)
+grpc_error_handle grpc_pollset_kick(grpc_pollset* pollset,
+                                    grpc_pollset_worker* specific_worker)
     GRPC_MUST_USE_RESULT;
 
 #endif /* GRPC_CORE_LIB_IOMGR_POLLSET_H */
index 98c8e64..62c4b39 100644 (file)
@@ -63,9 +63,9 @@ static void pollset_destroy(grpc_pollset* pollset) {
   gpr_mu_destroy(&pollset->mu);
 }
 
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** /*worker_hdl*/,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** /*worker_hdl*/,
+                                      grpc_millis deadline) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   gpr_mu_unlock(&pollset->mu);
   grpc_millis now = grpc_core::ExecCtx::Get()->Now();
@@ -87,8 +87,8 @@ static grpc_error* pollset_work(grpc_pollset* pollset,
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* /*pollset*/,
-                                grpc_pollset_worker* /*specific_worker*/) {
+static grpc_error_handle pollset_kick(
+    grpc_pollset* /*pollset*/, grpc_pollset_worker* /*specific_worker*/) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   poller_vtable->kick();
   return GRPC_ERROR_NONE;
index 184c330..f8758a3 100644 (file)
@@ -106,9 +106,9 @@ static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
 
 static void pollset_destroy(grpc_pollset* pollset) {}
 
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker_hdl,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker_hdl,
+                                      grpc_millis deadline) {
   grpc_pollset_worker worker;
   if (worker_hdl) *worker_hdl = &worker;
 
@@ -183,8 +183,8 @@ done:
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* p,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* p,
+                                      grpc_pollset_worker* specific_worker) {
   bool should_kick_global = false;
   if (specific_worker != NULL) {
     if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
index 2a8d67b..8d3cd98 100644 (file)
         defined(GRPC_CUSTOM_SOCKET) + defined(GRPC_CFSTREAM) != \
     1
 #error \
-    "Must define exactly one of GRPC_POSIX_SOCKET, GRPC_WINSOCK_SOCKET, GRPC_CUSTOM_SOCKET"
+    "Must define exactly one of GRPC_POSIX_SOCKET, GRPC_WINSOCK_SOCKET, GRPC_CUSTOM_SOCKET, GRPC_CFSTREAM"
 #endif
 
 #ifdef GRPC_POSIX_SOCKET
index 05d72a5..10c335b 100644 (file)
@@ -29,7 +29,7 @@
 // They are easier to define here (rather than in Cython)
 // because Cython doesn't handle #defines well.
 
-inline grpc_error* grpc_socket_error(char* error) {
+inline grpc_error_handle grpc_socket_error(char* error) {
   return grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error),
                             GRPC_ERROR_INT_GRPC_STATUS,
                             GRPC_STATUS_UNAVAILABLE);
index 7479836..83c6aac 100644 (file)
@@ -42,9 +42,9 @@ void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addresses) {
   gpr_free(addresses);
 }
 
-grpc_error* grpc_blocking_resolve_address(const char* name,
-                                          const char* default_port,
-                                          grpc_resolved_addresses** addresses) {
+grpc_error_handle grpc_blocking_resolve_address(
+    const char* name, const char* default_port,
+    grpc_resolved_addresses** addresses) {
   return grpc_resolve_address_impl->blocking_resolve_address(name, default_port,
                                                              addresses);
 }
index 025a141..112d0ac 100644 (file)
@@ -54,9 +54,9 @@ typedef struct grpc_address_resolver_vtable {
                           grpc_pollset_set* interested_parties,
                           grpc_closure* on_done,
                           grpc_resolved_addresses** addresses);
-  grpc_error* (*blocking_resolve_address)(const char* name,
-                                          const char* default_port,
-                                          grpc_resolved_addresses** addresses);
+  grpc_error_handle (*blocking_resolve_address)(
+      const char* name, const char* default_port,
+      grpc_resolved_addresses** addresses);
 } grpc_address_resolver_vtable;
 
 void grpc_set_resolver_impl(grpc_address_resolver_vtable* vtable);
@@ -74,8 +74,8 @@ void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addresses);
 
 /* Resolve addr in a blocking fashion. On success,
    result must be freed with grpc_resolved_addresses_destroy. */
-grpc_error* grpc_blocking_resolve_address(const char* name,
-                                          const char* default_port,
-                                          grpc_resolved_addresses** addresses);
+grpc_error_handle grpc_blocking_resolve_address(
+    const char* name, const char* default_port,
+    grpc_resolved_addresses** addresses);
 
 #endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H */
index 5ddd452..f89eab0 100644 (file)
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/iomgr/iomgr_custom.h"
 #include "src/core/lib/iomgr/port.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 struct grpc_custom_resolver {
   grpc_closure* on_done = nullptr;
@@ -53,7 +53,7 @@ static int retry_named_port_failure(grpc_custom_resolver* r,
     if (r->port == svc[i][0]) {
       r->port = svc[i][1];
       if (res) {
-        grpc_error* error = resolve_address_vtable->resolve(
+        grpc_error_handle error = resolve_address_vtable->resolve(
             r->host.c_str(), r->port.c_str(), res);
         if (error != GRPC_ERROR_NONE) {
           GRPC_ERROR_UNREF(error);
@@ -71,7 +71,7 @@ static int retry_named_port_failure(grpc_custom_resolver* r,
 
 void grpc_custom_resolve_callback(grpc_custom_resolver* r,
                                   grpc_resolved_addresses* result,
-                                  grpc_error* error) {
+                                  grpc_error_handle error) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
@@ -86,9 +86,10 @@ void grpc_custom_resolve_callback(grpc_custom_resolver* r,
   delete r;
 }
 
-static grpc_error* try_split_host_port(const char* name,
-                                       const char* default_port,
-                                       std::string* host, std::string* port) {
+static grpc_error_handle try_split_host_port(const char* name,
+                                             const char* default_port,
+                                             std::string* host,
+                                             std::string* port) {
   /* parse name, splitting it into host and port parts */
   grpc_core::SplitHostPort(name, host, port);
   if (host->empty()) {
@@ -106,13 +107,13 @@ static grpc_error* try_split_host_port(const char* name,
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* blocking_resolve_address_impl(
+static grpc_error_handle blocking_resolve_address_impl(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
 
   grpc_custom_resolver resolver;
-  grpc_error* err =
+  grpc_error_handle err =
       try_split_host_port(name, default_port, &resolver.host, &resolver.port);
   if (err != GRPC_ERROR_NONE) {
     return err;
@@ -144,7 +145,7 @@ static void resolve_address_impl(const char* name, const char* default_port,
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   std::string host;
   std::string port;
-  grpc_error* err = try_split_host_port(name, default_port, &host, &port);
+  grpc_error_handle err = try_split_host_port(name, default_port, &host, &port);
   if (err != GRPC_ERROR_NONE) {
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, err);
     return;
index f5f68ca..5f674dd 100644 (file)
 typedef struct grpc_custom_resolver grpc_custom_resolver;
 
 typedef struct grpc_custom_resolver_vtable {
-  grpc_error* (*resolve)(const char* host, const char* port,
-                         grpc_resolved_addresses** res);
+  grpc_error_handle (*resolve)(const char* host, const char* port,
+                               grpc_resolved_addresses** res);
   void (*resolve_async)(grpc_custom_resolver* resolver, const char* host,
                         const char* port);
 } grpc_custom_resolver_vtable;
 
 void grpc_custom_resolve_callback(grpc_custom_resolver* resolver,
                                   grpc_resolved_addresses* result,
-                                  grpc_error* error);
+                                  grpc_error_handle error);
 
 /* Internal APIs */
 void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl);
index 122dbe6..d0d1e0c 100644 (file)
@@ -42,7 +42,7 @@
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
-static grpc_error* posix_blocking_resolve_address(
+static grpc_error_handle posix_blocking_resolve_address(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   grpc_core::ExecCtx exec_ctx;
@@ -50,7 +50,7 @@ static grpc_error* posix_blocking_resolve_address(
   struct addrinfo *result = nullptr, *resp;
   int s;
   size_t i;
-  grpc_error* err;
+  grpc_error_handle err;
 
   std::string host;
   std::string port;
@@ -145,7 +145,7 @@ struct request {
 };
 /* Callback to be passed to grpc Executor to asynch-ify
  * grpc_blocking_resolve_address */
-static void do_request_thread(void* rp, grpc_error* /*error*/) {
+static void do_request_thread(void* rp, grpc_error_handle /*error*/) {
   request* r = static_cast<request*>(rp);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION, r->on_done,
index 5d2d365..926237b 100644 (file)
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 struct request {
   char* name;
@@ -54,7 +54,7 @@ struct request {
   grpc_closure* on_done;
   grpc_resolved_addresses** addresses;
 };
-static grpc_error* windows_blocking_resolve_address(
+static grpc_error_handle windows_blocking_resolve_address(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   grpc_core::ExecCtx exec_ctx;
@@ -62,7 +62,7 @@ static grpc_error* windows_blocking_resolve_address(
   struct addrinfo *result = NULL, *resp;
   int s;
   size_t i;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   /* parse name, splitting it into host and port parts */
   std::string host;
@@ -121,7 +121,7 @@ done:
 
 /* Callback to be passed to grpc_executor to asynch-ify
  * grpc_blocking_resolve_address */
-static void do_request_thread(void* rp, grpc_error* error) {
+static void do_request_thread(void* rp, grpc_error_handle error) {
   request* r = (request*)rp;
   if (error == GRPC_ERROR_NONE) {
     error =
index dcbd508..a4f4107 100644 (file)
@@ -276,7 +276,7 @@ static bool rq_reclaim_from_per_user_free_pool(
     grpc_resource_quota* resource_quota);
 static bool rq_reclaim(grpc_resource_quota* resource_quota, bool destructive);
 
-static void rq_step(void* rq, grpc_error* /*error*/) {
+static void rq_step(void* rq, grpc_error_handle /*error*/) {
   grpc_resource_quota* resource_quota = static_cast<grpc_resource_quota*>(rq);
   resource_quota->step_scheduled = false;
   do {
@@ -484,7 +484,7 @@ static grpc_slice ru_slice_create(grpc_resource_user* resource_user,
  * the combiner
  */
 
-static void ru_allocate(void* ru, grpc_error* /*error*/) {
+static void ru_allocate(void* ru, grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (rulist_empty(resource_user->resource_quota,
                    GRPC_RULIST_AWAITING_ALLOCATION)) {
@@ -493,7 +493,7 @@ static void ru_allocate(void* ru, grpc_error* /*error*/) {
   rulist_add_tail(resource_user, GRPC_RULIST_AWAITING_ALLOCATION);
 }
 
-static void ru_add_to_free_pool(void* ru, grpc_error* /*error*/) {
+static void ru_add_to_free_pool(void* ru, grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (!rulist_empty(resource_user->resource_quota,
                     GRPC_RULIST_AWAITING_ALLOCATION) &&
@@ -518,7 +518,7 @@ static bool ru_post_reclaimer(grpc_resource_user* resource_user,
   return true;
 }
 
-static void ru_post_benign_reclaimer(void* ru, grpc_error* /*error*/) {
+static void ru_post_benign_reclaimer(void* ru, grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (!ru_post_reclaimer(resource_user, false)) return;
   if (!rulist_empty(resource_user->resource_quota,
@@ -532,7 +532,8 @@ static void ru_post_benign_reclaimer(void* ru, grpc_error* /*error*/) {
   rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_BENIGN);
 }
 
-static void ru_post_destructive_reclaimer(void* ru, grpc_error* /*error*/) {
+static void ru_post_destructive_reclaimer(void* ru,
+                                          grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (!ru_post_reclaimer(resource_user, true)) return;
   if (!rulist_empty(resource_user->resource_quota,
@@ -548,7 +549,7 @@ static void ru_post_destructive_reclaimer(void* ru, grpc_error* /*error*/) {
   rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE);
 }
 
-static void ru_shutdown(void* ru, grpc_error* /*error*/) {
+static void ru_shutdown(void* ru, grpc_error_handle /*error*/) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) {
     gpr_log(GPR_INFO, "RU shutdown %p", ru);
   }
@@ -568,7 +569,7 @@ static void ru_shutdown(void* ru, grpc_error* /*error*/) {
   gpr_mu_unlock(&resource_user->mu);
 }
 
-static void ru_destroy(void* ru, grpc_error* /*error*/) {
+static void ru_destroy(void* ru, grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->refs) == 0);
   // Free all the remaining thread quota
@@ -601,7 +602,7 @@ static void ru_alloc_slices(
   }
 }
 
-static void ru_allocated_slices(void* arg, grpc_error* error) {
+static void ru_allocated_slices(void* arg, grpc_error_handle error) {
   grpc_resource_user_slice_allocator* slice_allocator =
       static_cast<grpc_resource_user_slice_allocator*>(arg);
   if (error == GRPC_ERROR_NONE) ru_alloc_slices(slice_allocator);
@@ -619,7 +620,7 @@ struct rq_resize_args {
   grpc_resource_quota* resource_quota;
   grpc_closure closure;
 };
-static void rq_resize(void* args, grpc_error* /*error*/) {
+static void rq_resize(void* args, grpc_error_handle /*error*/) {
   rq_resize_args* a = static_cast<rq_resize_args*>(args);
   int64_t delta = a->size - a->resource_quota->size;
   a->resource_quota->size += delta;
@@ -630,7 +631,7 @@ static void rq_resize(void* args, grpc_error* /*error*/) {
   gpr_free(a);
 }
 
-static void rq_reclamation_done(void* rq, grpc_error* /*error*/) {
+static void rq_reclamation_done(void* rq, grpc_error_handle /*error*/) {
   grpc_resource_quota* resource_quota = static_cast<grpc_resource_quota*>(rq);
   resource_quota->reclaiming = false;
   rq_step_sched(resource_quota);
index 45233bc..e8c9ee1 100644 (file)
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 /* set a socket to use zerocopy */
-grpc_error* grpc_set_socket_zerocopy(int fd) {
+grpc_error_handle grpc_set_socket_zerocopy(int fd) {
 #ifdef GRPC_LINUX_ERRQUEUE
   const int enable = 1;
   auto err = setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &enable, sizeof(enable));
@@ -68,7 +68,7 @@ grpc_error* grpc_set_socket_zerocopy(int fd) {
 }
 
 /* set a socket to non blocking mode */
-grpc_error* grpc_set_socket_nonblocking(int fd, int non_blocking) {
+grpc_error_handle grpc_set_socket_nonblocking(int fd, int non_blocking) {
   int oldflags = fcntl(fd, F_GETFL, 0);
   if (oldflags < 0) {
     return GRPC_OS_ERROR(errno, "fcntl");
@@ -87,7 +87,7 @@ grpc_error* grpc_set_socket_nonblocking(int fd, int non_blocking) {
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_set_socket_no_sigpipe_if_possible(int fd) {
+grpc_error_handle grpc_set_socket_no_sigpipe_if_possible(int fd) {
 #ifdef GRPC_HAVE_SO_NOSIGPIPE
   int val = 1;
   int newval;
@@ -108,7 +108,7 @@ grpc_error* grpc_set_socket_no_sigpipe_if_possible(int fd) {
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_set_socket_ip_pktinfo_if_possible(int fd) {
+grpc_error_handle grpc_set_socket_ip_pktinfo_if_possible(int fd) {
   // Use conditionally-important parameter to avoid warning
   (void)fd;
 #ifdef GRPC_HAVE_IP_PKTINFO
@@ -121,7 +121,7 @@ grpc_error* grpc_set_socket_ip_pktinfo_if_possible(int fd) {
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
+grpc_error_handle grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
   // Use conditionally-important parameter to avoid warning
   (void)fd;
 #ifdef GRPC_HAVE_IPV6_RECVPKTINFO
@@ -134,14 +134,14 @@ grpc_error* grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_set_socket_sndbuf(int fd, int buffer_size_bytes) {
+grpc_error_handle grpc_set_socket_sndbuf(int fd, int buffer_size_bytes) {
   return 0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size_bytes,
                          sizeof(buffer_size_bytes))
              ? GRPC_ERROR_NONE
              : GRPC_OS_ERROR(errno, "setsockopt(SO_SNDBUF)");
 }
 
-grpc_error* grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
+grpc_error_handle grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
   return 0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size_bytes,
                          sizeof(buffer_size_bytes))
              ? GRPC_ERROR_NONE
@@ -149,7 +149,7 @@ grpc_error* grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
 }
 
 /* set a socket to close on exec */
-grpc_error* grpc_set_socket_cloexec(int fd, int close_on_exec) {
+grpc_error_handle grpc_set_socket_cloexec(int fd, int close_on_exec) {
   int oldflags = fcntl(fd, F_GETFD, 0);
   if (oldflags < 0) {
     return GRPC_OS_ERROR(errno, "fcntl");
@@ -169,7 +169,7 @@ grpc_error* grpc_set_socket_cloexec(int fd, int close_on_exec) {
 }
 
 /* set a socket to reuse old addresses */
-grpc_error* grpc_set_socket_reuse_addr(int fd, int reuse) {
+grpc_error_handle grpc_set_socket_reuse_addr(int fd, int reuse) {
   int val = (reuse != 0);
   int newval;
   socklen_t intlen = sizeof(newval);
@@ -187,7 +187,7 @@ grpc_error* grpc_set_socket_reuse_addr(int fd, int reuse) {
 }
 
 /* set a socket to reuse old addresses */
-grpc_error* grpc_set_socket_reuse_port(int fd, int reuse) {
+grpc_error_handle grpc_set_socket_reuse_port(int fd, int reuse) {
 #ifndef SO_REUSEPORT
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "SO_REUSEPORT unavailable on compiling system");
@@ -232,7 +232,7 @@ bool grpc_is_socket_reuse_port_supported() {
 }
 
 /* disable nagle */
-grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) {
+grpc_error_handle grpc_set_socket_low_latency(int fd, int low_latency) {
   int val = (low_latency != 0);
   int newval;
   socklen_t intlen = sizeof(newval);
@@ -297,7 +297,7 @@ void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client) {
 }
 
 /* Set TCP_USER_TIMEOUT */
-grpc_error* grpc_set_socket_tcp_user_timeout(
+grpc_error_handle grpc_set_socket_tcp_user_timeout(
     int fd, const grpc_channel_args* channel_args, bool is_client) {
   // Use conditionally-important parameter to avoid warning
   (void)fd;
@@ -388,7 +388,8 @@ grpc_error* grpc_set_socket_tcp_user_timeout(
 }
 
 /* set a socket using a grpc_socket_mutator */
-grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) {
+grpc_error_handle grpc_set_socket_with_mutator(int fd,
+                                               grpc_socket_mutator* mutator) {
   GPR_ASSERT(mutator);
   if (!grpc_socket_mutator_mutate_fd(mutator, fd)) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("grpc_socket_mutator failed.");
@@ -396,8 +397,8 @@ grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) {
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_apply_socket_mutator_in_args(int fd,
-                                              const grpc_channel_args* args) {
+grpc_error_handle grpc_apply_socket_mutator_in_args(
+    int fd, const grpc_channel_args* args) {
   const grpc_arg* socket_mutator_arg =
       grpc_channel_args_find(args, GRPC_ARG_SOCKET_MUTATOR);
   if (socket_mutator_arg == nullptr) {
@@ -437,16 +438,17 @@ int grpc_ipv6_loopback_available(void) {
   return g_ipv6_loopback_available;
 }
 
-static grpc_error* error_for_fd(int fd, const grpc_resolved_address* addr) {
+static grpc_error_handle error_for_fd(int fd,
+                                      const grpc_resolved_address* addr) {
   if (fd >= 0) return GRPC_ERROR_NONE;
   std::string addr_str = grpc_sockaddr_to_string(addr, false);
-  grpc_error* err = grpc_error_set_str(
+  grpc_error_handle err = grpc_error_set_str(
       GRPC_OS_ERROR(errno, "socket"), GRPC_ERROR_STR_TARGET_ADDRESS,
       grpc_slice_from_copied_string(addr_str.c_str()));
   return err;
 }
 
-grpc_error* grpc_create_dualstack_socket(
+grpc_error_handle grpc_create_dualstack_socket(
     const grpc_resolved_address* resolved_addr, int type, int protocol,
     grpc_dualstack_mode* dsmode, int* newfd) {
   return grpc_create_dualstack_socket_using_factory(
@@ -460,7 +462,7 @@ static int create_socket(grpc_socket_factory* factory, int domain, int type,
              : socket(domain, type, protocol);
 }
 
-grpc_error* grpc_create_dualstack_socket_using_factory(
+grpc_error_handle grpc_create_dualstack_socket_using_factory(
     grpc_socket_factory* factory, const grpc_resolved_address* resolved_addr,
     int type, int protocol, grpc_dualstack_mode* dsmode, int* newfd) {
   const grpc_sockaddr* addr =
index b4dc909..13c22bc 100644 (file)
@@ -45,31 +45,31 @@ int grpc_accept4(int sockfd, grpc_resolved_address* resolved_addr, int nonblock,
                  int cloexec);
 
 /* set a socket to use zerocopy */
-grpc_error* grpc_set_socket_zerocopy(int fd);
+grpc_error_handle grpc_set_socket_zerocopy(int fd);
 
 /* set a socket to non blocking mode */
-grpc_error* grpc_set_socket_nonblocking(int fd, int non_blocking);
+grpc_error_handle grpc_set_socket_nonblocking(int fd, int non_blocking);
 
 /* set a socket to close on exec */
-grpc_error* grpc_set_socket_cloexec(int fd, int close_on_exec);
+grpc_error_handle grpc_set_socket_cloexec(int fd, int close_on_exec);
 
 /* set a socket to reuse old addresses */
-grpc_error* grpc_set_socket_reuse_addr(int fd, int reuse);
+grpc_error_handle grpc_set_socket_reuse_addr(int fd, int reuse);
 
 /* return true if SO_REUSEPORT is supported */
 bool grpc_is_socket_reuse_port_supported();
 
 /* disable nagle */
-grpc_error* grpc_set_socket_low_latency(int fd, int low_latency);
+grpc_error_handle grpc_set_socket_low_latency(int fd, int low_latency);
 
 /* set SO_REUSEPORT */
-grpc_error* grpc_set_socket_reuse_port(int fd, int reuse);
+grpc_error_handle grpc_set_socket_reuse_port(int fd, int reuse);
 
 /* Configure the default values for TCP_USER_TIMEOUT */
 void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client);
 
 /* Set TCP_USER_TIMEOUT */
-grpc_error* grpc_set_socket_tcp_user_timeout(
+grpc_error_handle grpc_set_socket_tcp_user_timeout(
     int fd, const grpc_channel_args* channel_args, bool is_client);
 
 /* Returns true if this system can create AF_INET6 sockets bound to ::1.
@@ -84,28 +84,29 @@ int grpc_ipv6_loopback_available(void);
 
 /* Tries to set SO_NOSIGPIPE if available on this platform.
    If SO_NO_SIGPIPE is not available, returns 1. */
-grpc_error* grpc_set_socket_no_sigpipe_if_possible(int fd);
+grpc_error_handle grpc_set_socket_no_sigpipe_if_possible(int fd);
 
 /* Tries to set IP_PKTINFO if available on this platform.
    If IP_PKTINFO is not available, returns 1. */
-grpc_error* grpc_set_socket_ip_pktinfo_if_possible(int fd);
+grpc_error_handle grpc_set_socket_ip_pktinfo_if_possible(int fd);
 
 /* Tries to set IPV6_RECVPKTINFO if available on this platform.
    If IPV6_RECVPKTINFO is not available, returns 1. */
-grpc_error* grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd);
+grpc_error_handle grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd);
 
 /* Tries to set the socket's send buffer to given size. */
-grpc_error* grpc_set_socket_sndbuf(int fd, int buffer_size_bytes);
+grpc_error_handle grpc_set_socket_sndbuf(int fd, int buffer_size_bytes);
 
 /* Tries to set the socket's receive buffer to given size. */
-grpc_error* grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes);
+grpc_error_handle grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes);
 
 /* Tries to set the socket using a grpc_socket_mutator */
-grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator);
+grpc_error_handle grpc_set_socket_with_mutator(int fd,
+                                               grpc_socket_mutator* mutator);
 
 /* Extracts the first socket mutator from args if any and applies on the fd. */
-grpc_error* grpc_apply_socket_mutator_in_args(int fd,
-                                              const grpc_channel_args* args);
+grpc_error_handle grpc_apply_socket_mutator_in_args(
+    int fd, const grpc_channel_args* args);
 
 /* An enum to keep track of IPv4/IPv6 socket modes.
 
@@ -149,14 +150,13 @@ int grpc_set_socket_dualstack(int fd);
      IPv4, so that bind() or connect() see the correct family.
    Also, it's important to distinguish between DUALSTACK and IPV6 when
    listening on the [::] wildcard address. */
-grpc_error* grpc_create_dualstack_socket(const grpc_resolved_address* addr,
-                                         int type, int protocol,
-                                         grpc_dualstack_mode* dsmode,
-                                         int* newfd);
+grpc_error_handle grpc_create_dualstack_socket(
+    const grpc_resolved_address* addr, int type, int protocol,
+    grpc_dualstack_mode* dsmode, int* newfd);
 
 /* Same as grpc_create_dualstack_socket(), but use the given socket factory (if
    non-null) to create the socket, rather than calling socket() directly. */
-grpc_error* grpc_create_dualstack_socket_using_factory(
+grpc_error_handle grpc_create_dualstack_socket_using_factory(
     grpc_socket_factory* factory, const grpc_resolved_address* addr, int type,
     int protocol, grpc_dualstack_mode* dsmode, int* newfd);
 
index d0be97a..5c0a95e 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <netinet/in.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/iomgr/cfstream_handle.h"
@@ -40,7 +41,6 @@
 #include "src/core/lib/iomgr/endpoint_cfstream.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/error_cfstream.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/timer.h"
 
@@ -78,7 +78,7 @@ static void CFStreamConnectCleanup(CFStreamConnect* connect) {
   delete connect;
 }
 
-static void OnAlarm(void* arg, grpc_error* error) {
+static void OnAlarm(void* arg, grpc_error_handle error) {
   CFStreamConnect* connect = static_cast<CFStreamConnect*>(arg);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT :%p OnAlarm, error:%p", connect, error);
@@ -93,13 +93,13 @@ static void OnAlarm(void* arg, grpc_error* error) {
   if (done) {
     CFStreamConnectCleanup(connect);
   } else {
-    grpc_error* error =
+    grpc_error_handle error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("connect() timed out");
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, closure, error);
   }
 }
 
-static void OnOpen(void* arg, grpc_error* error) {
+static void OnOpen(void* arg, grpc_error_handle error) {
   CFStreamConnect* connect = static_cast<CFStreamConnect*>(arg);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT :%p OnOpen, error:%p", connect, error);
index 046380c..d54a5f0 100644 (file)
@@ -25,9 +25,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/iomgr_custom.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_custom.h"
 #include "src/core/lib/iomgr/timer.h"
@@ -59,14 +59,13 @@ static void custom_tcp_connect_cleanup(grpc_custom_tcp_connect* connect) {
 
 static void custom_close_callback(grpc_custom_socket* /*socket*/) {}
 
-static void on_alarm(void* acp, grpc_error* error) {
+static void on_alarm(void* acp, grpc_error_handle error) {
   int done;
   grpc_custom_socket* socket = static_cast<grpc_custom_socket*>(acp);
   grpc_custom_tcp_connect* connect = socket->connector;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
     gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_alarm: error=%s",
-            connect->addr_name.c_str(), str);
+            connect->addr_name.c_str(), grpc_error_std_string(error).c_str());
   }
   if (error == GRPC_ERROR_NONE) {
     /* error == NONE implies that the timer ran out, and wasn't cancelled. If
@@ -81,7 +80,7 @@ static void on_alarm(void* acp, grpc_error* error) {
 }
 
 static void custom_connect_callback_internal(grpc_custom_socket* socket,
-                                             grpc_error* error) {
+                                             grpc_error_handle error) {
   grpc_custom_tcp_connect* connect = socket->connector;
   int done;
   grpc_closure* closure = connect->closure;
@@ -99,7 +98,7 @@ static void custom_connect_callback_internal(grpc_custom_socket* socket,
 }
 
 static void custom_connect_callback(grpc_custom_socket* socket,
-                                    grpc_error* error) {
+                                    grpc_error_handle error) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   if (grpc_core::ExecCtx::Get() == nullptr) {
     /* If we are being run on a thread which does not have an exec_ctx created
index 49e8854..741cc6a 100644 (file)
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/iomgr/tcp_posix.h"
@@ -64,9 +64,10 @@ struct async_connect {
   grpc_channel_args* channel_args;
 };
 
-static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd,
-                                  const grpc_channel_args* channel_args) {
-  grpc_error* err = GRPC_ERROR_NONE;
+static grpc_error_handle prepare_socket(const grpc_resolved_address* addr,
+                                        int fd,
+                                        const grpc_channel_args* channel_args) {
+  grpc_error_handle err = GRPC_ERROR_NONE;
 
   GPR_ASSERT(fd >= 0);
 
@@ -99,13 +100,12 @@ done:
   return err;
 }
 
-static void tc_on_alarm(void* acp, grpc_error* error) {
+static void tc_on_alarm(void* acp, grpc_error_handle error) {
   int done;
   async_connect* ac = static_cast<async_connect*>(acp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
     gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_alarm: error=%s",
-            ac->addr_str.c_str(), str);
+            ac->addr_str.c_str(), grpc_error_std_string(error).c_str());
   }
   gpr_mu_lock(&ac->mu);
   if (ac->fd != nullptr) {
@@ -126,7 +126,7 @@ grpc_endpoint* grpc_tcp_client_create_from_fd(
   return grpc_tcp_create(fd, channel_args, addr_str);
 }
 
-static void on_writable(void* acp, grpc_error* error) {
+static void on_writable(void* acp, grpc_error_handle error) {
   async_connect* ac = static_cast<async_connect*>(acp);
   int so_error = 0;
   socklen_t so_error_size;
@@ -139,9 +139,8 @@ static void on_writable(void* acp, grpc_error* error) {
   GRPC_ERROR_REF(error);
 
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
     gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_writable: error=%s",
-            ac->addr_str.c_str(), str);
+            ac->addr_str.c_str(), grpc_error_std_string(error).c_str());
   }
 
   gpr_mu_lock(&ac->mu);
@@ -242,12 +241,11 @@ finish:
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, closure, error);
 }
 
-grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args,
-                                       const grpc_resolved_address* addr,
-                                       grpc_resolved_address* mapped_addr,
-                                       int* fd) {
+grpc_error_handle grpc_tcp_client_prepare_fd(
+    const grpc_channel_args* channel_args, const grpc_resolved_address* addr,
+    grpc_resolved_address* mapped_addr, int* fd) {
   grpc_dualstack_mode dsmode;
-  grpc_error* error;
+  grpc_error_handle error;
   *fd = -1;
   /* Use dualstack sockets where available. Set mapped to v6 or v4 mapped to
      v6. */
@@ -293,7 +291,7 @@ void grpc_tcp_client_create_from_prepared_fd(
     return;
   }
   if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
-    grpc_error* error = GRPC_OS_ERROR(errno, "connect");
+    grpc_error_handle error = GRPC_OS_ERROR(errno, "connect");
     error = grpc_error_set_str(
         error, GRPC_ERROR_STR_TARGET_ADDRESS,
         grpc_slice_from_cpp_string(grpc_sockaddr_to_uri(addr)));
@@ -335,7 +333,7 @@ static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep,
                         grpc_millis deadline) {
   grpc_resolved_address mapped_addr;
   int fd = -1;
-  grpc_error* error;
+  grpc_error_handle error;
   *ep = nullptr;
   if ((error = grpc_tcp_client_prepare_fd(channel_args, addr, &mapped_addr,
                                           &fd)) != GRPC_ERROR_NONE) {
index 6f61866..2467f37 100644 (file)
@@ -45,10 +45,9 @@ grpc_endpoint* grpc_tcp_client_create_from_fd(
    fd: out parameter. The new FD
    Returns: error, if any. Out parameters are not set on error
 */
-grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args,
-                                       const grpc_resolved_address* addr,
-                                       grpc_resolved_address* mapped_addr,
-                                       int* fd);
+grpc_error_handle grpc_tcp_client_prepare_fd(
+    const grpc_channel_args* channel_args, const grpc_resolved_address* addr,
+    grpc_resolved_address* mapped_addr, int* fd);
 
 /* Connect a configured TCP client fd.
 
index 061e703..ef260ca 100644 (file)
 #include <grpc/support/log.h>
 #include <grpc/support/log_windows.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_windows.h"
@@ -66,7 +66,7 @@ static void async_connect_unlock_and_cleanup(async_connect* ac,
   if (socket != NULL) grpc_winsocket_destroy(socket);
 }
 
-static void on_alarm(void* acp, grpc_error* error) {
+static void on_alarm(void* acp, grpc_error_handle error) {
   async_connect* ac = (async_connect*)acp;
   gpr_mu_lock(&ac->mu);
   grpc_winsocket* socket = ac->socket;
@@ -77,7 +77,7 @@ static void on_alarm(void* acp, grpc_error* error) {
   async_connect_unlock_and_cleanup(ac, socket);
 }
 
-static void on_connect(void* acp, grpc_error* error) {
+static void on_connect(void* acp, grpc_error_handle error) {
   async_connect* ac = (async_connect*)acp;
   grpc_endpoint** ep = ac->endpoint;
   GPR_ASSERT(*ep == NULL);
@@ -137,7 +137,7 @@ static void tcp_connect(grpc_closure* on_done, grpc_endpoint** endpoint,
   GUID guid = WSAID_CONNECTEX;
   DWORD ioctl_num_bytes;
   grpc_winsocket_callback_info* info;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   async_connect* ac = NULL;
 
   *endpoint = NULL;
@@ -213,7 +213,7 @@ static void tcp_connect(grpc_closure* on_done, grpc_endpoint** endpoint,
 failure:
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   std::string target_uri = grpc_sockaddr_to_uri(addr);
-  grpc_error* final_error =
+  grpc_error_handle final_error =
       grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                              "Failed to connect", &error, 1),
                          GRPC_ERROR_STR_TARGET_ADDRESS,
index 0f45c75..c526a95 100644 (file)
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/iomgr_custom.h"
 #include "src/core/lib/iomgr/resource_quota.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_custom.h"
 #include "src/core/lib/iomgr/tcp_server.h"
@@ -122,15 +122,13 @@ static void tcp_unref(custom_tcp_endpoint* tcp) {
 static void tcp_ref(custom_tcp_endpoint* tcp) { gpr_ref(&tcp->refcount); }
 #endif
 
-static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error* error) {
+static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error_handle error) {
   grpc_closure* cb = tcp->read_cb;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "TCP:%p call_cb %p %p:%p", tcp->socket, cb, cb->cb,
             cb->cb_arg);
     size_t i;
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_INFO, "read: error=%s", str);
-
+    gpr_log(GPR_INFO, "read: error=%s", grpc_error_std_string(error).c_str());
     for (i = 0; i < tcp->read_slices->count; i++) {
       char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
                                    GPR_DUMP_HEX | GPR_DUMP_ASCII);
@@ -146,7 +144,7 @@ static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error* error) {
 }
 
 static void custom_read_callback(grpc_custom_socket* socket, size_t nread,
-                                 grpc_error* error) {
+                                 grpc_error_handle error) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
   grpc_slice_buffer garbage;
@@ -171,11 +169,11 @@ static void custom_read_callback(grpc_custom_socket* socket, size_t nread,
   call_read_cb(tcp, error);
 }
 
-static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
+static void tcp_read_allocation_done(void* tcpp, grpc_error_handle error) {
   custom_tcp_endpoint* tcp = static_cast<custom_tcp_endpoint*>(tcpp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "TCP:%p read_allocation_done: %s", tcp->socket,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   if (error == GRPC_ERROR_NONE) {
     /* Before calling read, we allocate a buffer with exactly one slice
@@ -191,8 +189,8 @@ static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
     call_read_cb(tcp, GRPC_ERROR_REF(error));
   }
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_INFO, "Initiating read on %p: error=%s", tcp->socket, str);
+    gpr_log(GPR_INFO, "Initiating read on %p: error=%s", tcp->socket,
+            grpc_error_std_string(error).c_str());
   }
 }
 
@@ -213,7 +211,7 @@ static void endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
 }
 
 static void custom_write_callback(grpc_custom_socket* socket,
-                                  grpc_error* error) {
+                                  grpc_error_handle error) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
   custom_tcp_endpoint* tcp =
@@ -221,8 +219,8 @@ static void custom_write_callback(grpc_custom_socket* socket,
   grpc_closure* cb = tcp->write_cb;
   tcp->write_cb = nullptr;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_INFO, "write complete on %p: error=%s", tcp->socket, str);
+    gpr_log(GPR_INFO, "write complete on %p: error=%s", tcp->socket,
+            grpc_error_std_string(error).c_str());
   }
   TCP_UNREF(tcp, "write");
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
@@ -287,12 +285,12 @@ static void endpoint_delete_from_pollset_set(grpc_endpoint* ep,
   (void)pollset;
 }
 
-static void endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) {
+static void endpoint_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   custom_tcp_endpoint* tcp = reinterpret_cast<custom_tcp_endpoint*>(ep);
   if (!tcp->shutting_down) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-      const char* str = grpc_error_string(why);
-      gpr_log(GPR_INFO, "TCP %p shutdown why=%s", tcp->socket, str);
+      gpr_log(GPR_INFO, "TCP %p shutdown why=%s", tcp->socket,
+              grpc_error_std_string(why).c_str());
     }
     tcp->shutting_down = true;
     // grpc_core::ExecCtx::Run(DEBUG_LOCATION,tcp->read_cb,
index d32ed2b..b342efb 100644 (file)
@@ -40,18 +40,19 @@ typedef struct grpc_custom_socket {
 } grpc_custom_socket;
 
 typedef void (*grpc_custom_connect_callback)(grpc_custom_socket* socket,
-                                             grpc_error* error);
+                                             grpc_error_handle error);
 typedef void (*grpc_custom_write_callback)(grpc_custom_socket* socket,
-                                           grpc_error* error);
+                                           grpc_error_handle error);
 typedef void (*grpc_custom_read_callback)(grpc_custom_socket* socket,
-                                          size_t nread, grpc_error* error);
+                                          size_t nread,
+                                          grpc_error_handle error);
 typedef void (*grpc_custom_accept_callback)(grpc_custom_socket* socket,
                                             grpc_custom_socket* client,
-                                            grpc_error* error);
+                                            grpc_error_handle error);
 typedef void (*grpc_custom_close_callback)(grpc_custom_socket* socket);
 
 typedef struct grpc_socket_vtable {
-  grpc_error* (*init)(grpc_custom_socket* socket, int domain);
+  grpc_error_handle (*init)(grpc_custom_socket* socket, int domain);
   void (*connect)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
                   size_t len, grpc_custom_connect_callback cb);
   void (*destroy)(grpc_custom_socket* socket);
@@ -61,13 +62,13 @@ typedef struct grpc_socket_vtable {
                 grpc_custom_write_callback cb);
   void (*read)(grpc_custom_socket* socket, char* buffer, size_t length,
                grpc_custom_read_callback cb);
-  grpc_error* (*getpeername)(grpc_custom_socket* socket,
-                             const grpc_sockaddr* addr, int* len);
-  grpc_error* (*getsockname)(grpc_custom_socket* socket,
-                             const grpc_sockaddr* addr, int* len);
-  grpc_error* (*bind)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
-                      size_t len, int flags);
-  grpc_error* (*listen)(grpc_custom_socket* socket);
+  grpc_error_handle (*getpeername)(grpc_custom_socket* socket,
+                                   const grpc_sockaddr* addr, int* len);
+  grpc_error_handle (*getsockname)(grpc_custom_socket* socket,
+                                   const grpc_sockaddr* addr, int* len);
+  grpc_error_handle (*bind)(grpc_custom_socket* socket,
+                            const grpc_sockaddr* addr, size_t len, int flags);
+  grpc_error_handle (*listen)(grpc_custom_socket* socket);
   void (*accept)(grpc_custom_socket* socket, grpc_custom_socket* client,
                  grpc_custom_accept_callback cb);
 } grpc_socket_vtable;
index a919010..1f28b77 100644 (file)
@@ -45,6 +45,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/debug/trace.h"
@@ -54,7 +55,6 @@
 #include "src/core/lib/iomgr/buffer_list.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/executor.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -435,12 +435,12 @@ static void ZerocopyDisableAndWaitForRemaining(grpc_tcp* tcp);
 static gpr_atm g_uncovered_notifications_pending;
 static gpr_atm g_backup_poller; /* backup_poller* */
 
-static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error* error);
-static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error);
+static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error_handle error);
+static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error_handle error);
 static void tcp_drop_uncovered_then_handle_write(void* arg /* grpc_tcp */,
-                                                 grpc_error* error);
+                                                 grpc_error_handle error);
 
-static void done_poller(void* bp, grpc_error* /*error_ignored*/) {
+static void done_poller(void* bp, grpc_error_handle /*error_ignored*/) {
   backup_poller* p = static_cast<backup_poller*>(bp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "BACKUP_POLLER:%p destroy", p);
@@ -449,7 +449,7 @@ static void done_poller(void* bp, grpc_error* /*error_ignored*/) {
   gpr_free(p);
 }
 
-static void run_poller(void* bp, grpc_error* /*error_ignored*/) {
+static void run_poller(void* bp, grpc_error_handle /*error_ignored*/) {
   backup_poller* p = static_cast<backup_poller*>(bp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "BACKUP_POLLER:%p run", p);
@@ -560,9 +560,11 @@ static void notify_on_write(grpc_tcp* tcp) {
   grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_done_closure);
 }
 
-static void tcp_drop_uncovered_then_handle_write(void* arg, grpc_error* error) {
+static void tcp_drop_uncovered_then_handle_write(void* arg,
+                                                 grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    gpr_log(GPR_INFO, "TCP:%p got_write: %s", arg, grpc_error_string(error));
+    gpr_log(GPR_INFO, "TCP:%p got_write: %s", arg,
+            grpc_error_std_string(error).c_str());
   }
   drop_uncovered(static_cast<grpc_tcp*>(arg));
   tcp_handle_write(arg, error);
@@ -604,7 +606,8 @@ static size_t get_target_read_size(grpc_tcp* tcp) {
   return sz;
 }
 
-static grpc_error* tcp_annotate_error(grpc_error* src_error, grpc_tcp* tcp) {
+static grpc_error_handle tcp_annotate_error(grpc_error_handle src_error,
+                                            grpc_tcp* tcp) {
   return grpc_error_set_str(
       grpc_error_set_int(
           grpc_error_set_int(src_error, GRPC_ERROR_INT_FD, tcp->fd),
@@ -615,10 +618,10 @@ static grpc_error* tcp_annotate_error(grpc_error* src_error, grpc_tcp* tcp) {
       grpc_slice_from_copied_string(tcp->peer_string.c_str()));
 }
 
-static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error* error);
-static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error);
+static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error_handle error);
+static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error_handle error);
 
-static void tcp_shutdown(grpc_endpoint* ep, grpc_error* why) {
+static void tcp_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   ZerocopyDisableAndWaitForRemaining(tcp);
   grpc_fd_shutdown(tcp->em_fd, why);
@@ -678,16 +681,14 @@ static void tcp_destroy(grpc_endpoint* ep) {
   TCP_UNREF(tcp, "destroy");
 }
 
-static void call_read_cb(grpc_tcp* tcp, grpc_error* error) {
+static void call_read_cb(grpc_tcp* tcp, grpc_error_handle error) {
   grpc_closure* cb = tcp->read_cb;
 
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "TCP:%p call_cb %p %p:%p", tcp, cb, cb->cb, cb->cb_arg);
     size_t i;
-    const char* str = grpc_error_string(error);
     gpr_log(GPR_INFO, "READ %p (peer=%s) error=%s", tcp,
-            tcp->peer_string.c_str(), str);
-
+            tcp->peer_string.c_str(), grpc_error_std_string(error).c_str());
     if (gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
       for (i = 0; i < tcp->incoming_buffer->count; i++) {
         char* dump = grpc_dump_slice(tcp->incoming_buffer->slices[i],
@@ -850,11 +851,11 @@ static void tcp_do_read(grpc_tcp* tcp) {
   TCP_UNREF(tcp, "read");
 }
 
-static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
+static void tcp_read_allocation_done(void* tcpp, grpc_error_handle error) {
   grpc_tcp* tcp = static_cast<grpc_tcp*>(tcpp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "TCP:%p read_allocation_done: %s", tcp,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
     grpc_slice_buffer_reset_and_unref_internal(tcp->incoming_buffer);
@@ -887,10 +888,11 @@ static void tcp_continue_read(grpc_tcp* tcp) {
   tcp_do_read(tcp);
 }
 
-static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error* error) {
+static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error_handle error) {
   grpc_tcp* tcp = static_cast<grpc_tcp*>(arg);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    gpr_log(GPR_INFO, "TCP:%p got_read: %s", tcp, grpc_error_string(error));
+    gpr_log(GPR_INFO, "TCP:%p got_read: %s", tcp,
+            grpc_error_std_string(error).c_str());
   }
 
   if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
@@ -958,7 +960,7 @@ static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
                                       int additional_flags = 0);
 
 /** The callback function to be invoked when we get an error on the socket. */
-static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error);
+static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error_handle error);
 
 static TcpZerocopySendRecord* tcp_get_send_zerocopy_record(
     grpc_tcp* tcp, grpc_slice_buffer* buf);
@@ -1213,10 +1215,12 @@ static bool process_errors(grpc_tcp* tcp) {
   }
 }
 
-static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) {
+static void tcp_handle_error(void* arg /* grpc_tcp */,
+                             grpc_error_handle error) {
   grpc_tcp* tcp = static_cast<grpc_tcp*>(arg);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    gpr_log(GPR_INFO, "TCP:%p got_error: %s", tcp, grpc_error_string(error));
+    gpr_log(GPR_INFO, "TCP:%p got_error: %s", tcp,
+            grpc_error_std_string(error).c_str());
   }
 
   if (error != GRPC_ERROR_NONE ||
@@ -1257,7 +1261,7 @@ static bool tcp_write_with_timestamps(grpc_tcp* /*tcp*/, struct msghdr* /*msg*/,
 }
 
 static void tcp_handle_error(void* /*arg*/ /* grpc_tcp */,
-                             grpc_error* /*error*/) {
+                             grpc_error_handle /*error*/) {
   gpr_log(GPR_ERROR, "Error handling is not supported for this platform");
   GPR_ASSERT(0);
 }
@@ -1323,7 +1327,7 @@ void TcpZerocopySendRecord::UpdateOffsetForBytesSent(size_t sending_length,
 
 // returns true if done, false if pending; if returning true, *error is set
 static bool do_tcp_flush_zerocopy(grpc_tcp* tcp, TcpZerocopySendRecord* record,
-                                  grpc_error** error) {
+                                  grpc_error_handle* error) {
   struct msghdr msg;
   struct iovec iov[MAX_WRITE_IOVEC];
   msg_iovlen_type iov_size;
@@ -1399,7 +1403,7 @@ static void UnrefMaybePutZerocopySendRecord(grpc_tcp* tcp,
 }
 
 static bool tcp_flush_zerocopy(grpc_tcp* tcp, TcpZerocopySendRecord* record,
-                               grpc_error** error) {
+                               grpc_error_handle* error) {
   bool done = do_tcp_flush_zerocopy(tcp, record, error);
   if (done) {
     // Either we encountered an error, or we successfully sent all the bytes.
@@ -1409,7 +1413,7 @@ static bool tcp_flush_zerocopy(grpc_tcp* tcp, TcpZerocopySendRecord* record,
   return done;
 }
 
-static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
+static bool tcp_flush(grpc_tcp* tcp, grpc_error_handle* error) {
   struct msghdr msg;
   struct iovec iov[MAX_WRITE_IOVEC];
   msg_iovlen_type iov_size;
@@ -1516,7 +1520,8 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
   }
 }
 
-static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error) {
+static void tcp_handle_write(void* arg /* grpc_tcp */,
+                             grpc_error_handle error) {
   grpc_tcp* tcp = static_cast<grpc_tcp*>(arg);
   grpc_closure* cb;
 
@@ -1549,8 +1554,7 @@ static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error) {
     tcp->write_cb = nullptr;
     tcp->current_zerocopy_send = nullptr;
     if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-      const char* str = grpc_error_string(error);
-      gpr_log(GPR_INFO, "write: %s", str);
+      gpr_log(GPR_INFO, "write: %s", grpc_error_std_string(error).c_str());
     }
     // No need to take a ref on error since tcp_flush provides a ref.
     grpc_core::Closure::Run(DEBUG_LOCATION, cb, error);
@@ -1562,7 +1566,7 @@ static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf,
                       grpc_closure* cb, void* arg) {
   GPR_TIMER_SCOPE("tcp_write", 0);
   grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   TcpZerocopySendRecord* zerocopy_send_record = nullptr;
 
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
@@ -1618,8 +1622,7 @@ static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf,
     notify_on_write(tcp);
   } else {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-      const char* str = grpc_error_string(error);
-      gpr_log(GPR_INFO, "write: %s", str);
+      gpr_log(GPR_INFO, "write: %s", grpc_error_std_string(error).c_str());
     }
     grpc_core::Closure::Run(DEBUG_LOCATION, cb, error);
   }
@@ -1639,7 +1642,6 @@ static void tcp_add_to_pollset_set(grpc_endpoint* ep,
 static void tcp_delete_from_pollset_set(grpc_endpoint* ep,
                                         grpc_pollset_set* pollset_set) {
   grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
-  ZerocopyDisableAndWaitForRemaining(tcp);
   grpc_pollset_set_del_fd(pollset_set, tcp->em_fd);
 }
 
index 046fd49..8d6fefb 100644 (file)
@@ -22,9 +22,9 @@
 
 grpc_tcp_server_vtable* grpc_tcp_server_impl;
 
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
-                                   const grpc_channel_args* args,
-                                   grpc_tcp_server** server) {
+grpc_error_handle grpc_tcp_server_create(grpc_closure* shutdown_complete,
+                                         const grpc_channel_args* args,
+                                         grpc_tcp_server** server) {
   return grpc_tcp_server_impl->create(shutdown_complete, args, server);
 }
 
@@ -34,9 +34,9 @@ void grpc_tcp_server_start(grpc_tcp_server* server,
   grpc_tcp_server_impl->start(server, pollsets, on_accept_cb, cb_arg);
 }
 
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     int* out_port) {
+grpc_error_handle grpc_tcp_server_add_port(grpc_tcp_server* s,
+                                           const grpc_resolved_address* addr,
+                                           int* out_port) {
   return grpc_tcp_server_impl->add_port(s, addr, out_port);
 }
 
index 6ba3513..50ac4e7 100644 (file)
@@ -63,14 +63,15 @@ class TcpServerFdHandler {
 }  // namespace grpc_core
 
 typedef struct grpc_tcp_server_vtable {
-  grpc_error* (*create)(grpc_closure* shutdown_complete,
-                        const grpc_channel_args* args,
-                        grpc_tcp_server** server);
+  grpc_error_handle (*create)(grpc_closure* shutdown_complete,
+                              const grpc_channel_args* args,
+                              grpc_tcp_server** server);
   void (*start)(grpc_tcp_server* server,
                 const std::vector<grpc_pollset*>* pollsets,
                 grpc_tcp_server_cb on_accept_cb, void* cb_arg);
-  grpc_error* (*add_port)(grpc_tcp_server* s, const grpc_resolved_address* addr,
-                          int* out_port);
+  grpc_error_handle (*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);
@@ -84,9 +85,9 @@ typedef struct grpc_tcp_server_vtable {
 /* Create a server, initially not bound to any ports. The caller owns one ref.
    If shutdown_complete is not NULL, it will be used by
    grpc_tcp_server_unref() when the ref count reaches zero. */
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
-                                   const grpc_channel_args* args,
-                                   grpc_tcp_server** server);
+grpc_error_handle grpc_tcp_server_create(grpc_closure* shutdown_complete,
+                                         const grpc_channel_args* args,
+                                         grpc_tcp_server** server);
 
 /* Start listening to bound ports */
 void grpc_tcp_server_start(grpc_tcp_server* server,
@@ -102,9 +103,9 @@ void grpc_tcp_server_start(grpc_tcp_server* server,
    but not dualstack sockets. */
 /* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle
                   all of the multiple socket port matching logic in one place */
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     int* out_port);
+grpc_error_handle 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. */
index 18d7494..fff7545 100644 (file)
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr_custom.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_custom.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 
@@ -80,9 +80,9 @@ struct grpc_tcp_server {
   grpc_resource_quota* resource_quota;
 };
 
-static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
-                                     const grpc_channel_args* args,
-                                     grpc_tcp_server** server) {
+static grpc_error_handle tcp_server_create(grpc_closure* shutdown_complete,
+                                           const grpc_channel_args* args,
+                                           grpc_tcp_server** server) {
   grpc_tcp_server* s =
       static_cast<grpc_tcp_server*>(gpr_malloc(sizeof(grpc_tcp_server)));
   // Let the implementation decide if so_reuseport can be enabled or not.
@@ -218,7 +218,7 @@ static void finish_accept(grpc_tcp_listener* sp, grpc_custom_socket* socket) {
   grpc_endpoint* ep = nullptr;
   grpc_resolved_address peer_name;
   std::string peer_name_string;
-  grpc_error* err;
+  grpc_error_handle err;
 
   memset(&peer_name, 0, sizeof(grpc_resolved_address));
   peer_name.len = GRPC_MAX_SOCKADDR_SIZE;
@@ -246,17 +246,18 @@ static void finish_accept(grpc_tcp_listener* sp, grpc_custom_socket* socket) {
 
 static void custom_accept_callback(grpc_custom_socket* socket,
                                    grpc_custom_socket* client,
-                                   grpc_error* error);
+                                   grpc_error_handle error);
 
 static void custom_accept_callback(grpc_custom_socket* socket,
                                    grpc_custom_socket* client,
-                                   grpc_error* error) {
+                                   grpc_error_handle error) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
   grpc_tcp_listener* sp = socket->listener;
   if (error != GRPC_ERROR_NONE) {
     if (!sp->closed) {
-      gpr_log(GPR_ERROR, "Accept failed: %s", grpc_error_string(error));
+      gpr_log(GPR_ERROR, "Accept failed: %s",
+              grpc_error_std_string(error).c_str());
     }
     gpr_free(client);
     GRPC_ERROR_UNREF(error);
@@ -275,14 +276,14 @@ static void custom_accept_callback(grpc_custom_socket* socket,
   }
 }
 
-static grpc_error* add_socket_to_server(grpc_tcp_server* s,
-                                        grpc_custom_socket* socket,
-                                        const grpc_resolved_address* addr,
-                                        unsigned port_index,
-                                        grpc_tcp_listener** listener) {
+static grpc_error_handle add_socket_to_server(grpc_tcp_server* s,
+                                              grpc_custom_socket* socket,
+                                              const grpc_resolved_address* addr,
+                                              unsigned port_index,
+                                              grpc_tcp_listener** listener) {
   grpc_tcp_listener* sp = nullptr;
   int port = -1;
-  grpc_error* error;
+  grpc_error_handle error;
   grpc_resolved_address sockname_temp;
 
   // NOTE(lidiz) The last argument is "flags" which is unused by other
@@ -335,9 +336,9 @@ static grpc_error* add_socket_to_server(grpc_tcp_server* s,
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
-                                       const grpc_resolved_address* addr,
-                                       int* port) {
+static grpc_error_handle tcp_server_add_port(grpc_tcp_server* s,
+                                             const grpc_resolved_address* addr,
+                                             int* port) {
   // This function is mostly copied from tcp_server_windows.c
   grpc_tcp_listener* sp = nullptr;
   grpc_custom_socket* socket;
@@ -346,7 +347,7 @@ static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
   grpc_resolved_address* allocated_addr = nullptr;
   grpc_resolved_address sockname_temp;
   unsigned port_index = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   int family;
 
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
@@ -392,7 +393,7 @@ static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "SERVER %p add_port %s error=%s", s,
             grpc_sockaddr_to_string(addr, false).c_str(),
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
 
   family = grpc_sockaddr_get_family(addr);
@@ -410,8 +411,9 @@ static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
   gpr_free(allocated_addr);
 
   if (error != GRPC_ERROR_NONE) {
-    grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-        "Failed to add port to server", &error, 1);
+    grpc_error_handle error_out =
+        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+            "Failed to add port to server", &error, 1);
     GRPC_ERROR_UNREF(error);
     error = error_out;
     *port = -1;
index d6e13e8..5662aec 100644 (file)
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.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"
 
-static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
-                                     const grpc_channel_args* args,
-                                     grpc_tcp_server** server) {
+static grpc_error_handle tcp_server_create(grpc_closure* shutdown_complete,
+                                           const grpc_channel_args* args,
+                                           grpc_tcp_server** server) {
   grpc_tcp_server* s =
       static_cast<grpc_tcp_server*>(gpr_zalloc(sizeof(grpc_tcp_server)));
   s->so_reuseport = grpc_is_socket_reuse_port_supported();
@@ -129,7 +129,7 @@ static void finish_shutdown(grpc_tcp_server* s) {
   gpr_free(s);
 }
 
-static void destroyed_port(void* server, grpc_error* /*error*/) {
+static void destroyed_port(void* server, grpc_error_handle /*error*/) {
   grpc_tcp_server* s = static_cast<grpc_tcp_server*>(server);
   gpr_mu_lock(&s->mu);
   s->destroyed_ports++;
@@ -188,7 +188,7 @@ static void tcp_server_destroy(grpc_tcp_server* s) {
 }
 
 /* event manager callback when reads are ready */
-static void on_read(void* arg, grpc_error* err) {
+static void on_read(void* arg, grpc_error_handle err) {
   grpc_tcp_listener* sp = static_cast<grpc_tcp_listener*>(arg);
   grpc_pollset* read_notifier_pollset;
   if (err != GRPC_ERROR_NONE) {
@@ -281,18 +281,18 @@ error:
 }
 
 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
-static grpc_error* add_wildcard_addrs_to_server(grpc_tcp_server* s,
-                                                unsigned port_index,
-                                                int requested_port,
-                                                int* out_port) {
+static grpc_error_handle add_wildcard_addrs_to_server(grpc_tcp_server* s,
+                                                      unsigned port_index,
+                                                      int requested_port,
+                                                      int* out_port) {
   grpc_resolved_address wild4;
   grpc_resolved_address wild6;
   unsigned fd_index = 0;
   grpc_dualstack_mode dsmode;
   grpc_tcp_listener* sp = nullptr;
   grpc_tcp_listener* sp2 = nullptr;
-  grpc_error* v6_err = GRPC_ERROR_NONE;
-  grpc_error* v4_err = GRPC_ERROR_NONE;
+  grpc_error_handle v6_err = GRPC_ERROR_NONE;
+  grpc_error_handle v4_err = GRPC_ERROR_NONE;
   *out_port = -1;
 
   if (grpc_tcp_server_have_ifaddrs() && s->expand_wildcard_addrs) {
@@ -325,19 +325,19 @@ static grpc_error* add_wildcard_addrs_to_server(grpc_tcp_server* s,
       gpr_log(GPR_INFO,
               "Failed to add :: listener, "
               "the environment may not support IPv6: %s",
-              grpc_error_string(v6_err));
+              grpc_error_std_string(v6_err).c_str());
       GRPC_ERROR_UNREF(v6_err);
     }
     if (v4_err != GRPC_ERROR_NONE) {
       gpr_log(GPR_INFO,
               "Failed to add 0.0.0.0 listener, "
               "the environment may not support IPv4: %s",
-              grpc_error_string(v4_err));
+              grpc_error_std_string(v4_err).c_str());
       GRPC_ERROR_UNREF(v4_err);
     }
     return GRPC_ERROR_NONE;
   } else {
-    grpc_error* root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+    grpc_error_handle root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Failed to add any wildcard listeners");
     GPR_ASSERT(v6_err != GRPC_ERROR_NONE && v4_err != GRPC_ERROR_NONE);
     root_err = grpc_error_add_child(root_err, v6_err);
@@ -346,10 +346,11 @@ static grpc_error* add_wildcard_addrs_to_server(grpc_tcp_server* s,
   }
 }
 
-static grpc_error* clone_port(grpc_tcp_listener* listener, unsigned count) {
+static grpc_error_handle clone_port(grpc_tcp_listener* listener,
+                                    unsigned count) {
   grpc_tcp_listener* sp = nullptr;
   std::string addr_str;
-  grpc_error* err;
+  grpc_error_handle err;
 
   for (grpc_tcp_listener* l = listener->next; l && l->is_sibling; l = l->next) {
     l->fd_index += count;
@@ -395,16 +396,16 @@ static grpc_error* clone_port(grpc_tcp_listener* listener, unsigned count) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
-                                       const grpc_resolved_address* addr,
-                                       int* out_port) {
+static grpc_error_handle tcp_server_add_port(grpc_tcp_server* s,
+                                             const grpc_resolved_address* addr,
+                                             int* out_port) {
   grpc_tcp_listener* sp;
   grpc_resolved_address sockname_temp;
   grpc_resolved_address addr6_v4mapped;
   int requested_port = grpc_sockaddr_get_port(addr);
   unsigned port_index = 0;
   grpc_dualstack_mode dsmode;
-  grpc_error* err;
+  grpc_error_handle err;
   *out_port = -1;
   if (s->tail != nullptr) {
     port_index = s->tail->port_index + 1;
index 6b8a5f9..ed4587a 100644 (file)
@@ -98,26 +98,27 @@ struct grpc_tcp_server {
 
 /* If successful, add a listener to \a s for \a addr, set \a dsmode for the
    socket, and return the \a listener. */
-grpc_error* grpc_tcp_server_add_addr(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     unsigned port_index, unsigned fd_index,
-                                     grpc_dualstack_mode* dsmode,
-                                     grpc_tcp_listener** listener);
+grpc_error_handle grpc_tcp_server_add_addr(grpc_tcp_server* s,
+                                           const grpc_resolved_address* addr,
+                                           unsigned port_index,
+                                           unsigned fd_index,
+                                           grpc_dualstack_mode* dsmode,
+                                           grpc_tcp_listener** listener);
 
 /* Get all addresses assigned to network interfaces on the machine and create a
    listener for each. requested_port is the port to use for every listener, or 0
    to select one random port that will be used for every listener. Set *out_port
    to the port selected. Return GRPC_ERROR_NONE only if all listeners were
    added. */
-grpc_error* grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
-                                                unsigned port_index,
-                                                int requested_port,
-                                                int* out_port);
+grpc_error_handle grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
+                                                      unsigned port_index,
+                                                      int requested_port,
+                                                      int* out_port);
 
 /* Prepare a recently-created socket for listening. */
-grpc_error* grpc_tcp_server_prepare_socket(grpc_tcp_server*, int fd,
-                                           const grpc_resolved_address* addr,
-                                           bool so_reuseport, int* port);
+grpc_error_handle grpc_tcp_server_prepare_socket(
+    grpc_tcp_server*, int fd, const grpc_resolved_address* addr,
+    bool so_reuseport, int* port);
 /* Ruturn true if the platform supports ifaddrs */
 bool grpc_tcp_server_have_ifaddrs(void);
 
index bd7ff9b..6fdf070 100644 (file)
@@ -37,9 +37,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
 #define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
@@ -80,14 +80,15 @@ static int get_max_accept_queue_size(void) {
   return s_max_accept_queue_size;
 }
 
-static grpc_error* add_socket_to_server(grpc_tcp_server* s, int fd,
-                                        const grpc_resolved_address* addr,
-                                        unsigned port_index, unsigned fd_index,
-                                        grpc_tcp_listener** listener) {
+static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, int fd,
+                                              const grpc_resolved_address* addr,
+                                              unsigned port_index,
+                                              unsigned fd_index,
+                                              grpc_tcp_listener** listener) {
   grpc_tcp_listener* sp = nullptr;
   int port = -1;
 
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_tcp_server_prepare_socket(s, fd, addr, s->so_reuseport, &port);
   if (err == GRPC_ERROR_NONE) {
     GPR_ASSERT(port > 0);
@@ -123,14 +124,15 @@ static grpc_error* add_socket_to_server(grpc_tcp_server* s, int fd,
 
 /* If successful, add a listener to s for addr, set *dsmode for the socket, and
    return the *listener. */
-grpc_error* grpc_tcp_server_add_addr(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     unsigned port_index, unsigned fd_index,
-                                     grpc_dualstack_mode* dsmode,
-                                     grpc_tcp_listener** listener) {
+grpc_error_handle grpc_tcp_server_add_addr(grpc_tcp_server* s,
+                                           const grpc_resolved_address* addr,
+                                           unsigned port_index,
+                                           unsigned fd_index,
+                                           grpc_dualstack_mode* dsmode,
+                                           grpc_tcp_listener** listener) {
   grpc_resolved_address addr4_copy;
   int fd;
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, dsmode, &fd);
   if (err != GRPC_ERROR_NONE) {
     return err;
@@ -143,11 +145,11 @@ grpc_error* grpc_tcp_server_add_addr(grpc_tcp_server* s,
 }
 
 /* Prepare a recently-created socket for listening. */
-grpc_error* grpc_tcp_server_prepare_socket(grpc_tcp_server* s, int fd,
-                                           const grpc_resolved_address* addr,
-                                           bool so_reuseport, int* port) {
+grpc_error_handle grpc_tcp_server_prepare_socket(
+    grpc_tcp_server* s, int fd, const grpc_resolved_address* addr,
+    bool so_reuseport, int* port) {
   grpc_resolved_address sockname_temp;
-  grpc_error* err = GRPC_ERROR_NONE;
+  grpc_error_handle err = GRPC_ERROR_NONE;
 
   GPR_ASSERT(fd >= 0);
 
@@ -210,7 +212,7 @@ error:
   if (fd >= 0) {
     close(fd);
   }
-  grpc_error* ret =
+  grpc_error_handle ret =
       grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                              "Unable to configure socket", &err, 1),
                          GRPC_ERROR_INT_FD, fd);
index d591f78..a7e8f84 100644 (file)
@@ -36,9 +36,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 /* Return the listener in s with address addr or NULL. */
 static grpc_tcp_listener* find_listener_with_addr(grpc_tcp_server* s,
@@ -58,12 +58,12 @@ static grpc_tcp_listener* find_listener_with_addr(grpc_tcp_server* s,
 }
 
 /* Bind to "::" to get a port number not used by any address. */
-static grpc_error* get_unused_port(int* port) {
+static grpc_error_handle get_unused_port(int* port) {
   grpc_resolved_address wild;
   grpc_sockaddr_make_wildcard6(0, &wild);
   grpc_dualstack_mode dsmode;
   int fd;
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd);
   if (err != GRPC_ERROR_NONE) {
     return err;
@@ -89,15 +89,15 @@ static grpc_error* get_unused_port(int* port) {
                     : GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
-                                                unsigned port_index,
-                                                int requested_port,
-                                                int* out_port) {
+grpc_error_handle grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
+                                                      unsigned port_index,
+                                                      int requested_port,
+                                                      int* out_port) {
   struct ifaddrs* ifa = nullptr;
   struct ifaddrs* ifa_it;
   unsigned fd_index = 0;
   grpc_tcp_listener* sp = nullptr;
-  grpc_error* err = GRPC_ERROR_NONE;
+  grpc_error_handle err = GRPC_ERROR_NONE;
   if (requested_port == 0) {
     /* Note: There could be a race where some local addrs can listen on the
        selected port and some can't. The sane way to handle this would be to
@@ -146,7 +146,7 @@ grpc_error* grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
     }
     if ((err = grpc_tcp_server_add_addr(s, &addr, port_index, fd_index, &dsmode,
                                         &new_sp)) != GRPC_ERROR_NONE) {
-      grpc_error* root_err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+      grpc_error_handle root_err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("Failed to add listener: ", addr_str).c_str());
       err = grpc_error_add_child(root_err, err);
       break;
index 86ee14f..a9354b0 100644 (file)
 
 #include "src/core/lib/iomgr/tcp_server_utils_posix.h"
 
-grpc_error* grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
-                                                unsigned port_index,
-                                                int requested_port,
-                                                int* out_port) {
+grpc_error_handle grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
+                                                      unsigned port_index,
+                                                      int requested_port,
+                                                      int* out_port) {
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING("no ifaddrs available");
 }
 
index c44c3a5..614ea35 100644 (file)
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/pollset_windows.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/iomgr/tcp_windows.h"
@@ -101,9 +101,9 @@ struct grpc_tcp_server {
 
 /* Public function. Allocates the proper data structures to hold a
    grpc_tcp_server. */
-static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
-                                     const grpc_channel_args* args,
-                                     grpc_tcp_server** server) {
+static grpc_error_handle tcp_server_create(grpc_closure* shutdown_complete,
+                                           const grpc_channel_args* args,
+                                           grpc_tcp_server** server) {
   grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server));
   s->channel_args = grpc_channel_args_copy(args);
   gpr_ref_init(&s->refs, 1);
@@ -120,7 +120,7 @@ static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
   return GRPC_ERROR_NONE;
 }
 
-static void destroy_server(void* arg, grpc_error* error) {
+static void destroy_server(void* arg, grpc_error_handle error) {
   grpc_tcp_server* s = (grpc_tcp_server*)arg;
 
   /* Now that the accepts have been aborted, we can destroy the sockets.
@@ -191,11 +191,11 @@ static void tcp_server_unref(grpc_tcp_server* s) {
 }
 
 /* Prepare (bind) a recently-created socket for listening. */
-static grpc_error* prepare_socket(SOCKET sock,
-                                  const grpc_resolved_address* addr,
-                                  int* port) {
+static grpc_error_handle prepare_socket(SOCKET sock,
+                                        const grpc_resolved_address* addr,
+                                        int* port) {
   grpc_resolved_address sockname_temp;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   int sockname_temp_len;
 
   error = grpc_tcp_prepare_socket(sock);
@@ -249,12 +249,12 @@ static void decrement_active_ports_and_notify_locked(grpc_tcp_listener* sp) {
 
 /* In order to do an async accept, we need to create a socket first which
    will be the one assigned to the new incoming connection. */
-static grpc_error* start_accept_locked(grpc_tcp_listener* port) {
+static grpc_error_handle start_accept_locked(grpc_tcp_listener* port) {
   SOCKET sock = INVALID_SOCKET;
   BOOL success;
   DWORD addrlen = sizeof(grpc_sockaddr_in6) + 16;
   DWORD bytes_received = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   if (port->shutting_down) {
     return GRPC_ERROR_NONE;
@@ -299,7 +299,7 @@ failure:
 }
 
 /* Event manager callback when reads are ready. */
-static void on_accept(void* arg, grpc_error* error) {
+static void on_accept(void* arg, grpc_error_handle error) {
   grpc_tcp_listener* sp = (grpc_tcp_listener*)arg;
   SOCKET sock = sp->new_socket;
   grpc_winsocket_callback_info* info = &sp->socket->read_info;
@@ -318,8 +318,8 @@ static void on_accept(void* arg, grpc_error* error) {
      this is necessary in the read/write case, it's useless for the accept
      case. We only need to adjust the pending callback count */
   if (error != GRPC_ERROR_NONE) {
-    const char* msg = grpc_error_string(error);
-    gpr_log(GPR_INFO, "Skipping on_accept due to error: %s", msg);
+    gpr_log(GPR_INFO, "Skipping on_accept due to error: %s",
+            grpc_error_std_string(error).c_str());
 
     gpr_mu_unlock(&sp->server->mu);
     return;
@@ -388,17 +388,17 @@ static void on_accept(void* arg, grpc_error* error) {
   gpr_mu_unlock(&sp->server->mu);
 }
 
-static grpc_error* add_socket_to_server(grpc_tcp_server* s, SOCKET sock,
-                                        const grpc_resolved_address* addr,
-                                        unsigned port_index,
-                                        grpc_tcp_listener** listener) {
+static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, SOCKET sock,
+                                              const grpc_resolved_address* addr,
+                                              unsigned port_index,
+                                              grpc_tcp_listener** listener) {
   grpc_tcp_listener* sp = NULL;
   int port = -1;
   int status;
   GUID guid = WSAID_ACCEPTEX;
   DWORD ioctl_num_bytes;
   LPFN_ACCEPTEX AcceptEx;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   /* We need to grab the AcceptEx pointer for that port, as it may be
      interface-dependent. We'll cache it to avoid doing that again. */
@@ -446,9 +446,9 @@ static grpc_error* add_socket_to_server(grpc_tcp_server* s, SOCKET sock,
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
-                                       const grpc_resolved_address* addr,
-                                       int* port) {
+static grpc_error_handle tcp_server_add_port(grpc_tcp_server* s,
+                                             const grpc_resolved_address* addr,
+                                             int* port) {
   grpc_tcp_listener* sp = NULL;
   SOCKET sock;
   grpc_resolved_address addr6_v4mapped;
@@ -456,7 +456,7 @@ static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
   grpc_resolved_address* allocated_addr = NULL;
   grpc_resolved_address sockname_temp;
   unsigned port_index = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   if (s->tail != NULL) {
     port_index = s->tail->port_index + 1;
@@ -508,8 +508,9 @@ done:
   gpr_free(allocated_addr);
 
   if (error != GRPC_ERROR_NONE) {
-    grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-        "Failed to add port to server", &error, 1);
+    grpc_error_handle error_out =
+        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+            "Failed to add port to server", &error, 1);
     GRPC_ERROR_UNREF(error);
     error = error_out;
     *port = -1;
index e395b14..8f64d22 100644 (file)
@@ -55,7 +55,7 @@ typedef struct uv_socket_t {
 
   int pending_connections;
   grpc_custom_socket* accept_socket;
-  grpc_error* accept_error;
+  grpc_error_handle accept_error;
 
   grpc_custom_connect_callback connect_cb;
   grpc_custom_write_callback write_cb;
@@ -65,11 +65,11 @@ typedef struct uv_socket_t {
 
 } uv_socket_t;
 
-static grpc_error* tcp_error_create(const char* desc, int status) {
+static grpc_error_handle tcp_error_create(const char* desc, int status) {
   if (status == 0) {
     return GRPC_ERROR_NONE;
   }
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc);
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc);
   /* All tcp errors are marked with UNAVAILABLE so that application may
    * choose to retry. */
   error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
@@ -95,7 +95,7 @@ static void alloc_uv_buf(uv_handle_t* handle, size_t suggested_size,
 
 static void uv_read_callback(uv_stream_t* stream, ssize_t nread,
                              const uv_buf_t* buf) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (nread == 0) {
     // Nothing happened. Wait for the next callback
     return;
@@ -126,7 +126,7 @@ static void uv_socket_read(grpc_custom_socket* socket, char* buffer,
                            size_t length, grpc_custom_read_callback read_cb) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int status;
-  grpc_error* error;
+  grpc_error_handle error;
   uv_socket->read_cb = read_cb;
   uv_socket->read_buf = buffer;
   uv_socket->read_len = length;
@@ -184,7 +184,8 @@ static void uv_socket_close(grpc_custom_socket* socket,
   uv_close((uv_handle_t*)uv_socket->handle, uv_close_callback);
 }
 
-static grpc_error* uv_socket_init_helper(uv_socket_t* uv_socket, int domain) {
+static grpc_error_handle uv_socket_init_helper(uv_socket_t* uv_socket,
+                                               int domain) {
   uv_tcp_t* tcp = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
   uv_socket->handle = tcp;
   int status = uv_tcp_init_ex(uv_default_loop(), tcp, (unsigned int)domain);
@@ -212,9 +213,10 @@ static grpc_error* uv_socket_init_helper(uv_socket_t* uv_socket, int domain) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* uv_socket_init(grpc_custom_socket* socket, int domain) {
+static grpc_error_handle uv_socket_init(grpc_custom_socket* socket,
+                                        int domain) {
   uv_socket_t* uv_socket = (uv_socket_t*)gpr_malloc(sizeof(uv_socket_t));
-  grpc_error* error = uv_socket_init_helper(uv_socket, domain);
+  grpc_error_handle error = uv_socket_init_helper(uv_socket, domain);
   if (error != GRPC_ERROR_NONE) {
     return error;
   }
@@ -223,18 +225,18 @@ static grpc_error* uv_socket_init(grpc_custom_socket* socket, int domain) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* uv_socket_getpeername(grpc_custom_socket* socket,
-                                         const grpc_sockaddr* addr,
-                                         int* addr_len) {
+static grpc_error_handle uv_socket_getpeername(grpc_custom_socket* socket,
+                                               const grpc_sockaddr* addr,
+                                               int* addr_len) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int err = uv_tcp_getpeername(uv_socket->handle,
                                (struct sockaddr*)IGNORE_CONST(addr), addr_len);
   return tcp_error_create("getpeername failed", err);
 }
 
-static grpc_error* uv_socket_getsockname(grpc_custom_socket* socket,
-                                         const grpc_sockaddr* addr,
-                                         int* addr_len) {
+static grpc_error_handle uv_socket_getsockname(grpc_custom_socket* socket,
+                                               const grpc_sockaddr* addr,
+                                               int* addr_len) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int err = uv_tcp_getsockname(uv_socket->handle,
                                (struct sockaddr*)IGNORE_CONST(addr), addr_len);
@@ -247,7 +249,7 @@ static void accept_new_connection(grpc_custom_socket* socket) {
     return;
   }
   grpc_custom_socket* new_socket = uv_socket->accept_socket;
-  grpc_error* error = uv_socket->accept_error;
+  grpc_error_handle error = uv_socket->accept_error;
   uv_socket->accept_socket = nullptr;
   uv_socket->accept_error = GRPC_ERROR_NONE;
   uv_socket->pending_connections -= 1;
@@ -293,16 +295,16 @@ void uv_socket_accept(grpc_custom_socket* socket,
   accept_new_connection(socket);
 }
 
-static grpc_error* uv_socket_bind(grpc_custom_socket* socket,
-                                  const grpc_sockaddr* addr, size_t len,
-                                  int flags) {
+static grpc_error_handle uv_socket_bind(grpc_custom_socket* socket,
+                                        const grpc_sockaddr* addr, size_t len,
+                                        int flags) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int status =
       uv_tcp_bind((uv_tcp_t*)uv_socket->handle, (struct sockaddr*)addr, 0);
   return tcp_error_create("Failed to bind to port", status);
 }
 
-static grpc_error* uv_socket_listen(grpc_custom_socket* socket) {
+static grpc_error_handle uv_socket_listen(grpc_custom_socket* socket) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int status =
       uv_listen((uv_stream_t*)uv_socket->handle, SOMAXCONN, uv_on_connect);
@@ -312,7 +314,7 @@ static grpc_error* uv_socket_listen(grpc_custom_socket* socket) {
 static void uv_tc_on_connect(uv_connect_t* req, int status) {
   grpc_custom_socket* socket = (grpc_custom_socket*)req->data;
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
-  grpc_error* error;
+  grpc_error_handle error;
   if (status == UV_ECANCELED) {
     // This should only happen if the handle is already closed
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timeout occurred");
@@ -370,8 +372,8 @@ static void uv_resolve_callback(uv_getaddrinfo_t* req, int status,
                                tcp_error_create("getaddrinfo failed", status));
 }
 
-static grpc_error* uv_resolve(const char* host, const char* port,
-                              grpc_resolved_addresses** result) {
+static grpc_error_handle uv_resolve(const char* host, const char* port,
+                                    grpc_resolved_addresses** result) {
   int status;
   uv_getaddrinfo_t req;
   struct addrinfo hints;
@@ -403,7 +405,7 @@ static void uv_resolve_async(grpc_custom_resolver* r, const char* host,
                           port, &hints);
   if (status != 0) {
     gpr_free(req);
-    grpc_error* error = tcp_error_create("getaddrinfo failed", status);
+    grpc_error_handle error = tcp_error_create("getaddrinfo failed", status);
     grpc_custom_resolve_callback(r, NULL, error);
   }
 }
index d28a54c..aa693cc 100644 (file)
 #include <grpc/support/log_windows.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_windows.h"
@@ -53,7 +53,7 @@
 
 extern grpc_core::TraceFlag grpc_tcp_trace;
 
-grpc_error* grpc_tcp_set_non_block(SOCKET sock) {
+grpc_error_handle grpc_tcp_set_non_block(SOCKET sock) {
   int status;
   uint32_t param = 1;
   DWORD ret;
@@ -64,7 +64,7 @@ grpc_error* grpc_tcp_set_non_block(SOCKET sock) {
              : GRPC_WSA_ERROR(WSAGetLastError(), "WSAIoctl(GRPC_FIONBIO)");
 }
 
-static grpc_error* set_dualstack(SOCKET sock) {
+static grpc_error_handle set_dualstack(SOCKET sock) {
   int status;
   unsigned long param = 0;
   status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&param,
@@ -74,7 +74,7 @@ static grpc_error* set_dualstack(SOCKET sock) {
              : GRPC_WSA_ERROR(WSAGetLastError(), "setsockopt(IPV6_V6ONLY)");
 }
 
-static grpc_error* enable_socket_low_latency(SOCKET sock) {
+static grpc_error_handle enable_socket_low_latency(SOCKET sock) {
   int status;
   BOOL param = TRUE;
   status = ::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
@@ -86,8 +86,8 @@ static grpc_error* enable_socket_low_latency(SOCKET sock) {
                      : GRPC_WSA_ERROR(status, "setsockopt(TCP_NODELAY)");
 }
 
-grpc_error* grpc_tcp_prepare_socket(SOCKET sock) {
-  grpc_error* err;
+grpc_error_handle grpc_tcp_prepare_socket(SOCKET sock) {
+  grpc_error_handle err;
   err = grpc_tcp_set_non_block(sock);
   if (err != GRPC_ERROR_NONE) return err;
   err = set_dualstack(sock);
@@ -123,7 +123,7 @@ typedef struct grpc_tcp {
      to protect ourselves when requesting a shutdown. */
   gpr_mu mu;
   int shutting_down;
-  grpc_error* shutdown_error;
+  grpc_error_handle shutdown_error;
 
   std::string peer_string;
   std::string local_address;
@@ -177,7 +177,7 @@ static void tcp_ref(grpc_tcp* tcp) { gpr_ref(&tcp->refcount); }
 #endif
 
 /* Asynchronous callback from the IOCP, or the background thread. */
-static void on_read(void* tcpp, grpc_error* error) {
+static void on_read(void* tcpp, grpc_error_handle error) {
   grpc_tcp* tcp = (grpc_tcp*)tcpp;
   grpc_closure* cb = tcp->read_cb;
   grpc_winsocket* socket = tcp->socket;
@@ -313,7 +313,7 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
 }
 
 /* Asynchronous callback from the IOCP, or the background thread. */
-static void on_write(void* tcpp, grpc_error* error) {
+static void on_write(void* tcpp, grpc_error_handle error) {
   grpc_tcp* tcp = (grpc_tcp*)tcpp;
   grpc_winsocket* handle = tcp->socket;
   grpc_winsocket_callback_info* info = &handle->write_info;
@@ -399,9 +399,9 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
      connection that has its send queue filled up. But if we don't, then we can
      avoid doing an async write operation at all. */
   if (info->wsa_error != WSAEWOULDBLOCK) {
-    grpc_error* error = status == 0
-                            ? GRPC_ERROR_NONE
-                            : GRPC_WSA_ERROR(info->wsa_error, "WSASend");
+    grpc_error_handle error = status == 0
+                                  ? GRPC_ERROR_NONE
+                                  : GRPC_WSA_ERROR(info->wsa_error, "WSASend");
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
     if (allocated) gpr_free(allocated);
     return;
@@ -454,7 +454,7 @@ static void win_delete_from_pollset_set(grpc_endpoint* ep,
    we're not going to protect against these. However the IO Completion Port
    callback will happen from another thread, so we need to protect against
    concurrent access of the data structure in that regard. */
-static void win_shutdown(grpc_endpoint* ep, grpc_error* why) {
+static void win_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   grpc_tcp* tcp = (grpc_tcp*)ep;
   gpr_mu_lock(&tcp->mu);
   /* At that point, what may happen is that we're already inside the IOCP
index 04ef810..de3dc55 100644 (file)
@@ -44,9 +44,9 @@ grpc_endpoint* grpc_tcp_create(grpc_winsocket* socket,
                                grpc_channel_args* channel_args,
                                const char* peer_string);
 
-grpc_error* grpc_tcp_prepare_socket(SOCKET sock);
+grpc_error_handle grpc_tcp_prepare_socket(SOCKET sock);
 
-grpc_error* grpc_tcp_set_non_block(SOCKET sock);
+grpc_error_handle grpc_tcp_set_non_block(SOCKET sock);
 
 #endif
 
index 867359a..cb01b7c 100644 (file)
@@ -30,7 +30,8 @@
 
 static grpc_custom_timer_vtable* custom_timer_impl;
 
-void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* /*error*/) {
+void grpc_custom_timer_callback(grpc_custom_timer* t,
+                                grpc_error_handle /*error*/) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
index bfea8ba..83c3e8d 100644 (file)
@@ -38,6 +38,6 @@ typedef struct grpc_custom_timer_vtable {
 
 void grpc_custom_timer_init(grpc_custom_timer_vtable* impl);
 
-void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error);
+void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error_handle error);
 
 #endif /* GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H */
index c4e961a..3d2fc00 100644 (file)
@@ -247,7 +247,7 @@ static grpc_millis saturating_add(grpc_millis a, grpc_millis b) {
 
 static grpc_timer_check_result run_some_expired_timers(grpc_millis now,
                                                        grpc_millis* next,
-                                                       grpc_error* error);
+                                                       grpc_error_handle error);
 
 static grpc_millis compute_min_deadline(timer_shard* shard) {
   return grpc_timer_heap_is_empty(&shard->heap)
@@ -561,7 +561,8 @@ static grpc_timer* pop_one(timer_shard* shard, grpc_millis now) {
 
 /* REQUIRES: shard->mu unlocked */
 static size_t pop_timers(timer_shard* shard, grpc_millis now,
-                         grpc_millis* new_min_deadline, grpc_error* error) {
+                         grpc_millis* new_min_deadline,
+                         grpc_error_handle error) {
   size_t n = 0;
   grpc_timer* timer;
   gpr_mu_lock(&shard->mu);
@@ -580,9 +581,8 @@ static size_t pop_timers(timer_shard* shard, grpc_millis now,
   return n;
 }
 
-static grpc_timer_check_result run_some_expired_timers(grpc_millis now,
-                                                       grpc_millis* next,
-                                                       grpc_error* error) {
+static grpc_timer_check_result run_some_expired_timers(
+    grpc_millis now, grpc_millis* next, grpc_error_handle error) {
   grpc_timer_check_result result = GRPC_TIMERS_NOT_CHECKED;
 
 #if GPR_ARCH_64
@@ -702,7 +702,7 @@ static grpc_timer_check_result timer_check(grpc_millis* next) {
     return GRPC_TIMERS_CHECKED_AND_EMPTY;
   }
 
-  grpc_error* shutdown_error =
+  grpc_error_handle shutdown_error =
       now != GRPC_MILLIS_INF_FUTURE
           ? GRPC_ERROR_NONE
           : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system");
index c2eacc5..4efaf23 100644 (file)
@@ -56,6 +56,8 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
+
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
@@ -64,7 +66,6 @@
 #include "src/core/lib/iomgr/executor.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_factory_posix.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
@@ -83,11 +84,11 @@ class GrpcUdpListener {
 
   /* Called when data is available to read from the socket.
    * Return true if there is more data to read from fd. */
-  void OnRead(grpc_error* error, void* do_read_arg);
+  void OnRead(grpc_error_handle error, void* do_read_arg);
 
   /* Called when the socket is writeable. The given closure should be scheduled
    * when the socket becomes blocked next time. */
-  void OnCanWrite(grpc_error* error, void* do_write_arg);
+  void OnCanWrite(grpc_error_handle error, void* do_write_arg);
 
   /* Called when the grpc_fd is about to be orphaned (and the FD closed). */
   void OnFdAboutToOrphan();
@@ -107,16 +108,16 @@ class GrpcUdpListener {
 
  private:
   /* event manager callback when reads are ready */
-  static void on_read(void* arg, grpc_error* error);
-  static void on_write(void* arg, grpc_error* error);
+  static void on_read(void* arg, grpc_error_handle error);
+  static void on_write(void* arg, grpc_error_handle error);
 
-  static void do_read(void* arg, grpc_error* error);
-  static void do_write(void* arg, grpc_error* error);
+  static void do_read(void* arg, grpc_error_handle error);
+  static void do_write(void* arg, grpc_error_handle error);
   // Wrapper of grpc_fd_notify_on_write() with a grpc_closure callback
   // interface.
-  static void fd_notify_on_write_wrapper(void* arg, grpc_error* error);
+  static void fd_notify_on_write_wrapper(void* arg, grpc_error_handle error);
 
-  static void shutdown_fd(void* args, grpc_error* error);
+  static void shutdown_fd(void* args, grpc_error_handle error);
 
   int fd_;
   grpc_fd* emfd_;
@@ -222,7 +223,7 @@ grpc_udp_server* grpc_udp_server_create(const grpc_channel_args* args) {
 }
 
 // static
-void GrpcUdpListener::shutdown_fd(void* args, grpc_error* error) {
+void GrpcUdpListener::shutdown_fd(void* args, grpc_error_handle error) {
   if (args == nullptr) {
     // No-op if shutdown args are null.
     return;
@@ -261,7 +262,7 @@ static void finish_shutdown(grpc_udp_server* s) {
   delete s;
 }
 
-static void destroyed_port(void* server, grpc_error* /*error*/) {
+static void destroyed_port(void* server, grpc_error_handle /*error*/) {
   grpc_udp_server* s = static_cast<grpc_udp_server*>(server);
   gpr_mu_lock(&s->mu);
   s->destroyed_ports++;
@@ -436,7 +437,7 @@ error:
 }
 
 // static
-void GrpcUdpListener::do_read(void* arg, grpc_error* error) {
+void GrpcUdpListener::do_read(void* arg, grpc_error_handle error) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   /* TODO: the reason we hold server->mu here is merely to prevent fd
@@ -460,12 +461,12 @@ void GrpcUdpListener::do_read(void* arg, grpc_error* error) {
 }
 
 // static
-void GrpcUdpListener::on_read(void* arg, grpc_error* error) {
+void GrpcUdpListener::on_read(void* arg, grpc_error_handle error) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   sp->OnRead(error, arg);
 }
 
-void GrpcUdpListener::OnRead(grpc_error* error, void* do_read_arg) {
+void GrpcUdpListener::OnRead(grpc_error_handle error, void* do_read_arg) {
   if (error != GRPC_ERROR_NONE) {
     gpr_mu_lock(&server_->mu);
     if (0 == --server_->active_ports && server_->shutdown) {
@@ -497,7 +498,7 @@ void GrpcUdpListener::OnRead(grpc_error* error, void* do_read_arg) {
 // static
 // Wrapper of grpc_fd_notify_on_write() with a grpc_closure callback interface.
 void GrpcUdpListener::fd_notify_on_write_wrapper(void* arg,
-                                                 grpc_error* /*error*/) {
+                                                 grpc_error_handle /*error*/) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   gpr_mu_lock(sp->mutex());
   if (!sp->notify_on_write_armed_) {
@@ -508,7 +509,7 @@ void GrpcUdpListener::fd_notify_on_write_wrapper(void* arg,
 }
 
 // static
-void GrpcUdpListener::do_write(void* arg, grpc_error* error) {
+void GrpcUdpListener::do_write(void* arg, grpc_error_handle error) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   gpr_mu_lock(sp->mutex());
   if (sp->already_shutdown_) {
@@ -527,12 +528,12 @@ void GrpcUdpListener::do_write(void* arg, grpc_error* error) {
 }
 
 // static
-void GrpcUdpListener::on_write(void* arg, grpc_error* error) {
+void GrpcUdpListener::on_write(void* arg, grpc_error_handle error) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   sp->OnCanWrite(error, arg);
 }
 
-void GrpcUdpListener::OnCanWrite(grpc_error* error, void* do_write_arg) {
+void GrpcUdpListener::OnCanWrite(grpc_error_handle error, void* do_write_arg) {
   if (error != GRPC_ERROR_NONE) {
     gpr_mu_lock(&server_->mu);
     if (0 == --server_->active_ports && server_->shutdown) {
@@ -630,7 +631,7 @@ int grpc_udp_server_add_port(grpc_udp_server* s, grpc_resolved_address* addr,
 
       /* Try listening on IPv6 first. */
       addr = &wild6;
-      // TODO(rjshade): Test and propagate the returned grpc_error*:
+      // TODO(rjshade): Test and propagate the returned grpc_error_handle:
       GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory(
           s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd));
       allocated_port1 =
@@ -666,7 +667,7 @@ int grpc_udp_server_add_port(grpc_udp_server* s, grpc_resolved_address* addr,
       addr = &wild4;
     }
 
-    // TODO(rjshade): Test and propagate the returned grpc_error*:
+    // TODO(rjshade): Test and propagate the returned grpc_error_handle:
     GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory(
         s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd));
     if (fd < 0) {
index 034aa91..2b077a3 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "absl/strings/str_cat.h"
 
-#include "src/core/lib/iomgr/parse_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
 #include <grpc/support/alloc.h>
@@ -42,7 +42,7 @@ void grpc_create_socketpair_if_unix(int sv[2]) {
   GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
 }
 
-grpc_error* grpc_resolve_unix_domain_address(
+grpc_error_handle grpc_resolve_unix_domain_address(
     const char* name, grpc_resolved_addresses** addresses) {
   *addresses = static_cast<grpc_resolved_addresses*>(
       gpr_malloc(sizeof(grpc_resolved_addresses)));
@@ -52,7 +52,7 @@ grpc_error* grpc_resolve_unix_domain_address(
   return grpc_core::UnixSockaddrPopulate(name, (*addresses)->addrs);
 }
 
-grpc_error* grpc_resolve_unix_abstract_domain_address(
+grpc_error_handle grpc_resolve_unix_abstract_domain_address(
     const absl::string_view name, grpc_resolved_addresses** addresses) {
   *addresses = static_cast<grpc_resolved_addresses*>(
       gpr_malloc(sizeof(grpc_resolved_addresses)));
index 302ac17..c35423b 100644 (file)
 
 void grpc_create_socketpair_if_unix(int sv[2]);
 
-grpc_error* grpc_resolve_unix_domain_address(
+grpc_error_handle grpc_resolve_unix_domain_address(
     const char* name, grpc_resolved_addresses** addresses);
 
-grpc_error* grpc_resolve_unix_abstract_domain_address(
+grpc_error_handle grpc_resolve_unix_abstract_domain_address(
     absl::string_view name, grpc_resolved_addresses** addresses);
 
 int grpc_is_unix_socket(const grpc_resolved_address* resolved_addr);
index 7205797..c265922 100644 (file)
 
 #include <grpc/support/log.h>
 
-void grpc_create_socketpair_if_unix(int sv[2]) {
+void grpc_create_socketpair_if_unix(int /* sv */[2]) {
   // TODO: Either implement this for the non-Unix socket case or make
   // sure that it is never called in any such case. Until then, leave an
   // assertion to notify if this gets called inadvertently
   GPR_ASSERT(0);
 }
 
-grpc_error* grpc_resolve_unix_domain_address(
-    const char* name, grpc_resolved_addresses** addresses) {
+grpc_error_handle grpc_resolve_unix_domain_address(
+    const char* /* name */, grpc_resolved_addresses** addresses) {
   *addresses = NULL;
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Unix domain sockets are not supported on Windows");
 }
 
-grpc_error* grpc_resolve_unix_abstract_domain_address(
+grpc_error_handle grpc_resolve_unix_abstract_domain_address(
     absl::string_view, grpc_resolved_addresses** addresses) {
   *addresses = NULL;
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Unix domain sockets are not supported on Windows");
 }
 
-int grpc_is_unix_socket(const grpc_resolved_address* addr) { return false; }
+int grpc_is_unix_socket(const grpc_resolved_address* /* addr */) {
+  return false;
+}
 
-void grpc_unlink_if_unix_domain_socket(const grpc_resolved_address* addr) {}
+void grpc_unlink_if_unix_domain_socket(
+    const grpc_resolved_address* /* addr */) {}
 
 std::string grpc_sockaddr_to_uri_unix_if_possible(
-    const grpc_resolved_address* addr) {
+    const grpc_resolved_address* /* addr */) {
   return "";
 }
 
index d68c9ad..3951fe6 100644 (file)
@@ -31,7 +31,7 @@
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/profiling/timers.h"
 
-static grpc_error* eventfd_create(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle eventfd_create(grpc_wakeup_fd* fd_info) {
   fd_info->read_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
   fd_info->write_fd = -1;
   if (fd_info->read_fd < 0) {
@@ -40,7 +40,7 @@ static grpc_error* eventfd_create(grpc_wakeup_fd* fd_info) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* eventfd_consume(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle eventfd_consume(grpc_wakeup_fd* fd_info) {
   eventfd_t value;
   int err;
   do {
@@ -52,7 +52,7 @@ static grpc_error* eventfd_consume(grpc_wakeup_fd* fd_info) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* eventfd_wakeup(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle eventfd_wakeup(grpc_wakeup_fd* fd_info) {
   GPR_TIMER_SCOPE("eventfd_wakeup", 0);
   int err;
   do {
index 797cd44..943d9d5 100644 (file)
 
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 
-static grpc_error* pipe_init(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle pipe_init(grpc_wakeup_fd* fd_info) {
   int pipefd[2];
   int r = pipe(pipefd);
   if (0 != r) {
     gpr_log(GPR_ERROR, "pipe creation failed (%d): %s", errno, strerror(errno));
     return GRPC_OS_ERROR(errno, "pipe");
   }
-  grpc_error* err;
+  grpc_error_handle err;
   err = grpc_set_socket_nonblocking(pipefd[0], 1);
   if (err != GRPC_ERROR_NONE) return err;
   err = grpc_set_socket_nonblocking(pipefd[1], 1);
@@ -50,7 +50,7 @@ static grpc_error* pipe_init(grpc_wakeup_fd* fd_info) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pipe_consume(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle pipe_consume(grpc_wakeup_fd* fd_info) {
   char buf[128];
   ssize_t r;
 
@@ -69,7 +69,7 @@ static grpc_error* pipe_consume(grpc_wakeup_fd* fd_info) {
   }
 }
 
-static grpc_error* pipe_wakeup(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle pipe_wakeup(grpc_wakeup_fd* fd_info) {
   char c = 0;
   while (write(fd_info->write_fd, &c, 1) != 1 && errno == EINTR) {
   }
index 3b66d6f..36b497b 100644 (file)
@@ -50,15 +50,15 @@ void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = nullptr; }
 
 int grpc_has_wakeup_fd(void) { return has_real_wakeup_fd; }
 
-grpc_error* grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info) {
+grpc_error_handle grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info) {
   return wakeup_fd_vtable->init(fd_info);
 }
 
-grpc_error* grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info) {
+grpc_error_handle grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info) {
   return wakeup_fd_vtable->consume(fd_info);
 }
 
-grpc_error* grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info) {
+grpc_error_handle grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info) {
   return wakeup_fd_vtable->wakeup(fd_info);
 }
 
index 670c319..1079ce6 100644 (file)
@@ -65,9 +65,9 @@ void grpc_enable_cv_wakeup_fds(int enable);
 typedef struct grpc_wakeup_fd grpc_wakeup_fd;
 
 typedef struct grpc_wakeup_fd_vtable {
-  grpc_error* (*init)(grpc_wakeup_fd* fd_info);
-  grpc_error* (*consume)(grpc_wakeup_fd* fd_info);
-  grpc_error* (*wakeup)(grpc_wakeup_fd* fd_info);
+  grpc_error_handle (*init)(grpc_wakeup_fd* fd_info);
+  grpc_error_handle (*consume)(grpc_wakeup_fd* fd_info);
+  grpc_error_handle (*wakeup)(grpc_wakeup_fd* fd_info);
   void (*destroy)(grpc_wakeup_fd* fd_info);
   /* Must be called before calling any other functions */
   int (*check_availability)(void);
@@ -83,10 +83,12 @@ extern int grpc_allow_pipe_wakeup_fd;
 
 #define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd)
 
-grpc_error* grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info) GRPC_MUST_USE_RESULT;
-grpc_error* grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info)
+grpc_error_handle grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info)
+    GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info)
+    GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info)
     GRPC_MUST_USE_RESULT;
-grpc_error* grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info) GRPC_MUST_USE_RESULT;
 void grpc_wakeup_fd_destroy(grpc_wakeup_fd* fd_info);
 
 /* Defined in some specialized implementation's .c file, or by
index 169562d..547b80c 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <functional>
 
+#include "absl/synchronization/mutex.h"
+
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/atomic.h"
 #include "src/core/lib/gprpp/debug_location.h"
@@ -43,12 +45,26 @@ namespace grpc_core {
 // other callbacks from other threads might also be executed before Run()
 // returns. Since an arbitrary set of callbacks might be executed when Run() is
 // called, generally no locks should be held while calling Run().
-class WorkSerializer {
+class ABSL_LOCKABLE WorkSerializer {
  public:
   WorkSerializer();
 
   ~WorkSerializer();
 
+  // Runs a given callback.
+  //
+  // If you want to use clang thread annotation to make sure that callback is
+  // called by WorkSerializer only, you need to add the annotation to both the
+  // lambda function given to Run and the actual callback function like;
+  //
+  //   void run_callback() {
+  //     work_serializer.Run(
+  //         []() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer) {
+  //            callback();
+  //         }, DEBUG_LOCATION);
+  //   }
+  //   void callback() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer) { ... }
+  //
   // TODO(yashkt): Replace grpc_core::DebugLocation with absl::SourceLocation
   // once we can start using it directly.
   void Run(std::function<void()> callback,
index 9b3e0be..fc09d3a 100644 (file)
@@ -56,7 +56,7 @@ class Json {
   using Array = std::vector<Json>;
 
   // Parses JSON string from json_str.  On error, sets *error.
-  static Json Parse(absl::string_view json_str, grpc_error** error);
+  static Json Parse(absl::string_view json_str, grpc_error_handle* error);
 
   Json() = default;
 
index d23112e..2daeadf 100644 (file)
@@ -38,7 +38,7 @@ namespace {
 
 class JsonReader {
  public:
-  static grpc_error* Parse(absl::string_view input, Json* output);
+  static grpc_error_handle Parse(absl::string_view input, Json* output);
 
  private:
   enum class Status {
@@ -117,7 +117,7 @@ class JsonReader {
   bool container_just_begun_ = false;
   uint16_t unicode_char_ = 0;
   uint16_t unicode_high_surrogate_ = 0;
-  std::vector<grpc_error*> errors_;
+  std::vector<grpc_error_handle> errors_;
   bool truncated_errors_ = false;
 
   Json root_value_;
@@ -821,7 +821,7 @@ JsonReader::Status JsonReader::Run() {
   GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
 }
 
-grpc_error* JsonReader::Parse(absl::string_view input, Json* output) {
+grpc_error_handle JsonReader::Parse(absl::string_view input, Json* output) {
   JsonReader reader(input);
   Status status = reader.Run();
   if (reader.truncated_errors_) {
@@ -849,7 +849,7 @@ grpc_error* JsonReader::Parse(absl::string_view input, Json* output) {
 
 }  // namespace
 
-Json Json::Parse(absl::string_view json_str, grpc_error** error) {
+Json Json::Parse(absl::string_view json_str, grpc_error_handle* error) {
   Json value;
   *error = JsonReader::Parse(json_str, &value);
   return value;
index 07c1442..489a480 100644 (file)
@@ -31,7 +31,7 @@ namespace grpc_core {
 absl::StatusOr<StringMatcher> StringMatcher::Create(Type type,
                                                     absl::string_view matcher,
                                                     bool case_sensitive) {
-  if (type == Type::SAFE_REGEX) {
+  if (type == Type::kSafeRegex) {
     RE2::Options options;
     options.set_case_sensitive(case_sensitive);
     auto regex_matcher = absl::make_unique<RE2>(std::string(matcher), options);
@@ -51,13 +51,13 @@ StringMatcher::StringMatcher(Type type, absl::string_view matcher,
 
 StringMatcher::StringMatcher(std::unique_ptr<RE2> regex_matcher,
                              bool case_sensitive)
-    : type_(Type::SAFE_REGEX),
+    : type_(Type::kSafeRegex),
       regex_matcher_(std::move(regex_matcher)),
       case_sensitive_(case_sensitive) {}
 
 StringMatcher::StringMatcher(const StringMatcher& other)
     : type_(other.type_), case_sensitive_(other.case_sensitive_) {
-  if (type_ == Type::SAFE_REGEX) {
+  if (type_ == Type::kSafeRegex) {
     RE2::Options options;
     options.set_case_sensitive(other.case_sensitive_);
     regex_matcher_ =
@@ -69,7 +69,7 @@ StringMatcher::StringMatcher(const StringMatcher& other)
 
 StringMatcher& StringMatcher::operator=(const StringMatcher& other) {
   type_ = other.type_;
-  if (type_ == Type::SAFE_REGEX) {
+  if (type_ == Type::kSafeRegex) {
     RE2::Options options;
     options.set_case_sensitive(other.case_sensitive_);
     regex_matcher_ =
@@ -83,7 +83,7 @@ StringMatcher& StringMatcher::operator=(const StringMatcher& other) {
 
 StringMatcher::StringMatcher(StringMatcher&& other) noexcept
     : type_(other.type_), case_sensitive_(other.case_sensitive_) {
-  if (type_ == Type::SAFE_REGEX) {
+  if (type_ == Type::kSafeRegex) {
     regex_matcher_ = std::move(other.regex_matcher_);
   } else {
     string_matcher_ = std::move(other.string_matcher_);
@@ -92,7 +92,7 @@ StringMatcher::StringMatcher(StringMatcher&& other) noexcept
 
 StringMatcher& StringMatcher::operator=(StringMatcher&& other) noexcept {
   type_ = other.type_;
-  if (type_ == Type::SAFE_REGEX) {
+  if (type_ == Type::kSafeRegex) {
     regex_matcher_ = std::move(other.regex_matcher_);
   } else {
     string_matcher_ = std::move(other.string_matcher_);
@@ -105,7 +105,7 @@ bool StringMatcher::operator==(const StringMatcher& other) const {
   if (type_ != other.type_ || case_sensitive_ != other.case_sensitive_) {
     return false;
   }
-  if (type_ == Type::SAFE_REGEX) {
+  if (type_ == Type::kSafeRegex) {
     return regex_matcher_->pattern() == other.regex_matcher_->pattern();
   } else {
     return string_matcher_ == other.string_matcher_;
@@ -114,22 +114,22 @@ bool StringMatcher::operator==(const StringMatcher& other) const {
 
 bool StringMatcher::Match(absl::string_view value) const {
   switch (type_) {
-    case Type::EXACT:
+    case Type::kExact:
       return case_sensitive_ ? value == string_matcher_
                              : absl::EqualsIgnoreCase(value, string_matcher_);
-    case StringMatcher::Type::PREFIX:
+    case StringMatcher::Type::kPrefix:
       return case_sensitive_
                  ? absl::StartsWith(value, string_matcher_)
                  : absl::StartsWithIgnoreCase(value, string_matcher_);
-    case StringMatcher::Type::SUFFIX:
+    case StringMatcher::Type::kSuffix:
       return case_sensitive_ ? absl::EndsWith(value, string_matcher_)
                              : absl::EndsWithIgnoreCase(value, string_matcher_);
-    case StringMatcher::Type::CONTAINS:
+    case StringMatcher::Type::kContains:
       return case_sensitive_
                  ? absl::StrContains(value, string_matcher_)
                  : absl::StrContains(absl::AsciiStrToLower(value),
                                      absl::AsciiStrToLower(string_matcher_));
-    case StringMatcher::Type::SAFE_REGEX:
+    case StringMatcher::Type::kSafeRegex:
       return RE2::FullMatch(std::string(value), *regex_matcher_);
     default:
       return false;
@@ -138,19 +138,19 @@ bool StringMatcher::Match(absl::string_view value) const {
 
 std::string StringMatcher::ToString() const {
   switch (type_) {
-    case Type::EXACT:
+    case Type::kExact:
       return absl::StrFormat("StringMatcher{exact=%s%s}", string_matcher_,
                              case_sensitive_ ? "" : ", case_sensitive=false");
-    case Type::PREFIX:
+    case Type::kPrefix:
       return absl::StrFormat("StringMatcher{prefix=%s%s}", string_matcher_,
                              case_sensitive_ ? "" : ", case_sensitive=false");
-    case Type::SUFFIX:
+    case Type::kSuffix:
       return absl::StrFormat("StringMatcher{suffix=%s%s}", string_matcher_,
                              case_sensitive_ ? "" : ", case_sensitive=false");
-    case Type::CONTAINS:
+    case Type::kContains:
       return absl::StrFormat("StringMatcher{contains=%s%s}", string_matcher_,
                              case_sensitive_ ? "" : ", case_sensitive=false");
-    case Type::SAFE_REGEX:
+    case Type::kSafeRegex:
       return absl::StrFormat("StringMatcher{safe_regex=%s%s}",
                              regex_matcher_->pattern(),
                              case_sensitive_ ? "" : ", case_sensitive=false");
@@ -177,7 +177,7 @@ absl::StatusOr<HeaderMatcher> HeaderMatcher::Create(
     }
     return HeaderMatcher(name, type, std::move(string_matcher.value()),
                          invert_match);
-  } else if (type == Type::RANGE) {
+  } else if (type == Type::kRange) {
     if (range_start > range_end) {
       return absl::InvalidArgumentError(
           "Invalid range specifier specified: end cannot be smaller than "
@@ -199,7 +199,7 @@ HeaderMatcher::HeaderMatcher(absl::string_view name, Type type,
 HeaderMatcher::HeaderMatcher(absl::string_view name, int64_t range_start,
                              int64_t range_end, bool invert_match)
     : name_(name),
-      type_(Type::RANGE),
+      type_(Type::kRange),
       range_start_(range_start),
       range_end_(range_end),
       invert_match_(invert_match) {}
@@ -207,7 +207,7 @@ HeaderMatcher::HeaderMatcher(absl::string_view name, int64_t range_start,
 HeaderMatcher::HeaderMatcher(absl::string_view name, bool present_match,
                              bool invert_match)
     : name_(name),
-      type_(Type::PRESENT),
+      type_(Type::kPresent),
       present_match_(present_match),
       invert_match_(invert_match) {}
 
@@ -216,11 +216,11 @@ HeaderMatcher::HeaderMatcher(const HeaderMatcher& other)
       type_(other.type_),
       invert_match_(other.invert_match_) {
   switch (type_) {
-    case Type::RANGE:
+    case Type::kRange:
       range_start_ = other.range_start_;
       range_end_ = other.range_end_;
       break;
-    case Type::PRESENT:
+    case Type::kPresent:
       present_match_ = other.present_match_;
       break;
     default:
@@ -233,11 +233,11 @@ HeaderMatcher& HeaderMatcher::operator=(const HeaderMatcher& other) {
   type_ = other.type_;
   invert_match_ = other.invert_match_;
   switch (type_) {
-    case Type::RANGE:
+    case Type::kRange:
       range_start_ = other.range_start_;
       range_end_ = other.range_end_;
       break;
-    case Type::PRESENT:
+    case Type::kPresent:
       present_match_ = other.present_match_;
       break;
     default:
@@ -251,11 +251,11 @@ HeaderMatcher::HeaderMatcher(HeaderMatcher&& other) noexcept
       type_(other.type_),
       invert_match_(other.invert_match_) {
   switch (type_) {
-    case Type::RANGE:
+    case Type::kRange:
       range_start_ = other.range_start_;
       range_end_ = other.range_end_;
       break;
-    case Type::PRESENT:
+    case Type::kPresent:
       present_match_ = other.present_match_;
       break;
     default:
@@ -268,11 +268,11 @@ HeaderMatcher& HeaderMatcher::operator=(HeaderMatcher&& other) noexcept {
   type_ = other.type_;
   invert_match_ = other.invert_match_;
   switch (type_) {
-    case Type::RANGE:
+    case Type::kRange:
       range_start_ = other.range_start_;
       range_end_ = other.range_end_;
       break;
-    case Type::PRESENT:
+    case Type::kPresent:
       present_match_ = other.present_match_;
       break;
     default:
@@ -286,10 +286,10 @@ bool HeaderMatcher::operator==(const HeaderMatcher& other) const {
   if (type_ != other.type_) return false;
   if (invert_match_ != other.invert_match_) return false;
   switch (type_) {
-    case Type::RANGE:
+    case Type::kRange:
       return range_start_ == other.range_start_ &&
              range_end_ == other.range_end_;
-    case Type::PRESENT:
+    case Type::kPresent:
       return present_match_ == other.present_match_;
     default:
       return matcher_ == other.matcher_;
@@ -299,12 +299,12 @@ bool HeaderMatcher::operator==(const HeaderMatcher& other) const {
 bool HeaderMatcher::Match(
     const absl::optional<absl::string_view>& value) const {
   bool match;
-  if (type_ == Type::PRESENT) {
+  if (type_ == Type::kPresent) {
     match = value.has_value() == present_match_;
   } else if (!value.has_value()) {
     // All other types fail to match if field is not present.
     match = false;
-  } else if (type_ == Type::RANGE) {
+  } else if (type_ == Type::kRange) {
     int64_t int_value;
     match = absl::SimpleAtoi(value.value(), &int_value) &&
             int_value >= range_start_ && int_value < range_end_;
@@ -316,19 +316,19 @@ bool HeaderMatcher::Match(
 
 std::string HeaderMatcher::ToString() const {
   switch (type_) {
-    case Type::RANGE:
+    case Type::kRange:
       return absl::StrFormat("HeaderMatcher{%s %srange=[%d, %d]}", name_,
                              invert_match_ ? "not " : "", range_start_,
                              range_end_);
-    case Type::PRESENT:
+    case Type::kPresent:
       return absl::StrFormat("HeaderMatcher{%s %spresent=%s}", name_,
                              invert_match_ ? "not " : "",
                              present_match_ ? "true" : "false");
-    case Type::EXACT:
-    case Type::PREFIX:
-    case Type::SUFFIX:
-    case Type::SAFE_REGEX:
-    case Type::CONTAINS:
+    case Type::kExact:
+    case Type::kPrefix:
+    case Type::kSuffix:
+    case Type::kSafeRegex:
+    case Type::kContains:
       return absl::StrFormat("HeaderMatcher{%s %s%s}", name_,
                              invert_match_ ? "not " : "", matcher_.ToString());
     default:
index 570fb33..af2ce59 100644 (file)
@@ -31,11 +31,11 @@ namespace grpc_core {
 class StringMatcher {
  public:
   enum class Type {
-    EXACT,       // value stored in string_matcher_ field
-    PREFIX,      // value stored in string_matcher_ field
-    SUFFIX,      // value stored in string_matcher_ field
-    SAFE_REGEX,  // pattern stored in regex_matcher_ field
-    CONTAINS,    // value stored in string_matcher_ field
+    kExact,      // value stored in string_matcher_ field
+    kPrefix,     // value stored in string_matcher_ field
+    kSuffix,     // value stored in string_matcher_ field
+    kSafeRegex,  // pattern stored in regex_matcher_ field
+    kContains,   // value stored in string_matcher_ field
   };
 
   // Creates StringMatcher instance. Returns error status on failure.
@@ -56,10 +56,10 @@ class StringMatcher {
 
   Type type() const { return type_; }
 
-  // Valid for EXACT, PREFIX, SUFFIX and CONTAINS
+  // Valid for kExact, kPrefix, kSuffix and kContains.
   const std::string& string_matcher() const { return string_matcher_; }
 
-  // Valid for SAFE_REGEX
+  // Valid for kSafeRegex.
   RE2* regex_matcher() const { return regex_matcher_.get(); }
 
   bool case_sensitive() const { return case_sensitive_; }
@@ -68,7 +68,7 @@ class StringMatcher {
   StringMatcher(Type type, absl::string_view matcher, bool case_sensitive);
   StringMatcher(std::unique_ptr<RE2> regex_matcher, bool case_sensitive);
 
-  Type type_ = Type::EXACT;
+  Type type_ = Type::kExact;
   std::string string_matcher_;
   std::unique_ptr<RE2> regex_matcher_;
   bool case_sensitive_ = true;
@@ -77,32 +77,32 @@ class StringMatcher {
 class HeaderMatcher {
  public:
   enum class Type {
-    EXACT,       // value stored in StringMatcher field
-    PREFIX,      // value stored in StringMatcher field
-    SUFFIX,      // value stored in StringMatcher field
-    SAFE_REGEX,  // value stored in StringMatcher field
-    CONTAINS,    // value stored in StringMatcher field
-    RANGE,       // uses range_start and range_end fields
-    PRESENT,     // uses present_match field
+    kExact,      // value stored in StringMatcher field
+    kPrefix,     // value stored in StringMatcher field
+    kSuffix,     // value stored in StringMatcher field
+    kSafeRegex,  // value stored in StringMatcher field
+    kContains,   // value stored in StringMatcher field
+    kRange,      // uses range_start and range_end fields
+    kPresent,    // uses present_match field
   };
 
   // Make sure that the first five HeaderMatcher::Type enum values match up to
   // the corresponding StringMatcher::Type enum values, so that it's safe to
   // convert by casting when delegating to StringMatcher.
-  static_assert(static_cast<StringMatcher::Type>(Type::EXACT) ==
-                    StringMatcher::Type::EXACT,
+  static_assert(static_cast<StringMatcher::Type>(Type::kExact) ==
+                    StringMatcher::Type::kExact,
                 "");
-  static_assert(static_cast<StringMatcher::Type>(Type::PREFIX) ==
-                    StringMatcher::Type::PREFIX,
+  static_assert(static_cast<StringMatcher::Type>(Type::kPrefix) ==
+                    StringMatcher::Type::kPrefix,
                 "");
-  static_assert(static_cast<StringMatcher::Type>(Type::SUFFIX) ==
-                    StringMatcher::Type::SUFFIX,
+  static_assert(static_cast<StringMatcher::Type>(Type::kSuffix) ==
+                    StringMatcher::Type::kSuffix,
                 "");
-  static_assert(static_cast<StringMatcher::Type>(Type::SAFE_REGEX) ==
-                    StringMatcher::Type::SAFE_REGEX,
+  static_assert(static_cast<StringMatcher::Type>(Type::kSafeRegex) ==
+                    StringMatcher::Type::kSafeRegex,
                 "");
-  static_assert(static_cast<StringMatcher::Type>(Type::CONTAINS) ==
-                    StringMatcher::Type::CONTAINS,
+  static_assert(static_cast<StringMatcher::Type>(Type::kContains) ==
+                    StringMatcher::Type::kContains,
                 "");
 
   // Creates HeaderMatcher instance. Returns error status on failure.
@@ -124,12 +124,12 @@ class HeaderMatcher {
 
   Type type() const { return type_; }
 
-  // Valid for EXACT, PREFIX, SUFFIX and CONTAINS
+  // Valid for kExact, kPrefix, kSuffix and kContains.
   const std::string& string_matcher() const {
     return matcher_.string_matcher();
   }
 
-  // Valid for SAFE_REGEX
+  // Valid for kSafeRegex.
   RE2* regex_matcher() const { return matcher_.regex_matcher(); }
 
   bool Match(const absl::optional<absl::string_view>& value) const;
@@ -147,7 +147,7 @@ class HeaderMatcher {
   HeaderMatcher(absl::string_view name, bool present_match, bool invert_match);
 
   std::string name_;
-  Type type_ = Type::EXACT;
+  Type type_ = Type::kExact;
   StringMatcher matcher_;
   int64_t range_start_;
   int64_t range_end_;
index 809784c..7889e62 100644 (file)
@@ -1,5 +1,4 @@
-
-// Copyright 2020 gRPC authors.
+// Copyright 2021 gRPC authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 
 #include <grpc/support/port_platform.h>
 
-#include <grpc/support/log.h>
-#include <map>
-#include <memory>
 #include <string>
-#include <vector>
-
-#include "absl/container/flat_hash_set.h"
-#include "envoy/config/rbac/v3/rbac.upb.h"
-#include "google/api/expr/v1alpha1/syntax.upb.h"
-#include "upb/upb.hpp"
 
 #include "src/core/lib/security/authorization/evaluate_args.h"
-#include "src/core/lib/security/authorization/mock_cel/activation.h"
 
 namespace grpc_core {
 
-// AuthorizationEngine makes an AuthorizationDecision to ALLOW or DENY the
-// current action based on the condition fields in provided RBAC policies.
-// The engine may be constructed with one or two policies. If two polcies,
-// the first policy is deny-if-matched and the second is allow-if-matched.
-// The engine returns UNDECIDED decision if it fails to find a match in any
-// policy. This engine ignores the principal and permission fields in RBAC
-// policies. It is the caller's responsibility to provide RBAC policies that
-// are compatible with this engine.
-//
-// Example:
-// AuthorizationEngine*
-// auth_engine = AuthorizationEngine::CreateAuthorizationEngine(rbac_policies);
-// auth_engine->Evaluate(evaluate_args); // returns authorization decision.
+// Interface for gRPC Authorization Engine.
 class AuthorizationEngine {
  public:
-  // rbac_policies must be a vector containing either a single policy of any
-  // kind, or one deny policy and one allow policy, in that order.
-  static std::unique_ptr<AuthorizationEngine> CreateAuthorizationEngine(
-      const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
-
-  // Users should use the CreateAuthorizationEngine factory function
-  // instead of calling the AuthorizationEngine constructor directly.
-  explicit AuthorizationEngine(
-      const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
-  // TODO(mywang@google.com): add an Evaluate member function.
-
- private:
-  enum Action {
-    kAllow,
-    kDeny,
+  struct Decision {
+    enum class Type {
+      kAllow,
+      kDeny,
+    };
+    Type type;
+    std::string matching_policy_name;
   };
 
-  std::unique_ptr<mock_cel::Activation> CreateActivation(
-      const EvaluateArgs& args);
-
-  std::map<const std::string, const google_api_expr_v1alpha1_Expr*>
-      deny_if_matched_;
-  std::map<const std::string, const google_api_expr_v1alpha1_Expr*>
-      allow_if_matched_;
-  upb::Arena arena_;
-  absl::flat_hash_set<std::string> envoy_attributes_;
-  absl::flat_hash_set<std::string> header_keys_;
-  std::unique_ptr<mock_cel::CelMap> headers_;
+  virtual ~AuthorizationEngine() = default;
+  virtual Decision Evaluate(const EvaluateArgs& args) const = 0;
 };
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H */
+#endif  // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H
@@ -16,7 +16,7 @@
 
 #include "absl/memory/memory.h"
 
-#include "src/core/lib/security/authorization/authorization_engine.h"
+#include "src/core/lib/security/authorization/cel_authorization_engine.h"
 
 namespace grpc_core {
 
@@ -36,8 +36,8 @@ constexpr char kCertServerName[] = "cert_server_name";
 
 }  // namespace
 
-std::unique_ptr<AuthorizationEngine>
-AuthorizationEngine::CreateAuthorizationEngine(
+std::unique_ptr<CelAuthorizationEngine>
+CelAuthorizationEngine::CreateCelAuthorizationEngine(
     const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies) {
   if (rbac_policies.empty() || rbac_policies.size() > 2) {
     gpr_log(GPR_ERROR,
@@ -52,11 +52,11 @@ AuthorizationEngine::CreateAuthorizationEngine(
                          policy and one allow policy, in that order.");
     return nullptr;
   } else {
-    return absl::make_unique<AuthorizationEngine>(rbac_policies);
+    return absl::make_unique<CelAuthorizationEngine>(rbac_policies);
   }
 }
 
-AuthorizationEngine::AuthorizationEngine(
+CelAuthorizationEngine::CelAuthorizationEngine(
     const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies) {
   for (const auto& rbac_policy : rbac_policies) {
     // Extract array of policies and store their condition fields in either
@@ -90,7 +90,7 @@ AuthorizationEngine::AuthorizationEngine(
   }
 }
 
-std::unique_ptr<mock_cel::Activation> AuthorizationEngine::CreateActivation(
+std::unique_ptr<mock_cel::Activation> CelAuthorizationEngine::CreateActivation(
     const EvaluateArgs& args) {
   std::unique_ptr<mock_cel::Activation> activation;
   for (const auto& elem : envoy_attributes_) {
@@ -158,7 +158,7 @@ std::unique_ptr<mock_cel::Activation> AuthorizationEngine::CreateActivation(
             kSpiffeId, mock_cel::CelValue::CreateStringView(spiffe_id));
       }
     } else if (elem == kCertServerName) {
-      absl::string_view cert_server_name(args.GetCertServerName());
+      absl::string_view cert_server_name(args.GetCommonName());
       if (!cert_server_name.empty()) {
         activation->InsertValue(
             kCertServerName,
diff --git a/src/core/lib/security/authorization/cel_authorization_engine.h b/src/core/lib/security/authorization/cel_authorization_engine.h
new file mode 100644 (file)
index 0000000..6f37bfb
--- /dev/null
@@ -0,0 +1,84 @@
+
+// Copyright 2020 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_SECURITY_AUTHORIZATION_CEL_AUTHORIZATION_ENGINE_H
+#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_CEL_AUTHORIZATION_ENGINE_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/log.h>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/container/flat_hash_set.h"
+#include "envoy/config/rbac/v3/rbac.upb.h"
+#include "google/api/expr/v1alpha1/syntax.upb.h"
+#include "upb/upb.hpp"
+
+#include "src/core/lib/security/authorization/evaluate_args.h"
+#include "src/core/lib/security/authorization/mock_cel/activation.h"
+
+namespace grpc_core {
+
+// CelAuthorizationEngine makes an AuthorizationDecision to ALLOW or DENY the
+// current action based on the condition fields in provided RBAC policies.
+// The engine may be constructed with one or two policies. If two polcies,
+// the first policy is deny-if-matched and the second is allow-if-matched.
+// The engine returns UNDECIDED decision if it fails to find a match in any
+// policy. This engine ignores the principal and permission fields in RBAC
+// policies. It is the caller's responsibility to provide RBAC policies that
+// are compatible with this engine.
+//
+// Example:
+// CelAuthorizationEngine* engine =
+// CelAuthorizationEngine::CreateCelAuthorizationEngine(rbac_policies);
+// engine->Evaluate(evaluate_args); // returns authorization decision.
+class CelAuthorizationEngine {
+ public:
+  // rbac_policies must be a vector containing either a single policy of any
+  // kind, or one deny policy and one allow policy, in that order.
+  static std::unique_ptr<CelAuthorizationEngine> CreateCelAuthorizationEngine(
+      const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
+
+  // Users should use the CreateCelAuthorizationEngine factory function
+  // instead of calling the CelAuthorizationEngine constructor directly.
+  explicit CelAuthorizationEngine(
+      const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
+  // TODO(mywang@google.com): add an Evaluate member function.
+
+ private:
+  enum Action {
+    kAllow,
+    kDeny,
+  };
+
+  std::unique_ptr<mock_cel::Activation> CreateActivation(
+      const EvaluateArgs& args);
+
+  std::map<const std::string, const google_api_expr_v1alpha1_Expr*>
+      deny_if_matched_;
+  std::map<const std::string, const google_api_expr_v1alpha1_Expr*>
+      allow_if_matched_;
+  upb::Arena arena_;
+  absl::flat_hash_set<std::string> envoy_attributes_;
+  absl::flat_hash_set<std::string> header_keys_;
+  std::unique_ptr<mock_cel::CelMap> headers_;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_CEL_AUTHORIZATION_ENGINE_H */
index 4f92549..12144df 100644 (file)
@@ -1,6 +1,4 @@
-//
-//
-// Copyright 2020 gRPC authors.
+// Copyright 2021 gRPC authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-//
-//
 
 #include <grpc/support/port_platform.h>
 
 #include "src/core/lib/security/authorization/evaluate_args.h"
 
-#include "absl/strings/str_join.h"
-
-#include "src/core/lib/iomgr/parse_address.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/slice/slice_utils.h"
 
 namespace grpc_core {
 
+namespace {
+
+absl::string_view GetAuthPropertyValue(grpc_auth_context* context,
+                                       const char* property_name) {
+  grpc_auth_property_iterator it =
+      grpc_auth_context_find_properties_by_name(context, property_name);
+  const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
+  if (prop == nullptr) {
+    gpr_log(GPR_DEBUG, "No value found for %s property.", property_name);
+    return "";
+  }
+  if (grpc_auth_property_iterator_next(&it) != nullptr) {
+    gpr_log(GPR_DEBUG, "Multiple values found for %s property.", property_name);
+    return "";
+  }
+  return absl::string_view(prop->value, prop->value_length);
+}
+
+void ParseEndpointUri(absl::string_view uri_text, std::string* address,
+                      int* port) {
+  absl::StatusOr<URI> uri = URI::Parse(uri_text);
+  if (!uri.ok()) {
+    gpr_log(GPR_DEBUG, "Failed to parse uri.");
+    return;
+  }
+  absl::string_view host_view;
+  absl::string_view port_view;
+  if (!SplitHostPort(uri->path(), &host_view, &port_view)) {
+    gpr_log(GPR_DEBUG, "Failed to split %s into host and port.",
+            uri->path().c_str());
+    return;
+  }
+  *address = std::string(host_view);
+  if (!absl::SimpleAtoi(port_view, port)) {
+    gpr_log(GPR_DEBUG, "Port %s is out of range or null.",
+            std::string(port_view).c_str());
+  }
+}
+
+}  // namespace
+
+EvaluateArgs::PerChannelArgs::PerChannelArgs(grpc_auth_context* auth_context,
+                                             grpc_endpoint* endpoint) {
+  if (auth_context != nullptr) {
+    transport_security_type = GetAuthPropertyValue(
+        auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME);
+    spiffe_id =
+        GetAuthPropertyValue(auth_context, GRPC_PEER_SPIFFE_ID_PROPERTY_NAME);
+    common_name =
+        GetAuthPropertyValue(auth_context, GRPC_X509_CN_PROPERTY_NAME);
+  }
+  if (endpoint != nullptr) {
+    ParseEndpointUri(grpc_endpoint_get_local_address(endpoint), &local_address,
+                     &local_port);
+    ParseEndpointUri(grpc_endpoint_get_peer(endpoint), &peer_address,
+                     &peer_port);
+  }
+}
+
 absl::string_view EvaluateArgs::GetPath() const {
   absl::string_view path;
   if (metadata_ != nullptr && metadata_->idx.named.path != nullptr) {
@@ -83,76 +135,52 @@ absl::optional<absl::string_view> EvaluateArgs::GetHeaderValue(
 }
 
 absl::string_view EvaluateArgs::GetLocalAddress() const {
-  absl::string_view addr = grpc_endpoint_get_local_address(endpoint_);
-  size_t first_colon = addr.find(":");
-  size_t last_colon = addr.rfind(":");
-  if (first_colon == std::string::npos || last_colon == std::string::npos) {
+  if (channel_args_ == nullptr) {
     return "";
-  } else {
-    return addr.substr(first_colon + 1, last_colon - first_colon - 1);
   }
+  return channel_args_->local_address;
 }
 
 int EvaluateArgs::GetLocalPort() const {
-  if (endpoint_ == nullptr) {
+  if (channel_args_ == nullptr) {
     return 0;
   }
-  absl::StatusOr<URI> uri =
-      URI::Parse(grpc_endpoint_get_local_address(endpoint_));
-  grpc_resolved_address resolved_addr;
-  if (!uri.ok() || !grpc_parse_uri(*uri, &resolved_addr)) {
-    return 0;
-  }
-  return grpc_sockaddr_get_port(&resolved_addr);
+  return channel_args_->local_port;
 }
 
 absl::string_view EvaluateArgs::GetPeerAddress() const {
-  absl::string_view addr = grpc_endpoint_get_peer(endpoint_);
-  size_t first_colon = addr.find(":");
-  size_t last_colon = addr.rfind(":");
-  if (first_colon == std::string::npos || last_colon == std::string::npos) {
+  if (channel_args_ == nullptr) {
     return "";
-  } else {
-    return addr.substr(first_colon + 1, last_colon - first_colon - 1);
   }
+  return channel_args_->peer_address;
 }
 
 int EvaluateArgs::GetPeerPort() const {
-  if (endpoint_ == nullptr) {
-    return 0;
-  }
-  absl::StatusOr<URI> uri = URI::Parse(grpc_endpoint_get_peer(endpoint_));
-  grpc_resolved_address resolved_addr;
-  if (!uri.ok() || !grpc_parse_uri(*uri, &resolved_addr)) {
+  if (channel_args_ == nullptr) {
     return 0;
   }
-  return grpc_sockaddr_get_port(&resolved_addr);
+  return channel_args_->peer_port;
 }
 
-absl::string_view EvaluateArgs::GetSpiffeId() const {
-  if (auth_context_ == nullptr) {
+absl::string_view EvaluateArgs::GetTransportSecurityType() const {
+  if (channel_args_ == nullptr) {
     return "";
   }
-  grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
-      auth_context_, GRPC_PEER_SPIFFE_ID_PROPERTY_NAME);
-  const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
-  if (prop == nullptr || grpc_auth_property_iterator_next(&it) != nullptr) {
-    return "";
-  }
-  return absl::string_view(prop->value, prop->value_length);
+  return channel_args_->transport_security_type;
 }
 
-absl::string_view EvaluateArgs::GetCertServerName() const {
-  if (auth_context_ == nullptr) {
+absl::string_view EvaluateArgs::GetSpiffeId() const {
+  if (channel_args_ == nullptr) {
     return "";
   }
-  grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
-      auth_context_, GRPC_X509_CN_PROPERTY_NAME);
-  const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
-  if (prop == nullptr || grpc_auth_property_iterator_next(&it) != nullptr) {
+  return channel_args_->spiffe_id;
+}
+
+absl::string_view EvaluateArgs::GetCommonName() const {
+  if (channel_args_ == nullptr) {
     return "";
   }
-  return absl::string_view(prop->value, prop->value_length);
+  return channel_args_->common_name;
 }
 
 }  // namespace grpc_core
index d280370..b3ac93c 100644 (file)
@@ -1,6 +1,4 @@
-//
-//
-// Copyright 2020 gRPC authors.
+// Copyright 2021 gRPC authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -13,8 +11,6 @@
 // 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_SECURITY_AUTHORIZATION_EVALUATE_ARGS_H
 #define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_EVALUATE_ARGS_H
@@ -33,9 +29,22 @@ namespace grpc_core {
 
 class EvaluateArgs {
  public:
-  EvaluateArgs(grpc_metadata_batch* metadata, grpc_auth_context* auth_context,
-               grpc_endpoint* endpoint)
-      : metadata_(metadata), auth_context_(auth_context), endpoint_(endpoint) {}
+  // Caller is responsible for ensuring auth_context outlives PerChannelArgs
+  // struct.
+  struct PerChannelArgs {
+    PerChannelArgs(grpc_auth_context* auth_context, grpc_endpoint* endpoint);
+
+    absl::string_view transport_security_type;
+    absl::string_view spiffe_id;
+    absl::string_view common_name;
+    std::string local_address;
+    int local_port = 0;
+    std::string peer_address;
+    int peer_port = 0;
+  };
+
+  EvaluateArgs(grpc_metadata_batch* metadata, PerChannelArgs* channel_args)
+      : metadata_(metadata), channel_args_(channel_args) {}
 
   absl::string_view GetPath() const;
   absl::string_view GetHost() const;
@@ -50,19 +59,18 @@ class EvaluateArgs {
   // string_view of that string.
   absl::optional<absl::string_view> GetHeaderValue(
       absl::string_view key, std::string* concatenated_value) const;
+
   absl::string_view GetLocalAddress() const;
   int GetLocalPort() const;
   absl::string_view GetPeerAddress() const;
   int GetPeerPort() const;
+  absl::string_view GetTransportSecurityType() const;
   absl::string_view GetSpiffeId() const;
-  absl::string_view GetCertServerName() const;
-
-  // TODO(unknown): Add a getter function for source.principal
+  absl::string_view GetCommonName() const;
 
  private:
   grpc_metadata_batch* metadata_;
-  grpc_auth_context* auth_context_;
-  grpc_endpoint* endpoint_;
+  PerChannelArgs* channel_args_;
 };
 
 }  // namespace grpc_core
diff --git a/src/core/lib/security/authorization/grpc_authorization_engine.cc b/src/core/lib/security/authorization/grpc_authorization_engine.cc
new file mode 100644 (file)
index 0000000..34fc976
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2021 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/authorization/grpc_authorization_engine.h"
+
+namespace grpc_core {
+
+GrpcAuthorizationEngine::GrpcAuthorizationEngine(Rbac policy)
+    : action_(policy.action) {
+  for (auto& sub_policy : policy.policies) {
+    Policy policy;
+    policy.name = sub_policy.first;
+    policy.matcher = absl::make_unique<PolicyAuthorizationMatcher>(
+        std::move(sub_policy.second));
+    policies_.push_back(std::move(policy));
+  }
+}
+
+AuthorizationEngine::Decision GrpcAuthorizationEngine::Evaluate(
+    const EvaluateArgs& args) const {
+  Decision decision;
+  bool matches = false;
+  for (const auto& policy : policies_) {
+    if (policy.matcher->Matches(args)) {
+      matches = true;
+      decision.matching_policy_name = policy.name;
+      break;
+    }
+  }
+  decision.type = (matches == (action_ == Rbac::Action::kAllow))
+                      ? Decision::Type::kAllow
+                      : Decision::Type::kDeny;
+  return decision;
+}
+
+}  // namespace grpc_core
diff --git a/src/core/lib/security/authorization/grpc_authorization_engine.h b/src/core/lib/security/authorization/grpc_authorization_engine.h
new file mode 100644 (file)
index 0000000..5b7791a
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2021 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_SECURITY_AUTHORIZATION_GRPC_AUTHORIZATION_ENGINE_H
+#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_GRPC_AUTHORIZATION_ENGINE_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/authorization/authorization_engine.h"
+#include "src/core/lib/security/authorization/matchers.h"
+#include "src/core/lib/security/authorization/rbac_policy.h"
+
+namespace grpc_core {
+
+// GrpcAuthorizationEngine can be either an Allow engine or Deny engine. This
+// engine makes authorization decisions to Allow or Deny incoming RPC request
+// based on permission and principal configs in the provided RBAC policy and the
+// engine type. This engine ignores condition field in RBAC config. It is the
+// caller's responsibility to provide RBAC policies that are compatible with
+// this engine.
+class GrpcAuthorizationEngine : public AuthorizationEngine {
+ public:
+  // Builds GrpcAuthorizationEngine without any policies.
+  explicit GrpcAuthorizationEngine(Rbac::Action action) : action_(action) {}
+  // Builds GrpcAuthorizationEngine with allow/deny RBAC policy.
+  explicit GrpcAuthorizationEngine(Rbac policy);
+
+  // Evaluates incoming request against RBAC policy and makes a decision to
+  // whether allow/deny this request.
+  Decision Evaluate(const EvaluateArgs& args) const override;
+
+ private:
+  struct Policy {
+    std::string name;
+    std::unique_ptr<AuthorizationMatcher> matcher;
+  };
+
+  Rbac::Action action_;
+  std::vector<Policy> policies_;
+};
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_GRPC_AUTHORIZATION_ENGINE_H
diff --git a/src/core/lib/security/authorization/matchers.cc b/src/core/lib/security/authorization/matchers.cc
new file mode 100644 (file)
index 0000000..5613b74
--- /dev/null
@@ -0,0 +1,202 @@
+// Copyright 2021 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/authorization/matchers.h"
+
+namespace grpc_core {
+
+namespace {
+
+bool AuthenticatedMatchesHelper(const EvaluateArgs& args,
+                                const StringMatcher& matcher) {
+  if (args.GetTransportSecurityType() != GRPC_SSL_TRANSPORT_SECURITY_TYPE) {
+    // Connection is not authenticated.
+    return false;
+  }
+  if (matcher.string_matcher().empty()) {
+    // Allows any authenticated user.
+    return true;
+  }
+  absl::string_view spiffe_id = args.GetSpiffeId();
+  if (!spiffe_id.empty()) {
+    return matcher.Match(spiffe_id);
+  }
+  // TODO(ashithasantosh): Check principal matches DNS SAN, followed by Subject
+  // field from certificate. This requires updating tsi_peer to expose these
+  // fields.
+  return false;
+}
+
+}  // namespace
+
+std::unique_ptr<AuthorizationMatcher> AuthorizationMatcher::Create(
+    Rbac::Permission permission) {
+  switch (permission.type) {
+    case Rbac::Permission::RuleType::kAnd:
+      return absl::make_unique<AndAuthorizationMatcher>(
+          std::move(permission.permissions), permission.not_rule);
+    case Rbac::Permission::RuleType::kOr:
+      return absl::make_unique<OrAuthorizationMatcher>(
+          std::move(permission.permissions), permission.not_rule);
+    case Rbac::Permission::RuleType::kAny:
+      return absl::make_unique<AlwaysAuthorizationMatcher>(permission.not_rule);
+    case Rbac::Permission::RuleType::kHeader:
+      return absl::make_unique<HeaderAuthorizationMatcher>(
+          std::move(permission.header_matcher), permission.not_rule);
+    case Rbac::Permission::RuleType::kPath:
+      return absl::make_unique<PathAuthorizationMatcher>(
+          std::move(permission.string_matcher), permission.not_rule);
+    case Rbac::Permission::RuleType::kDestIp:
+      return absl::make_unique<IpAuthorizationMatcher>(std::move(permission.ip),
+                                                       permission.not_rule);
+    case Rbac::Permission::RuleType::kDestPort:
+      return absl::make_unique<PortAuthorizationMatcher>(permission.port,
+                                                         permission.not_rule);
+    case Rbac::Permission::RuleType::kReqServerName:
+      return absl::make_unique<ReqServerNameAuthorizationMatcher>(
+          std::move(permission.string_matcher), permission.not_rule);
+  }
+  return nullptr;
+}
+
+std::unique_ptr<AuthorizationMatcher> AuthorizationMatcher::Create(
+    Rbac::Principal principal) {
+  switch (principal.type) {
+    case Rbac::Principal::RuleType::kAnd:
+      return absl::make_unique<AndAuthorizationMatcher>(
+          std::move(principal.principals), principal.not_rule);
+    case Rbac::Principal::RuleType::kOr:
+      return absl::make_unique<OrAuthorizationMatcher>(
+          std::move(principal.principals), principal.not_rule);
+    case Rbac::Principal::RuleType::kAny:
+      return absl::make_unique<AlwaysAuthorizationMatcher>(principal.not_rule);
+    case Rbac::Principal::RuleType::kPrincipalName:
+      return absl::make_unique<AuthenticatedAuthorizationMatcher>(
+          std::move(principal.string_matcher), principal.not_rule);
+    case Rbac::Principal::RuleType::kSourceIp:
+    case Rbac::Principal::RuleType::kDirectRemoteIp:
+    case Rbac::Principal::RuleType::kRemoteIp:
+      return absl::make_unique<IpAuthorizationMatcher>(std::move(principal.ip),
+                                                       principal.not_rule);
+    case Rbac::Principal::RuleType::kHeader:
+      return absl::make_unique<HeaderAuthorizationMatcher>(
+          std::move(principal.header_matcher), principal.not_rule);
+    case Rbac::Principal::RuleType::kPath:
+      return absl::make_unique<PathAuthorizationMatcher>(
+          std::move(principal.string_matcher), principal.not_rule);
+  }
+  return nullptr;
+}
+
+AndAuthorizationMatcher::AndAuthorizationMatcher(
+    std::vector<std::unique_ptr<Rbac::Permission>> rules, bool not_rule)
+    : not_rule_(not_rule) {
+  for (auto& rule : rules) {
+    matchers_.push_back(AuthorizationMatcher::Create(std::move(*rule)));
+  }
+}
+
+AndAuthorizationMatcher::AndAuthorizationMatcher(
+    std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule)
+    : not_rule_(not_rule) {
+  for (const auto& id : ids) {
+    matchers_.push_back(AuthorizationMatcher::Create(std::move(*id)));
+  }
+}
+
+bool AndAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  bool matches = true;
+  for (const auto& matcher : matchers_) {
+    if (!matcher->Matches(args)) {
+      matches = false;
+      break;
+    }
+  }
+  return matches != not_rule_;
+}
+
+OrAuthorizationMatcher::OrAuthorizationMatcher(
+    std::vector<std::unique_ptr<Rbac::Permission>> rules, bool not_rule)
+    : not_rule_(not_rule) {
+  for (const auto& rule : rules) {
+    matchers_.push_back(AuthorizationMatcher::Create(std::move(*rule)));
+  }
+}
+
+OrAuthorizationMatcher::OrAuthorizationMatcher(
+    std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule)
+    : not_rule_(not_rule) {
+  for (const auto& id : ids) {
+    matchers_.push_back(AuthorizationMatcher::Create(std::move(*id)));
+  }
+}
+
+bool OrAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  bool matches = false;
+  for (const auto& matcher : matchers_) {
+    if (matcher->Matches(args)) {
+      matches = true;
+      break;
+    }
+  }
+  return matches != not_rule_;
+}
+
+bool HeaderAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  std::string concatenated_value;
+  bool matches =
+      matcher_.Match(args.GetHeaderValue(matcher_.name(), &concatenated_value));
+  return matches != not_rule_;
+}
+
+// TODO(ashithasantosh): Implement IpAuthorizationMatcher::Matches.
+bool IpAuthorizationMatcher::Matches(const EvaluateArgs&) const {
+  bool matches = false;
+  return matches != not_rule_;
+}
+
+bool PortAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  bool matches = (port_ == args.GetLocalPort());
+  return matches != not_rule_;
+}
+
+bool AuthenticatedAuthorizationMatcher::Matches(
+    const EvaluateArgs& args) const {
+  bool matches = AuthenticatedMatchesHelper(args, matcher_);
+  return matches != not_rule_;
+}
+
+bool ReqServerNameAuthorizationMatcher::Matches(const EvaluateArgs&) const {
+  // Currently we do not support matching rules containing
+  // "requested_server_name".
+  bool matches = false;
+  return matches != not_rule_;
+}
+
+bool PathAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  bool matches = false;
+  absl::string_view path = args.GetPath();
+  if (!path.empty()) {
+    matches = matcher_.Match(path);
+  }
+  return matches != not_rule_;
+}
+
+bool PolicyAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  return permissions_->Matches(args) && principals_->Matches(args);
+}
+
+}  // namespace grpc_core
diff --git a/src/core/lib/security/authorization/matchers.h b/src/core/lib/security/authorization/matchers.h
new file mode 100644 (file)
index 0000000..86b40ee
--- /dev/null
@@ -0,0 +1,206 @@
+// Copyright 2021 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_SECURITY_AUTHORIZATION_MATCHERS_H
+#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <memory>
+
+#include "src/core/lib/matchers/matchers.h"
+#include "src/core/lib/security/authorization/evaluate_args.h"
+#include "src/core/lib/security/authorization/rbac_policy.h"
+
+namespace grpc_core {
+
+// Describes the rules for matching permission or principal.
+class AuthorizationMatcher {
+ public:
+  virtual ~AuthorizationMatcher() = default;
+
+  // Returns whether or not the permission/principal matches the rules of the
+  // matcher.
+  virtual bool Matches(const EvaluateArgs& args) const = 0;
+
+  // Creates an instance of a matcher based off the rules defined in Permission
+  // config.
+  static std::unique_ptr<AuthorizationMatcher> Create(
+      Rbac::Permission permission);
+
+  // Creates an instance of a matcher based off the rules defined in Principal
+  // config.
+  static std::unique_ptr<AuthorizationMatcher> Create(
+      Rbac::Principal principal);
+};
+
+class AlwaysAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit AlwaysAuthorizationMatcher(bool not_rule = false)
+      : not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs&) const override { return !not_rule_; }
+
+ private:
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+class AndAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit AndAuthorizationMatcher(
+      std::vector<std::unique_ptr<Rbac::Permission>> rules,
+      bool not_rule = false);
+  explicit AndAuthorizationMatcher(
+      std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule = false);
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  std::vector<std::unique_ptr<AuthorizationMatcher>> matchers_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+class OrAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit OrAuthorizationMatcher(
+      std::vector<std::unique_ptr<Rbac::Permission>> rules,
+      bool not_rule = false);
+  explicit OrAuthorizationMatcher(
+      std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule = false);
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  std::vector<std::unique_ptr<AuthorizationMatcher>> matchers_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// TODO(ashithasantosh): Add matcher implementation for metadata field.
+
+// Perform a match against HTTP headers.
+class HeaderAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit HeaderAuthorizationMatcher(HeaderMatcher matcher,
+                                      bool not_rule = false)
+      : matcher_(std::move(matcher)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  const HeaderMatcher matcher_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Perform a match against IP Cidr Range.
+// TODO(ashithasantosh): Handle type of Ip or use seperate matchers for each
+// type. Implement Match functionality, this would require updating EvaluateArgs
+// getters, to return format of IP as well.
+class IpAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit IpAuthorizationMatcher(Rbac::CidrRange range, bool not_rule = false)
+      : range_(std::move(range)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs&) const override;
+
+ private:
+  const Rbac::CidrRange range_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Perform a match against port number of the destination (local) address.
+class PortAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit PortAuthorizationMatcher(int port, bool not_rule = false)
+      : port_(port), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  const int port_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Matches the principal name as described in the peer certificate. Uses URI SAN
+// or DNS SAN in that order, otherwise uses subject field.
+class AuthenticatedAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit AuthenticatedAuthorizationMatcher(StringMatcher auth,
+                                             bool not_rule = false)
+      : matcher_(std::move(auth)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  const StringMatcher matcher_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Perform a match against the request server from the client's connection
+// request. This is typically TLS SNI. Currently unsupported.
+class ReqServerNameAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit ReqServerNameAuthorizationMatcher(
+      StringMatcher requested_server_name, bool not_rule = false)
+      : matcher_(std::move(requested_server_name)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs&) const override;
+
+ private:
+  const StringMatcher matcher_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Perform a match against the path header of HTTP request.
+class PathAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit PathAuthorizationMatcher(StringMatcher path, bool not_rule = false)
+      : matcher_(std::move(path)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  const StringMatcher matcher_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Performs a match for policy field in RBAC, which is a collection of
+// permission and principal matchers. Policy matches iff, we find a match in one
+// of its permissions and a match in one of its principals.
+class PolicyAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit PolicyAuthorizationMatcher(Rbac::Policy policy)
+      : permissions_(
+            AuthorizationMatcher::Create(std::move(policy.permissions))),
+        principals_(
+            AuthorizationMatcher::Create(std::move(policy.principals))) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  std::unique_ptr<AuthorizationMatcher> permissions_;
+  std::unique_ptr<AuthorizationMatcher> principals_;
+};
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H
index 668956e..a081c51 100644 (file)
@@ -40,7 +40,7 @@ Rbac& Rbac::operator=(Rbac&& other) noexcept {
 std::string Rbac::ToString() const {
   std::vector<std::string> contents;
   contents.push_back(absl::StrFormat(
-      "Rbac action=%s{", action == Rbac::Action::ALLOW ? "Allow" : "Deny"));
+      "Rbac action=%s{", action == Rbac::Action::kAllow ? "Allow" : "Deny"));
   for (const auto& p : policies) {
     contents.push_back(absl::StrFormat("{\n  policy_name=%s\n%s\n}", p.first,
                                        p.second.ToString()));
@@ -100,20 +100,20 @@ Rbac::Permission::Permission(Permission::RuleType type, int port, bool not_rule)
 Rbac::Permission::Permission(Rbac::Permission&& other) noexcept
     : type(other.type), not_rule(other.not_rule) {
   switch (type) {
-    case RuleType::AND:
-    case RuleType::OR:
+    case RuleType::kAnd:
+    case RuleType::kOr:
       permissions = std::move(other.permissions);
       break;
-    case RuleType::ANY:
+    case RuleType::kAny:
       break;
-    case RuleType::HEADER:
+    case RuleType::kHeader:
       header_matcher = std::move(other.header_matcher);
       break;
-    case RuleType::PATH:
-    case RuleType::REQ_SERVER_NAME:
+    case RuleType::kPath:
+    case RuleType::kReqServerName:
       string_matcher = std::move(other.string_matcher);
       break;
-    case RuleType::DEST_IP:
+    case RuleType::kDestIp:
       ip = std::move(other.ip);
       break;
     default:
@@ -126,20 +126,20 @@ Rbac::Permission& Rbac::Permission::operator=(
   type = other.type;
   not_rule = other.not_rule;
   switch (type) {
-    case RuleType::AND:
-    case RuleType::OR:
+    case RuleType::kAnd:
+    case RuleType::kOr:
       permissions = std::move(other.permissions);
       break;
-    case RuleType::ANY:
+    case RuleType::kAny:
       break;
-    case RuleType::HEADER:
+    case RuleType::kHeader:
       header_matcher = std::move(other.header_matcher);
       break;
-    case RuleType::PATH:
-    case RuleType::REQ_SERVER_NAME:
+    case RuleType::kPath:
+    case RuleType::kReqServerName:
       string_matcher = std::move(other.string_matcher);
       break;
-    case RuleType::DEST_IP:
+    case RuleType::kDestIp:
       ip = std::move(other.ip);
       break;
     default:
@@ -150,7 +150,7 @@ Rbac::Permission& Rbac::Permission::operator=(
 
 std::string Rbac::Permission::ToString() const {
   switch (type) {
-    case RuleType::AND: {
+    case RuleType::kAnd: {
       std::vector<std::string> contents;
       contents.reserve(permissions.size());
       for (const auto& permission : permissions) {
@@ -159,7 +159,7 @@ std::string Rbac::Permission::ToString() const {
       return absl::StrFormat("%sand=[%s]", not_rule ? "not " : "",
                              absl::StrJoin(contents, ","));
     }
-    case RuleType::OR: {
+    case RuleType::kOr: {
       std::vector<std::string> contents;
       contents.reserve(permissions.size());
       for (const auto& permission : permissions) {
@@ -168,20 +168,20 @@ std::string Rbac::Permission::ToString() const {
       return absl::StrFormat("%sor=[%s]", not_rule ? "not " : "",
                              absl::StrJoin(contents, ","));
     }
-    case RuleType::ANY:
+    case RuleType::kAny:
       return absl::StrFormat("%sany", not_rule ? "not " : "");
-    case RuleType::HEADER:
+    case RuleType::kHeader:
       return absl::StrFormat("%sheader=%s", not_rule ? "not " : "",
                              header_matcher.ToString());
-    case RuleType::PATH:
+    case RuleType::kPath:
       return absl::StrFormat("%spath=%s", not_rule ? "not " : "",
                              string_matcher.ToString());
-    case RuleType::DEST_IP:
+    case RuleType::kDestIp:
       return absl::StrFormat("%sdest_ip=%s", not_rule ? "not " : "",
                              ip.ToString());
-    case RuleType::DEST_PORT:
+    case RuleType::kDestPort:
       return absl::StrFormat("%sdest_port=%d", not_rule ? "not " : "", port);
-    case RuleType::REQ_SERVER_NAME:
+    case RuleType::kReqServerName:
       return absl::StrFormat("%srequested_server_name=%s",
                              not_rule ? "not " : "", string_matcher.ToString());
     default:
@@ -216,17 +216,17 @@ Rbac::Principal::Principal(Principal::RuleType type,
 Rbac::Principal::Principal(Rbac::Principal&& other) noexcept
     : type(other.type), not_rule(other.not_rule) {
   switch (type) {
-    case RuleType::AND:
-    case RuleType::OR:
+    case RuleType::kAnd:
+    case RuleType::kOr:
       principals = std::move(other.principals);
       break;
-    case RuleType::ANY:
+    case RuleType::kAny:
       break;
-    case RuleType::HEADER:
+    case RuleType::kHeader:
       header_matcher = std::move(other.header_matcher);
       break;
-    case RuleType::PRINCIPAL_NAME:
-    case RuleType::PATH:
+    case RuleType::kPrincipalName:
+    case RuleType::kPath:
       string_matcher = std::move(other.string_matcher);
       break;
     default:
@@ -238,17 +238,17 @@ Rbac::Principal& Rbac::Principal::operator=(Rbac::Principal&& other) noexcept {
   type = other.type;
   not_rule = other.not_rule;
   switch (type) {
-    case RuleType::AND:
-    case RuleType::OR:
+    case RuleType::kAnd:
+    case RuleType::kOr:
       principals = std::move(other.principals);
       break;
-    case RuleType::ANY:
+    case RuleType::kAny:
       break;
-    case RuleType::HEADER:
+    case RuleType::kHeader:
       header_matcher = std::move(other.header_matcher);
       break;
-    case RuleType::PRINCIPAL_NAME:
-    case RuleType::PATH:
+    case RuleType::kPrincipalName:
+    case RuleType::kPath:
       string_matcher = std::move(other.string_matcher);
       break;
     default:
@@ -259,7 +259,7 @@ Rbac::Principal& Rbac::Principal::operator=(Rbac::Principal&& other) noexcept {
 
 std::string Rbac::Principal::ToString() const {
   switch (type) {
-    case RuleType::AND: {
+    case RuleType::kAnd: {
       std::vector<std::string> contents;
       contents.reserve(principals.size());
       for (const auto& principal : principals) {
@@ -268,7 +268,7 @@ std::string Rbac::Principal::ToString() const {
       return absl::StrFormat("%sand=[%s]", not_rule ? "not " : "",
                              absl::StrJoin(contents, ","));
     }
-    case RuleType::OR: {
+    case RuleType::kOr: {
       std::vector<std::string> contents;
       contents.reserve(principals.size());
       for (const auto& principal : principals) {
@@ -277,24 +277,24 @@ std::string Rbac::Principal::ToString() const {
       return absl::StrFormat("%sor=[%s]", not_rule ? "not " : "",
                              absl::StrJoin(contents, ","));
     }
-    case RuleType::ANY:
+    case RuleType::kAny:
       return absl::StrFormat("%sany", not_rule ? "not " : "");
-    case RuleType::PRINCIPAL_NAME:
+    case RuleType::kPrincipalName:
       return absl::StrFormat("%sprincipal_name=%s", not_rule ? "not " : "",
                              string_matcher.ToString());
-    case RuleType::SOURCE_IP:
+    case RuleType::kSourceIp:
       return absl::StrFormat("%ssource_ip=%s", not_rule ? "not " : "",
                              ip.ToString());
-    case RuleType::DIRECT_REMOTE_IP:
+    case RuleType::kDirectRemoteIp:
       return absl::StrFormat("%sdirect_remote_ip=%s", not_rule ? "not " : "",
                              ip.ToString());
-    case RuleType::REMOTE_IP:
+    case RuleType::kRemoteIp:
       return absl::StrFormat("%sremote_ip=%s", not_rule ? "not " : "",
                              ip.ToString());
-    case RuleType::HEADER:
+    case RuleType::kHeader:
       return absl::StrFormat("%sheader=%s", not_rule ? "not " : "",
                              header_matcher.ToString());
-    case RuleType::PATH:
+    case RuleType::kPath:
       return absl::StrFormat("%spath=%s", not_rule ? "not " : "",
                              string_matcher.ToString());
     default:
index ccb9dbb..027bf92 100644 (file)
@@ -27,8 +27,8 @@ namespace grpc_core {
 // https://github.com/envoyproxy/envoy/blob/release/v1.17/api/envoy/config/rbac/v3/rbac.proto]
 struct Rbac {
   enum class Action {
-    ALLOW,
-    DENY,
+    kAllow,
+    kDeny,
   };
 
   struct CidrRange {
@@ -47,14 +47,14 @@ struct Rbac {
   // TODO(ashithasantosh): Add metadata field to Permission and Principal.
   struct Permission {
     enum class RuleType {
-      AND,
-      OR,
-      ANY,
-      HEADER,
-      PATH,
-      DEST_IP,
-      DEST_PORT,
-      REQ_SERVER_NAME,
+      kAnd,
+      kOr,
+      kAny,
+      kHeader,
+      kPath,
+      kDestIp,
+      kDestPort,
+      kReqServerName,
     };
 
     Permission() = default;
@@ -92,15 +92,15 @@ struct Rbac {
 
   struct Principal {
     enum class RuleType {
-      AND,
-      OR,
-      ANY,
-      PRINCIPAL_NAME,
-      SOURCE_IP,
-      DIRECT_REMOTE_IP,
-      REMOTE_IP,
-      HEADER,
-      PATH,
+      kAnd,
+      kOr,
+      kAny,
+      kPrincipalName,
+      kSourceIp,
+      kDirectRemoteIp,
+      kRemoteIp,
+      kHeader,
+      kPath,
     };
 
     Principal() = default;
index 093a4b0..ea5599d 100644 (file)
@@ -29,16 +29,16 @@ namespace {
 absl::string_view GetMatcherType(absl::string_view value,
                                  StringMatcher::Type* type) {
   if (value == "*") {
-    *type = StringMatcher::Type::PREFIX;
+    *type = StringMatcher::Type::kPrefix;
     return "";
   } else if (absl::StartsWith(value, "*")) {
-    *type = StringMatcher::Type::SUFFIX;
+    *type = StringMatcher::Type::kSuffix;
     return absl::StripPrefix(value, "*");
   } else if (absl::EndsWith(value, "*")) {
-    *type = StringMatcher::Type::PREFIX;
+    *type = StringMatcher::Type::kPrefix;
     return absl::StripSuffix(value, "*");
   }
-  *type = StringMatcher::Type::EXACT;
+  *type = StringMatcher::Type::kExact;
   return value;
 }
 
@@ -71,10 +71,10 @@ absl::StatusOr<Rbac::Principal> ParsePrincipalsArray(const Json& json) {
                                        matcher_or.status().message()));
     }
     principal_names.push_back(absl::make_unique<Rbac::Principal>(
-        Rbac::Principal::RuleType::PRINCIPAL_NAME,
+        Rbac::Principal::RuleType::kPrincipalName,
         std::move(matcher_or.value())));
   }
-  return Rbac::Principal(Rbac::Principal::RuleType::OR,
+  return Rbac::Principal(Rbac::Principal::RuleType::kOr,
                          std::move(principal_names));
 }
 
@@ -93,9 +93,9 @@ absl::StatusOr<Rbac::Principal> ParsePeer(const Json& json) {
     }
   }
   if (peer.empty()) {
-    return Rbac::Principal(Rbac::Principal::RuleType::ANY);
+    return Rbac::Principal(Rbac::Principal::RuleType::kAny);
   }
-  return Rbac::Principal(Rbac::Principal::RuleType::AND, std::move(peer));
+  return Rbac::Principal(Rbac::Principal::RuleType::kAnd, std::move(peer));
 }
 
 absl::StatusOr<Rbac::Permission> ParseHeaderValues(
@@ -117,9 +117,9 @@ absl::StatusOr<Rbac::Permission> ParseHeaderValues(
           absl::StrCat("\"values\" ", i, ": ", matcher_or.status().message()));
     }
     values.push_back(absl::make_unique<Rbac::Permission>(
-        Rbac::Permission::RuleType::HEADER, std::move(matcher_or.value())));
+        Rbac::Permission::RuleType::kHeader, std::move(matcher_or.value())));
   }
-  return Rbac::Permission(Rbac::Permission::RuleType::OR, std::move(values));
+  return Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(values));
 }
 
 absl::StatusOr<Rbac::Permission> ParseHeaders(const Json& json) {
@@ -165,7 +165,7 @@ absl::StatusOr<Rbac::Permission> ParseHeadersArray(const Json& json) {
     headers.push_back(
         absl::make_unique<Rbac::Permission>(std::move(headers_or.value())));
   }
-  return Rbac::Permission(Rbac::Permission::RuleType::AND, std::move(headers));
+  return Rbac::Permission(Rbac::Permission::RuleType::kAnd, std::move(headers));
 }
 
 absl::StatusOr<Rbac::Permission> ParsePathsArray(const Json& json) {
@@ -183,9 +183,9 @@ absl::StatusOr<Rbac::Permission> ParsePathsArray(const Json& json) {
           absl::StrCat("\"paths\" ", i, ": ", matcher_or.status().message()));
     }
     paths.push_back(absl::make_unique<Rbac::Permission>(
-        Rbac::Permission::RuleType::PATH, std::move(matcher_or.value())));
+        Rbac::Permission::RuleType::kPath, std::move(matcher_or.value())));
   }
-  return Rbac::Permission(Rbac::Permission::RuleType::OR, std::move(paths));
+  return Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(paths));
 }
 
 absl::StatusOr<Rbac::Permission> ParseRequest(const Json& json) {
@@ -215,9 +215,9 @@ absl::StatusOr<Rbac::Permission> ParseRequest(const Json& json) {
     }
   }
   if (request.empty()) {
-    return Rbac::Permission(Rbac::Permission::RuleType::ANY);
+    return Rbac::Permission(Rbac::Permission::RuleType::kAny);
   }
-  return Rbac::Permission(Rbac::Permission::RuleType::AND, std::move(request));
+  return Rbac::Permission(Rbac::Permission::RuleType::kAnd, std::move(request));
 }
 
 absl::StatusOr<Rbac::Policy> ParseRules(const Json& json) {
@@ -231,7 +231,7 @@ absl::StatusOr<Rbac::Policy> ParseRules(const Json& json) {
     if (!peer_or.ok()) return peer_or.status();
     principals = std::move(peer_or.value());
   } else {
-    principals = Rbac::Principal(Rbac::Principal::RuleType::ANY);
+    principals = Rbac::Principal(Rbac::Principal::RuleType::kAny);
   }
   Rbac::Permission permissions;
   it = json.object_value().find("request");
@@ -243,7 +243,7 @@ absl::StatusOr<Rbac::Policy> ParseRules(const Json& json) {
     if (!request_or.ok()) return request_or.status();
     permissions = std::move(request_or.value());
   } else {
-    permissions = Rbac::Permission(Rbac::Permission::RuleType::ANY);
+    permissions = Rbac::Permission(Rbac::Permission::RuleType::kAny);
   }
   return Rbac::Policy(std::move(permissions), std::move(principals));
 }
@@ -283,26 +283,26 @@ absl::StatusOr<Rbac> ParseDenyRulesArray(const Json& json,
                                          absl::string_view name) {
   auto policies_or = ParseRulesArray(json, name);
   if (!policies_or.ok()) return policies_or.status();
-  return Rbac(Rbac::Action::DENY, std::move(policies_or.value()));
+  return Rbac(Rbac::Action::kDeny, std::move(policies_or.value()));
 }
 
 absl::StatusOr<Rbac> ParseAllowRulesArray(const Json& json,
                                           absl::string_view name) {
   auto policies_or = ParseRulesArray(json, name);
   if (!policies_or.ok()) return policies_or.status();
-  return Rbac(Rbac::Action::ALLOW, std::move(policies_or.value()));
+  return Rbac(Rbac::Action::kAllow, std::move(policies_or.value()));
 }
 
 }  // namespace
 
 absl::StatusOr<RbacPolicies> GenerateRbacPolicies(
     absl::string_view authz_policy) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(authz_policy, &error);
   if (error != GRPC_ERROR_NONE) {
     absl::Status status = absl::InvalidArgumentError(
         absl::StrCat("Failed to parse SDK authorization policy. Error: ",
-                     grpc_error_string(error)));
+                     grpc_error_std_string(error)));
     GRPC_ERROR_UNREF(error);
     return status;
   }
@@ -332,7 +332,7 @@ absl::StatusOr<RbacPolicies> GenerateRbacPolicies(
     }
     rbac_policies.deny_policy = std::move(deny_policy_or.value());
   } else {
-    rbac_policies.deny_policy.action = Rbac::Action::DENY;
+    rbac_policies.deny_policy.action = Rbac::Action::kDeny;
   }
   it = json.mutable_object()->find("allow_rules");
   if (it == json.mutable_object()->end()) {
index bccc034..5543ad1 100644 (file)
@@ -36,7 +36,7 @@
 
 /* -- Composite call credentials. -- */
 
-static void composite_call_metadata_cb(void* arg, grpc_error* error);
+static void composite_call_metadata_cb(void* arg, grpc_error_handle error);
 
 namespace {
 struct grpc_composite_call_credentials_metadata_context {
@@ -64,7 +64,7 @@ struct grpc_composite_call_credentials_metadata_context {
 };
 }  // namespace
 
-static void composite_call_metadata_cb(void* arg, grpc_error* error) {
+static void composite_call_metadata_cb(void* arg, grpc_error_handle error) {
   grpc_composite_call_credentials_metadata_context* ctx =
       static_cast<grpc_composite_call_credentials_metadata_context*>(arg);
   if (error == GRPC_ERROR_NONE) {
@@ -91,7 +91,7 @@ static void composite_call_metadata_cb(void* arg, grpc_error* error) {
 bool grpc_composite_call_credentials::get_request_metadata(
     grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
     grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
-    grpc_error** error) {
+    grpc_error_handle* error) {
   grpc_composite_call_credentials_metadata_context* ctx;
   ctx = new grpc_composite_call_credentials_metadata_context(
       this, pollent, auth_md_context, md_array, on_request_metadata);
@@ -112,7 +112,7 @@ bool grpc_composite_call_credentials::get_request_metadata(
 }
 
 void grpc_composite_call_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* md_array, grpc_error* error) {
+    grpc_credentials_mdelem_array* md_array, grpc_error_handle error) {
   for (size_t i = 0; i < inner_.size(); ++i) {
     inner_[i]->cancel_get_request_metadata(md_array, GRPC_ERROR_REF(error));
   }
index 6b9e9d1..8634627 100644 (file)
@@ -83,10 +83,10 @@ class grpc_composite_call_credentials : public grpc_call_credentials {
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   grpc_security_level min_security_level() const override {
     return min_security_level_;
index cf9f402..b8609c5 100644 (file)
@@ -187,13 +187,13 @@ struct grpc_call_credentials
                                     grpc_auth_metadata_context context,
                                     grpc_credentials_mdelem_array* md_array,
                                     grpc_closure* on_request_metadata,
-                                    grpc_error** error) = 0;
+                                    grpc_error_handle* error) = 0;
 
   // Cancels a pending asynchronous operation started by
   // grpc_call_credentials_get_request_metadata() with the corresponding
   // value of \a md_array.
   virtual void cancel_get_request_metadata(
-      grpc_credentials_mdelem_array* md_array, grpc_error* error) = 0;
+      grpc_credentials_mdelem_array* md_array, grpc_error_handle error) = 0;
 
   virtual grpc_security_level min_security_level() const {
     return min_security_level_;
index 3ad09d2..c479bf0 100644 (file)
@@ -30,6 +30,7 @@ namespace {
 const char* kExpectedEnvironmentId = "aws1";
 
 const char* kRegionEnvVar = "AWS_REGION";
+const char* kDefaultRegionEnvVar = "AWS_DEFAULT_REGION";
 const char* kAccessKeyIdEnvVar = "AWS_ACCESS_KEY_ID";
 const char* kSecretAccessKeyEnvVar = "AWS_SECRET_ACCESS_KEY";
 const char* kSessionTokenEnvVar = "AWS_SESSION_TOKEN";
@@ -57,7 +58,7 @@ std::string UrlEncode(const absl::string_view& s) {
 RefCountedPtr<AwsExternalAccountCredentials>
 AwsExternalAccountCredentials::Create(Options options,
                                       std::vector<std::string> scopes,
-                                      grpc_error** error) {
+                                      grpc_error_handle* error) {
   auto creds = MakeRefCounted<AwsExternalAccountCredentials>(
       std::move(options), std::move(scopes), error);
   if (*error == GRPC_ERROR_NONE) {
@@ -68,7 +69,7 @@ AwsExternalAccountCredentials::Create(Options options,
 }
 
 AwsExternalAccountCredentials::AwsExternalAccountCredentials(
-    Options options, std::vector<std::string> scopes, grpc_error** error)
+    Options options, std::vector<std::string> scopes, grpc_error_handle* error)
     : ExternalAccountCredentials(options, std::move(scopes)) {
   audience_ = options.audience;
   auto it = options.credential_source.object_value().find("environment_id");
@@ -121,7 +122,7 @@ AwsExternalAccountCredentials::AwsExternalAccountCredentials(
 
 void AwsExternalAccountCredentials::RetrieveSubjectToken(
     HTTPRequestContext* ctx, const Options& /*options*/,
-    std::function<void(std::string, grpc_error*)> cb) {
+    std::function<void(std::string, grpc_error_handle)> cb) {
   if (ctx == nullptr) {
     FinishRetrieveSubjectToken(
         "",
@@ -140,6 +141,9 @@ void AwsExternalAccountCredentials::RetrieveSubjectToken(
 
 void AwsExternalAccountCredentials::RetrieveRegion() {
   UniquePtr<char> region_from_env(gpr_getenv(kRegionEnvVar));
+  if (region_from_env == nullptr) {
+    region_from_env = UniquePtr<char>(gpr_getenv(kDefaultRegionEnvVar));
+  }
   if (region_from_env != nullptr) {
     region_ = std::string(region_from_env.get());
     if (url_.empty()) {
@@ -175,14 +179,14 @@ void AwsExternalAccountCredentials::RetrieveRegion() {
 }
 
 void AwsExternalAccountCredentials::OnRetrieveRegion(void* arg,
-                                                     grpc_error* error) {
+                                                     grpc_error_handle error) {
   AwsExternalAccountCredentials* self =
       static_cast<AwsExternalAccountCredentials*>(arg);
   self->OnRetrieveRegionInternal(GRPC_ERROR_REF(error));
 }
 
 void AwsExternalAccountCredentials::OnRetrieveRegionInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishRetrieveSubjectToken("", error);
     return;
@@ -224,15 +228,15 @@ void AwsExternalAccountCredentials::RetrieveRoleName() {
   grpc_http_request_destroy(&request.http);
 }
 
-void AwsExternalAccountCredentials::OnRetrieveRoleName(void* arg,
-                                                       grpc_error* error) {
+void AwsExternalAccountCredentials::OnRetrieveRoleName(
+    void* arg, grpc_error_handle error) {
   AwsExternalAccountCredentials* self =
       static_cast<AwsExternalAccountCredentials*>(arg);
   self->OnRetrieveRoleNameInternal(GRPC_ERROR_REF(error));
 }
 
 void AwsExternalAccountCredentials::OnRetrieveRoleNameInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishRetrieveSubjectToken("", error);
     return;
@@ -287,15 +291,15 @@ void AwsExternalAccountCredentials::RetrieveSigningKeys() {
   grpc_http_request_destroy(&request.http);
 }
 
-void AwsExternalAccountCredentials::OnRetrieveSigningKeys(void* arg,
-                                                          grpc_error* error) {
+void AwsExternalAccountCredentials::OnRetrieveSigningKeys(
+    void* arg, grpc_error_handle error) {
   AwsExternalAccountCredentials* self =
       static_cast<AwsExternalAccountCredentials*>(arg);
   self->OnRetrieveSigningKeysInternal(GRPC_ERROR_REF(error));
 }
 
 void AwsExternalAccountCredentials::OnRetrieveSigningKeysInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishRetrieveSubjectToken("", error);
     return;
@@ -350,7 +354,7 @@ void AwsExternalAccountCredentials::OnRetrieveSigningKeysInternal(
 }
 
 void AwsExternalAccountCredentials::BuildSubjectToken() {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (signer_ == nullptr) {
     cred_verification_url_ = absl::StrReplaceAll(
         regional_cred_verification_url_, {{"{region}", region_}});
@@ -396,7 +400,7 @@ void AwsExternalAccountCredentials::BuildSubjectToken() {
 }
 
 void AwsExternalAccountCredentials::FinishRetrieveSubjectToken(
-    std::string subject_token, grpc_error* error) {
+    std::string subject_token, grpc_error_handle error) {
   // Reset context
   ctx_ = nullptr;
   // Move object state into local variables.
index edb7e82..50ccf19 100644 (file)
@@ -28,31 +28,33 @@ namespace grpc_core {
 class AwsExternalAccountCredentials final : public ExternalAccountCredentials {
  public:
   static RefCountedPtr<AwsExternalAccountCredentials> Create(
-      Options options, std::vector<std::string> scopes, grpc_error** error);
+      Options options, std::vector<std::string> scopes,
+      grpc_error_handle* error);
 
   AwsExternalAccountCredentials(Options options,
                                 std::vector<std::string> scopes,
-                                grpc_error** error);
+                                grpc_error_handle* error);
 
  private:
   void RetrieveSubjectToken(
       HTTPRequestContext* ctx, const Options& options,
-      std::function<void(std::string, grpc_error*)> cb) override;
+      std::function<void(std::string, grpc_error_handle)> cb) override;
 
   void RetrieveRegion();
-  static void OnRetrieveRegion(void* arg, grpc_error* error);
-  void OnRetrieveRegionInternal(grpc_error* error);
+  static void OnRetrieveRegion(void* arg, grpc_error_handle error);
+  void OnRetrieveRegionInternal(grpc_error_handle error);
 
   void RetrieveRoleName();
-  static void OnRetrieveRoleName(void* arg, grpc_error* error);
-  void OnRetrieveRoleNameInternal(grpc_error* error);
+  static void OnRetrieveRoleName(void* arg, grpc_error_handle error);
+  void OnRetrieveRoleNameInternal(grpc_error_handle error);
 
   void RetrieveSigningKeys();
-  static void OnRetrieveSigningKeys(void* arg, grpc_error* error);
-  void OnRetrieveSigningKeysInternal(grpc_error* error);
+  static void OnRetrieveSigningKeys(void* arg, grpc_error_handle error);
+  void OnRetrieveSigningKeysInternal(grpc_error_handle error);
 
   void BuildSubjectToken();
-  void FinishRetrieveSubjectToken(std::string subject_token, grpc_error* error);
+  void FinishRetrieveSubjectToken(std::string subject_token,
+                                  grpc_error_handle error);
 
   std::string audience_;
 
@@ -72,7 +74,7 @@ class AwsExternalAccountCredentials final : public ExternalAccountCredentials {
   std::string cred_verification_url_;
 
   HTTPRequestContext* ctx_ = nullptr;
-  std::function<void(std::string, grpc_error*)> cb_ = nullptr;
+  std::function<void(std::string, grpc_error_handle)> cb_ = nullptr;
 };
 
 }  // namespace grpc_core
index af8531e..b665701 100644 (file)
@@ -66,7 +66,8 @@ AwsRequestSigner::AwsRequestSigner(
     std::string access_key_id, std::string secret_access_key, std::string token,
     std::string method, std::string url, std::string region,
     std::string request_payload,
-    std::map<std::string, std::string> additional_headers, grpc_error** error)
+    std::map<std::string, std::string> additional_headers,
+    grpc_error_handle* error)
     : access_key_id_(std::move(access_key_id)),
       secret_access_key_(std::move(secret_access_key)),
       token_(std::move(token)),
index 62e112c..22c4ad6 100644 (file)
@@ -45,7 +45,7 @@ class AwsRequestSigner {
                    std::string token, std::string method, std::string url,
                    std::string region, std::string request_payload,
                    std::map<std::string, std::string> additional_headers,
-                   grpc_error** error);
+                   grpc_error_handle* error);
 
   // This method triggers the signing process then returns the headers of the
   // signed request as a map. In case there is an error, the input `error`
index 0b9fc19..f5d9442 100644 (file)
@@ -63,7 +63,8 @@ std::string UrlEncode(const absl::string_view& s) {
 }  // namespace
 
 RefCountedPtr<ExternalAccountCredentials> ExternalAccountCredentials::Create(
-    const Json& json, std::vector<std::string> scopes, grpc_error** error) {
+    const Json& json, std::vector<std::string> scopes,
+    grpc_error_handle* error) {
   GPR_ASSERT(*error == GRPC_ERROR_NONE);
   Options options;
   options.type = GRPC_AUTH_JSON_TYPE_INVALID;
@@ -213,14 +214,14 @@ void ExternalAccountCredentials::fetch_oauth2(
   ctx_ = new HTTPRequestContext(httpcli_context, pollent, deadline);
   metadata_req_ = metadata_req;
   response_cb_ = response_cb;
-  auto cb = [this](std::string token, grpc_error* error) {
+  auto cb = [this](std::string token, grpc_error_handle error) {
     OnRetrieveSubjectTokenInternal(token, error);
   };
   RetrieveSubjectToken(ctx_, options_, cb);
 }
 
 void ExternalAccountCredentials::OnRetrieveSubjectTokenInternal(
-    absl::string_view subject_token, grpc_error* error) {
+    absl::string_view subject_token, grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishTokenFetch(error);
   } else {
@@ -300,13 +301,15 @@ void ExternalAccountCredentials::ExchangeToken(
   grpc_http_request_destroy(&request.http);
 }
 
-void ExternalAccountCredentials::OnExchangeToken(void* arg, grpc_error* error) {
+void ExternalAccountCredentials::OnExchangeToken(void* arg,
+                                                 grpc_error_handle error) {
   ExternalAccountCredentials* self =
       static_cast<ExternalAccountCredentials*>(arg);
   self->OnExchangeTokenInternal(GRPC_ERROR_REF(error));
 }
 
-void ExternalAccountCredentials::OnExchangeTokenInternal(grpc_error* error) {
+void ExternalAccountCredentials::OnExchangeTokenInternal(
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishTokenFetch(error);
   } else {
@@ -330,7 +333,7 @@ void ExternalAccountCredentials::OnExchangeTokenInternal(grpc_error* error) {
 }
 
 void ExternalAccountCredentials::ImpersenateServiceAccount() {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   absl::string_view response_body(ctx_->response.body,
                                   ctx_->response.body_length);
   Json json = Json::Parse(response_body, &error);
@@ -389,14 +392,14 @@ void ExternalAccountCredentials::ImpersenateServiceAccount() {
 }
 
 void ExternalAccountCredentials::OnImpersenateServiceAccount(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   ExternalAccountCredentials* self =
       static_cast<ExternalAccountCredentials*>(arg);
   self->OnImpersenateServiceAccountInternal(GRPC_ERROR_REF(error));
 }
 
 void ExternalAccountCredentials::OnImpersenateServiceAccountInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishTokenFetch(error);
     return;
@@ -452,7 +455,7 @@ void ExternalAccountCredentials::OnImpersenateServiceAccountInternal(
   FinishTokenFetch(GRPC_ERROR_NONE);
 }
 
-void ExternalAccountCredentials::FinishTokenFetch(grpc_error* error) {
+void ExternalAccountCredentials::FinishTokenFetch(grpc_error_handle error) {
   GRPC_LOG_IF_ERROR("Fetch external account credentials access token",
                     GRPC_ERROR_REF(error));
   // Move object state into local variables.
@@ -473,12 +476,12 @@ void ExternalAccountCredentials::FinishTokenFetch(grpc_error* error) {
 
 grpc_call_credentials* grpc_external_account_credentials_create(
     const char* json_string, const char* scopes_string) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json json = grpc_core::Json::Parse(json_string, &error);
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "External account credentials creation failed. Error: %s.",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return nullptr;
   }
@@ -489,7 +492,7 @@ grpc_call_credentials* grpc_external_account_credentials_create(
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "External account credentials creation failed. Error: %s.",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return nullptr;
   }
index 0da7786..3c00096 100644 (file)
@@ -49,7 +49,8 @@ class ExternalAccountCredentials
   };
 
   static RefCountedPtr<ExternalAccountCredentials> Create(
-      const Json& json, std::vector<std::string> scopes, grpc_error** error);
+      const Json& json, std::vector<std::string> scopes,
+      grpc_error_handle* error);
 
   ExternalAccountCredentials(Options options, std::vector<std::string> scopes);
   ~ExternalAccountCredentials() override;
@@ -84,7 +85,7 @@ class ExternalAccountCredentials
   // back.
   virtual void RetrieveSubjectToken(
       HTTPRequestContext* ctx, const Options& options,
-      std::function<void(std::string, grpc_error*)> cb) = 0;
+      std::function<void(std::string, grpc_error_handle)> cb) = 0;
 
  private:
   // This method implements the common token fetch logic and it will be called
@@ -95,17 +96,17 @@ class ExternalAccountCredentials
                     grpc_millis deadline) override;
 
   void OnRetrieveSubjectTokenInternal(absl::string_view subject_token,
-                                      grpc_error* error);
+                                      grpc_error_handle error);
 
   void ExchangeToken(absl::string_view subject_token);
-  static void OnExchangeToken(void* arg, grpc_error* error);
-  void OnExchangeTokenInternal(grpc_error* error);
+  static void OnExchangeToken(void* arg, grpc_error_handle error);
+  void OnExchangeTokenInternal(grpc_error_handle error);
 
   void ImpersenateServiceAccount();
-  static void OnImpersenateServiceAccount(void* arg, grpc_error* error);
-  void OnImpersenateServiceAccountInternal(grpc_error* error);
+  static void OnImpersenateServiceAccount(void* arg, grpc_error_handle error);
+  void OnImpersenateServiceAccountInternal(grpc_error_handle error);
 
-  void FinishTokenFetch(grpc_error* error);
+  void FinishTokenFetch(grpc_error_handle error);
 
   Options options_;
   std::vector<std::string> scopes_;
index ec2cd60..d596d29 100644 (file)
@@ -28,7 +28,7 @@ namespace grpc_core {
 RefCountedPtr<FileExternalAccountCredentials>
 FileExternalAccountCredentials::Create(Options options,
                                        std::vector<std::string> scopes,
-                                       grpc_error** error) {
+                                       grpc_error_handle* error) {
   auto creds = MakeRefCounted<FileExternalAccountCredentials>(
       std::move(options), std::move(scopes), error);
   if (*error == GRPC_ERROR_NONE) {
@@ -39,7 +39,7 @@ FileExternalAccountCredentials::Create(Options options,
 }
 
 FileExternalAccountCredentials::FileExternalAccountCredentials(
-    Options options, std::vector<std::string> scopes, grpc_error** error)
+    Options options, std::vector<std::string> scopes, grpc_error_handle* error)
     : ExternalAccountCredentials(options, std::move(scopes)) {
   auto it = options.credential_source.object_value().find("file");
   if (it == options.credential_source.object_value().end()) {
@@ -92,7 +92,7 @@ FileExternalAccountCredentials::FileExternalAccountCredentials(
 
 void FileExternalAccountCredentials::RetrieveSubjectToken(
     HTTPRequestContext* /*ctx*/, const Options& /*options*/,
-    std::function<void(std::string, grpc_error*)> cb) {
+    std::function<void(std::string, grpc_error_handle)> cb) {
   struct SliceWrapper {
     ~SliceWrapper() { grpc_slice_unref_internal(slice); }
     grpc_slice slice = grpc_empty_slice();
@@ -100,7 +100,8 @@ void FileExternalAccountCredentials::RetrieveSubjectToken(
   SliceWrapper content_slice;
   // To retrieve the subject token, we read the file every time we make a
   // request because it may have changed since the last request.
-  grpc_error* error = grpc_load_file(file_.c_str(), 0, &content_slice.slice);
+  grpc_error_handle error =
+      grpc_load_file(file_.c_str(), 0, &content_slice.slice);
   if (error != GRPC_ERROR_NONE) {
     cb("", error);
     return;
index 7df5b6b..23a6b6d 100644 (file)
@@ -26,16 +26,17 @@ namespace grpc_core {
 class FileExternalAccountCredentials final : public ExternalAccountCredentials {
  public:
   static RefCountedPtr<FileExternalAccountCredentials> Create(
-      Options options, std::vector<std::string> scopes, grpc_error** error);
+      Options options, std::vector<std::string> scopes,
+      grpc_error_handle* error);
 
   FileExternalAccountCredentials(Options options,
                                  std::vector<std::string> scopes,
-                                 grpc_error** error);
+                                 grpc_error_handle* error);
 
  private:
   void RetrieveSubjectToken(
       HTTPRequestContext* ctx, const Options& options,
-      std::function<void(std::string, grpc_error*)> cb) override;
+      std::function<void(std::string, grpc_error_handle)> cb) override;
 
   // Fields of credential source
   std::string file_;
index 2fa42cb..55151b9 100644 (file)
@@ -26,7 +26,7 @@ namespace grpc_core {
 RefCountedPtr<UrlExternalAccountCredentials>
 UrlExternalAccountCredentials::Create(Options options,
                                       std::vector<std::string> scopes,
-                                      grpc_error** error) {
+                                      grpc_error_handle* error) {
   auto creds = MakeRefCounted<UrlExternalAccountCredentials>(
       std::move(options), std::move(scopes), error);
   if (*error == GRPC_ERROR_NONE) {
@@ -37,7 +37,7 @@ UrlExternalAccountCredentials::Create(Options options,
 }
 
 UrlExternalAccountCredentials::UrlExternalAccountCredentials(
-    Options options, std::vector<std::string> scopes, grpc_error** error)
+    Options options, std::vector<std::string> scopes, grpc_error_handle* error)
     : ExternalAccountCredentials(options, std::move(scopes)) {
   auto it = options.credential_source.object_value().find("url");
   if (it == options.credential_source.object_value().end()) {
@@ -113,7 +113,7 @@ UrlExternalAccountCredentials::UrlExternalAccountCredentials(
 
 void UrlExternalAccountCredentials::RetrieveSubjectToken(
     HTTPRequestContext* ctx, const Options& /*options*/,
-    std::function<void(std::string, grpc_error*)> cb) {
+    std::function<void(std::string, grpc_error_handle)> cb) {
   if (ctx == nullptr) {
     FinishRetrieveSubjectToken(
         "",
@@ -151,15 +151,15 @@ void UrlExternalAccountCredentials::RetrieveSubjectToken(
   grpc_http_request_destroy(&request.http);
 }
 
-void UrlExternalAccountCredentials::OnRetrieveSubjectToken(void* arg,
-                                                           grpc_error* error) {
+void UrlExternalAccountCredentials::OnRetrieveSubjectToken(
+    void* arg, grpc_error_handle error) {
   UrlExternalAccountCredentials* self =
       static_cast<UrlExternalAccountCredentials*>(arg);
   self->OnRetrieveSubjectTokenInternal(GRPC_ERROR_REF(error));
 }
 
 void UrlExternalAccountCredentials::OnRetrieveSubjectTokenInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishRetrieveSubjectToken("", error);
     return;
@@ -167,7 +167,7 @@ void UrlExternalAccountCredentials::OnRetrieveSubjectTokenInternal(
   absl::string_view response_body(ctx_->response.body,
                                   ctx_->response.body_length);
   if (format_type_ == "json") {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     Json response_json = Json::Parse(response_body, &error);
     if (error != GRPC_ERROR_NONE ||
         response_json.type() != Json::Type::OBJECT) {
@@ -196,7 +196,7 @@ void UrlExternalAccountCredentials::OnRetrieveSubjectTokenInternal(
 }
 
 void UrlExternalAccountCredentials::FinishRetrieveSubjectToken(
-    std::string subject_token, grpc_error* error) {
+    std::string subject_token, grpc_error_handle error) {
   // Reset context
   ctx_ = nullptr;
   // Move object state into local variables.
index 4e37c57..eaf984c 100644 (file)
@@ -26,21 +26,23 @@ namespace grpc_core {
 class UrlExternalAccountCredentials final : public ExternalAccountCredentials {
  public:
   static RefCountedPtr<UrlExternalAccountCredentials> Create(
-      Options options, std::vector<std::string> scopes, grpc_error** error);
+      Options options, std::vector<std::string> scopes,
+      grpc_error_handle* error);
 
   UrlExternalAccountCredentials(Options options,
                                 std::vector<std::string> scopes,
-                                grpc_error** error);
+                                grpc_error_handle* error);
 
  private:
   void RetrieveSubjectToken(
       HTTPRequestContext* ctx, const Options& options,
-      std::function<void(std::string, grpc_error*)> cb) override;
+      std::function<void(std::string, grpc_error_handle)> cb) override;
 
-  static void OnRetrieveSubjectToken(void* arg, grpc_error* error);
-  void OnRetrieveSubjectTokenInternal(grpc_error* error);
+  static void OnRetrieveSubjectToken(void* arg, grpc_error_handle error);
+  void OnRetrieveSubjectTokenInternal(grpc_error_handle error);
 
-  void FinishRetrieveSubjectToken(std::string subject_token, grpc_error* error);
+  void FinishRetrieveSubjectToken(std::string subject_token,
+                                  grpc_error_handle error);
 
   // Fields of credential source
   URI url_;
@@ -50,7 +52,7 @@ class UrlExternalAccountCredentials final : public ExternalAccountCredentials {
   std::string format_subject_token_field_name_;
 
   HTTPRequestContext* ctx_ = nullptr;
-  std::function<void(std::string, grpc_error*)> cb_ = nullptr;
+  std::function<void(std::string, grpc_error_handle)> cb_ = nullptr;
 };
 
 }  // namespace grpc_core
index c439282..57a897f 100644 (file)
@@ -92,7 +92,7 @@ const char* grpc_fake_transport_get_expected_targets(
 bool grpc_md_only_test_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context /*context*/,
     grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
-    grpc_error** /*error*/) {
+    grpc_error_handle* /*error*/) {
   grpc_credentials_mdelem_array_add(md_array, md_);
   if (is_async_) {
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_request_metadata,
@@ -103,7 +103,7 @@ bool grpc_md_only_test_credentials::get_request_metadata(
 }
 
 void grpc_md_only_test_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* /*md_array*/, grpc_error* error) {
+    grpc_credentials_mdelem_array* /*md_array*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
index 3c2449f..ea8c813 100644 (file)
@@ -72,10 +72,10 @@ class grpc_md_only_test_credentials : public grpc_call_credentials {
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   std::string debug_string() override { return "MD only Test Credentials"; };
 
index 1909934..0e1a2a1 100644 (file)
@@ -134,8 +134,8 @@ grpc_channel_args* grpc_google_default_channel_credentials::update_arguments(
   return updated;
 }
 
-static void on_metadata_server_detection_http_response(void* user_data,
-                                                       grpc_error* error) {
+static void on_metadata_server_detection_http_response(
+    void* user_data, grpc_error_handle error) {
   metadata_server_detector* detector =
       static_cast<metadata_server_detector*>(user_data);
   if (error == GRPC_ERROR_NONE && detector->response.status == 200 &&
@@ -161,7 +161,7 @@ static void on_metadata_server_detection_http_response(void* user_data,
   gpr_mu_unlock(g_polling_mu);
 }
 
-static void destroy_pollset(void* p, grpc_error* /*e*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*e*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
@@ -221,14 +221,14 @@ static int is_metadata_server_reachable() {
 }
 
 /* Takes ownership of creds_path if not NULL. */
-static grpc_error* create_default_creds_from_path(
+static grpc_error_handle create_default_creds_from_path(
     const std::string& creds_path,
     grpc_core::RefCountedPtr<grpc_call_credentials>* creds) {
   grpc_auth_json_key key;
   grpc_auth_refresh_token token;
   grpc_core::RefCountedPtr<grpc_call_credentials> result;
   grpc_slice creds_data = grpc_empty_slice();
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json;
   if (creds_path.empty()) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("creds_path unset");
@@ -304,9 +304,9 @@ static bool metadata_server_available() {
 }
 
 static grpc_core::RefCountedPtr<grpc_call_credentials> make_default_call_creds(
-    grpc_error** error) {
+    grpc_error_handle* error) {
   grpc_core::RefCountedPtr<grpc_call_credentials> call_creds;
-  grpc_error* err;
+  grpc_error_handle err;
 
   /* First, try the environment variable. */
   char* path_from_env = gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR);
@@ -344,7 +344,7 @@ grpc_channel_credentials* grpc_google_default_credentials_create(
     grpc_call_credentials* call_credentials) {
   grpc_channel_credentials* result = nullptr;
   grpc_core::RefCountedPtr<grpc_call_credentials> call_creds(call_credentials);
-  grpc_error* error = nullptr;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::ExecCtx exec_ctx;
 
   GRPC_API_TRACE("grpc_google_default_credentials_create(%p)", 1,
@@ -373,7 +373,7 @@ grpc_channel_credentials* grpc_google_default_credentials_create(
     GPR_ASSERT(result != nullptr);
   } else {
     gpr_log(GPR_ERROR, "Could not create google default credentials: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   GRPC_ERROR_UNREF(error);
   return result;
index 1aeaa88..c9dc223 100644 (file)
@@ -36,13 +36,13 @@ grpc_google_iam_credentials::~grpc_google_iam_credentials() {
 bool grpc_google_iam_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context /*context*/,
     grpc_credentials_mdelem_array* md_array,
-    grpc_closure* /*on_request_metadata*/, grpc_error** /*error*/) {
+    grpc_closure* /*on_request_metadata*/, grpc_error_handle* /*error*/) {
   grpc_credentials_mdelem_array_append(md_array, &md_array_);
   return true;
 }
 
 void grpc_google_iam_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* /*md_array*/, grpc_error* error) {
+    grpc_credentials_mdelem_array* /*md_array*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
index 9d4a1e2..881ba26 100644 (file)
@@ -35,10 +35,10 @@ class grpc_google_iam_credentials : public grpc_call_credentials {
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
   std::string debug_string() override { return debug_string_; }
 
  private:
index 520d60f..5e317c4 100644 (file)
@@ -72,7 +72,7 @@ grpc_auth_json_key grpc_auth_json_key_create_from_json(const Json& json) {
   BIO* bio = nullptr;
   const char* prop_value;
   int success = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   memset(&result, 0, sizeof(grpc_auth_json_key));
   result.type = GRPC_AUTH_JSON_TYPE_INVALID;
@@ -124,7 +124,7 @@ end:
 
 grpc_auth_json_key grpc_auth_json_key_create_from_string(
     const char* json_string) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_string, &error);
   GRPC_LOG_IF_ERROR("JSON key parsing", error);
   return grpc_auth_json_key_create_from_json(json);
index e5edc05..27590f4 100644 (file)
@@ -59,7 +59,7 @@ grpc_service_account_jwt_access_credentials::
 bool grpc_service_account_jwt_access_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context context,
     grpc_credentials_mdelem_array* md_array,
-    grpc_closure* /*on_request_metadata*/, grpc_error** error) {
+    grpc_closure* /*on_request_metadata*/, grpc_error_handle* error) {
   gpr_timespec refresh_threshold = gpr_time_from_seconds(
       GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
 
@@ -109,7 +109,7 @@ bool grpc_service_account_jwt_access_credentials::get_request_metadata(
 }
 
 void grpc_service_account_jwt_access_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* /*md_array*/, grpc_error* error) {
+    grpc_credentials_mdelem_array* /*md_array*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
@@ -141,7 +141,7 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
 }
 
 static char* redact_private_key(const char* json_key) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_key, &error);
   if (error != GRPC_ERROR_NONE || json.type() != Json::Type::OBJECT) {
     GRPC_ERROR_UNREF(error);
index d42fc25..5ae4c1f 100644 (file)
@@ -41,10 +41,10 @@ class grpc_service_account_jwt_access_credentials
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   const gpr_timespec& jwt_lifetime() const { return jwt_lifetime_; }
   const grpc_auth_json_key& key() const { return key_; }
index 8420543..8d43cf9 100644 (file)
@@ -87,10 +87,11 @@ static Json parse_json_part_from_jwt(const char* str, size_t len) {
     return Json();  // JSON null
   }
   absl::string_view string = grpc_core::StringViewFromSlice(slice);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(string, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     json = Json();  // JSON null
   }
@@ -412,7 +413,7 @@ static Json json_from_http(const grpc_httpcli_response* response) {
             response->status);
     return Json();  // JSON null
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(
       absl::string_view(response->body, response->body_length), &error);
   if (error != GRPC_ERROR_NONE) {
@@ -627,7 +628,7 @@ end:
   return result;
 }
 
-static void on_keys_retrieved(void* user_data, grpc_error* /*error*/) {
+static void on_keys_retrieved(void* user_data, grpc_error_handle /*error*/) {
   verifier_cb_ctx* ctx = static_cast<verifier_cb_ctx*>(user_data);
   Json json = json_from_http(&ctx->responses[HTTP_RESPONSE_KEYS]);
   EVP_PKEY* verification_key = nullptr;
@@ -666,7 +667,8 @@ end:
   verifier_cb_ctx_destroy(ctx);
 }
 
-static void on_openid_config_retrieved(void* user_data, grpc_error* /*error*/) {
+static void on_openid_config_retrieved(void* user_data,
+                                       grpc_error_handle /*error*/) {
   verifier_cb_ctx* ctx = static_cast<verifier_cb_ctx*>(user_data);
   const grpc_http_response* response = &ctx->responses[HTTP_RESPONSE_OPENID];
   Json json = json_from_http(response);
index bbd2cb5..50d20e6 100644 (file)
@@ -61,7 +61,7 @@ grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
   grpc_auth_refresh_token result;
   const char* prop_value;
   int success = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   memset(&result, 0, sizeof(grpc_auth_refresh_token));
   result.type = GRPC_AUTH_JSON_TYPE_INVALID;
@@ -94,10 +94,11 @@ end:
 
 grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
     const char* json_string) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_string, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parsing failed: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parsing failed: %s",
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
   }
   return grpc_auth_refresh_token_create_from_json(json);
@@ -164,11 +165,11 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response(
     const char* token_type = nullptr;
     const char* expires_in = nullptr;
     Json::Object::const_iterator it;
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     json = Json::Parse(null_terminated_body, &error);
     if (error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR, "Could not parse JSON from %s: %s",
-              null_terminated_body, grpc_error_string(error));
+              null_terminated_body, grpc_error_std_string(error).c_str());
       GRPC_ERROR_UNREF(error);
       status = GRPC_CREDENTIALS_ERROR;
       goto end;
@@ -221,7 +222,7 @@ end:
 }
 
 static void on_oauth2_token_fetcher_http_response(void* user_data,
-                                                  grpc_error* error) {
+                                                  grpc_error_handle error) {
   GRPC_LOG_IF_ERROR("oauth_fetch", GRPC_ERROR_REF(error));
   grpc_credentials_metadata_request* r =
       static_cast<grpc_credentials_metadata_request*>(user_data);
@@ -231,7 +232,7 @@ static void on_oauth2_token_fetcher_http_response(void* user_data,
 }
 
 void grpc_oauth2_token_fetcher_credentials::on_http_response(
-    grpc_credentials_metadata_request* r, grpc_error* error) {
+    grpc_credentials_metadata_request* r, grpc_error_handle error) {
   grpc_mdelem access_token_md = GRPC_MDNULL;
   grpc_millis token_lifetime = 0;
   grpc_credentials_status status =
@@ -253,7 +254,7 @@ void grpc_oauth2_token_fetcher_credentials::on_http_response(
   gpr_mu_unlock(&mu_);
   // Invoke callbacks for all pending requests.
   while (pending_request != nullptr) {
-    grpc_error* new_error = GRPC_ERROR_NONE;
+    grpc_error_handle new_error = GRPC_ERROR_NONE;
     if (status == GRPC_CREDENTIALS_OK) {
       grpc_credentials_mdelem_array_add(pending_request->md_array,
                                         access_token_md);
@@ -277,7 +278,7 @@ void grpc_oauth2_token_fetcher_credentials::on_http_response(
 bool grpc_oauth2_token_fetcher_credentials::get_request_metadata(
     grpc_polling_entity* pollent, grpc_auth_metadata_context /*context*/,
     grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
-    grpc_error** /*error*/) {
+    grpc_error_handle* /*error*/) {
   // Check if we can use the cached token.
   grpc_millis refresh_threshold =
       GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS * GPR_MS_PER_SEC;
@@ -325,7 +326,7 @@ bool grpc_oauth2_token_fetcher_credentials::get_request_metadata(
 }
 
 void grpc_oauth2_token_fetcher_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* md_array, grpc_error* error) {
+    grpc_credentials_mdelem_array* md_array, grpc_error_handle error) {
   gpr_mu_lock(&mu_);
   grpc_oauth2_pending_get_request_metadata* prev = nullptr;
   grpc_oauth2_pending_get_request_metadata* pending_request = pending_requests_;
@@ -525,8 +526,8 @@ void MaybeAddToBody(const char* field_name, const char* field,
   body->push_back(absl::StrFormat("&%s=%s", field_name, field));
 }
 
-grpc_error* LoadTokenFile(const char* path, gpr_slice* token) {
-  grpc_error* err = grpc_load_file(path, 1, token);
+grpc_error_handle LoadTokenFile(const char* path, gpr_slice* token) {
+  grpc_error_handle err = grpc_load_file(path, 1, token);
   if (err != GRPC_ERROR_NONE) return err;
   if (GRPC_SLICE_LENGTH(*token) == 0) {
     gpr_log(GPR_ERROR, "Token file %s is empty", path);
@@ -565,7 +566,7 @@ class StsTokenFetcherCredentials
                     grpc_millis deadline) override {
     char* body = nullptr;
     size_t body_length = 0;
-    grpc_error* err = FillBody(&body, &body_length);
+    grpc_error_handle err = FillBody(&body, &body_length);
     if (err != GRPC_ERROR_NONE) {
       response_cb(metadata_req, err);
       GRPC_ERROR_UNREF(err);
@@ -598,12 +599,12 @@ class StsTokenFetcherCredentials
     gpr_free(body);
   }
 
-  grpc_error* FillBody(char** body, size_t* body_length) {
+  grpc_error_handle FillBody(char** body, size_t* body_length) {
     *body = nullptr;
     std::vector<std::string> body_parts;
     grpc_slice subject_token = grpc_empty_slice();
     grpc_slice actor_token = grpc_empty_slice();
-    grpc_error* err = GRPC_ERROR_NONE;
+    grpc_error_handle err = GRPC_ERROR_NONE;
 
     auto cleanup = [&body, &body_length, &body_parts, &subject_token,
                     &actor_token, &err]() {
@@ -656,7 +657,7 @@ class StsTokenFetcherCredentials
 
 absl::StatusOr<URI> ValidateStsCredentialsOptions(
     const grpc_sts_credentials_options* options) {
-  absl::InlinedVector<grpc_error*, 3> error_list;
+  absl::InlinedVector<grpc_error_handle, 3> error_list;
   absl::StatusOr<URI> sts_url =
       URI::Parse(options->token_exchange_service_uri == nullptr
                      ? ""
@@ -685,7 +686,8 @@ absl::StatusOr<URI> ValidateStsCredentialsOptions(
   }
   auto grpc_error_vec = GRPC_ERROR_CREATE_FROM_VECTOR(
       "Invalid STS Credentials Options", &error_list);
-  auto retval = absl::InvalidArgumentError(grpc_error_string(grpc_error_vec));
+  auto retval =
+      absl::InvalidArgumentError(grpc_error_std_string(grpc_error_vec));
   GRPC_ERROR_UNREF(grpc_error_vec);
   return retval;
 }
@@ -718,13 +720,13 @@ grpc_access_token_credentials::~grpc_access_token_credentials() {
 bool grpc_access_token_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context /*context*/,
     grpc_credentials_mdelem_array* md_array,
-    grpc_closure* /*on_request_metadata*/, grpc_error** /*error*/) {
+    grpc_closure* /*on_request_metadata*/, grpc_error_handle* /*error*/) {
   grpc_credentials_mdelem_array_add(md_array, access_token_md_);
   return true;
 }
 
 void grpc_access_token_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* /*md_array*/, grpc_error* error) {
+    grpc_credentials_mdelem_array* /*md_array*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
index 2642919..f174112 100644 (file)
@@ -78,13 +78,13 @@ class grpc_oauth2_token_fetcher_credentials : public grpc_call_credentials {
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   void on_http_response(grpc_credentials_metadata_request* r,
-                        grpc_error* error);
+                        grpc_error_handle error);
   std::string debug_string() override;
 
  protected:
@@ -138,10 +138,10 @@ class grpc_access_token_credentials final : public grpc_call_credentials {
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   std::string debug_string() override;
 
index a5b01cd..4c583ad 100644 (file)
@@ -82,10 +82,10 @@ void grpc_plugin_credentials::pending_request_complete(pending_request* r) {
   Unref();
 }
 
-static grpc_error* process_plugin_result(
+static grpc_error_handle process_plugin_result(
     grpc_plugin_credentials::pending_request* r, const grpc_metadata* md,
     size_t num_md, grpc_status_code status, const char* error_details) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (status != GRPC_STATUS_OK) {
     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
         absl::StrCat("Getting metadata from plugin failed with error: ",
@@ -142,7 +142,7 @@ static void plugin_md_request_metadata_ready(void* request,
   r->creds->pending_request_complete(r);
   // If it has not been cancelled, process it.
   if (!r->cancelled) {
-    grpc_error* error =
+    grpc_error_handle error =
         process_plugin_result(r, md, num_md, status, error_details);
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_request_metadata, error);
   } else if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
@@ -157,7 +157,7 @@ static void plugin_md_request_metadata_ready(void* request,
 bool grpc_plugin_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context context,
     grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
-    grpc_error** error) {
+    grpc_error_handle* error) {
   bool retval = true;  // Synchronous return.
   if (plugin_.get_metadata != nullptr) {
     // Create pending_request object.
@@ -231,7 +231,7 @@ bool grpc_plugin_credentials::get_request_metadata(
 }
 
 void grpc_plugin_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* md_array, grpc_error* error) {
+    grpc_credentials_mdelem_array* md_array, grpc_error_handle error) {
   gpr_mu_lock(&mu_);
   for (pending_request* pending_request = pending_requests_;
        pending_request != nullptr; pending_request = pending_request->next) {
index 881eded..6835186 100644 (file)
@@ -47,10 +47,10 @@ struct grpc_plugin_credentials final : public grpc_call_credentials {
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   // Checks if the request has been cancelled.
   // If not, removes it from the pending list, so that it cannot be
index 179df8d..e831aa5 100644 (file)
@@ -100,8 +100,9 @@ bool grpc_tls_certificate_distributor::HasKeyCertPairs(
 };
 
 void grpc_tls_certificate_distributor::SetErrorForCert(
-    const std::string& cert_name, absl::optional<grpc_error*> root_cert_error,
-    absl::optional<grpc_error*> identity_cert_error) {
+    const std::string& cert_name,
+    absl::optional<grpc_error_handle> root_cert_error,
+    absl::optional<grpc_error_handle> identity_cert_error) {
   GPR_ASSERT(root_cert_error.has_value() || identity_cert_error.has_value());
   grpc_core::MutexLock lock(&mu_);
   CertificateInfo& cert_info = certificate_info_map_[cert_name];
@@ -112,7 +113,7 @@ void grpc_tls_certificate_distributor::SetErrorForCert(
       GPR_ASSERT(watcher_it != watchers_.end());
       // identity_cert_error_to_report is the error of the identity cert this
       // watcher is watching, if there is any.
-      grpc_error* identity_cert_error_to_report = GRPC_ERROR_NONE;
+      grpc_error_handle identity_cert_error_to_report = GRPC_ERROR_NONE;
       if (identity_cert_error.has_value() &&
           watcher_it->second.identity_cert_name == cert_name) {
         identity_cert_error_to_report = *identity_cert_error;
@@ -133,7 +134,7 @@ void grpc_tls_certificate_distributor::SetErrorForCert(
       GPR_ASSERT(watcher_it != watchers_.end());
       // root_cert_error_to_report is the error of the root cert this watcher is
       // watching, if there is any.
-      grpc_error* root_cert_error_to_report = GRPC_ERROR_NONE;
+      grpc_error_handle root_cert_error_to_report = GRPC_ERROR_NONE;
       if (root_cert_error.has_value() &&
           watcher_it->second.root_cert_name == cert_name) {
         // In this case, We've already sent the error updates at the time when
@@ -151,7 +152,7 @@ void grpc_tls_certificate_distributor::SetErrorForCert(
   }
 };
 
-void grpc_tls_certificate_distributor::SetError(grpc_error* error) {
+void grpc_tls_certificate_distributor::SetError(grpc_error_handle error) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   grpc_core::MutexLock lock(&mu_);
   for (const auto& watcher : watchers_) {
@@ -194,8 +195,8 @@ void grpc_tls_certificate_distributor::WatchTlsCertificates(
                               identity_cert_name};
     absl::optional<absl::string_view> updated_root_certs;
     absl::optional<grpc_core::PemKeyCertPairList> updated_identity_pairs;
-    grpc_error* root_error = GRPC_ERROR_NONE;
-    grpc_error* identity_error = GRPC_ERROR_NONE;
+    grpc_error_handle root_error = GRPC_ERROR_NONE;
+    grpc_error_handle identity_error = GRPC_ERROR_NONE;
     if (root_cert_name.has_value()) {
       CertificateInfo& cert_info = certificate_info_map_[*root_cert_name];
       start_watching_root_cert = cert_info.root_cert_watchers.empty();
index 9ce9443..36c46be 100644 (file)
@@ -68,8 +68,8 @@ struct grpc_tls_certificate_distributor
     // certificates.
     // @param identity_cert_error the error occurred while reloading identity
     // certificates.
-    virtual void OnError(grpc_error* root_cert_error,
-                         grpc_error* identity_cert_error) = 0;
+    virtual void OnError(grpc_error_handle root_cert_error,
+                         grpc_error_handle identity_cert_error) = 0;
   };
 
   // Sets the key materials based on their certificate name.
@@ -95,14 +95,14 @@ struct grpc_tls_certificate_distributor
   // @param identity_cert_error The error that the caller encounters when
   // reloading identity certs.
   void SetErrorForCert(const std::string& cert_name,
-                       absl::optional<grpc_error*> root_cert_error,
-                       absl::optional<grpc_error*> identity_cert_error);
+                       absl::optional<grpc_error_handle> root_cert_error,
+                       absl::optional<grpc_error_handle> identity_cert_error);
 
   // Propagates the error that the caller (e.g. Producer) encounters to all
   // watchers.
   //
   // @param error The error that the caller encounters.
-  void SetError(grpc_error* error);
+  void SetError(grpc_error_handle error);
 
   // Sets the TLS certificate watch status callback function. The
   // grpc_tls_certificate_distributor will invoke this callback when a new
@@ -169,9 +169,9 @@ struct grpc_tls_certificate_distributor
     // The contents of the identity key-certificate pairs.
     grpc_core::PemKeyCertPairList pem_key_cert_pairs;
     // The root cert reloading error propagated by the caller.
-    grpc_error* root_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle root_cert_error = GRPC_ERROR_NONE;
     // The identity cert reloading error propagated by the caller.
-    grpc_error* identity_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle identity_cert_error = GRPC_ERROR_NONE;
     // The set of watchers watching root certificates.
     // This is mainly used for quickly looking up the affected watchers while
     // performing a credential reloading.
@@ -185,11 +185,11 @@ struct grpc_tls_certificate_distributor
       GRPC_ERROR_UNREF(root_cert_error);
       GRPC_ERROR_UNREF(identity_cert_error);
     }
-    void SetRootError(grpc_error* error) {
+    void SetRootError(grpc_error_handle error) {
       GRPC_ERROR_UNREF(root_cert_error);
       root_cert_error = error;
     }
-    void SetIdentityError(grpc_error* error) {
+    void SetIdentityError(grpc_error_handle error) {
       GRPC_ERROR_UNREF(identity_cert_error);
       identity_cert_error = error;
     }
index 2dae03c..b4b6bf5 100644 (file)
@@ -60,8 +60,8 @@ StaticDataCertificateProvider::StaticDataCertificateProvider(
       distributor_->SetKeyMaterials(cert_name, std::move(root_certificate),
                                     std::move(pem_key_cert_pairs));
     }
-    grpc_error* root_cert_error = GRPC_ERROR_NONE;
-    grpc_error* identity_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle root_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle identity_cert_error = GRPC_ERROR_NONE;
     if (root_being_watched && !root_has_update) {
       root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "Unable to get latest root certificates.");
@@ -150,8 +150,8 @@ FileWatcherCertificateProvider::FileWatcherCertificateProvider(
       distributor_->SetKeyMaterials(cert_name, root_certificate,
                                     pem_key_cert_pairs);
     }
-    grpc_error* root_cert_error = GRPC_ERROR_NONE;
-    grpc_error* identity_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle root_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle identity_cert_error = GRPC_ERROR_NONE;
     if (root_being_watched && !root_certificate.has_value()) {
       root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "Unable to get latest root certificates.");
@@ -210,10 +210,11 @@ void FileWatcherCertificateProvider::ForceUpdate() {
   }
   if (root_cert_changed || identity_cert_changed) {
     ExecCtx exec_ctx;
-    grpc_error* root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+    grpc_error_handle root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Unable to get latest root certificates.");
-    grpc_error* identity_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "Unable to get latest identity certificates.");
+    grpc_error_handle identity_cert_error =
+        GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "Unable to get latest identity certificates.");
     for (const auto& p : watcher_info_) {
       const std::string& cert_name = p.first;
       const WatcherInfo& info = p.second;
@@ -256,11 +257,12 @@ FileWatcherCertificateProvider::ReadRootCertificatesFromFile(
     const std::string& root_cert_full_path) {
   // Read the root file.
   grpc_slice root_slice = grpc_empty_slice();
-  grpc_error* root_error =
+  grpc_error_handle root_error =
       grpc_load_file(root_cert_full_path.c_str(), 0, &root_slice);
   if (root_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "Reading file %s failed: %s",
-            root_cert_full_path.c_str(), grpc_error_string(root_error));
+            root_cert_full_path.c_str(),
+            grpc_error_std_string(root_error).c_str());
     GRPC_ERROR_UNREF(root_error);
     return absl::nullopt;
   }
@@ -314,19 +316,21 @@ FileWatcherCertificateProvider::ReadIdentityKeyCertPairFromFiles(
     }
     // Read the identity files.
     SliceWrapper key_slice, cert_slice;
-    grpc_error* key_error =
+    grpc_error_handle key_error =
         grpc_load_file(private_key_path.c_str(), 0, &key_slice.slice);
     if (key_error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR, "Reading file %s failed: %s. Start retrying...",
-              private_key_path.c_str(), grpc_error_string(key_error));
+              private_key_path.c_str(),
+              grpc_error_std_string(key_error).c_str());
       GRPC_ERROR_UNREF(key_error);
       continue;
     }
-    grpc_error* cert_error =
+    grpc_error_handle cert_error =
         grpc_load_file(identity_certificate_path.c_str(), 0, &cert_slice.slice);
     if (cert_error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR, "Reading file %s failed: %s. Start retrying...",
-              identity_certificate_path.c_str(), grpc_error_string(cert_error));
+              identity_certificate_path.c_str(),
+              grpc_error_std_string(cert_error).c_str());
       GRPC_ERROR_UNREF(cert_error);
       continue;
     }
@@ -367,6 +371,7 @@ FileWatcherCertificateProvider::ReadIdentityKeyCertPairFromFiles(
 grpc_tls_certificate_provider* grpc_tls_certificate_provider_static_data_create(
     const char* root_certificate, grpc_tls_identity_pairs* pem_key_cert_pairs) {
   GPR_ASSERT(root_certificate != nullptr || pem_key_cert_pairs != nullptr);
+  grpc_core::ExecCtx exec_ctx;
   grpc_core::PemKeyCertPairList identity_pairs_core;
   if (pem_key_cert_pairs != nullptr) {
     identity_pairs_core = std::move(pem_key_cert_pairs->pem_key_cert_pairs);
@@ -384,6 +389,7 @@ grpc_tls_certificate_provider*
 grpc_tls_certificate_provider_file_watcher_create(
     const char* private_key_path, const char* identity_certificate_path,
     const char* root_cert_path, unsigned int refresh_interval_sec) {
+  grpc_core::ExecCtx exec_ctx;
   return new grpc_core::FileWatcherCertificateProvider(
       private_key_path == nullptr ? "" : private_key_path,
       identity_certificate_path == nullptr ? "" : identity_certificate_path,
index cf2b4c6..bf26e70 100644 (file)
@@ -87,6 +87,7 @@ void grpc_tls_server_authorization_check_config::Cancel(
 /** -- Wrapper APIs declared in grpc_security.h -- **/
 
 grpc_tls_credentials_options* grpc_tls_credentials_options_create() {
+  grpc_core::ExecCtx exec_ctx;
   return new grpc_tls_credentials_options();
 }
 
@@ -109,6 +110,7 @@ void grpc_tls_credentials_options_set_certificate_provider(
     grpc_tls_certificate_provider* provider) {
   GPR_ASSERT(options != nullptr);
   GPR_ASSERT(provider != nullptr);
+  grpc_core::ExecCtx exec_ctx;
   options->set_certificate_provider(
       provider->Ref(DEBUG_LOCATION, "set_certificate_provider"));
 }
@@ -142,6 +144,7 @@ void grpc_tls_credentials_options_set_server_authorization_check_config(
     grpc_tls_server_authorization_check_config* config) {
   GPR_ASSERT(options != nullptr);
   GPR_ASSERT(config != nullptr);
+  grpc_core::ExecCtx exec_ctx;
   options->set_server_authorization_check_config(config->Ref());
 }
 
@@ -159,6 +162,7 @@ grpc_tls_server_authorization_check_config_create(
             "check config.");
     return nullptr;
   }
+  grpc_core::ExecCtx exec_ctx;
   return new grpc_tls_server_authorization_check_config(
       config_user_data, schedule, cancel, destruct);
 }
index a82a7d0..15b8e90 100644 (file)
@@ -40,13 +40,13 @@ bool XdsVerifySubjectAlternativeNames(
   if (matchers.empty()) return true;
   for (size_t i = 0; i < subject_alternative_names_size; ++i) {
     for (const auto& matcher : matchers) {
-      if (matcher.type() == StringMatcher::Type::EXACT) {
-        // For EXACT match, use DNS rules for verifying SANs
+      if (matcher.type() == StringMatcher::Type::kExact) {
+        // For Exact match, use DNS rules for verifying SANs
         // TODO(zhenlian): Right now, the SSL layer does not save the type of
         // the SAN, so we are doing a DNS style verification for all SANs when
         // the type is EXACT. When we expose the SAN type, change this to only
         // do this verification when the SAN type is DNS and match type is
-        // EXACT. For all other cases, we should use matcher.Match().
+        // kExact. For all other cases, we should use matcher.Match().
         if (VerifySubjectAlternativeName(subject_alternative_names[i],
                                          matcher.string_matcher())) {
           return true;
index 64c39e6..131436d 100644 (file)
@@ -54,7 +54,7 @@ void alts_check_peer(tsi_peer peer,
   *auth_context =
       grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(&peer);
   tsi_peer_destruct(&peer);
-  grpc_error* error =
+  grpc_error_handle error =
       *auth_context != nullptr
           ? GRPC_ERROR_NONE
           : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -103,6 +103,11 @@ class grpc_alts_channel_security_connector final
     alts_check_peer(peer, auth_context, on_peer_checked);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override {
     auto* other =
         reinterpret_cast<const grpc_alts_channel_security_connector*>(other_sc);
@@ -114,7 +119,7 @@ class grpc_alts_channel_security_connector final
   bool check_call_host(absl::string_view host,
                        grpc_auth_context* /*auth_context*/,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** error) override {
+                       grpc_error_handle* error) override {
     if (host.empty() || host != target_name_) {
       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "ALTS call host does not match target name");
@@ -123,7 +128,7 @@ class grpc_alts_channel_security_connector final
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -168,6 +173,11 @@ class grpc_alts_server_security_connector final
     alts_check_peer(peer, auth_context, on_peer_checked);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override {
     return server_security_connector_cmp(
         static_cast<const grpc_server_security_connector*>(other));
index fdf750f..0e25fb0 100644 (file)
@@ -79,6 +79,11 @@ class grpc_fake_channel_security_connector final
                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override {
     auto* other =
         reinterpret_cast<const grpc_fake_channel_security_connector*>(other_sc);
@@ -105,7 +110,7 @@ class grpc_fake_channel_security_connector final
   bool check_call_host(absl::string_view host,
                        grpc_auth_context* /*auth_context*/,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** /*error*/) override {
+                       grpc_error_handle* /*error*/) override {
     absl::string_view authority_hostname;
     absl::string_view authority_ignored_port;
     absl::string_view target_hostname;
@@ -135,7 +140,7 @@ class grpc_fake_channel_security_connector final
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -214,7 +219,7 @@ static void fake_check_peer(
     grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
     grpc_closure* on_peer_checked) {
   const char* prop_name;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   *auth_context = nullptr;
   if (peer.property_count != 2) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -287,6 +292,11 @@ class grpc_fake_server_security_connector
     fake_check_peer(this, peer, auth_context, on_peer_checked);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   void add_handshakers(const grpc_channel_args* args,
                        grpc_pollset_set* /*interested_parties*/,
                        grpc_core::HandshakeManager* handshake_mgr) override {
index ba0b89a..360764e 100644 (file)
@@ -52,13 +52,13 @@ RefCountedPtr<grpc_auth_context> TestOnlyMakeInsecureAuthContext() {
 // provide an insecure channel.
 bool InsecureChannelSecurityConnector::check_call_host(
     absl::string_view /*host*/, grpc_auth_context* /*auth_context*/,
-    grpc_closure* /*on_call_host_checked*/, grpc_error** error) {
+    grpc_closure* /*on_call_host_checked*/, grpc_error_handle* error) {
   *error = GRPC_ERROR_NONE;
   return true;
 }
 
 void InsecureChannelSecurityConnector::cancel_check_call_host(
-    grpc_closure* /*on_call_host_checked*/, grpc_error* error) {
+    grpc_closure* /*on_call_host_checked*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
index 7d0f79e..352e346 100644 (file)
@@ -47,10 +47,10 @@ class InsecureChannelSecurityConnector
 
   bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
                        grpc_closure* on_call_host_checked,
-                       grpc_error** error) override;
+                       grpc_error_handle* error) override;
 
   void cancel_check_call_host(grpc_closure* on_call_host_checked,
-                              grpc_error* error) override;
+                              grpc_error_handle error) override;
 
   void add_handshakers(const grpc_channel_args* args,
                        grpc_pollset_set* /* interested_parties */,
@@ -60,6 +60,11 @@ class InsecureChannelSecurityConnector
                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override;
 };
 
@@ -78,6 +83,11 @@ class InsecureServerSecurityConnector : public grpc_server_security_connector {
                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override;
 };
 
index f7c6c2c..4cd709f 100644 (file)
@@ -63,7 +63,7 @@ grpc_slice GetSystemRootCerts() {
   grpc_slice valid_bundle_slice = grpc_empty_slice();
   size_t num_cert_files_ = GPR_ARRAY_SIZE(kLinuxCertFiles);
   for (size_t i = 0; i < num_cert_files_; i++) {
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_load_file(kLinuxCertFiles[i], 1, &valid_bundle_slice);
     if (error == GRPC_ERROR_NONE) {
       return valid_bundle_slice;
index 2cec0db..1c1cfe9 100644 (file)
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/pollset.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.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 #include "src/core/lib/security/credentials/local/local_credentials.h"
@@ -103,7 +103,7 @@ void local_check_peer(tsi_peer peer, grpc_endpoint* ep,
       }
     }
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (!is_endpoint_local) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Endpoint is neither UDS or TCP loopback address.");
@@ -181,10 +181,15 @@ class grpc_local_channel_security_connector final
                      creds->connect_type());
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   bool check_call_host(absl::string_view host,
                        grpc_auth_context* /*auth_context*/,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** error) override {
+                       grpc_error_handle* error) override {
     if (host.empty() || host != target_name_) {
       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "local call host does not match target name");
@@ -193,7 +198,7 @@ class grpc_local_channel_security_connector final
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -230,6 +235,11 @@ class grpc_local_server_security_connector final
                      creds->connect_type());
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override {
     return server_security_connector_cmp(
         static_cast<const grpc_server_security_connector*>(other));
index 204b695..50d9af3 100644 (file)
@@ -55,13 +55,18 @@ class grpc_security_connector
         url_scheme_(url_scheme) {}
   ~grpc_security_connector() override = default;
 
-  /* Check the peer. Callee takes ownership of the peer object.
-     When done, sets *auth_context and invokes on_peer_checked. */
+  // Checks the peer. Callee takes ownership of the peer object.
+  // When done, sets *auth_context and invokes on_peer_checked.
   virtual void check_peer(
       tsi_peer peer, grpc_endpoint* ep,
       grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
       grpc_closure* on_peer_checked) = 0;
 
+  // Cancels the pending check_peer() request associated with on_peer_checked.
+  // If there is no such request pending, this is a no-op.
+  virtual void cancel_check_peer(grpc_closure* on_peer_checked,
+                                 grpc_error_handle error) = 0;
+
   /* Compares two security connectors. */
   virtual int cmp(const grpc_security_connector* other) const = 0;
 
@@ -103,12 +108,12 @@ class grpc_channel_security_connector : public grpc_security_connector {
   virtual bool check_call_host(absl::string_view host,
                                grpc_auth_context* auth_context,
                                grpc_closure* on_call_host_checked,
-                               grpc_error** error) = 0;
+                               grpc_error_handle* error) = 0;
   /// 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,
-                                      grpc_error* error) = 0;
+                                      grpc_error_handle error) = 0;
   /// Registers handshakers with \a handshake_mgr.
   virtual void add_handshakers(const grpc_channel_args* args,
                                grpc_pollset_set* interested_parties,
index ee5672b..3e424e3 100644 (file)
 #include "src/core/tsi/transport_security.h"
 
 namespace {
-grpc_error* ssl_check_peer(
+grpc_error_handle ssl_check_peer(
     const char* peer_name, const tsi_peer* peer,
     grpc_core::RefCountedPtr<grpc_auth_context>* auth_context) {
-  grpc_error* error = grpc_ssl_check_alpn(peer);
+  grpc_error_handle error = grpc_ssl_check_alpn(peer);
   if (error != GRPC_ERROR_NONE) {
     return error;
   }
@@ -145,7 +145,7 @@ class grpc_ssl_channel_security_connector final
     const char* target_name = overridden_target_name_.empty()
                                   ? target_name_.c_str()
                                   : overridden_target_name_.c_str();
-    grpc_error* error = ssl_check_peer(target_name, &peer, auth_context);
+    grpc_error_handle error = ssl_check_peer(target_name, &peer, auth_context);
     if (error == GRPC_ERROR_NONE &&
         verify_options_->verify_peer_callback != nullptr) {
       const tsi_peer_property* p =
@@ -173,6 +173,11 @@ class grpc_ssl_channel_security_connector final
     tsi_peer_destruct(&peer);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override {
     auto* other =
         reinterpret_cast<const grpc_ssl_channel_security_connector*>(other_sc);
@@ -185,14 +190,14 @@ class grpc_ssl_channel_security_connector final
 
   bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** error) override {
+                       grpc_error_handle* error) override {
     return grpc_ssl_check_call_host(host, target_name_.c_str(),
                                     overridden_target_name_.c_str(),
                                     auth_context, error);
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -288,11 +293,16 @@ class grpc_ssl_server_security_connector
   void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override {
-    grpc_error* error = ssl_check_peer(nullptr, &peer, auth_context);
+    grpc_error_handle error = ssl_check_peer(nullptr, &peer, auth_context);
     tsi_peer_destruct(&peer);
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override {
     return server_security_connector_cmp(
         static_cast<const grpc_server_security_connector*>(other));
index b0247cd..f445be9 100644 (file)
@@ -152,7 +152,7 @@ tsi_tls_version grpc_get_tsi_tls_version(grpc_tls_version tls_version) {
   }
 }
 
-grpc_error* grpc_ssl_check_alpn(const tsi_peer* peer) {
+grpc_error_handle grpc_ssl_check_alpn(const tsi_peer* peer) {
 #if TSI_OPENSSL_ALPN_SUPPORT
   /* Check the ALPN if ALPN is supported. */
   const tsi_peer_property* p =
@@ -169,8 +169,8 @@ grpc_error* grpc_ssl_check_alpn(const tsi_peer* peer) {
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_ssl_check_peer_name(absl::string_view peer_name,
-                                     const tsi_peer* peer) {
+grpc_error_handle grpc_ssl_check_peer_name(absl::string_view peer_name,
+                                           const tsi_peer* peer) {
   /* Check the peer name if specified. */
   if (!peer_name.empty() && !grpc_ssl_host_matches_name(peer, peer_name)) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -184,7 +184,7 @@ bool grpc_ssl_check_call_host(absl::string_view host,
                               absl::string_view target_name,
                               absl::string_view overridden_target_name,
                               grpc_auth_context* auth_context,
-                              grpc_error** error) {
+                              grpc_error_handle* error) {
   grpc_security_status status = GRPC_SECURITY_ERROR;
   tsi_peer peer = grpc_shallow_peer_from_ssl_auth_context(auth_context);
   if (grpc_ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
@@ -305,6 +305,9 @@ grpc_core::RefCountedPtr<grpc_auth_context> grpc_ssl_peer_to_auth_context(
       grpc_auth_context_add_property(
           ctx.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
           prop->value.data, prop->value.length);
+    } else if (strcmp(prop->name, TSI_X509_DNS_PEER_PROPERTY) == 0) {
+      grpc_auth_context_add_property(ctx.get(), GRPC_PEER_DNS_PROPERTY_NAME,
+                                     prop->value.data, prop->value.length);
     } else if (strcmp(prop->name, TSI_X509_URI_PEER_PROPERTY) == 0) {
       uri_count++;
       absl::string_view spiffe_id(prop->value.data, prop->value.length);
@@ -313,6 +316,12 @@ grpc_core::RefCountedPtr<grpc_auth_context> grpc_ssl_peer_to_auth_context(
         spiffe_length = prop->value.length;
         has_spiffe_id = true;
       }
+    } else if (strcmp(prop->name, TSI_X509_EMAIL_PEER_PROPERTY) == 0) {
+      grpc_auth_context_add_property(ctx.get(), GRPC_PEER_EMAIL_PROPERTY_NAME,
+                                     prop->value.data, prop->value.length);
+    } else if (strcmp(prop->name, TSI_X509_IP_PEER_PROPERTY) == 0) {
+      grpc_auth_context_add_property(ctx.get(), GRPC_PEER_IP_PROPERTY_NAME,
+                                     prop->value.data, prop->value.length);
     }
   }
   if (peer_identity_property_name != nullptr) {
@@ -376,9 +385,18 @@ tsi_peer grpc_shallow_peer_from_ssl_auth_context(
                  0) {
         add_shallow_auth_property_to_peer(&peer, prop,
                                           TSI_X509_PEM_CERT_CHAIN_PROPERTY);
+      } else if (strcmp(prop->name, GRPC_PEER_DNS_PROPERTY_NAME) == 0) {
+        add_shallow_auth_property_to_peer(&peer, prop,
+                                          TSI_X509_DNS_PEER_PROPERTY);
       } else if (strcmp(prop->name, GRPC_PEER_SPIFFE_ID_PROPERTY_NAME) == 0) {
         add_shallow_auth_property_to_peer(&peer, prop,
                                           TSI_X509_URI_PEER_PROPERTY);
+      } else if (strcmp(prop->name, GRPC_PEER_EMAIL_PROPERTY_NAME) == 0) {
+        add_shallow_auth_property_to_peer(&peer, prop,
+                                          TSI_X509_EMAIL_PEER_PROPERTY);
+      } else if (strcmp(prop->name, GRPC_PEER_IP_PROPERTY_NAME) == 0) {
+        add_shallow_auth_property_to_peer(&peer, prop,
+                                          TSI_X509_IP_PEER_PROPERTY);
       }
     }
   }
index 562a08c..1c41a54 100644 (file)
 #define GRPC_SSL_URL_SCHEME "https"
 
 /* Check ALPN information returned from SSL handshakes. */
-grpc_error* grpc_ssl_check_alpn(const tsi_peer* peer);
+grpc_error_handle grpc_ssl_check_alpn(const tsi_peer* peer);
 
 /* Check peer name information returned from SSL handshakes. */
-grpc_error* grpc_ssl_check_peer_name(absl::string_view peer_name,
-                                     const tsi_peer* peer);
+grpc_error_handle grpc_ssl_check_peer_name(absl::string_view peer_name,
+                                           const tsi_peer* peer);
 /* Compare targer_name information extracted from SSL security connectors. */
 int grpc_ssl_cmp_target_name(absl::string_view target_name,
                              absl::string_view other_target_name,
@@ -59,7 +59,7 @@ bool grpc_ssl_check_call_host(absl::string_view host,
                               absl::string_view target_name,
                               absl::string_view overridden_target_name,
                               grpc_auth_context* auth_context,
-                              grpc_error** error);
+                              grpc_error_handle* error);
 /* Return HTTP2-compliant cipher suites that gRPC accepts by default. */
 const char* grpc_get_ssl_cipher_suites(void);
 
index 22cc616..ea6b42e 100644 (file)
@@ -46,7 +46,7 @@ namespace grpc_core {
 namespace {
 
 tsi_ssl_pem_key_cert_pair* ConvertToTsiPemKeyCertPair(
-    const grpc_core::PemKeyCertPairList& cert_pair_list) {
+    const PemKeyCertPairList& cert_pair_list) {
   tsi_ssl_pem_key_cert_pair* tsi_pairs = nullptr;
   size_t num_key_cert_pairs = cert_pair_list.size();
   if (num_key_cert_pairs > 0) {
@@ -68,11 +68,11 @@ tsi_ssl_pem_key_cert_pair* ConvertToTsiPemKeyCertPair(
 }  // namespace
 
 // -------------------channel security connector-------------------
-grpc_core::RefCountedPtr<grpc_channel_security_connector>
+RefCountedPtr<grpc_channel_security_connector>
 TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector(
-    grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
-    grpc_core::RefCountedPtr<grpc_tls_credentials_options> options,
-    grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
+    RefCountedPtr<grpc_channel_credentials> channel_creds,
+    RefCountedPtr<grpc_tls_credentials_options> options,
+    RefCountedPtr<grpc_call_credentials> request_metadata_creds,
     const char* target_name, const char* overridden_target_name,
     tsi_ssl_session_cache* ssl_session_cache) {
   if (channel_creds == nullptr) {
@@ -93,18 +93,16 @@ TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector(
             "TlsChannelSecurityConnectorCreate()");
     return nullptr;
   }
-  grpc_core::RefCountedPtr<TlsChannelSecurityConnector> c =
-      grpc_core::MakeRefCounted<TlsChannelSecurityConnector>(
-          std::move(channel_creds), std::move(options),
-          std::move(request_metadata_creds), target_name,
-          overridden_target_name, ssl_session_cache);
-  return c;
+  return MakeRefCounted<TlsChannelSecurityConnector>(
+      std::move(channel_creds), std::move(options),
+      std::move(request_metadata_creds), target_name, overridden_target_name,
+      ssl_session_cache);
 }
 
 TlsChannelSecurityConnector::TlsChannelSecurityConnector(
-    grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
-    grpc_core::RefCountedPtr<grpc_tls_credentials_options> options,
-    grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
+    RefCountedPtr<grpc_channel_credentials> channel_creds,
+    RefCountedPtr<grpc_tls_credentials_options> options,
+    RefCountedPtr<grpc_call_credentials> request_metadata_creds,
     const char* target_name, const char* overridden_target_name,
     tsi_ssl_session_cache* ssl_session_cache)
     : grpc_channel_security_connector(GRPC_SSL_URL_SCHEME,
@@ -120,7 +118,7 @@ TlsChannelSecurityConnector::TlsChannelSecurityConnector(
   check_arg_ = ServerAuthorizationCheckArgCreate(this);
   absl::string_view host;
   absl::string_view port;
-  grpc_core::SplitHostPort(target_name, &host, &port);
+  SplitHostPort(target_name, &host, &port);
   target_name_ = std::string(host);
   // Create a watcher.
   auto watcher_ptr = absl::make_unique<TlsChannelCertificateWatcher>(this);
@@ -172,8 +170,8 @@ TlsChannelSecurityConnector::~TlsChannelSecurityConnector() {
 
 void TlsChannelSecurityConnector::add_handshakers(
     const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
-    grpc_core::HandshakeManager* handshake_mgr) {
-  grpc_core::MutexLock lock(&mu_);
+    HandshakeManager* handshake_mgr) {
+  MutexLock lock(&mu_);
   if (client_handshaker_factory_ != nullptr) {
     // Instantiate TSI handshaker.
     tsi_handshaker* tsi_hs = nullptr;
@@ -188,7 +186,7 @@ void TlsChannelSecurityConnector::add_handshakers(
       return;
     }
     // Create handshakers.
-    handshake_mgr->Add(grpc_core::SecurityHandshakerCreate(tsi_hs, this, args));
+    handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args));
     return;
   }
   // TODO(ZhenLian): Implement the logic(delegation to
@@ -199,14 +197,14 @@ void TlsChannelSecurityConnector::add_handshakers(
 
 void TlsChannelSecurityConnector::check_peer(
     tsi_peer peer, grpc_endpoint* /*ep*/,
-    grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
+    RefCountedPtr<grpc_auth_context>* auth_context,
     grpc_closure* on_peer_checked) {
   const char* target_name = overridden_target_name_.empty()
                                 ? target_name_.c_str()
                                 : overridden_target_name_.c_str();
-  grpc_error* error = grpc_ssl_check_alpn(&peer);
+  grpc_error_handle error = grpc_ssl_check_alpn(&peer);
   if (error != GRPC_ERROR_NONE) {
-    grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
+    ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
     tsi_peer_destruct(&peer);
     return;
   }
@@ -216,7 +214,7 @@ void TlsChannelSecurityConnector::check_peer(
     /* Do the default host name check if specifying the target name. */
     error = internal::TlsCheckHostName(target_name, &peer);
     if (error != GRPC_ERROR_NONE) {
-      grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
+      ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
       tsi_peer_destruct(&peer);
       return;
     }
@@ -299,7 +297,7 @@ void TlsChannelSecurityConnector::check_peer(
       error = ProcessServerAuthorizationCheckResult(check_arg_);
     }
   }
-  grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
+  ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
   tsi_peer_destruct(&peer);
 }
 
@@ -317,7 +315,7 @@ int TlsChannelSecurityConnector::cmp(
 
 bool TlsChannelSecurityConnector::check_call_host(
     absl::string_view host, grpc_auth_context* auth_context,
-    grpc_closure* /*on_call_host_checked*/, grpc_error** error) {
+    grpc_closure* /*on_call_host_checked*/, grpc_error_handle* error) {
   if (options_->server_verification_option() ==
           GRPC_TLS_SKIP_HOSTNAME_VERIFICATION ||
       options_->server_verification_option() ==
@@ -330,16 +328,15 @@ bool TlsChannelSecurityConnector::check_call_host(
 }
 
 void TlsChannelSecurityConnector::cancel_check_call_host(
-    grpc_closure* /*on_call_host_checked*/, grpc_error* error) {
+    grpc_closure* /*on_call_host_checked*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
 void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::
-    OnCertificatesChanged(
-        absl::optional<absl::string_view> root_certs,
-        absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) {
+    OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
+                          absl::optional<PemKeyCertPairList> key_cert_pairs) {
   GPR_ASSERT(security_connector_ != nullptr);
-  grpc_core::MutexLock lock(&security_connector_->mu_);
+  MutexLock lock(&security_connector_->mu_);
   if (root_certs.has_value()) {
     security_connector_->pem_root_certs_ = root_certs;
   }
@@ -362,16 +359,16 @@ void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::
 // TODO(ZhenLian): implement the logic to signal waiting handshakers once
 // BlockOnInitialCredentialHandshaker is implemented.
 void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::OnError(
-    grpc_error* root_cert_error, grpc_error* identity_cert_error) {
+    grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) {
   if (root_cert_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "TlsChannelCertificateWatcher getting root_cert_error: %s",
-            grpc_error_string(root_cert_error));
+            grpc_error_std_string(root_cert_error).c_str());
   }
   if (identity_cert_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "TlsChannelCertificateWatcher getting identity_cert_error: %s",
-            grpc_error_string(identity_cert_error));
+            grpc_error_std_string(identity_cert_error).c_str());
   }
   GRPC_ERROR_UNREF(root_cert_error);
   GRPC_ERROR_UNREF(identity_cert_error);
@@ -417,16 +414,17 @@ TlsChannelSecurityConnector::UpdateHandshakerFactoryLocked() {
 void TlsChannelSecurityConnector::ServerAuthorizationCheckDone(
     grpc_tls_server_authorization_check_arg* arg) {
   GPR_ASSERT(arg != nullptr);
-  grpc_core::ExecCtx exec_ctx;
-  grpc_error* error = ProcessServerAuthorizationCheckResult(arg);
+  ExecCtx exec_ctx;
+  grpc_error_handle error = ProcessServerAuthorizationCheckResult(arg);
   TlsChannelSecurityConnector* connector =
       static_cast<TlsChannelSecurityConnector*>(arg->cb_user_data);
-  grpc_core::ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error);
+  ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error);
 }
 
-grpc_error* TlsChannelSecurityConnector::ProcessServerAuthorizationCheckResult(
+grpc_error_handle
+TlsChannelSecurityConnector::ProcessServerAuthorizationCheckResult(
     grpc_tls_server_authorization_check_arg* arg) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   /* Server authorization check is cancelled by caller. */
   if (arg->status == GRPC_STATUS_CANCELLED) {
     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -491,10 +489,10 @@ void TlsChannelSecurityConnector::ServerAuthorizationCheckArgDestroy(
 }
 
 // -------------------server security connector-------------------
-grpc_core::RefCountedPtr<grpc_server_security_connector>
+RefCountedPtr<grpc_server_security_connector>
 TlsServerSecurityConnector::CreateTlsServerSecurityConnector(
-    grpc_core::RefCountedPtr<grpc_server_credentials> server_creds,
-    grpc_core::RefCountedPtr<grpc_tls_credentials_options> options) {
+    RefCountedPtr<grpc_server_credentials> server_creds,
+    RefCountedPtr<grpc_tls_credentials_options> options) {
   if (server_creds == nullptr) {
     gpr_log(GPR_ERROR,
             "server_creds is nullptr in "
@@ -507,15 +505,13 @@ TlsServerSecurityConnector::CreateTlsServerSecurityConnector(
             "TlsServerSecurityConnectorCreate()");
     return nullptr;
   }
-  grpc_core::RefCountedPtr<TlsServerSecurityConnector> c =
-      grpc_core::MakeRefCounted<TlsServerSecurityConnector>(
-          std::move(server_creds), std::move(options));
-  return c;
+  return MakeRefCounted<TlsServerSecurityConnector>(std::move(server_creds),
+                                                    std::move(options));
 }
 
 TlsServerSecurityConnector::TlsServerSecurityConnector(
-    grpc_core::RefCountedPtr<grpc_server_credentials> server_creds,
-    grpc_core::RefCountedPtr<grpc_tls_credentials_options> options)
+    RefCountedPtr<grpc_server_credentials> server_creds,
+    RefCountedPtr<grpc_tls_credentials_options> options)
     : grpc_server_security_connector(GRPC_SSL_URL_SCHEME,
                                      std::move(server_creds)),
       options_(std::move(options)) {
@@ -551,8 +547,8 @@ TlsServerSecurityConnector::~TlsServerSecurityConnector() {
 
 void TlsServerSecurityConnector::add_handshakers(
     const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
-    grpc_core::HandshakeManager* handshake_mgr) {
-  grpc_core::MutexLock lock(&mu_);
+    HandshakeManager* handshake_mgr) {
+  MutexLock lock(&mu_);
   if (server_handshaker_factory_ != nullptr) {
     // Instantiate TSI handshaker.
     tsi_handshaker* tsi_hs = nullptr;
@@ -564,7 +560,7 @@ void TlsServerSecurityConnector::add_handshakers(
       return;
     }
     // Create handshakers.
-    handshake_mgr->Add(grpc_core::SecurityHandshakerCreate(tsi_hs, this, args));
+    handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args));
     return;
   }
   // TODO(ZhenLian): Implement the logic(delegation to
@@ -575,13 +571,13 @@ void TlsServerSecurityConnector::add_handshakers(
 
 void TlsServerSecurityConnector::check_peer(
     tsi_peer peer, grpc_endpoint* /*ep*/,
-    grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
+    RefCountedPtr<grpc_auth_context>* auth_context,
     grpc_closure* on_peer_checked) {
-  grpc_error* error = grpc_ssl_check_alpn(&peer);
+  grpc_error_handle error = grpc_ssl_check_alpn(&peer);
   *auth_context =
       grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE);
   tsi_peer_destruct(&peer);
-  grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
+  ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
 }
 
 int TlsServerSecurityConnector::cmp(
@@ -591,11 +587,10 @@ int TlsServerSecurityConnector::cmp(
 }
 
 void TlsServerSecurityConnector::TlsServerCertificateWatcher::
-    OnCertificatesChanged(
-        absl::optional<absl::string_view> root_certs,
-        absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) {
+    OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
+                          absl::optional<PemKeyCertPairList> key_cert_pairs) {
   GPR_ASSERT(security_connector_ != nullptr);
-  grpc_core::MutexLock lock(&security_connector_->mu_);
+  MutexLock lock(&security_connector_->mu_);
   if (root_certs.has_value()) {
     security_connector_->pem_root_certs_ = root_certs;
   }
@@ -622,16 +617,16 @@ void TlsServerSecurityConnector::TlsServerCertificateWatcher::
 // TODO(ZhenLian): implement the logic to signal waiting handshakers once
 // BlockOnInitialCredentialHandshaker is implemented.
 void TlsServerSecurityConnector::TlsServerCertificateWatcher::OnError(
-    grpc_error* root_cert_error, grpc_error* identity_cert_error) {
+    grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) {
   if (root_cert_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "TlsServerCertificateWatcher getting root_cert_error: %s",
-            grpc_error_string(root_cert_error));
+            grpc_error_std_string(root_cert_error).c_str());
   }
   if (identity_cert_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "TlsServerCertificateWatcher getting identity_cert_error: %s",
-            grpc_error_string(identity_cert_error));
+            grpc_error_std_string(identity_cert_error).c_str());
   }
   GRPC_ERROR_UNREF(root_cert_error);
   GRPC_ERROR_UNREF(identity_cert_error);
@@ -672,7 +667,8 @@ TlsServerSecurityConnector::UpdateHandshakerFactoryLocked() {
 
 namespace internal {
 
-grpc_error* TlsCheckHostName(const char* peer_name, const tsi_peer* peer) {
+grpc_error_handle TlsCheckHostName(const char* peer_name,
+                                   const tsi_peer* peer) {
   /* Check the peer name if specified. */
   if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
index 453c531..80c2695 100644 (file)
@@ -35,18 +35,18 @@ class TlsChannelSecurityConnector final
     : public grpc_channel_security_connector {
  public:
   // static factory method to create a TLS channel security connector.
-  static grpc_core::RefCountedPtr<grpc_channel_security_connector>
+  static RefCountedPtr<grpc_channel_security_connector>
   CreateTlsChannelSecurityConnector(
-      grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
-      grpc_core::RefCountedPtr<grpc_tls_credentials_options> options,
-      grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
+      RefCountedPtr<grpc_channel_credentials> channel_creds,
+      RefCountedPtr<grpc_tls_credentials_options> options,
+      RefCountedPtr<grpc_call_credentials> request_metadata_creds,
       const char* target_name, const char* overridden_target_name,
       tsi_ssl_session_cache* ssl_session_cache);
 
   TlsChannelSecurityConnector(
-      grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
-      grpc_core::RefCountedPtr<grpc_tls_credentials_options> options,
-      grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
+      RefCountedPtr<grpc_channel_credentials> channel_creds,
+      RefCountedPtr<grpc_tls_credentials_options> options,
+      RefCountedPtr<grpc_call_credentials> request_metadata_creds,
       const char* target_name, const char* overridden_target_name,
       tsi_ssl_session_cache* ssl_session_cache);
 
@@ -54,33 +54,39 @@ class TlsChannelSecurityConnector final
 
   void add_handshakers(const grpc_channel_args* args,
                        grpc_pollset_set* interested_parties,
-                       grpc_core::HandshakeManager* handshake_mgr) override;
+                       HandshakeManager* handshake_mgr) override;
 
   void check_peer(tsi_peer peer, grpc_endpoint* ep,
-                  grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
+                  RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    // TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override;
 
   bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
                        grpc_closure* on_call_host_checked,
-                       grpc_error** error) override;
+                       grpc_error_handle* error) override;
 
   void cancel_check_call_host(grpc_closure* on_call_host_checked,
-                              grpc_error* error) override;
+                              grpc_error_handle error) override;
 
   tsi_ssl_client_handshaker_factory* ClientHandshakerFactoryForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     return client_handshaker_factory_;
   };
 
   absl::optional<absl::string_view> RootCertsForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     return pem_root_certs_;
   }
 
-  absl::optional<grpc_core::PemKeyCertPairList> KeyCertPairListForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+  absl::optional<PemKeyCertPairList> KeyCertPairListForTesting() {
+    MutexLock lock(&mu_);
     return pem_key_cert_pair_list_;
   }
 
@@ -96,9 +102,9 @@ class TlsChannelSecurityConnector final
         : security_connector_(security_connector) {}
     void OnCertificatesChanged(
         absl::optional<absl::string_view> root_certs,
-        absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) override;
-    void OnError(grpc_error* root_cert_error,
-                 grpc_error* identity_cert_error) override;
+        absl::optional<PemKeyCertPairList> key_cert_pairs) override;
+    void OnError(grpc_error_handle root_cert_error,
+                 grpc_error_handle identity_cert_error) override;
 
    private:
     TlsChannelSecurityConnector* security_connector_ = nullptr;
@@ -106,7 +112,8 @@ class TlsChannelSecurityConnector final
 
   // Updates |client_handshaker_factory_| when the certificates that
   // |certificate_watcher_| is watching get updated.
-  grpc_security_status UpdateHandshakerFactoryLocked();
+  grpc_security_status UpdateHandshakerFactoryLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   // gRPC-provided callback executed by application, which servers to bring the
   // control back to gRPC core.
@@ -114,7 +121,7 @@ class TlsChannelSecurityConnector final
       grpc_tls_server_authorization_check_arg* arg);
 
   // A util function to process server authorization check result.
-  static grpc_error* ProcessServerAuthorizationCheckResult(
+  static grpc_error_handle ProcessServerAuthorizationCheckResult(
       grpc_tls_server_authorization_check_arg* arg);
 
   // A util function to create a server authorization check arg instance.
@@ -125,57 +132,65 @@ class TlsChannelSecurityConnector final
   static void ServerAuthorizationCheckArgDestroy(
       grpc_tls_server_authorization_check_arg* arg);
 
-  grpc_core::Mutex mu_;
-  grpc_core::RefCountedPtr<grpc_tls_credentials_options> options_;
+  RefCountedPtr<grpc_tls_credentials_options> options_;
   grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
       certificate_watcher_ = nullptr;
   grpc_closure* on_peer_checked_ = nullptr;
   std::string target_name_;
   std::string overridden_target_name_;
-  tsi_ssl_client_handshaker_factory* client_handshaker_factory_ = nullptr;
   grpc_tls_server_authorization_check_arg* check_arg_ = nullptr;
-  tsi_ssl_session_cache* ssl_session_cache_ = nullptr;
-  absl::optional<absl::string_view> pem_root_certs_;
-  absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pair_list_;
+
+  Mutex mu_;
+  tsi_ssl_client_handshaker_factory* client_handshaker_factory_
+      ABSL_GUARDED_BY(mu_) = nullptr;
+  tsi_ssl_session_cache* ssl_session_cache_ ABSL_GUARDED_BY(mu_) = nullptr;
+  absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_);
+  absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_
+      ABSL_GUARDED_BY(mu_);
 };
 
 // Server security connector using TLS as transport security protocol.
 class TlsServerSecurityConnector final : public grpc_server_security_connector {
  public:
   // static factory method to create a TLS server security connector.
-  static grpc_core::RefCountedPtr<grpc_server_security_connector>
+  static RefCountedPtr<grpc_server_security_connector>
   CreateTlsServerSecurityConnector(
-      grpc_core::RefCountedPtr<grpc_server_credentials> server_creds,
-      grpc_core::RefCountedPtr<grpc_tls_credentials_options> options);
+      RefCountedPtr<grpc_server_credentials> server_creds,
+      RefCountedPtr<grpc_tls_credentials_options> options);
 
   TlsServerSecurityConnector(
-      grpc_core::RefCountedPtr<grpc_server_credentials> server_creds,
-      grpc_core::RefCountedPtr<grpc_tls_credentials_options> options);
+      RefCountedPtr<grpc_server_credentials> server_creds,
+      RefCountedPtr<grpc_tls_credentials_options> options);
   ~TlsServerSecurityConnector() override;
 
   void add_handshakers(const grpc_channel_args* args,
                        grpc_pollset_set* interested_parties,
-                       grpc_core::HandshakeManager* handshake_mgr) override;
+                       HandshakeManager* handshake_mgr) override;
 
   void check_peer(tsi_peer peer, grpc_endpoint* ep,
-                  grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
+                  RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    // TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override;
 
   tsi_ssl_server_handshaker_factory* ServerHandshakerFactoryForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     return server_handshaker_factory_;
   };
 
   const absl::optional<absl::string_view>& RootCertsForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     return pem_root_certs_;
   }
 
-  const absl::optional<grpc_core::PemKeyCertPairList>&
-  KeyCertPairListForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+  const absl::optional<PemKeyCertPairList>& KeyCertPairListForTesting() {
+    MutexLock lock(&mu_);
     return pem_key_cert_pair_list_;
   }
 
@@ -191,9 +206,9 @@ class TlsServerSecurityConnector final : public grpc_server_security_connector {
         : security_connector_(security_connector) {}
     void OnCertificatesChanged(
         absl::optional<absl::string_view> root_certs,
-        absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) override;
-    void OnError(grpc_error* root_cert_error,
-                 grpc_error* identity_cert_error) override;
+        absl::optional<PemKeyCertPairList> key_cert_pairs) override;
+    void OnError(grpc_error_handle root_cert_error,
+                 grpc_error_handle identity_cert_error) override;
 
    private:
     TlsServerSecurityConnector* security_connector_ = nullptr;
@@ -201,16 +216,19 @@ class TlsServerSecurityConnector final : public grpc_server_security_connector {
 
   // Updates |server_handshaker_factory_| when the certificates that
   // |certificate_watcher_| is watching get updated.
-  grpc_security_status UpdateHandshakerFactoryLocked();
+  grpc_security_status UpdateHandshakerFactoryLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
-  grpc_core::Mutex mu_;
-  grpc_core::RefCountedPtr<grpc_tls_credentials_options> options_;
+  RefCountedPtr<grpc_tls_credentials_options> options_;
   grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
       certificate_watcher_ = nullptr;
 
-  tsi_ssl_server_handshaker_factory* server_handshaker_factory_ = nullptr;
-  absl::optional<absl::string_view> pem_root_certs_;
-  absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pair_list_;
+  Mutex mu_;
+  tsi_ssl_server_handshaker_factory* server_handshaker_factory_
+      ABSL_GUARDED_BY(mu_) = nullptr;
+  absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_);
+  absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_
+      ABSL_GUARDED_BY(mu_);
 };
 
 // ---- Functions below are exposed for testing only -----------------------
@@ -218,7 +236,7 @@ namespace internal {
 
 // TlsCheckHostName checks if |peer_name| matches the identity information
 // contained in |peer|. This is AKA hostname check.
-grpc_error* TlsCheckHostName(const char* peer_name, const tsi_peer* peer);
+grpc_error_handle TlsCheckHostName(const char* peer_name, const tsi_peer* peer);
 
 }  // namespace internal
 
index c155be8..babc90f 100644 (file)
@@ -146,7 +146,7 @@ void grpc_auth_metadata_context_reset(
   }
 }
 
-static void add_error(grpc_error** combined, grpc_error* error) {
+static void add_error(grpc_error_handle* combined, grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) return;
   if (*combined == GRPC_ERROR_NONE) {
     *combined = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -155,14 +155,14 @@ static void add_error(grpc_error** combined, grpc_error* error) {
   *combined = grpc_error_add_child(*combined, error);
 }
 
-static void on_credentials_metadata(void* arg, grpc_error* input_error) {
+static void on_credentials_metadata(void* arg, grpc_error_handle input_error) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   grpc_call_element* elem =
       static_cast<grpc_call_element*>(batch->handler_private.extra_arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_auth_metadata_context_reset(&calld->auth_md_context);
-  grpc_error* error = GRPC_ERROR_REF(input_error);
+  grpc_error_handle error = GRPC_ERROR_REF(input_error);
   if (error == GRPC_ERROR_NONE) {
     GPR_ASSERT(calld->md_array.size <= MAX_CREDENTIALS_METADATA_COUNT);
     GPR_ASSERT(batch->send_initial_metadata);
@@ -225,13 +225,14 @@ void grpc_auth_metadata_context_build(
   gpr_free(host_and_port);
 }
 
-static void cancel_get_request_metadata(void* arg, grpc_error* error) {
+static void cancel_get_request_metadata(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
     calld->creds->cancel_get_request_metadata(&calld->md_array,
                                               GRPC_ERROR_REF(error));
   }
+  GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_get_request_metadata");
 }
 
 static void send_security_metadata(grpc_call_element* elem,
@@ -311,7 +312,7 @@ static void send_security_metadata(grpc_call_element* elem,
   GRPC_CALL_STACK_REF(calld->owning_call, "get_request_metadata");
   GRPC_CLOSURE_INIT(&calld->async_result_closure, on_credentials_metadata,
                     batch, grpc_schedule_on_exec_ctx);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (calld->creds->get_request_metadata(
           calld->pollent, calld->auth_md_context, &calld->md_array,
           &calld->async_result_closure, &error)) {
@@ -320,13 +321,16 @@ static void send_security_metadata(grpc_call_element* elem,
     GRPC_ERROR_UNREF(error);
   } else {
     // Async return; register cancellation closure with call combiner.
+    // TODO(yashykt): We would not need this ref if call combiners used
+    // Closure::Run() instead of ExecCtx::Run()
+    GRPC_CALL_STACK_REF(calld->owning_call, "cancel_get_request_metadata");
     calld->call_combiner->SetNotifyOnCancel(GRPC_CLOSURE_INIT(
         &calld->get_request_metadata_cancel_closure,
         cancel_get_request_metadata, elem, grpc_schedule_on_exec_ctx));
   }
 }
 
-static void on_host_checked(void* arg, grpc_error* error) {
+static void on_host_checked(void* arg, grpc_error_handle error) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   grpc_call_element* elem =
@@ -348,7 +352,7 @@ static void on_host_checked(void* arg, grpc_error* error) {
   GRPC_CALL_STACK_UNREF(calld->owning_call, "check_call_host");
 }
 
-static void cancel_check_call_host(void* arg, grpc_error* error) {
+static void cancel_check_call_host(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
@@ -356,6 +360,7 @@ static void cancel_check_call_host(void* arg, grpc_error* error) {
     chand->security_connector->cancel_check_call_host(
         &calld->async_result_closure, GRPC_ERROR_REF(error));
   }
+  GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_check_call_host");
 }
 
 static void client_auth_start_transport_stream_op_batch(
@@ -381,7 +386,7 @@ static void client_auth_start_transport_stream_op_batch(
       GRPC_CLOSURE_INIT(&calld->async_result_closure, on_host_checked, batch,
                         grpc_schedule_on_exec_ctx);
       absl::string_view call_host(grpc_core::StringViewFromSlice(calld->host));
-      grpc_error* error = GRPC_ERROR_NONE;
+      grpc_error_handle error = GRPC_ERROR_NONE;
       if (chand->security_connector->check_call_host(
               call_host, chand->auth_context.get(),
               &calld->async_result_closure, &error)) {
@@ -390,6 +395,9 @@ static void client_auth_start_transport_stream_op_batch(
         GRPC_ERROR_UNREF(error);
       } else {
         // Async return; register cancellation closure with call combiner.
+        // TODO(yashykt): We would not need this ref if call combiners used
+        // Closure::Run() instead of ExecCtx::Run()
+        GRPC_CALL_STACK_REF(calld->owning_call, "cancel_check_call_host");
         calld->call_combiner->SetNotifyOnCancel(GRPC_CLOSURE_INIT(
             &calld->check_call_host_cancel_closure, cancel_check_call_host,
             elem, grpc_schedule_on_exec_ctx));
@@ -403,7 +411,7 @@ static void client_auth_start_transport_stream_op_batch(
 }
 
 /* Constructor for call_data */
-static grpc_error* client_auth_init_call_elem(
+static grpc_error_handle client_auth_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   new (elem->call_data) call_data(elem, *args);
   return GRPC_ERROR_NONE;
@@ -424,7 +432,7 @@ static void client_auth_destroy_call_elem(
 }
 
 /* Constructor for channel_data */
-static grpc_error* client_auth_init_channel_elem(
+static grpc_error_handle client_auth_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   /* The first and the last filters tend to be implemented differently to
      handle the case that there's no 'next' filter to call on the up or down
index 7ab4d7b..fc1fb7e 100644 (file)
@@ -43,7 +43,7 @@
 
 #define STAGING_BUFFER_SIZE 8192
 
-static void on_read(void* user_data, grpc_error* error);
+static void on_read(void* user_data, grpc_error_handle error);
 
 namespace {
 struct secure_endpoint {
@@ -154,7 +154,7 @@ static void flush_read_staging_buffer(secure_endpoint* ep, uint8_t** cur,
   *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer);
 }
 
-static void call_read_cb(secure_endpoint* ep, grpc_error* error) {
+static void call_read_cb(secure_endpoint* ep, grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_secure_endpoint)) {
     size_t i;
     for (i = 0; i < ep->read_buffer->count; i++) {
@@ -169,7 +169,7 @@ static void call_read_cb(secure_endpoint* ep, grpc_error* error) {
   SECURE_ENDPOINT_UNREF(ep, "read");
 }
 
-static void on_read(void* user_data, grpc_error* error) {
+static void on_read(void* user_data, grpc_error_handle error) {
   unsigned i;
   uint8_t keep_looping = 0;
   tsi_result result = TSI_OK;
@@ -373,7 +373,7 @@ static void endpoint_write(grpc_endpoint* secure_ep, grpc_slice_buffer* slices,
   grpc_endpoint_write(ep->wrapped_ep, &ep->output_buffer, cb, arg);
 }
 
-static void endpoint_shutdown(grpc_endpoint* secure_ep, grpc_error* why) {
+static void endpoint_shutdown(grpc_endpoint* secure_ep, grpc_error_handle why) {
   secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   grpc_endpoint_shutdown(ep->wrapped_ep, why);
 }
index 6e09fef..6d05c97 100644 (file)
@@ -51,35 +51,36 @@ class SecurityHandshaker : public Handshaker {
                      grpc_security_connector* connector,
                      const grpc_channel_args* args);
   ~SecurityHandshaker() override;
-  void Shutdown(grpc_error* why) override;
+  void Shutdown(grpc_error_handle why) override;
   void DoHandshake(grpc_tcp_server_acceptor* acceptor,
                    grpc_closure* on_handshake_done,
                    HandshakerArgs* args) override;
   const char* name() const override { return "security"; }
 
  private:
-  grpc_error* DoHandshakerNextLocked(const unsigned char* bytes_received,
-                                     size_t bytes_received_size);
+  grpc_error_handle DoHandshakerNextLocked(const unsigned char* bytes_received,
+                                           size_t bytes_received_size);
 
-  grpc_error* OnHandshakeNextDoneLocked(
+  grpc_error_handle OnHandshakeNextDoneLocked(
       tsi_result result, const unsigned char* bytes_to_send,
       size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result);
-  void HandshakeFailedLocked(grpc_error* error);
+  void HandshakeFailedLocked(grpc_error_handle error);
   void CleanupArgsForFailureLocked();
 
-  static void OnHandshakeDataReceivedFromPeerFn(void* arg, grpc_error* error);
-  static void OnHandshakeDataSentToPeerFn(void* arg, grpc_error* error);
-  static void OnHandshakeDataReceivedFromPeerFnScheduler(void* arg,
-                                                         grpc_error* error);
+  static void OnHandshakeDataReceivedFromPeerFn(void* arg,
+                                                grpc_error_handle error);
+  static void OnHandshakeDataSentToPeerFn(void* arg, grpc_error_handle error);
+  static void OnHandshakeDataReceivedFromPeerFnScheduler(
+      void* arg, grpc_error_handle error);
   static void OnHandshakeDataSentToPeerFnScheduler(void* arg,
-                                                   grpc_error* error);
+                                                   grpc_error_handle error);
   static void OnHandshakeNextDoneGrpcWrapper(
       tsi_result result, void* user_data, const unsigned char* bytes_to_send,
       size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result);
-  static void OnPeerCheckedFn(void* arg, grpc_error* error);
-  void OnPeerCheckedInner(grpc_error* error);
+  static void OnPeerCheckedFn(void* arg, grpc_error_handle error);
+  void OnPeerCheckedInner(grpc_error_handle error);
   size_t MoveReadBufferIntoHandshakeBuffer();
-  grpc_error* CheckPeerLocked();
+  grpc_error_handle CheckPeerLocked();
 
   // State set at creation time.
   tsi_handshaker* handshaker_;
@@ -173,15 +174,14 @@ void SecurityHandshaker::CleanupArgsForFailureLocked() {
 
 // If the handshake failed or we're shutting down, clean up and invoke the
 // callback with the error.
-void SecurityHandshaker::HandshakeFailedLocked(grpc_error* error) {
+void SecurityHandshaker::HandshakeFailedLocked(grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) {
     // If we were shut down after the handshake succeeded but before an
     // endpoint callback was invoked, we need to generate our own error.
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshaker shutdown");
   }
-  const char* msg = grpc_error_string(error);
-  gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg);
-
+  gpr_log(GPR_DEBUG, "Security handshake failed: %s",
+          grpc_error_std_string(error).c_str());
   if (!is_shutdown_) {
     tsi_handshaker_shutdown(handshaker_);
     // TODO(ctiller): It is currently necessary to shutdown endpoints
@@ -225,7 +225,7 @@ MakeChannelzSecurityFromAuthContext(grpc_auth_context* auth_context) {
 
 }  // namespace
 
-void SecurityHandshaker::OnPeerCheckedInner(grpc_error* error) {
+void SecurityHandshaker::OnPeerCheckedInner(grpc_error_handle error) {
   MutexLock lock(&mu_);
   if (error != GRPC_ERROR_NONE || is_shutdown_) {
     HandshakeFailedLocked(error);
@@ -292,12 +292,12 @@ void SecurityHandshaker::OnPeerCheckedInner(grpc_error* error) {
   is_shutdown_ = true;
 }
 
-void SecurityHandshaker::OnPeerCheckedFn(void* arg, grpc_error* error) {
+void SecurityHandshaker::OnPeerCheckedFn(void* arg, grpc_error_handle error) {
   RefCountedPtr<SecurityHandshaker>(static_cast<SecurityHandshaker*>(arg))
       ->OnPeerCheckedInner(GRPC_ERROR_REF(error));
 }
 
-grpc_error* SecurityHandshaker::CheckPeerLocked() {
+grpc_error_handle SecurityHandshaker::CheckPeerLocked() {
   tsi_peer peer;
   tsi_result result =
       tsi_handshaker_result_extract_peer(handshaker_result_, &peer);
@@ -310,10 +310,10 @@ grpc_error* SecurityHandshaker::CheckPeerLocked() {
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* SecurityHandshaker::OnHandshakeNextDoneLocked(
+grpc_error_handle SecurityHandshaker::OnHandshakeNextDoneLocked(
     tsi_result result, const unsigned char* bytes_to_send,
     size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   // Handshaker was shutdown.
   if (is_shutdown_) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshaker shutdown");
@@ -374,7 +374,7 @@ void SecurityHandshaker::OnHandshakeNextDoneGrpcWrapper(
   RefCountedPtr<SecurityHandshaker> h(
       static_cast<SecurityHandshaker*>(user_data));
   MutexLock lock(&h->mu_);
-  grpc_error* error = h->OnHandshakeNextDoneLocked(
+  grpc_error_handle error = h->OnHandshakeNextDoneLocked(
       result, bytes_to_send, bytes_to_send_size, handshaker_result);
   if (error != GRPC_ERROR_NONE) {
     h->HandshakeFailedLocked(error);
@@ -383,7 +383,7 @@ void SecurityHandshaker::OnHandshakeNextDoneGrpcWrapper(
   }
 }
 
-grpc_error* SecurityHandshaker::DoHandshakerNextLocked(
+grpc_error_handle SecurityHandshaker::DoHandshakerNextLocked(
     const unsigned char* bytes_received, size_t bytes_received_size) {
   // Invoke TSI handshaker.
   const unsigned char* bytes_to_send = nullptr;
@@ -406,7 +406,7 @@ grpc_error* SecurityHandshaker::DoHandshakerNextLocked(
 // This callback might be run inline while we are still holding on to the mutex,
 // so schedule OnHandshakeDataReceivedFromPeerFn on ExecCtx to avoid a deadlock.
 void SecurityHandshaker::OnHandshakeDataReceivedFromPeerFnScheduler(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   SecurityHandshaker* h = static_cast<SecurityHandshaker*>(arg);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION,
@@ -416,8 +416,8 @@ void SecurityHandshaker::OnHandshakeDataReceivedFromPeerFnScheduler(
       GRPC_ERROR_REF(error));
 }
 
-void SecurityHandshaker::OnHandshakeDataReceivedFromPeerFn(void* arg,
-                                                           grpc_error* error) {
+void SecurityHandshaker::OnHandshakeDataReceivedFromPeerFn(
+    void* arg, grpc_error_handle error) {
   RefCountedPtr<SecurityHandshaker> h(static_cast<SecurityHandshaker*>(arg));
   MutexLock lock(&h->mu_);
   if (error != GRPC_ERROR_NONE || h->is_shutdown_) {
@@ -440,7 +440,7 @@ void SecurityHandshaker::OnHandshakeDataReceivedFromPeerFn(void* arg,
 // This callback might be run inline while we are still holding on to the mutex,
 // so schedule OnHandshakeDataSentToPeerFn on ExecCtx to avoid a deadlock.
 void SecurityHandshaker::OnHandshakeDataSentToPeerFnScheduler(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   SecurityHandshaker* h = static_cast<SecurityHandshaker*>(arg);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION,
@@ -451,7 +451,7 @@ void SecurityHandshaker::OnHandshakeDataSentToPeerFnScheduler(
 }
 
 void SecurityHandshaker::OnHandshakeDataSentToPeerFn(void* arg,
-                                                     grpc_error* error) {
+                                                     grpc_error_handle error) {
   RefCountedPtr<SecurityHandshaker> h(static_cast<SecurityHandshaker*>(arg));
   MutexLock lock(&h->mu_);
   if (error != GRPC_ERROR_NONE || h->is_shutdown_) {
@@ -482,10 +482,11 @@ void SecurityHandshaker::OnHandshakeDataSentToPeerFn(void* arg,
 // public handshaker API
 //
 
-void SecurityHandshaker::Shutdown(grpc_error* why) {
+void SecurityHandshaker::Shutdown(grpc_error_handle why) {
   MutexLock lock(&mu_);
   if (!is_shutdown_) {
     is_shutdown_ = true;
+    connector_->cancel_check_peer(&on_peer_checked_, GRPC_ERROR_REF(why));
     tsi_handshaker_shutdown(handshaker_);
     grpc_endpoint_shutdown(args_->endpoint, GRPC_ERROR_REF(why));
     CleanupArgsForFailureLocked();
@@ -501,7 +502,7 @@ void SecurityHandshaker::DoHandshake(grpc_tcp_server_acceptor* /*acceptor*/,
   args_ = args;
   on_handshake_done_ = on_handshake_done;
   size_t bytes_received_size = MoveReadBufferIntoHandshakeBuffer();
-  grpc_error* error =
+  grpc_error_handle error =
       DoHandshakerNextLocked(handshake_buffer_, bytes_received_size);
   if (error != GRPC_ERROR_NONE) {
     HandshakeFailedLocked(error);
@@ -517,7 +518,7 @@ void SecurityHandshaker::DoHandshake(grpc_tcp_server_acceptor* /*acceptor*/,
 class FailHandshaker : public Handshaker {
  public:
   const char* name() const override { return "security_fail"; }
-  void Shutdown(grpc_error* why) override { GRPC_ERROR_UNREF(why); }
+  void Shutdown(grpc_error_handle why) override { GRPC_ERROR_UNREF(why); }
   void DoHandshake(grpc_tcp_server_acceptor* /*acceptor*/,
                    grpc_closure* on_handshake_done,
                    HandshakerArgs* /*args*/) override {
index 925a70a..65a7e40 100644 (file)
@@ -28,8 +28,9 @@
 #include "src/core/lib/security/transport/auth_filters.h"
 #include "src/core/lib/slice/slice_internal.h"
 
-static void recv_initial_metadata_ready(void* arg, grpc_error* error);
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
+static void recv_initial_metadata_ready(void* arg, grpc_error_handle error);
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error);
 
 namespace {
 enum async_state {
@@ -79,10 +80,10 @@ struct call_data {
   grpc_transport_stream_op_batch* recv_initial_metadata_batch;
   grpc_closure* original_recv_initial_metadata_ready;
   grpc_closure recv_initial_metadata_ready;
-  grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
+  grpc_error_handle recv_initial_metadata_error = GRPC_ERROR_NONE;
   grpc_closure recv_trailing_metadata_ready;
   grpc_closure* original_recv_trailing_metadata_ready;
-  grpc_error* recv_trailing_metadata_error;
+  grpc_error_handle recv_trailing_metadata_error;
   bool seen_recv_trailing_metadata_ready = false;
   grpc_metadata_array md;
   const grpc_metadata* consumed_md;
@@ -135,7 +136,7 @@ static void on_md_processing_done_inner(grpc_call_element* elem,
                                         size_t num_consumed_md,
                                         const grpc_metadata* response_md,
                                         size_t num_response_md,
-                                        grpc_error* error) {
+                                        grpc_error_handle error) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_transport_stream_op_batch* batch = calld->recv_initial_metadata_batch;
   /* TODO(jboeuf): Implement support for response_md. */
@@ -175,7 +176,7 @@ static void on_md_processing_done(
   // If the call was not cancelled while we were in flight, process the result.
   if (gpr_atm_full_cas(&calld->state, static_cast<gpr_atm>(STATE_INIT),
                        static_cast<gpr_atm>(STATE_DONE))) {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     if (status != GRPC_STATUS_OK) {
       if (error_details == nullptr) {
         error_details = "Authentication metadata processing failed.";
@@ -196,7 +197,7 @@ static void on_md_processing_done(
   GRPC_CALL_STACK_UNREF(calld->owning_call, "server_auth_metadata");
 }
 
-static void cancel_call(void* arg, grpc_error* error) {
+static void cancel_call(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   // If the result was not already processed, invoke the callback now.
@@ -206,9 +207,10 @@ static void cancel_call(void* arg, grpc_error* error) {
     on_md_processing_done_inner(elem, nullptr, 0, nullptr, 0,
                                 GRPC_ERROR_REF(error));
   }
+  GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_call");
 }
 
-static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
+static void recv_initial_metadata_ready(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
@@ -218,6 +220,9 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
         chand->creds->auth_metadata_processor().process != nullptr) {
       // We're calling out to the application, so we need to make sure
       // to drop the call combiner early if we get cancelled.
+      // TODO(yashykt): We would not need this ref if call combiners used
+      // Closure::Run() instead of ExecCtx::Run()
+      GRPC_CALL_STACK_REF(calld->owning_call, "cancel_call");
       GRPC_CLOSURE_INIT(&calld->cancel_closure, cancel_call, elem,
                         grpc_schedule_on_exec_ctx);
       calld->call_combiner->SetNotifyOnCancel(&calld->cancel_closure);
@@ -242,7 +247,8 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
   grpc_core::Closure::Run(DEBUG_LOCATION, closure, GRPC_ERROR_REF(error));
 }
 
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* err) {
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle err) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (calld->original_recv_initial_metadata_ready != nullptr) {
@@ -280,7 +286,7 @@ static void server_auth_start_transport_stream_op_batch(
 }
 
 /* Constructor for call_data */
-static grpc_error* server_auth_init_call_elem(
+static grpc_error_handle server_auth_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   new (elem->call_data) call_data(elem, *args);
   return GRPC_ERROR_NONE;
@@ -295,16 +301,16 @@ static void server_auth_destroy_call_elem(
 }
 
 /* Constructor for channel_data */
-static grpc_error* server_auth_init_channel_elem(
+static grpc_error_handle server_auth_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   grpc_auth_context* auth_context =
       grpc_find_auth_context_in_args(args->channel_args);
   if (auth_context == nullptr) {
-    grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+    grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "No authorization context found. This might be a TRANSIENT failure due "
         "to certificates not having been loaded yet.");
-    gpr_log(GPR_DEBUG, "%s", grpc_error_string(error));
+    gpr_log(GPR_DEBUG, "%s", grpc_error_std_string(error).c_str());
     return error;
   }
   GPR_ASSERT(auth_context != nullptr);
index f78bb8d..4d337b4 100644 (file)
@@ -20,7 +20,8 @@
 
 #include "src/core/lib/security/transport/tsi_error.h"
 
-grpc_error* grpc_set_tsi_error_result(grpc_error* error, tsi_result result) {
+grpc_error_handle grpc_set_tsi_error_result(grpc_error_handle error,
+                                            tsi_result result) {
   return grpc_error_set_int(
       grpc_error_set_str(
           error, GRPC_ERROR_STR_TSI_ERROR,
index 16e04f7..26b8806 100644 (file)
@@ -24,6 +24,7 @@
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/tsi/transport_security_interface.h"
 
-grpc_error* grpc_set_tsi_error_result(grpc_error* error, tsi_result result);
+grpc_error_handle grpc_set_tsi_error_result(grpc_error_handle error,
+                                            tsi_result result);
 
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_TSI_ERROR_H */
index ff2fbc8..34bf88f 100644 (file)
@@ -30,7 +30,7 @@
 
 const char* grpc_json_get_string_property(const grpc_core::Json& json,
                                           const char* prop_name,
-                                          grpc_error** error) {
+                                          grpc_error_handle* error) {
   if (json.type() != grpc_core::Json::Type::OBJECT) {
     if (error != nullptr) {
       *error =
@@ -62,7 +62,7 @@ const char* grpc_json_get_string_property(const grpc_core::Json& json,
 bool grpc_copy_json_string_property(const grpc_core::Json& json,
                                     const char* prop_name,
                                     char** copied_value) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   const char* prop_value =
       grpc_json_get_string_property(json, prop_name, &error);
   GRPC_LOG_IF_ERROR("Could not copy JSON property", error);
index cde9ca9..d3c6ec3 100644 (file)
@@ -35,7 +35,7 @@
 // Gets a child property from a json node.
 const char* grpc_json_get_string_property(const grpc_core::Json& json,
                                           const char* prop_name,
-                                          grpc_error** error);
+                                          grpc_error_handle* error);
 
 // Copies the value of the json child property specified by prop_name.
 // Returns false if the property was not found.
index d749d39..ac0854c 100644 (file)
@@ -290,14 +290,15 @@ static void execute_batch(grpc_call* call,
 
 static void cancel_with_status(grpc_call* c, grpc_status_code status,
                                const char* description);
-static void cancel_with_error(grpc_call* c, grpc_error* error);
-static void destroy_call(void* call_stack, grpc_error* error);
-static void receiving_slice_ready(void* bctlp, grpc_error* error);
-static void set_final_status(grpc_call* call, grpc_error* error);
+static void cancel_with_error(grpc_call* c, grpc_error_handle error);
+static void destroy_call(void* call_stack, grpc_error_handle error);
+static void receiving_slice_ready(void* bctlp, grpc_error_handle error);
+static void set_final_status(grpc_call* call, grpc_error_handle error);
 static void process_data_after_md(batch_control* bctl);
 static void post_batch_completion(batch_control* bctl);
 
-static void add_init_error(grpc_error** composite, grpc_error* new_err) {
+static void add_init_error(grpc_error_handle* composite,
+                           grpc_error_handle new_err) {
   if (new_err == GRPC_ERROR_NONE) return;
   if (*composite == GRPC_ERROR_NONE) {
     *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Call creation failed");
@@ -335,15 +336,15 @@ size_t grpc_call_get_initial_size_estimate() {
          sizeof(grpc_linked_mdelem) * ESTIMATED_MDELEM_COUNT;
 }
 
-grpc_error* grpc_call_create(const grpc_call_create_args* args,
-                             grpc_call** out_call) {
+grpc_error_handle grpc_call_create(const grpc_call_create_args* args,
+                                   grpc_call** out_call) {
   GPR_TIMER_SCOPE("grpc_call_create", 0);
 
   GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
 
   grpc_core::Arena* arena;
   grpc_call* call;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_channel_stack* channel_stack =
       grpc_channel_get_channel_stack(args->channel);
   size_t initial_size = grpc_channel_get_call_size_estimate(args->channel);
@@ -524,7 +525,7 @@ void grpc_call_internal_unref(grpc_call* c REF_ARG) {
   GRPC_CALL_STACK_UNREF(CALL_STACK_FROM_CALL(c), REF_REASON);
 }
 
-static void release_call(void* call, grpc_error* /*error*/) {
+static void release_call(void* call, grpc_error_handle /*error*/) {
   grpc_call* c = static_cast<grpc_call*>(call);
   grpc_channel* channel = c->channel;
   grpc_core::Arena* arena = c->arena;
@@ -533,7 +534,7 @@ static void release_call(void* call, grpc_error* /*error*/) {
   GRPC_CHANNEL_INTERNAL_UNREF(channel, "call");
 }
 
-static void destroy_call(void* call, grpc_error* /*error*/) {
+static void destroy_call(void* call, grpc_error_handle /*error*/) {
   GPR_TIMER_SCOPE("destroy_call", 0);
   size_t i;
   int ii;
@@ -559,8 +560,8 @@ static void destroy_call(void* call, grpc_error* /*error*/) {
     GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
   }
 
-  grpc_error* status_error =
-      reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&c->status_error));
+  grpc_error_handle status_error =
+      reinterpret_cast<grpc_error_handle>(gpr_atm_acq_load(&c->status_error));
   grpc_error_get_status(status_error, c->send_deadline,
                         &c->final_info.final_status, nullptr, nullptr,
                         &(c->final_info.error_string));
@@ -610,11 +611,8 @@ void grpc_call_unref(grpc_call* c) {
     // Unset the call combiner cancellation closure.  This has the
     // effect of scheduling the previously set cancellation closure, if
     // any, so that it can release any internal references it may be
-    // holding to the call stack. Also flush the closures on exec_ctx so that
-    // filters that schedule cancel notification closures on exec_ctx do not
-    // need to take a ref of the call stack to guarantee closure liveness.
+    // holding to the call stack.
     c->call_combiner.SetNotifyOnCancel(nullptr);
-    grpc_core::ExecCtx::Get()->Flush();
   }
   GRPC_CALL_INTERNAL_UNREF(c, "destroy");
 }
@@ -630,7 +628,8 @@ grpc_call_error grpc_call_cancel(grpc_call* call, void* reserved) {
 
 // This is called via the call combiner to start sending a batch down
 // the filter stack.
-static void execute_batch_in_call_combiner(void* arg, grpc_error* /*ignored*/) {
+static void execute_batch_in_call_combiner(void* arg,
+                                           grpc_error_handle /*ignored*/) {
   GPR_TIMER_SCOPE("execute_batch_in_call_combiner", 0);
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
@@ -691,7 +690,7 @@ struct cancel_state {
 };
 // The on_complete callback used when sending a cancel_stream batch down
 // the filter stack.  Yields the call combiner when the batch is done.
-static void done_termination(void* arg, grpc_error* /*error*/) {
+static void done_termination(void* arg, grpc_error_handle /*error*/) {
   cancel_state* state = static_cast<cancel_state*>(arg);
   GRPC_CALL_COMBINER_STOP(&state->call->call_combiner,
                           "on_complete for cancel_stream op");
@@ -699,7 +698,7 @@ static void done_termination(void* arg, grpc_error* /*error*/) {
   gpr_free(state);
 }
 
-static void cancel_with_error(grpc_call* c, grpc_error* error) {
+static void cancel_with_error(grpc_call* c, grpc_error_handle error) {
   if (!gpr_atm_rel_cas(&c->cancelled_with_error, 0, 1)) {
     GRPC_ERROR_UNREF(error);
     return;
@@ -725,8 +724,8 @@ void grpc_call_cancel_internal(grpc_call* call) {
   cancel_with_error(call, GRPC_ERROR_CANCELLED);
 }
 
-static grpc_error* error_from_status(grpc_status_code status,
-                                     const char* description) {
+static grpc_error_handle error_from_status(grpc_status_code status,
+                                           const char* description) {
   // copying 'description' is needed to ensure the grpc_call_cancel_with_status
   // guarantee that can be short-lived.
   return grpc_error_set_int(
@@ -741,10 +740,10 @@ static void cancel_with_status(grpc_call* c, grpc_status_code status,
   cancel_with_error(c, error_from_status(status, description));
 }
 
-static void set_final_status(grpc_call* call, grpc_error* error) {
+static void set_final_status(grpc_call* call, grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_call_error_trace)) {
     gpr_log(GPR_DEBUG, "set_final_status %s", call->is_client ? "CLI" : "SVR");
-    gpr_log(GPR_DEBUG, "%s", grpc_error_string(error));
+    gpr_log(GPR_DEBUG, "%s", grpc_error_std_string(error).c_str());
   }
   if (call->is_client) {
     grpc_error_get_status(error, call->send_deadline,
@@ -770,7 +769,7 @@ static void set_final_status(grpc_call* call, grpc_error* error) {
         call->final_op.server.core_server->channelz_node();
     if (channelz_node != nullptr) {
       if (*call->final_op.server.cancelled ||
-          reinterpret_cast<grpc_error*>(
+          reinterpret_cast<grpc_error_handle>(
               gpr_atm_acq_load(&call->status_error)) != GRPC_ERROR_NONE) {
         channelz_node->RecordCallFailed();
       } else {
@@ -952,7 +951,7 @@ static int prepare_application_metadata(grpc_call* call, int count,
   for (i = 0; i < total_count; i++) {
     grpc_metadata* md = get_md_elem(metadata, additional_metadata, i, count);
     grpc_linked_mdelem* l = linked_from_md(md);
-    grpc_error* error = grpc_metadata_batch_link_tail(batch, l);
+    grpc_error_handle error = grpc_metadata_batch_link_tail(batch, l);
     if (error != GRPC_ERROR_NONE) {
       GRPC_MDELEM_UNREF(l->md);
     }
@@ -1053,14 +1052,14 @@ static void recv_initial_filter(grpc_call* call, grpc_metadata_batch* b) {
 }
 
 static void recv_trailing_filter(void* args, grpc_metadata_batch* b,
-                                 grpc_error* batch_error) {
+                                 grpc_error_handle batch_error) {
   grpc_call* call = static_cast<grpc_call*>(args);
   if (batch_error != GRPC_ERROR_NONE) {
     set_final_status(call, batch_error);
   } else if (b->idx.named.grpc_status != nullptr) {
     grpc_status_code status_code =
         grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     if (status_code != GRPC_STATUS_OK) {
       char* peer = grpc_call_get_peer(call);
       error = grpc_error_set_int(
@@ -1171,8 +1170,8 @@ static void finish_batch_completion(void* user_data,
 }
 
 static void reset_batch_errors(batch_control* bctl) {
-  GRPC_ERROR_UNREF(
-      reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)));
+  GRPC_ERROR_UNREF(reinterpret_cast<grpc_error_handle>(
+      gpr_atm_acq_load(&bctl->batch_error)));
   gpr_atm_rel_store(&bctl->batch_error,
                     reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE));
 }
@@ -1180,8 +1179,8 @@ static void reset_batch_errors(batch_control* bctl) {
 static void post_batch_completion(batch_control* bctl) {
   grpc_call* next_child_call;
   grpc_call* call = bctl->call;
-  grpc_error* error = GRPC_ERROR_REF(
-      reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)));
+  grpc_error_handle error = GRPC_ERROR_REF(reinterpret_cast<grpc_error_handle>(
+      gpr_atm_acq_load(&bctl->batch_error)));
 
   if (bctl->op.send_initial_metadata) {
     grpc_metadata_batch_destroy(
@@ -1254,7 +1253,7 @@ static void finish_batch_step(batch_control* bctl) {
 }
 
 static void continue_receiving_slices(batch_control* bctl) {
-  grpc_error* error;
+  grpc_error_handle error;
   grpc_call* call = bctl->call;
   for (;;) {
     size_t remaining = call->receiving_stream->length() -
@@ -1285,7 +1284,7 @@ static void continue_receiving_slices(batch_control* bctl) {
   }
 }
 
-static void receiving_slice_ready(void* bctlp, grpc_error* error) {
+static void receiving_slice_ready(void* bctlp, grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   bool release_error = false;
@@ -1345,13 +1344,13 @@ static void process_data_after_md(batch_control* bctl) {
   }
 }
 
-static void receiving_stream_ready(void* bctlp, grpc_error* error) {
+static void receiving_stream_ready(void* bctlp, grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   if (error != GRPC_ERROR_NONE) {
     call->receiving_stream.reset();
-    if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
-        GRPC_ERROR_NONE) {
+    if (reinterpret_cast<grpc_error_handle>(
+            gpr_atm_acq_load(&bctl->batch_error)) == GRPC_ERROR_NONE) {
       gpr_atm_rel_store(&bctl->batch_error,
                         reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
     }
@@ -1371,7 +1370,7 @@ static void receiving_stream_ready(void* bctlp, grpc_error* error) {
 // a recv_message op down the filter stack.  Yields the call combiner
 // before processing the received message.
 static void receiving_stream_ready_in_call_combiner(void* bctlp,
-                                                    grpc_error* error) {
+                                                    grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_message_ready");
@@ -1464,7 +1463,8 @@ static void validate_filtered_metadata(batch_control* bctl) {
   }
 }
 
-static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) {
+static void receiving_initial_metadata_ready(void* bctlp,
+                                             grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
 
@@ -1483,8 +1483,8 @@ static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) {
       call->send_deadline = md->deadline;
     }
   } else {
-    if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
-        GRPC_ERROR_NONE) {
+    if (reinterpret_cast<grpc_error_handle>(
+            gpr_atm_acq_load(&bctl->batch_error)) == GRPC_ERROR_NONE) {
       gpr_atm_rel_store(&bctl->batch_error,
                         reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
     }
@@ -1523,7 +1523,8 @@ static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) {
   finish_batch_step(bctl);
 }
 
-static void receiving_trailing_metadata_ready(void* bctlp, grpc_error* error) {
+static void receiving_trailing_metadata_ready(void* bctlp,
+                                              grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_trailing_metadata_ready");
@@ -1533,12 +1534,12 @@ static void receiving_trailing_metadata_ready(void* bctlp, grpc_error* error) {
   finish_batch_step(bctl);
 }
 
-static void finish_batch(void* bctlp, grpc_error* error) {
+static void finish_batch(void* bctlp, grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   GRPC_CALL_COMBINER_STOP(&call->call_combiner, "on_complete");
-  if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
-      GRPC_ERROR_NONE) {
+  if (reinterpret_cast<grpc_error_handle>(
+          gpr_atm_acq_load(&bctl->batch_error)) == GRPC_ERROR_NONE) {
     gpr_atm_rel_store(&bctl->batch_error,
                       reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
   }
@@ -1755,7 +1756,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
         call->send_extra_metadata_count = 1;
         call->send_extra_metadata[0].md = grpc_get_reffed_status_elem(
             op->data.send_status_from_server.status);
-        grpc_error* status_error =
+        grpc_error_handle status_error =
             op->data.send_status_from_server.status == GRPC_STATUS_OK
                 ? GRPC_ERROR_NONE
                 : grpc_error_set_int(
index 34d01db..a6ad3ca 100644 (file)
@@ -55,8 +55,8 @@ typedef struct grpc_call_create_args {
 /* Create a new call based on \a args.
    Regardless of success or failure, always returns a valid new call into *call
    */
-grpc_error* grpc_call_create(const grpc_call_create_args* args,
-                             grpc_call** call);
+grpc_error_handle grpc_call_create(const grpc_call_create_args* args,
+                                   grpc_call** call);
 
 void grpc_call_set_completion_queue(grpc_call* call, grpc_completion_queue* cq);
 
index d68f43f..d3552c8 100644 (file)
  *  (OK, Cancelled, Unknown). */
 #define NUM_CACHED_STATUS_ELEMS 3
 
-static void destroy_channel(void* arg, grpc_error* error);
+static void destroy_channel(void* arg, grpc_error_handle error);
 
 grpc_channel* grpc_channel_create_with_builder(
     grpc_channel_stack_builder* builder,
-    grpc_channel_stack_type channel_stack_type, grpc_error** error) {
+    grpc_channel_stack_type channel_stack_type, grpc_error_handle* error) {
   char* target = gpr_strdup(grpc_channel_stack_builder_get_target(builder));
   grpc_channel_args* args = grpc_channel_args_copy(
       grpc_channel_stack_builder_get_channel_arguments(builder));
@@ -70,12 +70,12 @@ grpc_channel* grpc_channel_create_with_builder(
   } else {
     GRPC_STATS_INC_CLIENT_CHANNELS_CREATED();
   }
-  grpc_error* builder_error = grpc_channel_stack_builder_finish(
+  grpc_error_handle builder_error = grpc_channel_stack_builder_finish(
       builder, sizeof(grpc_channel), 1, destroy_channel, nullptr,
       reinterpret_cast<void**>(&channel));
   if (builder_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "channel stack builder failed: %s",
-            grpc_error_string(builder_error));
+            grpc_error_std_string(builder_error).c_str());
     GPR_ASSERT(channel == nullptr);
     if (error != nullptr) {
       *error = builder_error;
@@ -225,7 +225,7 @@ grpc_channel* grpc_channel_create(const char* target,
                                   grpc_channel_stack_type channel_stack_type,
                                   grpc_transport* optional_transport,
                                   grpc_resource_user* resource_user,
-                                  grpc_error** error) {
+                                  grpc_error_handle* error) {
   // We need to make sure that grpc_shutdown() does not shut things down
   // until after the channel is destroyed.  However, the channel may not
   // actually be destroyed by the time grpc_channel_destroy() returns,
@@ -497,7 +497,7 @@ grpc_call* grpc_channel_create_registered_call(
   return call;
 }
 
-static void destroy_channel(void* arg, grpc_error* /*error*/) {
+static void destroy_channel(void* arg, grpc_error_handle /*error*/) {
   grpc_channel* channel = static_cast<grpc_channel*>(arg);
   if (channel->channelz_node != nullptr) {
     channel->channelz_node->AddTraceEvent(
index bb72363..8a14a72 100644 (file)
@@ -35,7 +35,7 @@ grpc_channel* grpc_channel_create(const char* target,
                                   grpc_channel_stack_type channel_stack_type,
                                   grpc_transport* optional_transport,
                                   grpc_resource_user* resource_user = nullptr,
-                                  grpc_error** error = nullptr);
+                                  grpc_error_handle* error = nullptr);
 
 /** The same as grpc_channel_destroy, but doesn't create an ExecCtx, and so
  * is safe to use from within core. */
@@ -43,7 +43,8 @@ void grpc_channel_destroy_internal(grpc_channel* channel);
 
 grpc_channel* grpc_channel_create_with_builder(
     grpc_channel_stack_builder* builder,
-    grpc_channel_stack_type channel_stack_type, grpc_error** error = nullptr);
+    grpc_channel_stack_type channel_stack_type,
+    grpc_error_handle* error = nullptr);
 
 /** Create a call given a grpc_channel, in order to call \a method.
     Progress is tied to activity on \a pollset_set. The returned call object is
index 82e5521..a6e53ec 100644 (file)
@@ -38,7 +38,7 @@ static void ping_destroy(void* arg, grpc_cq_completion* /*storage*/) {
   gpr_free(arg);
 }
 
-static void ping_done(void* arg, grpc_error* error) {
+static void ping_done(void* arg, grpc_error_handle error) {
   ping_result* pr = static_cast<ping_result*>(arg);
   grpc_cq_end_op(pr->cq, pr->tag, GRPC_ERROR_REF(error), ping_destroy, pr,
                  &pr->completion_storage);
index 9091c9d..2b889e0 100644 (file)
@@ -70,10 +70,10 @@ struct cq_poller_vtable {
   bool can_listen;
   size_t (*size)(void);
   void (*init)(grpc_pollset* pollset, gpr_mu** mu);
-  grpc_error* (*kick)(grpc_pollset* pollset,
-                      grpc_pollset_worker* specific_worker);
-  grpc_error* (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
-                      grpc_millis deadline);
+  grpc_error_handle (*kick)(grpc_pollset* pollset,
+                            grpc_pollset_worker* specific_worker);
+  grpc_error_handle (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
+                            grpc_millis deadline);
   void (*shutdown)(grpc_pollset* pollset, grpc_closure* closure);
   void (*destroy)(grpc_pollset* pollset);
 };
@@ -103,9 +103,9 @@ void non_polling_poller_destroy(grpc_pollset* pollset) {
   gpr_mu_destroy(&npp->mu);
 }
 
-grpc_error* non_polling_poller_work(grpc_pollset* pollset,
-                                    grpc_pollset_worker** worker,
-                                    grpc_millis deadline) {
+grpc_error_handle non_polling_poller_work(grpc_pollset* pollset,
+                                          grpc_pollset_worker** worker,
+                                          grpc_millis deadline) {
   non_polling_poller* npp = reinterpret_cast<non_polling_poller*>(pollset);
   if (npp->shutdown) return GRPC_ERROR_NONE;
   if (npp->kicked_without_poller) {
@@ -145,8 +145,8 @@ grpc_error* non_polling_poller_work(grpc_pollset* pollset,
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* non_polling_poller_kick(grpc_pollset* pollset,
-                                    grpc_pollset_worker* specific_worker) {
+grpc_error_handle non_polling_poller_kick(
+    grpc_pollset* pollset, grpc_pollset_worker* specific_worker) {
   non_polling_poller* p = reinterpret_cast<non_polling_poller*>(pollset);
   if (specific_worker == nullptr) {
     specific_worker = reinterpret_cast<grpc_pollset_worker*>(p->root);
@@ -202,7 +202,7 @@ struct cq_vtable {
   void (*shutdown)(grpc_completion_queue* cq);
   void (*destroy)(void* data);
   bool (*begin_op)(grpc_completion_queue* cq, void* tag);
-  void (*end_op)(grpc_completion_queue* cq, void* tag, grpc_error* error,
+  void (*end_op)(grpc_completion_queue* cq, void* tag, grpc_error_handle error,
                  void (*done)(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,
@@ -376,17 +376,17 @@ static bool cq_begin_op_for_callback(grpc_completion_queue* cq, void* tag);
 // 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,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle 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,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle 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,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle error,
     void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
     grpc_cq_completion* storage, bool internal);
 
@@ -439,7 +439,7 @@ grpc_core::TraceFlag grpc_cq_pluck_trace(false, "queue_pluck");
     }                                                    \
   } while (0)
 
-static void on_pollset_shutdown_done(void* arg, grpc_error* error);
+static void on_pollset_shutdown_done(void* arg, grpc_error_handle error);
 
 void grpc_cq_global_init() {
   gpr_tls_init(&g_cached_event);
@@ -604,7 +604,7 @@ void grpc_cq_internal_ref(grpc_completion_queue* cq) {
   cq->owning_refs.Ref(debug_location, reason);
 }
 
-static void on_pollset_shutdown_done(void* arg, grpc_error* /*error*/) {
+static void on_pollset_shutdown_done(void* arg, grpc_error_handle /*error*/) {
   grpc_completion_queue* cq = static_cast<grpc_completion_queue*>(arg);
   GRPC_CQ_INTERNAL_UNREF(cq, "pollset_destroy");
 }
@@ -690,7 +690,7 @@ bool grpc_cq_begin_op(grpc_completion_queue* cq, void* tag) {
  * completion
  * type of GRPC_CQ_NEXT) */
 static void cq_end_op_for_next(
-    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle 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);
@@ -698,14 +698,15 @@ static void cq_end_op_for_next(
   if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
       (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
        error != GRPC_ERROR_NONE)) {
-    const char* errmsg = grpc_error_string(error);
+    std::string errmsg = grpc_error_std_string(error);
     GRPC_API_TRACE(
         "cq_end_op_for_next(cq=%p, tag=%p, error=%s, "
         "done=%p, done_arg=%p, storage=%p)",
-        6, (cq, tag, errmsg, done, done_arg, storage));
+        6, (cq, tag, errmsg.c_str(), done, done_arg, storage));
     if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
         error != GRPC_ERROR_NONE) {
-      gpr_log(GPR_INFO, "Operation failed: tag=%p, error=%s", tag, errmsg);
+      gpr_log(GPR_INFO, "Operation failed: tag=%p, error=%s", tag,
+              errmsg.c_str());
     }
   }
   cq_next_data* cqd = static_cast<cq_next_data*> DATA_FROM_CQ(cq);
@@ -736,13 +737,13 @@ static void cq_end_op_for_next(
       /* Only kick if this is the first item queued */
       if (is_first) {
         gpr_mu_lock(cq->mu);
-        grpc_error* kick_error =
+        grpc_error_handle kick_error =
             cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), nullptr);
         gpr_mu_unlock(cq->mu);
 
         if (kick_error != GRPC_ERROR_NONE) {
-          const char* msg = grpc_error_string(kick_error);
-          gpr_log(GPR_ERROR, "Kick failed: %s", msg);
+          gpr_log(GPR_ERROR, "Kick failed: %s",
+                  grpc_error_std_string(kick_error).c_str());
           GRPC_ERROR_UNREF(kick_error);
         }
       }
@@ -771,7 +772,7 @@ static void cq_end_op_for_next(
  * completion
  * type of GRPC_CQ_PLUCK) */
 static void cq_end_op_for_pluck(
-    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle 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);
@@ -782,14 +783,15 @@ static void cq_end_op_for_pluck(
   if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
       (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
        error != GRPC_ERROR_NONE)) {
-    const char* errmsg = grpc_error_string(error);
+    std::string errmsg = grpc_error_std_string(error).c_str();
     GRPC_API_TRACE(
         "cq_end_op_for_pluck(cq=%p, tag=%p, error=%s, "
         "done=%p, done_arg=%p, storage=%p)",
-        6, (cq, tag, errmsg, done, done_arg, storage));
+        6, (cq, tag, errmsg.c_str(), done, done_arg, storage));
     if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
         error != GRPC_ERROR_NONE) {
-      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
+      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag,
+              errmsg.c_str());
     }
   }
 
@@ -820,15 +822,12 @@ static void cq_end_op_for_pluck(
       }
     }
 
-    grpc_error* kick_error =
+    grpc_error_handle kick_error =
         cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), pluck_worker);
-
     gpr_mu_unlock(cq->mu);
-
     if (kick_error != GRPC_ERROR_NONE) {
-      const char* msg = grpc_error_string(kick_error);
-      gpr_log(GPR_ERROR, "Kick failed: %s", msg);
-
+      gpr_log(GPR_ERROR, "Kick failed: %s",
+              grpc_error_std_string(kick_error).c_str());
       GRPC_ERROR_UNREF(kick_error);
     }
   }
@@ -836,14 +835,14 @@ static void cq_end_op_for_pluck(
   GRPC_ERROR_UNREF(error);
 }
 
-static void functor_callback(void* arg, grpc_error* error) {
+static void functor_callback(void* arg, grpc_error_handle 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,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle 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_callback", 0);
@@ -853,14 +852,15 @@ static void cq_end_op_for_callback(
   if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
       (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
        error != GRPC_ERROR_NONE)) {
-    const char* errmsg = grpc_error_string(error);
+    std::string errmsg = grpc_error_std_string(error);
     GRPC_API_TRACE(
         "cq_end_op_for_callback(cq=%p, tag=%p, error=%s, "
         "done=%p, done_arg=%p, storage=%p)",
-        6, (cq, tag, errmsg, done, done_arg, storage));
+        6, (cq, tag, errmsg.c_str(), done, done_arg, storage));
     if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
         error != GRPC_ERROR_NONE) {
-      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
+      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag,
+              errmsg.c_str());
     }
   }
 
@@ -896,7 +896,8 @@ static void cq_end_op_for_callback(
       GRPC_CLOSURE_CREATE(functor_callback, functor, nullptr), error);
 }
 
-void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
+void grpc_cq_end_op(grpc_completion_queue* cq, void* tag,
+                    grpc_error_handle error,
                     void (*done)(void* done_arg, grpc_cq_completion* storage),
                     void* done_arg, grpc_cq_completion* storage,
                     bool internal) {
@@ -1056,14 +1057,13 @@ static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline,
     /* The main polling work happens in grpc_pollset_work */
     gpr_mu_lock(cq->mu);
     cq->num_polls++;
-    grpc_error* err = cq->poller_vtable->work(POLLSET_FROM_CQ(cq), nullptr,
-                                              iteration_deadline);
+    grpc_error_handle err = cq->poller_vtable->work(
+        POLLSET_FROM_CQ(cq), nullptr, iteration_deadline);
     gpr_mu_unlock(cq->mu);
 
     if (err != GRPC_ERROR_NONE) {
-      const char* msg = grpc_error_string(err);
-      gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
-
+      gpr_log(GPR_ERROR, "Completion queue next failed: %s",
+              grpc_error_std_string(err).c_str());
       GRPC_ERROR_UNREF(err);
       ret.type = GRPC_QUEUE_TIMEOUT;
       ret.success = 0;
@@ -1299,14 +1299,13 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag,
       break;
     }
     cq->num_polls++;
-    grpc_error* err =
+    grpc_error_handle err =
         cq->poller_vtable->work(POLLSET_FROM_CQ(cq), &worker, deadline_millis);
     if (err != GRPC_ERROR_NONE) {
       del_plucker(cq, tag, &worker);
       gpr_mu_unlock(cq->mu);
-      const char* msg = grpc_error_string(err);
-      gpr_log(GPR_ERROR, "Completion queue pluck failed: %s", msg);
-
+      gpr_log(GPR_ERROR, "Completion queue pluck failed: %s",
+              grpc_error_std_string(err).c_str());
       GRPC_ERROR_UNREF(err);
       ret.type = GRPC_QUEUE_TIMEOUT;
       ret.success = 0;
index 59116d4..2bf91fa 100644 (file)
@@ -77,7 +77,8 @@ bool grpc_cq_begin_op(grpc_completion_queue* cq, void* tag);
 
 /* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to
    grpc_cq_begin_op */
-void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
+void grpc_cq_end_op(grpc_completion_queue* cq, void* tag,
+                    grpc_error_handle error,
                     void (*done)(void* done_arg, grpc_cq_completion* storage),
                     void* done_arg, grpc_cq_completion* storage,
                     bool internal = false);
index f92c192..65e659a 100644 (file)
@@ -44,14 +44,14 @@ namespace {
 struct ChannelData {
   explicit ChannelData(grpc_channel_element_args* args)
       : state_tracker("lame_channel", GRPC_CHANNEL_SHUTDOWN) {
-    grpc_error* err = grpc_channel_args_find_pointer<grpc_error>(
+    grpc_error_handle err = grpc_channel_args_find_pointer<grpc_error>(
         args->channel_args, GRPC_ARG_LAME_FILTER_ERROR);
     if (err != nullptr) error = GRPC_ERROR_REF(err);
   }
 
   ~ChannelData() { GRPC_ERROR_UNREF(error); }
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Mutex mu;
   ConnectivityStateTracker state_tracker;
 };
@@ -98,8 +98,8 @@ static void lame_start_transport_op(grpc_channel_element* elem,
   }
 }
 
-static grpc_error* lame_init_call_elem(grpc_call_element* elem,
-                                       const grpc_call_element_args* args) {
+static grpc_error_handle lame_init_call_elem(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   CallData* calld = static_cast<CallData*>(elem->call_data);
   calld->call_combiner = args->call_combiner;
   return GRPC_ERROR_NONE;
@@ -111,8 +111,8 @@ static void lame_destroy_call_elem(grpc_call_element* /*elem*/,
   ExecCtx::Run(DEBUG_LOCATION, then_schedule_closure, GRPC_ERROR_NONE);
 }
 
-static grpc_error* lame_init_channel_elem(grpc_channel_element* elem,
-                                          grpc_channel_element_args* args) {
+static grpc_error_handle lame_init_channel_elem(
+    grpc_channel_element* elem, grpc_channel_element_args* args) {
   new (elem->channel_data) ChannelData(args);
   return GRPC_ERROR_NONE;
 }
@@ -122,13 +122,13 @@ static void lame_destroy_channel_elem(grpc_channel_element* elem) {
   chand->~ChannelData();
 }
 
-// Channel arg vtable for a grpc_error*.
+// Channel arg vtable for a grpc_error_handle.
 void* ErrorCopy(void* p) {
-  grpc_error* error = static_cast<grpc_error*>(p);
+  grpc_error_handle error = static_cast<grpc_error_handle>(p);
   return GRPC_ERROR_REF(error);
 }
 void ErrorDestroy(void* p) {
-  grpc_error* error = static_cast<grpc_error*>(p);
+  grpc_error_handle error = static_cast<grpc_error_handle>(p);
   GRPC_ERROR_UNREF(error);
 }
 int ErrorCompare(void* p, void* q) { return GPR_ICMP(p, q); }
@@ -137,7 +137,7 @@ const grpc_arg_pointer_vtable kLameFilterErrorArgVtable = {
 
 }  // namespace
 
-grpc_arg MakeLameClientErrorArg(grpc_error* error) {
+grpc_arg MakeLameClientErrorArg(grpc_error_handle error) {
   return grpc_channel_arg_pointer_create(
       const_cast<char*>(GRPC_ARG_LAME_FILTER_ERROR), error,
       &kLameFilterErrorArgVtable);
@@ -169,7 +169,7 @@ grpc_channel* grpc_lame_client_channel_create(const char* target,
       "grpc_lame_client_channel_create(target=%s, error_code=%d, "
       "error_message=%s)",
       3, (target, (int)error_code, error_message));
-  grpc_error* error = grpc_error_set_str(
+  grpc_error_handle error = grpc_error_set_str(
       grpc_error_set_int(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("lame client channel"),
           GRPC_ERROR_INT_GRPC_STATUS, error_code),
index 94c7e55..41759cb 100644 (file)
@@ -25,7 +25,7 @@
 
 namespace grpc_core {
 // Does NOT take ownership of error.
-grpc_arg MakeLameClientErrorArg(grpc_error* error);
+grpc_arg MakeLameClientErrorArg(grpc_error_handle error);
 }  // namespace grpc_core
 
 extern const grpc_channel_filter grpc_lame_filter;
index a97c1c5..a8b4aaa 100644 (file)
@@ -159,7 +159,7 @@ class Server::RequestMatcherInterface {
   // Mark all application-requested RPCs failed if they have not been matched to
   // an incoming RPC. The error parameter indicates why the RPCs are being
   // failed (always server shutdown in all current implementations).
-  virtual void KillRequests(grpc_error* error) = 0;
+  virtual void KillRequests(grpc_error_handle error) = 0;
 
   // How many request queues are supported by this matcher. This is an abstract
   // concept that essentially maps to gRPC completion queues.
@@ -211,7 +211,7 @@ class Server::RealRequestMatcher : public RequestMatcherInterface {
     }
   }
 
-  void KillRequests(grpc_error* error) override {
+  void KillRequests(grpc_error_handle error) override {
     for (size_t i = 0; i < requests_per_cq_.size(); i++) {
       RequestedCall* rc;
       while ((rc = reinterpret_cast<RequestedCall*>(
@@ -336,7 +336,9 @@ class Server::AllocatingRequestMatcherBase : public RequestMatcherInterface {
 
   void ZombifyPending() override {}
 
-  void KillRequests(grpc_error* error) override { GRPC_ERROR_UNREF(error); }
+  void KillRequests(grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
 
   size_t request_queue_count() const override { return 0; }
 
@@ -444,7 +446,7 @@ class ChannelBroadcaster {
   }
 
   // Broadcasts a shutdown on each channel.
-  void BroadcastShutdown(bool send_goaway, grpc_error* force_disconnect) {
+  void BroadcastShutdown(bool send_goaway, grpc_error_handle force_disconnect) {
     for (grpc_channel* channel : channels_) {
       SendShutdown(channel, send_goaway, GRPC_ERROR_REF(force_disconnect));
       GRPC_CHANNEL_INTERNAL_UNREF(channel, "broadcast");
@@ -459,14 +461,14 @@ class ChannelBroadcaster {
     grpc_slice slice;
   };
 
-  static void ShutdownCleanup(void* arg, grpc_error* /*error*/) {
+  static void ShutdownCleanup(void* arg, grpc_error_handle /*error*/) {
     ShutdownCleanupArgs* a = static_cast<ShutdownCleanupArgs*>(arg);
     grpc_slice_unref_internal(a->slice);
     delete a;
   }
 
   static void SendShutdown(grpc_channel* channel, bool send_goaway,
-                           grpc_error* send_disconnect) {
+                           grpc_error_handle send_disconnect) {
     ShutdownCleanupArgs* sc = new ShutdownCleanupArgs;
     GRPC_CLOSURE_INIT(&sc->closure, ShutdownCleanup, sc,
                       grpc_schedule_on_exec_ctx);
@@ -607,13 +609,13 @@ void Server::Start() {
   starting_cv_.Signal();
 }
 
-grpc_error* Server::SetupTransport(
+grpc_error_handle Server::SetupTransport(
     grpc_transport* transport, grpc_pollset* accepting_pollset,
     const grpc_channel_args* args,
     const RefCountedPtr<grpc_core::channelz::SocketNode>& socket_node,
     grpc_resource_user* resource_user) {
   // Create channel.
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_channel* channel = grpc_channel_create(
       nullptr, args, GRPC_SERVER_CHANNEL, transport, resource_user, &error);
   if (channel == nullptr) {
@@ -710,7 +712,8 @@ void Server::DoneRequestEvent(void* req, grpc_cq_completion* /*c*/) {
   delete static_cast<RequestedCall*>(req);
 }
 
-void Server::FailCall(size_t cq_idx, RequestedCall* rc, grpc_error* error) {
+void Server::FailCall(size_t cq_idx, RequestedCall* rc,
+                      grpc_error_handle error) {
   *rc->call = nullptr;
   rc->initial_metadata->count = 0;
   GPR_ASSERT(error != GRPC_ERROR_NONE);
@@ -750,7 +753,7 @@ void Server::MaybeFinishShutdown() {
   }
 }
 
-void Server::KillPendingWorkLocked(grpc_error* error) {
+void Server::KillPendingWorkLocked(grpc_error_handle error) {
   if (started_) {
     unregistered_request_matcher_->KillRequests(GRPC_ERROR_REF(error));
     unregistered_request_matcher_->ZombifyPending();
@@ -772,7 +775,7 @@ std::vector<grpc_channel*> Server::GetChannelsLocked() const {
   return channels;
 }
 
-void Server::ListenerDestroyDone(void* arg, grpc_error* /*error*/) {
+void Server::ListenerDestroyDone(void* arg, grpc_error_handle /*error*/) {
   Server* server = static_cast<Server*>(arg);
   MutexLock lock(&server->mu_global_);
   server->listeners_destroyed_++;
@@ -1134,7 +1137,7 @@ void Server::ChannelData::AcceptStream(void* arg, grpc_transport* /*transport*/,
   args.add_initial_metadata_count = 0;
   args.send_deadline = GRPC_MILLIS_INF_FUTURE;
   grpc_call* call;
-  grpc_error* error = grpc_call_create(&args, &call);
+  grpc_error_handle error = grpc_call_create(&args, &call);
   grpc_call_element* elem =
       grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
   auto* calld = static_cast<Server::CallData*>(elem->call_data);
@@ -1146,7 +1149,8 @@ void Server::ChannelData::AcceptStream(void* arg, grpc_transport* /*transport*/,
   calld->Start(elem);
 }
 
-void Server::ChannelData::FinishDestroy(void* arg, grpc_error* /*error*/) {
+void Server::ChannelData::FinishDestroy(void* arg,
+                                        grpc_error_handle /*error*/) {
   auto* chand = static_cast<Server::ChannelData*>(arg);
   Server* server = chand->server_.get();
   GRPC_CHANNEL_INTERNAL_UNREF(chand->channel_, "server");
@@ -1173,7 +1177,7 @@ void Server::ChannelData::Destroy() {
       op);
 }
 
-grpc_error* Server::ChannelData::InitChannelElement(
+grpc_error_handle Server::ChannelData::InitChannelElement(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   GPR_ASSERT(args->is_first);
   GPR_ASSERT(!args->is_last);
@@ -1284,7 +1288,7 @@ void Server::CallData::Publish(size_t cq_idx, RequestedCall* rc) {
                  rc, &rc->completion, true);
 }
 
-void Server::CallData::PublishNewRpc(void* arg, grpc_error* error) {
+void Server::CallData::PublishNewRpc(void* arg, grpc_error_handle error) {
   grpc_call_element* call_elem = static_cast<grpc_call_element*>(arg);
   auto* calld = static_cast<Server::CallData*>(call_elem->call_data);
   auto* chand = static_cast<Server::ChannelData*>(call_elem->channel_data);
@@ -1300,7 +1304,7 @@ void Server::CallData::PublishNewRpc(void* arg, grpc_error* error) {
 
 namespace {
 
-void KillZombieClosure(void* call, grpc_error* /*error*/) {
+void KillZombieClosure(void* call, grpc_error_handle /*error*/) {
   grpc_call_unref(static_cast<grpc_call*>(call));
 }
 
@@ -1352,8 +1356,8 @@ void Server::CallData::StartNewRpc(grpc_call_element* elem) {
   }
 }
 
-void Server::CallData::RecvInitialMetadataBatchComplete(void* arg,
-                                                        grpc_error* error) {
+void Server::CallData::RecvInitialMetadataBatchComplete(
+    void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   auto* calld = static_cast<Server::CallData*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
@@ -1385,7 +1389,8 @@ void Server::CallData::StartTransportStreamOpBatchImpl(
   grpc_call_next_op(elem, batch);
 }
 
-void Server::CallData::RecvInitialMetadataReady(void* arg, grpc_error* error) {
+void Server::CallData::RecvInitialMetadataReady(void* arg,
+                                                grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   grpc_millis op_deadline;
@@ -1411,7 +1416,7 @@ void Server::CallData::RecvInitialMetadataReady(void* arg, grpc_error* error) {
     /* do nothing */
   } else {
     /* Pass the error reference to calld->recv_initial_metadata_error */
-    grpc_error* src_error = error;
+    grpc_error_handle src_error = error;
     error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
         "Missing :authority or :path", &src_error, 1);
     GRPC_ERROR_UNREF(src_error);
@@ -1428,7 +1433,8 @@ void Server::CallData::RecvInitialMetadataReady(void* arg, grpc_error* error) {
   Closure::Run(DEBUG_LOCATION, closure, error);
 }
 
-void Server::CallData::RecvTrailingMetadataReady(void* arg, grpc_error* error) {
+void Server::CallData::RecvTrailingMetadataReady(void* arg,
+                                                 grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   if (calld->original_recv_initial_metadata_ready_ != nullptr) {
@@ -1449,7 +1455,7 @@ void Server::CallData::RecvTrailingMetadataReady(void* arg, grpc_error* error) {
                error);
 }
 
-grpc_error* Server::CallData::InitCallElement(
+grpc_error_handle Server::CallData::InitCallElement(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   auto* chand = static_cast<ChannelData*>(elem->channel_data);
   new (elem->call_data) Server::CallData(elem, *args, chand->server());
index ef8ad12..413a5a8 100644 (file)
@@ -128,7 +128,7 @@ class Server : public InternallyRefCounted<Server> {
 
   // Sets up a transport.  Creates a channel stack and binds the transport to
   // the server.  Called from the listener when a new connection is accepted.
-  grpc_error* SetupTransport(
+  grpc_error_handle SetupTransport(
       grpc_transport* transport, grpc_pollset* accepting_pollset,
       const grpc_channel_args* args,
       const RefCountedPtr<channelz::SocketNode>& socket_node,
@@ -202,8 +202,8 @@ class Server : public InternallyRefCounted<Server> {
                                                  bool is_idempotent);
 
     // Filter vtable functions.
-    static grpc_error* InitChannelElement(grpc_channel_element* elem,
-                                          grpc_channel_element_args* args);
+    static grpc_error_handle InitChannelElement(
+        grpc_channel_element* elem, grpc_channel_element_args* args);
     static void DestroyChannelElement(grpc_channel_element* elem);
 
    private:
@@ -214,7 +214,7 @@ class Server : public InternallyRefCounted<Server> {
 
     void Destroy() ABSL_EXCLUSIVE_LOCKS_REQUIRED(server_->mu_global_);
 
-    static void FinishDestroy(void* arg, grpc_error* error);
+    static void FinishDestroy(void* arg, grpc_error_handle error);
 
     RefCountedPtr<Server> server_;
     grpc_channel* channel_;
@@ -264,8 +264,8 @@ class Server : public InternallyRefCounted<Server> {
     void FailCallCreation();
 
     // Filter vtable functions.
-    static grpc_error* InitCallElement(grpc_call_element* elem,
-                                       const grpc_call_element_args* args);
+    static grpc_error_handle InitCallElement(
+        grpc_call_element* elem, const grpc_call_element_args* args);
     static void DestroyCallElement(grpc_call_element* elem,
                                    const grpc_call_final_info* /*final_info*/,
                                    grpc_closure* /*ignored*/);
@@ -274,15 +274,16 @@ class Server : public InternallyRefCounted<Server> {
 
    private:
     // Helper functions for handling calls at the top of the call stack.
-    static void RecvInitialMetadataBatchComplete(void* arg, grpc_error* error);
+    static void RecvInitialMetadataBatchComplete(void* arg,
+                                                 grpc_error_handle error);
     void StartNewRpc(grpc_call_element* elem);
-    static void PublishNewRpc(void* arg, grpc_error* error);
+    static void PublishNewRpc(void* arg, grpc_error_handle error);
 
     // Functions used inside the call stack.
     void StartTransportStreamOpBatchImpl(grpc_call_element* elem,
                                          grpc_transport_stream_op_batch* batch);
-    static void RecvInitialMetadataReady(void* arg, grpc_error* error);
-    static void RecvTrailingMetadataReady(void* arg, grpc_error* error);
+    static void RecvInitialMetadataReady(void* arg, grpc_error_handle error);
+    static void RecvTrailingMetadataReady(void* arg, grpc_error_handle error);
 
     RefCountedPtr<Server> server_;
 
@@ -309,12 +310,12 @@ class Server : public InternallyRefCounted<Server> {
     uint32_t recv_initial_metadata_flags_ = 0;
     grpc_closure recv_initial_metadata_ready_;
     grpc_closure* original_recv_initial_metadata_ready_;
-    grpc_error* recv_initial_metadata_error_ = GRPC_ERROR_NONE;
+    grpc_error_handle recv_initial_metadata_error_ = GRPC_ERROR_NONE;
 
     bool seen_recv_trailing_metadata_ready_ = false;
     grpc_closure recv_trailing_metadata_ready_;
     grpc_closure* original_recv_trailing_metadata_ready_;
-    grpc_error* recv_trailing_metadata_error_ = GRPC_ERROR_NONE;
+    grpc_error_handle recv_trailing_metadata_error_ = GRPC_ERROR_NONE;
 
     grpc_closure publish_;
 
@@ -336,7 +337,7 @@ class Server : public InternallyRefCounted<Server> {
     grpc_cq_completion completion;
   };
 
-  static void ListenerDestroyDone(void* arg, grpc_error* error);
+  static void ListenerDestroyDone(void* arg, grpc_error_handle error);
 
   static void DoneShutdownEvent(void* server,
                                 grpc_cq_completion* /*completion*/) {
@@ -345,13 +346,13 @@ class Server : public InternallyRefCounted<Server> {
 
   static void DoneRequestEvent(void* req, grpc_cq_completion* completion);
 
-  void FailCall(size_t cq_idx, RequestedCall* rc, grpc_error* error);
+  void FailCall(size_t cq_idx, RequestedCall* rc, grpc_error_handle error);
   grpc_call_error QueueRequestedCall(size_t cq_idx, RequestedCall* rc);
 
   void MaybeFinishShutdown() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_global_)
       ABSL_LOCKS_EXCLUDED(mu_call_);
 
-  void KillPendingWorkLocked(grpc_error* error)
+  void KillPendingWorkLocked(grpc_error_handle error)
       ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_call_);
 
   static grpc_call_error ValidateServerRequest(
index 138f574..c1ec936 100644 (file)
@@ -30,9 +30,9 @@
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/surface/validate_metadata.h"
 
-static grpc_error* conforms_to(const grpc_slice& slice,
-                               const uint8_t* legal_bits,
-                               const char* err_desc) {
+static grpc_error_handle 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);
   for (; p != e; p++) {
@@ -40,7 +40,7 @@ static grpc_error* conforms_to(const grpc_slice& slice,
     int byte = idx / 8;
     int bit = idx % 8;
     if ((legal_bits[byte] & (1 << bit)) == 0) {
-      grpc_error* error = grpc_error_set_str(
+      grpc_error_handle 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)),
@@ -52,13 +52,13 @@ static grpc_error* conforms_to(const grpc_slice& slice,
   return GRPC_ERROR_NONE;
 }
 
-static int error2int(grpc_error* error) {
+static int error2int(grpc_error_handle error) {
   int r = (error == GRPC_ERROR_NONE);
   GRPC_ERROR_UNREF(error);
   return r;
 }
 
-grpc_error* grpc_validate_header_key_is_legal(const grpc_slice& slice) {
+grpc_error_handle 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,
@@ -82,7 +82,7 @@ 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_error_handle 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,
index 07c802c..daaaa1a 100644 (file)
@@ -27,8 +27,9 @@
 
 #include "src/core/lib/iomgr/error.h"
 
-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);
+grpc_error_handle grpc_validate_header_key_is_legal(const grpc_slice& slice);
+grpc_error_handle 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) {
index 737c2eb..8061df0 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <grpc/grpc.h>
 
-const char* grpc_version_string(void) { return "15.0.0"; }
+const char* grpc_version_string(void) { return "16.0.0"; }
 
-const char* grpc_g_stands_for(void) { return "gilded"; }
+const char* grpc_g_stands_for(void) {
+  return "guadalupe_river_park_conservancy";
+}
index 82f34ca..3cc5275 100644 (file)
@@ -59,7 +59,7 @@ bool SliceBufferByteStream::Next(size_t /*max_size_hint*/,
   return true;
 }
 
-grpc_error* SliceBufferByteStream::Pull(grpc_slice* slice) {
+grpc_error_handle SliceBufferByteStream::Pull(grpc_slice* slice) {
   if (GPR_UNLIKELY(shutdown_error_ != GRPC_ERROR_NONE)) {
     return GRPC_ERROR_REF(shutdown_error_);
   }
@@ -67,7 +67,7 @@ grpc_error* SliceBufferByteStream::Pull(grpc_slice* slice) {
   return GRPC_ERROR_NONE;
 }
 
-void SliceBufferByteStream::Shutdown(grpc_error* error) {
+void SliceBufferByteStream::Shutdown(grpc_error_handle error) {
   GRPC_ERROR_UNREF(shutdown_error_);
   shutdown_error_ = error;
 }
@@ -117,7 +117,7 @@ bool ByteStreamCache::CachingByteStream::Next(size_t max_size_hint,
   return cache_->underlying_stream_->Next(max_size_hint, on_complete);
 }
 
-grpc_error* ByteStreamCache::CachingByteStream::Pull(grpc_slice* slice) {
+grpc_error_handle ByteStreamCache::CachingByteStream::Pull(grpc_slice* slice) {
   if (shutdown_error_ != GRPC_ERROR_NONE) {
     return GRPC_ERROR_REF(shutdown_error_);
   }
@@ -128,7 +128,7 @@ grpc_error* ByteStreamCache::CachingByteStream::Pull(grpc_slice* slice) {
     return GRPC_ERROR_NONE;
   }
   GPR_ASSERT(cache_->underlying_stream_ != nullptr);
-  grpc_error* error = cache_->underlying_stream_->Pull(slice);
+  grpc_error_handle error = cache_->underlying_stream_->Pull(slice);
   if (error == GRPC_ERROR_NONE) {
     grpc_slice_buffer_add(&cache_->cache_buffer_,
                           grpc_slice_ref_internal(*slice));
@@ -142,7 +142,7 @@ grpc_error* ByteStreamCache::CachingByteStream::Pull(grpc_slice* slice) {
   return error;
 }
 
-void ByteStreamCache::CachingByteStream::Shutdown(grpc_error* error) {
+void ByteStreamCache::CachingByteStream::Shutdown(grpc_error_handle error) {
   GRPC_ERROR_UNREF(shutdown_error_);
   shutdown_error_ = GRPC_ERROR_REF(error);
   if (cache_->underlying_stream_ != nullptr) {
index e83fb62..09a3032 100644 (file)
@@ -56,7 +56,7 @@ class ByteStream : public Orphanable {
   // indicated by Next().
   //
   // Once a slice is returned into *slice, it is owned by the caller.
-  virtual grpc_error* Pull(grpc_slice* slice) = 0;
+  virtual grpc_error_handle Pull(grpc_slice* slice) = 0;
 
   // Shuts down the byte stream.
   //
@@ -65,7 +65,7 @@ class ByteStream : public Orphanable {
   //
   // The next call to Pull() (if any) will return the error passed to
   // Shutdown().
-  virtual void Shutdown(grpc_error* error) = 0;
+  virtual void Shutdown(grpc_error_handle error) = 0;
 
   uint32_t length() const { return length_; }
   uint32_t flags() const { return flags_; }
@@ -97,11 +97,11 @@ class SliceBufferByteStream : public ByteStream {
   void Orphan() override;
 
   bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
-  grpc_error* Pull(grpc_slice* slice) override;
-  void Shutdown(grpc_error* error) override;
+  grpc_error_handle Pull(grpc_slice* slice) override;
+  void Shutdown(grpc_error_handle error) override;
 
  private:
-  grpc_error* shutdown_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle shutdown_error_ = GRPC_ERROR_NONE;
   grpc_slice_buffer backing_buffer_;
 };
 
@@ -131,8 +131,8 @@ class ByteStreamCache {
     void Orphan() override;
 
     bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
-    grpc_error* Pull(grpc_slice* slice) override;
-    void Shutdown(grpc_error* error) override;
+    grpc_error_handle Pull(grpc_slice* slice) override;
+    void Shutdown(grpc_error_handle error) override;
 
     // Resets the byte stream to the start of the underlying stream.
     void Reset();
@@ -141,7 +141,7 @@ class ByteStreamCache {
     ByteStreamCache* cache_;
     size_t cursor_ = 0;
     size_t offset_ = 0;
-    grpc_error* shutdown_error_ = GRPC_ERROR_NONE;
+    grpc_error_handle shutdown_error_ = GRPC_ERROR_NONE;
   };
 
   explicit ByteStreamCache(OrphanablePtr<ByteStream> underlying_stream);
index c2008ab..01a4f5c 100644 (file)
@@ -73,7 +73,7 @@ class AsyncConnectivityStateWatcherInterface::Notifier {
   }
 
  private:
-  static void SendNotification(void* arg, grpc_error* /*ignored*/) {
+  static void SendNotification(void* arg, grpc_error_handle /*ignored*/) {
     Notifier* self = static_cast<Notifier*>(arg);
     if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) {
       gpr_log(GPR_INFO, "watcher %p: delivering async notification for %s (%s)",
index c6ef8ae..e8f0555 100644 (file)
@@ -25,8 +25,8 @@
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/status_conversion.h"
 
-static grpc_error* recursively_find_error_with_field(grpc_error* error,
-                                                     grpc_error_ints which) {
+static grpc_error_handle recursively_find_error_with_field(
+    grpc_error_handle error, grpc_error_ints which) {
   intptr_t unused;
   // If the error itself has a status code, return it.
   if (grpc_error_get_int(error, which, &unused)) {
@@ -38,14 +38,15 @@ static grpc_error* recursively_find_error_with_field(grpc_error* error,
   while (slot != UINT8_MAX) {
     grpc_linked_error* lerr =
         reinterpret_cast<grpc_linked_error*>(error->arena + slot);
-    grpc_error* result = recursively_find_error_with_field(lerr->err, which);
+    grpc_error_handle result =
+        recursively_find_error_with_field(lerr->err, which);
     if (result) return result;
     slot = lerr->next;
   }
   return nullptr;
 }
 
-void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
+void grpc_error_get_status(grpc_error_handle error, grpc_millis deadline,
                            grpc_status_code* code, grpc_slice* slice,
                            grpc_http2_error_code* http_error,
                            const char** error_string) {
@@ -71,7 +72,7 @@ void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
 
   // Start with the parent error and recurse through the tree of children
   // until we find the first one that has a status code.
-  grpc_error* found_error =
+  grpc_error_handle found_error =
       recursively_find_error_with_field(error, GRPC_ERROR_INT_GRPC_STATUS);
   if (found_error == nullptr) {
     /// If no grpc-status exists, retry through the tree to find a http2 error
@@ -96,7 +97,7 @@ void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
   if (code != nullptr) *code = status;
 
   if (error_string != nullptr && status != GRPC_STATUS_OK) {
-    *error_string = gpr_strdup(grpc_error_string(error));
+    *error_string = gpr_strdup(grpc_error_std_string(error).c_str());
   }
 
   if (http_error != nullptr) {
@@ -123,7 +124,7 @@ void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
   }
 }
 
-absl::Status grpc_error_to_absl_status(grpc_error* error) {
+absl::Status grpc_error_to_absl_status(grpc_error_handle error) {
   grpc_status_code status;
   // TODO(yashykt): This should be updated once we decide on how to use the
   // absl::Status payload to capture all the contents of grpc_error.
@@ -136,7 +137,17 @@ absl::Status grpc_error_to_absl_status(grpc_error* error) {
                                         GRPC_SLICE_LENGTH(message)));
 }
 
-bool grpc_error_has_clear_grpc_status(grpc_error* error) {
+grpc_error_handle absl_status_to_grpc_error(absl::Status status) {
+  // Special error checks
+  if (status.ok()) {
+    return GRPC_ERROR_NONE;
+  }
+  return grpc_error_set_int(
+      GRPC_ERROR_CREATE_FROM_STRING_VIEW(status.message()),
+      GRPC_ERROR_INT_GRPC_STATUS, static_cast<grpc_status_code>(status.code()));
+}
+
+bool grpc_error_has_clear_grpc_status(grpc_error_handle error) {
   intptr_t unused;
   if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &unused)) {
     return true;
index c61320d..777e632 100644 (file)
 /// be populated with the entire error string. If any of the attributes (code,
 /// msg, http_status, error_string) are unneeded, they can be passed as
 /// NULL.
-void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
+void grpc_error_get_status(grpc_error_handle error, grpc_millis deadline,
                            grpc_status_code* code, grpc_slice* slice,
                            grpc_http2_error_code* http_error,
                            const char** error_string);
 
-/// Utility Function to convert a grpc_error * \a error to an absl::Status.
-/// Does NOT consume a ref to grpc_error.
-absl::Status grpc_error_to_absl_status(grpc_error* error);
+/// Utility Function to convert a grpc_error_handle  \a error to an
+/// absl::Status. Does NOT consume a ref to grpc_error.
+absl::Status grpc_error_to_absl_status(grpc_error_handle error);
+
+/// Utility function to convert an absl::Status \a status to grpc_error. Note
+/// that this method does not return "special case" errors such as
+/// GRPC_ERROR_CANCELLED, with the exception of GRPC_ERROR_NONE returned for
+/// \a absl::OkStatus().
+grpc_error_handle absl_status_to_grpc_error(absl::Status status);
 
 /// A utility function to check whether there is a clear status code that
 /// doesn't need to be guessed in \a error. This means that \a error or some
 /// child has GRPC_ERROR_INT_GRPC_STATUS set, or that it is GRPC_ERROR_NONE or
 /// GRPC_ERROR_CANCELLED
-bool grpc_error_has_clear_grpc_status(grpc_error* error);
+bool grpc_error_has_clear_grpc_status(grpc_error_handle error);
 
 #endif /* GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H */
index 410d810..e85b476 100644 (file)
@@ -94,22 +94,23 @@ void grpc_metadata_batch_destroy(grpc_metadata_batch* batch) {
   }
 }
 
-grpc_error* grpc_attach_md_to_error(grpc_error* src, grpc_mdelem md) {
-  grpc_error* out = grpc_error_set_str(
+grpc_error_handle grpc_attach_md_to_error(grpc_error_handle src,
+                                          grpc_mdelem md) {
+  grpc_error_handle out = grpc_error_set_str(
       grpc_error_set_str(src, GRPC_ERROR_STR_KEY,
                          grpc_slice_ref_internal(GRPC_MDKEY(md))),
       GRPC_ERROR_STR_VALUE, grpc_slice_ref_internal(GRPC_MDVALUE(md)));
   return out;
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE error_with_md(grpc_mdelem md) {
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE error_with_md(grpc_mdelem md) {
   return grpc_attach_md_to_error(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unallowed duplicate metadata"), md);
 }
 
-static grpc_error* link_callout(grpc_metadata_batch* batch,
-                                grpc_linked_mdelem* storage,
-                                grpc_metadata_batch_callouts_index idx) {
+static grpc_error_handle link_callout(grpc_metadata_batch* batch,
+                                      grpc_linked_mdelem* storage,
+                                      grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(idx >= 0 && idx < GRPC_BATCH_CALLOUTS_COUNT);
   if (GPR_LIKELY(batch->idx.array[idx] == nullptr)) {
     ++batch->list.default_count;
@@ -119,12 +120,12 @@ static grpc_error* link_callout(grpc_metadata_batch* batch,
   return error_with_md(storage->md);
 }
 
-static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
-                                      grpc_linked_mdelem* storage)
+static grpc_error_handle maybe_link_callout(grpc_metadata_batch* batch,
+                                            grpc_linked_mdelem* storage)
     GRPC_MUST_USE_RESULT;
 
-static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
-                                      grpc_linked_mdelem* storage) {
+static grpc_error_handle maybe_link_callout(grpc_metadata_batch* batch,
+                                            grpc_linked_mdelem* storage) {
   grpc_metadata_batch_callouts_index idx =
       GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md));
   if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
@@ -145,9 +146,9 @@ static void maybe_unlink_callout(grpc_metadata_batch* batch,
   batch->idx.array[idx] = nullptr;
 }
 
-grpc_error* grpc_metadata_batch_add_head(grpc_metadata_batch* batch,
-                                         grpc_linked_mdelem* storage,
-                                         grpc_mdelem elem_to_add) {
+grpc_error_handle grpc_metadata_batch_add_head(grpc_metadata_batch* batch,
+                                               grpc_linked_mdelem* storage,
+                                               grpc_mdelem elem_to_add) {
   GPR_DEBUG_ASSERT(!GRPC_MDISNULL(elem_to_add));
   storage->md = elem_to_add;
   return grpc_metadata_batch_link_head(batch, storage);
@@ -169,10 +170,10 @@ static void link_head(grpc_mdelem_list* list, grpc_linked_mdelem* storage) {
   assert_valid_list(list);
 }
 
-grpc_error* grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
-                                          grpc_linked_mdelem* storage) {
+grpc_error_handle grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
+                                                grpc_linked_mdelem* storage) {
   assert_valid_callouts(batch);
-  grpc_error* err = maybe_link_callout(batch, storage);
+  grpc_error_handle err = maybe_link_callout(batch, storage);
   if (err != GRPC_ERROR_NONE) {
     assert_valid_callouts(batch);
     return err;
@@ -185,12 +186,12 @@ grpc_error* grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
 // TODO(arjunroy): Need to revisit this and see what guarantees exist between
 // C-core and the internal-metadata subsystem. E.g. can we ensure a particular
 // metadata is never added twice, even in the presence of user supplied data?
-grpc_error* grpc_metadata_batch_link_head(
+grpc_error_handle grpc_metadata_batch_link_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md)) == idx);
   assert_valid_callouts(batch);
-  grpc_error* err = link_callout(batch, storage, idx);
+  grpc_error_handle err = link_callout(batch, storage, idx);
   if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) {
     assert_valid_callouts(batch);
     return err;
@@ -200,9 +201,9 @@ grpc_error* grpc_metadata_batch_link_head(
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_metadata_batch_add_tail(grpc_metadata_batch* batch,
-                                         grpc_linked_mdelem* storage,
-                                         grpc_mdelem elem_to_add) {
+grpc_error_handle grpc_metadata_batch_add_tail(grpc_metadata_batch* batch,
+                                               grpc_linked_mdelem* storage,
+                                               grpc_mdelem elem_to_add) {
   GPR_DEBUG_ASSERT(!GRPC_MDISNULL(elem_to_add));
   storage->md = elem_to_add;
   return grpc_metadata_batch_link_tail(batch, storage);
@@ -224,10 +225,10 @@ static void link_tail(grpc_mdelem_list* list, grpc_linked_mdelem* storage) {
   assert_valid_list(list);
 }
 
-grpc_error* grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
-                                          grpc_linked_mdelem* storage) {
+grpc_error_handle grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
+                                                grpc_linked_mdelem* storage) {
   assert_valid_callouts(batch);
-  grpc_error* err = maybe_link_callout(batch, storage);
+  grpc_error_handle err = maybe_link_callout(batch, storage);
   if (err != GRPC_ERROR_NONE) {
     assert_valid_callouts(batch);
     return err;
@@ -237,12 +238,12 @@ grpc_error* grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_metadata_batch_link_tail(
+grpc_error_handle grpc_metadata_batch_link_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md)) == idx);
   assert_valid_callouts(batch);
-  grpc_error* err = link_callout(batch, storage, idx);
+  grpc_error_handle err = link_callout(batch, storage, idx);
   if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) {
     assert_valid_callouts(batch);
     return err;
@@ -323,11 +324,11 @@ absl::optional<absl::string_view> grpc_metadata_batch_get_value(
   return *concatenated_value;
 }
 
-grpc_error* grpc_metadata_batch_substitute(grpc_metadata_batch* batch,
-                                           grpc_linked_mdelem* storage,
-                                           grpc_mdelem new_mdelem) {
+grpc_error_handle grpc_metadata_batch_substitute(grpc_metadata_batch* batch,
+                                                 grpc_linked_mdelem* storage,
+                                                 grpc_mdelem new_mdelem) {
   assert_valid_callouts(batch);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_mdelem old_mdelem = storage->md;
   if (!grpc_slice_eq(GRPC_MDKEY(new_mdelem), GRPC_MDKEY(old_mdelem))) {
     maybe_unlink_callout(batch, storage);
@@ -364,7 +365,7 @@ size_t grpc_metadata_batch_size(grpc_metadata_batch* batch) {
   return size;
 }
 
-static void add_error(grpc_error** composite, grpc_error* error,
+static void add_error(grpc_error_handle* composite, grpc_error_handle error,
                       const char* composite_error_string) {
   if (error == GRPC_ERROR_NONE) return;
   if (*composite == GRPC_ERROR_NONE) {
@@ -373,12 +374,11 @@ static void add_error(grpc_error** composite, grpc_error* error,
   *composite = grpc_error_add_child(*composite, error);
 }
 
-grpc_error* grpc_metadata_batch_filter(grpc_metadata_batch* batch,
-                                       grpc_metadata_batch_filter_func func,
-                                       void* user_data,
-                                       const char* composite_error_string) {
+grpc_error_handle grpc_metadata_batch_filter(
+    grpc_metadata_batch* batch, grpc_metadata_batch_filter_func func,
+    void* user_data, const char* composite_error_string) {
   grpc_linked_mdelem* l = batch->list.head;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   while (l) {
     grpc_linked_mdelem* next = l->next;
     grpc_filtered_mdelem new_mdelem = func(user_data, l->md);
@@ -402,7 +402,7 @@ void grpc_metadata_batch_copy(grpc_metadata_batch* src,
   for (grpc_linked_mdelem* elem = src->list.head; elem != nullptr;
        elem = elem->next) {
     // Error unused in non-debug builds.
-    grpc_error* GRPC_UNUSED error = grpc_metadata_batch_add_tail(
+    grpc_error_handle GRPC_UNUSED error = grpc_metadata_batch_add_tail(
         dst, &storage[i++], GRPC_MDELEM_REF(elem->md));
     // The only way that grpc_metadata_batch_add_tail() can fail is if
     // there's a duplicate entry for a callout.  However, that can't be
index d80f879..b72859f 100644 (file)
@@ -74,9 +74,9 @@ void grpc_metadata_batch_remove(grpc_metadata_batch* batch,
                                 grpc_metadata_batch_callouts_index idx);
 
 /** Substitute a new mdelem for an old value */
-grpc_error* grpc_metadata_batch_substitute(grpc_metadata_batch* batch,
-                                           grpc_linked_mdelem* storage,
-                                           grpc_mdelem new_mdelem);
+grpc_error_handle grpc_metadata_batch_substitute(grpc_metadata_batch* batch,
+                                                 grpc_linked_mdelem* storage,
+                                                 grpc_mdelem new_mdelem);
 
 void grpc_metadata_batch_set_value(grpc_linked_mdelem* storage,
                                    const grpc_slice& value);
@@ -97,10 +97,10 @@ absl::optional<absl::string_view> grpc_metadata_batch_get_value(
     \a storage is owned by the caller and must survive for the
     lifetime of batch. This usually means it should be around
     for the lifetime of the call. */
-grpc_error* grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
-                                          grpc_linked_mdelem* storage)
+grpc_error_handle grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
+                                                grpc_linked_mdelem* storage)
     GRPC_MUST_USE_RESULT;
-grpc_error* grpc_metadata_batch_link_head(
+grpc_error_handle grpc_metadata_batch_link_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) GRPC_MUST_USE_RESULT;
 
@@ -109,10 +109,10 @@ grpc_error* grpc_metadata_batch_link_head(
     \a storage is owned by the caller and must survive for the
     lifetime of batch. This usually means it should be around
     for the lifetime of the call. */
-grpc_error* grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
-                                          grpc_linked_mdelem* storage)
+grpc_error_handle grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
+                                                grpc_linked_mdelem* storage)
     GRPC_MUST_USE_RESULT;
-grpc_error* grpc_metadata_batch_link_tail(
+grpc_error_handle grpc_metadata_batch_link_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) GRPC_MUST_USE_RESULT;
 
@@ -122,19 +122,19 @@ grpc_error* grpc_metadata_batch_link_tail(
     lifetime of batch. This usually means it should be around
     for the lifetime of the call.
     Takes ownership of \a elem_to_add */
-grpc_error* grpc_metadata_batch_add_head(
+grpc_error_handle grpc_metadata_batch_add_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT;
 
 // TODO(arjunroy, roth): Remove redundant methods.
 // add/link_head/tail are almost identical.
-inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_head(
+inline grpc_error_handle GRPC_MUST_USE_RESULT grpc_metadata_batch_add_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) {
   return grpc_metadata_batch_link_head(batch, storage, idx);
 }
 
-inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_head(
+inline grpc_error_handle GRPC_MUST_USE_RESULT grpc_metadata_batch_add_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_mdelem elem_to_add, grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(!GRPC_MDISNULL(elem_to_add));
@@ -148,17 +148,17 @@ inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_head(
     lifetime of batch. This usually means it should be around
     for the lifetime of the call.
     Takes ownership of \a elem_to_add */
-grpc_error* grpc_metadata_batch_add_tail(
+grpc_error_handle grpc_metadata_batch_add_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT;
 
-inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_tail(
+inline grpc_error_handle GRPC_MUST_USE_RESULT grpc_metadata_batch_add_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) {
   return grpc_metadata_batch_link_tail(batch, storage, idx);
 }
 
-inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_tail(
+inline grpc_error_handle GRPC_MUST_USE_RESULT grpc_metadata_batch_add_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_mdelem elem_to_add, grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(!GRPC_MDISNULL(elem_to_add));
@@ -166,10 +166,11 @@ inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_tail(
   return grpc_metadata_batch_add_tail(batch, storage, idx);
 }
 
-grpc_error* grpc_attach_md_to_error(grpc_error* src, grpc_mdelem md);
+grpc_error_handle grpc_attach_md_to_error(grpc_error_handle src,
+                                          grpc_mdelem md);
 
 struct grpc_filtered_mdelem {
-  grpc_error* error;
+  grpc_error_handle error;
   grpc_mdelem md;
 };
 #define GRPC_FILTERED_ERROR(error) \
@@ -181,7 +182,7 @@ struct grpc_filtered_mdelem {
 
 typedef grpc_filtered_mdelem (*grpc_metadata_batch_filter_func)(
     void* user_data, grpc_mdelem elem);
-grpc_error* grpc_metadata_batch_filter(
+grpc_error_handle grpc_metadata_batch_filter(
     grpc_metadata_batch* batch, grpc_metadata_batch_filter_func func,
     void* user_data, const char* composite_error_string) GRPC_MUST_USE_RESULT;
 
index dccab66..36060a6 100644 (file)
@@ -177,7 +177,7 @@ grpc_endpoint* grpc_transport_get_endpoint(grpc_transport* transport) {
 // though it lives in lib, it handles transport stream ops sure
 // it's grpc_transport_stream_op_batch_finish_with_failure
 void grpc_transport_stream_op_batch_finish_with_failure(
-    grpc_transport_stream_op_batch* batch, grpc_error* error,
+    grpc_transport_stream_op_batch* batch, grpc_error_handle error,
     grpc_core::CallCombiner* call_combiner) {
   if (batch->send_message) {
     batch->payload->send_message.send_message.reset();
@@ -219,7 +219,7 @@ struct made_transport_op {
   }
 };
 
-static void destroy_made_transport_op(void* arg, grpc_error* error) {
+static void destroy_made_transport_op(void* arg, grpc_error_handle error) {
   made_transport_op* op = static_cast<made_transport_op*>(arg);
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->inner_on_complete,
                           GRPC_ERROR_REF(error));
@@ -241,7 +241,8 @@ struct made_transport_stream_op {
   grpc_transport_stream_op_batch op;
   grpc_transport_stream_op_batch_payload payload;
 };
-static void destroy_made_transport_stream_op(void* arg, grpc_error* error) {
+static void destroy_made_transport_stream_op(void* arg,
+                                             grpc_error_handle error) {
   made_transport_stream_op* op = static_cast<made_transport_stream_op*>(arg);
   grpc_closure* c = op->inner_on_complete;
   gpr_free(op);
index 4076048..7372b38 100644 (file)
@@ -319,7 +319,7 @@ struct grpc_transport_stream_op_batch_payload {
   struct {
     // Error contract: the transport that gets this op must cause cancel_error
     //                 to be unref'ed after processing it
-    grpc_error* cancel_error = GRPC_ERROR_NONE;
+    grpc_error_handle cancel_error = GRPC_ERROR_NONE;
   } cancel_stream;
 
   /* Indexes correspond to grpc_context_index enum values */
@@ -339,11 +339,11 @@ typedef struct grpc_transport_op {
   /** should the transport be disconnected
    * Error contract: the transport that gets this op must cause
    *                 disconnect_with_error to be unref'ed after processing it */
-  grpc_error* disconnect_with_error = nullptr;
+  grpc_error_handle disconnect_with_error = GRPC_ERROR_NONE;
   /** what should the goaway contain?
    * Error contract: the transport that gets this op must cause
    *                 goaway_error to be unref'ed after processing it */
-  grpc_error* goaway_error = nullptr;
+  grpc_error_handle goaway_error = GRPC_ERROR_NONE;
   /** set the callback for accepting new streams;
       this is a permanent callback, unlike the other one-shot closures.
       If true, the callback is set to set_accept_stream_fn, with its
@@ -411,7 +411,7 @@ void grpc_transport_destroy_stream(grpc_transport* transport,
                                    grpc_closure* then_schedule_closure);
 
 void grpc_transport_stream_op_batch_finish_with_failure(
-    grpc_transport_stream_op_batch* batch, grpc_error* error,
+    grpc_transport_stream_op_batch* batch, grpc_error_handle error,
     grpc_core::CallCombiner* call_combiner);
 
 std::string grpc_transport_stream_op_batch_string(
index 722a64e..49dec38 100644 (file)
@@ -109,7 +109,7 @@ std::string grpc_transport_stream_op_batch_string(
   if (op->cancel_stream) {
     out.push_back(absl::StrCat(
         " CANCEL:",
-        grpc_error_string(op->payload->cancel_stream.cancel_error)));
+        grpc_error_std_string(op->payload->cancel_stream.cancel_error)));
   }
 
   return absl::StrJoin(out, "");
@@ -131,13 +131,13 @@ std::string grpc_transport_op_string(grpc_transport_op* op) {
   }
 
   if (op->disconnect_with_error != GRPC_ERROR_NONE) {
-    out.push_back(absl::StrCat(" DISCONNECT:",
-                               grpc_error_string(op->disconnect_with_error)));
+    out.push_back(absl::StrCat(
+        " DISCONNECT:", grpc_error_std_string(op->disconnect_with_error)));
   }
 
   if (op->goaway_error) {
-    out.push_back(
-        absl::StrCat(" SEND_GOAWAY:%s", grpc_error_string(op->goaway_error)));
+    out.push_back(absl::StrCat(" SEND_GOAWAY:%s",
+                               grpc_error_std_string(op->goaway_error)));
   }
 
   if (op->set_accept_stream) {
index 4d65caa..c330ca6 100644 (file)
 
 #include <grpc/support/port_platform.h>
 
+#include <grpc/event_engine/port.h>
+
 #include <assert.h>
 #include <stdint.h>
 #include <stdlib.h>
 
 #include <grpc/grpc.h>
 
+#ifndef GRPC_EVENT_ENGINE_POSIX
 struct iovec {
   void* iov_base;
   size_t iov_len;
 };
+#endif  // GRPC_EVENT_ENGINE_POSIX
 
 /**
  * A gsec interface for AEAD encryption schemes. The API is thread-compatible.
index 921de5f..ed70d81 100644 (file)
@@ -439,7 +439,7 @@ static tsi_result make_grpc_call(alts_handshaker_client* c, bool is_start) {
   }
 }
 
-static void on_status_received(void* arg, grpc_error* error) {
+static void on_status_received(void* arg, grpc_error_handle error) {
   alts_grpc_handshaker_client* client =
       static_cast<alts_grpc_handshaker_client*>(arg);
   if (client->handshake_status_code != GRPC_STATUS_OK) {
@@ -451,7 +451,7 @@ static void on_status_received(void* arg, grpc_error* error) {
             "alts_grpc_handshaker_client:%p on_status_received "
             "status:%d details:|%s| error:|%s|",
             client, client->handshake_status_code, status_details,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     gpr_free(status_details);
   }
   maybe_complete_tsi_next(client, true /* receive_status_finished */,
@@ -642,7 +642,7 @@ static void handshaker_client_shutdown(alts_handshaker_client* c) {
   }
 }
 
-static void handshaker_call_unref(void* arg, grpc_error* /* error */) {
+static void handshaker_call_unref(void* arg, grpc_error_handle /* error */) {
   grpc_call* call = static_cast<grpc_call*>(arg);
   grpc_call_unref(call);
 }
@@ -838,7 +838,8 @@ void alts_handshaker_client_ref_for_testing(alts_handshaker_client* c) {
 }
 
 void alts_handshaker_client_on_status_received_for_testing(
-    alts_handshaker_client* c, grpc_status_code status, grpc_error* error) {
+    alts_handshaker_client* c, grpc_status_code status,
+    grpc_error_handle error) {
   // We first make sure that the handshake queue has been initialized
   // here because there are tests that use this API that mock out
   // other parts of the alts_handshaker_client in such a way that the
index 60df0ce..9cca8ab 100644 (file)
@@ -372,7 +372,8 @@ tsi_result alts_tsi_handshaker_result_create(grpc_gcp_HandshakerResp* resp,
 }
 
 /* gRPC provided callback used when gRPC thread model is applied. */
-static void on_handshaker_service_resp_recv(void* arg, grpc_error* error) {
+static void on_handshaker_service_resp_recv(void* arg,
+                                            grpc_error_handle error) {
   alts_handshaker_client* client = static_cast<alts_handshaker_client*>(arg);
   if (client == nullptr) {
     gpr_log(GPR_ERROR, "ALTS handshaker client is nullptr");
@@ -382,7 +383,7 @@ static void on_handshaker_service_resp_recv(void* arg, grpc_error* error) {
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "ALTS handshaker on_handshaker_service_resp_recv error: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     success = false;
   }
   alts_handshaker_client_handle_response(client, success);
@@ -390,8 +391,8 @@ static void on_handshaker_service_resp_recv(void* arg, grpc_error* error) {
 
 /* gRPC provided callback used when dedicatd CQ and thread are used.
  * It serves to safely bring the control back to application. */
-static void on_handshaker_service_resp_recv_dedicated(void* arg,
-                                                      grpc_error* /*error*/) {
+static void on_handshaker_service_resp_recv_dedicated(
+    void* arg, grpc_error_handle /*error*/) {
   alts_shared_resource_dedicated* resource =
       grpc_alts_get_shared_resource_dedicated();
   grpc_cq_end_op(
@@ -480,8 +481,8 @@ struct alts_tsi_handshaker_continue_handshaker_next_args {
   grpc_closure closure;
 };
 
-static void alts_tsi_handshaker_create_channel(void* arg,
-                                               grpc_error* /* unused_error */) {
+static void alts_tsi_handshaker_create_channel(
+    void* arg, grpc_error_handle /* unused_error */) {
   alts_tsi_handshaker_continue_handshaker_next_args* next_args =
       static_cast<alts_tsi_handshaker_continue_handshaker_next_args*>(arg);
   alts_tsi_handshaker* handshaker = next_args->handshaker;
index cb99fdc..d5ab14d 100644 (file)
@@ -78,7 +78,8 @@ grpc_closure* alts_handshaker_client_get_closure_for_testing(
     alts_handshaker_client* client);
 
 void alts_handshaker_client_on_status_received_for_testing(
-    alts_handshaker_client* client, grpc_status_code status, grpc_error* error);
+    alts_handshaker_client* client, grpc_status_code status,
+    grpc_error_handle error);
 
 void alts_handshaker_client_ref_for_testing(alts_handshaker_client* c);
 
index d978441..4241b6f 100644 (file)
@@ -357,13 +357,17 @@ static tsi_result add_subject_alt_names_properties_to_peer(
         subject_alt_name->type == GEN_URI) {
       unsigned char* name = nullptr;
       int name_size;
+      std::string property_name;
       if (subject_alt_name->type == GEN_DNS) {
         name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName);
+        property_name = TSI_X509_DNS_PEER_PROPERTY;
       } else if (subject_alt_name->type == GEN_EMAIL) {
         name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.rfc822Name);
+        property_name = TSI_X509_EMAIL_PEER_PROPERTY;
       } else {
         name_size = ASN1_STRING_to_UTF8(
             &name, subject_alt_name->d.uniformResourceIdentifier);
+        property_name = TSI_X509_URI_PEER_PROPERTY;
       }
       if (name_size < 0) {
         gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
@@ -378,12 +382,10 @@ static tsi_result add_subject_alt_names_properties_to_peer(
         OPENSSL_free(name);
         break;
       }
-      if (subject_alt_name->type == GEN_URI) {
-        result = tsi_construct_string_peer_property(
-            TSI_X509_URI_PEER_PROPERTY, reinterpret_cast<const char*>(name),
-            static_cast<size_t>(name_size),
-            &peer->properties[(*current_insert_index)++]);
-      }
+      result = tsi_construct_string_peer_property(
+          property_name.c_str(), reinterpret_cast<const char*>(name),
+          static_cast<size_t>(name_size),
+          &peer->properties[(*current_insert_index)++]);
       OPENSSL_free(name);
     } else if (subject_alt_name->type == GEN_IPADD) {
       char ntop_buf[INET6_ADDRSTRLEN];
@@ -409,6 +411,10 @@ static tsi_result add_subject_alt_names_properties_to_peer(
       result = tsi_construct_string_peer_property_from_cstring(
           TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name,
           &peer->properties[(*current_insert_index)++]);
+      if (result != TSI_OK) break;
+      result = tsi_construct_string_peer_property_from_cstring(
+          TSI_X509_IP_PEER_PROPERTY, name,
+          &peer->properties[(*current_insert_index)++]);
     } else {
       result = tsi_construct_string_peer_property_from_cstring(
           TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, "other types of SAN",
@@ -438,7 +444,14 @@ static tsi_result peer_from_x509(X509* cert, int include_certificate_type,
   for (int i = 0; i < subject_alt_name_count; i++) {
     GENERAL_NAME* subject_alt_name =
         sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
-    if (subject_alt_name->type == GEN_URI) {
+    // TODO(zhenlian): Clean up tsi_peer to avoid duplicate entries.
+    // URI, DNS, email and ip address SAN fields are plumbed to tsi_peer, in
+    // addition to all SAN fields (results in duplicate values). This code
+    // snippet updates property_count accordingly.
+    if (subject_alt_name->type == GEN_URI ||
+        subject_alt_name->type == GEN_DNS ||
+        subject_alt_name->type == GEN_EMAIL ||
+        subject_alt_name->type == GEN_IPADD) {
       property_count += 1;
     }
   }
@@ -1911,14 +1924,16 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
 #else
   ssl_context = SSL_CTX_new(TLSv1_2_method());
 #endif
-  result = tsi_set_min_and_max_tls_versions(
-      ssl_context, options->min_tls_version, options->max_tls_version);
-  if (result != TSI_OK) return result;
   if (ssl_context == nullptr) {
+    log_ssl_error_stack();
     gpr_log(GPR_ERROR, "Could not create ssl context.");
     return TSI_INVALID_ARGUMENT;
   }
 
+  result = tsi_set_min_and_max_tls_versions(
+      ssl_context, options->min_tls_version, options->max_tls_version);
+  if (result != TSI_OK) return result;
+
   impl = static_cast<tsi_ssl_client_handshaker_factory*>(
       gpr_zalloc(sizeof(*impl)));
   tsi_ssl_handshaker_factory_init(&impl->base);
@@ -2078,15 +2093,18 @@ tsi_result tsi_create_ssl_server_handshaker_factory_with_options(
 #else
       impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
 #endif
-      result = tsi_set_min_and_max_tls_versions(impl->ssl_contexts[i],
-                                                options->min_tls_version,
-                                                options->max_tls_version);
-      if (result != TSI_OK) return result;
       if (impl->ssl_contexts[i] == nullptr) {
+        log_ssl_error_stack();
         gpr_log(GPR_ERROR, "Could not create ssl context.");
         result = TSI_OUT_OF_RESOURCES;
         break;
       }
+
+      result = tsi_set_min_and_max_tls_versions(impl->ssl_contexts[i],
+                                                options->min_tls_version,
+                                                options->max_tls_version);
+      if (result != TSI_OK) return result;
+
       result = populate_ssl_context(impl->ssl_contexts[i],
                                     &options->pem_key_cert_pairs[i],
                                     options->cipher_suites);
index d19738d..c3d30a8 100644 (file)
@@ -37,14 +37,13 @@ extern "C" {
 #define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \
   "x509_subject_alternative_name"
 #define TSI_SSL_SESSION_REUSED_PEER_PROPERTY "ssl_session_reused"
-
 #define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert"
-
 #define TSI_X509_PEM_CERT_CHAIN_PROPERTY "x509_pem_cert_chain"
-
 #define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
-
+#define TSI_X509_DNS_PEER_PROPERTY "x509_dns"
 #define TSI_X509_URI_PEER_PROPERTY "x509_uri"
+#define TSI_X509_EMAIL_PEER_PROPERTY "x509_email"
+#define TSI_X509_IP_PEER_PROPERTY "x509_ip"
 
 /* --- tsi_ssl_root_certs_store object ---
 
index 265950f..33ecc9d 100644 (file)
@@ -28,3 +28,6 @@ URI.2 = https://bar.test.domain.com/test
 URI.3 = spiffe://foo.com/bar/baz
 email.1 = foo@test.domain.com
 email.2 = bar@test.domain.com
+IP.1 = 192.168.7.1
+IP.2 = 13::17
+RID.1 = 1.2.3.4
index b5789e9..2b9cce0 100644 (file)
@@ -1,28 +1,28 @@
 -----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCuGVBYD3P/D2eT
-nhBhZ0izP+nuozNCEO/iQu/kyy6ZCzIEFvykt0aPzJVLcsCHCaWcNJVFPSqVDVRm
-9S5ZHUyLlnSl53mKUltZI4tDDVMcEdr7KpfXeBc86lm/93DqFDgAYDkvebekRr/8
-B1OJhVJRGowXjAU9sYABzuUqjkra522BleIik3m+7DborGHS4Io5X/8D8VjlXjeB
-Vht6QA8ij5JVfHvO6DsZr99EITPpha6i182O6S6lO2t1V+bdWP+EPjiOQJktrmvM
-QYTFjmjYkRKLCZI1xxSfCK8t7ia5sLPFOF6uDH91ck8mXmuHs96nSOyB1i/LdBy9
-XdInSRGXAgMBAAECggEAWoqZqSJoPfah9DhY5n8TZP1RSKUhTDOIvc/3+LHeSwNy
-gIP/4h3amYBZCELmc5QFx8Xk93xG//tNsLnD396H53RYt8s4/0GzdhkxHK76UPfM
-PaE6FHnFBA4QnPAvjdzz/uYL92/CnLGauJSK0lM+qyU2RCyysRH1s3sI3Wfg8BRd
-C9Xik+YzYirhCEGlYKju2D2As/tB2L0b/PRpM9FWeqd/YGCj8pUpceNrbvU8udc7
-4xQS6ssgMI2H1xGc50kJVDjoZix5OLiTaHDO4oRBZT+QdPTtfkam0/y2yZ9oX6UN
-Byl+ybtUpxsmsvl+I7bb/fZsILrXE3GHXtcsCMi5iQKBgQDmKi1HfmQo6KeDSnjp
-R+yIMc77QpZpLuzjPlKWGxY915KlL77GOUYR2cm0rPP9CPGN2Nj5IyuR32u6uHtI
-WKewR7cn69prxZI3VSNFQmsatWKBoR7dwyJ4j93cN54naEuBLA1BJQ0uXgYJtgwT
-x5KP97LcudpoDNVsh+FUopon8wKBgQDBpBMeDoc+7YVLnlx4FRJudzVfWWb4bPCL
-2cusycOVAlN2E0VsrD2vbVWoinpVPIeOfGgD0RZZLtVQL5Ui8mZcANmuoRXtEqaS
-sQ6VxkdC62uDXgrsi+i/0nsxvACmfde4sxALu3DZ7rjNlWUW7amJt34CsDBMlVeL
-eDAmD0WczQKBgQCHzSLiKATYzkzn/izRF4rL4PeK8ILmlLVYbxEzV9ALtQHlTQJ2
-2pwpNCL644EiLwC2/NcoSEQQ0Y4yoV68FPL745SBjXtWU0AuPaGN395p59OzQGmB
-1vyjvd7dbEN4ZOUH1gIMCdx5Gyjc2fjOQtaK808pRM9EzS2v14xv73CdWQKBgC/8
-qiQrs4Z7tCm+L+ouRqgLcLWVYTg1PxNZQOksAwT9U5OSSQUaVhsQPEcNMi3HV0yP
-NfOkMCafvYsmj43ehlFMgKWPE/DxS0hVCmlBfs1tq/IdLxXZwi8vSQpVLdAUpY4H
-CfXuWJQZXcDMwgWBlh8j0t11rjJ8W/qbKUt1Q2oNAoGBALdy/RpspFttVvthzFbg
-FLHUAwUhEsK1VSi26AYy4L0ZHw/KLnbIGEzKCEFWqn6nfWOlb9Rw5C7QlGx/1UCC
-Tnn9KnZoziK4JDQw6SEl/3hNQ5+FYI8y7QGsqAm1W9dobbgl0a1IfmbtBeEOZt+e
-7oFnqaxVruVmNr56M9IMCwA1
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAg51YU8NkgC7w
+Hx7Jf9Zj+wjHcLxedY6czsFjhl9wUlYRkQ+wdt3suH998TrbdVMc38tpI460pGk7
+gGBpMkbZgo1YNnwz/U1jAOR11EVGHN1QDy3H0BI2E5RYtl/vTWQLFo1khIaKK4eS
+3ptrPd+1XB6L25E4ISOVgd3yn4b5eTMGRbEei+wrkZIyZAVgCIw8d6BHHwldWz3A
+ljKRErMPzKtnyVL+ctp0Kx6ObppiBPPOWhNNTtMkmLgfeZQK3U7cPN5WI13Fso05
+FA3wVo/w6sXTtz4inIT14Y57E34V6sWZezrBbTtAI0yN3DqXSKTBgGjOQUbjqVxS
+i/JzRbZpAgMBAAECggEAXJMt59qn3D1T1P5yFJ2X4A5Io3eP7bCEOt2l25EzddTy
+NJJYRBh1Ea+LB2ooTn410G3B6DZEGpPxUr6iHhQiQ9hm1eOliG6ndxNnyU2hXlzl
+A+m4rxxclYqGzL4ulenWUQqwRYUBGZJjKHpJrKFdYV4CBmk4hRBSh0OjElgqVO5g
+nliMl3fC+GgUXtdMDGoPnC6MwD8q0RSJxbzpd8r+yREgX6KveEfPTfgSLAUieJrf
+2qqEk0Prdrwzsu0iyDYCaWLOq0cUstnHCo3e5synV4VzAFnaqxMT7lCVuUHgFpHj
+62rTwBCG/n3s+IVAp9CGBe37+SiJPRE8t5PDr65F3QKBgQDovkKLWzXxVJauTF/E
+tFRA+HqNDzYC3yiN0MIBmcF7IntdwCHznMyqydkaSE6WYn+NKglbH3c4RD5Hmdxc
+PUta8wgpmTg264568Svgna5jhwoqStrzh7qeBPXHmJvK4MkWALH4ukr3hIsWzsAh
+881ebstQDke8uHzyNZBY/URebwKBgQDTwEP6hgcgDOaf9yzipeMhtsArIm7zXn+r
+1RknpKUA8wM6fpEMpdUTgReu9tdJDgrcKac6imSZoNM6DBoOb/Hdj6FourHiTTvE
+dXAOjAzkDz/c86HFuDNoz27usoMPu/3iJPwuLQSO0IlflccLuOirhnnY8yVxIuy2
++9g+2iOkpwKBgE/Kin3EM2YdHdt7i4mgWRI9HaamhFnPr9OOsjRiRha0555odDtU
+kkYrFScRiv+7nQcEVljLHNBJdSCO+yEUUnVHxJCeWstZTmuPqv9Cj7rHXRDKwO2k
+prHt+WUISMDw9393lYw0MedRpW2YS/5X2xx413MGsklc5lkTS/12Nq45AoGAaVCf
+vrL4Sj2AWqEhxtwAmlz9OLbYfdxLHVhQOYJOuqkiuu4GEEdOMXQsJk4IhwIf7p4c
+2SXJoQr241DviKyum6Z6/c6U+Fu3VR+fiuym4Kqg9bCKjf7uOruojbllK+cw/0+r
+yP+E287l9A9XPwJJXj30zi0oOxvGpb+eLqxpu9MCgYEAxIgVhzyfRvoAdNYk7FE7
+JDig38EGC4m9grh/9G0tMvWT/E+F1Hb5V9NDK/iWA25dD3hOASxza1Hqkt1dP5on
+FMZrmP2T9Ov0wgfVuRIf8/c3YyiS1wJXb3wROVaJJDSvE5c2UszR5pfqvNE5C1YV
+zpc3ITQSAX66LK6ImkHb9Jw=
 -----END PRIVATE KEY-----
index d4ff936..727b8ff 100644 (file)
@@ -1,24 +1,24 @@
 -----BEGIN CERTIFICATE-----
-MIID/jCCAuagAwIBAgIUV2eOzlQQj1U+++TDdNyRHjRNamQwDQYJKoZIhvcNAQEL
+MIIEGzCCAwOgAwIBAgIUVwCmP2zKfeoWdaMbn32PjFgpdRswDQYJKoZIhvcNAQEL
 BQAwSjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEPMA0G
-A1UECwwGR29vZ2xlMRAwDgYDVQQDDAd4cGlnb3JzMB4XDTIwMDYwNzIyNTk1MFoX
-DTMwMDYwNTIyNTk1MFowSjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYD
+A1UECwwGR29vZ2xlMRAwDgYDVQQDDAd4cGlnb3JzMB4XDTIxMDQwOTE5MzgxOVoX
+DTMxMDQwNzE5MzgxOVowSjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYD
 VQQHDAJTRjEPMA0GA1UECwwGR29vZ2xlMRAwDgYDVQQDDAd4cGlnb3JzMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArhlQWA9z/w9nk54QYWdIsz/p7qMz
-QhDv4kLv5MsumQsyBBb8pLdGj8yVS3LAhwmlnDSVRT0qlQ1UZvUuWR1Mi5Z0ped5
-ilJbWSOLQw1THBHa+yqX13gXPOpZv/dw6hQ4AGA5L3m3pEa//AdTiYVSURqMF4wF
-PbGAAc7lKo5K2udtgZXiIpN5vuw26Kxh0uCKOV//A/FY5V43gVYbekAPIo+SVXx7
-zug7Ga/fRCEz6YWuotfNjukupTtrdVfm3Vj/hD44jkCZLa5rzEGExY5o2JESiwmS
-NccUnwivLe4mubCzxThergx/dXJPJl5rh7Pep0jsgdYvy3QcvV3SJ0kRlwIDAQAB
-o4HbMIHYMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMIG9BgNVHREEgbUwgbKCE2Zv
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwIOdWFPDZIAu8B8eyX/WY/sIx3C8
+XnWOnM7BY4ZfcFJWEZEPsHbd7Lh/ffE623VTHN/LaSOOtKRpO4BgaTJG2YKNWDZ8
+M/1NYwDkddRFRhzdUA8tx9ASNhOUWLZf701kCxaNZISGiiuHkt6baz3ftVwei9uR
+OCEjlYHd8p+G+XkzBkWxHovsK5GSMmQFYAiMPHegRx8JXVs9wJYykRKzD8yrZ8lS
+/nLadCsejm6aYgTzzloTTU7TJJi4H3mUCt1O3DzeViNdxbKNORQN8FaP8OrF07c+
+IpyE9eGOexN+FerFmXs6wW07QCNMjdw6l0ikwYBozkFG46lcUovyc0W2aQIDAQAB
+o4H4MIH1MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMIHaBgNVHREEgdIwgc+CE2Zv
 by50ZXN0LmRvbWFpbi5jb22CE2Jhci50ZXN0LmRvbWFpbi5jb22GIGh0dHBzOi8v
 Zm9vLnRlc3QuZG9tYWluLmNvbS90ZXN0hiBodHRwczovL2Jhci50ZXN0LmRvbWFp
 bi5jb20vdGVzdIYYc3BpZmZlOi8vZm9vLmNvbS9iYXIvYmF6gRNmb29AdGVzdC5k
-b21haW4uY29tgRNiYXJAdGVzdC5kb21haW4uY29tMA0GCSqGSIb3DQEBCwUAA4IB
-AQBlLNl/uXN01VARQFd5CNFMhwez879uB5N3s/pGBjzE8Z+NA9YjsBFkBSQlebFM
-5UP304rsvG2opHwcSkblG9a3TbpQVNaYjcHgudip3FqLTJ3NhYtx1A3uCBp4ABeP
-+AVlCcsNVysGwGvMzXlN++Y++U0A9BbfrP85VBslLaKn4rYpfB5pAdzu277ICdEy
-nyFZ+jo2OS1lbv7kE7IW6slCXbCFaxPIKvjPbpGFngsLt44sZ9VvSJCeKhDglMfn
-HKkhd4/UMnRn+8tZZ6eH/C5tpeKAChMUF+bkuwk3dBwnHq484KbBAKd2cwzZhTB7
-8unku1S1GumvoEYAgbG1P4gC
+b21haW4uY29tgRNiYXJAdGVzdC5kb21haW4uY29thwTAqAcBhxAAEwAAAAAAAAAA
+AAAAAAAXiAMqAwQwDQYJKoZIhvcNAQELBQADggEBAIHzi/MWANQDYqpNDGVA6HGg
+vYPnwxjLXL/8apVf1ZMHzS/R6Eudu8ugppnnEL7Cjsd4oA0r/sJLjBvhaZtf0r4S
+GguWdmai2RR1ghwkCLPF/HlCqiBKwUfWrjTxq8GOwwodhW7lk4hLPzhFRzh/I93g
+uN5/ugPKcloWQ7X/0okMdkdPmk8uLpMckXNKj13Lupl/0BgDggghVXRTA2t0ujhx
+TvRWfYi5H1eJtNcj824PaIDifPiSOpzeXZi+na2XzzVmCz5n/e2H4nlTMVcN6YGG
+M3U3uJqjjjpKkCrrdNAJJpqqJpln4P6fVvO2ND1QmyE5YIKV3tZ8p38AJOheUcw=
 -----END CERTIFICATE-----
index addc526..7b239a6 100644 (file)
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name     = 'Protobuf-C++'
-  s.version  = '3.15.2'
+  s.version  = '3.15.8'
   s.summary  = 'Protocol Buffers v3 runtime library for C++.'
   s.homepage = 'https://github.com/google/protobuf'
   s.license  = '3-Clause BSD License'
index f911ae2..a9f2083 100644 (file)
@@ -57,12 +57,13 @@ Channel::Channel(const std::string& host, grpc_channel* channel,
 
 Channel::~Channel() {
   grpc_channel_destroy(c_channel_);
-  if (callback_cq_ != nullptr) {
+  CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_relaxed);
+  if (callback_cq != nullptr) {
     if (grpc_iomgr_run_in_background()) {
       // gRPC-core provides the backing needed for the preferred CQ type
-      callback_cq_->Shutdown();
+      callback_cq->Shutdown();
     } else {
-      CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq_);
+      CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq);
     }
   }
 }
@@ -146,9 +147,9 @@ 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.
-  auto* info =
-      context->set_client_rpc_info(method.name(), method.method_type(), this,
-                                   interceptor_creators_, interceptor_pos);
+  auto* info = context->set_client_rpc_info(
+      method.name(), method.suffix_for_stats(), method.method_type(), this,
+      interceptor_creators_, interceptor_pos);
   context->set_call(c_call, shared_from_this());
 
   return ::grpc::internal::Call(c_call, this, cq, info);
@@ -243,25 +244,33 @@ class ShutdownCallback : public grpc_experimental_completion_queue_functor {
 ::grpc::CompletionQueue* Channel::CallbackCQ() {
   // TODO(vjpai): Consider using a single global CQ for the default CQ
   // if there is no explicit per-channel CQ registered
+  CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_acquire);
+  if (callback_cq != nullptr) {
+    return callback_cq;
+  }
+  // The callback_cq_ wasn't already set, so grab a lock and set it up exactly
+  // once for this channel.
   grpc::internal::MutexLock l(&mu_);
-  if (callback_cq_ == nullptr) {
+  callback_cq = callback_cq_.load(std::memory_order_relaxed);
+  if (callback_cq == nullptr) {
     if (grpc_iomgr_run_in_background()) {
       // gRPC-core provides the backing needed for the preferred CQ type
 
       auto* shutdown_callback = new ShutdownCallback;
-      callback_cq_ =
+      callback_cq =
           new ::grpc::CompletionQueue(grpc_completion_queue_attributes{
               GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK,
               GRPC_CQ_DEFAULT_POLLING, shutdown_callback});
 
       // Transfer ownership of the new cq to its own shutdown callback
-      shutdown_callback->TakeCQ(callback_cq_);
+      shutdown_callback->TakeCQ(callback_cq);
     } else {
       // Otherwise we need to use the alternative CQ variant
-      callback_cq_ = CompletionQueue::CallbackAlternativeCQ();
+      callback_cq = CompletionQueue::CallbackAlternativeCQ();
     }
+    callback_cq_.store(callback_cq, std::memory_order_release);
   }
-  return callback_cq_;
+  return callback_cq;
 }
 
 }  // namespace grpc
index a05761a..a10e1b5 100644 (file)
@@ -36,7 +36,7 @@ void ClientReactor::InternalScheduleOnDone(grpc::Status s) {
         : reactor(reactor_arg), status(std::move(s)) {
       GRPC_CLOSURE_INIT(
           &closure,
-          [](void* void_arg, grpc_error*) {
+          [](void* void_arg, grpc_error_handle) {
             ClosureWithArg* arg = static_cast<ClosureWithArg*>(void_arg);
             arg->reactor->OnDone(arg->status);
             delete arg;
index fd9cd4c..be99d54 100644 (file)
@@ -157,7 +157,7 @@ grpc::Status StsCredentialsOptionsFromJson(const std::string& json_string,
                         "options cannot be nullptr.");
   }
   ClearStsCredentialsOptions(options);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json json = grpc_core::Json::Parse(json_string.c_str(), &error);
   if (error != GRPC_ERROR_NONE ||
       json.type() != grpc_core::Json::Type::OBJECT) {
@@ -215,7 +215,7 @@ grpc::Status StsCredentialsOptionsFromEnv(StsCredentialsOptions* options) {
   ClearStsCredentialsOptions(options);
   grpc_slice json_string = grpc_empty_slice();
   char* sts_creds_path = gpr_getenv("STS_CREDENTIALS");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc::Status status;
   auto cleanup = [&json_string, &sts_creds_path, &error, &status]() {
     grpc_slice_unref_internal(json_string);
@@ -232,7 +232,7 @@ grpc::Status StsCredentialsOptionsFromEnv(StsCredentialsOptions* options) {
   error = grpc_load_file(sts_creds_path, 1, &json_string);
   if (error != GRPC_ERROR_NONE) {
     status =
-        grpc::Status(grpc::StatusCode::NOT_FOUND, grpc_error_string(error));
+        grpc::Status(grpc::StatusCode::NOT_FOUND, grpc_error_std_string(error));
     return cleanup();
   }
   status = StsCredentialsOptionsFromJson(
@@ -406,7 +406,7 @@ std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
 }
 
 namespace {
-void DeleteWrapper(void* wrapper, grpc_error* /*ignored*/) {
+void DeleteWrapper(void* wrapper, grpc_error_handle /*ignored*/) {
   MetadataCredentialsPluginWrapper* w =
       static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
   delete w;
index ac1b747..10d633c 100644 (file)
@@ -56,7 +56,7 @@ class AlarmImpl : public ::grpc::internal::CompletionQueueTag {
     GPR_ASSERT(grpc_cq_begin_op(cq_, this));
     GRPC_CLOSURE_INIT(
         &on_alarm_,
-        [](void* arg, grpc_error* error) {
+        [](void* arg, grpc_error_handle error) {
           // queue the op on the completion queue
           AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
           alarm->Ref();
@@ -82,10 +82,10 @@ class AlarmImpl : public ::grpc::internal::CompletionQueueTag {
     Ref();
     GRPC_CLOSURE_INIT(
         &on_alarm_,
-        [](void* arg, grpc_error* error) {
+        [](void* arg, grpc_error_handle error) {
           grpc_core::Executor::Run(
               GRPC_CLOSURE_CREATE(
-                  [](void* arg, grpc_error* error) {
+                  [](void* arg, grpc_error_handle error) {
                     AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
                     alarm->callback_(error == GRPC_ERROR_NONE);
                     alarm->Unref();
index b16f06b..d588056 100644 (file)
@@ -113,7 +113,7 @@ class TransportOp {
   grpc_transport_op* op() const { return op_; }
 
   // TODO(roth): Add a C++ wrapper for grpc_error?
-  grpc_error* disconnect_with_error() const {
+  grpc_error_handle disconnect_with_error() const {
     return op_->disconnect_with_error;
   }
   bool send_goaway() const { return op_->goaway_error != GRPC_ERROR_NONE; }
@@ -236,8 +236,8 @@ class ChannelData {
   // TODO(roth): Come up with a more C++-like API for the channel element.
 
   /// Initializes the channel data.
-  virtual grpc_error* Init(grpc_channel_element* /*elem*/,
-                           grpc_channel_element_args* /*args*/) {
+  virtual grpc_error_handle Init(grpc_channel_element* /*elem*/,
+                                 grpc_channel_element_args* /*args*/) {
     return GRPC_ERROR_NONE;
   }
 
@@ -259,8 +259,8 @@ class CallData {
   // TODO(roth): Come up with a more C++-like API for the call element.
 
   /// Initializes the call data.
-  virtual grpc_error* Init(grpc_call_element* /*elem*/,
-                           const grpc_call_element_args* /*args*/) {
+  virtual grpc_error_handle Init(grpc_call_element* /*elem*/,
+                                 const grpc_call_element_args* /*args*/) {
     return GRPC_ERROR_NONE;
   }
 
@@ -288,8 +288,8 @@ class ChannelFilter final {
  public:
   static const size_t channel_data_size = sizeof(ChannelDataType);
 
-  static grpc_error* InitChannelElement(grpc_channel_element* elem,
-                                        grpc_channel_element_args* args) {
+  static grpc_error_handle InitChannelElement(grpc_channel_element* elem,
+                                              grpc_channel_element_args* args) {
     // Construct the object in the already-allocated memory.
     ChannelDataType* channel_data = new (elem->channel_data) ChannelDataType();
     return channel_data->Init(elem, args);
@@ -319,8 +319,8 @@ class ChannelFilter final {
 
   static const size_t call_data_size = sizeof(CallDataType);
 
-  static grpc_error* InitCallElement(grpc_call_element* elem,
-                                     const grpc_call_element_args* args) {
+  static grpc_error_handle InitCallElement(grpc_call_element* elem,
+                                           const grpc_call_element_args* args) {
     // Construct the object in the already-allocated memory.
     CallDataType* call_data = new (elem->call_data) CallDataType();
     return call_data->Init(elem, args);
index 720c090..cac39ad 100644 (file)
@@ -25,12 +25,12 @@ namespace grpc {
 namespace experimental {
 std::string ValidateServiceConfigJSON(const std::string& service_config_json) {
   grpc_init();
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::ServiceConfig::Create(/*args=*/nullptr,
                                    service_config_json.c_str(), &error);
   std::string return_value;
   if (error != GRPC_ERROR_NONE) {
-    return_value = grpc_error_string(error);
+    return_value = grpc_error_std_string(error);
     GRPC_ERROR_UNREF(error);
   }
   grpc_shutdown();
index 86a79d7..b7afff4 100644 (file)
@@ -22,5 +22,5 @@
 #include <grpcpp/grpcpp.h>
 
 namespace grpc {
-std::string Version() { return "1.37.1"; }
+std::string Version() { return "1.38.0"; }
 }  // namespace grpc
index 80670bf..ea3bce9 100644 (file)
@@ -22,8 +22,8 @@
 
 namespace grpc {
 
-grpc_error* CensusChannelData::Init(grpc_channel_element* /*elem*/,
-                                    grpc_channel_element_args* /*args*/) {
+grpc_error_handle CensusChannelData::Init(grpc_channel_element* /*elem*/,
+                                          grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
index 0b7c682..d756f23 100644 (file)
@@ -27,8 +27,8 @@ namespace grpc {
 
 class CensusChannelData : public ChannelData {
  public:
-  grpc_error* Init(grpc_channel_element* elem,
-                   grpc_channel_element_args* args) override;
+  grpc_error_handle Init(grpc_channel_element* elem,
+                         grpc_channel_element_args* args) override;
 };
 
 }  // namespace grpc
index c5af4d7..380ad5b 100644 (file)
@@ -53,8 +53,8 @@ void FilterTrailingMetadata(grpc_metadata_batch* b, uint64_t* elapsed_time) {
 
 }  // namespace
 
-void CensusClientCallData::OnDoneRecvTrailingMetadataCb(void* user_data,
-                                                        grpc_error* error) {
+void CensusClientCallData::OnDoneRecvTrailingMetadataCb(
+    void* user_data, grpc_error_handle error) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
   CensusClientCallData* calld =
       reinterpret_cast<CensusClientCallData*>(elem->call_data);
@@ -70,7 +70,7 @@ void CensusClientCallData::OnDoneRecvTrailingMetadataCb(void* user_data,
 }
 
 void CensusClientCallData::OnDoneRecvMessageCb(void* user_data,
-                                               grpc_error* error) {
+                                               grpc_error_handle error) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
   CensusClientCallData* calld =
       reinterpret_cast<CensusClientCallData*>(elem->call_data);
@@ -138,8 +138,8 @@ void CensusClientCallData::StartTransportStreamOpBatch(
   grpc_call_next_op(elem, op->op());
 }
 
-grpc_error* CensusClientCallData::Init(grpc_call_element* elem,
-                                       const grpc_call_element_args* args) {
+grpc_error_handle CensusClientCallData::Init(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   path_ = grpc_slice_ref_internal(args->path);
   start_time_ = absl::Now();
   method_ = GetMethod(&path_);
index 8510228..f55a4b5 100644 (file)
@@ -54,8 +54,8 @@ class CensusClientCallData : public CallData {
     memset(&on_done_recv_message_, 0, sizeof(grpc_closure));
   }
 
-  grpc_error* Init(grpc_call_element* elem,
-                   const grpc_call_element_args* args) override;
+  grpc_error_handle Init(grpc_call_element* elem,
+                         const grpc_call_element_args* args) override;
 
   void Destroy(grpc_call_element* elem, const grpc_call_final_info* final_info,
                grpc_closure* then_call_closure) override;
@@ -63,11 +63,13 @@ class CensusClientCallData : public CallData {
   void StartTransportStreamOpBatch(grpc_call_element* elem,
                                    TransportStreamOpBatch* op) override;
 
-  static void OnDoneRecvTrailingMetadataCb(void* user_data, grpc_error* error);
+  static void OnDoneRecvTrailingMetadataCb(void* user_data,
+                                           grpc_error_handle error);
 
-  static void OnDoneSendInitialMetadataCb(void* user_data, grpc_error* error);
+  static void OnDoneSendInitialMetadataCb(void* user_data,
+                                          grpc_error_handle error);
 
-  static void OnDoneRecvMessageCb(void* user_data, grpc_error* error);
+  static void OnDoneRecvMessageCb(void* user_data, grpc_error_handle error);
 
  private:
   CensusContext context_;
index cffa68d..0650bd1 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "opencensus/tags/context_util.h"
 #include "opencensus/trace/context_util.h"
+#include "opencensus/trace/propagation/grpc_trace_bin.h"
 #include "src/cpp/ext/filters/census/context.h"
 
 namespace grpc {
@@ -33,14 +34,11 @@ void GenerateServerContext(absl::string_view tracing, absl::string_view method,
   // Destruct the current CensusContext to free the Span memory before
   // overwriting it below.
   context->~CensusContext();
-  GrpcTraceContext trace_ctxt;
-  if (TraceContextEncoding::Decode(tracing, &trace_ctxt) !=
-      TraceContextEncoding::kEncodeDecodeFailure) {
-    SpanContext parent_ctx = trace_ctxt.ToSpanContext();
-    if (parent_ctx.IsValid()) {
-      new (context) CensusContext(method, parent_ctx);
-      return;
-    }
+  SpanContext parent_ctx =
+      opencensus::trace::propagation::FromGrpcTraceBinHeader(tracing);
+  if (parent_ctx.IsValid()) {
+    new (context) CensusContext(method, parent_ctx);
+    return;
   }
   new (context) CensusContext(method, TagMap{});
 }
@@ -71,9 +69,13 @@ void GenerateClientContext(absl::string_view method, CensusContext* ctxt,
 
 size_t TraceContextSerialize(const ::opencensus::trace::SpanContext& context,
                              char* tracing_buf, size_t tracing_buf_size) {
-  GrpcTraceContext trace_ctxt(context);
-  return TraceContextEncoding::Encode(trace_ctxt, tracing_buf,
-                                      tracing_buf_size);
+  if (tracing_buf_size <
+      opencensus::trace::propagation::kGrpcTraceBinHeaderLen) {
+    return 0;
+  }
+  opencensus::trace::propagation::ToGrpcTraceBinHeader(
+      context, reinterpret_cast<uint8_t*>(tracing_buf));
+  return opencensus::trace::propagation::kGrpcTraceBinHeaderLen;
 }
 
 size_t StatsContextSerialize(size_t /*max_tags_len*/, grpc_slice* /*tags*/) {
index 5570996..67f5704 100644 (file)
@@ -75,8 +75,8 @@ class CensusContext {
   ::opencensus::tags::TagMap tags_;
 };
 
-// Serializes the outgoing trace context. Field IDs are 1 byte followed by
-// field data. A 1 byte version ID is always encoded first.
+// Serializes the outgoing trace context. tracing_buf must be
+// opencensus::trace::propagation::kGrpcTraceBinHeaderLen bytes long.
 size_t TraceContextSerialize(const ::opencensus::trace::SpanContext& context,
                              char* tracing_buf, size_t tracing_buf_size);
 
index 45a66d9..7ce3e94 100644 (file)
 
 namespace grpc {
 
-constexpr size_t TraceContextEncoding::kGrpcTraceContextSize;
-constexpr size_t TraceContextEncoding::kEncodeDecodeFailure;
-constexpr size_t TraceContextEncoding::kVersionIdSize;
-constexpr size_t TraceContextEncoding::kFieldIdSize;
-constexpr size_t TraceContextEncoding::kVersionIdOffset;
-constexpr size_t TraceContextEncoding::kVersionId;
-
 constexpr size_t RpcServerStatsEncoding::kRpcServerStatsSize;
 constexpr size_t RpcServerStatsEncoding::kEncodeDecodeFailure;
 constexpr size_t RpcServerStatsEncoding::kVersionIdSize;
index b897dfc..821c715 100644 (file)
 
 namespace grpc {
 
-// TODO(unknown): Rename to GrpcTraceContextV0.
-struct GrpcTraceContext {
-  GrpcTraceContext() {}
-
-  explicit GrpcTraceContext(const ::opencensus::trace::SpanContext& ctx) {
-    ctx.trace_id().CopyTo(trace_id);
-    ctx.span_id().CopyTo(span_id);
-    ctx.trace_options().CopyTo(trace_options);
-  }
-
-  ::opencensus::trace::SpanContext ToSpanContext() const {
-    return ::opencensus::trace::SpanContext(
-        ::opencensus::trace::TraceId(trace_id),
-        ::opencensus::trace::SpanId(span_id),
-        ::opencensus::trace::TraceOptions(trace_options));
-  }
-
-  // TODO(unknown): For performance:
-  // uint8_t version;
-  // uint8_t trace_id_field_id;
-  uint8_t trace_id[::opencensus::trace::TraceId::kSize];
-  // uint8_t span_id_field_id;
-  uint8_t span_id[::opencensus::trace::SpanId::kSize];
-  // uint8_t trace_options_field_id;
-  uint8_t trace_options[::opencensus::trace::TraceOptions::kSize];
-};
-
-// TraceContextEncoding encapsulates the logic for encoding and decoding of
-// trace contexts.
-class TraceContextEncoding {
- public:
-  // Size of encoded GrpcTraceContext. (16 + 8 + 1 + 4)
-  static constexpr size_t kGrpcTraceContextSize = 29;
-  // Error value.
-  static constexpr size_t kEncodeDecodeFailure = 0;
-
-  // Deserializes a GrpcTraceContext from the incoming buffer. Returns the
-  // number of bytes deserialized from the buffer. If the incoming buffer is
-  // empty or the encoding version is not supported it will return 0 bytes,
-  // currently only version 0 is supported. If an unknown field ID is
-  // encountered it will return immediately without parsing the rest of the
-  // buffer. Inlined for performance reasons.
-  static size_t Decode(absl::string_view buf, GrpcTraceContext* tc) {
-    if (buf.empty()) {
-      return kEncodeDecodeFailure;
-    }
-    uint8_t version = buf[kVersionIdOffset];
-    // TODO(unknown): Support other versions later. Only support version 0 for
-    // now.
-    if (version != kVersionId) {
-      return kEncodeDecodeFailure;
-    }
-
-    size_t pos = kVersionIdSize;
-    while (pos < buf.size()) {
-      size_t bytes_read =
-          ParseField(absl::string_view(&buf[pos], buf.size() - pos), tc);
-      if (bytes_read == 0) {
-        break;
-      } else {
-        pos += bytes_read;
-      }
-    }
-    return pos;
-  }
-
-  // Serializes a GrpcTraceContext into the provided buffer. Returns the number
-  // of bytes serialized into the buffer. If the buffer is not of sufficient
-  // size (it must be at least kGrpcTraceContextSize bytes) it will drop
-  // everything and return 0 bytes serialized. Inlined for performance reasons.
-  static size_t Encode(const GrpcTraceContext& tc, char* buf, size_t buf_size) {
-    if (buf_size < kGrpcTraceContextSize) {
-      return kEncodeDecodeFailure;
-    }
-    buf[kVersionIdOffset] = kVersionId;
-    buf[kTraceIdOffset] = kTraceIdField;
-    memcpy(&buf[kTraceIdOffset + 1], tc.trace_id,
-           opencensus::trace::TraceId::kSize);
-    buf[kSpanIdOffset] = kSpanIdField;
-    memcpy(&buf[kSpanIdOffset + 1], tc.span_id,
-           opencensus::trace::SpanId::kSize);
-    buf[kTraceOptionsOffset] = kTraceOptionsField;
-    memcpy(&buf[kTraceOptionsOffset + 1], tc.trace_options,
-           opencensus::trace::TraceOptions::kSize);
-    return kGrpcTraceContextSize;
-  }
-
- private:
-  // Parses the next field from the incoming buffer and stores the parsed value
-  // in a GrpcTraceContext struct.  If it does not recognize the field ID it
-  // will return 0, otherwise it returns the number of bytes read.
-  static size_t ParseField(absl::string_view buf, GrpcTraceContext* tc) {
-    // TODO(unknown): Add support for multi-byte field IDs.
-    if (buf.empty()) {
-      return 0;
-    }
-    // Field ID is always the first byte in a field.
-    uint32_t field_id = buf[0];
-    size_t bytes_read = kFieldIdSize;
-    switch (field_id) {
-      case kTraceIdField:
-        bytes_read += kTraceIdSize;
-        if (bytes_read > buf.size()) {
-          return 0;
-        }
-        memcpy(tc->trace_id, &buf[kFieldIdSize],
-               opencensus::trace::TraceId::kSize);
-        break;
-      case kSpanIdField:
-        bytes_read += kSpanIdSize;
-        if (bytes_read > buf.size()) {
-          return 0;
-        }
-        memcpy(tc->span_id, &buf[kFieldIdSize],
-               opencensus::trace::SpanId::kSize);
-        break;
-      case kTraceOptionsField:
-        bytes_read += kTraceOptionsSize;
-        if (bytes_read > buf.size()) {
-          return 0;
-        }
-        memcpy(tc->trace_options, &buf[kFieldIdSize],
-               opencensus::trace::TraceOptions::kSize);
-        break;
-      default:  // Invalid field ID
-        return 0;
-    }
-
-    return bytes_read;
-  }
-
-  // Size of Version ID.
-  static constexpr size_t kVersionIdSize = 1;
-  // Size of Field ID.
-  static constexpr size_t kFieldIdSize = 1;
-
-  // Offset and value for currently supported version ID.
-  static constexpr size_t kVersionIdOffset = 0;
-  static constexpr size_t kVersionId = 0;
-
-  // Fixed Field ID values:
-  enum FieldIdValue {
-    kTraceIdField = 0,
-    kSpanIdField = 1,
-    kTraceOptionsField = 2,
-  };
-
-  // Field data sizes in bytes
-  enum FieldSize {
-    kTraceIdSize = 16,
-    kSpanIdSize = 8,
-    kTraceOptionsSize = 1,
-  };
-
-  // Fixed size offsets for field ID start positions during encoding.  Field
-  // data immediately follows.
-  enum FieldIdOffset {
-    kTraceIdOffset = kVersionIdSize,
-    kSpanIdOffset = kTraceIdOffset + kFieldIdSize + kTraceIdSize,
-    kTraceOptionsOffset = kSpanIdOffset + kFieldIdSize + kSpanIdSize,
-  };
-
-  TraceContextEncoding() = delete;
-  TraceContextEncoding(const TraceContextEncoding&) = delete;
-  TraceContextEncoding(TraceContextEncoding&&) = delete;
-  TraceContextEncoding operator=(const TraceContextEncoding&) = delete;
-  TraceContextEncoding operator=(TraceContextEncoding&&) = delete;
-};
-
 // TODO(unknown): This may not be needed. Check to see if opencensus requires
 // a trailing server response.
 // RpcServerStatsEncoding encapsulates the logic for encoding and decoding of
index 61e28de..72ee8e1 100644 (file)
@@ -62,7 +62,7 @@ void FilterInitialMetadata(grpc_metadata_batch* b,
 }  // namespace
 
 void CensusServerCallData::OnDoneRecvMessageCb(void* user_data,
-                                               grpc_error* error) {
+                                               grpc_error_handle error) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
   CensusServerCallData* calld =
       reinterpret_cast<CensusServerCallData*>(elem->call_data);
@@ -78,8 +78,8 @@ void CensusServerCallData::OnDoneRecvMessageCb(void* user_data,
                           GRPC_ERROR_REF(error));
 }
 
-void CensusServerCallData::OnDoneRecvInitialMetadataCb(void* user_data,
-                                                       grpc_error* error) {
+void CensusServerCallData::OnDoneRecvInitialMetadataCb(
+    void* user_data, grpc_error_handle error) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
   CensusServerCallData* calld =
       reinterpret_cast<CensusServerCallData*>(elem->call_data);
@@ -154,8 +154,8 @@ void CensusServerCallData::StartTransportStreamOpBatch(
   grpc_call_next_op(elem, op->op());
 }
 
-grpc_error* CensusServerCallData::Init(grpc_call_element* elem,
-                                       const grpc_call_element_args* args) {
+grpc_error_handle CensusServerCallData::Init(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   start_time_ = absl::Now();
   gc_ =
       grpc_call_from_top_element(grpc_call_stack_element(args->call_stack, 0));
index e393ed3..81bec8f 100644 (file)
@@ -54,8 +54,8 @@ class CensusServerCallData : public CallData {
     memset(&on_done_recv_message_, 0, sizeof(grpc_closure));
   }
 
-  grpc_error* Init(grpc_call_element* elem,
-                   const grpc_call_element_args* args) override;
+  grpc_error_handle Init(grpc_call_element* elem,
+                         const grpc_call_element_args* args) override;
 
   void Destroy(grpc_call_element* elem, const grpc_call_final_info* final_info,
                grpc_closure* then_call_closure) override;
@@ -63,9 +63,10 @@ class CensusServerCallData : public CallData {
   void StartTransportStreamOpBatch(grpc_call_element* elem,
                                    TransportStreamOpBatch* op) override;
 
-  static void OnDoneRecvInitialMetadataCb(void* user_data, grpc_error* error);
+  static void OnDoneRecvInitialMetadataCb(void* user_data,
+                                          grpc_error_handle error);
 
-  static void OnDoneRecvMessageCb(void* user_data, grpc_error* error);
+  static void OnDoneRecvMessageCb(void* user_data, grpc_error_handle error);
 
  private:
   CensusContext context_;
index 3db355a..5159b3a 100644 (file)
 // TODO(lidiz) build a real registration system that can pull in services
 // automatically with minimum amount of code.
 #include "src/cpp/server/channelz/channelz_service.h"
-#ifndef GRPC_NO_XDS
+#if !defined(GRPC_NO_XDS) && !defined(DISABLED_XDS_PROTO_IN_CC)
 #include "src/cpp/server/csds/csds.h"
-#endif  // GRPC_NO_XDS
+#endif  // GRPC_NO_XDS or DISABLED_XDS_PROTO_IN_CC
 namespace grpc {
 
 namespace {
 
 static auto* g_channelz_service = new ChannelzService();
-#ifndef GRPC_NO_XDS
+#if !defined(GRPC_NO_XDS) && !defined(DISABLED_XDS_PROTO_IN_CC)
 static auto* g_csds = new xds::experimental::ClientStatusDiscoveryService();
-#endif  // GRPC_NO_XDS
+#endif  // GRPC_NO_XDS or DISABLED_XDS_PROTO_IN_CC
 
 }  // namespace
 
 void AddAdminServices(ServerBuilder* builder) {
   builder->RegisterService(g_channelz_service);
-#ifndef GRPC_NO_XDS
+#if !defined(GRPC_NO_XDS) && !defined(DISABLED_XDS_PROTO_IN_CC)
   builder->RegisterService(g_csds);
-#endif  // GRPC_NO_XDS
+#endif  // GRPC_NO_XDS or DISABLED_XDS_PROTO_IN_CC
 }
 
 }  // namespace grpc
index 7e7da86..695aa54 100644 (file)
@@ -223,8 +223,8 @@ ServerBuilder& ServerBuilder::AddListeningPort(
   return *this;
 }
 
-std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
-  grpc::ChannelArguments args;
+ChannelArguments ServerBuilder::BuildChannelArgs() {
+  ChannelArguments args;
   if (max_receive_message_size_ >= -1) {
     args.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, max_receive_message_size_);
   }
@@ -245,16 +245,19 @@ std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
     args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM,
                 maybe_default_compression_algorithm_.algorithm);
   }
-
   if (resource_quota_ != nullptr) {
     args.SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA, resource_quota_,
                               grpc_resource_quota_arg_vtable());
   }
-
   for (const auto& plugin : plugins_) {
     plugin->UpdateServerBuilder(this);
     plugin->UpdateChannelArguments(&args);
   }
+  return args;
+}
+
+std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
+  ChannelArguments args = BuildChannelArgs();
 
   // == Determine if the server has any syncrhonous methods ==
   bool has_sync_methods = false;
@@ -304,6 +307,10 @@ std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
     }
   }
 
+  if (callback_generic_service_ != nullptr) {
+    has_frequently_polled_cqs = true;
+  }
+
   const bool is_hybrid_server = has_sync_methods && has_frequently_polled_cqs;
 
   if (has_sync_methods) {
index f6b72c0..5b2d328 100644 (file)
@@ -37,7 +37,7 @@ void ServerCallbackCall::ScheduleOnDone(bool inline_ondone) {
       explicit ClosureWithArg(ServerCallbackCall* call_arg) : call(call_arg) {
         GRPC_CLOSURE_INIT(
             &closure,
-            [](void* void_arg, grpc_error*) {
+            [](void* void_arg, grpc_error_handle) {
               ClosureWithArg* arg = static_cast<ClosureWithArg*>(void_arg);
               arg->call->CallOnDone();
               delete arg;
@@ -66,7 +66,7 @@ void ServerCallbackCall::CallOnCancel(ServerReactor* reactor) {
           : call(call_arg), reactor(reactor_arg) {
         GRPC_CLOSURE_INIT(
             &closure,
-            [](void* void_arg, grpc_error*) {
+            [](void* void_arg, grpc_error_handle) {
               ClosureWithArg* arg = static_cast<ClosureWithArg*>(void_arg);
               arg->reactor->OnCancel();
               arg->call->MaybeDone();
index 2844bfa..a334cdd 100644 (file)
@@ -67,6 +67,15 @@ namespace {
 // max-threads set) to the server builder.
 #define DEFAULT_MAX_SYNC_SERVER_THREADS INT_MAX
 
+// Give a useful status error message if the resource is exhausted specifically
+// because the server threadpool is full.
+const char* kServerThreadpoolExhausted = "Server Threadpool Exhausted";
+
+// Although we might like to give a useful status error message on unimplemented
+// RPCs, it's not always possible since that also would need to be added across
+// languages and isn't actually required by the spec.
+const char* kUnknownRpcMethod = "";
+
 class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
  public:
   ~DefaultGlobalCallbacks() override {}
@@ -802,7 +811,7 @@ class Server::SyncRequestThreadManager : public grpc::ThreadManager {
     if (has_sync_method_) {
       unknown_method_ = absl::make_unique<grpc::internal::RpcServiceMethod>(
           "unknown", grpc::internal::RpcMethod::BIDI_STREAMING,
-          new grpc::internal::UnknownMethodHandler);
+          new grpc::internal::UnknownMethodHandler(kUnknownRpcMethod));
       server_->server()->core_server->SetBatchMethodAllocator(
           server_cq_->cq(), [this] {
             grpc_core::Server::BatchCallAllocation result;
@@ -930,14 +939,16 @@ Server::~Server() {
       for (const auto& value : sync_req_mgrs_) {
         value->Shutdown();
       }
-      if (callback_cq_ != nullptr) {
+      CompletionQueue* callback_cq =
+          callback_cq_.load(std::memory_order_relaxed);
+      if (callback_cq != nullptr) {
         if (grpc_iomgr_run_in_background()) {
           // gRPC-core provides the backing needed for the preferred CQ type
-          callback_cq_->Shutdown();
+          callback_cq->Shutdown();
         } else {
-          CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq_);
+          CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq);
         }
-        callback_cq_ = nullptr;
+        callback_cq_.store(nullptr, std::memory_order_release);
       }
     }
   }
@@ -1192,7 +1203,8 @@ void Server::Start(grpc::ServerCompletionQueue** cqs, size_t num_cqs) {
   // to deal with the case of thread exhaustion
   if (sync_server_cqs_ != nullptr && !sync_server_cqs_->empty()) {
     resource_exhausted_handler_ =
-        absl::make_unique<grpc::internal::ResourceExhaustedHandler>();
+        absl::make_unique<grpc::internal::ResourceExhaustedHandler>(
+            kServerThreadpoolExhausted);
   }
 
   for (const auto& value : sync_req_mgrs_) {
@@ -1256,14 +1268,15 @@ void Server::ShutdownInternal(gpr_timespec deadline) {
 
   // Shutdown the callback CQ. The CQ is owned by its own shutdown tag, so it
   // will delete itself at true shutdown.
-  if (callback_cq_ != nullptr) {
+  CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_relaxed);
+  if (callback_cq != nullptr) {
     if (grpc_iomgr_run_in_background()) {
       // gRPC-core provides the backing needed for the preferred CQ type
-      callback_cq_->Shutdown();
+      callback_cq->Shutdown();
     } else {
-      CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq_);
+      CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq);
     }
-    callback_cq_ = nullptr;
+    callback_cq_.store(nullptr, std::memory_order_release);
   }
 
   // Drain the shutdown queue (if the previous call to AsyncNext() timed out
@@ -1318,8 +1331,9 @@ bool Server::UnimplementedAsyncRequest::FinalizeResult(void** tag,
 Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse(
     UnimplementedAsyncRequest* request)
     : request_(request) {
-  grpc::Status status(grpc::StatusCode::UNIMPLEMENTED, "");
-  grpc::internal::UnknownMethodHandler::FillOps(request_->context(), this);
+  grpc::Status status(grpc::StatusCode::UNIMPLEMENTED, kUnknownRpcMethod);
+  grpc::internal::UnknownMethodHandler::FillOps(request_->context(),
+                                                kUnknownRpcMethod, this);
   request_->stream()->call_.PerformOps(this);
 }
 
@@ -1330,25 +1344,33 @@ grpc::ServerInitializer* Server::initializer() {
 grpc::CompletionQueue* Server::CallbackCQ() {
   // TODO(vjpai): Consider using a single global CQ for the default CQ
   // if there is no explicit per-server CQ registered
+  CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_acquire);
+  if (callback_cq != nullptr) {
+    return callback_cq;
+  }
+  // The callback_cq_ wasn't already set, so grab a lock and set it up exactly
+  // once for this server.
   grpc::internal::MutexLock l(&mu_);
-  if (callback_cq_ != nullptr) {
-    return callback_cq_;
+  callback_cq = callback_cq_.load(std::memory_order_relaxed);
+  if (callback_cq != nullptr) {
+    return callback_cq;
   }
   if (grpc_iomgr_run_in_background()) {
     // gRPC-core provides the backing needed for the preferred CQ type
     auto* shutdown_callback = new grpc::ShutdownCallback;
-    callback_cq_ = new grpc::CompletionQueue(grpc_completion_queue_attributes{
+    callback_cq = new grpc::CompletionQueue(grpc_completion_queue_attributes{
         GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
         shutdown_callback});
 
     // Transfer ownership of the new cq to its own shutdown callback
-    shutdown_callback->TakeCQ(callback_cq_);
+    shutdown_callback->TakeCQ(callback_cq);
   } else {
     // Otherwise we need to use the alternative CQ variant
-    callback_cq_ = CompletionQueue::CallbackAlternativeCQ();
+    callback_cq = CompletionQueue::CallbackAlternativeCQ();
   }
 
-  return callback_cq_;
+  callback_cq_.store(callback_cq, std::memory_order_release);
+  return callback_cq;
 }
 
 }  // namespace grpc
index e28b5c5..6d3fb58 100644 (file)
@@ -33,11 +33,11 @@ namespace Grpc.Core
         /// <summary>
         /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyFileVersion = "2.37.1.0";
+        public const string CurrentAssemblyFileVersion = "2.38.0.0";
 
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "2.37.1";
+        public const string CurrentVersion = "2.38.0";
     }
 }
index 122d8ef..497282d 100644 (file)
@@ -2,7 +2,10 @@
   <PropertyGroup>
     <Authors>The gRPC Authors</Authors>
     <Copyright>Copyright 2015 The gRPC Authors</Copyright>
-    <Description>Debug symbols for the grpc_csharp_ext native library contained in Grpc.Core</Description>
+    <Description>Debug symbols for the grpc_csharp_ext native library contained in Grpc.Core
+
+Note that the Grpc.Core implementation of gRPC for C# is in maintenance mode and will be replaced by grpc-dotnet in the future.
+See https://grpc.io/blog/grpc-csharp-future/ for details.</Description>
     <PackageIconUrl>https://github.com/grpc/grpc.github.io/raw/master/img/grpc_square_reverse_4x.png</PackageIconUrl>
     <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
     <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
index e9809d7..45618f0 100755 (executable)
@@ -1,7 +1,10 @@
 ï»¿<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <Authors>The gRPC Authors</Authors>
-    <Description>Miscellaneous code for testing Grpc.Core</Description>
+    <Description>Miscellaneous code for testing Grpc.Core
+
+Note that the Grpc.Core implementation of gRPC for C# is in maintenance mode and will be replaced by grpc-dotnet in the future.
+See https://grpc.io/blog/grpc-csharp-future/ for details.</Description>
     <Copyright>Copyright 2017 The gRPC Authors</Copyright>
     <PackageIconUrl>https://github.com/grpc/grpc.github.io/raw/master/img/grpc_square_reverse_4x.png</PackageIconUrl>
     <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
diff --git a/src/csharp/Grpc.Core.Tests/Internal/UserAgentStringProviderTest.cs b/src/csharp/Grpc.Core.Tests/Internal/UserAgentStringProviderTest.cs
new file mode 100644 (file)
index 0000000..24e788f
--- /dev/null
@@ -0,0 +1,63 @@
+#region Copyright notice and license
+
+// Copyright 2021 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;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+    public class UserAgentStringProviderTest
+    {
+        [Test]
+        public void BasicTest()
+        {
+            Assert.AreEqual("grpc-csharp/1.0 (.NET Framework 4.6.1; CLR 1.2.3.4; net45; x64)",
+                new UserAgentStringProvider("1.0", ".NET Framework 4.6.1", "1.2.3.4", "net45", CommonPlatformDetection.CpuArchitecture.X64).GrpcCsharpUserAgentString);
+            Assert.AreEqual("grpc-csharp/1.0 (CLR 1.2.3.4; net45; x64)",
+                new UserAgentStringProvider("1.0", null, "1.2.3.4", "net45", CommonPlatformDetection.CpuArchitecture.X64).GrpcCsharpUserAgentString);
+            Assert.AreEqual("grpc-csharp/1.0 (.NET Framework 4.6.1; net45; x64)",
+                new UserAgentStringProvider("1.0", ".NET Framework 4.6.1", null, "net45", CommonPlatformDetection.CpuArchitecture.X64).GrpcCsharpUserAgentString);
+            Assert.AreEqual("grpc-csharp/1.0 (.NET Framework 4.6.1; CLR 1.2.3.4; x64)",
+                new UserAgentStringProvider("1.0", ".NET Framework 4.6.1", "1.2.3.4", null, CommonPlatformDetection.CpuArchitecture.X64).GrpcCsharpUserAgentString);
+        }
+
+        [Test]
+        public void ArchitectureTest()
+        {
+            Assert.AreEqual("grpc-csharp/1.0 (.NET Framework 4.6.1; CLR 1.2.3.4; net45; arm64)",
+                new UserAgentStringProvider("1.0", ".NET Framework 4.6.1", "1.2.3.4", "net45", CommonPlatformDetection.CpuArchitecture.Arm64).GrpcCsharpUserAgentString);
+
+            // unknown architecture
+            Assert.AreEqual("grpc-csharp/1.0 (.NET Framework 4.6.1; CLR 1.2.3.4; net45)",
+                new UserAgentStringProvider("1.0", ".NET Framework 4.6.1", "1.2.3.4", "net45", CommonPlatformDetection.CpuArchitecture.Unknown).GrpcCsharpUserAgentString);
+        }
+
+        [Test]
+        public void FrameworkDescriptionTest()
+        {
+            Assert.AreEqual("grpc-csharp/1.0 (Mono 6.12.0.93; x64)",
+                new UserAgentStringProvider("1.0", "Mono 6.12.0.93 (2020-02/620cf538206 Tue Aug 25 14:04:52 EDT 2020)", null, null, CommonPlatformDetection.CpuArchitecture.X64).GrpcCsharpUserAgentString);
+
+            Assert.AreEqual("grpc-csharp/1.0 (x64)",
+                new UserAgentStringProvider("1.0", "(some invalid framework description)", null, null, CommonPlatformDetection.CpuArchitecture.X64).GrpcCsharpUserAgentString);
+        }
+    }
+}
index 1b4676f..baf7ca5 100644 (file)
@@ -50,10 +50,10 @@ namespace Grpc.Core.Tests
             helper = new MockServiceHelper(Host);
             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
             {
-                var userAgentString = context.RequestHeaders.First(m => (m.Key == "user-agent")).Value;
+                var userAgentString = context.RequestHeaders.GetValue("user-agent");
                 var parts = userAgentString.Split(new [] {' '}, 2);
-                Assert.AreEqual(string.Format("grpc-csharp/{0}", VersionInfo.CurrentVersion), parts[0]);
-                Assert.IsTrue(parts[1].StartsWith("grpc-c/"));
+                Assert.AreEqual($"grpc-csharp/{VersionInfo.CurrentVersion}", parts[0]);
+                Assert.That(parts[1], Does.Match(@"\(.*\) grpc-c/.*"));
                 return Task.FromResult("PASS");
             });
 
@@ -71,9 +71,10 @@ namespace Grpc.Core.Tests
                 channelOptions: new[] { new ChannelOption(ChannelOptions.PrimaryUserAgentString, "XYZ") });
             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
             {
-                var userAgentString = context.RequestHeaders.First(m => (m.Key == "user-agent")).Value;
+                var userAgentString = context.RequestHeaders.GetValue("user-agent");
                 var parts = userAgentString.Split(new[] { ' ' }, 3);
                 Assert.AreEqual("XYZ", parts[0]);
+                Assert.AreEqual($"grpc-csharp/{VersionInfo.CurrentVersion}", parts[1]);
                 return Task.FromResult("PASS");
             });
 
index 277a1a4..d822536 100644 (file)
@@ -3,9 +3,12 @@
     <Authors>The gRPC Authors</Authors>
     <Copyright>Copyright 2015 The gRPC Authors</Copyright>
     <Description>Xamarin support for gRPC C#. Note that the gRPC C# support for the Xamarin platform is considered experimental.
-    This package contains the native grpc_csharp_ext libraries that are needed to run gRPC C# on mobile platforms (Android, iOS).
-    WARNING: Versions of Grpc.Core.Xamarin and Grpc.Core dependencies being used in your project must always match exactly, otherwise
-    things will be badly broken.</Description>
+
+This package contains the native grpc_csharp_ext libraries that are needed to run gRPC C# on mobile platforms (Android, iOS).
+WARNING: Versions of Grpc.Core.Xamarin and Grpc.Core dependencies being used in your project must always match exactly, otherwise things will be badly broken.
+
+Note that the Grpc.Core implementation of gRPC for C# is in maintenance mode and will be replaced by grpc-dotnet in the future.
+See https://grpc.io/blog/grpc-csharp-future/ for details.</Description>
     <PackageIconUrl>https://github.com/grpc/grpc.github.io/raw/master/img/grpc_square_reverse_4x.png</PackageIconUrl>
     <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
     <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
index 81b7f1f..e2d69e4 100644 (file)
@@ -318,8 +318,7 @@ namespace Grpc.Core
                 userAgentString = option.StringValue + " ";
             };
 
-            // TODO(jtattermusch): it would be useful to also provide .NET/mono version.
-            userAgentString += string.Format("grpc-csharp/{0}", VersionInfo.CurrentVersion);
+            userAgentString += UserAgentStringProvider.DefaultInstance.GrpcCsharpUserAgentString;
 
             options[ChannelOptions.PrimaryUserAgentString] = new ChannelOption(key, userAgentString);
         }
index 918ac74..4d376ae 100755 (executable)
@@ -2,7 +2,10 @@
   <PropertyGroup>
     <Authors>The gRPC Authors</Authors>
     <Copyright>Copyright 2015 The gRPC Authors</Copyright>
-    <Description>C# implementation of gRPC based on native gRPC C-core library.</Description>
+    <Description>C# implementation of gRPC based on native gRPC C-core library.
+
+Note that the Grpc.Core implementation of gRPC for C# is in maintenance mode and will be replaced by grpc-dotnet in the future.
+See https://grpc.io/blog/grpc-csharp-future/ for details.</Description>
     <PackageIconUrl>https://github.com/grpc/grpc.github.io/raw/master/img/grpc_square_reverse_4x.png</PackageIconUrl>
     <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
     <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
index 4f8a512..5ad443b 100644 (file)
@@ -47,6 +47,8 @@ namespace Grpc.Core.Internal
         static readonly bool isMono;
         static readonly bool isNet5OrHigher;
         static readonly bool isNetCore;
+        static readonly string frameworkDescription;
+        static readonly string clrVersion;
         static readonly string unityApplicationPlatform;
         static readonly bool isXamarin;
         static readonly bool isXamarinIOS;
@@ -72,6 +74,8 @@ namespace Grpc.Core.Internal
             isNet5OrHigher = false;
             isNetCore = false;
 #endif
+            frameworkDescription = TryGetFrameworkDescription();
+            clrVersion = TryGetClrVersion();
 
             // Detect mono runtime
             isMono = Type.GetType("Mono.Runtime") != null;
@@ -125,6 +129,18 @@ namespace Grpc.Core.Internal
         public static bool IsNet5OrHigher => isNet5OrHigher;
 
         /// <summary>
+        /// Contains <c>RuntimeInformation.FrameworkDescription</c> if the property is available on current TFM.
+        /// <c>null</c> otherwise.
+        /// </summary>
+        public static string FrameworkDescription => frameworkDescription;
+
+        /// <summary>
+        /// Contains the version of common language runtime obtained from <c>Environment.Version</c>
+        /// if the property is available on current TFM. <c>null</c> otherwise.
+        /// </summary>
+        public static string ClrVersion => clrVersion;
+
+        /// <summary>
         /// true if running on .NET Core (CoreCLR) or NET 5+, false otherwise.
         /// </summary>
         public static bool IsNetCore => isNetCore;
@@ -184,31 +200,54 @@ namespace Grpc.Core.Internal
             }
         }
 
-        [DllImport("libc")]
-        static extern int uname(IntPtr buf);
+        /// <summary>
+        /// Returns description of the framework this process is running on.
+        /// Value is based on <c>RuntimeInformation.FrameworkDescription</c>.
+        /// </summary>
+        static string TryGetFrameworkDescription()
+        {
+#if NETSTANDARD
+            return RuntimeInformation.FrameworkDescription;
+#else
+            // on full .NET framework we are targeting net45, and the property is only available starting from .NET Framework 4.7.1+
+            // try obtaining the value by reflection since we might be running on a newer framework even though we're targeting
+            // an older one.
+            var runtimeInformationClass = Type.GetType("System.Runtime.InteropServices.RuntimeInformation");
+            var frameworkDescriptionProperty = runtimeInformationClass?.GetTypeInfo().GetProperty("FrameworkDescription", BindingFlags.Static | BindingFlags.Public);
+            return frameworkDescriptionProperty?.GetValue(null)?.ToString();
+#endif
+        }
 
-        static string GetUname()
+        /// <summary>
+        /// Returns version of the common language runtime this process is running on.
+        /// Value is based on <c>Environment.Version</c>.
+        /// </summary>
+        static string TryGetClrVersion()
         {
-            var buffer = Marshal.AllocHGlobal(8192);
-            try
-            {
-                if (uname(buffer) == 0)
-                {
-                    return Marshal.PtrToStringAnsi(buffer);
-                }
-                return string.Empty;
-            }
-            catch
-            {
-                return string.Empty;
-            }
-            finally
-            {
-                if (buffer != IntPtr.Zero)
-                {
-                    Marshal.FreeHGlobal(buffer);
-                }
-            }
+#if NETSTANDARD1_5
+            return null;
+#else
+            return Environment.Version.ToString();
+#endif
+        }
+
+        /// <summary>
+        /// Returns the TFM of the Grpc.Core assembly.
+        /// </summary>
+        public static string GetGrpcCoreTargetFrameworkMoniker()
+        {
+#if NETSTANDARD1_5
+            return "netstandard1.5";
+#elif NETSTANDARD2_0
+            return "netstandard2.0";
+#elif NET45
+            return "net45";
+#else
+            // The TFM is determined at compile time.
+            // The is intentionally no "default" return clause here so that
+            // if the set of TFMs we build for changes and this method is not updated accordingly,
+            // it will result in compilation error.
+#endif
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/UserAgentStringProvider.cs b/src/csharp/Grpc.Core/Internal/UserAgentStringProvider.cs
new file mode 100644 (file)
index 0000000..01f1585
--- /dev/null
@@ -0,0 +1,108 @@
+#region Copyright notice and license
+
+// Copyright 2021 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.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace Grpc.Core.Internal
+{
+    /// <summary>
+    /// Helps constructing the grpc-csharp component of the user agent string.
+    /// </summary>
+    internal class UserAgentStringProvider
+    {
+        static readonly UserAgentStringProvider defaultInstance;
+        readonly string userAgentString;
+
+        static UserAgentStringProvider()
+        {
+            defaultInstance = new UserAgentStringProvider(VersionInfo.CurrentVersion, PlatformApis.FrameworkDescription, PlatformApis.ClrVersion, PlatformApis.GetGrpcCoreTargetFrameworkMoniker(), PlatformApis.ProcessArchitecture);
+        }
+
+        public static UserAgentStringProvider DefaultInstance => defaultInstance;
+
+        public string GrpcCsharpUserAgentString => userAgentString;
+
+        public UserAgentStringProvider(string grpcCsharpVersion, string frameworkDescription, string clrVersion, string tfm, CommonPlatformDetection.CpuArchitecture arch)
+        {
+            var detailComponents = new List<string>();
+
+            string sanitizedFrameworkDescription = SanitizeFrameworkDescription(frameworkDescription);
+            if (sanitizedFrameworkDescription != null)
+            {
+                detailComponents.Add(sanitizedFrameworkDescription);
+            }
+
+            if (clrVersion != null)
+            {
+                detailComponents.Add($"CLR {clrVersion}");
+            }
+
+            if (tfm != null)
+            {
+                detailComponents.Add(tfm);
+            }
+
+            string architectureString = TryGetArchitectureString(arch);
+            if (architectureString != null)
+            {
+                detailComponents.Add(architectureString);
+            }
+
+            // TODO(jtattermusch): consider adding details about running under unity / xamarin etc.
+            var details = string.Join("; ", detailComponents);
+            userAgentString = $"grpc-csharp/{grpcCsharpVersion} ({details})";
+        }
+
+        static string TryGetArchitectureString(CommonPlatformDetection.CpuArchitecture arch)
+        {
+            if (arch == CommonPlatformDetection.CpuArchitecture.Unknown)
+            {
+                return null;
+            }
+            return arch.ToString().ToLowerInvariant();
+        }
+
+        static string SanitizeFrameworkDescription(string frameworkDescription)
+        {
+            if (frameworkDescription == null)
+            {
+                return null;
+            }
+
+            // Some platforms return more details in the FrameworkDescription string than we want.
+            // e.g. on mono, we will get something like "Mono 6.12.0.93 (2020-02/620cf538206 Tue Aug 25 14:04:52 EDT 2020)"
+            // For user agent string, we only want basic info on framework name and its version.
+            var parts = new List<string>(frameworkDescription.Split(' '));
+            
+            int i = 0;
+            for  (; i < parts.Count; i++)
+            {
+                var part = parts[i];
+                if (!Regex.IsMatch(part, @"^[-.,+@A-Za-z0-9]*$"))
+                {
+                    // stop once we find first part that's not framework name or version
+                    break;
+                }
+            }
+
+            var result = string.Join(" ", parts.GetRange(0, i));
+            return !string.IsNullOrEmpty(result) ? result : null;
+        }
+    }
+}
index 41a9cfb..e98f6e9 100644 (file)
@@ -73,7 +73,16 @@ namespace Grpc.Tools.Tests
             if (RuntimeInformation.OSArchitecture == Architecture.Arm64)
             {
                 _cpuMatched++;
-                Assert.AreEqual("arm64", _task.Cpu);
+
+                // On macosx arm64, x64 is used until a native protoc is shipped
+                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+                {
+                    Assert.AreEqual("x64", _task.Cpu);
+                }
+                else
+                {
+                    Assert.AreEqual("arm64", _task.Cpu);
+                }
             }
         }
 
index 40e8b72..2bccb0c 100644 (file)
@@ -59,6 +59,13 @@ namespace Grpc.Tools
                 case CommonPlatformDetection.CpuArchitecture.Arm64: Cpu = "arm64"; break;
                 default: Cpu = ""; break;
             }
+
+            // Use x64 on macosx arm64 until a native protoc is shipped
+            if (Os == "macosx" && Cpu == "arm64")
+            {
+                Cpu = "x64";
+            }
+
             return true;
         }
     };
index f45d6e3..19bb992 100644 (file)
@@ -4,14 +4,10 @@ gRPC C#
 
 A C# implementation of gRPC based on the native gRPC Core library.
 
-There are currently two official implementations of gRPC for C#
-
-- The original gRPC C# implementation based on the native gRPC Core library (the source code lives in this directory)
-- The new "gRPC for .NET" implementation written in pure C# and based on the newly released .NET Core 3 (source code available at https://github.com/grpc/grpc-dotnet)
-
-The implementations are meant to coexist side-by-side and each has its own advantages in terms of available features, integrations, supported platforms, maturity level and performance.
-They share the same API for invoking and handling RPCs, thus limiting the lock-in and enabling users to choose the implementation that satisfies their needs the best
-(and perhaps adjust their choice over time without needing to do too much refactoring).
+The implementation in this directory is the original implementation of gRPC for C# (i.e. `Grpc.Core` nuget package)
+and it is currently in maintenance mode. We plan to deprecate it in the future
+in favor of the [grpc-dotnet](https://github.com/grpc/grpc-dotnet) implementation.
+See [blogpost](https://grpc.io/blog/grpc-csharp-future/) for more details.
 
 The following documentation is for the original gRPC C# implementation only (the `Grpc.Core` nuget package).
 
index 35b92e2..a2051ee 100644 (file)
@@ -1,7 +1,7 @@
 <!-- This file is generated -->
 <Project>
   <PropertyGroup>
-    <GrpcCsharpVersion>2.37.1</GrpcCsharpVersion>
-    <GoogleProtobufVersion>3.15.2</GoogleProtobufVersion>
+    <GrpcCsharpVersion>2.38.0</GrpcCsharpVersion>
+    <GoogleProtobufVersion>3.15.8</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
index 108911b..4b0018e 100644 (file)
@@ -17,6 +17,7 @@
     "Grpc.Core.Internal.Tests.SliceBufferSafeHandleTest",
     "Grpc.Core.Internal.Tests.SliceTest",
     "Grpc.Core.Internal.Tests.TimespecTest",
+    "Grpc.Core.Internal.Tests.UserAgentStringProviderTest",
     "Grpc.Core.Internal.Tests.WellKnownStringsTest",
     "Grpc.Core.Tests.AppDomainUnloadTest",
     "Grpc.Core.Tests.AuthContextTest",
index 585796c..dd4a1b7 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-gRPCCppPlugin'
-  v = '1.37.1'
+  v = '1.38.0'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates C++ files from .proto services.'
   s.description = <<-DESC
@@ -100,7 +100,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.15.2'
+  s.dependency '!ProtoCompiler', '3.15.8'
   # For the Protobuf dependency not to complain:
   s.ios.deployment_target = '9.0'
   s.osx.deployment_target = '10.10'
index 05408e5..8028ff9 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.37.1'
+  v = '1.38.0'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
   s.description = <<-DESC
@@ -102,7 +102,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.15.2'
+  s.dependency '!ProtoCompiler', '3.15.8'
   # For the Protobuf dependency not to complain:
   s.ios.deployment_target = '9.0'
   s.osx.deployment_target = '10.10'
index e6db8f7..0a86fe7 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.15.2'
+  v = '3.15.8'
   s.version  = v
   s.summary  = 'The Protobuf Compiler (protoc) generates Objective-C files from .proto files'
   s.description = <<-DESC
index 2ceadbc..f2ef17d 100644 (file)
@@ -39,7 +39,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'BoringSSL-GRPC'
-  version = '0.0.17'
+  version = '0.0.18'
   s.version  = version
   s.summary  = 'BoringSSL is a fork of OpenSSL that is designed to meet Google\'s needs.'
   # Adapted from the homepage:
@@ -76,7 +76,7 @@ Pod::Spec.new do |s|
 
   s.source = {
     :git => 'https://github.com/google/boringssl.git',
-    :commit => "1a7359455220f7010def8c63f7c7e041ce6707c6",
+    :commit => "688fc5cf5428868679d2ae1072cad81055752068",
   }
 
   s.ios.deployment_target = '9.0'
@@ -213,494 +213,496 @@ Pod::Spec.new do |s|
     # /src/boringssl/boringssl_prefix_symbols.h. Here we decode the content and inject the header to
     # the correct location in BoringSSL.
     base64 -D <<EOF | gunzip > src/include/openssl/boringssl_prefix_symbols.h
-      H4sICAAAAAAC/2JvcmluZ3NzbF9wcmVmaXhfc3ltYm9scy5oAKy9XXPbuJaofT+/wnXm5pyqXTOx0+72
-      fu8UW+lo2rE9ktzTmRsWJVE2dyhSISg77l//AiAl4mMtkGvBVbtmOpaeZ1EgvgkC//mfZ09ZmdVpk23O
-      Vm+nfySrqs7LJyGKZF9n2/xn8pylm6z+D/F8VpVnn/Sni8Xt2bra7fLm/zs7T3/7ePnPXy4vLy4+bH/7
-      cP5hk22v1r9+3P62/i378Mv5Ovv1tw+/rX/9t3/7z/88u672b3X+9Nyc/d/1/zu7+HB+9Y+z36vqqcjO
-      ZuX6P+RX1LcesnqXC5HLeE11dhDZP2S0/ds/znbVJt/K/5+Wm/+s6rNNLpo6Xx2a7Kx5zsWZqLbNa1pn
-      Z1v5YVq+Kdf+UO8rkZ295o38AbX+/9WhOdtm2ZlEnrM6U7++TkuZEP8429fVS76RSdI8p438P9lZuqpe
-      MmVan669rJp8namraOPu++s9frTfZ2l9lpdnaVEoMs/E8dctv0zPFvefl/8zmU/PZouzh/n9n7Ob6c3Z
-      /5ks5L//z9nk7kZ/afK4/HI/P7uZLa5vJ7Ovi7PJ7e2ZpOaTu+VsulCu/5ktv5zNp79P5hK5l5T09e67
-      69vHm9nd7xqcfX24nckoveDs/rNyfJ3Or7/Iv0w+zW5ny286/OfZ8m66WPyHdJzd3Z9N/5zeLc8WX5TH
-      uLJP07Pb2eTT7fTss/zX5O6b0i0eptezye0/5HXPp9fLf0jF8b/kl67v7xbT/36UOvmds5vJ18nv6kI0
-      ffyn/mFfJsvFvYw7lz9v8Xi7VD/j8/z+69nt/UJd+dnjYipjTJYTRcs0lJe8+IfkpvIC5+q6J/J/18vZ
-      /Z3ySUCGXs4n6jrupr/fzn6f3l1PFXuvgeX9XH73cdEx/zibzGcLFfT+canoe+XUWfj+7m6qv9OmvkoP
-      eS36KqZzmRBfJ1r82b4b/6Hz/6f7uXTK4pNMbm6Sh/n08+yvs30qmkycNa/Vmcx6ZZNv86wWMvPIzF+V
-      mbwJjcpiMlPvhPqDEuWNKq0qx1Xbs126rquz7Oc+LXUmlP/LG3GW1k+HnfSJs1Um4UwHkqX3P/7t32UZ
-      zcsMvJz/m/7jbPX/wI+Smfzp8/YLQYf5xbP07N///SxR/2f1bz01u0+2iaxl4Gvo/9j+4R898P8sh8ga
-      qqVDes/N8naRrItcJlWyy2T1sBmr80nHytCBHpHVL1nN0VmkY1V1YbI6bLcyu3HcAG9HeDlPLvgp69OA
-      nalFfeyU9mnPHpMS4XR4knm6yXeZatloXoP0rM+yhSsyptiGPTcrEZBfH3PPwndM1RV5mTd5Whx/SbI5
-      dDUvNRCu6uNO5/OkqNJNogyqdyO7YmMDQWxvvn+Y3qkP1DVQqkyX640P069JnXXxFrK7oNrEkVaIBcyr
-      vIqyO7wd4bWWrShX78GQO+LyQUEfQ/3xevYgey7JJhPrOt9TsiRMg3ZVP6QHWc+X+YahN3HUv1K9FZ5b
-      oah3ne9l/z7iynsBGmOTP2WiiYjRC9AYbHfA+f1nUqa7jCnu6KCdfdUtjLp36c9EVtmCl98dAx4lL2Oj
-      9AY0SsQtCKb/vt5G3ICODtirplpXRRIR4WRAo9TbdUz6HHHU/5IWB65cs7g5Kt+E8kwuklS2awxzR2LW
-      VVGtv3f1Hc9uGsAoopE9wrTecG+qxTsR7r8+JOlmk6yr3b7O9FQMsTs4oAHibessA74pyBExERBT5o8P
-      9PSzSNj6Lj8E8SAR8w0rQL5BfNxkgVJl+ZfKBx+S9XMqa/F1Vjcks4+D/vM4//mQX39i3ZG0eGIEAj1I
-      xHaYej1hhTnCsDv72dRpXJJ5DjiSaH8mJ0CH+t71cybrx32dv6hZ9u/ZG9XuCYAYbX9V/ranujrsyRFs
-      HPAXWVobqSfIEVwBFsO9T8xIngaLt6s2GS+EIjFrpcdVzGvvYN+dlemqyJJqLfaqUdwXcqBPDQE50Egi
-      fyqzrhZQUxcS2O0FMyQsQ2M3hVD3rywzcncTk/ixtsVBPB+LLvmH2TRgl+072SkZ36QbcZVy+TZfy1qA
-      anV5LIIqLzy3IkNWXmF2eSTCPq3THcutScza1riMGtvBQX9bEESjns/Q9QaN2E+5PlmvWAFMARJDNxuC
-      ZW9RxHvsDiRFLhqW3jLAUeSf0kMhh6SpEK/cVPIkI2MlB5HVm7RJ3yXoyQZHz34m3FAdinrL7FV2GzbZ
-      T6b8xGMRInsDoASOlZfbKlmnRbFK1985cSwBHENWBkX1FBXFUcBx1ESXriG4BcgS4DH0dA5r2gOTILHk
-      rYuP5UqQWIwe4ZGDjczeoIHC3h+HXD3Sfj40m+qVlSS2AY6in6ekz9TZJ4+G7V3vSeZnOcxhp71vgaMR
-      n2gCKOIthKxl5HfW39siyrrZvgWOJrNvvn2LqkUcRTDOJts3zxFBNB+MwL3tBu779RPR7htFtU5ZZRCU
-      +LHKTI5smt0+mS/IEyAmC5lf6cJX31Nnu+ol405w2LRvVx8k6Xot7zRVbaBBb/JUVZsIuebDEeqszJ6q
-      JmcMsBANEq+tpraHomDF6XHMv0qec3pnyWQxcyUHBWveTe7YsJl/m03BQIzYGw14kIh6MKJvl8j/5gWz
-      FYE4+osrdowWD/hVXz3C3+IBf1fJRIQ4GZAo7EIRKBFqAXDGs7Yo4i0PuxXxkZyNIl4RnyPFmBwp4nKk
-      GMqRIi5HiqEcKaJzpBiRI7teJS//HGHI3XzoFmgm+6piNDM2j0RgzReKwHxh+9lx8kbw1Ccc8R/7vuz5
-      N9gCRjtnp9F5II3kZ4f6hVPrnNCglzVt4PJIBNZcbU8iVpE/pcUTL0E6NmzmJ4kpQGLEPesAFEic98j5
-      5yNzfiKHltVrcii/l9WrenC872ZfODcJl2GxI6ON8YusUJ1ATuvgGuAo7dN3lr5DA17u/R+87/rzyCkK
-      zINE1FO7abnhPF33BGgM/vMUMfw8RfSrTpk1jYkj/qjnKmLEcxXjOzGZ1zIgUQ51rb6k+kDcMLYCiyOz
-      +q7Lh7wohgCOEf0kSox7EiXe9UmUID6JMr/fFet92jyLmLimB4lYCV2Ty3pWTxDz0taVwLGytC7e9POy
-      bv0BpykHLEg03lM9EXqqpz7cpoXI1NqQumt2s03SvTyrWy1OwCEnfCVPdZZKLCItbQMcJX8qZVumOlDn
-      HxP1GOSpTjeslhE2IVFjnjaK4aeNIv5poxjztFHEPm0Uw08bxXs8bRTjnjYevyYy2RvY1umTepGWG8uS
-      ILFin2yKcU82BfPJpkCfbOpPRFz2MvnhCElaP8VGUQ44UqmevbWpGNWzhzxDEUWSbl7U8iyRbaLDOjI4
-      tl4AWGdiX5WClSksARKD99xbhJ57C/0SyWkpLGexP2pBoonvpx5pRFYHNHi87uXU2HiOBonXbZTBidGi
-      sPfHIV9H3B4DR/0Rqx/EiNUPImr1gxhY/dB+3qiRZ1XKHp94Ti8uf02qrTn+EbyoQ1bsarr+tOzjypJ9
-      2GW86K4FjnasHPtVqcyaDxRhMWNXm4iRq03M76khf1U2soKOidZbwtFUwd88Z9y1LgEVEhda183uCuI2
-      PHpePqkXU6pajih2evciwQ0NqJC4dbNXze02LzJeNFOAxGjqfB09LeRb4GjdsiP1smBEte1bsGjs3BnM
-      jfY8eMzYETahUVX3q21v1Wtl3K4qKBobM6a7gNvC0Zu0OYjYX3uSjInFayRcRzBSvwIvLprlGRlRvEs8
-      EYx2UJMxsv6JCHVUIHFknb15Zuk1GbLGZXNbgcfJ1vzrVyxurkXKFUs06I1OGtOBRKoPvGZIg7CTP7ke
-      mlXveqHv0DGATcGorDWzYnDN7EENubdUb0sBNlmGH9pR8B/0B2c2PWRPJou787gQWjEYR/WnIuMoBRxn
-      vpjEJZglGBGDnWy+ZUw0buL5FjhaxCuMDj7oZ6ec6xiO1D4+5qYdbBqO+h7x8Ehq6NduStm8Jc85fQ4c
-      lNixus2tErXB6ulxUP/4ixJxQAXHNZ60rdO96t5zQvoWOBr1bWCTw4zVLlm9NbQBqE/D9vbdW/LGMAAe
-      8POmRhBFIA57uhu3BKLts4g0U/CA2yzDIiqQZRqK2s4lxsVrHYFI7zOdNFIZuI52LMWO2eKon/P0HsCD
-      fta7uZgDj0RbsGiTuHWn9kauqQu6YAMe5bQdGePha8iDR+yG6EW+zfS6I2rTOuQKRd5l/Ei7LGwmzuUB
-      OO6PvDnBe/KcitjKzVHgcfhVSk/D9ly0j1q4fRiThyMQ30M0MNinVxLzqo4ODXpjehWOAo0TU4eLoTpc
-      vFPtJEbXTv3sPTdOKIeKiBpIBGsgEVcDiaEaSMixRLFJVuptp/KpyNTIhhUI8MARm4rfqz+yYXOyreqI
-      mw1o4Hj0+SqbtK30F4yh94oj9vcL7u0Xsa9fcE8/tblcut8Xefv2ucqwDWV38JDDj8Taxy+wh5/6SM0y
-      dK8NHFb/ytaNUDlI9sJpE9UDKiduob6kNrnudkQnRXLhAXdSVJEBtAGKokfp3aSwaqKLhh7Hd0CRmrd9
-      xk4rAx5wM9PKNdhR2pUYzzkpcU6Q41ILZNqt+Ei2HnN8Mfs/Duz9SL9K4Ppi9nYc2NeRt8citr8ie2/F
-      wL6KjA0NwH0M1oemea6rw9Oz3i+1yGgz3ABu+zdZkT2pM7uSdZ3pKdW0UD0IUg8alTixKn2IhxzOfCf9
-      CJNzjLI5Z7x2ZGC2r51zPa3pXTc/1S5fmT4FSY35KEGGXFBkPdvbdi5odwDAUb96d0G11eQqGXM4kSJ3
-      Ex3eSfTddhEl7CAavXvoiJ1Ds7qW/V7m8Rse7Lh/7qtaL+FQLd1OFtZaFlJSANBgR6E+i/CfQZyODVSL
-      W/QW8BSfT7v25oP5iiytkPk0YDcfg6nOhSBH8AxQFF6zGt73tN3SvX/N4LQJDT2VQAsQjf38ZOi5CW//
-      Vmzv1v45Q+yIKWzConKfy4x5HtN/p2vGu/3Y2zUpzHCgCovrroNhxvQ0QLzuzYU6+3GQ1bys9Im7gaAS
-      MFbMMm1EAcV5lydbpCdaT3oDCvqebybnGZPuET9ReMR8H3NViIMC3nbJ8+qNfuQLgKN+xh3EV2Mz91VG
-      91SO2095aC9l4/Na9vyrHVPewoC7e0WfvgzBpwP2/oALdohegcfpD2plRjkJwBgvGbGra3KYkXq4ik36
-      1uOb+4wZewD3/d7YhxrBEwAxVBee7FUQ4KI/Q0Kf/xsfJH9dfvhnsljez6d6NVa++ckMAZjAqKzVBuFV
-      Bt3m3TuRiMNeDWroagP23VtyadkC5UT+IxfPGd3Vcb6RvTfAwC7k+uMXcrsiEd9zGrglRUYuYxbsu9n7
-      CQzsXB69a/mIHcujdysfsVM5Z5dyeIfydl/O47gvaarvWZmsZFFUUwecUdmAzY/OmM1F90XXK3GOgyj6
-      xnsAHvAzO6wuj0TgVioWjLkPRRGbRI4DiaTf4W5k507oKSmdBQQrHmhCoqrBUdoc6qwfYrJiAh4oYpu9
-      eT1UmwbsrCNobBKwGsuyyV6DDZvJS9tAgR+D/97/0IkHegvhVV5RnYoBTKydA0JnJpw+E2pGo1xnLPER
-      Btz0DlEN9YhEtlalpt8dW0+d8bpwIRcUuZ3vtd6upocEJFCsdnaJNe61YNStXsljlH2bxuyckV1Phqx6
-      Npyv1jjkZ43Q0Vks8ZzWag6NN9li06idsS+tT0N2Xu2H13tAY9edUE6OgZrGRVWDA1YGCrjGRWaVCMQD
-      ROTuGPEU3i3CWAmePmWJ+E5bqQvggJ/9ONWnYfuhzH/Qp2h7ErQab/yfHkExQkCaoXicHOwb/CgRG+sO
-      nvsTc+ZP+LyfiLN+guf8GB/SF8d5MOjmtDnoqP2V0bt8BXuXr/S+2ivUV3uVVVbG7lDatG1X7yzEPoXF
-      HHakvGS+NWqBntPYtJQoNUjPKsfmVJ1CHI9INrK2IHlaxPMoOWu6wWU9c9ujIypbyHcBzazarGIvqIkQ
-      MHlRI/aE9Wnfbs2P8RZxBDR2PNUTOuw3xBmrnrJtRb6q0/qNnJlNzjGqg9b6R43UcRuAA/527VW7GE6Q
-      9RZt23fpU74+zeactk9rSLkflbix1MayaZFUsqBQpxc82HZzz7HDz7AjvjfmvS9WHnb24J9033zatu+z
-      jNSFUt93Dfp20SQacTx1tVZn+uiJzn0lGt4S3IAGjtdWUuoB3DHD0V8LGnJ5kV/yTdZeIrXF9mDb3W4a
-      KvP46Vcn2yJ/em6oT6mCIiCmnlkrspesIEfpUcDbdrB4YoO1zTWx0qi9eoJ5gB56Xp7xAadEAbjrF+6j
-      /X8RV/0jCjtOtxVpv6qSEsGDXbfaTFxGLtpXYmhqm3XNbWmtM+oLBTbpWjknhGGng0WcDBY8FUx/SJ30
-      P0GAK+qMpTEni+nvvHKu+BW64nPWPTpH7hHnZDL0VLKYE8nCp5HpT6G3YcghIAkQi/wsHTvxjHvaGX7S
-      WdQpZwMnnEWebjZ4sln8qWZjTjQTvDWvAlvzqs//as8KVnN91Ou1WMDMO/sseO6Z+pBe4yRQfcM5GAo9
-      0Szq9K+Bk78iTuQKnsYVdxLX0Clc+vPueGJW5rJgwM09D2vgLKz485PGnJ2kv9O+4JWtn7vjgchBXAEU
-      Y1vV60xPLOk5FJE+MeIAEiAWfQUpuvuIIK+KFMCqyPc5VWnsiUpRpykNnKSkPv7X5vv5efJa1d/TujqU
-      5NRxeT8Ce73jwNlJ0ecmjTgzKfq8pBFnJUWfkzTijCTO+Ujw2Ugx5yKFz0SKPQ9p+Cwk/Y3mQJY2B9/D
-      fmVw4HQh5slC6KlC8ScKjTlN6B1OEhp1itA7nCA06vQg5slB6KlBpyN/zO1U6W/jBTRIPN7tRk8nOn0Y
-      s+wVlSCx1F67ahi6lmMYWR/tq7zkpRokAmMy1yANnbrEP3EpdNpS+1k/Rcip510eivCeZzlxznES9DWc
-      AlrDKXir7QS22i7+LKQx5yDp7zxnG2PKXn5vm5ObSFACxeLlfzznv88LwpRTlN7pBKXRpydFnZw0cGpS
-      e9YRY8SLjHTjTl8ac/LS+5xXNPasIuPwlmf1YJC62hHi0Qgxq+7E2FV3InrVnRix6i7y3JzBM3N45+Vg
-      Z+VEnpMzeEYO93wc/Gwc5rk46Jk4sefhDJ+Fo7/hv9xGrswgBxCJeuIOctoO76Qd7JSd9zlhZ+zpOjEn
-      64RP1RExK0hFeAWpoK/TFNA6TVZPA+5lkNtHoG1Uf2LsSmZyuJG8PaQH2+6mUg+9+SuIIN6OwD9FKXSC
-      UuTpSYMnJ0WemjR4YlLUaUkDJyXFn5I05oSk+NORxpyMFHEqUvBEpNjTkIZPQoo9j2j4LKLoc4hGnEGk
-      1q0kz1lRVGq4Xb8dd4sihgEddiTGvDU4U/2a0hJBfd8xqIVhJIUCLMfLxcfjRAR5As1jPTNLibi6WUyW
-      0mJ78/J2wfvxHmg76TLIwvrBHmg71Ylayeqw3coMyTADuOV/OU/O2Snqw76bJ8Vs3BT2Ydd9EZMKF+FU
-      uGBKMVtEKlyEUyEiDYIpwBHCpojfjvzyzUWeGOcfjHU6GOqjrN4B0N6bX2w41+lgqI9ynQDae2Wrfz3/
-      9rC8Tz49fv48neuhfHs84PZQrsfGGNAMxVP75r5DvJMmEG+TZXt9YexQJ0MgilrcXx6Kgh3kKAjFOOz4
-      +sMuYN4fxDNbreCAW4x/ZwJiA2bS5pUwbdkX8+WD/P79cnq9VOVG/ufn2e2Uc2+HVOPiku53wDIqGjEP
-      hDR2PLXSc/bw5VRH7PbUko8psDhq7XGT8QK0LGo+7Jnawx5zyj9teFJFYlZOpvVp1E7LmhaIOakZ0CYx
-      K7WScFHLq7d8vJt8nbKzMmIIRmG0zZgiFIfTJmMKJA6nLQZoxE4sSDaIOQkHAngg4iS8+ulyuJFa2H0Y
-      ce+rPT8VjjDmphV5G0Scej11TME0BVgMwoZdHug744rfUMnjZg48X9Bq/yPie7hZC89V4jnfku+MhnwX
-      teXood41ub6Wg7DkZrq4ns8eltTjzhE86B+/8QAIB92EmgumDft0kVx/nVyP9nXftw3r1TrJynX9Nv74
-      QwdzfNvV+cUVS2mRjrWpuVaLtK2bjKzrENuTrVecSzMwx8dwQZ6KfS+qwL0QerN0/QHlvSgA9b1dQI7X
-      QG3voXyt0z1V2VOYLdmnm834BVUgbLs51wlfZcQ14le4uDtPJnffKPVjjzieT7Nlsliq77cHEZKMLoy7
-      SU0FwOLmJ/0SYsOVdzju56tDVkrz46O4lzBFBaBBb0wqCziVvz6ws4eFol7qFRsg6iTfOpN0rff3t9PJ
-      Hfk6T5jjm949fp3OJ8vpDT1JHRY3PxHzmI3i3pytDaUD9XbZKO4V/FQQoVRoquTTHdesYcf9mZnJPqO5
-      7PfpnYx3O/vf6c1yJoeC6eZfJDPAD0SgN02gYSAKuchAgoEYxJvg4wN+anYH+IEI+5qwRAc3DEShFi+A
-      H45AXOI4oIHjcVs4Hw/6efkKa+3sj5l5Cm31ZpNLbqrYKOolpoYJok5qKlika71bTn9Xz4B2e5qz5xAj
-      4bGOyyFG+j0yQMRJ7UIYHGLMecIc85Hvds8hRsH8zQL9zarqOciq9NdfuOIOR/z0rohFOta7x9tbemY6
-      UZCNeNM7BjJRb/cRclz3n/5rer1U+0QRFvr6JGwlp53BwUZi+p0o2EZNwx5zfdfLaT+xQKwiXTjkplaW
-      Lhxy0++WS4fs1DtnsyEz+S46cMhNrQJd2HE/yL8vJ59up9wkhwQDMYgJ7+MDfmryAzwWISJ9ginDTpNA
-      avDTIZgClJdHAdTxLqb//Ti9u55yJmMdFjNzrYBxybvMJXKFbXZr0ybdbGhWBw6510WWlsR6GhKEYlC7
-      oy4Mu6ktF9pmHT8grDZxOdhI2VTM5RAj705tsPtDrrLwmryf8P/A/uEnGHWfji/epeI7M4TlgCMVWfk0
-      /h1Zn4St1EoXbXO6D+hTRSYYcCbjzyCG2LA52e5j5BKH/YJXywisflEb/jKFH1BjsnpL7mY3TG9H4/bY
-      0iFGlQ73W0kq1u8RTXngiHLA+7j8fMUJ0qGIl9phMTjcyC3oR9YxL38951bXNop6ib0WE0Sd1DSwSNfK
-      fMayRJ+xsB6sIE9TmI9Q0Ocm+oNNvt3SdYqCbPSMgzxv4TxkgZ+ssB6nIM9QmA9O0KclrEckyHORmIch
-      4Scg+lNZvT1lZVanRf53tlE7VdEj+A430reHKbm/fYQgFz0/HinIRh1fHCHIRc6RHQS5BOe6BHxdapd1
-      luzcsT3ezf6czhf8J2eQYCAGscLw8QE/9aYBvBthec1qIgwOMdIbCovErLu93qYuaXjqE4746bnEABFn
-      zrvWHLtGci7oOcRIb1IsErFSqwWDw42c5sXHPf/nK3Y1YbO4mZwNDBK30jODiTreP2eLWcQ8uI8H/cQE
-      ceGgm5osHu3YaQdcG4jjafsfjRz+qM1CST4bxbwvH3nSl4+esUmqFeXsKwdzfHmT7ZLNRU6yHSHERdkD
-      wAMxJ3HaxuBAIz3jGBxoPHAu8ABenTragXNLWg4xkusNE0Sc+cWGpZQcYqTWEAYHGXk/GvvFrJ+L/Fa1
-      +QWrnHQg5uSUk5aDjKzbgdyLfUrseZ4oyKa2K6bbFIXZknXzk2dUJGQ9lLzf3HKQkbb/p8s5xt2q23WR
-      /OzJIjFrydeWgLdtvmR6/00r0QbnGGUveZc3+UtGryZs1PUemiSraHPSHQOYGK19jzm+Jn26oL7o0TGA
-      SYw/HtlkXFO22xd6/0DqTbBIw/q4/CKB5bdkdvf5Pule8CTZUcNQFELaIvxQBEqNjAmgGH9Mv81umKnU
-      s7iZkzJHEreyUuOE9t5Pk8XsOrm+v5NDjcnsbknLLzAdso9PDYgNmQkpAsKGe3afpPu9PtYpLzLKdvMA
-      antPJxitm7qgWC3QcRZZWifbIh1/sKaDQb52Q1Cm1YAdt9roRB8UrL9CMtuo46Ump5+K8i96uKgPYyFu
-      pooKkBjtCddPh7ROyybLWGEcBxCJeCC1y9nGTXU8YZHi6ynbllVbikZ+3ebVjjCkx8gW5LgKwi4nJ8Bx
-      1LS76NST3V+StCioFsXYJr3WhrAUyGR80/ht4HsCsOzJlr1vycu8oXoU45t2ahKCkUZHDjbux3cMHcz3
-      qd1dZH4dvyTIA30ns053UMyrjhQdv000xPpm6gkCLucZqT/c+bXP2c/NYUfKzB1ie9QNKkl5uSVcS0Nu
-      +Y6MbVLZUB9OVdJSyORcY/NMrhZPEOCidPAMBjDpDaRIL7MAKOYl3g4LRJwb2ZGoqzeWtmMRM7VAWCDi
-      lINwnlOBiLMmHKrngYiTtJm8T/rWit4jMTDbR8zsXj5XjcAqr5J9mtdE0YnzjYwOoIH5PlrfoiUAC+H8
-      BpMBTHuyZ+9bVJ24Omypqg7zfaJaf8/Iid5Sru0n0fPTNRx2q6wml0cDA32qRMk2hKHsSNvKGPiAY559
-      RcoQ8usOr5YjkDJCSziWpiY3K0fGMREHOntvnEOt3P06nZp1/DzTnpYqynOqRkOAizPLY4GuU9CKqwYc
-      xyvvql6RaxKculvANbcg1tvCq7UFuc4WQI2tTuTY0SQScB302lWAdavuwxWEU6UtCHDJpNfnVVLzgAcj
-      bjUQ2BP2SQVhxM32wk7qSF2AsxmCPJshgNkM/TfqCPoEAa49WbT3LdSZEQHOjIhuQoLYezEw2JdVWzXO
-      P9QlR9vTvr0kLCUwGd90mocg55CeDFiJMyMiODPSfyr22TpPC566gzE3eYDkoL6XM5sj0Nmc01CsO6GJ
-      9IgcFTgxnqtDsUnkiIiT0i4MuslZrscQH/HBismBRnpGMDjX2N5J+RlNeMIcX0nvYx8Z29RkglGx95Rt
-      O6hjn0lX1RK25YU6f/biz529cJLoBU6jV8bA6hUcWZGzFJCX2qJLfGRygiAXp8ttk4b1dvLH9OLTxeWv
-      o20nArIkn/OSUP04HGicUToNNgb6HvcbypyqCxrOu+TT7ezupn3Pv3zJCL1JH4W9pKLlcLAxL1/SIicl
-      AUijdmYy5IFUoMwz2pjlu17+lWTjD/foCc9CvC1HxPMQXk7rCc9CS56O8CyiSWvq1WjGMv0+vbv+pNeB
-      EFQ9BLgEKY1OjGX6en+31BdMWfTocrCRmBUsDjbSbqeJoT5VyYiG8gIoKsBjbKs62VWbQ3EQ3CiGAo5D
-      ywwmhvqSQs2TbJjajrbs6UokuUheq5piNSjbtiFZNh5NvpAOsT1ifbEqKRYNWI5VXtIcLWA75F9ykkMD
-      gIN4LIDLAcZ9SrftU8+0Xq1Y19ZzrnGTrWkqCbiOZ8IajyPgOoqM9cNOmOvb7XOaSQKWQ68DJCj0930D
-      ZXt+kwFMxOakh2wXYfHHnf0efvtvap1xRGwPrbH12th1dShVBfua/J3VlUowQdJ5tGWXeZxWG7WA7chf
-      KIL8xaWp6XxEbM+Bcrett9rkv7PyOS3X2SbZ5UWhHn+mupKr853s6TdvevKAoB+js+P/OKQFq4PikLb1
-      JyVN5LctmlgKvfK3raud7MiUzVO1y+o3ksoiLevTmpJV5Ldt+vjWqroXWUKqzj3WMTdJvV1/vLz4tfvC
-      +eXHX0l6SODFOIzfbLknPAuxxB0RyyPbNlrd0QKWg/Qw5M59DnKn+oqyTiP2iHvIdZXZU6pemaLJjpRr
-      q0id1hbwHCXxYiTgOvbV6wVNogjPQi8xBgXbtqmstdS8LE9r4K6fmMGhMYf8m2o0aRZFWJYioxUS/X3b
-      QDqJ8QQAjnOy5Nyy7NJaPMvWhrSiw8Ycn/hO7dGcGNtUbYhjxI6ALMmPQz7+nViX84y0VrgjIMuFbhPp
-      rpaDjExh2MfqxsACPAaxfHusZ9ZTr4J6yR2F2ZJVoRaDb3jWI43aqw3XXAE5n1zP9BDiOmfJzjEbq1xa
-      LGKOECPe3aEg6iQBWXgdaB/23MROwRHxPOJHTdRIArI0dI2f78RhRdUcVpCFlSVOnGdkVFd+LbXPaV2J
-      FrAdtHzp5kmZpai/pEMsD21y353TL0uZPBRefd83UEtAD9muw47ahTkioIeawBbnG99k/5hqU4xlog1C
-      3BHIPlUtjur8JYdS7UVCag8B2rZz52gCszGkXe2O3/cNlAWDPWJ7RHbYVEmdkp7YGhRmU//nKeM5W9Yy
-      Ey/QuzLWJQWupf0zbVhpcbaR2jOq/V5RTe4R1UBviHgMbk94FsZUh4l5Ptq8lADmpQR9XkpA81K0Honb
-      GyH2RLxeCK0H4vY+VA+CmgYdYnmaKnGOZiUYfRh0d2etMcQd6VpZXV2Ls4wH2oTAwZ0NONAeIB3cJ0gH
-      WlY4uHnhJS0OGbHtPTGWiTiN5cxhnb6yPZTrJq/K5JlQA4E0ZBdZsaW14T5qeB8/J1+nX7stXkYrLcq3
-      kR6JGIxveqqrV6pJMbCpPWOI42tJ30rpoveI71EvTNUv5ETrMNu3y3aUp3wnwraIpiZaWsKzFOu0IWoU
-      AngIT4h7xPOU9J9VQr+rLLKS6inM9zqvP33S06GUaWKTgU3JqqoKjk6DiJN0eKlPItZq3ZD3m0YFWIx8
-      0z4nbQhvCuMGJMqBn0AHJIVIQ1IL8l1in64zqktDvutw/ivVJBHQ051xJYd08qOf44e7AQUYp8gY5gL6
-      7RfkeywR0BP9230FEOfjBdn78QL0MNJQQYCLXk4OUPmQf2Rck4IA1xVZdAVZom/qVfieEs9YNBDbQ3n7
-      9Ph9x5ATX6KyINcl1mm9SdbPebGh+QzQdsr/yMfvDNATkIWyWbRNOTbKrmwnAHC0DYca1I/fcw6EbTdl
-      kcnx+74hIef8nrJthP5V93WbJ/apDcT2UIaFx++bhkXXvcpqNQrfZPV4mYdC3rzp9lp+TgVl1gs3AFFU
-      L0heAq0X5bO2We2zleal6FZdvlGqE4h27fs3ajfKpGwbrc5ceHXmQq8OS8s3Yn/f5nBjkhXZjrADG8bD
-      EVQOjI3iOoBInJSBU4U+EnJAxMn9/YO/O8l3+yJf5/QBEe7AItEGKy6JWA987QHxkgvvCfJdRSoaUkfP
-      wnxftVezdMRVXiA84GZlY98wFIU3GB8yDUXlZRrI4UcijVRPCOjhd+xRBRinyBjmIgNcF+REdUaqpz9G
-      //bwSLX7EmWkekJADyMN3ZHqgrqE3EBAD+Oa3JFq92dyBQbVXTEjVcxgR6GNJRbeWGKhFgkfFzKc2p7s
-      idZ5xhxeJP2iutMZJgaCFKE4vJ/jC+wYpDHTwh0zLdrdidSrMhTLCbJd+yz73l5qk5JS0wJtp/ie7ykq
-      9X3H0Ix/onT8vmugPBnpCcMynS9nn2fXk+X04f52dj2b0k6pwPhwBEKJBOmwnfAkDMEN/9fJNfkVfAsC
-      XKQENiHARfmxBuOYSPuf9IRjoex5cgIcx5yywWNPOBbabikGYnju7z4nf05uH0mnsNqUY9N7BGSCdv9d
-      EHEWVbdnJkt8oh17u5avyMc/43cwwze/TW5mi2XycE8+CwdicTMhE3okbqVkAh81vd8elvfJp8fPn6dz
-      +Y37W2JSgHjQT7p0iMbsaVGMP5IMQDEvaYbLIzErP5lDKaznjGXTyjMfacxO6UW5IOZkZ4dATtDboKhH
-      0+yUMA1YFNrObxDrmb8+Lqd/kR9nASxiJg0/XBBxqs1bSFsbwnTITnuiBuOI/1DGXb/BhyPwf4Mp8GLI
-      juI32cJTH+xBMOpm5BoTRb0H3clJVurnCWYAy+FFWiwny9l1ZEaFJSNicW45YglH42diTDMqXvTvC+bs
-      5Zf5dHIzu0nWh7qmPFqAcdyvt6TuDt3jBjEd4UjlYZfV+TomUKcIx9lXaiKkjonTKbw469X6/OJK7eVS
-      v+2p98WGMXdWRrg72HdvV+rjc67dwTH/VZx/8Pqj7Kj7OZX/Sy4+ULVHzje2PRHVt9bHttN70YDBj9LU
-      EWliwQNu9U/CbDyu8OJsq/q7LBCNOsQ5fyqrOkt26eYlec33WVXqT9WmfmqFOmX+lSP3r00dPMi7fSbq
-      eZ/WO5UwKbnF6kHMyauXbHjAzcoLkAKLw8vPNjzgjvkN4fzcfYnVJbVYzKzHqd+zN577SGN22fSN35IM
-      QDEvZbbfBX2nOvjire0/tcfUcfswAVMwanfe3HuEdVXBuO2Fxge1PGBEXrVnkJiVfOIngoN+XaV3m43l
-      VckI4RjAKDr1KDuoQyxqVmvuIm6xqwDjNM/6ZCf5XcLDBhj3/c+pWulKHzf3oOdUaxBTsSMKO8q3tR03
-      cn/vxHlGXa2KN0F5lxtAfa8+nGqbq0NR87RIVgfKcuiAw4tU5Ks6rd84981EPe9OTy9ztAbpW7Md4Q1T
-      C/Jcqkbh1XYG6VsPu4Qzt3PiPGMVMwKqwiOgqlxTKzOFeJ59Vbydf/xwyev/ODRuZ+Qmi8XNB9rjSpD2
-      7XLcIWTxXlU/WZfu4J6/3jDqnRZCXGrvmSbfF9kV5ZSsgMKPk23bDXblkCBRX9ebEZKW1Q+J8Jh5ueZG
-      kajnVfNF6lWdmN4Z6AAjvU/PVxB6vuL9er6C0vMV79TzFaN7voLd8xWBnq8+hm4Tc/UGDdoj+41iTL9R
-      xPUbxVC/kdd9wnpO3d+TfJukL2lepKsi46kthRenKcS5rKGpdeQRM3zLeXIz//Q7bU95mwJsx52XycIj
-      CDhJbZgJAS71dhVhqamNGb7n9Fr1zIkTOxbV226mi+NU1cexLpOxTdl69ZHabXM5z8gUIr5NdqEeILCk
-      DuuZP0aYPwbMJf3+HBnbVDKvr0SvTdV1hCk6AwE9yaFcP2eUQ2ZA2HdXssOxT+u8IV9qTxrWL4mONNrV
-      fd83JPvDipSADmcbq93+ILs3RF9PYTY1v/BMuCcQjLpp55yAsOWmLLnqvm7xpx38acloYrBP5qJ0lzVZ
-      LQhbzqECJ0bzIXkiORXgO6i/uUV8z55q2QOOH+RfJBHAU+cvnB925AAjudCamO/7QTX9cB3qUIjf/nn+
-      z+Tiwy9XNJuFWt7jlux9viOYfdhyExYEtt+2aeJ+qgZiedpFw6zf56KWV9DLkoDKkqCXAwGVAz3s0W8s
-      0UwdZLsIpzJ3X7d42oLKE2A6dKoLymk+JmOYZvPp9fJ+/m2xnFPPEIVY3Dx+GOGTuJVSiHzU9C4ebiff
-      ltO/lsQ0sDnYSPntJgXbSL/Zwixft1A+uZt8nVJ/s8fiZtJvd0jcSksDFwW9zCRAfz3rhyO/mfdzsV+q
-      58j2lIeaIGy4F5NkMSPWHgbjm7q2kyrrMN9HScAe8T26zaOaNGS72iGMejU1bQ41yeigtndTxah92rOr
-      T4hKhXiel6zOt29EUws5Ltk43nwhiTRhW6g518+1rEGTwyFG3rAJNbhRSAOnEwFYyL/c6+8d/7one/aQ
-      5Qf9d9n9xtNfqQMoF4ScxCGUwwHGH2TXD89CfSTiYKCPvAwIYm1zxMAMpBG7vHuMIg3giP+wKvI1W3+i
-      bTuxrfPaOfaQEGBBMy9VPRh0s1LUZW2zYNRtAqzbBKNWEmCtJHglVWAlldqs+206aVDcfd82EIfFJ8K2
-      0DsWQK+CMbw2od41vebNSrscbky2+V5wtRq23IyevE3Btop4xg7EQmbVitGdisJsSc3zJTVqFEwj+IuJ
-      IyMPhJ0/Ke88eyDkJLRCFgS5SKMuB4N8gpVrBJJrmoqbt4+kayWOsywIcNGqRAdzffQLg66K0lr0hGvh
-      /DD/VyW/f+5OvJR9lufxZ6b5pGctc9HsLy5+4ZkdGrFf/hpjP9Gg/e8o+9+YfX7/+JAQFvWaDGAiNNMm
-      A5hozZ4BAa52mNyOwKuabLVxzF/VhP2EART2yi7CNl0zr/oEY+5D/ZKpPMKTH+mgnTK3ieCIf5M9cfJI
-      jyJe9o1E72Nb8AhbhPskYFXj8dVbTDJ7BiQKP59YNGDXKUZ6egqggFcc97PdFuNfgYNpxM6vTiwasev3
-      4NULJOrwY3UE1baqd6xIoMmK+sf0WzfXTBu/OCDiJI20bM4zyhuey6ykxyEiW9fjN0pDBX4MUgvWEZ6F
-      2HodEc/DmcoG0KCXc9s9HoigGs26IidnD8JOxpwVgiN+8rwVTEN2XQ6pZdljQXNWrnV1JRjmEwubaZNb
-      PolZyZPRCO75c5FU+/THgVoET5xnlPfzgvBKjk15tuO0MavphgVoDH5xCc6dd98hTS0cCcjC7smAPBiB
-      PHiyQc/ZTlWzL9rFET998h/BMT87fwSeAnTf4PbCPBY0c+tSEaxLRURdKoJ1qWDXpSJQl+reJKOZPXGg
-      kZ8rHBq2c5tYGx5wJ+lWfSjvtRwq5GVKmhcc5/OugPbgxIIs19fp8sv9Tbs1Qp4Vm6R521MqGJC3IrRL
-      iAgHDpsMYNJvQlH7vS4KeUlzUycGMhF2sLYgwLVZFWSVZCDTgf773BEHfdWcBQEufR5MTPEJaUbHI045
-      DKmAuLkaFjfkGC0G+USSqreV1av0DT232Tjsl0N43WngyI8sYN4d6DlaMoCJ1icE1kee/lqtmws9f0H2
-      nUjAqv9+sV6tyNYTiVplXKZVkoBVvE85FGPLoXi/cigo5bDtk+32dSZEtnmX2LgOid9U/ILr8FaErouf
-      by5Kwj7yHgg6RSM/2zCcLWg59Yldh7xo8q6WoOQzHzbcNxeXl+f/VH2ofZqPnzC1MdR3nM4b/94eKvBj
-      kJ6xGoxvIj4htSjTNnuYzJffyK8KeCDiHL9W3sEQH6U1cDjDePf77I74e3vE86jM2j6CJs4JwDjon8fY
-      57hbn1RxLGlZ+SQ/EsQIkMKLQ7lvJ8Kz1NmTrGrUaZNFoWvkImuotxB0eJFE3D0VQ/dUxNxTgd3T+TxZ
-      TP6c6j2qifnbR22v2tYmq+uqps04eGTIuuVrt7a3HQPqjylOA4N84k1mnB1Xa9K2vf0ZtMPJXA43JiXX
-      mZS2Ve+H234kKE6Tc4yHcs3++R5su/W8PvVWnSDElRTqTxyhJkNWcsECcN9fZj/7b+kt/qghfIMdRf6R
-      fQtd1jGrluXT7J6T51wWMKv/4JoNFjDPJ3c3bLUJA269U0nFttu47dfH85GLTE9hNnKhcdCgl1xsIB6I
-      oM8H5iVGjwa9vGRx+OEIvASCJE6saq8Gqbu0/k6y95jjq9XSEh2SlK1NDjcm6xVXKtGAd7tne7d7x3vg
-      5LgDmNfqLBVVya6YAdz176oX1aoTtiVzOdDYbS/HFZu46xeNOjyAYTZA2ylSThr0lGOTrS21OB0Zw/Tn
-      QzKZTm702ZQp4UQdD0ScxNO9IBYxk0YsLog4VRdm/G74AIp4KfvneWDAmbzmzXOyyetsTdn9fMiDRKSM
-      yx0OMVb7jHfRCgw4k6e0eSaspEV4JILICG/euGDAmYh12jTMyzYFSIwmfSK94AOwiJmyi68HAk71yJu2
-      Tw+AAl71ppKs+OtnTk1nwoibm8IGC5hLtfM2Nz1M2HZ/Ui8dLas/CEshLMq2Xc8evkzn+qbq4+loL/dg
-      AjTGOt8TC7gH4256m+XTuJ2yFsBHcW9TF1yvRFFvt98lpU+ICdAYtBVPAIubib0EB0W9+lH/fk8bL+EK
-      NA615+CguPeFUaFAPBqBV4eDAjTGrtpw765CUS+xp2OTuDXfcK35BrXWlFPbIRY1i/g8LsbkcfWlmBrg
-      xAcjROdHWxKMpbZj5VeYhgGMEtW+DrSt3PuAp39MTROuZaLu6MCdZNYsaK3CK/t+uad3e6C+jv7b57xM
-      C8JeUj4JWWfUButEYTbWJXYg5HwknfjicrbxJlvLO/4pFdmvv1CMJgcaVSllCBUG+fQdo/s0Bvmod7mn
-      IBv9jpgcZNzckusFC/ScqgfLKTAOCnoZiXnEUB/vMsFS033Gukk96Djzp0zQfrQmIAs9b/cY6vvr/jNT
-      KUnUSr0rFglZyVnnRGE21iXC+UZ/tKCsYrMozMa83ycU8/LS8khiVkaxcVjIzLXixj9pawQdDjcy75YB
-      427eHetZ3MxNX5O27dOS1a4bGOQjp66BQT5qivYUZKOnoslBRka7boGek9uuOyjoZSQm3K4bH/AuE6yf
-      u89YNwlr1788/DHlzqG6LGLOfu6rumGJWxTxUmfaLBBxcp83gAIkBvUZmgUiTuoTLgtEnc1hn6zkkCep
-      k596iTkzhOcZjijeKaIgR1Sv+uoTKt8r9EkYvIa9+P4eyWxqBuOJ94knqPHeI4lBH3AFetKeU5qPIOJ8
-      /r7ZJjuetmNt89ebiGdxHgy6GXX818DKjuNnxOdjBob6iK2mTcJWfYIqR6pB0Nkdj8qQdiRopT4B+4qt
-      kvnKW8vyFVvJ0n1Ay/QnCHQRn9t8RdandH8nP1kxOdDIetLhsrCZV8LRsk166d/GPB+7DgrUP5xUhFNP
-      vRjT7lbAUNqw52b8ZvDXMu6GfycePk0TQTrz0qYc2x/Xi6sL2QR9I9lOlGubfrvQH9JsR8q3sdZEWCDi
-      3NBaPJNDjNQa2gIRZ7sj2Hfa2h6fDtlrkSZVmu2TIl1lBT+O7cEj6i/unrbnxCYDcwxE0pcUGalzDERi
-      PC3GHEORhEhEWjTENWohTyDi6fygmGQ0JUgsYqtvcrgxyTdcaZJjVyreqdyI0eVG79+0bvfiUiuxuOEs
-      yYhYT1nZbyIQHdSyBaKrJJG1lvo6aWPXAc+4iPvDKvu5f4+YrWkgakxNKEbVhOIdakIxqiYU71ATilE1
-      oTBqsC61I3+ZZSJEfYfb5+vGx49pBnDdiPjvFXg4YnT7I4bbn1QI4gNOA0N9yc1iwnQqFPe2275x1S2N
-      2+f8q56DV60nPhntR8dBRk6zgLQBlP3hDAY2cXbbhHHIr2ayYgLYPBBhk9FHlgaHG8nzTR4MutVm3Ayr
-      wlAf91JPLG7WS0Iz2so/iAcidMvzyeaOw4285DBhwM0aKyPjZD36HH9qqMuhRkYteAQxJ7PeNljMPOde
-      7Ry72nNmmp6jaXrOTdNzPE3PI9L0PJim59w0PQ+laVMIVTbUUgbavoRBCxwtqdNX1j68AUcoEn1PXlwB
-      xGF0IMC+A31vd48ErG0HmqxsMdTHq3wNFjDvctlXK59iOhK+AojDmc+B53LUZExsXgYcoUj8vOwrgDjH
-      6RCy/QgGnLw8Y9GQXe9i0R6LSZcbMO5u7wxX3tK4Xd8OrlzDgFtwWzWBt2oiolUTwVZNcFs1gbdq4l1a
-      NTGyVdO7pBKfolkg5OSM/JFxvx4Es8rfiQStfzN+sfcEUv+ZlXpIyhH3qrcxwPdCXrxsYKiPdz8MFjfX
-      2Vot6+PKO3zQH/ULTIcdibUKH1l/z1l5D6+5P/6VuNjHwHwffXEstm6fuRoeXQfPWwGPrX3v/05MPQuE
-      nPQUxNfQq208270bkrTIU1J3wmV984b8TlJPOTa1q1SaieT84ipZr9aJeE51K0WSY5KRsZJ8t5d9j5y6
-      o9Eo4fA1qFNf3+EXd5pQvPUuWRWHrKkq2osBuGVstOTqfeIlV6GITZ0879JjavAj2p5AxKf1jh1FsmGz
-      HOKUG70pTUyM3jIQTURk/o4fiCBz5/lFVAxtGBHlY3SUj1iUf17w73rLImZVfqNrQFcyMlZ0DRgSDl9D
-      TA3oa4bjfbz65T3idZpQvHeokQBPICI3b3Zs2BxZI3mWgWgiIjOGa6TjN/g1kmUYEeVjdBSoRlo/p/J/
-      Fx+SfVW8nX/8cEmO4hmAKBt5Jdkm+xhXPYGWsdGiKqhBI3AV5aEo+L/VogH7z/gb93Pwzp16hzT3CUN8
-      Tc3yNTXsywg7CNsY7CNXgGhvrP2g2rKuT2KAT3YAOPejxRAf4360GOzj3I8Wg32c+wH3k9oPOPejxXxf
-      15ZTfR2G+Oj3o8NgH+N+dBjsY9wPpG/QfsC4Hx1m+1ZF+j27WBF7ST1l2xgv3IFv2qmmg5hDOsT3EO9k
-      hwAe2n5bHQJ6PjJEH2ETJ5mOHGLkJFjHgUbmJfpXqI4PVk08RXZkbJM+Ml7Pta3eSMdTA2zATHuu76C+
-      t53J412xyQbM9Cs2UNxbrf7F9UrU9j6nQldnz2m9eU1rUkq4rG0+Hurehk7S4qmq8+aZVHFjDjgS87F/
-      +PR58wush/0+7dg3pK3k5Ndd/pLGX3q87uUTJZqxTe0x7TH3GzZAUZj3OnSSfP8x6z67rG2u1xfJLx+o
-      lXdP+TaGCvD8QnM4eY+ab/w8o+aCLn4hOiThW2h9LmgOqp0NI1ok4VkuafMxLQFZEvqv6ijbpqYK1LyB
-      Xti9S0kZx2Vhc1dm1UPkesPRWwI4RvvZ8ZvisFfb+2SsaIgKi6uPj2G8rQQbjCh/Lad3N9MbtQ4neVxM
-      fieezAjjQT/hATIEB92UlXwg3ds/zx4WpF15TwDgSAgbO1hQ7/p9ejedT24TdWLsgnSTfBKzjr81LocZ
-      CTfEA2En5S0Yl0OMhDfsXQ4xcm9P4O60i+ArdUzMHWHAEFCE4rykxSEihsYRPy+ToXmMm8UCOUwvpWQ5
-      NYlYxSnxS+79sxWhOPz7JwL3b/H4aTmf8rK3yeJmeuboSdzKyCIG2nu//HEzepde9V2bVNsBpuWGIugQ
-      z9PU6bohijRjmL5Orkcb5HdtkrMfl8tBRsJeXBaEuAiLy1wOMFKyvQUBLspCSQsCXITsbTKAibQDlU05
-      NtLCw55wLDNqKs38FCIuMjQZx0RbWmggjoeySvoEGI75YqFeOE3Hl7wT4ViykmrRhGN5ysqsJs6FeKDj
-      5E95Ibjj5060gLDrroq3j7KwvmTj9431QNC5OxQMoaR622yxeJRfTW5mi2XycD+7W5LqNQQP+seXYRAO
-      ugl1H0z39q83o6de5FctjlbdnQDbQansjt+3Dcs6LcW2qncUzQmyXbTKridMy+V4/NLiqOl56afnJTE9
-      L730vOSk5yWcnpfk9Lz003O6/HJ/Q3mRpSc8y6GkezTTm/Rw4fr+brGcT2RhWiTr52z8ZvMwHbBTaikQ
-      DrjHZxQADXgJtRPEGmb5yWdaEpwI16J3OaMd4OuBoJN0kLfLucaiGr/pcU9AlmSVV3STolwb5XYeAcMx
-      XS6uJw/TZPHwh+zUkW6mj6JeQl52QdRJ+eEeCVtnyerXX1SnlDDFivGhCO17mvwILY9F4N7EWeAeznSp
-      kL1LQrcU47EIvEwyQ/PIjJtFZqEcIiLTQQymA+WVWp/ErLTXQyHWMN8vZ9dT+VVaXrMoyEbIAQYDmSh3
-      3oR61/2n/0rWK3FBWK9iII6HNillII5nR3PsXJ60YXtP2JYN7Zds3F8h/2Ojsmq+UasZBMXloKh39Raj
-      7mjbrp8hUE6BtSDbRTuwsyccS0nNnC1hW+QfLtarFUXTIb6nKKmaovQthJVcBuJ7BPlqhHM1UktN4g7x
-      Pc3PhuqRiO0R5DsugDsutVRNh/ge4r3qEMPzML1TX1JvEadF0S9vEsm6KkcPBgc0frzVIS/U/mrtjrqC
-      GsfBfb+uvkVG9XYY4iPUuzYG+2pS6+2TgFWmdf5ENmoKsO0PsjLWR9OQlT3qezm/Gv69T7sm35FdLYXZ
-      ZB7+F8+oSNS6ybdbplahvvc5Fc8fL6jKlvJtefrxYp3ukweq8AQCTvXARG+kWJGtPep725G4qgFkBbCr
-      NoeCXoFADj/STtZl1ZrqbinMRnrKB6CAN9tt6EW0pXxbWTGrkRPoO2UnlpOQHeb7RFOvU5FRuuMeCVoZ
-      6dhSoK1Ypw1DpzDEN/5JuIOBvpKfiGUoFUteMpZYOpaErbodzPc1VVG9jt/1yMEM3/LLdE5dfGZBkIvU
-      NloUZCNUNAYDmQjjeQsyXPushLuIo8WoAY/SvmzDDtHhuL9dq8v2d7jvf5FRCXPxDob6kvKwYzoV2nsf
-      pl+TyeLuXNXRo0cyFoS4KBPzHgg4X2UOychCTWE21iWeSNv61+WHfyazu8/35IS0yZCVer0+jdlZyQHg
-      tn/11mSCdeU2aVvlfyZrWeZW6fjnkS7nGr/LHtm2otlaxjFViTpcd3yrZEG2S83zq1X+17MHWQ/rhKZY
-      Adz272vZEaXsw2hBtoua5/2cru/1zRfazq4eCDkXk4f2haw/xj9pgGnYnjw8fiJskgqgsJebFEcSsE6v
-      I5LChEE3NyFOJGBV5/H9RjZqCrFdsWxXmE1+ffanfs2EWkAxBxSJl7B4qvJzQTAPzKPK2nygrKnP9ao8
-      rvwIw25uKs9D5Vi1kWSjghBXMnn8i+VTIOa8nt/ynBLEnPPpf/OcEgScxP4D3HM4/pXfzpgw5o4qA54B
-      j8LNrzaO+2OSKNAGqc+j2iFXgMaISaBQm6Q+57VLJzJgvWJbr0LWyHYK8WAR+QkfTvW4XDOYZ+bRZXc+
-      ouxGtWOuAI8RcxfmQ/UDq107ggEnq30z4ZCb086ZcMjNae9M2HaTJzuAeY52UM5p6mwStHILCoAjfkb2
-      dVnEzE4QuFVrP+Q2aT4N29nJgbRk7YfkZszAMN8Vz3eF+mIS1hGMiEE5YjgoQWPxm2JUAsZiZphAbom5
-      EcF7MI+rT+ZD9Qm3yfVpxM5O7XmwtqI2sz2F2agNrE2iVmLTapOoldio2mTImtxN/4dvVjRkJw5SkVnz
-      058j2m58nGp8HlfmBkaq1pfYpSM0VrW+EZVQoXY9ZrgKG/AoUckUbOdZQ1YHDXmv+N6roDc24Ue0/8DX
-      eH0ARBSMGdsXGDUuN74akcEGclfsjRq8R/P4+mo+pr6K6yuEx+fWd6LuxnywVuT1HeAxuv0Zrw+Bj9Kd
-      z1l9CXyc7nzO6lMMjNStz3l9C9dgRJHF+/wiefg0VatNRpstyrPRXmCxIM9FWepkIJ5HPbH+LuvMtNwk
-      66wevxgH470IemsHolUznqk71Y6w2aEH2s5Leav+uPl8kVC27vHAgDNZfJmcs8Wadu37VXahXtIkn8+O
-      4KCfc/47gtv+35LVodwUmaoxSFnNAhGnyn/5Nl/L8sJzmwI3BrXA/QaUt990caH/9CMF2VRtxjMeSczK
-      T07IAEWJizBkVycxx0VwDW4UyruuPeFa1Moedb445fU8n0StpDMRIRYzd6U82/DkJxz3v2RFtef7Oxzz
-      q3vBlbds2DwpN9O4n+B77IjOAIRcR0F8OAKtOfDpsJ2wThrBXX/X0tGsHeS6ugxLc3WQ6zrupnUqBJzd
-      z0eo3LjtPlvvEDUg8mKq/qF6l5gY4YiBPsHzCdt3fzu7/kYvOjYG+ggFxYRAF6VYWJRr++/HyS3z11oo
-      6qX+agNEneRfb5Kulb3/EYIH/dTUQHdBAj4mpwq+E1L3+dfJw4Mi6ZdtkJiVk9Yminq5Fxu6VnraGqRh
-      nd//JZN9Ol+2zZPeH30xu7+jJUbQMiYaIYkCjjGRKAkXkrixulSmJ5sBIk5q4pwwxEdOgp7rjfPJ3U3S
-      vUE01mYyjkn+JUvfSKIWcTyEmbDj9x2DfsWE5NAEZEle8+ZZhcjV7mnqQCHC8GlA48Qjbl9gMo4pe6Kl
-      oPy+ayjTVZEl26r+nhxKkW6zZHXYbjPKRnGDIifmNpdfpGyxblOOrR1Yl5tklzXPFS09HNYx69fSVViS
-      80Q5tn01/iC1E+A6RHbYVIxsb4KOU2QZLdEU4Dn490AE74Fo0uZA+60tYniuR+8aK79qcfriCGMZAzE8
-      5gMryn5RHmg7j0+nqEqTs4z/m5x/uPhFbcCgdrVP0pefFwQvQFv25GGxSB4m88lXWk8ZQFHv+NbXA1En
-      oQX2SduqXjTef1+Lczm8lX/9SfG6rG1e5eOftBy/7xiKvFQnDyXj33N2MNunN4uV9eCedF09BdkoJdGE
-      bBdxDsdAXM82PRQNtc7zSNtKnBUyENuzLdInUtJrwHEQi6lfNs394wlb/ANowEvNZB7supsPybpuEtp6
-      JAAFvBuybgNZdvtzukhCoOsHx/UDcmVkUQZYtum6qWp6wnccYMx/7PZknYIAF7ESOjKAqSR7SsBC/2HQ
-      r/pBtvzwLLKU0kZNNgb6ZBuayBaGWnXYrG3ORVLt0x8HUmY9QbYr4lxZBEf85GMwYNq2E7s2Xn9GJTC9
-      9esp29Ydfah7OnqhRXI/mT4ku6ctqX4KaIbiqb5bfLijZSiafioXGat1jIp08Q6RLvBIZVVm3AiKhc1t
-      F+4dcgMoGo7Jv0e+ZWS0i3eJ5t0p5onIIAy6WTUUfk6P/pRyzN8J8Bz6shm9fgeFvYz+uoPCXt03rasd
-      cbIHNeBRmiouRlOFIjTUE1pA2HG3+YVzSy0StHJuqEWC1ojbCQnQGKyb6eO2X/BHRCI0IhLM3r5Ae/uC
-      0UMXYA9d8PqzAuvPUtZ2Hb/vG5K9EOQ20AIBZ52+knWScU1/ZzTL306bf9hTTk7qCdtCO9mhJyBLRLcQ
-      FIAxOHfUQUEv8a72VG+jrDa21xarf9GOCOsJx0I5JOwEOA7yMWE25dhoB4UZiOW5uPiFoJDfdmly+p4Y
-      z0RM4yPiecgp00O26/JXiuTyV5emp82R8UzUtOkQz8PJgxaHGz8V1fq74Hpb2rPT7+UJslwfryj5XH7b
-      pcn38sR4JuK9PCKeh5w2PWS5Ls8vCBL5bZdOaCWlIyALOZUtDjQSU9vEQB851W3Qc3J+MfxrGb8U/JWc
-      OsLiPCMrzbz0mj18mSy+JIQW60QYlofJH9ML8jndDgb6CBOZNuXZTs+GduKJqDRRz6v2XM1Ud42sNUjD
-      SlqC5a6+av9N3dbapnrbcv64WCbL+z+md8n17Wx6t9STeoRRGG4IRlllT3mZ5EIc0nKdRQSzRSNi1tkm
-      2+0p53OOUAXjyr/n4vk9fqxjGhP1XX6u5wpHJtQQCB70E2oMmA7a1SyAqOvIMmBY4GjqvOzpPKa02YZg
-      FO4dMfCgX2XImACaD0Zg3vOeDtpVxs52EQFawYgYlKF9UBKMpXLfLmtSNZUVmb1c1WDciLLjW+Bokm3/
-      g5uvLQEcoz379jSbfUwCTjREBcfNfu6zOt9lZZO8nHOiWYLhGLKTslvFxtGSMbFeqn29jY+mNXA8bpbA
-      c4K55IhjNnk4ArNys2q1x8V03h4AS0oCBwN948dHFgS6CD/Vpgzb8vOVWiYyeueHE+A49geiQwG946+L
-      y8vz0Tu8tN92aZUn9mle0yxHyrN1T4P0s6auuiGaAYMR5fLDP//8qN7PUZsFtI//KYdbYjwYQe3DEhPB
-      4sEIhHdYbAqzJWmRp4LnbFnUXOTjX9wHUNTLTd3BlG0/TcT3GLnEQT/xLRyfBK2bi5xhlBRoo9TCDgb6
-      ZAXG0EkKs1E2WfNJ0JpfcIySAm3cvInnyzZT8X73iQXNpOUuLocbk+2eK5Uo6H3RaxZLhrYjPWt3cp5s
-      MUS2psw0YLwXQVYI54zMdcQgn3rVqNyktXrjpclKNS0m6HrIAkaTaXfIGH7N4cZkVVUFV6vhAXdCLoEe
-      H4hALzMWGzAf1s9pzXZr2rPrCoBRrZ84z9hnGlYF4uKeX9XV9Fato0Abr4QbJGxtKO+seiDoZJcPGw64
-      6TfMYj1zu6CS0dPrQc/ZpTon25oo4G2SdfOTrNQUaOO09ifON+qMwfrZPWlbk8nt7/dzyouKNgXZKEfe
-      2hRo2xw4ts0BtlETz8BAH2XfHwcDfZwbgd0HwryETYE2wfulAvulehJ2wzNK0HUul/PZp8flNFlMl+RU
-      dGDUva4OJVetWdxM2jsVhAfcyeotuZvdRIXoHCMi3X/6r+hI0jEiUvOziY4kHWgkcv1jkqiVXg9ZKOpt
-      34YkTOpjfDhCtfqXbEljYrSGcBTKQbIYj0Zg1xGB+oFc45okapUV3nnMPT3x4QhR99QwOFH0HkiTx7/o
-      Wd4iMSvxNhocZqTeRBPEnOSRkIO63tndZ0Z6HinIpkce+VOZNoeaobVwyE+9Ty0Dmcj3p4Mgl+5LVJt8
-      m2cbutSkXfv8lr5nqU9iVmpq9hxmJKeqAQLOr9Pll/sb3q83WNzMud4eBbzpZvMhqbOX6js1Kzgw7D5X
-      MxvU+T4Pht3qU45WcYCxfXlTHPImW5G1Jgy5iWPDjgFMm6zI1EuLjJ/eo5A3327pRgmBLsrm1A4G+Q70
-      1PN7oeqvrIKJlEjd15K9aLWVONlpwgG3yOo8Ldj2Fsf8vNlyiMciFKloaEufMR6LUMqLiInQ81gEZu/A
-      w2F/Mp/+ef/H9IYjP7KImVNFdBxu5AynfTzspw6ifTzsX9d5k695xcp1BCLRZ008OmAnPgtwWcSsV2/W
-      LHGLIt64imCwHtAbmdDHih6N2OMqmcE6pq8jqM+zYQMShfieAcQCZkaXHOyN79Jm/UxWaQqwcbrJcP+Y
-      MYQ9UpiNuBLAAgGnnoOIKGAOj0WIKAQOD0dgbuQXUCBx2oqKtPMtxiMR+LWRGKiNREQ5FsFyTNkYwYIQ
-      F/WRogVCzorRy1YQ4KJtceBggI+22YGDOb7Tjunkp5MWiVkjnoogjhGRqB06xIFGoo4PLRK1kseK2B7+
-      zof6kCtOFxRWBOOQKyEfD/oZk+eQAI3BLQKhEkDtGyBnGDififi7KsbcVRF3V8XQXRWxd1Vgd5U3L4zN
-      CbNmb5GZ29v7+z8eH1QtQ1717bKoWf7tKavpvUnQgEbp+iaMaSPEgUYSB3om8WjYvm5q1rUrDjZSTg9w
-      OcRIzccGBxufUyG7fXnNsR5Z2Ew57tPlYCO13PUY7BPPh2ZTvZYc6ZF1zHol8vRuOZ9NyT0ph8XM3yI6
-      U5hkTCxqdwqTjIlFXWaCSfBY1M6bjeJecgl1WNzM6lgBfDgCoxEGDXiUnG0PlQlq3WCjuFdk7MsVWRP0
-      Rt1NMXg3RfTdFMG7ObtbTud3k1vWDTVgyK0fl5ZN/UY3n9Cgl115uobBKKxq0zUMRmFVmK4BikJ9hHyE
-      INfxSTDvxpo0aKc//jU40MhpI5DWoU1n+sMZF4bcvDYHa23aRYnExzEWiVi5N/6EYl69zT+7RLuGwSis
-      Eu0asCgN82knJBiKwf4hDfrMU39FjQvoYkVhtqQqNjyjIiErp9GC2ypWzwPpc1RlVuQlozB3IOSkD/57
-      DPURjvPxyZCV+pTKhSE3qw/n995kbp9et+9XqzfyGlkn0SZtIAEcQ9ek6g8c/wlG3fS13g4Lm/PNT+4c
-      DWiAo9RZU+fZSxYZCtAMxKM/KwYNcJT2KQ+jgwDwToQHdaY9uY9woiAbtc47Qq6rPa727v6GU015tGt/
-      /MT75T0HG4kbKRgY6vvQbpHP1HY0bM9ZF5sj10q+8ycM9gleWgosLUVUWgo8LecP94spdccXk0OMjJ1I
-      XBYxk9+WNMGAk76GwaNDdhGnF2G/ftSw4epbOmyPuv6TIBCD3kZ4dMAekTjBlGnqg+BftaYRO70KOXGO
-      Ue34xHteaJGYlVgTGxxmpNbGJgg49csPadPUZOmJDFk541pIMBSDOq6FBEMxqBNukACOwV0g7+ODfvLC
-      T1gBxGlfTGEcOYYbgCjdlCArxxosZKZPJvYY5CO28B0DmE5Jz7p5Fg3YWRUfUudFvMfg47D/PMl2aV5w
-      3B0Ke3lZ6ggGnNwq0OEHInAqQIcPRaB3QHwc8Vv5U7Bi2IqhOJExMP/+sOJUej2KePlr9kEDFqWdD6F3
-      9CEBEoOznthhATOjiwX2rjgdK7hPRZ/XOFGYjTr5aoKoc7tnOrdQKyXiy7IYU5YFv6yJUFkTsaVADJcC
-      EVEKRLAUkFfVHyHERV5Vb4KAs6nok9sGBxgZa+F7zPPp9xv575FDAjwG+Y1Jh0XMzDe2fRzzk3u0Jw4x
-      MvqePYg4Y944RhyhSGpTgnWqNr27ob6xFPCEIrbrZe8Ou1VW8+OZFjwaOzPB7/c6n/K6xpBiOA69gwwp
-      huOwluYHPAMROR1zwDAQhfoOMMAjEXLexefYFdN7cScOMap29x0Kua8JxIsu4q7EibWY/U6ve48Q4CI/
-      dzhCsGvHce0AFzF3tQjgoeaqjnFNy/v5VJ9Ex3kC5NGonX5nLRT16naDvAkJwA9EeE7zMiqEEgzEONS1
-      OhdmTXwBBNeMi8fY9iBoCkelPxSFBIMxdAoQhwuoZSBaVeTrt6Th53BXE44nmqqOiqQF4Riy+VWPuoi7
-      YmGSUKzz2LJ1Ply2zqPz+PmIvB37Q4Z/R1+2oyo8SxOMl9V1FZFqLT8cQQ7z9s1zbJzWEo72k/62A2gY
-      iiIb2nadbVyok2Yg3l5WHXnTVSFRIS0TGpX8Up2Nol5yn8YkUev+UO8rofaqf5bdT+6FOxY0ml68Ixtf
-      wYxz4sMRYtpRMdyO6tex+bXMEQ/7I+pLMVhfGluiRMToDANR+LXXiQ9GiKmHxWA9LKJrRjGiZlTf2Rbp
-      U0S5aPlghK6URsToDMEoTb6LCaHwsJ+8SgnggxHaKedkvYqIcnKgkbr+nzpdaP2dGclyoJH+zuqKGUCh
-      oFfNbDPrwCOKe1mDvI5ErUVVfWcN4XsYdDNH7+jI3dgNnlMdmDju57aQA6PMdsgh7y3zyjs44Ob1HU4s
-      Zua+qQAJ0BjqtzEzt4njfr0eKyLAkR+IoId7m6ggrWIgTj/9GhWr1+Dx2PN7Bo3a202ZuHelo4N29hDe
-      FqAx2uovpmRbisE47FJuGtAojCfRLjzg5vUdngb7DUWVqraozc2cJLIFYAzeOBMbY+rhlGxBcxUwLaIm
-      z1AXFvmc3c71MOaOqc3FUG0uImtzMVibi/jaXIypzcX71OZibG0uompzMVCbm1uJ7tPmWTBjWI5AJN7Y
-      OTxujhlrhseZIqqtEwNtnYht68RwWyfi2zoxpq0T0W2dGNHWxY35h8b7MWPx8DhcxLTRItxGx47vh8f2
-      jD1kTdBxLuePC/Ip9j0F2jj1o0WCVvKagh5DffSFnQ6LmRnvGDosaqav8HFY1EyvtR0WNdPLscOCZupb
-      fycKs7HmrD3asf85YZz+coQAF/Ehyp/QDlvqj9R+eMe4pul89vlb8jCZT762pzIxHoRhksFYTboi7q+J
-      OAYinSfPFTEDw4pQHFX51YxCiElCsegZ0qVDdnJV7dFDdnrFDSsG4+yzrH6HWEfNQDxG5Q4rhuLQu/6w
-      YihOZG7GWhbrS5xHy5AgFIMxuQ/woQjk6tiBQ24128CXK3rIzngJE3EMRoqriU+KwTj5PjJKvh8RI0nF
-      OjqOkgzGiqvFTorBOLrpzjMRGeuoGYgXW5OJMTWZiK/JxJiaTH1J5c13iHXSDMXjDOAxyVAs8qN70DAY
-      hTzYgBWhOLrTyBro4honHvvds8A7Z/qjOtOvJDI2BvZxyK8Tj603ad9Ofv8IfkNOn5hA76b2GOgjN7M9
-      5vj06ir+ubA+DvoZM0km6DlVuPQ7cdqjx0DfOmXY1inoovdRDA40kvsiPQb6iH2OI4S4yH0LE4Sd9Gc5
-      gSc4cTvEDO0O033OaN4sErTSmxiDc43E7bX9nbXlX07LyslNrAsDbpYTcDHfR0bfQ2bs0APuzkN9j9l/
-      f1nXEPRJlR5zfPK/NsaJOKn8F+NkHdSCROMsUHJY10xNESAt9PxJemieKzlGf+M8ngMN4SiyOqHO34OG
-      cBTGPQUNUBTmG+/hN93bebOqmWwbzj04koj1U7alvl1lo5C33d8jWeWNaBiXbOGQn/1q7tBb9xF7ZwX3
-      zWo/7PYl4eZzm4ciNCuhLiEtnuj2noXMB+pWMifKt3EmrtCdw/QH1Vrs6TpF+bbE2JiW6jRZwKyXB+Xl
-      tiJ7TyRgPa470d9J6ywl2z3DUBTqwWWQYESMJCtfouMoyVAs8olxoGFMlPifdLQEoh375zG3yXAAkThv
-      z+BvE0a9Qzjw5iBn/xR435SI/VKC+6RE7I8S3Bcldj+U4X1Q+PufhPY94e53gu9zcto6cJNtdOt5EOlT
-      xpE7CiyO3jqNPqEM8EAE7onmT8HTzNWn/KQJpQi36xroufI7rqF+q165WWQl2dlxkJG+Rx66F+VTzJ40
-      T+G9aOL2uBza3zJqb8uBfS25e1ri+1mqbWzYmXYXyLU7frbd4fl2pyZ9knTzL5rzhDk+b96CPFcGGuAo
-      6n5y/Uc2YCYfiOXCA27y8ViQwI1Ba0i9FRSy3sg39KcsPQb6yE9Zeszx6ZdVju9J0DvePo76I9yol3/J
-      8NVSF6D4a07UIFamNH27WxN0nPu0Flmyratdsjpst8Ra0KNde7vvj56cp4kNEHYW2UtWHOenNhnH7ihC
-      cdTnjL4v4oAj6c+N3Zk4kVzHYCT6YlLEMRTpxyEt8m0um+G4aL0Hjqj2mKLPi7twwK2vQt9RdoReMRSH
-      tdgHtQxFO8hG/J1CWqpA3LZosEuW63AjkatKsI7k7AiO7AbOPYQRP3+Rtbc4sq94NxvPePBnkY61W9Gi
-      l06TpCboONv1cpyeu0UiVkbP3UYhbz9sSounii63+XCEl7Q4ZDEhtMCPwZoNxHfQERFzHCI4xyG4sxEC
-      n40Q7NkIEZiNYO6vj+6tH7Wf7cA+tlF79g/s18/dqx/fp5+8Rz+wPz9rb35kX/6+dG0OxIGwjaJeenvn
-      sK7ZuF3kwbsLh9zk4btHD9nJA3jQ4EXZ76ta7eB0msslxvB4JwJrxgeZ7zn+mdqVMTjX2J4WoQ56oBl7
-      zjXq5an0roLBOUbGKkxw/SXjjWbwPebj28fUzbcMDjd2u4WKRhbmJ67ektix0oZ3gqHJ4UbG8zYAD/uJ
-      z90APOwnnloI4J6feQafTXpWPUxTfTJeqrg45OdcMnzCm/EBL5MET3dzPmclRjCH8M9182Db/fKRs2q/
-      pzwbbw2pBXpOxnP5nsJsjGzgwSE3MRN4cMjNeUYPG9Ao5Izmsr05vciT36d30/nkNrmbfJ2OtbqcbZw9
-      SHg+XSwouhOEuJK7a5ZOcrYx3xO27DgBhmOVJ00meySrdJMcyle1irfJdrKzl9aj+xBBSTjWa12VT7IT
-      85QLwgB42AREXRfVSo4Uk/r8AzmOwQbN5xHm86D5IsJ8ETR/jDB/DJp/iTD/EjRfRpgvQ+Yrvvgq5P0n
-      3/vPkDf9yRenP0Pm1Z5vXu2D5ohrXgWveR1hXgfNm5xv3uRBc8Q1b4LXLCKuWYSu+edux69CFRx2n8e4
-      zwfcURd+PnTlcZc+dO0XUfaLAfvHKPvHAfsvUfZfBuyXUfbLsD0q2QdSPSrRB9I8KskHUjwqwQfS+9cY
-      969h928x7t/C7qsY91XY/c8YN9SD0IN12W1u94na5HW2bo4rfMmxQjIgtt5rIy6irwDiNHW6U8/fy4zs
-      71HA24046qw51CVZbdG4XTTp+IlXEA65qz1fXZm9u0ycX1w9rXcif0nkP5Lvo9djAGjQm2TlOvl5HqHv
-      DEiUTbZmuSWHGLP1SodcFdX4ZWW4AYsiP9+Jp+TnL7wQJ3zIfxXnv0L83zdbllhylvHi8lduPnTRoJee
-      DxEDEoWWDy0OMXLzIWLAonDyIYQP+a/i/FeIn5YPLc4yJuum1u0TYaWEg9m+59dkvVqrH1C/7RuK0iZ9
-      a1N/vDh+2t5bQdUDCi+OzJmMK+8oz9blRYbRIH0rz4jY2t3E2kQhZgOfBu3HJOfZDdq2lxU/t7ksZI7M
-      cagEiMXIdSYHGLlpgqdHRD6BeCQCM69AvBWhqwCf9e5lv5IOpIRp3B4lH3LLjv7by/inXBgPReg+Sp6r
-      uiQ830B4K0KZJ/JLjGxug5CTntFt0HCK8jzZVEm6Gb1zmYE4HtWEU1bMWxDgIuUpEwJcdUY6EtrlAKNI
-      X+g6BTmup0zmnLTI/842eoFUUyXNjiQGDV4UdXBKla8zWWUUclw+/qxMjAcibPOs2CT7hu4+kY41b7Jd
-      sq52K/kXeubyaMdeZ1v9kFoVNj1DokfSlHMSBzRYPFVtV2XGi9LBjltE3mExeIcPzZqZQy2yt66y7JDs
-      qo0stGrlrVotXlM2McN4I0JedbNeQnZDqKfEwrRt324S8VwdCj1jNP6ZPIDaXrW7n8xJalmnSrbuAtSf
-      0s2G9AvCJjuq+pCeRj3l29SKdfnfVF2HGb4ySdV2Q4eVLNClaEj5BGBt82aTvFb1+P2KTMYyrav9G1nV
-      Q5ZrIzsYnN9qcZYx+7mX952gagHLsc0bIQsc+UdanG1U733uqrJ5qnYZoQh5ZMiaiF1aFHx3y1sRntLm
-      OasvCc6OsCwySeq0fMrICWqDtlOondB0lU62OqjrrbMibfKXrHhTK/1J+RKgLfu/0nW1ygnCFrAcxXrH
-      KjMWZxszIZLmOS3NzDCnqEEBEoN6uxzSsu7yotALSWT3h9SZhtiAuZG9T8p5fqjAiVHmssglr/lm/Mbx
-      Lmcbq017OjQjf3gsaKbePYvzjLLyTVap7NZcsC8ZUoBxVNYkV5E+7Lm7ntmHtrjzw6AeLCI7yTwejUCt
-      /zwWNQs59s+aqACmwotTiOd8q47CZqaRxyMRIgME/LtDEdO4YwovDre/6bGgmVNfnDjPeDj/lX2tFuuY
-      ZVErP5B8mrAtMrFZNaTJeUY1tE9/IepaCHZdcVxXgItxF0zOM6o0JcoUAnoYHVcX9bzkAnhkPBMnh/i5
-      o5J5ptSvHqtuZ7V6yauDkL1OecP2lZA9DkKEQZcdudTzHKzxjMda5n31SrtrLWA5ajXu5403XNT3dm2O
-      /g5VbLK2Odsc1plMmjXJ2VOYTQ2g9kXK1Z5wxy/yvxlpa2C2r2tpyUKTA4zH9Nb/IHstGrLzLhe4WrFO
-      m4aW64+I7dFTmuTrMjHH17BHKB7rmUUjx0NrxtXaqOflCAHTj/rqp8z+jTorkVLp26DrpLfmPQS7rjiu
-      K8BFb80tzjNSW8sT45nId/TIuKaf7Fv6E72njB4u3Lu12kRy6gG0ZT9wJwUO+IzAgTtwOOCjhlfy9O2r
-      N39bqXfxhVA7C+7VkVbFVj+sGu1E+D7C+iJPJou78+TTbJkslkowVg6ggHd2t5z+Pp2TpR0HGO8//df0
-      ekkWtpjhW630UEXNcJaj1x/alG87rMVFssqoug4DfM32I0vYcaDximG7sk3qIbD6a0LYTdnlTKM+/418
-      L0zKt5HvhYUBPvK9sDnQeMWwmffiOZX/u9Cb/b2df/xwmVR7wh0B6ZBdZOPbG5g27GpxS6VXuqwLNS7M
-      SrUAaHSNifF9hI0q/NfX6lXvm+niej57WM7u78b6Ydqx8+rOTaju7D/8+sDVHknIen9/O53c0Z0tBxin
-      d49fp/PJcnpDlvYo4O22EZj97/RmORu/AwHG4xGYqWzRgH02uWSaTyRkpbWoG7RFPX1y93h7S9YpCHDR
-      WucN1jr3H1wvp+zSZcKA+0H+fTn5dEvPWScyZGVetMMDERbT/36c3l1Pk8ndN7LehEH3kqldIsblr+fM
-      lDiRkJVTISC1wPLbA8MlIcD1eDf7czpfsOsUh4ciLK9ZP77jQOPnK+7lnlDA++dsMeOXA4t27I/LLxJc
-      fpOV2uf7rpEmBYAEWIw/pt9mNzy7Rh3voake2qOX/hi/gtwnbeunyWJ2nVzf38nkmsj6g5QaHmy7r6fz
-      5ezz7Fq20g/3t7Pr2ZRkB3DHP79NbmaLZfJwT71yB7W9N1/2aZ3uBEV4ZGBTQlga53KOcTaX7d39/Bu9
-      cDio61083E6+Lad/LWnOE+b5usQl6joKs5G2lAJQx7uY8IqUBQac5BvvwiH3+E28IdY3H1ZFvmYkxJHz
-      jMSzEm0KszGS1CBRKzkxe9B3Lma/U20S8TyMaugI2a7pNeOqTpDrelARsoZwNoPLeUZWITQ53EjNLy4b
-      MNPyjIO6XkZhOUGIi/7T0ZLSf0T90Vg5md7MHibz5TdqhW5yjvGv5fTuZnqjek/J42LyO83r0bads6fh
-      Bt3T0P1kwVU6fZfZYvEoCWb769O2/W66XFxPHqbJ4uGPyTXFbJO4dcaVzhzn/XImO5DTzyTfEbJd98sv
-      0zn1tp8g2/Xwx/Vi/A5SPQFZqMW7p0AbrWCfIN/1G9XzG+Dg/Ljf4N92xW8MADzspyfiVaBV0J+riZ0/
-      da2kxpxkvY0P+lkp5CuG4zBSyjNAUVjXj1wx5xq9q1Jj12/kW3eiINt/P05uecYj6Vjn93990wPuNmV1
-      W7ggPvJAJVCs9mro+pZzjOSOE9Rr4nWZsP4Sq7OE9JR4vWOsbxxRGYbqQXYVGKj9OANSZDQ654705/hI
-      fx4z0p+HR/rziJH+PDjSnzNH+nN0pG9+wkkGkw2Y6YlgoJ43eVgsEjmQmHxdELUGCVjJddEcmfGYs2c8
-      5oEZjzl3xmOOz3g8LmRPV3edKcKesm1qd3mKR33fNyST29/v51RPS2G2BU+3gHzL5Xz26XE5pSuPJGR9
-      /Ivue/wLMOlWnKM7gpBT9groPglBrvktXTW/hU3kfrUFIk5imTU5xEgrrwYG+FgdPJsMWRd8LVRaqGPv
-      E4S4kundcv6NZWxRwEuv+A0M8BHOyDIZ2MTL4UcQcXJyeMchRkYObzHQ9+f9H7SFRSYHGInT50cGMP05
-      oddekgFMnHsApz8j7a10F2mi94DZZeNfkrAg26WP8k729CcNANubs3Xy++fuRWbCiS0OBvs2q4Ljkxjs
-      22ZFtusOS39rxh+wHHKEIu0OBT+EhENu8aPmuyUccjdVbPocDXCUp7o67BP553z8mZMYH4pA2bkBpkN2
-      ve3ToR6/l1lAAcdRV5Ds60y9LskJYvJwBGYORfOmWvqrdk1gSjUbMjfrZ75awrg7IpkNPODXI+e4n2A6
-      vEiyMDTq1Mx1tcnUm3xFWqv9aKiFGNN48US+2xf6WNnkZ7KuqnqTl2lDvfOIBYsWWYMjlnA0Zm0IOrBI
-      ETUiYAhHeWLWW7AkHItRA3t8OIJ4j18jhn6N3huE+UtaFjWLJFU1tbpzzRszguUIRKrKmLQyBFiMfZWX
-      jd6VjRei58MR+Pmq58MRVJaQpTbuxoCqYFyRZD8OaRERrjNYUdKt+q9u16+0JMcAeShC+9Y33dxykFEm
-      3DEsXWvAtps6rDIZy7TKn8qDrt91RU/wOSRibVtglrZFLW9EYx1soVXX59Bkyevd5DPFaWCWr200acPJ
-      EwOYqPndoAAbq/sR7HO0H5bZE1koGcgk62m1iW6yS8V3utOkATu5kJsY5Dus6LLDCjCpbpbO/2TfiUSs
-      rLsN9vpUz8ksSLJiIetRx2Akcn2CS+xYuh9VZq8U9ZGxTM+peFYpp/sZyf7j1S/Jz53a7ze9PL9IhHg9
-      JJs63TYffiOEGi8Fr6UbB7kc/zrCQusamJMA6Nj/1IjLy2ibSYLVhwfc5AEvprDi7L9nb9T2+8TYJt1D
-      09XyoVRpVWdCZJR2BzEAUfTOXdTy56JBL3XuBeSHItDuJywIx6DndkwxEEfPp0SF0YYxUeITDp39OY4y
-      iK2yiYG+5lgA+9pfMPyQBojHaGVt0Ha295+RKhZoOdVua5XuHuneEbkog7wVobvTtI5vD0Eu3YmlHg+A
-      4JCf1Rn2WNRM3wwQFUAx8vLlQ1QMRwDGEKRzMTwQcto7sNLVNg9FoA1GeghytXv/0XUtBxnJxdriQCNp
-      ENJDkItRlTkkYo255cjumMgXVMbm1xqoyo7bzouJdNtNXVECuaxtbufD4gt5yBOI+C5JOc5oXkX79Obv
-      i8tfk/Tl58VpD0bCCAVVIHGoO+yCMOImVUE2hxhl/yPuik1BIIbaKzAqxlGAxGg7PqRuAkQP2cnjw4Ak
-      GGtTyb5tTJxWgMQ45uFLVoATPWD/LcqOla+onATkos3F5eX5PxkT4C7oO+mDchfsnWojsSc9WSJrobE+
-      C4Jcemsyuk1jkE+dI0nXKQqyCSGyj3SdxhyfvN6GnHJHCHLRU67HIB855U4UZKOnXI/ZPj1rRky4IwOY
-      yMnWU4CNmmgnCHCRk6ynelt+kUbs6QfTjp23px2AAl7i7m0uBxhpO645GOCj7UjjYKZvzd0dEUABLzkl
-      12hKbqJy1GYgR2346bAJpcOGuUukT0JW2i6RLgcYOSVqEypRm6hdIjEej8BMZWSXyNPn5F0ifRKyUkvH
-      JlQ6qLtEWhDgotZZG6zO2vB3iQRhwE3eJdInQ1bmRaO7RJ6+wdklEoRB95KpXSJG8i6RPglZORUCUgtQ
-      dom0IMDF3CUS46EItF0iXQ40UneJBFDAy9olEqYde8wukagAi0HaJRJAbS97P0cQtt0R+zkiuOPn7ecI
-      oLaXup+jycAmyntXLucYefs5AqjrJe/n6GCej7iflE1hNtK7nQDqeDm7PHhgwEm+8fguD/7H41/Bg1jf
-      TN3lweU8I/ElV5vCbIwkBXc3cD4jJya0u8HxI8KrnwbieRjVkL+fo/ozeT9HC3Jd9P0cXc4zsgohvJ+j
-      +wk1v+D7OXqf0vIMup9j+yGjsAD7OVp/pv90tKRw9nN0OcfI2M/R5Rwjez9HmLbtnP0cXQ43LrhKp+/C
-      388Rpm07bz9Hn8StM670/2/tXHrctqEwuu8/6a6jSZCui24CBCigKbolZJm2BduSItLOTH59SVm2dMlL
-      Wd9VdoMRz6FepPjy5dfAicZzJBB1wfEcCURdWDzHkeAsaPHm4jlO/o8VbCae4/3fX1DPF8Yhubgv/LVN
-      IiZ+rXeNxMwonueD39DYMJvLyit5ehXrruDp2dfVdu0VDIrn+ay7kpuByUUWazOBP/WL7tZcrM1UIsHd
-      mom1OaYRnX/ijCXnGJ0VHGuTUpwNjbUZk4F1bazNWQmXFxZrM+QCI9yo5Vq0suZsqi0rasgmWrGynkuq
-      37Kiap+r1cUV+kxdLhksSIwU5NJRmDw9CpOvGYXJ50dh8hWjMPnsKEwuHIXJk6Mw0libHDtjxm8CG2tz
-      OCiItRmTjBWui/LEaFQuHo3KZ0ajculoVJ4ejcJjbVKK2pBYm/f0sQGLtUmplO1NpnvjfGiszZjkrMuD
-      Y04ZxoTG2oxAzgnE2iQQ58q/4ar8G2+C29WJWJvkEFhm+Vib5AhWXtlYm+SA3RiR0HGMUdRkTEXvjI+9
-      ybVc+UNHWpjoneTfWPROBmW8+KeEjd75OABE75wyvElWZuLoneSQpMxE0TvJEUGZCaN3Tg5A0TtDjjGC
-      kyVx9M7Hf4HonVOGMUmeAX//Bfeeve+SeiqqozotrvgClPf6t0boHVDeK3QGvsZPDOGNfoJNfUa+CtLM
-      rYKMDipwsVpCwOQBryk0yTWFZs26PTO/bs/K1hja1BrDq3z97nVu/e5VOHd1Tc5dXaVzV9fU3NXxr6ar
-      6r1L7Tozb987+++PxXUdx86bv+l6jdzhE/8/ra79YV2Ypn6zPvXfhS0WZ5DgUzn8V5wuy399y7HzZuTe
-      8PjoP+mrPvW/k6ub7eKfwFEqtLk/JboHNvEd1Faf9PJIYQ+AOpri5E632yOaO0NMu04j5+KTE76qDRDI
-      8QEQBxDl6Jaa0pezqqxevmhlyhBTp11J0FfkftwR1qOOy7+uAUZ8xnb+l2mAaiBGy3n7SW1OTXlUW1fO
-      /U9i9eJIGxw7NX8ejhbmLLLz/JhDc9uYFG2vBNjoa4+lecn88+8KWzW1UUVZ6tYWwE9m5xxRTv7nmPvl
-      VRylIlu70UrXZffRYmE7Ezj1f1GbS73F7sOdCU1t0RmtDroA3oaYpNY/+/Pf6v78ESkBJ87zxjZHXSv9
-      3r6499DV2IutMZrylqdK17Z/onh4lwWqVL7u9fHvJ1QRpQ3pXKxyX4amU+5UrGtKSLMKNKn8KmMuuvsl
-      d5NVpfLt3Psoy8aTKaup9rXM6smU9VKveJcHmHdn8lKSqVnvLyslGVJKstWlJFtQSrJfU0qypaUk+3Wl
-      JENKSSYuJdlMKcnEpSSbKSXZmlKSMaWkcS2ND1UW5UHf2v5boE/G0yk70GqPwITTaCtSOi5tVOeibZGX
-      PcFHOfQNRcFteHC8EeiKBFjk8x2/Psoz7pyivFdw5Q+ON56RcIoRSJwfKv+O7IQyQUaPD+7n67mjK2h9
-      VKrNZbfTfqTCNV99M3txsX1umuQq2SOq4/eI6sZ9nm6RJoHvC8dSs/uz8EE3wLYwg/Le9rZkRFl3+4y7
-      e2dJDpGEz8vX0aorfkiyuLMp808ts/7U1AhH4yEQcf1UL39kn9S+sAfdfe7jggFShubsPqqWzHwnOWvt
-      nmHW6a1QTXDO745lPpHQT3DOb8rCWvlNJzjr/95J1QM5Wk1WieYmQo4xSuYmWHjiPhQv4iEmFiZuH35r
-      hZ3Did9HC1/h5/CJ3/1b6xbax2XKBCZk/PgBMA7V2g72eIi6Li0iubSE3gHt7yE55YGG0JCc8Nj49QOg
-      DqNM01mNXMiDISagqXhLHdKqvpxOmKJHqGf5fg+31IRuG+R9cKlDGn2md4T1uL6aQOUoarssH34fkhMe
-      6FvdUod03xvYXeoS0zww6jtUO+h8fHpqaKAy45MT/urn7QBBn54YkAjQQ/KRt/4R933s5bu5TJnRdL1/
-      FPEZdAalXskMesiljW9S5VvaCRQ2Bp14X1XhW87V4hp1JKjlZBHDyRJ6Uza1Afg+PTGUrmuLGPr01NCd
-      fHTiLbC5FKUiG1C7j0Rk6fr5d1B0g0LXFrPQJ+waJa695f4NSB4MMel3q44XQHMDiMN9O8xBGwue0BQj
-      vmrbAhqXmtL1rkFwlzzgD9XGx+KsP6DTmGDE5wvoxRR75E1+MMRUF2e//UVtbFf4LfoAYYhSr1FV8Vmd
-      KoPUGxMqsJVA2/IBEEdTmtbPLbs3BHkGUyz21U0/toT6Boz42rICNC41pYfhXtGTjGHOPQwgC8R3klgN
-      WKhMVKoM/GUz0ZetabudYDIu5Fjjqmm4Zx42R8kEXAJn/aumwp552ByRSbAAY33I9FeAsT5w4ismJ9a2
-      0EaVm/K+qmSxNAQjp+1es8dalX50xYByxhDmAo6fEyh0ie5A4up9723IBioXHMy573dF5J7Ao/tdGAr/
-      PRkJfziy18jWDATiXL7s9kUX3URkRsHl0760L36fkTbDMxjZWfPrCvMra37td3X006+CGz6lOftt7xUf
-      Kx53j+y8GdqyLyl4koc5+7W04LZ6z01srsv3USIQ57IN9OmLwMgJT4q9J3eoGI6YEtzdKuQmRv/Ll221
-      9x2rfpawOO2brrKHxf3ftIHP5aq7avcBrcpM4IG/7fymLP2MojEKi9GXFAR59FPO9r2vGwxmpyjj9Zn6
-      msG+w94RpV4/3tLXwO7gQUPeAI28t9Unrnuva1MBQ0AJPPK7POEtzRg08p6a5mhcN/So1db1SX1PF9Qz
-      hiiXWwcaqPYo9vtv/wM/DBrFrZQEAA==
+      H4sICAAAAAAC/2JvcmluZ3NzbF9wcmVmaXhfc3ltYm9scy5oAKydXXPbuJZo3+dXuO683Kk6NRM77bT7
+      vim20tG0Y/tISk9nXliURNk8oUiFoOy4f/0FQErEx94g94arTs10LK21KQDEF0Hgv/7r7DErszptss3Z
+      6vX0j2RV1Xn5KESR7Otsm/9MnrJ0k9X/KZ7OqvLso/50sbg9W1e7Xd78v7MPV1fb9eV6e/nLxdXVh6sP
+      v/62uUiz83e/XqzTzdX5u8vLXy8v3n24+rd/+6//Oruu9q91/vjUnP3f9X+cXbw7v/rH2e9V9VhkZ7Ny
+      /Z/yK+pbD1m9y4XIZbymOjuI7B8y2v71H2e7apNv5f9Py81/VfXZJhdNna8OTXbWPOXiTFTb5iWts7Ot
+      /DAtX5Vrf6j3lcjOXvJG/oBa///q0Jxts+xMIk9ZnalfX6elTIh/nO3r6jnfyCRpntJG/p/sLF1Vz5ky
+      rU/XXlZNvs7UVbRx9/31Hj/a77O0PsvLs7QoFJln4vjrlp+nZ4v7T8v/mcynZ7PF2cP8/s/ZzfTm7P9M
+      FvLf/+dscnejvzT5uvx8Pz+7mS2ubyezL4uzye3tmaTmk7vlbLpQrv+ZLT+fzae/T+YSuZeU9PXuu+vb
+      rzezu981OPvycDuTUXrB2f0n5fgynV9/ln+ZfJzdzpbfdPhPs+XddLH4T+k4u7s/m/45vVueLT4rj3Fl
+      H6dnt7PJx9vp2Sf5r8ndN6VbPEyvZ5Pbf8jrnk+vl/+QiuN/yS9d398tpv/8KnXyO2c3ky+T39WFaPr4
+      T/3DPk+Wi3sZdy5/3uLr7VL9jE/z+y9nt/cLdeVnXxdTGWOynChapqG85MU/JDeVFzhX1z2R/7tezu7v
+      lE8CMvRyPlHXcTf9/Xb2+/TueqrYew0s7+fyu18XHfOPs8l8tlBB778uFX2vnLoI39/dTfV32tRX6SGv
+      RV/FdC4T4stEiz/ZufGfuvx/vJ9Lp7x9ksnNTfIwn36a/XW2T0WTibPmpTqTRa9s8m2e1UIWHln4qzKT
+      mdCoIiYL9U6oPyhR3qi7VZW4anu2S9d1dZb93KelLoTyf3kjztL68bCTPnG2yiSc6UDy7v3Pf/v3jbyz
+      ywy8nP+b/uNs9R/gR8lM/vR5+4Wgw/ziWXr27/9+lqj/s/q3nprdJ9tE1jLwNfR/bP/wjx74D8shsoZq
+      6ZDec7O8XSTrIpdJlewyWT1sxup80rEydKBHZPVzVnN0FulYVV2YrA7brSxuHDfA2xGez5MLfsr6NGBn
+      alEfO6V92rPHpEQ4HR5lmW7yXaZaNprXID3rk2zhiowptmHPzUoE5NfH5Fk4x1RdkZd5k6fF8Zckm0NX
+      81ID4ao+7nQ+T4oq3STKoHo3sis2NhDE9ub7h+md+kBdA6XKdLne+DD9ktRZF28huwuqTRxphVjAvMqr
+      KLvD2xFeatmKcvUeDLkjLh8U9DHUH69nD7Lnkmwysa7zPaVIwjRoV/VDepD1fJlvGHoTR/0r1VvhuRWK
+      etf5XvbvI668F6AxNvljJpqIGL0AjcF2B5zffyZlusuY4o4O2tlX3cKoe5f+TGSVLXjl3THgUfIyNkpv
+      QKNEZEEw/ff1NiIDOjpgr5pqXRVJRISTAY1Sb9cx6XPEUf9zWhy4cs3i5qhyEyozuUhS2a4xzB2JWVdF
+      tf7e1Xc8u2kAo4hG9gjTesPNVIt3Itx/eUjSzSZZV7t9nempGGJ3cEADxNvWWQZ8U5AjYiIgpiwf7+jp
+      Z5Gw9U1+COJBIuYbVoB8g/i4yQKlyvIvVQ7eJeunVNbi66xuSGYfB/3ncf7zIb/+xMqRtHhkBAI9SMR2
+      mHo9YYU5wrA7+9nUaVySeQ44kmh/JidAh/re9VMm68d9nT+rWfbv2SvV7gmAGG1/Vf62x7o67MkRbBzw
+      F1laG6knyBFcARbDzSdmJE+DxdtVm4wXQpGYtdLjKua1d7Dvzsp0VWRJtRZ71SjuCznQp4aAHGgkkT+W
+      WVcLqKkLCez2ghkSlqGxm0Ko/CvLjNzdxCR+rG1xEE/HW5f8w2wasMv2neyUjG/SjbhKuXybr2UtQLW6
+      PBZB3S88tyJDVt7N7PJIhH1apzuWW5OYta1xGTW2g4P+9kYQjXo+Q9cbNGI/lfpkvWIFMAVIDN1sCJa9
+      RRHvsTuQFLloWHrLAEeRf0oPhRySpkK8cFPJk4yMlRxEVm/SJn2ToCcbHD37mXBDdSjqLbMX2W3YZD+Z
+      8hOPRYjsDYASOFZebqtknRbFKl1/58SxBHAMWRkU1WNUFEcBx1ETXbqG4N5AlgCPoadzWNMemASJJbMu
+      PpYrQWIxeoRHDjYye4MGCnt/HHL1SPvp0GyqF1aS2AY4in6ekj5RZ588GrZ3vSdZnuUwh532vgWORnyi
+      CaCItxCylpHfWX9vb1FWZvsWOJosvvn2NaoWcRTBOJts3zxFBNF8MAI32w3c9+snot03imqdsu5BUOLH
+      KjM5sml2+2S+IE+AmCxkfqELX3xPne2q54w7wWHTvl19kKTrtcxpqtpAg97ksao2EXLNhyPUWZk9Vk3O
+      GGAhGiReW01tD0XBitPjmH+VPOX0zpLJYuZKDgrWvEzu2LCZn82mYCBGbEYDHiSiHozo7BL537xgtiIQ
+      R39xxY7R4gG/6qtH+Fs84O8qmYgQJwMShX1TBO4ItQA441lbFPGWh92K+EjORhGviC+RYkyJFHElUgyV
+      SBFXIsVQiRTRJVKMKJFdr5JXfo4w5G7edQs0k31VMZoZm0cisOYLRWC+sP3sOHkjeOoTjviPfV/2/Bts
+      AaOds9PoPJBG8rND/cypdU5o0MuaNnB5JEK2fjquvZTN6DZ/5AeDVUhc1hxxTyJWkT+mxSMvIzo2bOan
+      jilAYsQ9YwEUSJy3uOPOR95xiRzSVi/JofxeVi/qgfW+m/XhZBIuw2JHRhvjF1mhOp+cVsk1wFHap/4s
+      fYcGvNz8H8x3/Xnk1AjmQSLqKeW03HCe6nsCNAb/OY4Yfo4j+tWuzJrGxBF/1PMcMeJ5jvGdmMJrGZAo
+      h7pWX1J9L24YW4HFkUV915VDXhRDAMeIfgImxj0BE2/6BEwQn4CZ3+9u633aPImYuKYHiVgJXZPLelZP
+      TPPS1pXAsbK0Ll71c7pu3QOnKQcsSDTe00QRepqoPtymhcjUmpS6a3azTdK9tKtbLU7AISd8JY91lkos
+      Ii1tAxwl6nmjGH7eKOKfN4oxzxtF7PNGMfy8UbzF80Yx7nnj8Wsik+3ytk4f1au03FiWBIkV+2xTjHu2
+      KZjPNgX6bFN/IuKKl8kPR0jS+jE2inLAkUr19K1Nxag+NuQZiiiSdPOsFmiJbBMd1pHBsfUSwDoT+6oU
+      rEJhCZAYvCffIvTkW+jXSE6LYTnL/VELEk18P/UNI4o6oMHjHec1IuM5GiRet1UGJ0aLwt4fh3wdkT0G
+      jvoj1j+IEesfRNT6BzGw/qH9vFFjwKqUfS/xlF5cfkiqrTkSEbyoQ1bsarqerextyjv7sMt40V0LHO1Y
+      OfbrUpk1HyjCYsauNxEj15uY31OD76psZAUdE623hKOpG3/zlHFXuwRUSFxoZTe7K4jb8Oh5+aheTalq
+      2bff6f2LBDc0oELi1s1eNbfbvMh40UwBEqOp83X0BI1vgaN1C4/U64IR1bZvwaKxS2ewNNoz0jGjONiE
+      RlXdr7a9VS+WcbuqoGhszJjuAm4LR2/S5iBif+1JMiYWr5FwHcFI/Rq8uGiWZ2RE8SbxRDDaQU2LyPon
+      ItRRgcSRdfbmiaXXZMgaV8xtBR4nW/OvX7G4uRYpVyzRoDc6aUwHEqk+8JohDcJO/jR3aH6764W+QccA
+      NgWjslbNisFVswc15N5SvS0F2OQ9/NCOgv+gP8Ky6SF7MlncnceF0IrBOKo/FRlHKeA488UkLsEswYgY
+      7GTzLWOicRPPt8DRIl5idPBBPzvlXMdwpPZBLjftYNNw1LeIh0dSQ792W8rmNXnK6XPgoMSONb3+nCym
+      8z+n8+T6/u7T7PfkdrZYqvfpKcFwy6ho1Nd0A5pR8YhL+nHLqGj0BiMosmN225Mlaovc04O1/kEiJeqA
+      Co5rPLNcp3s1POOE9C1wNGpBMTnMWO2S1WtDm0Dwadjevj1N3toHwAN+3tQWogjEYT+uwC2BaPssIs0U
+      POA262ARFcgyDUVt54Lj4rWOQKS3mQ4cqQxcRzsWZsdscdTPWQcB4EE/6+1qzIFHoi39tEnculO7W9fU
+      pXGwAY9y2lCO8fA85MEjdlMsRb7N9AouatdoyBWKvMv4kXZZ2EyciwVw3B+ZOcE8eUpFbOXmKPA4/Cql
+      p2F7LtpHZdw+jMnDEYjdTgODfXpNNq/q6NCgN6ZX4SjQODF1uBiqw8Ub1U5idO3UP33hxgmVUBFRA4lg
+      DSTiaiAxVAMJOZYoNslKva9WPhaZGpmyAgEeOGJT8Xv1RzZsTrZVHZHZgAaORx8+2qRtpb8iDr0ZHrFD
+      Y3B3xoidGYO7MqrtAdP9vsjb/QNUgW0o+7uHHH4k1k6MgV0Y1Udqlqh7AeOw+le2boQqQbIXTnvQMKBy
+      4hbqS2qb8m5Pe1IkFx5wJ0UVGUAboCh6lN5N6qsmumjocXwHFKl53WfstDLgATczrVyDHaVdSfOUkxLn
+      BDkutcCp3UyRZOsxxxezg+fA7p30qwSuL2Z3zoGdOXm7ZGI7ZLJ3xwzsjMnYkgLciWJ9aJqnujo8Pukd
+      b4uM9oQCwG3/JiuyR3XqWrKuMz0lnhaqB0HqQaMSJ1alj2GRw5nvpB9hco5RNueMF7gMzPa1c66nNdnr
+      5qfapy3T51ipMR8lyJALiqxne9vOBS0HABz1q7dAVFtNrpIxhxMpcj/Y4b1g32wfWMIesNH7v47Y+zWr
+      a9nvZR6g4sGO++e+qvUSHNXS7eTNWsublBQANNhRqM8i/GcQp4Mf1eIkvYk/xefTrr15Z75sTLvJfBqw
+      m48xVedCkCN4BigKr1kN71zbbsrfvyZy2kaInkqgBYjGfn4y9NyEtwMvtvtu/5whdsQUNmFRuc9lxjyP
+      6b/TNePdjvrtmiJmOFCFxXXXMTFjehogXvfmSZ39OMhqXlb6xP1cUAkYK2aZPaKA4rzJky3SE61HvZUH
+      fdc+k/OMSbdEgyg8Yr6PuarHQQFvu2R99Uo/tAfAUT8jB/HV9MydsdFdseN2xB7aDdv4vJY9/2rHlLcw
+      4O42O6AvQ/DpgL0/ooQdolfgcfqjdplRTgIwxnNG7OqaHGakHo9jk771uAcCY8YewH2/N/ahRvAEQAzV
+      hSd7FQS46M+Q0Of/xgfJX5fvfksWy/v5VK+myzc/mSEAExiVtdogvMqg2359JxJx2KtBDV1twL57S75b
+      tsB9Iv+Ri6eM7uo438je22FgH3n98TO5XZGI7zkN3JIiI99jFuy72ftBDOw9H73v/Ig956P3mx+x1zxn
+      n3l4j/l2Z9XjuC9pqu9ZmazkraimDjijsgGbH50xm4vubK9X4hwHUfStEwE84Gd2WF0eicCtVCwYcx+K
+      IjaJHAcSSb+D38jOndBTUroICFY80IREVYOjtDnUWT/EZMUEPFDEtnjzeqg2DdhZhwjZJGA1ltWTvQYb
+      NpOXtoECPwZ/34ahMyv0JtCrvKI6FQOYWDs/hE69OH0m1IxGuc5Y4iMMuOkdohrqEYlsre6afn9zPXXG
+      68KFXFDkdr7XejueHhKQQLHa2SXWuNeCUbd6pZJx79s0ZueM7HoyZNWz4Xy1xiE/a4SOzmKJp7RWc2i8
+      yRabRu2MHX59GrLzaj+83gMau+6MeXIM1DQuqhocsApQwDUuMuuOQDxARO6OH4/h3T6MleDpY5aI77SV
+      ugAO+NmPU30ath/K/Ad9irYnQauxY8PpERQjBKQZiscpwb7BjxKxRfHgyU0xpzaFT2yKOK0peFKT8SF9
+      cZwHg25Om4OO2l8YvcsXsHf5Qu+rvUB9tRdZZWXsDqVN23b1zkLsU1jMYUfKS+ZboxboOY3tX4lSg/Ss
+      cmxO1SnE8YhkI2sLkqdFPI+Ss6YbXNYztz06orKFfBfQzKrNRvaCmggBkxfVnsHiLbMIaOx4qq9y2G+I
+      c0o9ZduKfFWn9Su5uJmcY1SH2fUPA6kjKwAH/O3qqHa5miDrLdq279LHfH2abzltUNeQyicqcWOprXvT
+      IqlkUaZOAHiw7eaeFYifE0h8s8t7o6s87OzhOSnffNq277OM1MlR33cNOrtoEo04nrpaq3OT9FTkvhIN
+      b5FsQAPHk5X2+Xv9iOxY4Ogv7gy5vMjP+SZrL5Hapnqw7W63ZZVl/PSrk22RPz411OdIQREQU899Fdlz
+      VpCj9CjgbbtAPLHB2uaaWGnUXj3BPKQQPZPQ+IBzRwG469eLtIzcVLO/ghYDVLhxhPuQ/1/E9f+Iwo7T
+      bSrbr6+kRPBg1622hZeRi/blGJraZl2zWiuc/521W5nkRd7ktMkK2IBFichtVOLGauu5OqO+LGGTrpVz
+      fh12dl3EuXXBM+v0h9QHGicIcEWdxDXm3Dv9nRfOFb9AV3zOyqNzJI845+ahZ+bFnJcXPitPfwq96UMO
+      AUmAWOR1Ati5eNwz8fDz8KLOwhs4By/yDLzB8+/iz74bc+6d4K3nFdh6Xn1KXHuStZrHpF6vxQJm3gl5
+      wdPx1If0GieB6hvO8WHouXdRZ8QNnA8XcW5b8My2uPPahs5q0593h2ezCpcFA27uqWkDJ6bFn7I15oQt
+      /Z325TV1tGl7iBQ5iCuAYmyrep3pSTM9+yTSR0YcQALEoq+ORXdWEeQVnwJY8an+FtVrbYb6qxHrPwfO
+      9VIf/2vz/fw8eanq72ldHUpyeri8H4G9enPgJK/oU7xGnOAVfXrXiJO7ok/tGnFiF+e0LvikrphTusIn
+      dMWezjV8Mpf+RnMgS5uD72G/ADlw1hXznCv0jKv4863GnG31BudajTrT6g3Osxp1lhXzHCv0DKvTAVTm
+      5rD0dwsDGiQeL7vRs7JOH8Ys4kUlSCy187MaeK7lqEXWR/sqL3mpBonAmMwVVUNngPHP/wqd/dV+1k+n
+      cup5l4civOXJYpxTxQR9RaqAVqQK3tpBga0djD+Za8ypXPo7T9nG6C3K721zchMJSqBYvPKPl/y3ed2Z
+      cqbXG53nNfosr6hzvAbO8GpP3mKMcZGxbdxZYGPOAXub07PGnpxlHCX0pB6iUtduQjwaIWYNoRi7hlBE
+      ryEUI9YQRp7iNHiCE+/0JuzkpshTmwZPbOKe1oSf1MQ8pQk9oSn2dKbhk5n0N/xX9ciVGeQAIlHPf0LO
+      fuKd+4Sd+fQ25z2NPesp5pyn8BlPImY9rAivhxX0VacCWnXK6mnAvQxy+wi0jepPjD3WTA43kje79GDb
+      3VTqwT1/tRXE2xH4Z3qFzvOKPMtr8ByvyDO8Bs/vijq7a+Dcrvgzu8ac1xV/VteYc7oizugKns8VezbX
+      8LlcsadjDZ+MFX0q1ogTsdRKleQpK4pKDbfr1+OaKGIY0GFHYsxbgzPVLyktEdT3HYNaREdSKMByPF+8
+      P05EkCfQPNYzs5SIq5vFZCkttjcvbxe8H++BtpMugyysH+yBtlOdD5asDtutLJAMM4Bb/ufz5Jydoj7s
+      u3lSzMZNYR923RcxqXARToULphSzRaTCRTgVItIgmAIcIWyK+O3IL99c5IlxmsNYp4OhPsp6HQDtvfnF
+      hnOdDob6KNcJoL1XtvrX828Py/vk49dPn6ZzPZRvDzvcHsr12BgDmqF4ahfgN4h30gTibbJsry+MHepk
+      CERRL0KUh6JgBzkKQjEOO77+sAuY9wfxxFYrOOAW498vgdiAmbQVJ0xb9sV8+SC/f7+cXi/VfSP/89Ps
+      dsrJ2yHVuLik/A5YRkUjloGQxo6n1nbOHj6f6ojdnnrnYwosjlpt3GS8AC2Lmg97pvawx5zyTxueVJGY
+      lVNofRq104qmBWJOagG0ScxKrSRc1PLqDSzvJl+m7KKMGIJRGG0zpgjF4bTJmAKJw2mLARqxE28kG8Sc
+      hOMNPBBxEl6TdTncSL3ZfRhx76s9PxWOMOam3fI2iDj1CuqYG9MUYDEI2495oO+Mu/2G7jxu4cDLBa32
+      PyK+h1u08FIlnvItOWc05LuoLUcP9a7J9bUchCU308X1fPawpB7ejuBB//hNGkA46CbUXDBt2KeL5PrL
+      5Hq0r/u+bViv1klWruvX8Yc5Opjj267OL65YSot0rE3NtVqkbd1kZF2H2J5sveJcmoE5PoYL8lTsvKgC
+      eSH01u/6A8qbUADqe7uAHK+B2t5D+VKne6qypzBbsk83m/ELqkDYdnOuE77KiGvEr3Bxd55M7r5R6sce
+      cTwfZ8tksVTfb49VJBldGHeTmgqAxc2P+rXDhivvcNzPV4eslObHR3EvYYoKQIPemFQWcCp/eWAXDwtF
+      vdQrNkDUSc46k3St9/e308kd+TpPmOOb3n39Mp1PltMbepI6LG5+JJYxG8W9OVsbSgdqdtko7hX8VBCh
+      VGiq5OMd16xhx/2JWcg+oaXs9+mdjHc7+9/pzXImh4Lp5l8kM8APRKA3TaBhIAr5loEEAzGImeDjA35q
+      cQf4gQj7mrBEBzcMRKHeXgA/HIG4xHFAA8fjtnA+HvTzyhXW2tkfM8sU2urNJpfcVLFR1EtMDRNEndRU
+      sEjXerec/q6eAe32NGfPIUbCYx2XQ4z0PDJAxEntQhgcYsx5whzzkXO75xCjYP5mgf5mVfUcZFX64Reu
+      uMMRP70rYpGO9e7r7S29MJ0oyEbM9I6BTNTsPkKO6/7jf0+vl2pnKMJCX5+EreS0MzjYSEy/EwXbqGnY
+      Y67vejntJxaIVaQLh9zUytKFQ256brl0yE7NOZsNmcm56MAhN7UKdGHH/SD/vpx8vJ1ykxwSDMQgJryP
+      D/ipyQ/wWISI9AmmDDtNAqnBT4dgClBeHgVQx7uY/vPr9O56ypmMdVjMzLUCxiXvMpfIFbbFrU2bdLOh
+      WR045F4XWVoS62lIEIpB7Y66MOymtlxom3X8gLDaxOVgI2UbMZdDjLyc2mD5Q66y8Jq8n/B/x/7hJxh1
+      nw5j3qXiOzOE5YAjFVn5OP4dWZ+ErdRKF21zug/oU0UmGHAm409UhtiwOdnuY+QSh/2CV8sIrH5RW/wy
+      he9QY7J6Te5mN0xvR+P22LtDjLo73G8lqVi/RTTlgSPKAe/X5acrTpAORbzUDovB4UbujX5kHfPywzm3
+      urZR1EvstZgg6qSmgUW6VuYzliX6jIX1YAV5msJ8hII+N9EfbPLtlq5TFGSjFxzkeQvnIQv8ZIX1OAV5
+      hsJ8cII+LWE9IkGei8Q8DAk/AdGfyurtMSuzWh9LsFE7VdEj+A430reHKbm/fYQgF708HinIRh1fHCHI
+      RS6RHQS5BOe6BHxdal91luzcsX29m/05nS/4T84gwUAMYoXh4wN+aqYBvBthec1qIgwOMdIbCovErLu9
+      3qYuaXjqE4746aXEABFnzrvWHLtGcinoOcRIb1IsErFSqwWDw42c5sXHPf+nK3Y1YbO4mVwMDBK30guD
+      iTreP2eLWcQ8uI8H/cQEceGgm5osHu3Yacd1G4jjafsfjRz+qM1CST4bxbzP73nS5/eesUmqFeX8Lgdz
+      fHmT7ZLNRU6yHSHERdkDwAMxJ3HaxuBAI73gGBxoPHAu8ABenTrMgZMlLYcYyfWGCSLO/GLDUkoOMVJr
+      CIODjLwfjf1i1s9Ffqva/IJ1n3Qg5uTcJy0HGVnZgeTFPiX2PE8UZFPbFdNtisJsybr5yTMqErIeSt5v
+      bjnISNv/0+Uc427V7bpIfvZkkZi15GtLwNs2XzK9/6bd0QbnGGUveZc3+XNGryZs1PUemiSraHPSHQOY
+      GK19jzm+Jn28oL7o0TGASYw/StpkXFO22xd6/0BqJlikYf26/CyB5bdkdvfpPule8CTZUcNQFELaIvxQ
+      BEqNjAmgGH9Mv81umKnUs7iZkzJHEreyUuOE9t6Pk8XsOrm+v5NDjcnsbkkrLzAdso9PDYgNmQkpAsKG
+      e3afpPu9PtYpLzLKdvMAantPJxitm7qgWC3QcRZZWifbIh1/lKaDQb52Q1Cm1YAdt9roRB92rL9CMtuo
+      46Ump5+K8i96uKgPYyFupooKkBjtaeCPh7ROyybLWGEcBxCJeHi3y9nGTXU8U5Hi6ynbllVbikZ+3ebV
+      jjCkx8gW5LgKwi4nJ8Bx1LRcdOrJ7i9JWhRUi2Jsk15rQ1gKZDK+afw28D0BWPZky9635GXeUD2K8U07
+      NQnBSKMjBxv34zuGDub71O4usryOXxLkgb6TWac7KOZVh4iO3yYaYn0z9QQBl/OM1B/u/Nqn7OfmsCMV
+      5g6xPSqDSlJZbgnX0pBbviNjm1Qx1IdTlbQUMjnX2DyRq8UTBLgoHTyDAUx6AynSyywAinmJ2WGBiHMj
+      OxJ19crSdixipt4QFog45SCc51Qg4qwJh+p5IOIkbSbvk761ovdIDMz2EQu7V85VI7DKq2Sf5jVRdOJ8
+      I6MDaGC+j9a3aAnAQji/wWQA057s2fsWVSeuDluqqsN8n6jW3zNyoreUa/tJ9Px0DYfdKqvJ96OBgT51
+      R8k2hKHsSNvKGPiAY559RSoQ8usOr5YjkApCSziWpiY3K0fGMREHOntvnEOt3P06nVp0/DLTnpYqynOq
+      RkOAizPLY4GuU9BuVw04jhfeVb0g1yQ4dbeAa25BrLeFV2sLcp0tgBpbncixo0kk4DrotasA61bdhysI
+      p0pbEOCSSa/Pq6SWAQ9G3GogsCfskwrCiJvthZ3UkboAZzMEeTZDALMZ+m/UEfQJAlx7smjvW6gzIwKc
+      GRHdhASx92JgsC+rtmqcf6hLjranfXtJWEpgMr7pNA9BLiE9GbASZ0ZEcGak/1Tss3WeFjx1B2Nu8gDJ
+      QX0vZzZHoLM5p6FYd0IT6RE5KnBiPFWHYpPIEREnpV0YdJOLXI8hPuKDFZMDjfSCYHCusc1J+RlNeMIc
+      X0nvYx8Z29RkglGx95RtO6hjn0lX1RK25Zk6f/bsz509c5LoGU6jF8bA6gUcWZGLFFCW2luX+MjkBEEu
+      TpfbJg3r7eSP6cXHi8sPo20nArIkn/KSUP04HGicUToNNgb6vu43lDlVFzScd8nH29ndTfuef/mcEXqT
+      Pgp7SbeWw8HGvHxOi5yUBCCN2pnJkAdSgTLPaGOW73r5V5KNP9yjJzwLMVuOiOchvJzWE56Fljwd4VlE
+      k9bUq9GMZfp9enf9Ua8DIah6CHAJUhqdGMv05f5uqS+YsujR5WAjsShYHGykZaeJoT5VyYiG8gIoKsBj
+      bKs62VWbQ3EQ3CiGAo5DKwwmhvqSQs2TbJjajrbs6UokuUheqppiNSjbtiFZNh5NvpAOsT1ifbEqKRYN
+      WI5VXtIcLWA75F9ykkMDgIN4LIDLAcZ9SrftU8+0Xq1Y19ZzrnGTrWkqCbiOJ8IajyPgOoqM9cNOmOvb
+      7XOaSQKWQ68DJCj0930DZXt+kwFMxOakh2wXYfHHnf0efvtvap1xRGwPrbH12th1dShVBfuS/J3VlUow
+      QdJ5tGWXZZxWG7WA7cifKYL82aWp6XxEbM+BktvWW23y31n5lJbrbJPs8qJQjz9TXcnV+U729JtXPXlA
+      0I/R2fF/HNKC1UFxSNv6k5Im8tsWTbwLvftvW1c72ZEpm8dql9WvJJVFWtbHNaWoyG/b9PGtVZUXWUKq
+      zj3WMTdJvV2/v7z40H3h/PL9B5IeEngxDuM3W+4Jz0K8446I5ZFtG63uaAHLQXoYcuc+B7lTfUVZpxF7
+      xD3kusrsMVWvTNFkR8q1VaROawt4jpJ4MRJwHfvq5YImUYRnod8xBgXbtqmstdS8LE9r4K6fWMChMYf8
+      m2o0aRZFWJYio90k+vu2gXQS4wkAHOdkybll2aW1eJKtDWlFh405PvGd2qM5Mbap2hDHiB0BWZIfh3z8
+      O7Eu5xlprXBHQJYL3SbSXS0HGZnCsI/VjYEFeAzi/e2xnllPvQrqJXcUZktWhVoMvuFZjzRqrzZccwWU
+      fHI900OI65wlO8dsrPvSYhFzhBjx7g4FUScJyMLrQPuw5yZ2Co6I5xE/aqJGEpCloWv8cicOK6rmsIIs
+      rCJx4jwjo7rya6l9TutKtIDtoJVLt0zKIkX9JR1ieWiT++6cflnK5KHw6vu+gXoH9JDtOuyoXZgjAnqo
+      CWxxvvFV9o+pNsVYJtogxB2B7FPV4qjOX3Io1V4kpPYQoG07d44mMBtD2tXu+H3fQFkw2CO2R2SHTZXU
+      KemJrUFhNvV/HjOes2UtM/ECvStjXVLgWto/04aVFmcbqT2j2u8V1eQeUQ30hojH4PaEZ2FMdZiY56PN
+      SwlgXkrQ56UENC9F65G4vRFiT8TrhdB6IG7vQ/UgqGnQIZanqRLnaFaC0YdBd3fWGkPcka6V1dW1OMt4
+      oE0IHNzZgAPtAdLBfYJ0oBWFg1sWntPikBHb3hNjmYjTWM4c1ukr20O5bvKqTJ4INRBIQ3aRFVtaG+6j
+      hvfrp+TL9Eu3xctopUX5NtIjEYPxTY919UI1KQY2tWcMcXwt6VspXfQe8T3qhan6mZxoHWb7dtmO8pTv
+      RNgW0dRES0t4lmKdNkSNQgAP4Qlxj3iekv6zSuh3lUVWUj2F+V7n9cePejqUMk1sMrApWVVVwdFpEHGS
+      Di/1ScRarRvyftOoAIuRb9rnpA3hTWHcgEQ58BPogKQQaUhqQb5L7NN1RnVpyHcdzj9QTRIBPd0ZV3JI
+      Jz/6OX64G1CAcYqMYS6g335BzmOJgJ7o3+4rgDjvL8je9xegh5GGCgJc9PvkAN0f8o+Ma1IQ4Loii64g
+      S3SmXoXzlHjGooHYHsrbp8fvO4ac+BKVBbkusU7rTbJ+yosNzWeAtlP+Rz5+Z4CegCyUzaJtyrFRdmU7
+      AYCjbTjUoH78nnMgbLspi0yO3/cNCbnk95RtI/Svuq/bPLFPbSC2hzIsPH7fNCy67lVWq1H4JqvHyzwU
+      8uZNt9fyUyoos164AYiiekHyEmi9KJ+1zWqfrTQvRbfq8pVSnUC0a9+/UrtRJmXbaHXmwqszF3p1WFq+
+      Evv7Nocbk6zIdoQd2DAejqBKYGwU1wFE4qQMnCr0kZADIk7u7x/83Um+2xf5OqcPiHAHFok2WHFJxHrg
+      aw+Il3zzniDfVaSiIXX0LMz3VXs1S0dc5QXCA25WMfYNQ1F4g/Eh01BUXqGBHH4k0kj1hIAefsceVYBx
+      ioxhLjLAdUFOVGekevpj9G8Pj1S7L1FGqicE9DDS0B2pLqhLyA0E9DCuyR2pdn8mV2BQ3RUzUsUMdhTa
+      WGLhjSUWapHwcSHDqe3JHmmdZ8zhRdIvqjudYWIgSBGKw/s5vsCOQRozLdwx06LdnUi9KkOxnCDbtc+y
+      7+2lNikpNS3Qdorv+Z6iUt93DM34J0rH77sGypORnjAs0/ly9ml2PVlOH+5vZ9ezKe2UCowPRyDckSAd
+      thOehCG44f8yuSa/gm9BgIuUwCYEuCg/1mAcE2n/k55wLJQ9T06A45hTNnjsCcdC2y3FQAzP/d2n5M/J
+      7VfSKaw25dj0HgGZoOW/CyLOour2zGSJT7Rjb9fyFfn4Z/wOZvjmt8nNbLFMHu7JZ+FALG4mFEKPxK2U
+      QuCjpvfbw/I++fj106fpXH7j/paYFCAe9JMuHaIxe1oU448kA1DMS5rh8kjMyk/mUArrOWPZtPLMRxqz
+      U3pRLog52cUhUBL0Nijq0TQ7JUwDFoW28xvEeuYvX5fTv8iPswAWMZOGHy6IONXmLaStDWE6ZKc9UYNx
+      xH8o467f4MMR+L/BFHgxZEfxm2zhqQ/2IBh1M0qNiaLeg+7kJCv18wQzgOXwIi2Wk+XsOrKgwpIRsThZ
+      jljC0fiFGNOMihf9+4Ile/l5Pp3czG6S9aGuKY8WYBz36y2pu0P3uEFMRzhSedhldb6OCdQpwnH2lZoI
+      qWPidAovznq1Pr+4Unu51K97ar7YMObOygh3B/vu7Up9fM61Ozjmv4rzD15/lB11P6Xyf8nFO6r2yPnG
+      tiei+tb62HZ6Lxow+FGaOiJNLHjArf5JmI3HFV6cbVV/lzdEow5xzh/Lqs6SXbp5Tl7yfVaV+lO1qZ9a
+      oU6Zf+XI/WtTBw/yss9EPe/jeqcSJiW3WD2IOXn1kg0PuFllAVJgcXjl2YYH3DG/IVyeuy+xuqQWi5n1
+      OPV79spzH2nMLpu+8VuSASjmpcz2u6DvVAdfvLb9p/aYOm4fJmAKRu3Om3uLsK4qGLe90PiglgeMyKv2
+      DBKzkk/8RHDQr6v0brOxvCoZIRwDGEWnHmUHdYhFzWrNXUQWuwowTvOkT3aS3yU8bIBx3/+UqpWu9HFz
+      D3pOtQYxFTuisKN8W9txI/f3Tpxn1NWqeBWUd7kB1Pfqw6m2uToUNU+LZHWgLIcOOLxIRb6q0/qVk28m
+      6nl3enqZozVI35rtCG+YWpDnUjUKr7YzSN962CWcuZ0T5xmrmBFQFR4BVeWaWpkpxPPsq+L1/P27S17/
+      x6FxO6M0WSxuPtAeV4K0b5fjDiFv71X1k3XpDu756w2j3mkhxKX2nmnyfZFdUU7JCij8ONm23WBXDgkS
+      9XW9GSFpWf2QCI+Zl2tuFIl6XjVfpF7ViemdgQ4w0tv0fAWh5yverucrKD1f8UY9XzG65yvYPV8R6Pnq
+      Y+g2MVdv0KA9st8oxvQbRVy/UQz1G3ndJ6zn1P09ybdJ+pzmRboqMp7aUnhxmkKcyxqaWkceMcO3nCc3
+      84+/0/aUtynAdtx5mSw8goCT1IaZEOBSb1cRlpramOF7Sq9Vz5w4sWNRve1mujhOVb0f6zIZ25StV++p
+      3TaX84xMIeLbZBfqAQJL6rCe+X2E+X3AXNLz58jYppJ5fSV6baquI0zRGQjoSQ7l+imjHDIDwr67kh2O
+      fVrnDflSe9Kwfk50pNGu7vu+IdkfVqQEdDjbWO32B9m9Ifp6CrOp+YUnQp5AMOqmnXMCwpabsuSq+7rF
+      n3bwpyWjicE+WYrSXdZktSBsOYcKnBjNu+SR5FSA76D+5hbxPXuqZQ84fpB/kUQAT50/c37YkQOM5JvW
+      xHzfD6rph+tQh0L8+tv5b8nFu1+uaDYLtbzHLdn7ckcw+7DlJiwIbL9t08T9VA3E8rSLhlm/z0Utr6Df
+      SwK6lwT9PhDQfaCHPfqNJZqpg2wX4VTm7usWT1tQeQJMh051QTnNx2QM02w+vV7ez78tlnPqGaIQi5vH
+      DyN8ErdSbiIfNb2Lh9vJt+X0ryUxDWwONlJ+u0nBNtJvtjDL1y2UT+4mX6bU3+yxuJn02x0St9LSwEVB
+      LzMJ0F/P+uHIb+b9XOyX6jmyPeWhJggb7sUkWcyItYfB+Kau7aTKOsz3URKwR3yPbvOoJg3ZrnYIo15N
+      TZtDTTI6qO3dVDFqn/bs6hOiUiGe5zmr8+0r0dRCjks2jjefSSJN2BZqyfVLLWvQ5HCIkTdsQg1uFNLA
+      6UQAFvIv9/p7x7/uyZ49ZPlB/112v/H0V+oAygUhJ3EI5XCA8QfZ9cOzUB+JOBjoIy8DgljbHDEwA2nE
+      LnOPcUsDOOI/rIp8zdafaNtObOu8do49JARY0MxLVQ8G3awUdVnbLBh1mwDrNsGolQRYKwnenSqwO5Xa
+      rPttOmlQ3H3fNhCHxSfCttA7FkCvgjG8NqHeNb3mzUq7HG5MtvlecLUattyMnrxNwbaKeMYOxEJm1YrR
+      nYrCbEnN8yU1ahRMI/iLiSMjD4SdPynvPHsg5CS0QhYEuUijLgeDfIJVagRSapqKW7aPpGsljrMsCHDR
+      qkQHc330C4OuSv0tecmbp6RUiwv1Yq4iS7+b7TvnZSCe3b+6vzNqxL+9ksZJdj/Nk98/dedxyh7V0/gT
+      3XzSs5a5aPYXF7/wzA6N2C8/xNhPNGj/O8r+N2af3399SAhLjk0GMBE6ESYDmGiNsgEBrnYQ384PVDXZ
+      auOYv6oJux0DKOxttwbbFukjR93TiH1dbdM1M01OMOY+1M+ZKoE8+ZEO2inzugiO+DfZI6cE9ijiZRcT
+      tJS0tzVhe3SfBKxqLmL1GpPMngGJwi8nFg3YdYqRnhwDKOAVUfelGLgv1ef8ysqiEbveA0C9PKMOflbH
+      b8nuwY4VCTRZUf+Yfuvm2WljNwdEnKRRps15RpnhuSxKegwmsnU9fpM4VODHILWPHeFZiG3jEfE8nGl8
+      AA16Odnu8UAE1STXFTk5exB2MubrEBzxk+fsYBqy6/uQei97LGjOyrWurgTDfGJhM21izycxK3kiHsE9
+      fy6Sap/+OFBvwRPnGWV+XhBeR7Ipz3acMmc13bAAjcG/XYLPDbrvkKZVjgRkYfdkQB6MQB6a2aDnbKfp
+      2Rft4oif/uADwTE/u3wEnoB03+D2wjwWNHPrUhGsS0VEXSqCdalg16UiUJfq3iSjmT1xoJFfKhwatnOb
+      WBsecCfpVn0o81oOFfIyJc2JjvN5V0B7aGRBluvLdPn5/qbdFiLPik3SvO4pFQzIWxHa5VOEw5ZNBjDp
+      t8Co/V4Xhbykma8TA5kIu3dbEODarAqySjKQ6UD/fe6Ig75i0IIAl56Zirl9QprR8YhTDkMqIG6uhsUN
+      OUaLQT6RpOpNbbWNQEMvbTYO++UQXncaOPIjC5h3B3qJlgxgovUJgbWhp79W6+ZCz1+QfScSsOq/X6xX
+      K7L1RKJWGZdplSRgFW9zH4qx96F4u/tQUO7Dtk+229eZENnmTWLjOiR+U/FvXIe3InRd/HxzURL20PdA
+      0Cka+dmG4WxBy6lPKzvkRZN3tQSlnPmw4b65uLw8/031ofZpPn7C1MZQ33E6b/w7i6jAj0F6vmwwvon4
+      /NWiTNvsYTJffiO/JuGBiHP8ewIOhvgorYHDGca732d3xN/bI55HFdb2ATdxTgDGQf88xj7H3fqUjuOd
+      lpWP8iNBjAApvDiUfDsRnqXOHmVVo07aLApdIxdZQ81C0OFFEnF5KobyVMTkqcDydD5PFpM/p3p/bmL5
+      9lHbq7b0yeq6qmkzDh4Zsm752q3tbceA+mOK08Agn3iVBWfH1Zq0bW9/Bu1gNpfDjUnJdSalbdV7Abcf
+      CYrT5BzjoVyzf74H2249r0/NqhOEuJJC/Ykj1GTISr6xANz3l9nP/lt6e0NqCN9gR5F/ZGehyzpm1bJ8
+      nN1zypzLAmb1H1yzwQLm+eTuhq02YcCtd2mp2HYbt/36aELyLdNTmI180zho0Eu+bSAeiKDPRuYlRo8G
+      vbxkcfjhCLwEgiROrGqvBqm7tP5OsveY46vV0hIdklSsTQ43JusVVyrRgHe7Z3u3e8d74JS4A1jW6iwV
+      VcmumAHc9e+qZ9WqE7ZkcznQ2G2txxWbuOsXjTo4gWE2QNspUk4a9JRjk60t9XY6Mobpz4dkMp3c6HM5
+      U8JpQh6IOIknm0EsYiaNWFwQcaouzPiTAAAU8VL2DvTAgLNd2r/J62xN2fl9yINEpIzLHQ4xVvuMd9EK
+      DDiTx7R5IqykRXgkgsgIbx25YMCZiHXaNMzLNgVIjCZ9JL3cBLCImbKDsQcCTvXIm7ZHEYACXvWWlqz4
+      6ydOTWfCiJubwgYLmNtXd5jpYcK2+6N64WpZ/UFYCmFRtu169vB5OteZqo/mo706hAnQGOt8T7zBPRh3
+      09ssn8btlLUAPop7m7rgeiWKeru9Pil9QkyAxqCteAJY3EzsJTgo6tWP+vd72ngJV6BxqD0HB8W9z4wK
+      BeLRCLw6HBSgMXbVhpu7CkW9xJ6OTeLWfMO15hvUWlNOrIdY1Cziy7gYU8bVl2JqgBMfjBBdHm1JMJba
+      ipZfYRoGMEpU+zrQtnLzAU//mJomXMtE5ehATjJrFrRW4d37/n1P7/ZAfR39t095mRaEfbR8ErLOqA3W
+      icJsrEvsQMj5lXTajcvZxptsLXP8YyqyD79QjCYHGtVdyhAqDPLpHKP7NAb5qLncU5CNniMmBxk3t+R6
+      wQI9p+rBcm4YBwW9jMQ8YqiPd5ngXdN9xsqkHnSc+WMmaD9aE5CFXrZ7DPX9df+JqZQkaqXmikVCVnLR
+      OVGYjXWJcLnRHy0oq9gsCrMx8/uEYl5eWh5JzMq4bRwWMnOtuPFP2hpBh8ONzNwyYNzNy7Gexc3c9DVp
+      2z4tWe26gUE+cuoaGOSjpmhPQTZ6KpocZGS06xboObntuoOCXkZiwu268QHvMsH6ufuMlUlYu/754Y8p
+      dw7VZRFz9nNf1Q1L3KKIV0/HqcfBtJEaxAcifN9sYwK0OOKnzhVaIOLkPjEBBUgM6lNAC0Sc1Gd0Fog6
+      m8M+WclBW1InP/UieWYIzzMcUbxRREGOeNof7q1Cn4TBa9iL72+RzKZmMJ54m3iCGu8tkhj0AVdwrKfI
+      oY4g4nxSddOOp+1Y2/zlJuJpogeDbkYr9SWwNuX4GfEJn4GhPmK7b5OwVZ9/y5FqEHR2h9sypB0JWqnP
+      8L5g63y+8FbjfMHW4nQf0Ar9CQJdxCdPX5AVNt3fyc+GTA40sp7VuCxs5t3h6L1N2rbAxjwfuw4K1D+c
+      VIRTT73a0+63wFDasOdm/Gbw1zJyw8+Jh4/TRJBOLLUpx/bH9eLqQjZB30i2E+Xapt8u9Ic025HybaxV
+      HRaIODe0Fs/kECO1hrZAxNnuafadtjrJp0P2WqRJlWb7pEhXWcGPY3vwiPqLu8ftObHJwBwDkfQlRUbq
+      HAORGM+7McdQJCESkRYNcZVdyBOIeDr9KSYZTQkSi9jqmxxuJM4zOCjiFW9034jR943egWrd7iam1pJx
+      w1mSEbEes7LfBiE6qGULRFdJImst9XXS1rQDnnER94dV9nP/FjFb00DUmJpQjKoJxRvUhGJUTSjeoCYU
+      o2pCYdRgXWpH/jLLRIj6Btnn68bHj2kGcN2I+G8VeDhidPsjhtufVAjiI1oDQ33JzWLCdCoU97Yb13HV
+      LY3b5/yrnoNXrSc+Ge1Hx0FGTrOAtAGUHe4MBjZx9guFccivZrJiAtg8EGGT0UeWBocbyfNNHgy61Xbi
+      DKvCUB/3Uk8sbtaLWjPa2kWIByJ0LxiQzR2HG3nJYcKAmzVWRsbJevQ5/sxXl0ONjFrwCGJOZr1tsJh5
+      zr3aOXa158w0PUfT9Jybpud4mp5HpOl5ME3PuWl6HkrTphDq3lCLMWg7KwYtcLSkTl9YOwkHHKFI9F2F
+      cQUQh9GBAPsO9N3pPRKwth1osrLFUB+v8jVYwLzLZV+tfIzpSPgKIA5nPgeey1GTMbFlGXCEIvHLsq8A
+      4hynQ8j2Ixhw8sqMRUN2vQ9He6gpXW7AuLvNGa68pXG7zg6uXMOAW3BbNYG3aiKiVRPBVk1wWzWBt2ri
+      TVo1MbJV0/u8Ep+iWSDk5Iz8kXG/HgSz7r8TCVr/Zvxi7wmk/jMr9ZCUI+62b2OA75m8/NrAUB8vPwwW
+      N9fZWi3r48o7fNAf9QtMhx2J9R4B8gYB590B+K2B41+Ji30MzPfRl/dibx4w1/OjK/l5a/ix1fv934mp
+      Z4GQk56C+FsAaiPSdveJJC3ylNSdcFnfvCG/VdVTjk0tZE4zkZxfXCXr1ToRT6lupUhyTDIyVpLv9rLv
+      kVP3ZBolDF3DepesikPWVBXtVQPcMjZacvU28ZKrUMSmTp52qU6Xi8sP/Ii2JxDxcb1jR5Fs2CyHHOVG
+      b3MTE6O3DEQTEYWx4wciyJJ6fhEVQxtGRHkfHeU9FuW3C36utyxiVodVR9dIrmRkrOgaKSQMXcMb3LGA
+      JxCRm3cdGzZH3rGeZSCaiMis8B17/Ab/jrUMI6K8j44C3bHrp1T+7+Jdsq+K1/P37y7JUTwDEGUjryTb
+      ZO/jbl/QMjZa1A08aASuojwUBf+3WjRg/xmfcT8Hc+7Uj6K5Txjia2qWr6lhX0bYs9fGYB+5AkR7K+0H
+      1ZZ1fRIDfLKB5ORHiyE+Rn60GOzj5EeLwT5OfsD9iPYDTn60mO/rWnWqr8MQHz0/Ogz2MfKjw2AfIz+Q
+      vkH7ASM/Osz2rYr0e3axIvaSesq2MV4QA98MU00HsYR0iO8h5mSHAB7aDlcdAnreM0TvYRMnmY4cYuQk
+      WMeBRuYl+leoDuxVTTxFdmRskz6kXc8NrV5JB0IDbMBMew7toL63nXniXbHJBsz0KzZQ3Fut/sX1StT2
+      PqVCV2dPab15SWtSSrisbT4eo96GTtLisarz5olUcWMOOBLzMXX4vHfzC6yH0z7t2Dekzdvk113+ksZf
+      erzu5RMlmrFN7cHoMfkNG6AozLwOnd3ef8zKZ5e1zfX6IvnlHbXy7infxlABnl9oDqfsUcuNX2b0+HKr
+      N7LRxwCIbF2rZeOH7Tb/SVWjIi/mxcUvRLkkfAutnwfNe8m/vb+iXoskPMslbQ6oJSBLQv9VHWXb1PSE
+      mqvQi593Kamwuixs7uoJ9aC13nD0lgCO0X52/KY47NUmPhkrGqLC4upDYhhv9MAGI8pfy+ndzfRGrVVJ
+      vi4mvxPPX4TxoJ/wkBWCg27KajeQ7u2fZg8L0t67JwBwJITNDyzIcelDgtbVoSSczeGBvfP36d10PrlN
+      1FmzC1LG+yRmHZ/dLocZCZnsgbCT8vaJyyFGwpvtLocYudkTyJ128XmlDpi5Iwx8AopQnOe0OETE0Dji
+      5xUytIxxi1ighOkljCynJhGrOCV+yc0/WxGKw88/Eci/xdePy/mUV7xNFjfTC0dP4lZGETHQ3vv5j5vR
+      +/uq79qk2kgwLTcUQYd4nqZO1w1RpBnD9GVyPdogv2uTnH2wXA4yEvbAsiDERVjU5XKAkVLsLQhwURYo
+      WhDgIhRvkwFMpJ2fbMqxkRb89YRjmVFTaeanEHFxn8k4JtqSPgNxPJTVySfAcMwXC/WiZzr+zjsRjiUr
+      qRZNOJbHrMxq4pyOBzpO/tQdgjt+7oQRCLvuqnh9L2/W52z8jrMeCDp3h4IhlFRvmy0WX+VXk5vZYpk8
+      3M/ulqR6DcGD/vH3MAgH3YS6D6Z7+5eb0dM58qsWR6vuToDtoFR2x+/bhmWdlmJb1TuK5gTZLlpl1xOm
+      5XI8fmlx1PS89NPzkpiel156XnLS8xJOz0tyel766Tldfr6/obxA0hOe5VDSPZrpTXq4cH1/t1jOJ/Jm
+      WiTrp2z8NvUwHbBTaikQDrjHFxQADXgJtRPEGmb5ySdaEpwI16J3F6Md/euBoJN0BLjLucaiGr/ZcE9A
+      lmSVV3STolwbJTuPgOGYLhfXk4dpsnj4Q3bqSJnpo6iXUJZdEHVSfrhHwtZZsvrwi+qUEqZtMT4UoX0/
+      kh+h5bEI3EycBfJwpu8K2bskdEsxHovAKyQztIzMuEVkFiohIjIdxGA6UF5l9UnMSnstE2IN8/1ydj2V
+      X6WVNYuCbIQSYDCQiZLzJtS77j/+d7JeiQvCuhsDcTy0SSkDcTw7mmPn8qSN0nvCtmxov2Tj/gr5HxtV
+      VPONWpUhKC4HRb2r1xh1R9t2/QyBcn6sBdku2lGfPeFYSmrhbAnbIv9wsV6tKJoO8T1FSdUUpW8hrEgz
+      EN8jyFcjnKuRWmoSd4jvaX42VI9EbI8g57gAclxqqZoO8T3EvOoQw/MwvVNfUm/vpkXRL9MSyboqRw8G
+      BzR+vNUhL9S+Zu1OtoIax8F9v66+RUb1dhjiI9S7Ngb7alLr7ZOAVaZ1/kg2agqw7Q+yMtZHwpCVPep7
+      Ob8a/r2PuybfkV0thdlkGf4Xz6hI1LrJt1umVqG+9ykVT+8vqMqW8m15+v5ine6TB6rwBAJO9cBEb2BY
+      ka096nvbkbiqAWQFsKs2h4JegUAOP9JO1mXVmupuKcxGesoHoIA3223ot2hL+bayYlYjJ9B3yk4sJyE7
+      zPeJpl6nIqN0xz0StDLSsaVAW7FOG4ZOYYhv/JNwBwN9JT8Ry1AqlrxkLLF0LAlbZDuY72uqonoZv/rO
+      wQzf8vN0Tl18ZkGQi9Q2WhRkI1Q0BgOZCON5CzJc+6yEu4ijxagBj9K+NMQO0eG4v13/y/Z3uO9/llEJ
+      c/EOhvqS8rBjOhXaex+mX5LJ4u5cL0wda7QgxEWZmPdAwPkiS0hGFmoKs7Eu8UTa1r8u3/2WzO4+3ZMT
+      0iZDVur1+jRmZyUHgNv+1WuTCdaV26Rtlf+ZrOU9t0rHP490Odf4XfbIthXN1jKOqUrUobbjWyULsl1q
+      nl+9OXA9e5D1sE5oihXAbf++lh1Ryv6HFmS7qGXeL+k6r28+03ZU9UDIuZg8tC+W/TH+SQNMw/bk4etH
+      wuakAAp7uUlxJAHr9DoiKUwYdHMT4kQCVnUO3q9ko6YQ2xXLdoXZ5Ndnf+pXV6g3KOaAIvESFk9VfikI
+      loF51L02H7jX1Od6VR5XfoRhNzeV56H7WLWRZKOCEFcy+foXy6dAzHk9v+U5JYg559N/8pwSBJzE/gPc
+      czj+ld/OmDDmjroHPAMehVtebRz3xyRRoA1Sn0e1Q64AjRGTQKE2SX3Oa5dOZMB6xbZehayR7RTiwSLy
+      Ez6c6nGlZrDMzKPv3fmIezeqHXMFeIyYXJgP1Q+sdu0IBpys9s2EQ25OO2fCITenvTNh202e7ADmOdpB
+      Oaeps0nQyr1RABzxM4qvyyJmdoLArVr7IbdJ82nYzk4OpCVrPyQ3YwaG+a54vivUF5OwjmBEDMrRvkEJ
+      GovfFKMSMBazwARKS0xGBPNgHlefzIfqE26T69OInZ3a82BtRW1mewqzURtYm0StxKbVJlErsVG1yZA1
+      uZv+D9+saMhOHKQis+anP0e03fg41fg87p4bGKlaX2LfHaGxqvWNqIQKtesxw1XYgEeJSqZgO88asjpo
+      yHvF914FvbEJP6L9B77G6wMgomDM2L7AqHG58dWIAjZQumIzajCP5vH11XxMfRXXVwiPz63vROXGfLBW
+      5PUd4DG6/RmvD4GP0p3PWX0JfJzufM7qUwyM1K3PeX0L12BEkbf3+UXy8HGqVpuMNluUZ6O9wGJBnouy
+      1MlAPI96Yv1d1plpuUnWWT1+MQ7GexH01g5Eq2Y8U3eaHGEDRQ+0nZcyq/64+XSRULbu8cCAM1l8npyz
+      xZp27ftVdsE60R7BQT/n3HUEt/2/JqtDuSkyVWOQipoFIk5V/vJtvpb3C89tCtwY1BvuV+B++1XfLvSf
+      fqQgm6rNeMYjiVn5yQkZoChxEYbs6gTkuAiuwY1Cede1J1yLWtmjzvWmvJ7nk6iVdBYhxGLm7i7PNjz5
+      Ccf9z1lR7fn+Dsf8Ki+48pYNmyflZhr3E3yPHdEZgJDrKIgPR6A1Bz4dthPWSSO46+9aOpq1g1xXV2Bp
+      rg5yXcfdtE43AWcX9xEqN267z9YbRA2IvJiqf6jeJSZGOGKgT/B8wvbd386uv9FvHRsDfYQbxYRAF+W2
+      sCjX9s+vk1vmr7VQ1Ev91QaIOsm/3iRdK3v/IwQP+qmpge6CBHxMThV8J6Tu8y+ThwdF0i/bIDErJ61N
+      FPVyLzZ0rfS0NUjDOr//Syb7dL5smye95/pidn9HS4ygZUw0QhIFHGMiURIuJHFjdalMTzYDRJzUxDlh
+      iI+cBD3XG+eTu5uke4NorM1kHJP8S5a+kkQt4ngIM2HH7zsG/YoJyaEJyNIebaJOdFC7p6mDkQjDpwGN
+      E4+4fYHJOKbskZaC8vuuoUxXRZZsq/p7cihFus2S1WG7zSgbxQ2KnJjbXH6RssW6TTm2dmBdbpJd1jxV
+      tPRwWMesX0tXYUnOE+XY9tX4A+FOgOsQ2WFTMYq9CTpOkWW0RFOA5+DngQjmgWjS5kD7rS1ieK5H7xor
+      v2px+uIIYxkDMTzmAyvKflEeaDuPT6eoSpOzjP+bnL+7+EVtwKB2tU/S558XBC9AW/bkYbFIHibzyRda
+      TxlAUe/41tcDUSehBfZJ26peNN5/X4tzObzNCIdwQaxtXuXjn7Qcv+8YirxUpxkl499zdjDbpzeLlfXg
+      nnRdPQXZKHeiCdku4hyOgbiebXooGmqd55G2lTgrZCC2Z1ukj6Sk14DjIN6m/r1p7h9P2OIfQANeaiHz
+      YNfdvEvWdZPQ1iMBKODdkHUbyLLbn9NFEgJdPziuH5ArI4sywLJN101V0xO+4wBj/mO3J+sUBLiIldCR
+      AUwl2VMCFvoPg37VD7Llh2eRdylt1GRjoE+2oYlsYahVh83a5lwk1T79cSAV1hNkuyLOx0VwxE8+BgOm
+      bTuxa+P1Z1QC01u/nrJt3XGKuqejF1ok95PpQ7J73JLqp4BmKJ7qu8WHO1qGoumncpGxWseoSBdvEOkC
+      j1RWZcaNoFjY3Hbh3qA0gKLhmPw88i0jo128STQvp5gnO4Mw6GbVUPg5PfpTyjF/J8Bz6Mtm9PodFPYy
+      +usOCnt137SudsTJHtSAR2mquBhNFYrQUE9oAWHH3ZYXTpZaJGjlZKhFgtaI7IQEaAxWZvq47Rf8EZEI
+      jYgEs7cv0N6+YPTQBdhDF7z+rMD6s5S1Xcfv+4ZkLwS5DbRAwFmnL2SdZFzT3xnN8rfT5h/2lJOTesK2
+      0E526AnIEtEtBAVgDE6OOijoJeZqT/U2ympje22x+hftiLCecCyUQ8JOgOMgHxNmU46NdlCYgViei4tf
+      CAr5bZcmp++J8UzEND4inoecMj1kuy4/UCSXH1yanjZHxjNR06ZDPA+nDFocbvxYVOvvguttac9Oz8sT
+      ZLneX1HKufy2S5Pz8sR4JmJeHhHPQ06bHrJcl+cXBIn8tksntDulIyALOZUtDjQSU9vEQB851W3Qc3J+
+      MfxrGb8U/JWcOsLiPCMrzbz0mj18niw+J4QW60QYlofJH9ML8jndDgb6CBOZNuXZTs+GduKRqDRRz6v2
+      XM1Ud42sNUjDSlqC5a6+av9N3dbapnrbcv51sUyW939M75Lr29n0bqkn9QijMNwQjLLKHvMyyYU4pOU6
+      iwhmi0bErLNNtttTzuccoQrGlX/PxdNb/FjHNCbqm/xczxWOTKghEDzoJ9QYMB20q1kAUdeR94BhgaOp
+      87Kn85i7zTYEo3BzxMCDflUgYwJoPhiBmec9HbSrgp3tIgK0ghExKEP7oCQYS5W+Xdakaiorsni5qsG4
+      EfeOb4GjSbb9D265tgRwjPbs29Ns9jEJONEQFRw3+7nP6nyXlU3yfM6JZgmGY8hOym4VG0dLxsR6rvb1
+      Nj6a1sDxuEUCLwnmkiOO2eThCMzKzarVvi6m8/YAWFISOBjoGz8+siDQRfipNmXYlp+u1DKR0Ts/nADH
+      sT8QHQroHX9dXF6ej97hpf22S6sysU/zmmY5Up6texqknzV11Q3RDBiMKJfvfvvzvXo/R20W0D7+pxxu
+      ifFgBLUPS0wEiwcjEN5hsSnMlqRFngqes2VRc5GPf3EfQFEvN3UHU7b9NBHfY+QSB/3Et3B8ErRuLnKG
+      UVKgjVILOxjokxUYQycpzEbZZM0nQWt+wTFKCrRxyyZeLttCxfvdJxY0k5a7uBxuTLZ7rlSioPdZr1ks
+      GdqO9KzdyXmyxRDZmjLTgPFeBFkhnDMK1xGDfOpVo3KT1uqNlyYr1bSYoOshCxhNpt0hY/g1hxuTVVUV
+      XK2GB9wJ+Q70+EAE+j1jsQHzYf2U1my3pj27rgAY1fqJ84x9oWFVIC7u+VVdTW/VOgq08e5wg4StDeWd
+      VQ8Enez7w4YDbnqGWaxnbhdUMnp6Peg5u1TnFFsTBbxNsm5+kpWaAm2c1v7E+UZdMFg/uydtazK5/f1+
+      TnlR0aYgG+XIW5sCbZsDx7Y5wDZq4hkY6KPs++NgoI+TEVg+EOYlbAq0Cd4vFdgv1ZOwG55Rgq5zuZzP
+      Pn5dTmXLdCiJiWizuJm0vykID7iT1WtyN7uJCtE5RkS6//jf0ZGkY0Sk5mcTHUk60EjkOsIkUSu9rrBQ
+      1Nu+sUiYeMf4cIRq9S/Z2sXEaA3hKJTDXjEejZBzLz/Hr5pcK5okapWV0nlMnp74cISoPDUMThS9T9Hk
+      61/0Im+RmJWYjQaHGamZaIKYkzxacVDXO7v7xEjPIwXZqOnYMpCJnH4d5Lrmt/SdOX0Ss1J/b89hRvLv
+      NkDA+WW6/Hx/w/v1BoubOdfbo4A33WzeJXX2XH3PNmSzCcPuczV+p85qeTDsVp9ytIoDjO0riuKQN9mK
+      rDVhyE0cAXUMYNpkRaZezWP89B6FvPl2SzdKCHRRtmB2MMh3oKee349Tf2XdmMgdqXsrsh+qNswmO004
+      4BZZnacF297imJ83JwzxWIQiFQ1tgS/GYxFKeRExEXoei6DeJkubQ80McMJhfzKf/nn/x/SGIz+yiJlT
+      RXQcbuQMSH087KcOQ3087F/XeZOvebeV6whEos87eHTATpzxdlnErNco1ixxiyLeuIpgsB7Q23XQR1se
+      jdjjKpnBOqavI6hPbWEDEoW4mh5iATOjSw72xndps34iqzQF2DjdZLh/zBgEHinMRnzebYGAU4/iI24w
+      h8ciRNwEDg9HYG5XF1AgcdqKirS/K8YjEfi1kRiojUTEfSyC9zHl9X8LQlzUB2cWCDkrRi9bQYCL9iK/
+      gwE+2iv9Dub4TvuCk5/BWSRmjXiugDhGRKJ26BAHGok6PrRI1EoeK2I71Tsf6qOcOF1QWBGMQ66EfDzo
+      Z0w/QwI0BvcWCN0B1L4BslO/85mIz1UxJldFXK6KoVwVsbkqsFzlzQtjc8Ks2Vtk5vb2/v6Prw+qliGv
+      bXZZ1Cz/9pjV9N4kaECjdH0TxrQR4kAjiQO9kHg0bF83NevaFQcbKXvkuxxipJZjg4ONT6mQ3b685liP
+      LGymHGrpcrCRet/1GOwTT4dmU72UHOmRdcx6ve30bjmfTck9KYfFzN8iOlOYZEwsancKk4yJRV2ogUnw
+      WNTOm43iXvId6rC4mdWxAvhwBEYjDBrwKDnbHronqHWDjeJekbEvV2RN0BuVm2IwN0V0bopgbs7ultP5
+      3eSWlaEGDLn149KyqV/p5hMa9LIrT9cwGIVVbbqGwSisCtM1QFGoj5CPEOQ6PgnmZaxJg3b641+DA42c
+      NgJpHdp0pj+ccWHIzWtzsNamXdZHfBxjkYiVm/EnFPPqzezZd7RrGIzCuqNdAxalYT7thARDMdg/pEGf
+      eeqvqHEBXawozJZUxYZnVCRk5TRacFvF6nkgfY6qzIq8ZNzMHQg56YP/HkN9hENrfDJkpT6lcmHIzerD
+      +b03Wdqn1+1bxOq9s0bWSbRJG0gAx9A1qfoDx3+CUTd9tbTDwuZ885M7RwMa4Ch11tR59pxFhgI0A/Ho
+      z4pBAxylfcrD6CAAvBPhQZ3cTu4jnCjIRq3zjpDrag9lvbu/4VRTHu3av37k/fKeg43E7QIMDPW9azeC
+      Z2o7OmQnH0MRUMBxclai5EiakEvYCYN9gpdnAsszEZVnAs+z+cP9YkrdP8XkECNjXw+XRczkdw9NMOCk
+      r5Xw6JBdxOlF2K8faWy4+pYO26Ou/yQIxKC3RR4dsEckTjBlmvog+FetacROr0JOnGNU+yfxnktaJGYl
+      1sQGhxmptbEJAk79kkXaNDVZeiJDVs74GRIMxaCOnyHBUAzqxB4kgGNwF+L7+KCfvMAUVgBx2hdgGAd4
+      4QYgSjf1yCqxBguZ6ZOWPQb5iC18xwCmU9KzMs+iATur4kPqvIj3JXwc9p8n2S7NC467Q2Evr0gdwYCT
+      WwU6/EAETgXo8KEI9A6IjyP+iLrPxhG/HCxxKqMeRbz8NfugAYvSzofQO+CQAInBWU/ssICZ0fUBez2c
+      Dg/c16HPa5wozEadfDVB1LndM51bqPUQ/HtAhO4BEVs6xXDpFBGlUwRLJ3m1+xFCXOTV7iYIOBkrynvM
+      8+m3BPlvY0MCPAb5vUOHRczM9559HPOT+2snDjEyelY9iDhj3ttFHKFI6tX+dao2SLuhvvcT8IQitqtO
+      7w67VVbz45kWPBq7MMFvyTqf8jp+kGI4Dr37BymG47AWuAc8AxE53U7AMBCF+iYtwCMRct7F59gV0/tC
+      Jw4xqlbyDW5yXxOIF32LuxIn1mL2O73uPUKAizyrfoRg147j2gEuYulqEcBDLVUd45qW9/OpPrWM83zD
+      o1E7PWctFPXqdoO8lQfAD0R4SvMyKoQSDMQ41LU6Q2RNfI0C14yLx9g8IGgKR6U/8oMEgzF0ChA796hl
+      IFpV5OvXpOGXcFcTjieaqo6KpAXhGLL5VQ9yiHtLYZJQrPPYe+t8+N46jy7j5yPKduwPGf4d/b0dVeFZ
+      mmC8rK6riFRr+eEIcpi3b55i47SWcLSf9HcGQMNQFNnQtqtV40KdNAPx9rLqyJuuCokKaZnQqORX02wU
+      9ZL7NCaJWveHel8Jta/5k+x+ci/csaDR9NIU2fgKZpwTH44Q046K4XZUv9TMr2WOeNgfUV+KwfrS2Fgk
+      IkZnGIjCr71OfDBCTD0sButhEV0zihE1o/rOtkgfI+6Llg9G6O7SiBidIRilyXcxIRQe9pPX4AB8MEI7
+      5ZysVxFRTg40Utf/UyfRrL8zI1kONNLfWV0xAygU9KqZbWYdeERxL2uQ15Gotaiq76whfA+DbuboHR25
+      G7uSc6oDE8f93BZyYJTZDjlk3jKvvIMDbl7f4cRiZu56f0iAxlC/jVm4TRz369VGEQGO/EAEPdzbRAVp
+      FQNx+unXqFi9Bo/Hnt8zaNTebm3EzZWODtrZQ3hbgMZoq7+YO9tSDMZh3+WmAY3CeBLtwgNuXt/hcbDf
+      UFSpaova0sxJIlsAxuCNM7Exph5OyRY0VwHTImryDHVhkc/Z7VwPY+6Y2lwM1eYisjYXg7W5iK/NxZja
+      XLxNbS7G1uYiqjYXA7W5uSHnPm2eBDOG5QhE4o2dw+PmmLFmeJwpoto6MdDWidi2Tgy3dSK+rRNj2joR
+      3daJEW1d3Jh/aLwfMxYPj8NFTBstwm107Ph+eGzP2InVBB3ncv51QT7xvKdAG6d+tEjQSl5T0GOoj74M
+      02ExM+MNOodFzfQVPg6Lmum1tsOiZvp97LCgmfpO24nCbKw5a4927H9OGGeoHCHARXyI8ie0T5X6I7Uf
+      3jGuaTqfffqWPEzmky/t2UaMB2GYZDBWk66Iu1QijoFI58lTRSzAsCIUR1V+NeMmxCShWPQC6dIhO7mq
+      9ughO73ihhWDcfZZVr9BrKNmIB6jcocVQ3HoXX9YMRQnsjRjLYv1Jc6jZUgQisGY3Af4UARydezAIbea
+      beDLFT1kZ7xiiDgGI8XVxCfFYJx8Hxkl34+IkaRiHR1HSQZjxdViJ8VgHN1055mIjHXUDMSLrcnEmJpM
+      xNdkYkxNpr6kyuYbxDpphuJxBvCYZCgW+dE9aBiMQh5swIpQHN1pZA10cY0Tj/3uWeCdM/1RnekXCBnb
+      6/o45NeJx9abtG8nv38EvyGnzx2gd1N7DPSRm9kec3x6dRX/dFUfB/2MmSQT9JwqXPqdOO3RY6BvnTJs
+      6xR00fsoBgcayX2RHgN9xD7HEUJc5L6FCcJO+rOcwBOcuP1PhvY+6T5nNG8WCVrpTYzBuUbiJtX+/tTy
+      L6dl5eQm1oUBN8sJuJjvI6PvITP2nwH3nqG+x+y/v6xrCPqkSo85PvlfG+NcmVT+i3E+DWpBonEWKDms
+      a6amCJAWev4kPTRPlRyjv3Iez4GGcBRZnVDn70FDOAojT0EDFIX5xnv4Tfd23qxqJtuGkwdHErF+zLbU
+      t6tsFPK2u3Ekq7wRDeOSLRzys1/NHXrrPmJnqOCuUO2H3S4i3HJu81CEZiXUJaTFI93es5D5kG8YZVpR
+      vo0zcYXui6U/qNZiT9cpyrclxrarVKfJAubjChG9TCits5Ts9wxDUagHdUGCETGSrHyOjqMkQ7HIJ6SB
+      hjFR4n/S0RKIduxJx2ST4QAicd5zwd/7i3rbb+AdP85OJ/AOJxE7mwR3NInYySS4g0nsziXDO5bwdyoJ
+      7VDC3ZkE35HktFXeJtvodu4g0seMI3cUWBy94yR96hfggQjcE7wfg6d3q0/5SRNKEW4nM9DH5HcxQz1M
+      vcayyEqys+MgI33vOXTvxceY3WMew7vGxO3pOLSfY9RejgP7OHL3cMT3b1QbzrAL7S5Qanf8YrvDy+1O
+      Tc8k6eZfNOcJc3zeDAN5Vgs0wFFUfnL9RzZgJh8A5cIDbvJxUJDAjUFrSL21DrLeyDf05yE9BvrIz0N6
+      zPHp10qObzTQO94+jvoj3KiXf8nw1VKXivirQ9RwU6Y0fXtXE3Sc+7QWWbKtq12yOmy3xFrQo117u0OP
+      nkaniQ0QdhbZc1YcZ5I2GcfuKEJx1OeMvi/igCPpz419lDiRXMdgJPqyT8QxFOnHIS3ybS6b4bhovQeO
+      qHaDos9gu3DAra9C5yg7Qq8YisNaloNahqIdZCP+RiEtVSBue2uw7yzX4UYiV5VgHcnZARvZ/Zp76CB+
+      3iBrL21kH+1u3pzxiM4iHWu39kQvciZJTdBxtivbOD13i0SsjJ67jULeftiUFo8VXW7z4QjPaXHIYkJo
+      gR+DNRuI73UjIuY4RHCOQ3BnIwQ+GyHYsxEiMBvB3Lce3bM+aufZgR1no/bCH9gHn7sHPr7/PXnve2Df
+      e9ae98h+9/3dtTkQB8I2inrp7Z3DumYju8iDdxcOucnDd48espMH8KDBi7LfV7Xaa+k0l0uM4fFOBNaM
+      DzLfc/wztStjcK6xSo5HMtCMPeca9UJSelfB4BwjY70kuFKS8e4x+Mbx8T1h6jZZBocbu309RSNv5keu
+      3pLYsdKGd5KeyeFGxvM2AA/7ic/dADzsJ56eB+Cen3kWnE16Vj1MU30yXqq4OOTnXDJ80pjxAa+QBE8Z
+      cz5nJUawhPDPF/Ng2/38nrO+vqc8G2+1pwV6TsZz+Z7CbIxi4MEhN7EQeHDIzXlGDxvQKOSC5rK9Ob3I
+      k9+nd9P55Da5m3yZjrW6nG2cPUh4Pl0sKLoThLiSu2uWTnK2Md8TNtc4AYZjlSdNJnskq3STHMoXtd62
+      yXays5fWo/sQQUk41ktdlY+yE/OYC8IAeNgERF0X1UqOFJP6/B05jsEGzecR5vOg+SLCfBE0v48wvw+a
+      f4kw/xI0X0aYL0PmK774KuT9je/9LeRNf/LF6c+QebXnm1f7oDnimlfBa15HmNdB8ybnmzd50BxxzZvg
+      NYuIaxaha/652/GrUAWH3ecx7vMBd9SFnw9dedylD137RZT9YsD+Psr+fsD+S5T9lwH7ZZT9MmyPSvaB
+      VI9K9IE0j0rygRSPSvCB9P4Q4/4Qdv8a4/417L6KcV+F3b/FuKEehB6sy25zu6PTJq+zdXNc4UuOFZIB
+      sfWuGHERfQUQp6nTnXr+XmZkf48C3m7EUWfNoS7JaovG7aJJx0+8gnDIXe356srs3WXi/OLqcb0T+XMi
+      /5F8H70eA0CD3iQr18nP8wh9Z0CibLI1yy05xJitVzrkqqjGLyvDDVgU+flOPCY/f+GFOOFD/qs4/xXi
+      /77ZssSSs4wXlx+45dBFg156OUQMSBRaObQ4xMgth4gBi8IphxA+5L+K818hflo5tDjLmKybWrdPhJUS
+      Dmb7nl6S9WqtfkD9um8oSpv0rU39/uL4aZu3gqoHFF4cWTIZV95Rnq0riwyjQfpWnhGxtft+tYlCLAY+
+      DdqPSc6zG7RtLyt+aXNZyBxZ4lAJEItR6kwOMHLTBE+PiHIC8UgEZlmBeCtCVwE+6X3GPpCOjoRp3B4l
+      H3LLjv7r8/inXBgPReg+Sp6quiQ830B4K0KZJ/JLjGJug5CTXtBt0HCK8jzZVEm6Gb3HmIE4HtWEU1bM
+      WxDgIpUpEwJcdUY6vNnlAKNIn+k6BTmux0yWnLTI/842eoFUUyXjj7zHDV4UdcRJla8zWWUUclw+/lRL
+      jAcibPOs2CT7hu4+kY41b7Jdsq52K/kXeuHyaMdeZ1v9kFrdbHqGRI+kKScaDmiweKrarsqMF6WDHbeI
+      zGExmMPN675b0J2kQlZ9eUl5JowanCiHZs28Dyyyt66y7JDsqo2sGtT6XnUBNWVTM4w3IuRVN7cmZGeH
+      emosTNv27SYRT9Wh0PNS45/8A6jtVbv9yfKqFo+qZOsuQP0p3WxIvyBssqOqD+lp1FO+Ta2Ll/9N1XWY
+      4SuTVG0/dFjJaqMUDamcAKxt3mySl6oev3+RyVimdbV/Jat6yHJtZDeG81stzjJmP/cy3wmqFrAc27wR
+      8oYj/0iLs43q7dJdVTaP1S4j3EIeGbImYpcWBd/d8laEx7R5yupLgrMjLItMkjotHzNygtqg7RRqZzTd
+      cJCtDup666xIm/w5K17V+wSkcgnQlv1f6bpa5QRhC1iOYr1j3TMWZxszIZLmKS3NwjCnqEEBEoOaXQ5p
+      WXd5UejlKrKTReqyQ2zALHsKpPP9UIETo8zlLZe85JvxG8m7nG2sNu1p0Yzy4bGgmZp7FucZZeWbrFLZ
+      rblgXzKkAOOookmuIn3Yc3c9s3ft7c4Pg3qwiOwk83g0ArX+81jULLJ1nTVRAUyFF6cQT/lWHY3NTCOP
+      RyJEBgj4d4cipnHHFF4cbn/TY0Ezp744cZ7xcP6Bfa0W65jlrVa+I/k0YVtkYrNqSJPzjGoCIf2FqGsh
+      2HXFcV0BLkYumJxnVGlKlCkE9DA6ri7qeck34JHxTJwS4peOSpaZUr/grLqd1eo5rw5C9jplhu0rIXsc
+      hAiDLjtyqec5WOMZj7XM++qFlmstYDlqNe7njTdc1Pd2bY7+DlVssrY52xzWmUyaNcnZU5hNDaD2RcrV
+      nnDHL/K/GWlrYLava2nJQpMDjMf01v8gey0asvMuF7hasU6bhlbqj4jt0ROn5OsyMcfXsEcoHuuZRSPH
+      Q2vG1dqo5+UIAdOP+upnomeIy5RS6dug66S35j0Eu644rivARW/NLc4zUlvLE+OZyDl6ZFzTT3aW/kTz
+      lNHDhXu3VptITj2AtuwH7qTAAZ8ROHAHDgd81PBCnr598eZvK/XGvxBq/8K9OuKq2OpHYqOdCN9HWF/k
+      yWRxd558nC2TxVIJxsoBFPDO7pbT36dzsrTjAOP9x/+eXi/JwhYzfKuVHqqoGc5y9CpHm/Jth7W4SFYZ
+      VddhgK/ZvmcJOw40XjFsV7ZJPWpWf00Ieza7nGnU58GR88KkfBs5LywM8JHzwuZA4xXDZubFUyr/d6G3
+      FHw9f//uMqn2hBwB6ZBdZOPbG5g27GoJTaXX06wLNS7MSrXMaHSNifF9hI26+a+v1QvlN9PF9Xz2sJzd
+      3431w7Rj59Wdm1Dd2X/45YGrPZKQ9f7+djq5oztbDjBO775+mc4ny+kNWdqjgLfbrGD2v9Ob5Wz8PgcY
+      j0dgprJFA/bZ5JJpPpGQldaibtAW9fTJ3dfbW7JOQYCL1jpvsNa5/+B6OWXfXSYMuB/k35eTj7f0knUi
+      Q1bmRTs8EGEx/efX6d31NJncfSPrTRh0L5naJWJcfjhnpsSJhKycCgGpBZbfHhguCQGur3ezP6fzBbtO
+      cXgowvKa9eM7DjR+uuJe7gkFvH/OFjP+fWDRjv3r8rMEl99kpfbpvmukSQEgARbjj+m32Q3PrlHHe2iq
+      h/aApz/Gr1P3Sdv6cbKYXSfX93cyuSay/iClhgfb7uvpfDn7NLuWrfTD/e3sejYl2QHc8c9vk5vZYpk8
+      3FOv3EFt783nfVqnO0ERHhnYlBCWxrmcY5zNZXt3P/9Gvzkc1PUuHm4n35bTv5Y05wnzfF3iEnUdhdlI
+      G1cBqONdTHi3lAUGnOSMd+GQe/xW4RDrmw+rIl8zEuLIeUbi2Yk2hdkYSWqQqJWcmD3oOxez36k2iXge
+      RjV0hGzX9JpxVSfIdT2oCFlDOAHC5Twj6yY0OdxILS8uGzDTyoyDul7GzXKCEBf9p6N3Sv8R9Udj98n0
+      ZvYwmS+/USt0k3OMfy2ndzfTG9V7Sr4uJr/TvB5t2zk7J27QnRPdTxZcpdN3mS0WXyXBbH992rbfTZeL
+      68nDNFk8/DG5pphtErfOuNKZ47xfzmQHcvqJ5DtCtut++Xk6p2b7CbJdD39cL8bvU9UTkIV6e/cUaKPd
+      2CfId/1K9fwKODg/7lf4t13xGwMAD/vpiXgVaBX052pi509dK6kxJ1lv44N+Vgr5iuE4jJTyDFAU1vUj
+      V8y5Ru+q1Nj1GznrThRk++fXyS3PeCQd6/z+r296wN2mrG4LF8RHHqgEitVeDV3fco6R3HGCek28LhPW
+      X2J1lpCeEq93jPWNIyrDUD3IrgIDtR9nQIqMRufckf4cH+nPY0b68/BIfx4x0p8HR/pz5kh/jo70zU84
+      yWCyATM9EQzU8yYPi0UiBxKTLwui1iABK7kumiMzHnP2jMc8MOMx5854zPEZj68L2dPVXWeKsKdsm9rD
+      nuJR3/cNyeT29/s51dNSmG3B0y0g33I5n338upzSlUcSsn79i+77+hdg0q04R3cEIafsFdB9EoJc81u6
+      an4Lm8j9agtEnMR71uQQI+1+NTDAx+rg2WTIuuBrobuFOvY+QYgrmd4t599YxhYFvPSK38AAH+EkLpOB
+      TbwSfgQRJ6eEdxxiZJTwFgN9f97/QVtYZHKAkTh9fmQA058Teu0lGcDEyQM4/Rlpb6W7SBO9B8wuG/+S
+      hAXZLn1geLKnP2kA2N6crZPfP3UvMhPOhXEw2LdZFRyfxGDfNiuyXXck+2sz/hjnkCMUaXco+CEkHHKL
+      HzXfLeGQu6li0+dogKM81tVhn8g/5+NPtsT4UATKzg0wHbLrzaUO9fgd0wIKOI66gmRfZ+p1SU4Qk4cj
+      MEsoWjbV0l+1awJTqtmQuVk/8dUSxt0RyWzgAb8eOcf9BNPhRZI3Q6PO5lxXm0y9yVektdqPhnoTYxov
+      nsh3+0IfXpv8TNZVVW/yMm2oOY9YsGiRNThiCUdj1oagA4sUUSMChnCUR2a9BUvCsRg1sMeHI4i3+DVi
+      6NfovUGYv6RlUbNIUlVTq5xrXpkRLEcgUlXGpJUhwGLo7Q/1rmy8ED0fjsAvVz0fjqCKhLxr4zIGVAXj
+      iiT7cUiLiHCdwYqSbtV/dbt+pSU5BshDEdq3vunmloOMMuGOYelaA7bd1GGVyVimVf5YHnT9rit6gs8h
+      EWvbArO0LWp5IxrrYAutuj6HJkte7iafKE4Ds3xto0kbTp4YwEQt7wYF2Fjdj2Cfo/2wzB7JQslAJllP
+      q616k10qvtOdJg3YyTe5iUG+w4ouO6wAk+pm6fJP9p1IxMrKbbDXp3pO5o2kdg2m6lHHYCRyfYJL7Fi6
+      H1VmLxT1kbFMT6l4Uimn+xnJ/v3VL8nPndrvN708v0iEeDkkmzrdNu9+JYQaLwWvpRsHuRz/OsJC6xqY
+      kwDo2P/UiMvLaJtJgtWHB9zkAS+msOLsv2ev1Pb7xNgm3UPT1fKhVGlVZ0JklHYHMQBR9M5d1PvPRYNe
+      6twLyA9FoOUnLAjHoJd2TDEQR8+nRIXRhjFR4hMOnf05jjKIrbKJgb7meAP2tb9g+CENEI/Rytqg7Wzz
+      n5EqFmg51W5rle4e6d4R+VYGeStCl9O0jm8PQS7diaUeD4DgkJ/VGfZY1EzfDBAVQDHy8vldVAxHAMYQ
+      pNM3PBBy2juw0tU2D0WgDUZ6CHK1e//RdS0HGcm3tcWBRtIgpIcgF6Mqc0jEGpPlyO6YyBdUwebXGqjK
+      jtvOi4l0201dUQK5rG1u58Pib/KQJxDxTZJynNG8CvWkXshRbPKSN0+qnVlnybaqk+9l9VImaSlespq0
+      aRlBaV5H+xTp74vLD0n6/PPitBckYaSEKpA41J1+QRhxk6pCm0OMsh8Ud8WmIBBD7VkYFeMoQGK0HTBS
+      dwWih+zkcWpAEoy1qWQfOyZOK0BiHMvwJSvAiR6w/xplx+6vqJIElKLNxeXl+W+MiXgX9J30yQEX7J1q
+      Q7NHPWkja6GxPguCXHqLNLpNY5BPnZpJ1ykKsgkhsvd0ncYcn7zehpxyRwhy0VOuxyAfOeVOFGSjp1yP
+      2T49e0dMuCMDmMjJ1lOAjZpoJwhwkZOsp3pbfpFG7C0I046dt7cegAJe4i5yLgcYaTu/ORjgo+2M42Cm
+      b83dpRFAAS85JddoSm6iStRmoERt+OmwCaXDhrlbpU9CVtpulS4HGDl31CZ0R22idqvEeDwCM5WR3SpP
+      n5N3q/RJyEq9Ozahu4O6W6UFAS5qnbXB6qwNf7dKEAbc5N0qfTJkZV40ulvl6Ruc3SpBGHQvmdolYiTv
+      VumTkJVTISC1AGW3SgsCXMzdKjEeikDbrdLlQCN1t0oABbys3Sph2rHH7FaJCrAYpN0qAdT2sveVBGHb
+      HbGvJII7ft6+kgBqe6n7SpoMbKK8/+VyjvH/t3YGPY7aYBi+95/01mF2NT1Xvay0UiVS9YoIcRIUAix2
+      sjP762sTEvjsz4T3Y26j4OcxIZgxNryW5UoyqO+FcyU9LPCBuVaUitmgd0wZ1PNK0iYCcMYJ//DxtIlw
+      8/JXATk2NKNpEz4XGMGXbSkVswkOKZuy4G2DDyaXsnDfBLyCOkECj+AyFOZKuo/hXEkC+S48V9LnAqOo
+      EfK5kv4W9HyJ50oGW7FzJporedsoaCxMriT5GP/q0ZYiyZX0Oc8oyJX0Oc8ozpXkaWqX5Er6XNy4kSq9
+      vos8V5KnqV2WKxmSces3qfSb50RzJQlEXXCuJIGoC8uVHAnOgjZvLldy8jnWsJlcyfvHb6jnjXFIvtwb
+      /90myY3f6n0jMTOK5/XgBzQ0zNay8ps8/RbrvsHTva/L3dpvMCie17Pum9wMTC2yzM8I/tQvOlpzmZ+x
+      QoKjNZP5OZYR7X9kjyX7GOwVnPlJKc6GZn6GpGddm/k5K+HqwjI/fc4zwp1arkcr687G+rKijmykFyu7
+      c4ndt6y4tM9d1cUX9JlruWSwIDJSkEpHYdL4KEy6ZhQmnR+FSVeMwqSzozCpcBQmjY7CSDM/OXbGjB8E
+      NvNz2CjI/AxJxgpfi9LIaFQqHo1KZ0ajUuloVBofjcIzPylFbUjm5718aMAyPykVs21kug3nQzM/Q5Kz
+      Lg/pnDKMCc38DEDOCWR+Eohzpd9xVfqdN8H96kjmJ9kEtlk+85Nswdorm/lJNpitFgktxxhFXcZYimi4
+      bSPXcu0PHWlhUkTJx1iKKIMyXvxfCZsi+tgApIhOGd4kazNhiijZJGkzQYoo2SJoM36K6GQDlCLqc4wR
+      nCwJU0QfnwIpolOGMUl+A/74C449e9wl16ngGtUp8YXPQ3mvO2uE3gHlvUKn52vcxBDe6SfY1KflT0Hq
+      uacgg40Z+LBaRMDUAT9TqKPPFOo1z+3p+ef2jOwZQxN7xvAqf373Ovf87lU4d3WNzl1dpXNX19jc1emv
+      pivrgy1tb2Y2Pzrz78/F1zqOnTd/V/UaucUn/n9aVbvNKtdNvTGu9N+5yRdXEOFjNfyXV5flbwFz7LwZ
+      OTY8PvordVVV/55c3ewWvwJHKd9m/5ToHtjEd8x2qlLLE8seAHU0eWV3tzsgmjtDTPtOIfviihO+rDUQ
+      KPkAiANIW7qVpvTlnJVGLX9oZcoQU6dsS1BX5HjcEdaTnZb/d/Uw4tOmc2+mAaqBGC3n3ZdsWzXFKdvZ
+      du5eiVWLEz84dmr+OmzN9Vlk5/mxhua2QCraX/Gw0deeCv2SuN+/y03Z1DrLi0K1JgdemZ1zBDW51zEP
+      yy9xlAps7VZlqi66jxaLD43g1P+WbS/1DjsOd8Y3tXmnVXZUOXA2hCS1/tnv/071+49ICThxnremOak6
+      U+/tiz0P7RV7sTVEY96iKlVt+l8Uj5lZoIrVa08fd35CF6K4IV6LyY59mILLT7BdCWlVniZWX6n1RXWf
+      cjRZVazezp6PsmocGbO6UAqZ1ZEx66VecS4PMO9O5K0kyWa9n9ZKEqSVJKtbSbKglSSf00qSpa0k+bxW
+      kiCtJBG3kmSmlSTiVpLMtJJkTStJmFbS2J7GR1bkxVHd+v474J6Mp2N2oNcegBGnVkaktFzcmJ3ztkVO
+      9ggf1NB3FAWH4cHxRuBWxMMCn7vx69OmcecU5b2Cb/7geOMZiXUMQOL8yNIfyIosE2T0uJBBd5072YbW
+      p2NtL/u9ciMVtvvqutmLm+1z06RWyVpVHb9WVTeuN3VLvAT+v3AsNds/cxe6AfaFGZT3trdHRjJjD5+2
+      R+8sqSGQ8HX1wVxd/lNSxZ2NmX8pmfWXokY4jYdAxPUre/kj+ZIdcnNU3dc+FwyQMjRnd6laMvOd5Ky1
+      /Q2TTu2EaoJzfrstcYWEfoJzfl3kxsgPOsFZ/49Oqh7I0aqTUjQ34XOMUTI3wcIT9zF/EQ8xsTBxu/it
+      FXYOJ36XWr7Cz+ETv/1YqRZaT2bKeCZk/PgBMI6sNR3scRB1XVpEcmkJvQf630NxygMdoaE44bHx6wdA
+      HTrTTWcU8kUeDDEBXcVbaZ/O6ktVYYoeoZ7l607cShO6bZDzwZb2afQ3vSOsx96rCVSWorbL8uH3oTjh
+      gXurW2mf7u8G9pe6wDQPjPqO5R7aH1eeGhqozbjihL+6eTtA0JcnBiSJeig+8sb9xP099vJVZabMaLre
+      /yniM+gMSr2SGXSfixs3UuUm7gQaG4NOvK9Z7nrO5eIr6khQS2UQQ2UIvS2aWgN8X54YCntrixj68tTQ
+      VS4leQcsckWpwAZc3UcisHT9/DsoukG+a4dZ6C9sOyW2v2U/BiQPhpjUu8lOF0BzA4jD/u/QR6UNuENT
+      jPjKXQtobGlK1/sGwW1xjz+WW5fFWX9AuzHBiM810IvOD8iZ/GCIqc7PbhmOWpsud0sFAkIfpV6dlfnX
+      rCo1ct2YUJ6tAPqWD4A4mkK3bm7ZniHIbzDFQl/d9GNLqG/AiK8tSkBjS1N6GO4V/ZIhzLmHAWSB+E4S
+      qwYblQ5alYb/s+ngP1vTdnvBZJzPscZV03DPPGyNkgm4CM76V02FPfOwNSKTYB7G+pDpLw9jfeDEV0hO
+      rG2udFZsi/tTJYulPhg4TfeaPJ5V6UdXNChnDH4t4Pg5gXyX6AhEvr27exuqgdoFB3Pu+1ERuSfw6H4X
+      RuG/R5Pwhy0HhSzNQCDO5dpu33TRxUxmFFw97Uv74tY7aRO8gpGdNb+uML+y5td+dUk3/So44FOas9/W
+      gHFZ8bh7ZOfN0NKBUcGTOvTZPUsLLu/33MTWunw9JwJxLtNA//oCMHDCk2Lv0RUqhi26AFfZ8rmJ0b35
+      sisP7saqnyXMq0PTlea4+P43buBruaqu3H9AT2VGcM/fdm5Rln5GUesMy+iLCrw6+iln895fGzRmpyjj
+      dZW6K4N5h70jSr1uvKW/AtuNRwV5PTTw3p4+sbf3qtYlMAQUwQO/rRNeWo1BA2/VNCdtb0NPKtvZe1J3
+      pwvqGUNQy+0GGrjsUez33/4Hk9kXTTeXBAA=
     EOF
 
     # We are renaming openssl to openssl_grpc so that there is no conflict with openssl if it exists
index 4b84b5b..0b028e9 100644 (file)
@@ -271,10 +271,14 @@ static NSString *const kBearerPrefix = @"Bearer ";
 }
 
 - (void)dealloc {
-  __block GRPCWrappedCall *wrappedCall = _wrappedCall;
-  dispatch_async(_callQueue, ^{
-    wrappedCall = nil;
-  });
+  if (_callQueue) {
+    __block GRPCWrappedCall *wrappedCall = _wrappedCall;
+    dispatch_async(_callQueue, ^{
+      wrappedCall = nil;
+    });
+  } else {
+    _wrappedCall = nil;
+  }
 }
 
 #pragma mark Read messages
index 656a8aa..4b710ef 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.37.1"
+#define GRPC_OBJC_VERSION_STRING @"1.38.0"
index ee84f36..a13b95a 100644 (file)
@@ -1096,7 +1096,7 @@ static dispatch_once_t initGlobalInterceptorFactory;
   options.PEMRootCertificates = [[self class] PEMRootCertificates];
   options.hostNameOverride = [[self class] hostNameOverride];
   options.flowControlEnabled = YES;
-  __block BOOL canWriteData = NO;
+  __block int writeMessageCount = 0;
 
   __block GRPCStreamingProtoCall *call = [_service
       fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
@@ -1112,8 +1112,9 @@ static dispatch_once_t initGlobalInterceptorFactory;
                                                 id request = [RMTStreamingOutputCallRequest
                                                     messageWithPayloadSize:requests[index]
                                                      requestedResponseSize:responses[index]];
-                                                XCTAssertTrue(canWriteData);
-                                                canWriteData = NO;
+                                                XCTAssertLessThanOrEqual(
+                                                    index, writeMessageCount,
+                                                    @"Message received before writing message.");
                                                 [call writeMessage:request];
                                                 [call receiveNextMessage];
                                               } else {
@@ -1131,7 +1132,7 @@ static dispatch_once_t initGlobalInterceptorFactory;
                                               [expectation fulfill];
                                             }
                                             writeMessageCallback:^{
-                                              canWriteData = YES;
+                                              writeMessageCount++;
                                             }]
                             callOptions:options];
   [call start];
@@ -1338,7 +1339,7 @@ static dispatch_once_t initGlobalInterceptorFactory;
                                       }];
                    }];
 
-  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
+  [self waitForExpectationsWithTimeout:STREAMING_CALL_TEST_TIMEOUT handler:nil];
 }
 
 - (void)testCompressedUnaryRPC {
@@ -1527,10 +1528,10 @@ static dispatch_once_t initGlobalInterceptorFactory;
   NSArray *requests = @[ @1, @2, @3, @4 ];
   NSArray *responses = @[ @1, @2, @3, @4 ];
 
-  __block int index = 0;
+  __block int messageIndex = 0;
 
-  id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
-                                               requestedResponseSize:responses[index]];
+  id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[messageIndex]
+                                               requestedResponseSize:responses[messageIndex]];
   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
   // For backwards compatibility
   options.transportType = [[self class] transportType];
@@ -1539,24 +1540,26 @@ static dispatch_once_t initGlobalInterceptorFactory;
   options.hostNameOverride = [[self class] hostNameOverride];
   options.flowControlEnabled = YES;
   options.interceptorFactories = @[ factory ];
-  __block BOOL canWriteData = NO;
+
+  __block int writeMessageCount = 0;
 
   __block GRPCStreamingProtoCall *call = [_service
       fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
                                             initWithInitialMetadataCallback:nil
                                             messageCallback:^(id message) {
-                                              XCTAssertLessThan(index, 4,
+                                              XCTAssertLessThan(messageIndex, 4,
                                                                 @"More than 4 responses received.");
                                               id expected = [RMTStreamingOutputCallResponse
-                                                  messageWithPayloadSize:responses[index]];
+                                                  messageWithPayloadSize:responses[messageIndex]];
                                               XCTAssertEqualObjects(message, expected);
-                                              index += 1;
-                                              if (index < 4) {
+                                              messageIndex += 1;
+                                              if (messageIndex < 4) {
                                                 id request = [RMTStreamingOutputCallRequest
-                                                    messageWithPayloadSize:requests[index]
-                                                     requestedResponseSize:responses[index]];
-                                                XCTAssertTrue(canWriteData);
-                                                canWriteData = NO;
+                                                    messageWithPayloadSize:requests[messageIndex]
+                                                     requestedResponseSize:responses[messageIndex]];
+                                                XCTAssertLessThanOrEqual(
+                                                    messageIndex, writeMessageCount,
+                                                    @"Message received before writing message.");
                                                 [call writeMessage:request];
                                                 [call receiveNextMessage];
                                               } else {
@@ -1568,13 +1571,13 @@ static dispatch_once_t initGlobalInterceptorFactory;
                                               XCTAssertNil(error,
                                                            @"Finished with unexpected error: %@",
                                                            error);
-                                              XCTAssertEqual(index, 4,
+                                              XCTAssertEqual(messageIndex, 4,
                                                              @"Received %i responses instead of 4.",
-                                                             index);
+                                                             messageIndex);
                                               [expectation fulfill];
                                             }
                                             writeMessageCallback:^{
-                                              canWriteData = YES;
+                                              writeMessageCount++;
                                             }]
                             callOptions:options];
   [call start];
@@ -1582,6 +1585,7 @@ static dispatch_once_t initGlobalInterceptorFactory;
   [call writeMessage:request];
 
   [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
+  XCTAssertEqual(writeMessageCount, 4);
   XCTAssertEqual(startCount, 1);
   XCTAssertEqual(writeDataCount, 4);
   XCTAssertEqual(finishCount, 1);
@@ -1592,15 +1596,13 @@ static dispatch_once_t initGlobalInterceptorFactory;
   XCTAssertEqual(didWriteDataCount, 4);
 }
 
-// Chain a default interceptor and a hook interceptor which, after two writes, cancels the call
+// Chain a default interceptor and a hook interceptor which, after one write, cancels the call
 // under the hood but forward further data to the user.
 - (void)testHijackingInterceptor {
-  NSUInteger kCancelAfterWrites = 2;
+  NSUInteger kCancelAfterWrites = 1;
   XCTAssertNotNil([[self class] host]);
   __weak XCTestExpectation *expectUserCallComplete =
       [self expectationWithDescription:@"User call completed."];
-  __weak XCTestExpectation *expectCallInternalComplete =
-      [self expectationWithDescription:@"Internal gRPC call completed."];
 
   NSArray *responses = @[ @1, @2, @3, @4 ];
   __block int index = 0;
@@ -1657,7 +1659,6 @@ static dispatch_once_t initGlobalInterceptorFactory;
         XCTAssertNil(trailingMetadata);
         XCTAssertNotNil(error);
         XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
-        [expectCallInternalComplete fulfill];
       }
       didWriteDataHook:nil];
 
@@ -1713,7 +1714,7 @@ static dispatch_once_t initGlobalInterceptorFactory;
   XCTAssertEqual(writeDataCount, 4);
   XCTAssertEqual(finishCount, 1);
   XCTAssertEqual(responseHeaderCount, 1);
-  XCTAssertEqual(responseDataCount, 2);
+  XCTAssertEqual(responseDataCount, 1);
   XCTAssertEqual(responseCloseCount, 1);
 }
 
@@ -1786,7 +1787,7 @@ static dispatch_once_t initGlobalInterceptorFactory;
   options.flowControlEnabled = YES;
   globalInterceptorFactory.enabled = YES;
 
-  __block BOOL canWriteData = NO;
+  __block int writeMessageCount = 0;
   __block GRPCStreamingProtoCall *call = [_service
       fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
                                             initWithInitialMetadataCallback:nil
@@ -1798,8 +1799,9 @@ static dispatch_once_t initGlobalInterceptorFactory;
                                                 id request = [RMTStreamingOutputCallRequest
                                                     messageWithPayloadSize:requests[index]
                                                      requestedResponseSize:responses[index]];
-                                                XCTAssertTrue(canWriteData);
-                                                canWriteData = NO;
+                                                XCTAssertLessThanOrEqual(
+                                                    index, writeMessageCount,
+                                                    @"Message received before writing message.");
                                                 [call writeMessage:request];
                                                 [call receiveNextMessage];
                                               } else {
@@ -1814,7 +1816,7 @@ static dispatch_once_t initGlobalInterceptorFactory;
                                               [expectation fulfill];
                                             }
                                             writeMessageCallback:^{
-                                              canWriteData = YES;
+                                              writeMessageCount++;
                                             }]
                             callOptions:options];
   [call start];
@@ -1973,7 +1975,7 @@ static dispatch_once_t initGlobalInterceptorFactory;
   options.interceptorFactories = @[ factory ];
   globalInterceptorFactory.enabled = YES;
 
-  __block BOOL canWriteData = NO;
+  __block int writeMessageCount = 0;
   __block GRPCStreamingProtoCall *call = [_service
       fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
                                             initWithInitialMetadataCallback:nil
@@ -1983,7 +1985,9 @@ static dispatch_once_t initGlobalInterceptorFactory;
                                                 id request = [RMTStreamingOutputCallRequest
                                                     messageWithPayloadSize:requests[index]
                                                      requestedResponseSize:responses[index]];
-                                                canWriteData = NO;
+                                                XCTAssertLessThanOrEqual(
+                                                    index, writeMessageCount,
+                                                    @"Message received before writing message.");
                                                 [call writeMessage:request];
                                                 [call receiveNextMessage];
                                               } else {
@@ -1995,7 +1999,7 @@ static dispatch_once_t initGlobalInterceptorFactory;
                                               [expectation fulfill];
                                             }
                                             writeMessageCallback:^{
-                                              canWriteData = YES;
+                                              writeMessageCount++;
                                             }]
                             callOptions:options];
   [call start];
index 621123d..8bc99f0 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.37.1"
-#define GRPC_C_VERSION_STRING @"15.0.0"
+#define GRPC_OBJC_VERSION_STRING @"1.38.0"
+#define GRPC_C_VERSION_STRING @"16.0.0"
index 7c0aac9..ae06c35 100644 (file)
@@ -230,7 +230,7 @@ Or require the `google/protobuf` composer package. Add this to your
 
 ### Generate PHP classes from your service definition
 
-With all the above done, now you can define your message and service defintion
+With all the above done, now you can define your message and service definition
 in a `.proto` file and generate the corresponding PHP classes, which you can
 import into your project, with a command similar to the following:
 
index 5dd22f6..c904753 100755 (executable)
@@ -40,7 +40,7 @@ mv $output_file ./src/proto/grpc/testing/test.proto
 # interop test protos
 $PROTOC --proto_path=. \
        --php_out=src/php/tests/interop \
-       --grpc_out=src/php/tests/interop \
+       --grpc_out=generate_server:src/php/tests/interop \
        --plugin=$PLUGIN \
        src/proto/grpc/testing/messages.proto \
        src/proto/grpc/testing/empty.proto \
@@ -53,12 +53,3 @@ mv $output_file ./src/proto/grpc/testing/empty.proto
 sed 's/grpc\.testing\.EmptyMessage/grpc\.testing\.Empty/g' \
   src/proto/grpc/testing/test.proto > $output_file
 mv $output_file ./src/proto/grpc/testing/test.proto
-
-# Hack for xDS interop: need this to be a separate file in the correct namespace.
-# To be removed when grpc_php_plugin generates service stubs.
-echo '<?php
-// DO NOT EDIT
-namespace Grpc\Testing;
-class LoadBalancerStatsServiceStub {
-}
-' > ./src/php/tests/interop/Grpc/Testing/LoadBalancerStatsServiceStub.php
index a77c364..3cea59f 100644 (file)
@@ -2,7 +2,7 @@
   "name": "grpc/grpc-dev",
   "description": "gRPC library for PHP - for Development use only",
   "license": "Apache-2.0",
-  "version": "1.37.1",
+  "version": "1.38.0",
   "require": {
     "php": ">=7.0.0",
     "google/protobuf": "^v3.3.0"
index 76d5537..da3a1a8 100644 (file)
@@ -20,6 +20,6 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define PHP_GRPC_VERSION "1.37.1"
+#define PHP_GRPC_VERSION "1.38.0"
 
 #endif /* VERSION_H */
index ed3b986..c631e58 100644 (file)
@@ -32,135 +32,120 @@ namespace Grpc;
  */
 class RpcServer extends Server
 {
-    protected $call;
-    // [ <String method_full_path> => [
-    //   'service' => <Object service>,
-    //   'method'  => <String method_name>,
-    //   'request' => <Object request>,
-    // ] ]
-    protected $paths_map;
+    // [ <String method_full_path> => MethodDescriptor ]
+    private $paths_map = [];
 
-    private function waitForNextEvent() {
+    private function waitForNextEvent()
+    {
         return $this->requestCall();
     }
 
-    private function loadRequest($request) {
-        if (!$this->call) {
-            throw new Exception("serverCall is not ready");
-        }
-        $event = $this->call->startBatch([
-            OP_RECV_MESSAGE => true,
-        ]);
-        $request->clear();
-        $request->mergeFromString($event->message);
-        return $request;
-    }
-
-    protected function sendOkResponse($response) {
-        if (!$this->call) {
-            throw new Exception("serverCall is not ready");
-        }
-        $this->call->startBatch([
-            OP_SEND_INITIAL_METADATA => [],
-            OP_SEND_MESSAGE => ['message' =>
-                                $response->serializeToString()],
-            OP_SEND_STATUS_FROM_SERVER => [
-                'metadata' => [],
-                'code' => STATUS_OK,
-                'details' => 'OK',
-            ],
-            OP_RECV_CLOSE_ON_SERVER => true,
-        ]);
-    }
-
     /**
      * Add a service to this server
      *
      * @param Object   $service      The service to be added
      */
-    public function handle($service) {
-        $rf = new \ReflectionClass($service);
-
-        // If input does not have a parent class, which should be the
-        // generated stub, don't proceeed. This might change in the
-        // future.
-        if (!$rf->getParentClass()) return;
-
-        // The input class name needs to match the service name
-        $service_name = $rf->getName();
-        $namespace = $rf->getParentClass()->getNamespaceName();
-        $prefix = "";
-        if ($namespace) {
-            $parts = explode("\\", $namespace);
-            foreach ($parts as $part) {
-                $prefix .= lcfirst($part) . ".";
-            }
+    public function handle($service)
+    {
+        $methodDescriptors = $service->getMethodDescriptors();
+        $exist_methods = array_intersect_key($this->paths_map, $methodDescriptors);
+        if (!empty($exist_methods)) {
+            fwrite(STDERR, "WARNING: " . 'override already registered methods: ' .
+                implode(', ', array_keys($exist_methods)) . PHP_EOL);
         }
-        $base_path = "/" . $prefix . $service_name;
-
-        // Right now, assume all the methods in the class are RPC method
-        // implementations. Might change in the future.
-        $methods = $rf->getMethods();
-        foreach ($methods as $method) {
-            $method_name = $method->getName();
-            $full_path = $base_path . "/" . ucfirst($method_name);
-
-            $method_params = $method->getParameters();
-            // RPC should have exactly 1 request param
-            if (count($method_params) != 1) continue;
-            $request_param = $method_params[0];
-            // Method implementation must have type hint for request param
-            if (!$request_param->getType()) continue;
-            $request_type = $request_param->getType()->getName();
 
-            // $full_path needs to match the incoming event->method
-            // from requestCall() for us to know how to handle the request
-            $this->paths_map[$full_path] = [
-                'service' => $service,
-                'method' => $method_name,
-                'request' => new $request_type(),
-            ];
-        }
+        $this->paths_map = array_merge($this->paths_map, $methodDescriptors);
+        return $this->paths_map;
     }
 
-    public function run() {
+    public function run()
+    {
         $this->start();
-        while (true) {
+        while (true) try {
             // This blocks until the server receives a request
             $event = $this->waitForNextEvent();
-            if (!$event) {
-                throw new Exception(
-                    "Unexpected error: server->waitForNextEvent delivers"
-                    . " an empty event");
-            }
-            if (!$event->call) {
-                throw new Exception(
-                    "Unexpected error: server->waitForNextEvent delivers"
-                    . " an event without a call");
-            }
-            $this->call = $event->call;
-            $full_path = $event->method;
-
-            // TODO: Can send a proper UNIMPLEMENTED response in the future
-            if (!array_key_exists($full_path, $this->paths_map)) continue;
 
-            $service = $this->paths_map[$full_path]['service'];
-            $method = $this->paths_map[$full_path]['method'];
-            $request = $this->paths_map[$full_path]['request'];
-
-            $request = $this->loadRequest($request);
-            if (!$request) {
-                throw new Exception("Unexpected error: fail to parse request");
-            }
-            if (!method_exists($service, $method)) {
-                // TODO: Can send a proper UNIMPLEMENTED response in the future
-                throw new Exception("Method not implemented");
+            $full_path = $event->method;
+            $context = new ServerContext($event);
+            $server_writer = new ServerCallWriter($event->call, $context);
+
+            if (!array_key_exists($full_path, $this->paths_map)) {
+                $context->setStatus(Status::unimplemented());
+                $server_writer->finish();
+                continue;
+            };
+
+            $method_desc = $this->paths_map[$full_path];
+            $server_reader = new ServerCallReader(
+                $event->call,
+                $method_desc->request_type
+            );
+
+            try {
+                $this->processCall(
+                    $method_desc,
+                    $server_reader,
+                    $server_writer,
+                    $context
+                );
+            } catch (\Exception $e) {
+                $context->setStatus(Status::status(
+                    STATUS_INTERNAL,
+                    $e->getMessage()
+                ));
+                $server_writer->finish();
             }
+        } catch (\Exception $e) {
+            fwrite(STDERR, "ERROR: " . $e->getMessage() . PHP_EOL);
+            exit(1);
+        }
+    }
 
-            // Dispatch to actual server logic
-            $response = $service->$method($request);
-            $this->sendOkResponse($response);
-            $this->call = null;
+    private function processCall(
+        MethodDescriptor $method_desc,
+        ServerCallReader $server_reader,
+        ServerCallWriter $server_writer,
+        ServerContext $context
+    ) {
+        // Dispatch to actual server logic
+        switch ($method_desc->call_type) {
+            case MethodDescriptor::UNARY_CALL:
+                $request = $server_reader->read();
+                $response =
+                    call_user_func(
+                        array($method_desc->service, $method_desc->method_name),
+                        $request ?? new $method_desc->request_type,
+                        $context
+                    );
+                $server_writer->finish($response);
+                break;
+            case MethodDescriptor::SERVER_STREAMING_CALL:
+                $request = $server_reader->read();
+                call_user_func(
+                    array($method_desc->service, $method_desc->method_name),
+                    $request ?? new $method_desc->request_type,
+                    $server_writer,
+                    $context
+                );
+                break;
+            case MethodDescriptor::CLIENT_STREAMING_CALL:
+                $response = call_user_func(
+                    array($method_desc->service, $method_desc->method_name),
+                    $server_reader,
+                    $context
+                );
+                $server_writer->finish($response);
+                break;
+            case MethodDescriptor::BIDI_STREAMING_CALL:
+                call_user_func(
+                    array($method_desc->service, $method_desc->method_name),
+                    $server_reader,
+                    $server_writer,
+                    $context
+                );
+                break;
+            default:
+                throw new \Exception();
         }
     }
 }
index f9d8d9e..aceb20c 100644 (file)
@@ -28,44 +28,51 @@ namespace Grpc;
 
 class ServerCallWriter
 {
-    public function __construct($call)
+    public function __construct($call, $serverContext)
     {
         $this->call_ = $call;
+        $this->serverContext_ = $serverContext;
     }
 
     public function start(
-        array $initialMetadata,
         $data = null,
         array $options = []
     ) {
         $batch = [];
-        $this->addSendInitialMetadataOpIfNotSent($batch, $initialMetadata);
+        $this->addSendInitialMetadataOpIfNotSent(
+            $batch,
+            $this->serverContext_->initialMetadata()
+        );
         $this->addSendMessageOpIfHasData($batch, $data, $options);
         $this->call_->startBatch($batch);
     }
 
     public function write(
         $data,
-        array $options = [],
-        array $initialMetadata = null
+        array $options = []
     ) {
         $batch = [];
-        $this->addSendInitialMetadataOpIfNotSent($batch, $initialMetadata);
+        $this->addSendInitialMetadataOpIfNotSent(
+            $batch,
+            $this->serverContext_->initialMetadata()
+        );
         $this->addSendMessageOpIfHasData($batch, $data, $options);
         $this->call_->startBatch($batch);
     }
 
     public function finish(
-        array $status = null,
-        array $initialMetadata = null,
         $data = null,
         array $options = []
     ) {
         $batch = [
-            OP_SEND_STATUS_FROM_SERVER => $status ?? Status::ok(),
+            OP_SEND_STATUS_FROM_SERVER =>
+            $this->serverContext_->status() ?? Status::ok(),
             OP_RECV_CLOSE_ON_SERVER => true,
         ];
-        $this->addSendInitialMetadataOpIfNotSent($batch, $initialMetadata);
+        $this->addSendInitialMetadataOpIfNotSent(
+            $batch,
+            $this->serverContext_->initialMetadata()
+        );
         $this->addSendMessageOpIfHasData($batch, $data, $options);
         $this->call_->startBatch($batch);
     }
@@ -98,4 +105,5 @@ class ServerCallWriter
 
     private $call_;
     private $initialMetadataSent_ = false;
+    private $serverContext_;
 }
index e177ae0..104250e 100644 (file)
@@ -50,5 +50,27 @@ class ServerContext
         return $this->event->method;
     }
 
+    public function setInitialMetadata($initialMetadata)
+    {
+        $this->initialMetadata_ = $initialMetadata;
+    }
+
+    public function initialMetadata()
+    {
+        return $this->initialMetadata_;
+    }
+
+    public function setStatus($status)
+    {
+        $this->status_ = $status;
+    }
+
+    public function status()
+    {
+        return $this->status_;
+    }
+
     private $event;
+    private $initialMetadata_;
+    private $status_;
 }
index 529f5b0..f99f489 100644 (file)
@@ -1,6 +1,82 @@
 <?php
-// DO NOT EDIT
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// Copyright 2015-2016 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+//
 namespace Grpc\Testing;
+
+/**
+ * A service used to obtain stats for verifying LB behavior.
+ */
 class LoadBalancerStatsServiceStub {
-}
 
+    /**
+     * Gets the backend distribution for RPCs sent by a test client.
+     * @param \Grpc\Testing\LoadBalancerStatsRequest $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\LoadBalancerStatsResponse for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function GetClientStats(
+        \Grpc\Testing\LoadBalancerStatsRequest $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\LoadBalancerStatsResponse {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * Gets the accumulated stats for RPCs sent by a test client.
+     * @param \Grpc\Testing\LoadBalancerAccumulatedStatsRequest $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\LoadBalancerAccumulatedStatsResponse for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function GetClientAccumulatedStats(
+        \Grpc\Testing\LoadBalancerAccumulatedStatsRequest $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\LoadBalancerAccumulatedStatsResponse {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * Get the method descriptors of the service for server registration
+     *
+     * @return array of \Grpc\MethodDescriptor for the service methods
+     */
+    public final function getMethodDescriptors(): array
+    {
+        return [
+            '/grpc.testing.LoadBalancerStatsService/GetClientStats' => new \Grpc\MethodDescriptor(
+                $this,
+                'GetClientStats',
+                '\Grpc\Testing\LoadBalancerStatsRequest',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+            '/grpc.testing.LoadBalancerStatsService/GetClientAccumulatedStats' => new \Grpc\MethodDescriptor(
+                $this,
+                'GetClientAccumulatedStats',
+                '\Grpc\Testing\LoadBalancerAccumulatedStatsRequest',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+        ];
+    }
+
+}
diff --git a/src/php/tests/interop/Grpc/Testing/ReconnectServiceStub.php b/src/php/tests/interop/Grpc/Testing/ReconnectServiceStub.php
new file mode 100644 (file)
index 0000000..450ecc0
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// Copyright 2015-2016 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+//
+namespace Grpc\Testing;
+
+/**
+ * A service used to control reconnect server.
+ */
+class ReconnectServiceStub {
+
+    /**
+     * @param \Grpc\Testing\ReconnectParams $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\EmptyMessage for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function Start(
+        \Grpc\Testing\ReconnectParams $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\EmptyMessage {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * @param \Grpc\Testing\EmptyMessage $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\ReconnectInfo for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function Stop(
+        \Grpc\Testing\EmptyMessage $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\ReconnectInfo {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * Get the method descriptors of the service for server registration
+     *
+     * @return array of \Grpc\MethodDescriptor for the service methods
+     */
+    public final function getMethodDescriptors(): array
+    {
+        return [
+            '/grpc.testing.ReconnectService/Start' => new \Grpc\MethodDescriptor(
+                $this,
+                'Start',
+                '\Grpc\Testing\ReconnectParams',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+            '/grpc.testing.ReconnectService/Stop' => new \Grpc\MethodDescriptor(
+                $this,
+                'Stop',
+                '\Grpc\Testing\EmptyMessage',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+        ];
+    }
+
+}
diff --git a/src/php/tests/interop/Grpc/Testing/TestServiceStub.php b/src/php/tests/interop/Grpc/Testing/TestServiceStub.php
new file mode 100644 (file)
index 0000000..d6c3fac
--- /dev/null
@@ -0,0 +1,222 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// Copyright 2015-2016 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+//
+namespace Grpc\Testing;
+
+/**
+ * A simple service to test the various types of RPCs and experiment with
+ * performance with various types of payload.
+ */
+class TestServiceStub {
+
+    /**
+     * One empty request followed by one empty response.
+     * @param \Grpc\Testing\EmptyMessage $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\EmptyMessage for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function EmptyCall(
+        \Grpc\Testing\EmptyMessage $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\EmptyMessage {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * One request followed by one response.
+     * @param \Grpc\Testing\SimpleRequest $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\SimpleResponse for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function UnaryCall(
+        \Grpc\Testing\SimpleRequest $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\SimpleResponse {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * One request followed by one response. Response has cache control
+     * headers set such that a caching HTTP proxy (such as GFE) can
+     * satisfy subsequent requests.
+     * @param \Grpc\Testing\SimpleRequest $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\SimpleResponse for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function CacheableUnaryCall(
+        \Grpc\Testing\SimpleRequest $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\SimpleResponse {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * One request followed by a sequence of responses (streamed download).
+     * The server returns the payload with client desired type and sizes.
+     * @param \Grpc\Testing\StreamingOutputCallRequest $request client request
+     * @param \Grpc\ServerCallWriter $writer write response data of \Grpc\Testing\StreamingOutputCallResponse
+     * @param \Grpc\ServerContext $context server request context
+     * @return void
+     */
+    public function StreamingOutputCall(
+        \Grpc\Testing\StreamingOutputCallRequest $request,
+        \Grpc\ServerCallWriter $writer,
+        \Grpc\ServerContext $context
+    ): void {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        $writer->finish();
+    }
+
+    /**
+     * A sequence of requests followed by one response (streamed upload).
+     * The server returns the aggregated size of client payload as the result.
+     * @param \Grpc\ServerCallReader $reader read client request data of \Grpc\Testing\StreamingInputCallRequest
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\StreamingInputCallResponse for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function StreamingInputCall(
+        \Grpc\ServerCallReader $reader,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\StreamingInputCallResponse {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * A sequence of requests with each request served by the server immediately.
+     * As one request could lead to multiple responses, this interface
+     * demonstrates the idea of full duplexing.
+     * @param \Grpc\ServerCallReader $reader read client request data of \Grpc\Testing\StreamingOutputCallRequest
+     * @param \Grpc\ServerCallWriter $writer write response data of \Grpc\Testing\StreamingOutputCallResponse
+     * @param \Grpc\ServerContext $context server request context
+     * @return void
+     */
+    public function FullDuplexCall(
+        \Grpc\ServerCallReader $reader,
+        \Grpc\ServerCallWriter $writer,
+        \Grpc\ServerContext $context
+    ): void {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        $writer->finish();
+    }
+
+    /**
+     * A sequence of requests followed by a sequence of responses.
+     * The server buffers all the client requests and then serves them in order. A
+     * stream of responses are returned to the client when the server starts with
+     * first request.
+     * @param \Grpc\ServerCallReader $reader read client request data of \Grpc\Testing\StreamingOutputCallRequest
+     * @param \Grpc\ServerCallWriter $writer write response data of \Grpc\Testing\StreamingOutputCallResponse
+     * @param \Grpc\ServerContext $context server request context
+     * @return void
+     */
+    public function HalfDuplexCall(
+        \Grpc\ServerCallReader $reader,
+        \Grpc\ServerCallWriter $writer,
+        \Grpc\ServerContext $context
+    ): void {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        $writer->finish();
+    }
+
+    /**
+     * The test server will not implement this method. It will be used
+     * to test the behavior when clients call unimplemented methods.
+     * @param \Grpc\Testing\EmptyMessage $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\EmptyMessage for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function UnimplementedCall(
+        \Grpc\Testing\EmptyMessage $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\EmptyMessage {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * Get the method descriptors of the service for server registration
+     *
+     * @return array of \Grpc\MethodDescriptor for the service methods
+     */
+    public final function getMethodDescriptors(): array
+    {
+        return [
+            '/grpc.testing.TestService/EmptyCall' => new \Grpc\MethodDescriptor(
+                $this,
+                'EmptyCall',
+                '\Grpc\Testing\EmptyMessage',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+            '/grpc.testing.TestService/UnaryCall' => new \Grpc\MethodDescriptor(
+                $this,
+                'UnaryCall',
+                '\Grpc\Testing\SimpleRequest',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+            '/grpc.testing.TestService/CacheableUnaryCall' => new \Grpc\MethodDescriptor(
+                $this,
+                'CacheableUnaryCall',
+                '\Grpc\Testing\SimpleRequest',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+            '/grpc.testing.TestService/StreamingOutputCall' => new \Grpc\MethodDescriptor(
+                $this,
+                'StreamingOutputCall',
+                '\Grpc\Testing\StreamingOutputCallRequest',
+                \Grpc\MethodDescriptor::SERVER_STREAMING_CALL
+            ),
+            '/grpc.testing.TestService/StreamingInputCall' => new \Grpc\MethodDescriptor(
+                $this,
+                'StreamingInputCall',
+                '\Grpc\Testing\StreamingInputCallRequest',
+                \Grpc\MethodDescriptor::CLIENT_STREAMING_CALL
+            ),
+            '/grpc.testing.TestService/FullDuplexCall' => new \Grpc\MethodDescriptor(
+                $this,
+                'FullDuplexCall',
+                '\Grpc\Testing\StreamingOutputCallRequest',
+                \Grpc\MethodDescriptor::BIDI_STREAMING_CALL
+            ),
+            '/grpc.testing.TestService/HalfDuplexCall' => new \Grpc\MethodDescriptor(
+                $this,
+                'HalfDuplexCall',
+                '\Grpc\Testing\StreamingOutputCallRequest',
+                \Grpc\MethodDescriptor::BIDI_STREAMING_CALL
+            ),
+            '/grpc.testing.TestService/UnimplementedCall' => new \Grpc\MethodDescriptor(
+                $this,
+                'UnimplementedCall',
+                '\Grpc\Testing\EmptyMessage',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+        ];
+    }
+
+}
diff --git a/src/php/tests/interop/Grpc/Testing/UnimplementedServiceStub.php b/src/php/tests/interop/Grpc/Testing/UnimplementedServiceStub.php
new file mode 100644 (file)
index 0000000..086cca2
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// Copyright 2015-2016 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+//
+namespace Grpc\Testing;
+
+/**
+ * A simple service NOT implemented at servers so clients can test for
+ * that case.
+ */
+class UnimplementedServiceStub {
+
+    /**
+     * A call that no server should implement
+     * @param \Grpc\Testing\EmptyMessage $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\EmptyMessage for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function UnimplementedCall(
+        \Grpc\Testing\EmptyMessage $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\EmptyMessage {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * Get the method descriptors of the service for server registration
+     *
+     * @return array of \Grpc\MethodDescriptor for the service methods
+     */
+    public final function getMethodDescriptors(): array
+    {
+        return [
+            '/grpc.testing.UnimplementedService/UnimplementedCall' => new \Grpc\MethodDescriptor(
+                $this,
+                'UnimplementedCall',
+                '\Grpc\Testing\EmptyMessage',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+        ];
+    }
+
+}
index a167897..fb3bb1c 100644 (file)
@@ -1,6 +1,61 @@
 <?php
-// DO NOT EDIT
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// Copyright 2015-2016 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+//
 namespace Grpc\Testing;
+
+/**
+ * A service to dynamically update the configuration of an xDS test client.
+ */
 class XdsUpdateClientConfigureServiceStub {
-}
 
+    /**
+     * Update the tes client's configuration.
+     * @param \Grpc\Testing\ClientConfigureRequest $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\ClientConfigureResponse for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function Configure(
+        \Grpc\Testing\ClientConfigureRequest $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\ClientConfigureResponse {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * Get the method descriptors of the service for server registration
+     *
+     * @return array of \Grpc\MethodDescriptor for the service methods
+     */
+    public final function getMethodDescriptors(): array
+    {
+        return [
+            '/grpc.testing.XdsUpdateClientConfigureService/Configure' => new \Grpc\MethodDescriptor(
+                $this,
+                'Configure',
+                '\Grpc\Testing\ClientConfigureRequest',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+        ];
+    }
+
+}
diff --git a/src/php/tests/interop/Grpc/Testing/XdsUpdateHealthServiceStub.php b/src/php/tests/interop/Grpc/Testing/XdsUpdateHealthServiceStub.php
new file mode 100644 (file)
index 0000000..07ff63a
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// Copyright 2015-2016 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+//
+namespace Grpc\Testing;
+
+/**
+ * A service to remotely control health status of an xDS test server.
+ */
+class XdsUpdateHealthServiceStub {
+
+    /**
+     * @param \Grpc\Testing\EmptyMessage $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\EmptyMessage for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function SetServing(
+        \Grpc\Testing\EmptyMessage $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\EmptyMessage {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * @param \Grpc\Testing\EmptyMessage $request client request
+     * @param \Grpc\ServerContext $context server request context
+     * @return \Grpc\Testing\EmptyMessage for response data, null if if error occured
+     *     initial metadata (if any) and status (if not ok) should be set to $context
+     */
+    public function SetNotServing(
+        \Grpc\Testing\EmptyMessage $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\EmptyMessage {
+        $context->setStatus(\Grpc\Status::unimplemented());
+        return null;
+    }
+
+    /**
+     * Get the method descriptors of the service for server registration
+     *
+     * @return array of \Grpc\MethodDescriptor for the service methods
+     */
+    public final function getMethodDescriptors(): array
+    {
+        return [
+            '/grpc.testing.XdsUpdateHealthService/SetServing' => new \Grpc\MethodDescriptor(
+                $this,
+                'SetServing',
+                '\Grpc\Testing\EmptyMessage',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+            '/grpc.testing.XdsUpdateHealthService/SetNotServing' => new \Grpc\MethodDescriptor(
+                $this,
+                'SetNotServing',
+                '\Grpc\Testing\EmptyMessage',
+                \Grpc\MethodDescriptor::UNARY_CALL
+            ),
+        ];
+    }
+
+}
index b814652..c2e3cfc 100644 (file)
@@ -28,7 +28,10 @@ require_once $autoload_path;
 class XdsUpdateClientConfigureService
         extends \Grpc\Testing\XdsUpdateClientConfigureServiceStub
 {
-    function configure(\Grpc\Testing\ClientConfigureRequest $request) {
+    function configure(
+        \Grpc\Testing\ClientConfigureRequest $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\ClientConfigureResponse {
         $rpc_types = $request->getTypes();
         $all_metadata = $request->getMetadata();
         $rpcs_to_send = [];
@@ -75,7 +78,10 @@ class XdsUpdateClientConfigureService
 class LoadBalancerStatsService
     extends \Grpc\Testing\LoadBalancerStatsServiceStub
 {
-    function getClientStats(\Grpc\Testing\LoadBalancerStatsRequest $request) {
+    function getClientStats(
+        \Grpc\Testing\LoadBalancerStatsRequest $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\LoadBalancerStatsResponse {
         $num_rpcs = $request->getNumRpcs();
         $timeout_sec = $request->getTimeoutSec();
         $rpcs_by_method = [];
@@ -155,8 +161,10 @@ class LoadBalancerStatsService
         return $response;
     }
 
-    function getClientAccumulatedStats(
-        \Grpc\Testing\LoadBalancerAccumulatedStatsRequest $request) {
+    function GetClientAccumulatedStats(
+        \Grpc\Testing\LoadBalancerAccumulatedStatsRequest $request,
+        \Grpc\ServerContext $context
+    ): ?\Grpc\Testing\LoadBalancerAccumulatedStatsResponse {
         global $client_thread;
         $response = new Grpc\Testing\LoadBalancerAccumulatedStatsResponse();
         $response->setNumRpcsStartedByMethod(
diff --git a/src/php/tests/unit_tests/RpcServerTest.php b/src/php/tests/unit_tests/RpcServerTest.php
new file mode 100644 (file)
index 0000000..26e884a
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+/*
+ *
+ * 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.
+ *
+ */
+
+require_once(dirname(__FILE__) . '/../../lib/Grpc/ServerCallReader.php');
+require_once(dirname(__FILE__) . '/../../lib/Grpc/ServerCallWriter.php');
+require_once(dirname(__FILE__) . '/../../lib/Grpc/Status.php');
+require_once(dirname(__FILE__) . '/../../lib/Grpc/MethodDescriptor.php');
+require_once(dirname(__FILE__) . '/../../lib/Grpc/RpcServer.php');
+
+class RpcServerTest extends \PHPUnit\Framework\TestCase
+{
+    public function setUp(): void
+    {
+        $this->server = new \Grpc\RpcServer();
+        $this->mockService = $this->getMockBuilder(stdClass::class)
+            ->setMethods(['getMethodDescriptors', 'hello'])
+            ->getMock();
+    }
+
+    public function testHandleServices()
+    {
+        $helloMethodDescriptor = new \Grpc\MethodDescriptor(
+            $this->mockService,
+            'hello',
+            'String',
+            \Grpc\MethodDescriptor::UNARY_CALL
+        );
+        $this->mockService->expects($this->once())
+            ->method('getMethodDescriptors')
+            ->with()
+            ->will($this->returnValue([
+                '/test/hello' => $helloMethodDescriptor
+            ]));
+
+        $pathMap = $this->server->handle($this->mockService);
+        $this->assertEquals($pathMap, [
+            '/test/hello' => $helloMethodDescriptor
+        ]);
+
+        $mockService2 = $this->getMockBuilder(stdClass::class)
+            ->setMethods(['getMethodDescriptors', 'hello', 'bye'])
+            ->getMock();
+        $helloMethodDescriptor2 = new \Grpc\MethodDescriptor(
+            $this->mockService,
+            'hello',
+            'Number',
+            \Grpc\MethodDescriptor::UNARY_CALL
+        );
+        $byeMethodDescritor = new \Grpc\MethodDescriptor(
+            $this->mockService,
+            'bye',
+            'String',
+            \Grpc\MethodDescriptor::UNARY_CALL
+        );
+        $mockService2->expects($this->once())
+            ->method('getMethodDescriptors')
+            ->with()
+            ->will($this->returnValue([
+                '/test/hello' => $helloMethodDescriptor2,
+                '/test/bye' => $byeMethodDescritor
+            ]));
+
+        $pathMap = $this->server->handle($mockService2);
+        $this->assertEquals($pathMap, [
+            '/test/hello' => $helloMethodDescriptor2,
+            '/test/bye' => $byeMethodDescritor
+        ]);
+    }
+}
index 8090c1c..e6b474e 100644 (file)
 require_once(dirname(__FILE__) . '/../../lib/Grpc/ServerCallReader.php');
 require_once(dirname(__FILE__) . '/../../lib/Grpc/ServerCallWriter.php');
 require_once(dirname(__FILE__) . '/../../lib/Grpc/Status.php');
-
-// load protobuf from third_party
-set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/../../../../third_party/protobuf/php/src/');
-
-spl_autoload_register(function ($className) {
-$classPath = str_replace('\\', DIRECTORY_SEPARATOR, $className);
-if (strpos($classPath, 'Google/Protobuf') === 0 || strpos($classPath, 'GPBMetadata/Google/Protobuf') === 0) {
-require_once($classPath . '.php');
-}
-});
+require_once(dirname(__FILE__) . '/../../lib/Grpc/ServerContext.php');
 
 class StartBatchEvent
 {
@@ -40,6 +31,31 @@ class StartBatchEvent
     public $message;
 }
 
+class StringValue
+{
+    public function setValue(string $value)
+    {
+        $this->value = $value;
+    }
+
+    public function getValue(): string
+    {
+        return $this->value;
+    }
+
+    public function serializeToString(): string
+    {
+        return $this->value;
+    }
+
+    public function mergeFromString(string $value)
+    {
+        $this->value = $value;
+    }
+
+    private $value = '';
+}
+
 class ServerCallTest extends \PHPUnit\Framework\TestCase
 {
     public function setUp(): void
@@ -47,11 +63,12 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
         $this->mockCall = $this->getMockBuilder(stdClass::class)
             ->setMethods(['startBatch'])
             ->getMock();
+        $this->serverContext = new \Grpc\ServerContext($this->mockCall);
     }
 
     public function newStringMessage(string $value = 'a string')
     {
-        $message = new \Google\Protobuf\StringValue();
+        $message = new StringValue();
         $message->setValue($value);
         return $message;
     }
@@ -68,7 +85,7 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
 
         $serverCallReader = new \Grpc\ServerCallReader(
             $this->mockCall,
-            '\Google\Protobuf\StringValue'
+            '\StringValue'
         );
         $return = $serverCallReader->read();
         $this->assertEquals($message, $return);
@@ -82,8 +99,12 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 \Grpc\OP_SEND_INITIAL_METADATA => [],
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
-        $serverCallWriter->start([]);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
+        $this->serverContext->setInitialMetadata([]);
+        $serverCallWriter->start();
     }
 
     public function testStartWithMetadata()
@@ -96,8 +117,12 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 \Grpc\OP_SEND_INITIAL_METADATA => $metadata,
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
-        $serverCallWriter->start($metadata);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
+        $this->serverContext->setInitialMetadata($metadata);
+        $serverCallWriter->start();
         return $serverCallWriter;
     }
 
@@ -113,8 +138,12 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 \Grpc\OP_SEND_MESSAGE => ['message' => $message->serializeToString()],
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
-        $serverCallWriter->start($metadata, $message);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
+        $this->serverContext->setInitialMetadata($metadata);
+        $serverCallWriter->start($message);
     }
 
     public function testWriteStartWithMessageAndOptions()
@@ -132,8 +161,12 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 ],
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
-        $serverCallWriter->start($metadata, $message, ['flags' => 0x02]);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
+        $this->serverContext->setInitialMetadata($metadata);
+        $serverCallWriter->start($message, ['flags' => 0x02]);
     }
 
     public function testWriteDataOnly()
@@ -147,7 +180,10 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 \Grpc\OP_SEND_MESSAGE => ['message' => $message->serializeToString()],
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
         $serverCallWriter->write($message);
     }
 
@@ -165,7 +201,10 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 ],
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
         $serverCallWriter->write($message, ['flags' => 0x02]);
     }
 
@@ -181,8 +220,12 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 \Grpc\OP_SEND_MESSAGE => ['message' => $message->serializeToString()],
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
-        $serverCallWriter->write($message, [], $metadata);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
+        $this->serverContext->setInitialMetadata($metadata);
+        $serverCallWriter->write($message, []);
     }
 
     public function testFinish()
@@ -201,8 +244,12 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 \Grpc\OP_SEND_INITIAL_METADATA => [],
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
-        $serverCallWriter->finish($status);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
+        $this->serverContext->setStatus($status);
+        $serverCallWriter->finish();
     }
 
     public function testFinishWithMetadataAndMessage()
@@ -223,8 +270,13 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 ],
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
-        $serverCallWriter->finish($status, $metadata, $message, ['flags' => 0x02]);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
+        $this->serverContext->setInitialMetadata($metadata);
+        $this->serverContext->setStatus($status);
+        $serverCallWriter->finish($message, ['flags' => 0x02]);
     }
 
     public function testStartWriteFinish()
@@ -259,8 +311,12 @@ class ServerCallTest extends \PHPUnit\Framework\TestCase
                 \Grpc\OP_RECV_CLOSE_ON_SERVER => true,
             ]));
 
-        $serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
-        $serverCallWriter->start($metadata);
+        $serverCallWriter = new \Grpc\ServerCallWriter(
+            $this->mockCall,
+            $this->serverContext
+        );
+        $this->serverContext->setInitialMetadata($metadata);
+        $serverCallWriter->start();
         $serverCallWriter->write($message1, [], $metadata2 /* should not send */);
         $serverCallWriter->write($message2, ['flags' => 0x02]);
         $serverCallWriter->finish();
index f7a27c8..be730de 100644 (file)
@@ -15,6 +15,7 @@
 licenses(["notice"])  # Apache v2
 
 load("//bazel:grpc_build_system.bzl", "grpc_package", "grpc_proto_library")
+load("//bazel:python_rules.bzl", "py_grpc_library", "py_proto_library")
 
 grpc_package(
     name = "xds_v3",
@@ -278,3 +279,29 @@ grpc_proto_library(
         "route_proto",
     ],
 )
+
+py_proto_library(
+    name = "csds_py_pb2",
+    deps = [":_csds_proto_only"],
+)
+
+py_grpc_library(
+    name = "csds_py_pb2_grpc",
+    srcs = [":_csds_proto_only"],
+    deps = [":csds_py_pb2"],
+)
+
+py_proto_library(
+    name = "config_dump_py_pb2",
+    deps = [":_config_dump_proto_only"],
+)
+
+py_proto_library(
+    name = "base_py_pb2",
+    deps = [":_base_proto_only"],
+)
+
+py_proto_library(
+    name = "percent_py_pb2",
+    deps = [":_percent_proto_only"],
+)
index f4a3d2b..df8fc46 100644 (file)
@@ -258,10 +258,14 @@ class BuildExt(build_ext.build_ext):
             old_compile = self.compiler._compile
 
             def new_compile(obj, src, ext, cc_args, extra_postargs, pp_opts):
-                if src[-2:] == '.c':
+                if src.endswith('.c'):
                     extra_postargs = [
                         arg for arg in extra_postargs if not '-std=c++' in arg
                     ]
+                elif src.endswith('.cc') or src.endswith('.cpp'):
+                    extra_postargs = [
+                        arg for arg in extra_postargs if not '-std=gnu99' in arg
+                    ]
                 return old_compile(obj, src, ext, cc_args, extra_postargs,
                                    pp_opts)
 
index 69803ed..ea393c4 100644 (file)
@@ -1174,6 +1174,16 @@ class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)):
         """
         raise NotImplementedError()
 
+    def trailing_metadata(self):
+        """Access value to be used as trailing metadata upon RPC completion.
+
+        This is an EXPERIMENTAL API.
+
+        Returns:
+          The trailing :term:`metadata` for the RPC.
+        """
+        raise NotImplementedError()
+
     @abc.abstractmethod
     def abort(self, code, details):
         """Raises an exception to terminate the RPC with a non-OK status.
@@ -1237,6 +1247,26 @@ class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)):
         """
         raise NotImplementedError()
 
+    def code(self):
+        """Accesses the value to be used as status code upon RPC completion.
+
+        This is an EXPERIMENTAL API.
+
+        Returns:
+          The StatusCode value for the RPC.
+        """
+        raise NotImplementedError()
+
+    def details(self):
+        """Accesses the value to be used as detail string upon RPC completion.
+
+        This is an EXPERIMENTAL API.
+
+        Returns:
+          The details string of the RPC.
+        """
+        raise NotImplementedError()
+
     def disable_next_message_compression(self):
         """Disables compression for the next response message.
 
index 2c2a3ff..7bce185 100644 (file)
@@ -134,37 +134,38 @@ cdef class _AioCall(GrpcCallWrapper):
     cdef void _set_status(self, AioRpcStatus status) except *:
         cdef list waiters
 
+        # No more waiters should be expected since status has been set.
         self._status = status
 
         if self._initial_metadata is None:
             self._set_initial_metadata(_IMMUTABLE_EMPTY_METADATA)
 
-        # No more waiters should be expected since status
-        # has been set.
-        waiters = self._waiters_status
-        self._waiters_status = None
-
-        for waiter in waiters:
+        for waiter in self._waiters_status:
             if not waiter.done():
                 waiter.set_result(None)
+        self._waiters_status = []
 
         for callback in self._done_callbacks:
             callback()
 
     cdef void _set_initial_metadata(self, tuple initial_metadata) except *:
+        if self._initial_metadata is not None:
+            # Some gRPC calls might end before the initial metadata arrived in
+            # the Call object. That causes this method to be invoked twice: 1.
+            # filled with an empty metadata; 2. updated with the actual user
+            # provided metadata.
+            return
+
         cdef list waiters
 
+        # No more waiters should be expected since initial metadata has been
+        # set.
         self._initial_metadata = initial_metadata
 
-        # No more waiters should be expected since initial metadata
-        # has been set.
-        waiters = self._waiters_initial_metadata
-        self._waiters_initial_metadata = None
-
-        for waiter in waiters:
+        for waiter in self._waiters_initial_metadata:
             if not waiter.done():
                 waiter.set_result(None)
-
+        self._waiters_initial_metadata = []
 
     def add_done_callback(self, callback):
         if self.done():
index 917ae24..86171de 100644 (file)
@@ -31,13 +31,13 @@ cdef grpc_custom_poller_vtable asyncio_pollset_vtable
 cdef bint so_reuse_port
 
 
-cdef grpc_error* asyncio_socket_init(
+cdef grpc_error_handle asyncio_socket_init(
         grpc_custom_socket* grpc_socket,
         int domain) with gil:
     socket = _AsyncioSocket.create(grpc_socket, None, None)
     Py_INCREF(socket)
     grpc_socket.impl = <void*>socket
-    return <grpc_error*>0
+    return <grpc_error_handle>0
 
 
 cdef void asyncio_socket_destroy(grpc_custom_socket* grpc_socket) with gil:
@@ -84,7 +84,7 @@ cdef void asyncio_socket_read(
     socket.read(buffer_, length, read_cb)
 
 
-cdef grpc_error* asyncio_socket_getpeername(
+cdef grpc_error_handle asyncio_socket_getpeername(
         grpc_custom_socket* grpc_socket,
         const grpc_sockaddr* addr,
         int* length) with gil:
@@ -99,7 +99,7 @@ cdef grpc_error* asyncio_socket_getpeername(
     return grpc_error_none()
 
 
-cdef grpc_error* asyncio_socket_getsockname(
+cdef grpc_error_handle asyncio_socket_getsockname(
         grpc_custom_socket* grpc_socket,
         const grpc_sockaddr* addr,
         int* length) with gil:
@@ -118,7 +118,7 @@ cdef grpc_error* asyncio_socket_getsockname(
     return grpc_error_none()
 
 
-cdef grpc_error* asyncio_socket_listen(grpc_custom_socket* grpc_socket) with gil:
+cdef grpc_error_handle asyncio_socket_listen(grpc_custom_socket* grpc_socket) with gil:
     (<_AsyncioSocket>grpc_socket.impl).listen()
     return grpc_error_none()
 
@@ -134,7 +134,7 @@ def _asyncio_apply_socket_options(object s, int flags):
     s.setsockopt(native_socket.IPPROTO_TCP, native_socket.TCP_NODELAY, True)
 
 
-cdef grpc_error* asyncio_socket_bind(
+cdef grpc_error_handle asyncio_socket_bind(
         grpc_custom_socket* grpc_socket,
         const grpc_sockaddr* addr,
         size_t len, int flags) with gil:
@@ -166,7 +166,7 @@ cdef void asyncio_socket_accept(
     (<_AsyncioSocket>grpc_socket.impl).accept(grpc_socket_client, accept_cb)
 
 
-cdef grpc_error* asyncio_resolve(
+cdef grpc_error_handle asyncio_resolve(
         const char* host,
         const char* port,
         grpc_resolved_addresses** res) with gil:
index 1a2e244..64e3e63 100644 (file)
@@ -45,7 +45,7 @@ cdef class _AsyncioResolver:
             grpc_custom_resolve_callback(
                 <grpc_custom_resolver*>self._grpc_resolver,
                 tuples_to_resolvaddr(resolved),
-                <grpc_error*>0
+                <grpc_error_handle>0
             )
 
     cdef void resolve(self, const char* host, const char* port):
index eecef17..43817ef 100644 (file)
@@ -81,7 +81,7 @@ cdef class _AsyncioSocket:
 
             self._grpc_connect_cb(
                 <grpc_custom_socket*>self._grpc_socket,
-                <grpc_error*>0
+                <grpc_error_handle>0
             )
 
     cdef void connect(self,
@@ -115,7 +115,7 @@ cdef class _AsyncioSocket:
             self._grpc_read_cb(
                 <grpc_custom_socket*>self._grpc_socket,
                 len(inbound_buffer),
-                <grpc_error*>0
+                <grpc_error_handle>0
             )
 
     cdef void read(self, char * buffer_, size_t length, grpc_custom_read_callback grpc_read_cb):
@@ -132,7 +132,7 @@ cdef class _AsyncioSocket:
             await self._writer.drain()
             self._grpc_write_cb(
                 <grpc_custom_socket*>self._grpc_socket,
-                <grpc_error*>0
+                <grpc_error_handle>0
             )
         except ConnectionError as connection_error:
             self._grpc_write_cb(
index c150837..f2f7f49 100644 (file)
@@ -31,7 +31,7 @@ cdef class _AsyncioTimer:
 
     def on_time_up(self):
         self._active = False
-        grpc_custom_timer_callback(self._grpc_timer, <grpc_error*>0)
+        grpc_custom_timer_callback(self._grpc_timer, <grpc_error_handle>0)
         cpython.Py_DECREF(self)
 
     def __repr__(self):
index 38c0d71..2b46c0c 100644 (file)
@@ -197,15 +197,24 @@ cdef class _ServicerContext:
     def set_trailing_metadata(self, object metadata):
         self._rpc_state.trailing_metadata = tuple(metadata)
 
+    def trailing_metadata(self):
+        return self._rpc_state.trailing_metadata
+
     def invocation_metadata(self):
         return self._rpc_state.invocation_metadata()
 
     def set_code(self, object code):
         self._rpc_state.status_code = get_status_code(code)
 
+    def code(self):
+        return self._rpc_state.status_code
+
     def set_details(self, str details):
         self._rpc_state.status_details = details
 
+    def details(self):
+        return self._rpc_state.status_details
+
     def set_compression(self, object compression):
         if self._rpc_state.metadata_sent:
             raise RuntimeError('Compression setting must be specified before sending initial metadata')
index e7e5926..b2ca84f 100644 (file)
@@ -45,12 +45,17 @@ cdef int _get_metadata(void *state,
   cdef size_t metadata_count
   cdef grpc_metadata *c_metadata
   def callback(metadata, grpc_status_code status, bytes error_details):
+    cdef char* c_error_details = NULL
+    if error_details is not None:
+      c_error_details = <char*> error_details
     if status == StatusCode.ok:
       _store_c_metadata(metadata, &c_metadata, &metadata_count)
-      cb(user_data, c_metadata, metadata_count, status, NULL)
+      with nogil:
+        cb(user_data, c_metadata, metadata_count, status, NULL)
       _release_c_metadata(c_metadata, metadata_count)
     else:
-      cb(user_data, NULL, 0, status, error_details)
+      with nogil:
+        cb(user_data, NULL, 0, status, c_error_details)
   args = context.service_url, context.method_name, callback,
   _spawn_callback_async(<object>state, args)
   return 0  # Asynchronous return
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/csds.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/csds.pyx.pxi
new file mode 100644 (file)
index 0000000..c33eb76
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+def dump_xds_configs():
+    cdef grpc_slice client_config_in_slice
+    with nogil:
+        client_config_in_slice = grpc_dump_xds_configs()
+    cdef bytes result = _slice_bytes(client_config_in_slice)
+    return result
index 4d0c608..fb8ceae 100644 (file)
@@ -405,13 +405,14 @@ cdef extern from "grpc/grpc.h":
        grpc_server* server, grpc_server_config_fetcher* config_fetcher) nogil
 
   ctypedef struct grpc_server_xds_status_notifier:
-    void (*on_serving_status_change)(void* user_data, const char* uri,
+    void (*on_serving_status_update)(void* user_data, const char* uri,
                                    grpc_status_code code,
                                    const char* error_message)
     void* user_data;
 
   grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create(
-       grpc_server_xds_status_notifier notifier) nogil
+       grpc_server_xds_status_notifier notifier,
+       const grpc_channel_args* args) nogil
 
 
   int grpc_server_add_insecure_http2_port(
@@ -432,6 +433,8 @@ cdef extern from "grpc/grpc.h":
   char* grpc_channelz_get_subchannel(intptr_t subchannel_id)
   char* grpc_channelz_get_socket(intptr_t socket_id)
 
+  grpc_slice grpc_dump_xds_configs() nogil
+
 
 cdef extern from "grpc/grpc_security.h":
 
@@ -583,7 +586,7 @@ cdef extern from "grpc/grpc_security.h":
 
   ctypedef void (*grpc_credentials_plugin_metadata_cb)(
       void *user_data, const grpc_metadata *creds_md, size_t num_creds_md,
-      grpc_status_code status, const char *error_details)
+      grpc_status_code status, const char *error_details) nogil
 
   ctypedef struct grpc_metadata_credentials_plugin:
     int (*get_metadata)(
index d857317..c86ff2f 100644 (file)
@@ -41,7 +41,7 @@ cdef class SocketWrapper:
   def __dealloc__(self):
     grpc_shutdown()
 
-cdef grpc_error* socket_init(grpc_custom_socket* socket, int domain) with gil:
+cdef grpc_error_handle socket_init(grpc_custom_socket* socket, int domain) with gil:
   sw = SocketWrapper()
   sw.c_socket = socket
   sw.sockopts = []
@@ -168,7 +168,7 @@ cdef void socket_read(grpc_custom_socket* socket, char* buffer,
   sw.len = length
   _spawn_greenlet(socket_read_async, sw)
 
-cdef grpc_error* socket_getpeername(grpc_custom_socket* socket,
+cdef grpc_error_handle socket_getpeername(grpc_custom_socket* socket,
                                     const grpc_sockaddr* addr,
                                     int* length) with gil:
   cdef char* src_buf
@@ -181,7 +181,7 @@ cdef grpc_error* socket_getpeername(grpc_custom_socket* socket,
   length[0] = c_addr.len
   return grpc_error_none()  
 
-cdef grpc_error* socket_getsockname(grpc_custom_socket* socket,
+cdef grpc_error_handle socket_getsockname(grpc_custom_socket* socket,
                                     const grpc_sockaddr* addr,
                                     int* length) with gil:
   cdef char* src_buf
@@ -200,7 +200,7 @@ def applysockopts(s):
   s.setsockopt(gevent_socket.SOL_SOCKET, gevent_socket.SO_REUSEADDR, 1)
   s.setsockopt(gevent_socket.IPPROTO_TCP, gevent_socket.TCP_NODELAY, True)
 
-cdef grpc_error* socket_bind(grpc_custom_socket* socket,
+cdef grpc_error_handle socket_bind(grpc_custom_socket* socket,
                              const grpc_sockaddr* addr,
                              size_t len, int flags) with gil:
   addr_tuple = sockaddr_to_tuple(addr, len)
@@ -219,7 +219,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_handle socket_listen(grpc_custom_socket* socket) with gil:
   (<SocketWrapper>socket.impl).socket.listen(50)
   return grpc_error_none()
 
@@ -290,7 +290,7 @@ cdef void socket_resolve_async(grpc_custom_resolver* r, const char* host, const
   rw.c_port = port
   _spawn_greenlet(socket_resolve_async_python, rw)
 
-cdef grpc_error* socket_resolve(const char* host, const char* port,
+cdef grpc_error_handle socket_resolve(const char* host, const char* port,
                                 grpc_resolved_addresses** res) with gil:
     try:
       result = gevent_socket.getaddrinfo(host, port)
index 0c5a4e5..9cf3113 100644 (file)
@@ -23,11 +23,12 @@ cdef extern from "grpc/impl/codegen/slice.h":
 cdef extern from "src/core/lib/iomgr/error.h":
   struct grpc_error:
     pass
+  ctypedef grpc_error* grpc_error_handle
 
 # TODO(https://github.com/grpc/grpc/issues/20135) Change the filename
 # for something more meaningful.
 cdef extern from "src/core/lib/iomgr/python_util.h":
-  grpc_error* grpc_socket_error(char* error) 
+  grpc_error_handle grpc_socket_error(char* error) 
   char* grpc_slice_buffer_start(grpc_slice_buffer* buffer, int i)
   int grpc_slice_buffer_length(grpc_slice_buffer* buffer, int i)
 
@@ -49,12 +50,12 @@ cdef extern from "src/core/lib/iomgr/resolve_address_custom.h":
     pass
 
   struct grpc_custom_resolver_vtable:
-    grpc_error* (*resolve)(const char* host, const char* port, grpc_resolved_addresses** res);
+    grpc_error_handle (*resolve)(const char* host, const char* port, grpc_resolved_addresses** res);
     void (*resolve_async)(grpc_custom_resolver* resolver, const char* host, const char* port);
 
   void grpc_custom_resolve_callback(grpc_custom_resolver* resolver,
                                     grpc_resolved_addresses* result,
-                                    grpc_error* error);
+                                    grpc_error_handle error);
 
 cdef extern from "src/core/lib/iomgr/tcp_custom.h":
   cdef int GRPC_CUSTOM_SOCKET_OPT_SO_REUSEPORT
@@ -63,18 +64,18 @@ cdef extern from "src/core/lib/iomgr/tcp_custom.h":
     void* impl
     # We don't care about the rest of the fields
   ctypedef void (*grpc_custom_connect_callback)(grpc_custom_socket* socket,
-                                             grpc_error* error)
+                                             grpc_error_handle error)
   ctypedef void (*grpc_custom_write_callback)(grpc_custom_socket* socket,
-                                           grpc_error* error)
+                                           grpc_error_handle error)
   ctypedef void (*grpc_custom_read_callback)(grpc_custom_socket* socket,
-                                          size_t nread, grpc_error* error)
+                                          size_t nread, grpc_error_handle error)
   ctypedef void (*grpc_custom_accept_callback)(grpc_custom_socket* socket,
                                             grpc_custom_socket* client,
-                                            grpc_error* error)
+                                            grpc_error_handle error)
   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_handle (*init)(grpc_custom_socket* socket, int domain);
       void (*connect)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
                       size_t len, grpc_custom_connect_callback cb);
       void (*destroy)(grpc_custom_socket* socket);
@@ -84,13 +85,13 @@ cdef extern from "src/core/lib/iomgr/tcp_custom.h":
                     grpc_custom_write_callback cb);
       void (*read)(grpc_custom_socket* socket, char* buffer, size_t length,
                    grpc_custom_read_callback cb);
-      grpc_error* (*getpeername)(grpc_custom_socket* socket,
+      grpc_error_handle (*getpeername)(grpc_custom_socket* socket,
                                  const grpc_sockaddr* addr, int* len);
-      grpc_error* (*getsockname)(grpc_custom_socket* socket,
+      grpc_error_handle (*getsockname)(grpc_custom_socket* socket,
                              const grpc_sockaddr* addr, int* len);
-      grpc_error* (*bind)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
+      grpc_error_handle (*bind)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
                           size_t len, int flags);
-      grpc_error* (*listen)(grpc_custom_socket* socket);
+      grpc_error_handle (*listen)(grpc_custom_socket* socket);
       void (*accept)(grpc_custom_socket* socket, grpc_custom_socket* client,
                      grpc_custom_accept_callback cb);
 
@@ -104,7 +105,7 @@ cdef extern from "src/core/lib/iomgr/timer_custom.h":
     void (*start)(grpc_custom_timer* t);
     void (*stop)(grpc_custom_timer* t);
 
-  void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error);
+  void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error_handle error);
 
 cdef extern from "src/core/lib/iomgr/pollset_custom.h":
   struct grpc_custom_poller_vtable:
@@ -119,11 +120,11 @@ cdef extern from "src/core/lib/iomgr/iomgr_custom.h":
                             grpc_custom_timer_vtable* timer,
                             grpc_custom_poller_vtable* poller);
 
-cdef extern from "src/core/lib/iomgr/sockaddr_utils.h":
+cdef extern from "src/core/lib/address_utils/sockaddr_utils.h":
   int grpc_sockaddr_get_port(const grpc_resolved_address *addr);
   cppstring grpc_sockaddr_to_string(const grpc_resolved_address *addr,
                                     bool_t normalize);
-  void grpc_string_to_sockaddr(grpc_resolved_address *out, char* addr, int port);
+  grpc_error_handle grpc_string_to_sockaddr(grpc_resolved_address *out, char* addr, int port);
   int grpc_sockaddr_set_port(const grpc_resolved_address *resolved_addr,
                              int port)
   const char* grpc_sockaddr_get_uri_scheme(const grpc_resolved_address* resolved_addr)
index 3d6bb24..292e047 100644 (file)
@@ -17,10 +17,10 @@ from libc cimport string
 from libc.stdlib cimport malloc
 from libcpp.string cimport string as cppstring
 
-cdef grpc_error* grpc_error_none():
-  return <grpc_error*>0
+cdef grpc_error_handle grpc_error_none():
+  return <grpc_error_handle>0
 
-cdef grpc_error* socket_error(str syscall, str err):
+cdef grpc_error_handle socket_error(str syscall, str err):
   error_str = "{} failed: {}".format(syscall, err)
   error_bytes = str_to_bytes(error_str)
   return grpc_socket_error(error_bytes)
index ed1dda2..d3caf3a 100644 (file)
@@ -26,11 +26,11 @@ cdef class Server:
     cdef _ChannelArgs channel_args = _ChannelArgs(arguments)
     self.c_server = grpc_server_create(channel_args.c_args(), NULL)
     cdef grpc_server_xds_status_notifier notifier
-    notifier.on_serving_status_change = NULL
+    notifier.on_serving_status_update = NULL
     notifier.user_data = NULL
     if xds:
       grpc_server_set_config_fetcher(self.c_server,
-        grpc_server_config_fetcher_xds_create(notifier))
+        grpc_server_config_fetcher_xds_create(notifier, channel_args.c_args()))
     self.references.append(arguments)
 
   def request_call(
index 0ce8bda..b958975 100644 (file)
@@ -41,6 +41,7 @@ include "_cygrpc/arguments.pyx.pxi"
 include "_cygrpc/call.pyx.pxi"
 include "_cygrpc/channel.pyx.pxi"
 include "_cygrpc/channelz.pyx.pxi"
+include "_cygrpc/csds.pyx.pxi"
 include "_cygrpc/credentials.pyx.pxi"
 include "_cygrpc/completion_queue.pyx.pxi"
 include "_cygrpc/event.pyx.pxi"
index d182b9b..b38d887 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
 
-__version__ = """1.37.1"""
+__version__ = """1.38.0"""
index 069ffa7..6c6f02d 100644 (file)
@@ -305,6 +305,9 @@ class _Context(grpc.ServicerContext):
         with self._state.condition:
             self._state.trailing_metadata = trailing_metadata
 
+    def trailing_metadata(self):
+        return self._state.trailing_metadata
+
     def abort(self, code, details):
         # treat OK like other invalid arguments: fail the RPC
         if code == grpc.StatusCode.OK:
@@ -326,10 +329,16 @@ class _Context(grpc.ServicerContext):
         with self._state.condition:
             self._state.code = code
 
+    def code(self):
+        return self._state.code
+
     def set_details(self, details):
         with self._state.condition:
             self._state.details = _common.encode(details)
 
+    def details(self):
+        return self._state.details
+
     def _finalize_state(self):
         pass
 
index 7cbedf9..e22ef3e 100644 (file)
@@ -193,7 +193,7 @@ class ServicerContext(Generic[RequestType, ResponseType], abc.ABC):
         """
 
     @abc.abstractmethod
-    async def set_trailing_metadata(self, trailing_metadata: Metadata) -> None:
+    def set_trailing_metadata(self, trailing_metadata: Metadata) -> None:
         """Sends the trailing metadata for the RPC.
 
         This method need not be called by implementations if they have no
@@ -304,3 +304,33 @@ class ServicerContext(Generic[RequestType, ResponseType], abc.ABC):
           remaining for the RPC to complete before it is considered to have
           timed out, or None if no deadline was specified for the RPC.
         """
+
+    def trailing_metadata(self):
+        """Access value to be used as trailing metadata upon RPC completion.
+
+        This is an EXPERIMENTAL API.
+
+        Returns:
+          The trailing :term:`metadata` for the RPC.
+        """
+        raise NotImplementedError()
+
+    def code(self):
+        """Accesses the value to be used as status code upon RPC completion.
+
+        This is an EXPERIMENTAL API.
+
+        Returns:
+          The StatusCode value for the RPC.
+        """
+        raise NotImplementedError()
+
+    def details(self):
+        """Accesses the value to be used as detail string upon RPC completion.
+
+        This is an EXPERIMENTAL API.
+
+        Returns:
+          The details string of the RPC.
+        """
+        raise NotImplementedError()
index e7ee6a7..c8c4468 100644 (file)
@@ -67,6 +67,8 @@ CORE_SOURCE_FILES = [
     'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
     'src/core/ext/filters/client_channel/resolver_registry.cc',
     'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
+    'src/core/ext/filters/client_channel/retry_filter.cc',
+    'src/core/ext/filters/client_channel/retry_service_config.cc',
     'src/core/ext/filters/client_channel/retry_throttle.cc',
     'src/core/ext/filters/client_channel/server_address.cc',
     'src/core/ext/filters/client_channel/service_config.cc',
@@ -323,6 +325,8 @@ CORE_SOURCE_FILES = [
     'src/core/ext/xds/xds_http_fault_filter.cc',
     'src/core/ext/xds/xds_http_filters.cc',
     'src/core/ext/xds/xds_server_config_fetcher.cc',
+    'src/core/lib/address_utils/parse_address.cc',
+    'src/core/lib/address_utils/sockaddr_utils.cc',
     'src/core/lib/avl/avl.cc',
     'src/core/lib/backoff/backoff.cc',
     'src/core/lib/channel/channel_args.cc',
@@ -345,6 +349,8 @@ CORE_SOURCE_FILES = [
     'src/core/lib/debug/stats.cc',
     'src/core/lib/debug/stats_data.cc',
     'src/core/lib/debug/trace.cc',
+    'src/core/lib/event_engine/slice_allocator.cc',
+    'src/core/lib/event_engine/sockaddr.cc',
     'src/core/lib/gpr/alloc.cc',
     'src/core/lib/gpr/atm.cc',
     'src/core/lib/gpr/cpu_iphone.cc',
@@ -385,6 +391,7 @@ CORE_SOURCE_FILES = [
     'src/core/lib/gprpp/mpscq.cc',
     'src/core/lib/gprpp/stat_posix.cc',
     'src/core/lib/gprpp/stat_windows.cc',
+    'src/core/lib/gprpp/status_helper.cc',
     'src/core/lib/gprpp/thd_posix.cc',
     'src/core/lib/gprpp/thd_windows.cc',
     'src/core/lib/gprpp/time_util.cc',
@@ -433,8 +440,6 @@ CORE_SOURCE_FILES = [
     'src/core/lib/iomgr/is_epollexclusive_available.cc',
     'src/core/lib/iomgr/load_file.cc',
     'src/core/lib/iomgr/lockfree_event.cc',
-    'src/core/lib/iomgr/parse_address.cc',
-    'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
     'src/core/lib/iomgr/polling_entity.cc',
     'src/core/lib/iomgr/pollset.cc',
     'src/core/lib/iomgr/pollset_custom.cc',
@@ -448,7 +453,6 @@ CORE_SOURCE_FILES = [
     'src/core/lib/iomgr/resolve_address_posix.cc',
     'src/core/lib/iomgr/resolve_address_windows.cc',
     'src/core/lib/iomgr/resource_quota.cc',
-    'src/core/lib/iomgr/sockaddr_utils.cc',
     'src/core/lib/iomgr/socket_factory_posix.cc',
     'src/core/lib/iomgr/socket_mutator.cc',
     'src/core/lib/iomgr/socket_utils_common_posix.cc',
@@ -637,6 +641,7 @@ CORE_SOURCE_FILES = [
     'third_party/abseil-cpp/absl/debugging/symbolize.cc',
     'third_party/abseil-cpp/absl/hash/internal/city.cc',
     'third_party/abseil-cpp/absl/hash/internal/hash.cc',
+    'third_party/abseil-cpp/absl/hash/internal/wyhash.cc',
     'third_party/abseil-cpp/absl/numeric/int128.cc',
     'third_party/abseil-cpp/absl/status/status.cc',
     'third_party/abseil-cpp/absl/status/status_payload_printer.cc',
@@ -647,6 +652,8 @@ CORE_SOURCE_FILES = [
     'third_party/abseil-cpp/absl/strings/escaping.cc',
     'third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc',
     'third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc',
+    'third_party/abseil-cpp/absl/strings/internal/cord_internal.cc',
+    'third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc',
     'third_party/abseil-cpp/absl/strings/internal/escaping.cc',
     'third_party/abseil-cpp/absl/strings/internal/memutil.cc',
     'third_party/abseil-cpp/absl/strings/internal/ostringstream.cc',
@@ -799,7 +806,6 @@ CORE_SOURCE_FILES = [
     'third_party/boringssl-with-bazel/src/crypto/ex_data.c',
     'third_party/boringssl-with-bazel/src/crypto/fipsmodule/bcm.c',
     'third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c',
-    'third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c',
     'third_party/boringssl-with-bazel/src/crypto/hkdf/hkdf.c',
     'third_party/boringssl-with-bazel/src/crypto/hpke/hpke.c',
     'third_party/boringssl-with-bazel/src/crypto/hrss/hrss.c',
@@ -866,7 +872,6 @@ CORE_SOURCE_FILES = [
     'third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c',
     'third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c',
     'third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c',
-    'third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c',
     'third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c',
     'third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c',
     'third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c',
@@ -931,6 +936,7 @@ CORE_SOURCE_FILES = [
     'third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc',
     'third_party/boringssl-with-bazel/src/ssl/dtls_method.cc',
     'third_party/boringssl-with-bazel/src/ssl/dtls_record.cc',
+    'third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc',
     'third_party/boringssl-with-bazel/src/ssl/handoff.cc',
     'third_party/boringssl-with-bazel/src/ssl/handshake.cc',
     'third_party/boringssl-with-bazel/src/ssl/handshake_client.cc',
index ece1ae8..29beeb7 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION = '1.37.1'
+VERSION = '1.38.0'
diff --git a/src/python/grpcio_admin/.gitignore b/src/python/grpcio_admin/.gitignore
new file mode 100644 (file)
index 0000000..6f95c5f
--- /dev/null
@@ -0,0 +1,6 @@
+*.proto
+*_pb2.py
+*_pb2_grpc.py
+build/
+grpcio_admin.egg-info/
+dist/
diff --git a/src/python/grpcio_admin/MANIFEST.in b/src/python/grpcio_admin/MANIFEST.in
new file mode 100644 (file)
index 0000000..eb7e029
--- /dev/null
@@ -0,0 +1,4 @@
+include grpc_version.py
+recursive-include grpc_admin *.py
+global-exclude *.pyc
+include LICENSE
diff --git a/src/python/grpcio_admin/README.rst b/src/python/grpcio_admin/README.rst
new file mode 100644 (file)
index 0000000..d995984
--- /dev/null
@@ -0,0 +1,23 @@
+gRPC Python Admin Interface Package
+===================================
+
+Debugging gRPC library can be a complex task. There are many configurations and
+internal states, which will affect the behavior of the library. This Python
+package will be the collection of admin services that are exposing debug
+information. Currently, it includes:
+
+* Channel tracing metrics (grpcio-channelz)
+* Client Status Discovery Service (grpcio-csds)
+
+Here is a snippet to create an admin server on "localhost:50051":
+
+    server = grpc.server(ThreadPoolExecutor())
+    port = server.add_insecure_port('localhost:50051')
+    grpc_admin.add_admin_servicers(self._server)
+    server.start()
+
+Welcome to explore the admin services with CLI tool "grpcdebug":
+https://github.com/grpc-ecosystem/grpcdebug.
+
+For any issues or suggestions, please send to
+https://github.com/grpc/grpc/issues.
diff --git a/src/python/grpcio_admin/grpc_admin/BUILD.bazel b/src/python/grpcio_admin/grpc_admin/BUILD.bazel
new file mode 100644 (file)
index 0000000..bd81a66
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright 2021 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.
+
+package(default_visibility = ["//visibility:public"])
+
+py_library(
+    name = "grpc_admin",
+    srcs = glob(["*.py"]),
+    imports = ["../"],
+    deps = [
+        "//src/python/grpcio_channelz/grpc_channelz/v1:grpc_channelz",
+        "//src/python/grpcio_csds/grpc_csds",
+    ],
+)
diff --git a/src/python/grpcio_admin/grpc_admin/__init__.py b/src/python/grpcio_admin/grpc_admin/__init__.py
new file mode 100644 (file)
index 0000000..96dfca1
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright 2021 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.
+"""gRPC Python's Admin interface."""
+
+import grpc_csds
+from grpc_channelz.v1 import channelz
+
+
+def add_admin_servicers(server):
+    """Register admin servicers to a server.
+
+    gRPC provides some predefined admin services to make debugging easier by
+    exposing gRPC's internal states. Each existing admin service is packaged as
+    a separate library, and the documentation of the predefined admin services
+    is usually scattered. It can be time consuming to get the dependency
+    management, module initialization, and library import right for each one of
+    them. 
+
+    This API provides a convenient way to create a gRPC server to expose admin
+    services. With this, any new admin services that you may add in the future
+    are automatically available via the admin interface just by upgrading your
+    gRPC version.
+
+    Args:
+        server: A gRPC server to which all admin services will be added.
+    """
+    channelz.add_channelz_servicer(server)
+    grpc_csds.add_csds_servicer(server)
+
+
+__all__ = ['add_admin_servicers']
diff --git a/src/python/grpcio_admin/grpc_version.py b/src/python/grpcio_admin/grpc_version.py
new file mode 100644 (file)
index 0000000..e051e71
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_admin/grpc_version.py.template`!!!
+
+VERSION = '1.38.0'
diff --git a/src/python/grpcio_admin/setup.py b/src/python/grpcio_admin/setup.py
new file mode 100644 (file)
index 0000000..6c2438e
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Setup module for admin interface in gRPC Python."""
+
+import os
+import sys
+
+import setuptools
+
+_PACKAGE_PATH = os.path.realpath(os.path.dirname(__file__))
+_README_PATH = os.path.join(_PACKAGE_PATH, 'README.rst')
+
+# Ensure we're in the proper directory whether or not we're being used by pip.
+os.chdir(os.path.dirname(os.path.abspath(__file__)))
+
+# Break import-style to ensure we can actually find our local modules.
+import grpc_version
+
+CLASSIFIERS = [
+    'Development Status :: 5 - Production/Stable',
+    'Programming Language :: Python',
+    'Programming Language :: Python :: 2',
+    'Programming Language :: Python :: 3',
+    'License :: OSI Approved :: Apache Software License',
+]
+
+PACKAGE_DIRECTORIES = {
+    '': '.',
+}
+
+INSTALL_REQUIRES = (
+    'grpcio-channelz>={version}'.format(version=grpc_version.VERSION),
+    'grpcio-csds>={version}'.format(version=grpc_version.VERSION),
+)
+SETUP_REQUIRES = INSTALL_REQUIRES
+
+setuptools.setup(name='grpcio-admin',
+                 version=grpc_version.VERSION,
+                 license='Apache License 2.0',
+                 description='a collection of admin services',
+                 long_description=open(_README_PATH, 'r').read(),
+                 author='The gRPC Authors',
+                 author_email='grpc-io@googlegroups.com',
+                 classifiers=CLASSIFIERS,
+                 url='https://grpc.io',
+                 package_dir=PACKAGE_DIRECTORIES,
+                 packages=setuptools.find_packages('.'),
+                 install_requires=INSTALL_REQUIRES,
+                 setup_requires=SETUP_REQUIRES)
index 197b529..f42051a 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/grpc_version.py.template`!!!
 
-VERSION = '1.37.1'
+VERSION = '1.38.0'
diff --git a/src/python/grpcio_csds/.gitignore b/src/python/grpcio_csds/.gitignore
new file mode 100644 (file)
index 0000000..24f7dd9
--- /dev/null
@@ -0,0 +1,6 @@
+*.proto
+*_pb2.py
+*_pb2_grpc.py
+build/
+grpcio_csds.egg-info/
+dist/
diff --git a/src/python/grpcio_csds/MANIFEST.in b/src/python/grpcio_csds/MANIFEST.in
new file mode 100644 (file)
index 0000000..4ecdf74
--- /dev/null
@@ -0,0 +1,4 @@
+include grpc_version.py
+recursive-include grpc_csds *.py
+global-exclude *.pyc
+include LICENSE
diff --git a/src/python/grpcio_csds/README.rst b/src/python/grpcio_csds/README.rst
new file mode 100644 (file)
index 0000000..f8803f2
--- /dev/null
@@ -0,0 +1,10 @@
+gRPC Python Client Status Discovery Service package
+===================================================
+
+CSDS is part of the Envoy xDS protocol:
+https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/status/v3/csds.proto.
+It allows the gRPC application to programmatically expose the received traffic
+configuration (xDS resources). Welcome to explore with CLI tool "grpcdebug":
+https://github.com/grpc-ecosystem/grpcdebug.
+
+For any issues or suggestions, please send to https://github.com/grpc/grpc/issues.
diff --git a/src/python/grpcio_csds/grpc_csds/BUILD.bazel b/src/python/grpcio_csds/grpc_csds/BUILD.bazel
new file mode 100644 (file)
index 0000000..2e799ef
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright 2021 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")
+
+package(default_visibility = ["//visibility:public"])
+
+py_library(
+    name = "grpc_csds",
+    srcs = glob(["*.py"]),
+    imports = ["../"],
+    deps = [
+        "//src/proto/grpc/testing/xds/v3:base_py_pb2",
+        "//src/proto/grpc/testing/xds/v3:config_dump_py_pb2",
+        "//src/proto/grpc/testing/xds/v3:csds_py_pb2",
+        "//src/proto/grpc/testing/xds/v3:csds_py_pb2_grpc",
+        "//src/proto/grpc/testing/xds/v3:percent_py_pb2",
+        "//src/python/grpcio/grpc:grpcio",
+    ],
+)
diff --git a/src/python/grpcio_csds/grpc_csds/__init__.py b/src/python/grpcio_csds/grpc_csds/__init__.py
new file mode 100644 (file)
index 0000000..e309255
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Channelz debug service implementation in gRPC Python."""
+
+from grpc._cython import cygrpc
+
+from google.protobuf import json_format
+try:
+    from envoy.service.status.v3 import csds_pb2, csds_pb2_grpc
+except ImportError:
+    from src.proto.grpc.testing.xds.v3 import csds_pb2, csds_pb2_grpc
+
+
+class ClientStatusDiscoveryServiceServicer(
+        csds_pb2_grpc.ClientStatusDiscoveryServiceServicer):
+    """CSDS Servicer works for both the sync API and asyncio API."""
+
+    @staticmethod
+    def FetchClientStatus(request, unused_context):
+        client_config = csds_pb2.ClientConfig.FromString(
+            cygrpc.dump_xds_configs())
+        response = csds_pb2.ClientStatusResponse()
+        response.config.append(client_config)
+        return response
+
+    @staticmethod
+    def StreamClientStatus(request_iterator, context):
+        for request in request_iterator:
+            yield ClientStatusDiscoveryServiceServicer.FetchClientStatus(
+                request, context)
+
+
+def add_csds_servicer(server):
+    """Register CSDS servicer to a server.
+
+    CSDS is part of xDS protocol used to expose in-effective traffic
+    configuration (or xDS resources). It focuses on simplify the debugging of
+    unexpected routing behaviors, which could be due to a misconfiguration,
+    unhealthy backends or issues in the control or data plane. 
+
+    Args:
+        server: A gRPC server to which the CSDS service will be added.
+    """
+    csds_pb2_grpc.add_ClientStatusDiscoveryServiceServicer_to_server(
+        ClientStatusDiscoveryServiceServicer(), server)
+
+
+__all__ = ['ClientStatusDiscoveryServiceServicer', 'add_csds_servicer']
diff --git a/src/python/grpcio_csds/grpc_version.py b/src/python/grpcio_csds/grpc_version.py
new file mode 100644 (file)
index 0000000..680126b
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_csds/grpc_version.py.template`!!!
+
+VERSION = '1.38.0'
diff --git a/src/python/grpcio_csds/setup.py b/src/python/grpcio_csds/setup.py
new file mode 100644 (file)
index 0000000..c699fc7
--- /dev/null
@@ -0,0 +1,61 @@
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Setup module for CSDS in gRPC Python."""
+
+import os
+import sys
+
+import setuptools
+
+_PACKAGE_PATH = os.path.realpath(os.path.dirname(__file__))
+_README_PATH = os.path.join(_PACKAGE_PATH, 'README.rst')
+
+# Ensure we're in the proper directory whether or not we're being used by pip.
+os.chdir(os.path.dirname(os.path.abspath(__file__)))
+
+# Break import-style to ensure we can actually find our local modules.
+import grpc_version
+
+CLASSIFIERS = [
+    'Development Status :: 5 - Production/Stable',
+    'Programming Language :: Python',
+    'Programming Language :: Python :: 2',
+    'Programming Language :: Python :: 3',
+    'License :: OSI Approved :: Apache Software License',
+]
+
+PACKAGE_DIRECTORIES = {
+    '': '.',
+}
+
+INSTALL_REQUIRES = (
+    'protobuf>=3.6.0',
+    'xds-protos>=0.0.7',
+    'grpcio>={version}'.format(version=grpc_version.VERSION),
+)
+SETUP_REQUIRES = INSTALL_REQUIRES
+
+setuptools.setup(name='grpcio-csds',
+                 version=grpc_version.VERSION,
+                 license='Apache License 2.0',
+                 description='xDS configuration dump library',
+                 long_description=open(_README_PATH, 'r').read(),
+                 author='The gRPC Authors',
+                 author_email='grpc-io@googlegroups.com',
+                 classifiers=CLASSIFIERS,
+                 url='https://grpc.io',
+                 package_dir=PACKAGE_DIRECTORIES,
+                 packages=setuptools.find_packages('.'),
+                 install_requires=INSTALL_REQUIRES,
+                 setup_requires=SETUP_REQUIRES)
index 3e60e12..1359a02 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
 
-VERSION = '1.37.1'
+VERSION = '1.38.0'
index 7b3e707..17c4671 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
 
-VERSION = '1.37.1'
+VERSION = '1.38.0'
index 95a2a87..09099b9 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_status/grpc_version.py.template`!!!
 
-VERSION = '1.37.1'
+VERSION = '1.38.0'
index 899dae7..ca8dfde 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
 
-VERSION = '1.37.1'
+VERSION = '1.38.0'
index 889b0bd..f5f3849 100644 (file)
@@ -231,6 +231,9 @@ class TestGevent(setuptools.Command):
         # TODO(https://github.com/grpc/grpc/pull/15411) enable this test
         'unit._server_test.ServerTest.test_failed_port_binding_exception',
     )
+    BANNED_MACOS_TESTS = (
+        # TODO(https://github.com/grpc/grpc/issues/15411) enable this test
+        'unit._dynamic_stubs_test.DynamicStubTest',)
     description = 'run tests with gevent.  Assumes grpc/gevent are installed'
     user_options = []
 
@@ -258,6 +261,8 @@ class TestGevent(setuptools.Command):
         runner = tests.Runner()
         if sys.platform == 'win32':
             runner.skip_tests(self.BANNED_TESTS + self.BANNED_WINDOWS_TESTS)
+        elif sys.platform == 'darwin':
+            runner.skip_tests(self.BANNED_TESTS + self.BANNED_MACOS_TESTS)
         else:
             runner.skip_tests(self.BANNED_TESTS)
         result = gevent.spawn(runner.run, loader.suite)
index 69d40de..b2b27c8 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
 
-VERSION = '1.37.1'
+VERSION = '1.38.0'
diff --git a/src/python/grpcio_tests/tests/admin/BUILD.bazel b/src/python/grpcio_tests/tests/admin/BUILD.bazel
new file mode 100644 (file)
index 0000000..d94be8c
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2021 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("//bazel:python_rules.bzl", "py2and3_test")
+
+py2and3_test(
+    name = "test_admin",
+    size = "small",
+    srcs = ["test_admin.py"],
+    main = "test_admin.py",
+    deps = [
+        "//src/python/grpcio/grpc:grpcio",
+        "//src/python/grpcio_admin/grpc_admin",
+    ],
+)
diff --git a/src/python/grpcio_tests/tests/admin/test_admin.py b/src/python/grpcio_tests/tests/admin/test_admin.py
new file mode 100644 (file)
index 0000000..484cfa0
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright 2021 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.
+"""A test to ensure that admin services are registered correctly."""
+
+import logging
+import unittest
+from concurrent.futures import ThreadPoolExecutor
+
+import grpc
+import grpc_admin
+from grpc_csds import csds_pb2, csds_pb2_grpc
+from grpc_channelz.v1 import channelz_pb2, channelz_pb2_grpc
+
+
+class TestAdmin(unittest.TestCase):
+
+    def setUp(self):
+        self._server = grpc.server(ThreadPoolExecutor())
+        port = self._server.add_insecure_port('localhost:0')
+        grpc_admin.add_admin_servicers(self._server)
+        self._server.start()
+
+        self._channel = grpc.insecure_channel('localhost:%s' % port)
+
+    def tearDown(self):
+        self._channel.close()
+        self._server.stop(0)
+
+    def test_has_csds(self):
+        stub = csds_pb2_grpc.ClientStatusDiscoveryServiceStub(self._channel)
+        resp = stub.FetchClientStatus(csds_pb2.ClientStatusRequest())
+        # No exception raised and the response is valid
+        self.assertGreater(len(resp.config), 0)
+
+    def test_has_channelz(self):
+        stub = channelz_pb2_grpc.ChannelzStub(self._channel)
+        resp = stub.GetTopChannels(channelz_pb2.GetTopChannelsRequest())
+        # No exception raised and the response is valid
+        self.assertGreater(len(resp.channel), 0)
+
+
+if __name__ == "__main__":
+    logging.basicConfig(level=logging.DEBUG)
+    unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/csds/BUILD.bazel b/src/python/grpcio_tests/tests/csds/BUILD.bazel
new file mode 100644 (file)
index 0000000..3cf916d
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright 2021 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("//bazel:python_rules.bzl", "py2and3_test")
+
+py2and3_test(
+    name = "test_csds",
+    size = "small",
+    srcs = ["test_csds.py"],
+    main = "test_csds.py",
+    deps = [
+        "//src/python/grpcio/grpc:grpcio",
+        "//src/python/grpcio_csds/grpc_csds",
+        "@six",
+    ],
+)
diff --git a/src/python/grpcio_tests/tests/csds/test_csds.py b/src/python/grpcio_tests/tests/csds/test_csds.py
new file mode 100644 (file)
index 0000000..f970943
--- /dev/null
@@ -0,0 +1,134 @@
+# Copyright 2021 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.
+"""A simple test to ensure that the Python wrapper can get xDS config."""
+
+import logging
+import os
+import time
+from six.moves import queue
+import unittest
+from concurrent.futures import ThreadPoolExecutor
+
+import grpc
+import grpc_csds
+
+from google.protobuf import json_format
+try:
+    from envoy.service.status.v3 import csds_pb2, csds_pb2_grpc
+except ImportError:
+    from src.proto.grpc.testing.xds.v3 import csds_pb2, csds_pb2_grpc
+
+_DUMMY_XDS_ADDRESS = 'xds:///foo.bar'
+_DUMMY_BOOTSTRAP_FILE = """
+{
+  \"xds_servers\": [
+    {
+      \"server_uri\": \"fake:///xds_server\",
+      \"channel_creds\": [
+        {
+          \"type\": \"fake\"
+        }
+      ],
+      \"server_features\": [\"xds_v3\"]
+    }
+  ],
+  \"node\": {
+    \"id\": \"python_test_csds\",
+    \"cluster\": \"test\",
+    \"metadata\": {
+      \"foo\": \"bar\"
+    },
+    \"locality\": {
+      \"region\": \"corp\",
+      \"zone\": \"svl\",
+      \"sub_zone\": \"mp3\"
+    }
+  }
+}\
+"""
+
+
+class TestCsds(unittest.TestCase):
+
+    def setUp(self):
+        os.environ['GRPC_XDS_BOOTSTRAP_CONFIG'] = _DUMMY_BOOTSTRAP_FILE
+        self._server = grpc.server(ThreadPoolExecutor())
+        port = self._server.add_insecure_port('localhost:0')
+        grpc_csds.add_csds_servicer(self._server)
+        self._server.start()
+
+        self._channel = grpc.insecure_channel('localhost:%s' % port)
+        self._stub = csds_pb2_grpc.ClientStatusDiscoveryServiceStub(
+            self._channel)
+
+    def tearDown(self):
+        self._channel.close()
+        self._server.stop(0)
+        os.environ.pop('GRPC_XDS_BOOTSTRAP_CONFIG', None)
+
+    def get_xds_config_dump(self):
+        return self._stub.FetchClientStatus(csds_pb2.ClientStatusRequest())
+
+    def test_has_node(self):
+        resp = self.get_xds_config_dump()
+        self.assertEqual(1, len(resp.config))
+        self.assertEqual(4, len(resp.config[0].xds_config))
+        self.assertEqual('python_test_csds', resp.config[0].node.id)
+        self.assertEqual('test', resp.config[0].node.cluster)
+
+    def test_no_lds_found(self):
+        dummy_channel = grpc.insecure_channel(_DUMMY_XDS_ADDRESS)
+
+        # Force the XdsClient to initialize and request a resource
+        with self.assertRaises(grpc.RpcError) as rpc_error:
+            dummy_channel.unary_unary('')(b'', wait_for_ready=False)
+        self.assertEqual(grpc.StatusCode.UNAVAILABLE,
+                         rpc_error.exception.code())
+
+        # The resource request will fail with DOES_NOT_EXIST (after 15s)
+        while True:
+            resp = self.get_xds_config_dump()
+            config = json_format.MessageToDict(resp)
+            ok = False
+            try:
+                for xds_config in config["config"][0]["xdsConfig"]:
+                    if "listenerConfig" in xds_config:
+                        listener = xds_config["listenerConfig"][
+                            "dynamicListeners"][0]
+                        if listener['clientStatus'] == 'DOES_NOT_EXIST':
+                            ok = True
+                            break
+            except KeyError as e:
+                logging.debug("Invalid config: %s\n%s: %s", config, type(e), e)
+                pass
+            if ok:
+                break
+            time.sleep(1)
+        dummy_channel.close()
+
+
+class TestCsdsStream(TestCsds):
+
+    def get_xds_config_dump(self):
+        if not hasattr(self, 'request_queue'):
+            request_queue = queue.Queue()
+            response_iterator = self._stub.StreamClientStatus(
+                iter(request_queue.get, None))
+        request_queue.put(csds_pb2.ClientStatusRequest())
+        return next(response_iterator)
+
+
+if __name__ == "__main__":
+    logging.basicConfig(level=logging.DEBUG)
+    unittest.main(verbosity=2)
index bd4139b..93f55bf 100644 (file)
@@ -60,6 +60,7 @@
   "unit._invocation_defects_test.InvocationDefectsTest",
   "unit._local_credentials_test.LocalCredentialsTest",
   "unit._logging_test.LoggingTest",
+  "unit._metadata_code_details_test.InspectContextTest",
   "unit._metadata_code_details_test.MetadataCodeDetailsTest",
   "unit._metadata_flags_test.MetadataFlagsTest",
   "unit._metadata_test.MetadataTest",
index 5b06eb2..900fabd 100644 (file)
@@ -658,6 +658,64 @@ class MetadataCodeDetailsTest(unittest.TestCase):
         self.assertEqual(_DETAILS, exception_context.exception.details())
 
 
+class _InspectServicer(_Servicer):
+
+    def __init__(self):
+        super(_InspectServicer, self).__init__()
+        self.actual_code = None
+        self.actual_details = None
+        self.actual_trailing_metadata = None
+
+    def unary_unary(self, request, context):
+        super(_InspectServicer, self).unary_unary(request, context)
+
+        self.actual_code = context.code()
+        self.actual_details = context.details()
+        self.actual_trailing_metadata = context.trailing_metadata()
+
+
+class InspectContextTest(unittest.TestCase):
+
+    def setUp(self):
+        self._servicer = _InspectServicer()
+        self._server = test_common.test_server()
+        self._server.add_generic_rpc_handlers(
+            (_generic_handler(self._servicer),))
+        port = self._server.add_insecure_port('[::]:0')
+        self._server.start()
+
+        self._channel = grpc.insecure_channel('localhost:{}'.format(port))
+        self._unary_unary = self._channel.unary_unary(
+            '/'.join((
+                '',
+                _SERVICE,
+                _UNARY_UNARY,
+            )),
+            request_serializer=_REQUEST_SERIALIZER,
+            response_deserializer=_RESPONSE_DESERIALIZER,
+        )
+
+    def tearDown(self):
+        self._server.stop(None)
+        self._channel.close()
+
+    def testCodeDetailsInContext(self):
+        self._servicer.set_code(_NON_OK_CODE)
+        self._servicer.set_details(_DETAILS)
+
+        with self.assertRaises(grpc.RpcError) as exc_info:
+            self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
+
+        err = exc_info.exception
+        self.assertEqual(_NON_OK_CODE, err.code())
+
+        self.assertEqual(self._servicer.actual_code, _NON_OK_CODE)
+        self.assertEqual(self._servicer.actual_details.decode('utf-8'),
+                         _DETAILS)
+        self.assertEqual(self._servicer.actual_trailing_metadata,
+                         _SERVER_TRAILING_METADATA)
+
+
 if __name__ == '__main__':
     logging.basicConfig()
     unittest.main(verbosity=2)
index 2261446..8f8c392 100644 (file)
@@ -33,6 +33,7 @@ _TEST_GENERIC_HANDLER = '/test/TestGenericHandler'
 _TEST_UNARY_STREAM = '/test/TestUnaryStream'
 _TEST_STREAM_UNARY = '/test/TestStreamUnary'
 _TEST_STREAM_STREAM = '/test/TestStreamStream'
+_TEST_INSPECT_CONTEXT = '/test/TestInspectContext'
 
 _REQUEST = b'\x00\x00\x00'
 _RESPONSE = b'\x01\x01\x01'
@@ -75,6 +76,9 @@ _INVALID_METADATA_TEST_CASES = (
     ),
 )
 
+_NON_OK_CODE = grpc.StatusCode.NOT_FOUND
+_DETAILS = 'Test details!'
+
 
 class _TestGenericHandlerForMethods(grpc.GenericRpcHandler):
 
@@ -95,6 +99,8 @@ class _TestGenericHandlerForMethods(grpc.GenericRpcHandler):
                 grpc.stream_unary_rpc_method_handler(self._test_stream_unary),
             _TEST_STREAM_STREAM:
                 grpc.stream_stream_rpc_method_handler(self._test_stream_stream),
+            _TEST_INSPECT_CONTEXT:
+                grpc.unary_unary_rpc_method_handler(self._test_inspect_context),
         }
 
     @staticmethod
@@ -153,6 +159,19 @@ class _TestGenericHandlerForMethods(grpc.GenericRpcHandler):
         yield _RESPONSE
         context.set_trailing_metadata(_TRAILING_METADATA)
 
+    @staticmethod
+    async def _test_inspect_context(request, context):
+        assert _REQUEST == request
+        context.set_code(_NON_OK_CODE)
+        context.set_details(_DETAILS)
+        context.set_trailing_metadata(_TRAILING_METADATA)
+
+        # ensure that we can read back the data we set on the context
+        assert context.get_code() == _NON_OK_CODE
+        assert context.get_details() == _DETAILS
+        assert context.get_trailing_metadata() == _TRAILING_METADATA
+        return _RESPONSE
+
     def service(self, handler_call_details):
         return self._routing_table.get(handler_call_details.method)
 
@@ -291,6 +310,15 @@ class TestMetadata(AioTestBase):
         self.assertEqual(expected_sum, metadata_obj + aio.Metadata(
             ('third', '3')))
 
+    async def test_inspect_context(self):
+        multicallable = self._client.unary_unary(_TEST_INSPECT_CONTEXT)
+        call = multicallable(_REQUEST)
+        with self.assertRaises(grpc.RpcError) as exc_data:
+            await call
+
+        err = exc_data.exception
+        self.assertEqual(_NON_OK_CODE, err.code())
+
 
 if __name__ == '__main__':
     logging.basicConfig(level=logging.DEBUG)
index 21d2071..506d744 100644 (file)
@@ -8,5 +8,22 @@ py_binary(
         "//src/proto/grpc/testing:py_test_proto",
         "//src/proto/grpc/testing:test_py_pb2_grpc",
         "//src/python/grpcio/grpc:grpcio",
+        "//src/python/grpcio_channelz/grpc_channelz/v1:grpc_channelz",
+    ],
+)
+
+py_binary(
+    name = "xds_interop_server",
+    srcs = ["xds_interop_server.py"],
+    python_version = "PY3",
+    deps = [
+        "//src/proto/grpc/testing:empty_py_pb2",
+        "//src/proto/grpc/testing:py_messages_proto",
+        "//src/proto/grpc/testing:py_test_proto",
+        "//src/proto/grpc/testing:test_py_pb2_grpc",
+        "//src/python/grpcio/grpc:grpcio",
+        "//src/python/grpcio_channelz/grpc_channelz/v1:grpc_channelz",
+        "//src/python/grpcio_health_checking/grpc_health/v1:grpc_health",
+        "//src/python/grpcio_reflection/grpc_reflection/v1alpha:grpc_reflection",
     ],
 )
diff --git a/src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client b/src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client
new file mode 100644 (file)
index 0000000..e8184e7
--- /dev/null
@@ -0,0 +1,25 @@
+FROM phusion/baseimage:master@sha256:65ea10d5f757e5e86272625f8675d437dd83d8db64bdb429e2354d58f5462750
+
+RUN apt-get update -y && \
+        apt-get install -y \
+            build-essential \
+            clang \
+            python3 \
+            python3-dev
+
+WORKDIR /workdir
+
+RUN ln -s /usr/bin/python3 /usr/bin/python
+RUN mkdir /artifacts
+
+COPY . .
+RUN tools/bazel build -c dbg //src/python/grpcio_tests/tests_py3_only/interop:xds_interop_client
+RUN cp -rL /workdir/bazel-bin/src/python/grpcio_tests/tests_py3_only/interop/xds_interop_client* /artifacts/
+
+FROM phusion/baseimage:master@sha256:65ea10d5f757e5e86272625f8675d437dd83d8db64bdb429e2354d58f5462750
+COPY --from=0 /artifacts ./
+
+RUN apt-get update -y && apt-get install -y python3
+RUN ln -s /usr/bin/python3 /usr/bin/python
+
+ENTRYPOINT ["/xds_interop_client"]
diff --git a/src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.server b/src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.server
new file mode 100644 (file)
index 0000000..b7259bf
--- /dev/null
@@ -0,0 +1,25 @@
+FROM phusion/baseimage:master@sha256:65ea10d5f757e5e86272625f8675d437dd83d8db64bdb429e2354d58f5462750
+
+RUN apt-get update -y && \
+        apt-get install -y \
+            build-essential \
+            clang \
+            python3 \
+            python3-dev
+
+WORKDIR /workdir
+
+RUN ln -s /usr/bin/python3 /usr/bin/python
+RUN mkdir /artifacts
+
+COPY . .
+RUN tools/bazel build -c dbg //src/python/grpcio_tests/tests_py3_only/interop:xds_interop_server
+RUN cp -rL /workdir/bazel-bin/src/python/grpcio_tests/tests_py3_only/interop/xds_interop_server* /artifacts/
+
+FROM phusion/baseimage:master@sha256:65ea10d5f757e5e86272625f8675d437dd83d8db64bdb429e2354d58f5462750
+COPY --from=0 /artifacts ./
+
+RUN apt-get update -y && apt-get install -y python3
+RUN ln -s /usr/bin/python3 /usr/bin/python
+
+ENTRYPOINT ["/xds_interop_server"]
index fa953e5..e71be52 100644 (file)
@@ -27,6 +27,7 @@ import collections
 from concurrent import futures
 
 import grpc
+from grpc_channelz.v1 import channelz
 
 from src.proto.grpc.testing import test_pb2
 from src.proto.grpc.testing import test_pb2_grpc
@@ -257,9 +258,9 @@ class _ChannelConfiguration:
     When accessing any of its members, the lock member should be held.
     """
 
-    def __init__(self, method: str, metadata: Sequence[Tuple[str,
-                                                             str]], qps: int,
-                 server: str, rpc_timeout_sec: int, print_response: bool):
+    def __init__(self, method: str, metadata: Sequence[Tuple[str, str]],
+                 qps: int, server: str, rpc_timeout_sec: int,
+                 print_response: bool, secure_mode: bool):
         # condition is signalled when a change is made to the config.
         self.condition = threading.Condition()
 
@@ -269,13 +270,21 @@ class _ChannelConfiguration:
         self.server = server
         self.rpc_timeout_sec = rpc_timeout_sec
         self.print_response = print_response
+        self.secure_mode = secure_mode
 
 
 def _run_single_channel(config: _ChannelConfiguration) -> None:
     global _global_rpc_id  # pylint: disable=global-statement
     with config.condition:
         server = config.server
-    with grpc.insecure_channel(server) as channel:
+    channel = None
+    if config.secure_mode:
+        fallback_creds = grpc.experimental.insecure_channel_credentials()
+        channel_creds = grpc.xds_channel_credentials(fallback_creds)
+        channel = grpc.secure_channel(server, channel_creds)
+    else:
+        channel = grpc.insecure_channel(server)
+    with channel:
         stub = test_pb2_grpc.TestServiceStub(channel)
         futures: Dict[int, Tuple[grpc.Future, str]] = {}
         while not _stop_event.is_set():
@@ -382,7 +391,7 @@ def _run(args: argparse.Namespace, methods: Sequence[str],
             qps = 0
         channel_config = _ChannelConfiguration(
             method, per_method_metadata.get(method, []), qps, args.server,
-            args.rpc_timeout_sec, args.print_response)
+            args.rpc_timeout_sec, args.print_response, args.secure_mode)
         channel_configs[method] = channel_config
         method_handles.append(_MethodHandle(args.num_channels, channel_config))
     _global_server = grpc.server(futures.ThreadPoolExecutor())
@@ -392,6 +401,7 @@ def _run(args: argparse.Namespace, methods: Sequence[str],
     test_pb2_grpc.add_XdsUpdateClientConfigureServiceServicer_to_server(
         _XdsUpdateClientConfigureServicer(channel_configs, args.qps),
         _global_server)
+    channelz.add_channelz_servicer(_global_server)
     _global_server.start()
     _global_server.wait_for_termination()
     for method_handle in method_handles:
@@ -420,6 +430,15 @@ def parse_rpc_arg(rpc_arg: str) -> Sequence[str]:
     return methods
 
 
+def bool_arg(arg: str) -> bool:
+    if arg.lower() in ("true", "yes", "y"):
+        return True
+    elif arg.lower() in ("false", "no", "n"):
+        return False
+    else:
+        raise argparse.ArgumentTypeError(f"Could not parse '{arg}' as a bool.")
+
+
 if __name__ == "__main__":
     parser = argparse.ArgumentParser(
         description='Run Python XDS interop client.')
@@ -429,8 +448,8 @@ if __name__ == "__main__":
         type=int,
         help="The number of channels from which to send requests.")
     parser.add_argument("--print_response",
-                        default=False,
-                        action="store_true",
+                        default="False",
+                        type=bool_arg,
                         help="Write RPC response to STDOUT.")
     parser.add_argument(
         "--qps",
@@ -449,6 +468,11 @@ if __name__ == "__main__":
         default=50052,
         type=int,
         help="The port on which to expose the peer distribution stats service.")
+    parser.add_argument(
+        "--secure_mode",
+        default="False",
+        type=bool_arg,
+        help="If specified, uses xDS credentials to connect to the server.")
     parser.add_argument('--verbose',
                         help='verbose log output',
                         default=False,
diff --git a/src/python/grpcio_tests/tests_py3_only/interop/xds_interop_server.py b/src/python/grpcio_tests/tests_py3_only/interop/xds_interop_server.py
new file mode 100644 (file)
index 0000000..b0901b2
--- /dev/null
@@ -0,0 +1,178 @@
+# Copyright 2021 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.
+
+import argparse
+import logging
+import signal
+import threading
+import time
+import socket
+import sys
+
+from typing import DefaultDict, Dict, List, Mapping, Set, Sequence, Tuple
+import collections
+
+from concurrent import futures
+
+import grpc
+from grpc_channelz.v1 import channelz
+from grpc_channelz.v1 import channelz_pb2
+from grpc_health.v1 import health_pb2, health_pb2_grpc
+from grpc_health.v1 import health as grpc_health
+from grpc_reflection.v1alpha import reflection
+
+from src.proto.grpc.testing import test_pb2
+from src.proto.grpc.testing import test_pb2_grpc
+from src.proto.grpc.testing import messages_pb2
+from src.proto.grpc.testing import empty_pb2
+
+# NOTE: This interop server is not fully compatible with all xDS interop tests.
+#  It currently only implements enough functionality to pass the xDS security
+#  tests.
+
+_LISTEN_HOST = "[::]"
+
+_THREAD_POOL_SIZE = 256
+
+logger = logging.getLogger()
+console_handler = logging.StreamHandler()
+formatter = logging.Formatter(fmt='%(asctime)s: %(levelname)-8s %(message)s')
+console_handler.setFormatter(formatter)
+logger.addHandler(console_handler)
+
+
+class TestService(test_pb2_grpc.TestServiceServicer):
+
+    def __init__(self, server_id, hostname):
+        self._server_id = server_id
+        self._hostname = hostname
+
+    def EmptyCall(self, _: empty_pb2.Empty,
+                  context: grpc.ServicerContext) -> empty_pb2.Empty:
+        return empty_pb2.Empty()
+
+    def UnaryCall(self, request: messages_pb2.SimpleRequest,
+                  context: grpc.ServicerContext) -> messages_pb2.SimpleResponse:
+        response = messages_pb2.SimpleResponse()
+        response.server_id = self._server_id
+        response.hostname = self._hostname
+        return response
+
+
+def _configure_maintenance_server(server: grpc.Server,
+                                  maintenance_port: int) -> None:
+    channelz.add_channelz_servicer(server)
+    listen_address = f"{_LISTEN_HOST}:{maintenance_port}"
+    server.add_insecure_port(listen_address)
+    health_servicer = grpc_health.HealthServicer(
+        experimental_non_blocking=True,
+        experimental_thread_pool=futures.ThreadPoolExecutor(
+            max_workers=_THREAD_POOL_SIZE))
+
+    health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)
+    SERVICE_NAMES = (
+        test_pb2.DESCRIPTOR.services_by_name["TestService"].full_name,
+        health_pb2.DESCRIPTOR.services_by_name["Health"].full_name,
+        channelz_pb2.DESCRIPTOR.services_by_name["Channelz"].full_name,
+        reflection.SERVICE_NAME,
+    )
+    for service in SERVICE_NAMES:
+        health_servicer.set(service, health_pb2.HealthCheckResponse.SERVING)
+    reflection.enable_server_reflection(SERVICE_NAMES, server)
+
+
+def _configure_test_server(server: grpc.Server, port: int, secure_mode: bool,
+                           server_id: str) -> None:
+    test_pb2_grpc.add_TestServiceServicer_to_server(
+        TestService(server_id, socket.gethostname()), server)
+    listen_address = f"{_LISTEN_HOST}:{port}"
+    if not secure_mode:
+        server.add_insecure_port(listen_address)
+    else:
+        logger.info("Running with xDS Server credentials")
+        server_fallback_creds = grpc.insecure_server_credentials()
+        server_creds = grpc.xds_server_credentials(server_fallback_creds)
+        server.add_secure_port(listen_address, server_creds)
+
+
+def _run(port: int, maintenance_port: int, secure_mode: bool,
+         server_id: str) -> None:
+    if port == maintenance_port:
+        server = grpc.server(
+            futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE))
+        _configure_test_server(server, port, secure_mode, server_id)
+        _configure_maintenance_server(server, maintenance_port)
+        server.start()
+        logger.info("Test server listening on port %d", port)
+        logger.info("Maintenance server listening on port %d", maintenance_port)
+        server.wait_for_termination()
+    else:
+        test_server = grpc.server(
+            futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE),
+            xds=secure_mode)
+        _configure_test_server(test_server, port, secure_mode, server_id)
+        test_server.start()
+        logger.info("Test server listening on port %d", port)
+        maintenance_server = grpc.server(
+            futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE))
+        _configure_maintenance_server(maintenance_server, maintenance_port)
+        maintenance_server.start()
+        logger.info("Maintenance server listening on port %d", maintenance_port)
+        test_server.wait_for_termination()
+        maintenance_server.wait_for_termination()
+
+
+def bool_arg(arg: str) -> bool:
+    if arg.lower() in ("true", "yes", "y"):
+        return True
+    elif arg.lower() in ("false", "no", "n"):
+        return False
+    else:
+        raise argparse.ArgumentTypeError(f"Could not parse '{arg}' as a bool.")
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        description="Run Python xDS interop server.")
+    parser.add_argument("--port",
+                        type=int,
+                        default=8080,
+                        help="Port for test server.")
+    parser.add_argument("--maintenance_port",
+                        type=int,
+                        default=8080,
+                        help="Port for servers besides test server.")
+    parser.add_argument(
+        "--secure_mode",
+        type=bool_arg,
+        default="False",
+        help="If specified, uses xDS to retrieve server credentials.")
+    parser.add_argument("--server_id",
+                        type=str,
+                        default="python_server",
+                        help="The server ID to return in responses..")
+    parser.add_argument('--verbose',
+                        help='verbose log output',
+                        default=False,
+                        action='store_true')
+    args = parser.parse_args()
+    if args.verbose:
+        logger.setLevel(logging.DEBUG)
+    else:
+        logger.setLevel(logging.INFO)
+    if args.secure_mode and args.port == args.maintenance_port:
+        raise ValueError(
+            "--port and --maintenance_port must not be the same when --secure_mode is set."
+        )
+    _run(args.port, args.maintenance_port, args.secure_mode, args.server_id)
index 8187d7f..a98f6f0 100644 (file)
@@ -18,6 +18,11 @@ INSTALLATION
 gem install grpc
 ```
 
+If using a Gemfile and you wish to pull from a git repository or GitHub, make sure to tell bundler to retrieve submodules:
+```
+gem 'grpc', github: 'grpc/grpc', submodules: true
+```
+
 BUILD FROM SOURCE
 ---------------------
 - Clone this repository
index 961117c..c4b908f 100644 (file)
@@ -23,7 +23,7 @@ module Math
   module Math
     class Service
 
-      include GRPC::GenericService
+      include ::GRPC::GenericService
 
       self.marshal_class_method = :encode
       self.unmarshal_class_method = :decode
index a61d1b2..44033ce 100644 (file)
@@ -215,7 +215,7 @@ extern grpc_server_create_type grpc_server_create_import;
 typedef void(*grpc_server_register_completion_queue_type)(grpc_server* server, grpc_completion_queue* cq, void* reserved);
 extern grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
 #define grpc_server_register_completion_queue grpc_server_register_completion_queue_import
-typedef grpc_server_config_fetcher*(*grpc_server_config_fetcher_xds_create_type)(grpc_server_xds_status_notifier notifier);
+typedef grpc_server_config_fetcher*(*grpc_server_config_fetcher_xds_create_type)(grpc_server_xds_status_notifier notifier, const grpc_channel_args* args);
 extern grpc_server_config_fetcher_xds_create_type grpc_server_config_fetcher_xds_create_import;
 #define grpc_server_config_fetcher_xds_create grpc_server_config_fetcher_xds_create_import
 typedef void(*grpc_server_config_fetcher_destroy_type)(grpc_server_config_fetcher* config_fetcher);
index 31425b1..5c5f9a5 100644 (file)
@@ -14,5 +14,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '1.37.1'
+  VERSION = '1.38.0'
 end
index 351e7e1..9ddc0ac 100644 (file)
@@ -28,7 +28,7 @@ module Grpc
       module Health
         class Service
 
-          include GRPC::GenericService
+          include ::GRPC::GenericService
 
           self.marshal_class_method = :encode
           self.unmarshal_class_method = :decode
index 19e6df7..55837a6 100644 (file)
@@ -29,7 +29,7 @@ module Grpc
       # performance with various types of payload.
       class Service
 
-        include GRPC::GenericService
+        include ::GRPC::GenericService
 
         self.marshal_class_method = :encode
         self.unmarshal_class_method = :decode
@@ -70,7 +70,7 @@ module Grpc
       # that case.
       class Service
 
-        include GRPC::GenericService
+        include ::GRPC::GenericService
 
         self.marshal_class_method = :encode
         self.unmarshal_class_method = :decode
@@ -86,7 +86,7 @@ module Grpc
       # A service used to control reconnect server.
       class Service
 
-        include GRPC::GenericService
+        include ::GRPC::GenericService
 
         self.marshal_class_method = :encode
         self.unmarshal_class_method = :decode
@@ -102,7 +102,7 @@ module Grpc
       # A service used to obtain stats for verifying LB behavior.
       class Service
 
-        include GRPC::GenericService
+        include ::GRPC::GenericService
 
         self.marshal_class_method = :encode
         self.unmarshal_class_method = :decode
@@ -120,7 +120,7 @@ module Grpc
       # A service to remotely control health status of an xDS test server.
       class Service
 
-        include GRPC::GenericService
+        include ::GRPC::GenericService
 
         self.marshal_class_method = :encode
         self.unmarshal_class_method = :decode
@@ -136,7 +136,7 @@ module Grpc
       # A service to dynamically update the configuration of an xDS test client.
       class Service
 
-        include GRPC::GenericService
+        include ::GRPC::GenericService
 
         self.marshal_class_method = :encode
         self.unmarshal_class_method = :decode
index 63e2d5d..9439fe5 100644 (file)
@@ -26,7 +26,7 @@ module Grpc
     module BenchmarkService
       class Service
 
-        include GRPC::GenericService
+        include ::GRPC::GenericService
 
         self.marshal_class_method = :encode
         self.unmarshal_class_method = :decode
index 5e41cfe..5f50fb1 100644 (file)
@@ -26,7 +26,7 @@ module Grpc
     module ReportQpsScenarioService
       class Service
 
-        include GRPC::GenericService
+        include ::GRPC::GenericService
 
         self.marshal_class_method = :encode
         self.unmarshal_class_method = :decode
index 049db47..f5584c6 100644 (file)
@@ -26,7 +26,7 @@ module Grpc
     module WorkerService
       class Service
 
-        include GRPC::GenericService
+        include ::GRPC::GenericService
 
         self.marshal_class_method = :encode
         self.unmarshal_class_method = :decode
index 52237fe..f2cfb68 100644 (file)
@@ -29,7 +29,12 @@ module PLATFORM
   end
 
   def PLATFORM.architecture
-    case RbConfig::CONFIG['host_cpu']
+    host_cpu = RbConfig::CONFIG['host_cpu']
+
+    # When we're on arm in macOS, we can rely on Rosetta and use the x86_64 binary
+    return 'x86_64' if RbConfig::CONFIG['host_os'] =~ /darwin/ && host_cpu =~ /arm/
+
+    case host_cpu
       when /x86_64/
         'x86_64'
       else
index f1e378e..f5a4326 100644 (file)
@@ -14,6 +14,6 @@
 
 module GRPC
   module Tools
-    VERSION = '1.37.1'
+    VERSION = '1.38.0'
   end
 end
index 0a14440..cef2534 100644 (file)
   def get_absl_dep(lib_name):
       return lib_map[lib_name].cmake_target
 
-  def list_absl_lib_files_for(lib_name):
-    ret = []
-    lib = lib_map[lib_name]
-    for dep in lib.transitive_deps:
-      if is_absl_lib(dep) and len(lib_map[dep].src) > 0:
-        ret.append(get_absl_dep(dep).replace("::", "_"))
-    return ret
+  def lib_and_transitive_deps(lib):
+    return list(sorted(set({lib} | set(lib_map[lib].transitive_deps))))
+
+  def list_abseil_pkg_targets(lib):
+    # This returns a list of abseil pkg targets which the given lib and
+    # its non-abseil transitive dependencies depend on.
+    # As a result, internal abseil libraries are excluded from the result.
+    absl_specs = set()
+    for lib_name in lib_and_transitive_deps(lib):
+      if is_absl_lib(lib_name): continue
+      for dep in lib_map[lib_name].deps:
+        if is_absl_lib(dep):
+          absl_specs.add(get_absl_dep(dep).replace("::", "_"))
+    return list(sorted(absl_specs))
 
   def is_shared_only_lib(lib_name):
     """Returns True if only shared library should be generated."""
@@ -53,7 +60,6 @@
     # only makes sense as a shared lib.
     return lib_name in ['grpc_csharp_ext']
 
-
   def get_deps(target_dict):
     deps = []
     if target_dict.get('baselib', False) or target_dict['name'] == 'address_sorting':
   </%def>
 
   <%def name="cc_install(tgt)">
+  % if tgt.name == 'grpcpp_channelz':
+  # grpcpp_channelz doesn't build with protobuf-lite, so no install required
+  # See https://github.com/grpc/grpc/issues/22826
+  if(gRPC_INSTALL AND NOT gRPC_USE_PROTO_LITE)
+  % else:
   if(gRPC_INSTALL)
+  % endif
     install(TARGETS ${tgt.name} EXPORT gRPCTargets
       RUNTIME DESTINATION <%text>${gRPC_INSTALL_BINDIR}</%text>
       LIBRARY DESTINATION <%text>${gRPC_INSTALL_LIBDIR}</%text>
     "gpr"
     "gRPC platform support library"
     "<%text>${gRPC_CORE_VERSION}</%text>"
-    ""
-    "${" ".join(("-l" + l) for l in ["gpr",] + list_absl_lib_files_for("gpr"))}"
+    "${" ".join(list_abseil_pkg_targets("gpr"))}"
+    "${" ".join(("-l" + l) for l in ["gpr"])}"
     ""
     "gpr.pc")
 
     "gRPC"
     "high performance general RPC framework"
     "<%text>${gRPC_CORE_VERSION}</%text>"
-    "gpr openssl"
-    "${" ".join(("-l" + l) for l in ["grpc", "address_sorting", "re2", "upb", "cares", "z"] + list_absl_lib_files_for("grpc"))}"
+    "${" ".join(["gpr", "openssl"] + list_abseil_pkg_targets("grpc"))}"
+    "${" ".join(("-l" + l) for l in ["grpc", "address_sorting", "re2", "upb", "cares", "z"])}"
     ""
     "grpc.pc")
 
     "gRPC unsecure"
     "high performance general RPC framework without SSL"
     "<%text>${gRPC_CORE_VERSION}</%text>"
-    "gpr"
-    "${" ".join(("-l" + l) for l in ["grpc_unsecure",] + list_absl_lib_files_for("grpc_unsecure"))}"
+    "${" ".join(["gpr"] + list_abseil_pkg_targets("grpc_unsecure"))}"
+    "${" ".join(("-l" + l) for l in ["grpc_unsecure"])}"
     ""
     "grpc_unsecure.pc")
 
     "gRPC++"
     "C++ wrapper for gRPC"
     "<%text>${gRPC_CPP_VERSION}</%text>"
-    "grpc"
-    "${" ".join(("-l" + l) for l in ["grpc++",] + list_absl_lib_files_for("grpc++"))}"
+    "${" ".join(["grpc"] + list_abseil_pkg_targets("grpc++"))}"
+    "${" ".join(("-l" + l) for l in ["grpc++"])}"
     ""
     "grpc++.pc")
 
     "gRPC++ unsecure"
     "C++ wrapper for gRPC without SSL"
     "<%text>${gRPC_CPP_VERSION}</%text>"
-    "grpc_unsecure"
-    "${" ".join(("-l" + l) for l in ["grpc++_unsecure",] + list_absl_lib_files_for("grpc++_unsecure"))}"
+    "${" ".join(["grpc_unsecure"] + list_abseil_pkg_targets("grpc++_unsecure"))}"
+    "${" ".join(("-l" + l) for l in ["grpc++_unsecure"])}"
     ""
     "grpc++_unsecure.pc")
index 9664575..24f176b 100644 (file)
       ss.header_mappings_dir = '.'
       ss.dependency "#{s.name}/Interface", version
       ss.dependency 'gRPC-Core', version
-      abseil_version = '1.20200923.3'
+      abseil_version = '1.20210324.0'
       % for abseil_spec in grpcpp_abseil_specs:
       ss.dependency '${abseil_spec}', abseil_version
       % endfor
index d9e6a85..254ebf5 100644 (file)
         files.update(lib.get(field, []))
     return list(sorted(files))
 
+  # Wrapped languages don't need to access EventEngine APIs. `port.h` is a
+  # special case - it's needed in some security code.
+  event_engine_files = [
+      file
+      for file in list_lib_files("grpc", ("public_headers", "headers", "src"))
+      if '/event_engine/' in file
+      and not file.endswith('/port.h')
+  ]
+
   # ObjectiveC doesn't use c-ares so we don't need address_sorting files at all
   address_sorting_unwanted_files = list_lib_files("address_sorting", ("public_headers", "headers", "src"))
 
   # ObjectiveC needs to obtain re2 explicitly unlike other languages; TODO @donnadionne make ObjC more consistent with others
-  grpc_private_files = list(sorted((set(list_lib_files("grpc", ("headers", "src"))) - set(address_sorting_unwanted_files)) | set(list_lib_files("re2", ("headers", "src")))))
-  grpc_public_headers = list(sorted((set(list_lib_files("grpc", ("public_headers",))) - set(address_sorting_unwanted_files)) | set(list_lib_files("re2", ("public_headers",)))))
-  grpc_private_headers = list(sorted((set(list_lib_files("grpc", ("headers",))) - set(address_sorting_unwanted_files)) | set(list_lib_files("re2", ("headers",)))))
+  grpc_private_files = list(
+      sorted((set(list_lib_files("grpc", ("headers", "src"))) -
+              set(address_sorting_unwanted_files) - set(event_engine_files))
+            | set(list_lib_files("re2", ("headers", "src")))))
+  grpc_public_headers = list(
+      sorted((set(list_lib_files("grpc", ("public_headers", ))) -
+              set(address_sorting_unwanted_files)) - set(event_engine_files)
+             | set(list_lib_files("re2", ("public_headers", )))))
+  grpc_private_headers = list(
+      sorted((set(list_lib_files("grpc", ("headers", ))) -
+              set(address_sorting_unwanted_files)) - set(event_engine_files)
+             | set(list_lib_files("re2", ("headers", )))))
   grpc_abseil_specs = list_abseil_specs("grpc")
   grpc_tests_abseil_specs = list(sorted(set(list_abseil_specs("end2end_tests")) - set(grpc_abseil_specs)))
 
     set(list_lib_files("end2end_tests", ("src", "headers")))
     - set(grpc_private_files)
     - set(address_sorting_unwanted_files)
+    - set(event_engine_files)
     - set([
       # Subprocess is not supported in tvOS and not needed by our tests.
       "test/core/util/subprocess_posix.cc",
     s.requires_arc = false
 
     name = 'grpc'
-    abseil_version = '1.20200923.3'
+    abseil_version = '1.20210324.0'
 
     # When creating a dynamic framework, name it grpc.framework instead of gRPC-Core.framework.
     # This lets users write their includes like `#include <grpc/grpc.h>` as opposed to `#include
       ss.header_mappings_dir = '.'
       ss.libraries = 'z'
       ss.dependency "#{s.name}/Interface", version
-      ss.dependency 'BoringSSL-GRPC', '0.0.17'
+      ss.dependency 'BoringSSL-GRPC', '0.0.18'
       % for abseil_spec in grpc_abseil_specs:
       ss.dependency '${abseil_spec}', abseil_version
       % endfor
index e18bc3d..83f1ec5 100644 (file)
@@ -1,8 +1,8 @@
 %YAML 1.2
 --- |
-  <%!
+  <%
   # TODO (mxyan): Make this list from build.yaml
-  textual_headers = ["include/grpc/support/atm_gcc_atomic.h",
+  textual_headers = {"include/grpc/support/atm_gcc_atomic.h",
                      "include/grpc/support/atm_gcc_sync.h",
                      "include/grpc/support/atm_windows.h",
                      "include/grpc/support/sync_custom.h",
                      "include/grpc/impl/codegen/atm_windows.h",
                      "include/grpc/impl/codegen/sync_custom.h",
                      "include/grpc/impl/codegen/sync_posix.h",
-                     "include/grpc/impl/codegen/sync_windows.h"]
-
-  def grpc_public_headers_no_dir(libs):
-    out = []
-    for lib in libs:
-      if lib.name in ("grpc", "gpr"):
-        out += lib.get('public_headers', [])
-    out = [f for f in out if f not in textual_headers]
-    out = [hdr.split('/', 2)[2] for hdr in out]
-    return out
-
-  # Generate the list of platform-specific headers as textual headers so that
-  # they are not built when the module is built but only when they are named by
-  # an #include directive.
-  def grpc_public_textual_headers_no_dir(libs):
-    out = []
-    for lib in libs:
-      if lib.name in ("grpc", "gpr"):
-        out += lib.get('public_headers', [])
-    out = [f for f in out if f in textual_headers]
-    out = [hdr.split('/', 2)[2] for hdr in out]
-    return out
+                     "include/grpc/impl/codegen/sync_windows.h"}
+
+  grpc_public_headers = {
+      file for lib in libs for file in lib.get('public_headers', [])
+      if lib.name in ("grpc", "gpr")
+  }
+
+  event_engine_files = {
+      file for file in grpc_public_headers if 'event_engine' in file
+  }
+
+  def un_dir(files):
+    return {f.split ('/', 2)[2] for f in files}
 
   def header_lines(files):
     return ('\n  ').join('header "%s"' % f for f in files)
   framework module grpc {
     umbrella header "grpc.h"
 
-    ${header_lines(grpc_public_headers_no_dir(libs))}
+  ${header_lines(
+      sorted(un_dir(grpc_public_headers - event_engine_files -
+                    textual_headers)))}
 
-    ${textual_header_lines(grpc_public_textual_headers_no_dir(libs))}
+  ${textual_header_lines(
+      sorted(un_dir(grpc_public_headers.intersection(textual_headers) -
+                    event_engine_files)))}
 
     export *
     module * { export * }
index 0cb3154..4e9f2c3 100644 (file)
@@ -27,4 +27,6 @@
 
   const char* grpc_version_string(void) { return "${settings.core_version}"; }
 
-  const char* grpc_g_stands_for(void) { return "${settings.g_stands_for}"; }
+  const char* grpc_g_stands_for(void) {
+    return "${settings.g_stands_for}";
+  }
index b949e70..c927fb9 100644 (file)
@@ -69,7 +69,7 @@
 
   Pod::Spec.new do |s|
     s.name     = 'BoringSSL-GRPC'
-    version = '0.0.17'
+    version = '0.0.18'
     s.version  = version
     s.summary  = 'BoringSSL is a fork of OpenSSL that is designed to meet Google\'s needs.'
     # Adapted from the homepage:
diff --git a/templates/src/python/grpcio_admin/grpc_version.py.template b/templates/src/python/grpcio_admin/grpc_version.py.template
new file mode 100644 (file)
index 0000000..45a4fbc
--- /dev/null
@@ -0,0 +1,19 @@
+%YAML 1.2
+--- |
+  # Copyright 2021 The gRPC Authors
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #     http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+
+  # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_admin/grpc_version.py.template`!!!
+
+  VERSION = '${settings.python_version.pep440()}'
diff --git a/templates/src/python/grpcio_csds/grpc_version.py.template b/templates/src/python/grpcio_csds/grpc_version.py.template
new file mode 100644 (file)
index 0000000..b4a497a
--- /dev/null
@@ -0,0 +1,19 @@
+%YAML 1.2
+--- |
+  # Copyright 2021 The gRPC Authors
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #     http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+
+  # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_csds/grpc_version.py.template`!!!
+
+  VERSION = '${settings.python_version.pep440()}'
index 2932d7a..5cadf57 100644 (file)
@@ -27,6 +27,8 @@
     return False
   def is_cronet_header(hdr):
     return "cronet" in hdr
+  def is_event_engine_header(hdr):
+    return "/event_engine/" in hdr
   hdrs = set()
   pfx = 'include/'
   for lib in libs:
@@ -34,6 +36,7 @@
     for hdr in lib.get('public_headers', []):
       if is_platform_header(hdr): continue
       if is_cronet_header(hdr): continue
+      if is_event_engine_header(hdr): continue
       assert(hdr[0:len(pfx)] == pfx)
       hdrs.add(hdr[len(pfx):])
   hdrs = sorted(list(hdrs))
index c908a63..292eaa8 100644 (file)
@@ -1,6 +1,6 @@
 %YAML 1.2
 --- |
-  # Copyright 2015 gRPC authors.
+  # Copyright 2021 The gRPC Authors
   #
   # Licensed under the Apache License, Version 2.0 (the "License");
   # you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
   # See the License for the specific language governing permissions and
   # limitations under the License.
   
-  FROM golang:1.11
+  FROM golang:1.16
   
   <%include file="../../go_path.include"/>
   <%include file="../../python_deps.include"/>
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_go1.16/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_go1.16/Dockerfile.template
new file mode 100644 (file)
index 0000000..292eaa8
--- /dev/null
@@ -0,0 +1,23 @@
+%YAML 1.2
+--- |
+  # Copyright 2021 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 golang:1.16
+  
+  <%include file="../../go_path.include"/>
+  <%include file="../../python_deps.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh.template b/templates/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh.template
new file mode 100644 (file)
index 0000000..a08798b
--- /dev/null
@@ -0,0 +1,3 @@
+%YAML 1.2
+--- |
+  <%include file="../../go_build_interop.sh.include"/>  
similarity index 54%
rename from test/core/iomgr/poller/BUILD
rename to test/core/address_utils/BUILD
index e5998f3..a01a033 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2019 gRPC authors.
+# 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.
@@ -17,26 +17,44 @@ load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package")
 licenses(["notice"])
 
 grpc_package(
-    name = "test/core/iomgr/poller",
-    visibility = "public",
-)  # Used to test IO poller implementations.
+    name = "test/core/address_utils",
+    visibility = "private",
+)
 
 grpc_cc_test(
-    name = "eventmanager_libuv_test",
-    srcs = ["eventmanager_libuv_test.cc"],
+    name = "sockaddr_utils_test",
+    srcs = ["sockaddr_utils_test.cc"],
     external_deps = [
         "gtest",
     ],
     language = "C++",
-    tags = [
-        # TSAN has a false-positive for ShutdownRefAsync
-        # https://github.com/grpc/grpc/issues/24242
-        "notsan",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "parse_address_test",
+    srcs = ["parse_address_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
     ],
+)
+
+grpc_cc_test(
+    name = "parse_address_with_named_scope_id_test",
+    srcs = ["parse_address_with_named_scope_id_test.cc"],
+    language = "C++",
+    tags = ["no_windows"],
     uses_polling = False,
     deps = [
-        "//:eventmanager_libuv",
-        "//:grpc_base_c",
+        "//:gpr",
+        "//:grpc",
         "//test/core/util:grpc_test_util",
     ],
 )
similarity index 97%
rename from test/core/iomgr/parse_address_test.cc
rename to test/core/address_utils/parse_address_test.cc
index d61ff5d..a1730ff 100644 (file)
@@ -16,9 +16,9 @@
  *
  */
 
-#include "src/core/lib/iomgr/parse_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/socket_utils.h"
 
 #include <string.h>
 #ifdef GRPC_HAVE_UNIX_SOCKET
@@ -16,9 +16,9 @@
  *
  */
 
-#include "src/core/lib/iomgr/parse_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/socket_utils.h"
 
 #include <net/if.h>
 #include <string.h>
similarity index 97%
rename from test/core/iomgr/sockaddr_utils_test.cc
rename to test/core/address_utils/sockaddr_utils_test.cc
index 14842bd..208fb22 100644 (file)
@@ -18,7 +18,7 @@
 // using that endpoint. Because of various transitive includes in uv.h,
 // including windows.h on Windows, uv.h must be included before other system
 // headers. Therefore, sockaddr.h must always be included first
-#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/socket_utils.h"
 
@@ -227,11 +227,13 @@ void VerifySocketAddressMatch(const std::string& ip_address,
                               const std::string& subnet, uint32_t mask_bits,
                               bool success) {
   grpc_resolved_address addr;
-  grpc_string_to_sockaddr(&addr, ip_address.c_str(), false);
+  ASSERT_EQ(grpc_string_to_sockaddr(&addr, ip_address.c_str(), false),
+            GRPC_ERROR_NONE);
   // Setting the port has no effect on the match.
   grpc_sockaddr_set_port(&addr, 12345);
   grpc_resolved_address subnet_addr;
-  grpc_string_to_sockaddr(&subnet_addr, subnet.c_str(), false);
+  ASSERT_EQ(grpc_string_to_sockaddr(&subnet_addr, subnet.c_str(), false),
+            GRPC_ERROR_NONE);
   grpc_sockaddr_mask_bits(&subnet_addr, mask_bits);
   EXPECT_EQ(grpc_sockaddr_match_subnet(&addr, &subnet_addr, mask_bits), success)
       << "IP=" << ip_address << " Subnet=" << subnet << " Mask=" << mask_bits;
index 1c9457e..c3a61ed 100644 (file)
@@ -57,7 +57,7 @@ static void thd_func(void* arg) {
 }
 
 /* Sets the done_write event */
-static void set_done_write(void* arg, grpc_error* /*error*/) {
+static void set_done_write(void* arg, grpc_error_handle /*error*/) {
   gpr_event* done_write = static_cast<gpr_event*>(arg);
   gpr_event_set(done_write, reinterpret_cast<void*>(1));
 }
@@ -70,7 +70,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
 }
 
 /* Sets the read_done event */
-static void set_read_done(void* arg, grpc_error* /*error*/) {
+static void set_read_done(void* arg, grpc_error_handle /*error*/) {
   gpr_event* read_done = static_cast<gpr_event*>(arg);
   gpr_event_set(read_done, reinterpret_cast<void*>(1));
 }
index b154ad2..409e913 100644 (file)
 #include "src/core/lib/surface/channel_init.h"
 #include "test/core/util/test_config.h"
 
-static grpc_error* channel_init_func(grpc_channel_element* /*elem*/,
-                                     grpc_channel_element_args* /*args*/) {
+static grpc_error_handle channel_init_func(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* call_init_func(grpc_call_element* /*elem*/,
-                                  const grpc_call_element_args* /*args*/) {
+static grpc_error_handle call_init_func(
+    grpc_call_element* /*elem*/, const grpc_call_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
index 58f854b..8c872c1 100644 (file)
@@ -27,8 +27,8 @@
 #include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/test_config.h"
 
-static grpc_error* channel_init_func(grpc_channel_element* elem,
-                                     grpc_channel_element_args* args) {
+static grpc_error_handle channel_init_func(grpc_channel_element* elem,
+                                           grpc_channel_element_args* args) {
   GPR_ASSERT(args->channel_args->num_args == 1);
   GPR_ASSERT(args->channel_args->args[0].type == GRPC_ARG_INTEGER);
   GPR_ASSERT(0 == strcmp(args->channel_args->args[0].key, "test_key"));
@@ -39,8 +39,8 @@ static grpc_error* channel_init_func(grpc_channel_element* elem,
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* call_init_func(grpc_call_element* elem,
-                                  const grpc_call_element_args* /*args*/) {
+static grpc_error_handle call_init_func(
+    grpc_call_element* elem, const grpc_call_element_args* /*args*/) {
   ++*static_cast<int*>(elem->channel_data);
   *static_cast<int*>(elem->call_data) = 0;
   return GRPC_ERROR_NONE;
@@ -64,12 +64,12 @@ static void channel_func(grpc_channel_element* elem,
   ++*static_cast<int*>(elem->channel_data);
 }
 
-static void free_channel(void* arg, grpc_error* /*error*/) {
+static void free_channel(void* arg, grpc_error_handle /*error*/) {
   grpc_channel_stack_destroy(static_cast<grpc_channel_stack*>(arg));
   gpr_free(arg);
 }
 
-static void free_call(void* arg, grpc_error* /*error*/) {
+static void free_call(void* arg, grpc_error_handle /*error*/) {
   grpc_call_stack_destroy(static_cast<grpc_call_stack*>(arg), nullptr, nullptr);
   gpr_free(arg);
 }
@@ -127,7 +127,7 @@ static void test_create_channel_stack(void) {
       nullptr,                 /* arena */
       nullptr,                 /* call_combiner */
   };
-  grpc_error* error =
+  grpc_error_handle error =
       grpc_call_stack_init(channel_stack, 1, free_call, call_stack, &args);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(call_stack->count == 1);
index fa8e660..cc17a33 100644 (file)
@@ -105,9 +105,9 @@ void ValidateGetTopChannels(size_t expected_channels) {
   std::string json_str = ChannelzRegistry::GetTopChannels(0);
   grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(
       json_str.c_str());
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   // This check will naturally have to change when we support pagination.
   // tracked: https://github.com/grpc/grpc/issues/16019.
@@ -125,9 +125,9 @@ void ValidateGetServers(size_t expected_servers) {
   std::string json_str = ChannelzRegistry::GetServers(0);
   grpc::testing::ValidateGetServersResponseProtoJsonTranslation(
       json_str.c_str());
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   // This check will naturally have to change when we support pagination.
   // tracked: https://github.com/grpc/grpc/issues/16019.
@@ -207,9 +207,9 @@ void ValidateChildInteger(const Json::Object& object, const std::string& key,
 
 void ValidateCounters(const std::string& json_str,
                       const ValidateChannelDataArgs& args) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(json.type(), Json::Type::OBJECT);
   Json::Object* object = json.mutable_object();
   Json& data = (*object)["data"];
@@ -365,9 +365,9 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsPagination) {
   std::string json_str = ChannelzRegistry::GetTopChannels(0);
   grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(
       json_str.c_str());
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   // 100 is the pagination limit.
   ValidateJsonArraySize((*parsed_json.mutable_object())["channel"], 100);
@@ -378,7 +378,7 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsPagination) {
       json_str.c_str());
   error = GRPC_ERROR_NONE;
   parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   ValidateJsonArraySize((*parsed_json.mutable_object())["channel"], 50);
   ValidateJsonEnd(parsed_json, true);
@@ -390,9 +390,9 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidCheck) {
   ChannelFixture channels[kNumChannels];
   (void)channels;  // suppress unused variable error
   std::string json_str = ChannelzRegistry::GetTopChannels(0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   Json& array = (*parsed_json.mutable_object())["channel"];
   ValidateJsonArraySize(array, kNumChannels);
@@ -410,9 +410,9 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMiddleUuidCheck) {
   (void)channels;  // suppress unused variable error
   // Only query for the end of the channels.
   std::string json_str = ChannelzRegistry::GetTopChannels(kMidQuery);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   Json& array = (*parsed_json.mutable_object())["channel"];
   ValidateJsonArraySize(array, kNumChannels - kMidQuery + 1);
@@ -432,9 +432,9 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsNoHitUuid) {
   (void)channels;                   // suppress unused variable error
   // Query in the middle of the server channels.
   std::string json_str = ChannelzRegistry::GetTopChannels(45);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   Json& array = (*parsed_json.mutable_object())["channel"];
   ValidateJsonArraySize(array, 10);
@@ -453,9 +453,9 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMoreGaps) {
   ChannelFixture channel_with_uuid5;
   // Current state of list: [1, NULL, 3, NULL, 5]
   std::string json_str = ChannelzRegistry::GetTopChannels(2);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   Json array = (*parsed_json.mutable_object())["channel"];
   ValidateJsonArraySize(array, 2);
@@ -465,7 +465,7 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMoreGaps) {
   json_str = ChannelzRegistry::GetTopChannels(4);
   error = GRPC_ERROR_NONE;
   parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   array = (*parsed_json.mutable_object())["channel"];
   ValidateJsonArraySize(array, 1);
@@ -486,9 +486,9 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidAfterCompaction) {
     }
   }
   std::string json_str = ChannelzRegistry::GetTopChannels(0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json parsed_json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT);
   Json& array = (*parsed_json.mutable_object())["channel"];
   ValidateJsonArraySize(array, kLoopIterations);
index 0c6b6d0..ef33b14 100644 (file)
@@ -33,7 +33,7 @@ class FakeCertificateProviderFactory1 : public CertificateProviderFactory {
   const char* name() const override { return "fake1"; }
 
   RefCountedPtr<Config> CreateCertificateProviderConfig(
-      const Json& /*config_json*/, grpc_error** /*error*/) override {
+      const Json& /*config_json*/, grpc_error_handle* /*error*/) override {
     return nullptr;
   }
 
@@ -48,7 +48,7 @@ class FakeCertificateProviderFactory2 : public CertificateProviderFactory {
   const char* name() const override { return "fake2"; }
 
   RefCountedPtr<Config> CreateCertificateProviderConfig(
-      const Json& /*config_json*/, grpc_error** /*error*/) override {
+      const Json& /*config_json*/, grpc_error_handle* /*error*/) override {
     return nullptr;
   }
 
index f79031d..d82d92d 100644 (file)
@@ -41,7 +41,7 @@ static void my_resolve_address(const char* addr, const char* /*default_port*/,
                                grpc_resolved_addresses** addrs) {
   gpr_mu_lock(&g_mu);
   GPR_ASSERT(0 == strcmp("test", addr));
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (g_fail_resolution) {
     g_fail_resolution = false;
     gpr_mu_unlock(&g_mu);
@@ -69,7 +69,7 @@ static grpc_ares_request* my_dns_lookup_ares_locked(
     std::shared_ptr<grpc_core::WorkSerializer> /*combiner*/) {  // NOLINT
   gpr_mu_lock(&g_mu);
   GPR_ASSERT(0 == strcmp("test", addr));
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (g_fail_resolution) {
     g_fail_resolution = false;
     gpr_mu_unlock(&g_mu);
@@ -113,7 +113,7 @@ class ResultHandler : public grpc_core::Resolver::ResultHandler {
  public:
   struct ResolverOutput {
     grpc_core::Resolver::Result result;
-    grpc_error* error = nullptr;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     gpr_event ev;
 
     ResolverOutput() { gpr_event_init(&ev); }
@@ -133,7 +133,7 @@ class ResultHandler : public grpc_core::Resolver::ResultHandler {
     gpr_event_set(&output->ev, reinterpret_cast<void*>(1));
   }
 
-  void ReturnError(grpc_error* error) override {
+  void ReturnError(grpc_error_handle error) override {
     ResolverOutput* output =
         reinterpret_cast<ResolverOutput*>(gpr_atm_acq_load(&output_));
     GPR_ASSERT(output != nullptr);
index cfedceb..ed54022 100644 (file)
@@ -24,9 +24,9 @@
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/memory.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/work_serializer.h"
 #include "test/core/util/test_config.h"
 
@@ -86,7 +86,7 @@ static void test_resolve_address_impl(const char* name,
   grpc_core::ExecCtx::Get()->InvalidateNow();
 }
 
-static grpc_error* test_blocking_resolve_address_impl(
+static grpc_error_handle test_blocking_resolve_address_impl(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   return default_resolve_address->blocking_resolve_address(name, default_port,
@@ -136,7 +136,7 @@ static gpr_timespec test_deadline(void) {
   return grpc_timeout_seconds_to_deadline(100);
 }
 
-static void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
+static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 static void iomgr_args_init(iomgr_args* args) {
   gpr_event_init(&args->ev);
@@ -212,8 +212,9 @@ class ResultHandler : public grpc_core::Resolver::ResultHandler {
     cb(state);
   }
 
-  void ReturnError(grpc_error* error) override {
-    gpr_log(GPR_ERROR, "resolver returned error: %s", grpc_error_string(error));
+  void ReturnError(grpc_error_handle error) override {
+    gpr_log(GPR_ERROR, "resolver returned error: %s",
+            grpc_error_std_string(error).c_str());
     GPR_ASSERT(false);
   }
 
index 6aa6371..7bc867e 100644 (file)
@@ -32,7 +32,7 @@ static std::shared_ptr<grpc_core::WorkSerializer>* g_work_serializer;
 
 class TestResultHandler : public grpc_core::Resolver::ResultHandler {
   void ReturnResult(grpc_core::Resolver::Result /*result*/) override {}
-  void ReturnError(grpc_error* /*error*/) override {}
+  void ReturnError(grpc_error_handle /*error*/) override {}
 };
 
 static void test_succeeds(grpc_core::ResolverFactory* factory,
index 5dde6be..0d20844 100644 (file)
@@ -28,9 +28,9 @@
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/work_serializer.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 
@@ -58,7 +58,7 @@ class ResultHandler : public grpc_core::Resolver::ResultHandler {
     ev_ = nullptr;
   }
 
-  void ReturnError(grpc_error* /*error*/) override {}
+  void ReturnError(grpc_error_handle /*error*/) override {}
 
  private:
   grpc_core::Resolver::Result expected_;
index 9dfd883..8b06925 100644 (file)
@@ -34,7 +34,9 @@ class ResultHandler : public grpc_core::Resolver::ResultHandler {
  public:
   void ReturnResult(grpc_core::Resolver::Result /*result*/) override {}
 
-  void ReturnError(grpc_error* error) override { GRPC_ERROR_UNREF(error); }
+  void ReturnError(grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
 };
 
 static void test_succeeds(grpc_core::ResolverFactory* factory,
index cc170c0..fb5e554 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <grpc/grpc.h>
 #include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
+#include "src/core/ext/filters/client_channel/retry_service_config.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
 #include "src/core/ext/filters/client_channel/service_config_parser.h"
 #include "src/core/ext/filters/message_size/message_size_filter.h"
 namespace grpc_core {
 namespace testing {
 
+//
+// ServiceConfig tests
+//
+
 // Set this channel arg to true to disable parsing.
 #define GRPC_ARG_DISABLE_PARSING "disable_parsing"
 
@@ -50,7 +55,7 @@ class TestParser1 : public ServiceConfigParser::Parser {
  public:
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
       const grpc_channel_args* args, const Json& json,
-      grpc_error** error) override {
+      grpc_error_handle* error) override {
     GPR_DEBUG_ASSERT(error != nullptr);
     if (grpc_channel_args_find_bool(args, GRPC_ARG_DISABLE_PARSING, false)) {
       return nullptr;
@@ -86,7 +91,7 @@ class TestParser2 : public ServiceConfigParser::Parser {
  public:
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
       const grpc_channel_args* args, const Json& json,
-      grpc_error** error) override {
+      grpc_error_handle* error) override {
     GPR_DEBUG_ASSERT(error != nullptr);
     if (grpc_channel_args_find_bool(args, GRPC_ARG_DISABLE_PARSING, false)) {
       return nullptr;
@@ -123,7 +128,7 @@ class ErrorParser : public ServiceConfigParser::Parser {
  public:
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
       const grpc_channel_args* /*arg*/, const Json& /*json*/,
-      grpc_error** error) override {
+      grpc_error_handle* error) override {
     GPR_DEBUG_ASSERT(error != nullptr);
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(MethodError());
     return nullptr;
@@ -131,7 +136,7 @@ class ErrorParser : public ServiceConfigParser::Parser {
 
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
       const grpc_channel_args* /*arg*/, const Json& /*json*/,
-      grpc_error** error) override {
+      grpc_error_handle* error) override {
     GPR_DEBUG_ASSERT(error != nullptr);
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(GlobalError());
     return nullptr;
@@ -158,18 +163,18 @@ class ServiceConfigTest : public ::testing::Test {
 
 TEST_F(ServiceConfigTest, ErrorCheck1) {
   const char* test_json = "";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex("JSON parse error"));
   GRPC_ERROR_UNREF(error);
 }
 
 TEST_F(ServiceConfigTest, BasicTest1) {
   const char* test_json = "{}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
 }
 
 TEST_F(ServiceConfigTest, SkipMethodConfigWithNoNameOrEmptyName) {
@@ -179,9 +184,9 @@ TEST_F(ServiceConfigTest, SkipMethodConfigWithNoNameOrEmptyName) {
       "  {\"name\":[], \"method_param\":1},"
       "  {\"name\":[{\"service\":\"TestServ\"}], \"method_param\":2}"
       "]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   ASSERT_NE(vector_ptr, nullptr);
@@ -195,10 +200,10 @@ TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNames) {
       "  {\"name\":[{\"service\":\"TestServ\"}]},"
       "  {\"name\":[{\"service\":\"TestServ\"}]}"
       "]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("Service config parsing error.*referenced_errors"
                                ".*Method Params.*referenced_errors"
                                ".*methodConfig.*referenced_errors"
@@ -212,10 +217,10 @@ TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithNullMethod) {
       "  {\"name\":[{\"service\":\"TestServ\",\"method\":null}]},"
       "  {\"name\":[{\"service\":\"TestServ\"}]}"
       "]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("Service config parsing error.*referenced_errors"
                                ".*Method Params.*referenced_errors"
                                ".*methodConfig.*referenced_errors"
@@ -229,10 +234,10 @@ TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithEmptyMethod) {
       "  {\"name\":[{\"service\":\"TestServ\",\"method\":\"\"}]},"
       "  {\"name\":[{\"service\":\"TestServ\"}]}"
       "]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("Service config parsing error.*referenced_errors"
                                ".*Method Params.*referenced_errors"
                                ".*methodConfig.*referenced_errors"
@@ -246,10 +251,10 @@ TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigs) {
       "  {\"name\":[{}]},"
       "  {\"name\":[{}]}"
       "]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("Service config parsing error.*referenced_errors"
                                ".*Method Params.*referenced_errors"
                                ".*methodConfig.*referenced_errors"
@@ -263,10 +268,10 @@ TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithNullService) {
       "  {\"name\":[{\"service\":null}]},"
       "  {\"name\":[{}]}"
       "]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("Service config parsing error.*referenced_errors"
                                ".*Method Params.*referenced_errors"
                                ".*methodConfig.*referenced_errors"
@@ -280,10 +285,10 @@ TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithEmptyService) {
       "  {\"name\":[{\"service\":\"\"}]},"
       "  {\"name\":[{}]}"
       "]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("Service config parsing error.*referenced_errors"
                                ".*Method Params.*referenced_errors"
                                ".*methodConfig.*referenced_errors"
@@ -294,16 +299,16 @@ TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithEmptyService) {
 TEST_F(ServiceConfigTest, ValidMethodConfig) {
   const char* test_json =
       "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}]}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
 }
 
 TEST_F(ServiceConfigTest, Parser1BasicTest1) {
   const char* test_json = "{\"global_param\":5}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ((static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0)))
                 ->value(),
             5);
@@ -314,9 +319,9 @@ TEST_F(ServiceConfigTest, Parser1BasicTest1) {
 
 TEST_F(ServiceConfigTest, Parser1BasicTest2) {
   const char* test_json = "{\"global_param\":1000}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ((static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0)))
                 ->value(),
             1000);
@@ -327,17 +332,17 @@ TEST_F(ServiceConfigTest, Parser1DisabledViaChannelArg) {
       const_cast<char*>(GRPC_ARG_DISABLE_PARSING), 1);
   grpc_channel_args args = {1, &arg};
   const char* test_json = "{\"global_param\":5}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(&args, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(svc_cfg->GetGlobalParsedConfig(0), nullptr);
 }
 
 TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) {
   const char* test_json = "{\"global_param\":\"5\"}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(absl::StrCat(
                   "Service config parsing error.*referenced_errors.*"
                   "Global Params.*referenced_errors.*",
@@ -347,9 +352,9 @@ TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) {
 
 TEST_F(ServiceConfigTest, Parser1ErrorInvalidValue) {
   const char* test_json = "{\"global_param\":-5}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(absl::StrCat(
                   "Service config parsing error.*referenced_errors.*"
                   "Global Params.*referenced_errors.*",
@@ -361,9 +366,9 @@ TEST_F(ServiceConfigTest, Parser2BasicTest) {
   const char* test_json =
       "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
       "\"method_param\":5}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   ASSERT_NE(vector_ptr, nullptr);
@@ -378,9 +383,9 @@ TEST_F(ServiceConfigTest, Parser2DisabledViaChannelArg) {
   const char* test_json =
       "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
       "\"method_param\":5}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(&args, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   ASSERT_NE(vector_ptr, nullptr);
@@ -392,9 +397,9 @@ TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) {
   const char* test_json =
       "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
       "\"method_param\":\"5\"}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(absl::StrCat(
                   "Service config parsing error.*referenced_errors\":\\[.*"
                   "Method Params.*referenced_errors.*methodConfig.*"
@@ -407,9 +412,9 @@ TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) {
   const char* test_json =
       "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
       "\"method_param\":-5}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(absl::StrCat(
                   "Service config parsing error.*referenced_errors\":\\[.*"
                   "Method Params.*referenced_errors.*methodConfig.*"
@@ -435,10 +440,10 @@ class ErroredParsersScopingTest : public ::testing::Test {
 
 TEST_F(ErroredParsersScopingTest, GlobalParams) {
   const char* test_json = "{}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex(absl::StrCat(
           "Service config parsing error.*referenced_errors\":\\[.*"
           "Global Params.*referenced_errors.*",
@@ -448,10 +453,10 @@ TEST_F(ErroredParsersScopingTest, GlobalParams) {
 
 TEST_F(ErroredParsersScopingTest, MethodParams) {
   const char* test_json = "{\"methodConfig\": [{}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex(absl::StrCat(
           "Service config parsing error.*referenced_errors\":\\[.*"
           "Global Params.*referenced_errors.*",
@@ -462,6 +467,10 @@ TEST_F(ErroredParsersScopingTest, MethodParams) {
   GRPC_ERROR_UNREF(error);
 }
 
+//
+// client_channel parser tests
+//
+
 class ClientChannelParserTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -476,9 +485,9 @@ class ClientChannelParserTest : public ::testing::Test {
 
 TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) {
   const char* test_json = "{\"loadBalancingConfig\": [{\"pick_first\":{}}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* parsed_config =
       static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
           svc_cfg->GetGlobalParsedConfig(0));
@@ -489,9 +498,9 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) {
 TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) {
   const char* test_json =
       "{\"loadBalancingConfig\": [{\"round_robin\":{}}, {}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto parsed_config =
       static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
           svc_cfg->GetGlobalParsedConfig(0));
@@ -503,9 +512,9 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
   const char* test_json =
       "{\"loadBalancingConfig\": "
       "[{\"grpclb\":{\"childPolicy\":[{\"pick_first\":{}}]}}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* parsed_config =
       static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
           svc_cfg->GetGlobalParsedConfig(0));
@@ -526,9 +535,9 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) {
       "    } }\n"
       "  ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* parsed_config =
       static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
           svc_cfg->GetGlobalParsedConfig(0));
@@ -538,9 +547,9 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) {
 
 TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) {
   const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Global Params.*referenced_errors.*"
@@ -556,9 +565,9 @@ TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) {
       "  {\"grpclb\":{\"childPolicy\":1}},"
       "  {\"round_robin\":{}}"
       "]}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Global Params.*referenced_errors.*"
@@ -572,9 +581,9 @@ TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) {
 
 TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) {
   const char* test_json = "{\"loadBalancingPolicy\":\"pick_first\"}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* parsed_config =
       static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
           svc_cfg->GetGlobalParsedConfig(0));
@@ -583,9 +592,9 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) {
 
 TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) {
   const char* test_json = "{\"loadBalancingPolicy\":\"PICK_FIRST\"}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* parsed_config =
       static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
           svc_cfg->GetGlobalParsedConfig(0));
@@ -594,9 +603,9 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) {
 
 TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) {
   const char* test_json = "{\"loadBalancingPolicy\":\"unknown\"}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Global Params.*referenced_errors.*"
@@ -608,9 +617,9 @@ TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) {
 TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) {
   const char* test_json =
       "{\"loadBalancingPolicy\":\"xds_cluster_resolver_experimental\"}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Global Params.*referenced_errors.*"
@@ -621,84 +630,6 @@ TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) {
   GRPC_ERROR_UNREF(error);
 }
 
-TEST_F(ClientChannelParserTest, ValidRetryThrottling) {
-  const char* test_json =
-      "{\n"
-      "  \"retryThrottling\": {\n"
-      "    \"maxTokens\": 2,\n"
-      "    \"tokenRatio\": 1.0\n"
-      "  }\n"
-      "}";
-  grpc_error* error = GRPC_ERROR_NONE;
-  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
-  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);
-}
-
-TEST_F(ClientChannelParserTest, RetryThrottlingMissingFields) {
-  const char* test_json =
-      "{\n"
-      "  \"retryThrottling\": {\n"
-      "  }\n"
-      "}";
-  grpc_error* error = GRPC_ERROR_NONE;
-  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
-              ::testing::ContainsRegex(
-                  "Service config parsing error.*referenced_errors.*"
-                  "Global Params.*referenced_errors.*"
-                  "Client channel global parser.*referenced_errors.*"
-                  "field:retryThrottling field:maxTokens error:Not found.*"
-                  "field:retryThrottling field:tokenRatio error:Not found"));
-  GRPC_ERROR_UNREF(error);
-}
-
-TEST_F(ClientChannelParserTest, InvalidRetryThrottlingNegativeMaxTokens) {
-  const char* test_json =
-      "{\n"
-      "  \"retryThrottling\": {\n"
-      "    \"maxTokens\": -2,\n"
-      "    \"tokenRatio\": 1.0\n"
-      "  }\n"
-      "}";
-  grpc_error* error = GRPC_ERROR_NONE;
-  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
-              ::testing::ContainsRegex(
-                  "Service config parsing error.*referenced_errors.*"
-                  "Global Params.*referenced_errors.*"
-                  "Client channel global parser.*referenced_errors.*"
-                  "field:retryThrottling field:maxTokens error:should "
-                  "be greater than zero"));
-  GRPC_ERROR_UNREF(error);
-}
-
-TEST_F(ClientChannelParserTest, InvalidRetryThrottlingInvalidTokenRatio) {
-  const char* test_json =
-      "{\n"
-      "  \"retryThrottling\": {\n"
-      "    \"maxTokens\": 2,\n"
-      "    \"tokenRatio\": -1\n"
-      "  }\n"
-      "}";
-  grpc_error* error = GRPC_ERROR_NONE;
-  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
-              ::testing::ContainsRegex(
-                  "Service config parsing error.*referenced_errors.*"
-                  "Global Params.*referenced_errors.*"
-                  "Client channel global parser.*referenced_errors.*"
-                  "field:retryThrottling field:tokenRatio "
-                  "error:Failed parsing"));
-  GRPC_ERROR_UNREF(error);
-}
-
 TEST_F(ClientChannelParserTest, ValidTimeout) {
   const char* test_json =
       "{\n"
@@ -709,9 +640,9 @@ TEST_F(ClientChannelParserTest, ValidTimeout) {
       "    \"timeout\": \"5s\"\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   ASSERT_NE(vector_ptr, nullptr);
@@ -732,9 +663,9 @@ TEST_F(ClientChannelParserTest, InvalidTimeout) {
       "    \"timeout\": \"5sec\"\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Method Params.*referenced_errors.*"
@@ -755,9 +686,9 @@ TEST_F(ClientChannelParserTest, ValidWaitForReady) {
       "    \"waitForReady\": true\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   ASSERT_NE(vector_ptr, nullptr);
@@ -784,9 +715,9 @@ TEST_F(ClientChannelParserTest, InvalidWaitForReady) {
       "    \"waitForReady\": \"true\"\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Method Params.*referenced_errors.*"
@@ -796,7 +727,136 @@ TEST_F(ClientChannelParserTest, InvalidWaitForReady) {
   GRPC_ERROR_UNREF(error);
 }
 
-TEST_F(ClientChannelParserTest, ValidRetryPolicy) {
+TEST_F(ClientChannelParserTest, ValidHealthCheck) {
+  const char* test_json =
+      "{\n"
+      "  \"healthCheckConfig\": {\n"
+      "    \"serviceName\": \"health_check_service_name\"\n"
+      "    }\n"
+      "}";
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  ASSERT_NE(parsed_config, nullptr);
+  EXPECT_EQ(parsed_config->health_check_service_name(),
+            "health_check_service_name");
+}
+
+TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) {
+  const char* test_json =
+      "{\n"
+      "  \"healthCheckConfig\": {\n"
+      "    \"serviceName\": \"health_check_service_name\"\n"
+      "    },\n"
+      "  \"healthCheckConfig\": {\n"
+      "    \"serviceName\": \"health_check_service_name1\"\n"
+      "    }\n"
+      "}";
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
+  EXPECT_THAT(grpc_error_std_string(error),
+              ::testing::ContainsRegex(
+                  "JSON parsing failed.*referenced_errors.*"
+                  "duplicate key \"healthCheckConfig\" at index 104"));
+  GRPC_ERROR_UNREF(error);
+}
+
+//
+// retry parser tests
+//
+
+class RetryParserTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    ServiceConfigParser::Shutdown();
+    ServiceConfigParser::Init();
+    EXPECT_EQ(ServiceConfigParser::RegisterParser(
+                  absl::make_unique<internal::RetryServiceConfigParser>()),
+              0);
+  }
+};
+
+TEST_F(RetryParserTest, ValidRetryThrottling) {
+  const char* test_json =
+      "{\n"
+      "  \"retryThrottling\": {\n"
+      "    \"maxTokens\": 2,\n"
+      "    \"tokenRatio\": 1.0\n"
+      "  }\n"
+      "}";
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
+  const auto* parsed_config =
+      static_cast<grpc_core::internal::RetryGlobalConfig*>(
+          svc_cfg->GetGlobalParsedConfig(0));
+  ASSERT_NE(parsed_config, nullptr);
+  EXPECT_EQ(parsed_config->max_milli_tokens(), 2000);
+  EXPECT_EQ(parsed_config->milli_token_ratio(), 1000);
+}
+
+TEST_F(RetryParserTest, RetryThrottlingMissingFields) {
+  const char* test_json =
+      "{\n"
+      "  \"retryThrottling\": {\n"
+      "  }\n"
+      "}";
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
+  EXPECT_THAT(grpc_error_std_string(error),
+              ::testing::ContainsRegex(
+                  "Service config parsing error.*referenced_errors.*"
+                  "Global Params.*referenced_errors.*"
+                  "retryThrottling.*referenced_errors.*"
+                  "field:retryThrottling field:maxTokens error:Not found.*"
+                  "field:retryThrottling field:tokenRatio error:Not found"));
+  GRPC_ERROR_UNREF(error);
+}
+
+TEST_F(RetryParserTest, InvalidRetryThrottlingNegativeMaxTokens) {
+  const char* test_json =
+      "{\n"
+      "  \"retryThrottling\": {\n"
+      "    \"maxTokens\": -2,\n"
+      "    \"tokenRatio\": 1.0\n"
+      "  }\n"
+      "}";
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
+  EXPECT_THAT(grpc_error_std_string(error),
+              ::testing::ContainsRegex(
+                  "Service config parsing error.*referenced_errors.*"
+                  "Global Params.*referenced_errors.*"
+                  "retryThrottling.*referenced_errors.*"
+                  "field:retryThrottling field:maxTokens error:should "
+                  "be greater than zero"));
+  GRPC_ERROR_UNREF(error);
+}
+
+TEST_F(RetryParserTest, InvalidRetryThrottlingInvalidTokenRatio) {
+  const char* test_json =
+      "{\n"
+      "  \"retryThrottling\": {\n"
+      "    \"maxTokens\": 2,\n"
+      "    \"tokenRatio\": -1\n"
+      "  }\n"
+      "}";
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
+  EXPECT_THAT(grpc_error_std_string(error),
+              ::testing::ContainsRegex(
+                  "Service config parsing error.*referenced_errors.*"
+                  "Global Params.*referenced_errors.*"
+                  "retryThrottling.*referenced_errors.*"
+                  "field:retryThrottling field:tokenRatio "
+                  "error:Failed parsing"));
+  GRPC_ERROR_UNREF(error);
+}
+
+TEST_F(RetryParserTest, ValidRetryPolicy) {
   const char* test_json =
       "{\n"
       "  \"methodConfig\": [ {\n"
@@ -812,25 +872,25 @@ TEST_F(ClientChannelParserTest, ValidRetryPolicy) {
       "    }\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   ASSERT_NE(vector_ptr, nullptr);
   const auto* parsed_config =
-      static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>(
+      static_cast<grpc_core::internal::RetryMethodConfig*>(
           ((*vector_ptr)[0]).get());
-  ASSERT_NE(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));
+  ASSERT_NE(parsed_config, nullptr);
+  EXPECT_EQ(parsed_config->max_attempts(), 3);
+  EXPECT_EQ(parsed_config->initial_backoff(), 1000);
+  EXPECT_EQ(parsed_config->max_backoff(), 120000);
+  EXPECT_EQ(parsed_config->backoff_multiplier(), 1.6f);
+  EXPECT_TRUE(
+      parsed_config->retryable_status_codes().Contains(GRPC_STATUS_ABORTED));
 }
 
-TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxAttempts) {
+TEST_F(RetryParserTest, InvalidRetryPolicyMaxAttempts) {
   const char* test_json =
       "{\n"
       "  \"methodConfig\": [ {\n"
@@ -846,20 +906,19 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxAttempts) {
       "    }\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Method Params.*referenced_errors.*"
                   "methodConfig.*referenced_errors.*"
-                  "Client channel parser.*referenced_errors.*"
                   "retryPolicy.*referenced_errors.*"
                   "field:maxAttempts error:should be at least 2"));
   GRPC_ERROR_UNREF(error);
 }
 
-TEST_F(ClientChannelParserTest, InvalidRetryPolicyInitialBackoff) {
+TEST_F(RetryParserTest, InvalidRetryPolicyInitialBackoff) {
   const char* test_json =
       "{\n"
       "  \"methodConfig\": [ {\n"
@@ -875,21 +934,20 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyInitialBackoff) {
       "    }\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Method Params.*referenced_errors.*"
                   "methodConfig.*referenced_errors.*"
-                  "Client channel parser.*referenced_errors.*"
                   "retryPolicy.*referenced_errors.*"
                   "field:initialBackoff error:type should be STRING of the "
                   "form given by google.proto.Duration"));
   GRPC_ERROR_UNREF(error);
 }
 
-TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxBackoff) {
+TEST_F(RetryParserTest, InvalidRetryPolicyMaxBackoff) {
   const char* test_json =
       "{\n"
       "  \"methodConfig\": [ {\n"
@@ -905,21 +963,20 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxBackoff) {
       "    }\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Method Params.*referenced_errors.*"
                   "methodConfig.*referenced_errors.*"
-                  "Client channel parser.*referenced_errors.*"
                   "retryPolicy.*referenced_errors.*"
                   "field:maxBackoff error:type should be STRING of the form "
                   "given by google.proto.Duration"));
   GRPC_ERROR_UNREF(error);
 }
 
-TEST_F(ClientChannelParserTest, InvalidRetryPolicyBackoffMultiplier) {
+TEST_F(RetryParserTest, InvalidRetryPolicyBackoffMultiplier) {
   const char* test_json =
       "{\n"
       "  \"methodConfig\": [ {\n"
@@ -935,20 +992,19 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyBackoffMultiplier) {
       "    }\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Method Params.*referenced_errors.*"
                   "methodConfig.*referenced_errors.*"
-                  "Client channel parser.*referenced_errors.*"
                   "retryPolicy.*referenced_errors.*"
                   "field:backoffMultiplier error:should be of type number"));
   GRPC_ERROR_UNREF(error);
 }
 
-TEST_F(ClientChannelParserTest, InvalidRetryPolicyRetryableStatusCodes) {
+TEST_F(RetryParserTest, InvalidRetryPolicyRetryableStatusCodes) {
   const char* test_json =
       "{\n"
       "  \"methodConfig\": [ {\n"
@@ -964,55 +1020,21 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyRetryableStatusCodes) {
       "    }\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Method Params.*referenced_errors.*"
                   "methodConfig.*referenced_errors.*"
-                  "Client channel parser.*referenced_errors.*"
                   "retryPolicy.*referenced_errors.*"
                   "field:retryableStatusCodes error:should be non-empty"));
   GRPC_ERROR_UNREF(error);
 }
 
-TEST_F(ClientChannelParserTest, ValidHealthCheck) {
-  const char* test_json =
-      "{\n"
-      "  \"healthCheckConfig\": {\n"
-      "    \"serviceName\": \"health_check_service_name\"\n"
-      "    }\n"
-      "}";
-  grpc_error* error = GRPC_ERROR_NONE;
-  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
-  const auto* parsed_config =
-      static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
-          svc_cfg->GetGlobalParsedConfig(0));
-  ASSERT_NE(parsed_config, nullptr);
-  EXPECT_EQ(parsed_config->health_check_service_name(),
-            "health_check_service_name");
-}
-
-TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) {
-  const char* test_json =
-      "{\n"
-      "  \"healthCheckConfig\": {\n"
-      "    \"serviceName\": \"health_check_service_name\"\n"
-      "    },\n"
-      "  \"healthCheckConfig\": {\n"
-      "    \"serviceName\": \"health_check_service_name1\"\n"
-      "    }\n"
-      "}";
-  grpc_error* error = GRPC_ERROR_NONE;
-  auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
-              ::testing::ContainsRegex(
-                  "JSON parsing failed.*referenced_errors.*"
-                  "duplicate key \"healthCheckConfig\" at index 104"));
-  GRPC_ERROR_UNREF(error);
-}
+//
+// message_size parser tests
+//
 
 class MessageSizeParserTest : public ::testing::Test {
  protected:
@@ -1036,9 +1058,9 @@ TEST_F(MessageSizeParserTest, Valid) {
       "    \"maxResponseMessageBytes\": 1024\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
       grpc_slice_from_static_string("/TestServ/TestMethod"));
   ASSERT_NE(vector_ptr, nullptr);
@@ -1059,9 +1081,9 @@ TEST_F(MessageSizeParserTest, InvalidMaxRequestMessageBytes) {
       "    \"maxRequestMessageBytes\": -1024\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Method Params.*referenced_errors.*"
@@ -1081,9 +1103,9 @@ TEST_F(MessageSizeParserTest, InvalidMaxResponseMessageBytes) {
       "    \"maxResponseMessageBytes\": {}\n"
       "  } ]\n"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   auto svc_cfg = ServiceConfig::Create(nullptr, test_json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "Service config parsing error.*referenced_errors.*"
                   "Method Params.*referenced_errors.*"
index cb5427f..b4e2707 100644 (file)
@@ -95,12 +95,13 @@ static grpc_closure on_write;
 
 static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }
 
-static void done_write(void* /*arg*/, grpc_error* error) {
+static void done_write(void* /*arg*/, grpc_error_handle error) {
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   gpr_atm_rel_store(&state.done_atm, 1);
 }
 
-static void done_writing_settings_frame(void* /* arg */, grpc_error* error) {
+static void done_writing_settings_frame(void* /* arg */,
+                                        grpc_error_handle error) {
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   grpc_endpoint_read(state.tcp, &state.temp_incoming_buffer, &on_read,
                      /*urgent=*/false);
@@ -115,9 +116,10 @@ static void handle_write() {
   grpc_endpoint_write(state.tcp, &state.outgoing_buffer, &on_write, nullptr);
 }
 
-static void handle_read(void* /*arg*/, grpc_error* error) {
+static void handle_read(void* /*arg*/, grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "handle_read error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "handle_read error: %s",
+            grpc_error_std_string(error).c_str());
     return;
   }
   state.incoming_data_length += state.temp_incoming_buffer.length;
index 2b332dc..2307843 100644 (file)
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -60,7 +60,7 @@ static void drain_cq(grpc_completion_queue* cq) {
 
 static void log_resolved_addrs(const char* label, const char* hostname) {
   grpc_resolved_addresses* res = nullptr;
-  grpc_error* error = grpc_blocking_resolve_address(hostname, "80", &res);
+  grpc_error_handle error = grpc_blocking_resolve_address(hostname, "80", &res);
   if (error != GRPC_ERROR_NONE || res == nullptr) {
     GRPC_LOG_IF_ERROR(hostname, error);
     return;
@@ -277,7 +277,7 @@ void test_connect(const char* server_host, const char* client_host, int port,
 
 int external_dns_works(const char* host) {
   grpc_resolved_addresses* res = nullptr;
-  grpc_error* error = grpc_blocking_resolve_address(host, "80", &res);
+  grpc_error_handle error = grpc_blocking_resolve_address(host, "80", &res);
   GRPC_ERROR_UNREF(error);
   if (res != nullptr) {
     grpc_resolved_addresses_destroy(res);
index 62ef4bb..958b1b7 100644 (file)
@@ -125,6 +125,8 @@ extern void resource_quota_server(grpc_end2end_test_config config);
 extern void resource_quota_server_pre_init(void);
 extern void retry(grpc_end2end_test_config config);
 extern void retry_pre_init(void);
+extern void retry_cancel_during_delay(grpc_end2end_test_config config);
+extern void retry_cancel_during_delay_pre_init(void);
 extern void retry_cancellation(grpc_end2end_test_config config);
 extern void retry_cancellation_pre_init(void);
 extern void retry_disabled(grpc_end2end_test_config config);
@@ -133,6 +135,8 @@ extern void retry_exceeds_buffer_size_in_initial_batch(grpc_end2end_test_config
 extern void retry_exceeds_buffer_size_in_initial_batch_pre_init(void);
 extern void retry_exceeds_buffer_size_in_subsequent_batch(grpc_end2end_test_config config);
 extern void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void);
+extern void retry_lb_drop(grpc_end2end_test_config config);
+extern void retry_lb_drop_pre_init(void);
 extern void retry_non_retriable_status(grpc_end2end_test_config config);
 extern void retry_non_retriable_status_pre_init(void);
 extern void retry_non_retriable_status_before_recv_trailing_metadata_started(grpc_end2end_test_config config);
@@ -239,10 +243,12 @@ void grpc_end2end_tests_pre_init(void) {
   request_with_payload_pre_init();
   resource_quota_server_pre_init();
   retry_pre_init();
+  retry_cancel_during_delay_pre_init();
   retry_cancellation_pre_init();
   retry_disabled_pre_init();
   retry_exceeds_buffer_size_in_initial_batch_pre_init();
   retry_exceeds_buffer_size_in_subsequent_batch_pre_init();
+  retry_lb_drop_pre_init();
   retry_non_retriable_status_pre_init();
   retry_non_retriable_status_before_recv_trailing_metadata_started_pre_init();
   retry_recv_initial_metadata_pre_init();
@@ -327,10 +333,12 @@ void grpc_end2end_tests(int argc, char **argv,
     request_with_payload(config);
     resource_quota_server(config);
     retry(config);
+    retry_cancel_during_delay(config);
     retry_cancellation(config);
     retry_disabled(config);
     retry_exceeds_buffer_size_in_initial_batch(config);
     retry_exceeds_buffer_size_in_subsequent_batch(config);
+    retry_lb_drop(config);
     retry_non_retriable_status(config);
     retry_non_retriable_status_before_recv_trailing_metadata_started(config);
     retry_recv_initial_metadata(config);
@@ -554,6 +562,10 @@ void grpc_end2end_tests(int argc, char **argv,
       retry(config);
       continue;
     }
+    if (0 == strcmp("retry_cancel_during_delay", argv[i])) {
+      retry_cancel_during_delay(config);
+      continue;
+    }
     if (0 == strcmp("retry_cancellation", argv[i])) {
       retry_cancellation(config);
       continue;
@@ -570,6 +582,10 @@ void grpc_end2end_tests(int argc, char **argv,
       retry_exceeds_buffer_size_in_subsequent_batch(config);
       continue;
     }
+    if (0 == strcmp("retry_lb_drop", argv[i])) {
+      retry_lb_drop(config);
+      continue;
+    }
     if (0 == strcmp("retry_non_retriable_status", argv[i])) {
       retry_non_retriable_status(config);
       continue;
index 0641fc6..d3603b3 100644 (file)
@@ -127,6 +127,8 @@ extern void resource_quota_server(grpc_end2end_test_config config);
 extern void resource_quota_server_pre_init(void);
 extern void retry(grpc_end2end_test_config config);
 extern void retry_pre_init(void);
+extern void retry_cancel_during_delay(grpc_end2end_test_config config);
+extern void retry_cancel_during_delay_pre_init(void);
 extern void retry_cancellation(grpc_end2end_test_config config);
 extern void retry_cancellation_pre_init(void);
 extern void retry_disabled(grpc_end2end_test_config config);
@@ -135,6 +137,8 @@ extern void retry_exceeds_buffer_size_in_initial_batch(grpc_end2end_test_config
 extern void retry_exceeds_buffer_size_in_initial_batch_pre_init(void);
 extern void retry_exceeds_buffer_size_in_subsequent_batch(grpc_end2end_test_config config);
 extern void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void);
+extern void retry_lb_drop(grpc_end2end_test_config config);
+extern void retry_lb_drop_pre_init(void);
 extern void retry_non_retriable_status(grpc_end2end_test_config config);
 extern void retry_non_retriable_status_pre_init(void);
 extern void retry_non_retriable_status_before_recv_trailing_metadata_started(grpc_end2end_test_config config);
@@ -242,10 +246,12 @@ void grpc_end2end_tests_pre_init(void) {
   request_with_payload_pre_init();
   resource_quota_server_pre_init();
   retry_pre_init();
+  retry_cancel_during_delay_pre_init();
   retry_cancellation_pre_init();
   retry_disabled_pre_init();
   retry_exceeds_buffer_size_in_initial_batch_pre_init();
   retry_exceeds_buffer_size_in_subsequent_batch_pre_init();
+  retry_lb_drop_pre_init();
   retry_non_retriable_status_pre_init();
   retry_non_retriable_status_before_recv_trailing_metadata_started_pre_init();
   retry_recv_initial_metadata_pre_init();
@@ -331,10 +337,12 @@ void grpc_end2end_tests(int argc, char **argv,
     request_with_payload(config);
     resource_quota_server(config);
     retry(config);
+    retry_cancel_during_delay(config);
     retry_cancellation(config);
     retry_disabled(config);
     retry_exceeds_buffer_size_in_initial_batch(config);
     retry_exceeds_buffer_size_in_subsequent_batch(config);
+    retry_lb_drop(config);
     retry_non_retriable_status(config);
     retry_non_retriable_status_before_recv_trailing_metadata_started(config);
     retry_recv_initial_metadata(config);
@@ -562,6 +570,10 @@ void grpc_end2end_tests(int argc, char **argv,
       retry(config);
       continue;
     }
+    if (0 == strcmp("retry_cancel_during_delay", argv[i])) {
+      retry_cancel_during_delay(config);
+      continue;
+    }
     if (0 == strcmp("retry_cancellation", argv[i])) {
       retry_cancellation(config);
       continue;
@@ -578,6 +590,10 @@ void grpc_end2end_tests(int argc, char **argv,
       retry_exceeds_buffer_size_in_subsequent_batch(config);
       continue;
     }
+    if (0 == strcmp("retry_lb_drop", argv[i])) {
+      retry_lb_drop(config);
+      continue;
+    }
     if (0 == strcmp("retry_non_retriable_status", argv[i])) {
       retry_non_retriable_status(config);
       continue;
index f0ada89..c6fd2ec 100644 (file)
@@ -48,12 +48,9 @@ static grpc_server* create_proxy_server(const char* port,
 static grpc_channel* create_proxy_client(const char* target,
                                          grpc_channel_args* client_args) {
   // Disable retries in proxy client.
-  grpc_arg arg;
-  arg.type = GRPC_ARG_INTEGER;
-  arg.key = const_cast<char*>(GRPC_ARG_ENABLE_RETRIES);
-  arg.value.integer = 0;
+  const char* args_to_remove = GRPC_ARG_ENABLE_RETRIES;
   grpc_channel_args* new_args =
-      grpc_channel_args_copy_and_add(client_args, &arg, 1);
+      grpc_channel_args_copy_and_remove(client_args, &args_to_remove, 1);
   grpc_channel* channel =
       grpc_insecure_channel_create(target, new_args, nullptr);
   grpc_channel_args_destroy(new_args);
index 3a2f18d..67ac6fe 100644 (file)
@@ -52,7 +52,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
   grpc_core::ExecCtx exec_ctx;
   grpc_endpoint_pair* sfd = static_cast<grpc_endpoint_pair*>(f->fixture_data);
   grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq));
-  grpc_error* error = f->server->core_server->SetupTransport(
+  grpc_error_handle error = f->server->core_server->SetupTransport(
       transport, nullptr, f->server->core_server->channel_args(), nullptr);
   if (error == GRPC_ERROR_NONE) {
     grpc_chttp2_transport_start_reading(transport, nullptr, nullptr, nullptr);
@@ -74,7 +74,7 @@ static void client_setup_transport(void* ts, grpc_transport* transport) {
       const_cast<char*>("test-authority"));
   grpc_channel_args* args =
       grpc_channel_args_copy_and_add(cs->client_args, &authority_arg, 1);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   cs->f->client =
       grpc_channel_create("socketpair-target", args, GRPC_CLIENT_DIRECT_CHANNEL,
                           transport, nullptr, &error);
index b3c40d8..5d5fb0b 100644 (file)
@@ -46,7 +46,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
   grpc_core::ExecCtx exec_ctx;
   grpc_endpoint_pair* sfd = static_cast<grpc_endpoint_pair*>(f->fixture_data);
   grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq));
-  grpc_error* error = f->server->core_server->SetupTransport(
+  grpc_error_handle error = f->server->core_server->SetupTransport(
       transport, nullptr, f->server->core_server->channel_args(), nullptr);
   if (error == GRPC_ERROR_NONE) {
     grpc_chttp2_transport_start_reading(transport, nullptr, nullptr, nullptr);
@@ -69,7 +69,7 @@ static void client_setup_transport(void* ts, grpc_transport* transport) {
       const_cast<char*>("test-authority"));
   grpc_channel_args* args =
       grpc_channel_args_copy_and_add(cs->client_args, &authority_arg, 1);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   cs->f->client =
       grpc_channel_create("socketpair-target", args, GRPC_CLIENT_DIRECT_CHANNEL,
                           transport, nullptr, &error);
index f1f4feb..434a614 100644 (file)
@@ -46,7 +46,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
   grpc_core::ExecCtx exec_ctx;
   grpc_endpoint_pair* sfd = static_cast<grpc_endpoint_pair*>(f->fixture_data);
   grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq));
-  grpc_error* error = f->server->core_server->SetupTransport(
+  grpc_error_handle error = f->server->core_server->SetupTransport(
       transport, nullptr, f->server->core_server->channel_args(), nullptr);
   if (error == GRPC_ERROR_NONE) {
     grpc_chttp2_transport_start_reading(transport, nullptr, nullptr, nullptr);
@@ -69,7 +69,7 @@ static void client_setup_transport(void* ts, grpc_transport* transport) {
       const_cast<char*>("test-authority"));
   grpc_channel_args* args =
       grpc_channel_args_copy_and_add(cs->client_args, &authority_arg, 1);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   cs->f->client =
       grpc_channel_create("socketpair-target", args, GRPC_CLIENT_DIRECT_CHANNEL,
                           transport, nullptr, &error);
index a5c3353..83db10b 100644 (file)
@@ -31,6 +31,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/host_port.h"
@@ -44,7 +45,6 @@
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/iomgr/timer.h"
@@ -154,25 +154,25 @@ enum failure_type {
 };
 
 // Forward declarations
-static void on_client_write_done(void* arg, grpc_error* error);
-static void on_server_write_done(void* arg, grpc_error* error);
-static void on_client_read_done(void* arg, grpc_error* error);
-static void on_server_read_done(void* arg, grpc_error* error);
-static void on_server_connect_done(void* arg, grpc_error* error);
-static void on_read_request_done(void* arg, grpc_error* error);
-
-static void on_client_write_done_locked(void* arg, grpc_error* error);
-static void on_server_write_done_locked(void* arg, grpc_error* error);
-static void on_client_read_done_locked(void* arg, grpc_error* error);
-static void on_server_read_done_locked(void* arg, grpc_error* error);
-static void on_server_connect_done_locked(void* arg, grpc_error* error);
-static void on_read_request_done_locked(void* arg, grpc_error* error);
+static void on_client_write_done(void* arg, grpc_error_handle error);
+static void on_server_write_done(void* arg, grpc_error_handle error);
+static void on_client_read_done(void* arg, grpc_error_handle error);
+static void on_server_read_done(void* arg, grpc_error_handle error);
+static void on_server_connect_done(void* arg, grpc_error_handle error);
+static void on_read_request_done(void* arg, grpc_error_handle error);
+
+static void on_client_write_done_locked(void* arg, grpc_error_handle error);
+static void on_server_write_done_locked(void* arg, grpc_error_handle error);
+static void on_client_read_done_locked(void* arg, grpc_error_handle error);
+static void on_server_read_done_locked(void* arg, grpc_error_handle error);
+static void on_server_connect_done_locked(void* arg, grpc_error_handle error);
+static void on_read_request_done_locked(void* arg, grpc_error_handle error);
 
 // Helper function to shut down the proxy connection.
 static void proxy_connection_failed(proxy_connection* conn,
                                     failure_type failure, const char* prefix,
-                                    grpc_error* error) {
-  gpr_log(GPR_INFO, "%s: %s", prefix, grpc_error_string(error));
+                                    grpc_error_handle error) {
+  gpr_log(GPR_INFO, "%s: %s", prefix, grpc_error_std_string(error).c_str());
   // Decide whether we should shut down the client and server.
   bool shutdown_client = false;
   bool shutdown_server = false;
@@ -207,7 +207,7 @@ static void proxy_connection_failed(proxy_connection* conn,
 }
 
 // Callback for writing proxy data to the client.
-static void on_client_write_done_locked(void* arg, grpc_error* error) {
+static void on_client_write_done_locked(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   conn->client_is_writing = false;
   if (error != GRPC_ERROR_NONE) {
@@ -233,7 +233,7 @@ static void on_client_write_done_locked(void* arg, grpc_error* error) {
   }
 }
 
-static void on_client_write_done(void* arg, grpc_error* error) {
+static void on_client_write_done(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   GRPC_CLOSURE_INIT(&conn->on_client_write_done, on_client_write_done_locked,
                     conn, nullptr);
@@ -242,7 +242,7 @@ static void on_client_write_done(void* arg, grpc_error* error) {
 }
 
 // Callback for writing proxy data to the backend server.
-static void on_server_write_done_locked(void* arg, grpc_error* error) {
+static void on_server_write_done_locked(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   conn->server_is_writing = false;
   if (error != GRPC_ERROR_NONE) {
@@ -268,7 +268,7 @@ static void on_server_write_done_locked(void* arg, grpc_error* error) {
   }
 }
 
-static void on_server_write_done(void* arg, grpc_error* error) {
+static void on_server_write_done(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   GRPC_CLOSURE_INIT(&conn->on_server_write_done, on_server_write_done_locked,
                     conn, nullptr);
@@ -278,7 +278,7 @@ static void on_server_write_done(void* arg, grpc_error* error) {
 
 // Callback for reading data from the client, which will be proxied to
 // the backend server.
-static void on_client_read_done_locked(void* arg, grpc_error* error) {
+static void on_client_read_done_locked(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(conn, CLIENT_READ_FAILED, "HTTP proxy client read",
@@ -311,7 +311,7 @@ static void on_client_read_done_locked(void* arg, grpc_error* error) {
                      &conn->on_client_read_done, /*urgent=*/false);
 }
 
-static void on_client_read_done(void* arg, grpc_error* error) {
+static void on_client_read_done(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   GRPC_CLOSURE_INIT(&conn->on_client_read_done, on_client_read_done_locked,
                     conn, nullptr);
@@ -320,7 +320,7 @@ static void on_client_read_done(void* arg, grpc_error* error) {
 
 // Callback for reading data from the backend server, which will be
 // proxied to the client.
-static void on_server_read_done_locked(void* arg, grpc_error* error) {
+static void on_server_read_done_locked(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(conn, SERVER_READ_FAILED, "HTTP proxy server read",
@@ -353,7 +353,7 @@ static void on_server_read_done_locked(void* arg, grpc_error* error) {
                      &conn->on_server_read_done, /*urgent=*/false);
 }
 
-static void on_server_read_done(void* arg, grpc_error* error) {
+static void on_server_read_done(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   GRPC_CLOSURE_INIT(&conn->on_server_read_done, on_server_read_done_locked,
                     conn, nullptr);
@@ -361,7 +361,7 @@ static void on_server_read_done(void* arg, grpc_error* error) {
 }
 
 // Callback to write the HTTP response for the CONNECT request.
-static void on_write_response_done_locked(void* arg, grpc_error* error) {
+static void on_write_response_done_locked(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   conn->client_is_writing = false;
   if (error != GRPC_ERROR_NONE) {
@@ -387,7 +387,7 @@ static void on_write_response_done_locked(void* arg, grpc_error* error) {
                      &conn->on_server_read_done, /*urgent=*/false);
 }
 
-static void on_write_response_done(void* arg, grpc_error* error) {
+static void on_write_response_done(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   GRPC_CLOSURE_INIT(&conn->on_write_response_done,
                     on_write_response_done_locked, conn, nullptr);
@@ -397,7 +397,7 @@ static void on_write_response_done(void* arg, grpc_error* error) {
 
 // Callback to connect to the backend server specified by the HTTP
 // CONNECT request.
-static void on_server_connect_done_locked(void* arg, grpc_error* error) {
+static void on_server_connect_done_locked(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   if (error != GRPC_ERROR_NONE) {
     // TODO(roth): Technically, in this case, we should handle the error
@@ -422,7 +422,7 @@ static void on_server_connect_done_locked(void* arg, grpc_error* error) {
                       &conn->on_write_response_done, nullptr);
 }
 
-static void on_server_connect_done(void* arg, grpc_error* error) {
+static void on_server_connect_done(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   GRPC_CLOSURE_INIT(&conn->on_server_connect_done,
                     on_server_connect_done_locked, conn, nullptr);
@@ -456,10 +456,10 @@ static bool proxy_auth_header_matches(char* proxy_auth_header_val,
 // the client indicating that the request failed.  However, for the purposes
 // of this test code, it's fine to pretend this is a client-side error,
 // which will cause the client connection to be dropped.
-static void on_read_request_done_locked(void* arg, grpc_error* error) {
+static void on_read_request_done_locked(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   gpr_log(GPR_DEBUG, "on_read_request_done: %p %s", conn,
-          grpc_error_string(error));
+          grpc_error_std_string(error).c_str());
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(conn, SETUP_FAILED, "HTTP proxy read request",
                             GRPC_ERROR_REF(error));
@@ -543,7 +543,7 @@ static void on_read_request_done_locked(void* arg, grpc_error* error) {
   grpc_resolved_addresses_destroy(resolved_addresses);
 }
 
-static void on_read_request_done(void* arg, grpc_error* error) {
+static void on_read_request_done(void* arg, grpc_error_handle error) {
   proxy_connection* conn = static_cast<proxy_connection*>(arg);
   GRPC_CLOSURE_INIT(&conn->on_read_request_done, on_read_request_done_locked,
                     conn, nullptr);
@@ -612,7 +612,7 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(
   gpr_log(GPR_INFO, "Proxy address: %s", proxy->proxy_name.c_str());
   // Create TCP server.
   proxy->channel_args = grpc_channel_args_copy(args);
-  grpc_error* error =
+  grpc_error_handle error =
       grpc_tcp_server_create(nullptr, proxy->channel_args, &proxy->server);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   // Bind to port.
@@ -638,7 +638,7 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(
   return proxy;
 }
 
-static void destroy_pollset(void* arg, grpc_error* /*error*/) {
+static void destroy_pollset(void* arg, grpc_error_handle /*error*/) {
   grpc_pollset* pollset = static_cast<grpc_pollset*>(arg);
   grpc_pollset_destroy(pollset);
   gpr_free(pollset);
index f812e65..58aae8f 100755 (executable)
@@ -281,6 +281,10 @@ END2END_TESTS = {
         needs_client_channel = True,
         proxyable = False,
     ),
+    "retry_cancel_during_delay": _test_options(
+        needs_client_channel = True,
+        proxyable = False,
+    ),
     "retry_disabled": _test_options(needs_client_channel = True, proxyable = False),
     "retry_exceeds_buffer_size_in_initial_batch": _test_options(
         needs_client_channel = True,
@@ -296,6 +300,10 @@ END2END_TESTS = {
         # See b/151617965
         short_name = "retry_exceeds_buffer_size_in_subseq",
     ),
+    "retry_lb_drop": _test_options(
+        needs_client_channel = True,
+        proxyable = False,
+    ),
     "retry_non_retriable_status": _test_options(
         needs_client_channel = True,
         proxyable = False,
@@ -422,12 +430,14 @@ def grpc_end2end_tests():
             "end2end_tests.h",
         ],
         language = "C++",
+        testonly = 1,
         deps = [
             ":cq_verifier",
             ":ssl_test_data",
             ":http_proxy",
             ":proxy",
             ":local_util",
+            "//test/core/util:test_lb_policies",
         ],
     )
 
@@ -436,6 +446,7 @@ def grpc_end2end_tests():
             name = "%s_test" % f,
             srcs = ["fixtures/%s.cc" % f],
             language = "C++",
+            testonly = 1,
             data = [
                 "//src/core/tsi/test_creds:ca.pem",
                 "//src/core/tsi/test_creds:server1.key",
@@ -497,12 +508,14 @@ def grpc_end2end_nosec_tests():
             "end2end_tests.h",
         ],
         language = "C++",
+        testonly = 1,
         deps = [
             ":cq_verifier",
             ":ssl_test_data",
             ":http_proxy",
             ":proxy",
             ":local_util",
+            "//test/core/util:test_lb_policies",
         ],
     )
 
@@ -513,6 +526,7 @@ def grpc_end2end_nosec_tests():
             name = "%s_nosec_test" % f,
             srcs = ["fixtures/%s.cc" % f],
             language = "C++",
+            testonly = 1,
             data = [
                 "//src/core/tsi/test_creds:ca.pem",
                 "//src/core/tsi/test_creds:server1.key",
index d0ca219..679000d 100644 (file)
@@ -75,7 +75,7 @@ static void my_resolve_address(const char* addr, const char* default_port,
     return;
   }
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   gpr_mu_lock(&g_mu);
   if (g_resolve_port < 0) {
     gpr_mu_unlock(&g_mu);
@@ -97,7 +97,7 @@ static void my_resolve_address(const char* addr, const char* default_port,
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, error);
 }
 
-static grpc_error* my_blocking_resolve_address(
+static grpc_error_handle my_blocking_resolve_address(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   return default_resolver->blocking_resolve_address(name, default_port,
@@ -121,7 +121,7 @@ static grpc_ares_request* my_dns_lookup_ares_locked(
         std::move(work_serializer));
   }
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   gpr_mu_lock(&g_mu);
   if (g_resolve_port < 0) {
     gpr_mu_unlock(&g_mu);
index fb1af99..f7471c1 100644 (file)
@@ -195,7 +195,7 @@ typedef struct {
   uint8_t unused;
 } channel_data;
 
-static void recv_im_ready(void* arg, grpc_error* error) {
+static void recv_im_ready(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_core::Closure::Run(
@@ -218,8 +218,8 @@ static void start_transport_stream_op_batch(
   grpc_call_next_op(elem, op);
 }
 
-static grpc_error* init_call_elem(grpc_call_element* /*elem*/,
-                                  const grpc_call_element_args* /*args*/) {
+static grpc_error_handle init_call_elem(
+    grpc_call_element* /*elem*/, const grpc_call_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
@@ -227,8 +227,8 @@ static void destroy_call_elem(grpc_call_element* /*elem*/,
                               const grpc_call_final_info* /*final_info*/,
                               grpc_closure* /*ignored*/) {}
 
-static grpc_error* init_channel_elem(grpc_channel_element* /*elem*/,
-                                     grpc_channel_element_args* /*args*/) {
+static grpc_error_handle init_channel_elem(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
index 5b02e06..0b97dc4 100644 (file)
@@ -225,8 +225,8 @@ struct call_data {
   grpc_call_context_element* context;
 };
 
-static grpc_error* init_call_elem(grpc_call_element* elem,
-                                  const grpc_call_element_args* args) {
+static grpc_error_handle init_call_elem(grpc_call_element* elem,
+                                        const grpc_call_element_args* args) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->context = args->context;
   gpr_log(GPR_INFO, "init_call_elem(): context=%p", args->context);
@@ -251,8 +251,8 @@ static void destroy_call_elem(grpc_call_element* /*elem*/,
                               const grpc_call_final_info* /*final_info*/,
                               grpc_closure* /*ignored*/) {}
 
-static grpc_error* init_channel_elem(grpc_channel_element* /*elem*/,
-                                     grpc_channel_element_args* /*args*/) {
+static grpc_error_handle init_channel_elem(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
index 00e2fa6..43da690 100644 (file)
@@ -416,8 +416,8 @@ static void test_client_subchannel_filter(grpc_end2end_test_config config) {
  * Test filter - always fails to initialize a call
  */
 
-static grpc_error* init_call_elem(grpc_call_element* /*elem*/,
-                                  const grpc_call_element_args* /*args*/) {
+static grpc_error_handle init_call_elem(
+    grpc_call_element* /*elem*/, const grpc_call_element_args* /*args*/) {
   return grpc_error_set_int(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("access denied"),
       GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_PERMISSION_DENIED);
@@ -427,8 +427,8 @@ static void destroy_call_elem(grpc_call_element* /*elem*/,
                               const grpc_call_final_info* /*final_info*/,
                               grpc_closure* /*ignored*/) {}
 
-static grpc_error* init_channel_elem(grpc_channel_element* /*elem*/,
-                                     grpc_channel_element_args* /*args*/) {
+static grpc_error_handle init_channel_elem(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   if (g_channel_filter_init_failure) {
     return grpc_error_set_int(
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test channel filter init error"),
index 1a8091e..6b94d94 100644 (file)
@@ -247,8 +247,8 @@ static void test_request(grpc_end2end_test_config config) {
  * Test latency filter
  */
 
-static grpc_error* init_call_elem(grpc_call_element* /*elem*/,
-                                  const grpc_call_element_args* /*args*/) {
+static grpc_error_handle init_call_elem(
+    grpc_call_element* /*elem*/, const grpc_call_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
@@ -268,8 +268,8 @@ static void server_destroy_call_elem(grpc_call_element* /*elem*/,
   gpr_mu_unlock(&g_mu);
 }
 
-static grpc_error* init_channel_elem(grpc_channel_element* /*elem*/,
-                                     grpc_channel_element_args* /*args*/) {
+static grpc_error_handle init_channel_elem(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
index 061166f..6359980 100644 (file)
@@ -275,8 +275,8 @@ static void server_start_transport_stream_op_batch(
   grpc_call_next_op(elem, op);
 }
 
-static grpc_error* init_call_elem(grpc_call_element* elem,
-                                  const grpc_call_element_args* args) {
+static grpc_error_handle init_call_elem(grpc_call_element* elem,
+                                        const grpc_call_element_args* args) {
   final_status_data* data = static_cast<final_status_data*>(elem->call_data);
   data->call = args->call_stack;
   return GRPC_ERROR_NONE;
@@ -312,8 +312,8 @@ static void server_destroy_call_elem(grpc_call_element* elem,
   gpr_mu_unlock(&g_mu);
 }
 
-static grpc_error* init_channel_elem(grpc_channel_element* /*elem*/,
-                                     grpc_channel_element_args* /*args*/) {
+static grpc_error_handle init_channel_elem(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
index 5e9f8aa..1c82b51 100644 (file)
@@ -120,25 +120,28 @@ static void test_retry(grpc_end2end_test_config config) {
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 3,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 3,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry", &client_args, nullptr);
 
diff --git a/test/core/end2end/tests/retry_cancel_during_delay.cc b/test/core/end2end/tests/retry_cancel_during_delay.cc
new file mode 100644 (file)
index 0000000..161b7aa
--- /dev/null
@@ -0,0 +1,288 @@
+//
+// Copyright 2017 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+#include "absl/strings/str_cat.h"
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests retry cancellation during backoff.
+static void test_retry_cancel_during_delay(grpc_end2end_test_config config,
+                                           cancellation_mode mode) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 3,\n"
+              "      \"initialBackoff\": \"10s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    },\n"
+              "    \"timeout\": \"5s\"\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
+  std::string name = absl::StrCat("retry_cancel_during_delay/", mode.name);
+  grpc_end2end_test_fixture f =
+      begin_test(config, name.c_str(), &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec expect_finish_before = n_seconds_from_now(10);
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+                               grpc_slice_from_static_string("/service/method"),
+                               nullptr, deadline, nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  // Client starts a batch with all 6 ops.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  // Server gets a call and fails with retryable status.
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  grpc_call_unref(s);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_details_init(&call_details);
+
+  // Server should never get a second call, because the initial retry
+  // delay is longer than the call's deadline.
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(201));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  cq_verify_empty(cqv);
+
+  // Initiate cancellation.
+  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, nullptr));
+
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  // Make sure we didn't wait the full deadline before failing.
+  gpr_log(
+      GPR_INFO, "Expect completion before: %s",
+      absl::FormatTime(grpc_core::ToAbslTime(expect_finish_before)).c_str());
+  GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), expect_finish_before) <
+             0);
+
+  gpr_log(GPR_INFO, "status=%d expected=%d", status, mode.expect_status);
+  GPR_ASSERT(status == mode.expect_status);
+  GPR_ASSERT(was_cancelled == 0);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_cancel_during_delay(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(cancellation_modes); ++i) {
+    test_retry_cancel_during_delay(config, cancellation_modes[i]);
+  }
+}
+
+void retry_cancel_during_delay_pre_init(void) {}
index 261e962..c4f1b94 100644 (file)
@@ -121,27 +121,30 @@ static void test_retry_cancellation(grpc_end2end_test_config config,
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 3,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    },\n"
-      "    \"timeout\": \"5s\"\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
-  std::string name = absl::StrCat("retry_cancellation/%s", mode.name);
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 3,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    },\n"
+              "    \"timeout\": \"5s\"\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
+  std::string name = absl::StrCat("retry_cancellation/", mode.name);
   grpc_end2end_test_fixture f =
       begin_test(config, name.c_str(), &client_args, nullptr);
 
index 3cdc045..dc953db 100644 (file)
@@ -93,11 +93,13 @@ static void end_test(grpc_end2end_test_fixture* f) {
   grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
-// Tests that we don't retry when retries are disabled via the
+// Tests that we don't retry when retries are not enabled via the
 // GRPC_ARG_ENABLE_RETRIES channel arg, even when there is retry
 // configuration in the service config.
 // - 1 retry allowed for ABORTED status
 // - first attempt returns ABORTED but does not retry
+// TODO(roth): Update this when we change the default of
+// GRPC_ARG_ENABLE_RETRIES to true.
 static void test_retry_disabled(grpc_end2end_test_config config) {
   grpc_call* c;
   grpc_call* s;
@@ -121,28 +123,24 @@ static void test_retry_disabled(grpc_end2end_test_config config) {
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg args[2];
-  args[0].type = GRPC_ARG_STRING;
-  args[0].key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  args[0].value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 2,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  args[1].type = GRPC_ARG_INTEGER;
-  args[1].key = const_cast<char*>(GRPC_ARG_ENABLE_RETRIES);
-  args[1].value.integer = 0;
-  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
+  grpc_arg arg = grpc_channel_arg_string_create(
+      const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+      const_cast<char*>(
+          "{\n"
+          "  \"methodConfig\": [ {\n"
+          "    \"name\": [\n"
+          "      { \"service\": \"service\", \"method\": \"method\" }\n"
+          "    ],\n"
+          "    \"retryPolicy\": {\n"
+          "      \"maxAttempts\": 2,\n"
+          "      \"initialBackoff\": \"1s\",\n"
+          "      \"maxBackoff\": \"120s\",\n"
+          "      \"backoffMultiplier\": 1.6,\n"
+          "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+          "    }\n"
+          "  } ]\n"
+          "}"));
+  grpc_channel_args client_args = {1, &arg};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_disabled", &client_args, nullptr);
 
index 4d5f691..3a7f42b 100644 (file)
@@ -123,27 +123,29 @@ static void test_retry_exceeds_buffer_size_in_initial_batch(
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg args[2];
-  args[0].type = GRPC_ARG_STRING;
-  args[0].key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  args[0].value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 2,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  args[1].type = GRPC_ARG_INTEGER;
-  args[1].key = const_cast<char*>(GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE);
-  args[1].value.integer = 2;
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 2,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE), 2),
+  };
   grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_exceeds_buffer_size_in_initial_batch",
index 1c99f4c..7c84297 100644 (file)
@@ -128,27 +128,29 @@ static void test_retry_exceeds_buffer_size_in_subsequent_batch(
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg args[2];
-  args[0].type = GRPC_ARG_STRING;
-  args[0].key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  args[0].value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 2,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  args[1].type = GRPC_ARG_INTEGER;
-  args[1].key = const_cast<char*>(GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE);
-  args[1].value.integer = 102400;
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 2,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE), 102400),
+  };
   grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_exceeds_buffer_size_in_subsequent_batch",
diff --git a/test/core/end2end/tests/retry_lb_drop.cc b/test/core/end2end/tests/retry_lb_drop.cc
new file mode 100644 (file)
index 0000000..d81b04a
--- /dev/null
@@ -0,0 +1,279 @@
+//
+// Copyright 2017 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+#include "test/core/util/test_lb_policies.h"
+
+namespace grpc_core {
+namespace {
+
+const char* kDropPolicyName = "drop_lb";
+
+class DropPolicy : public LoadBalancingPolicy {
+ public:
+  explicit DropPolicy(Args args) : LoadBalancingPolicy(std::move(args)) {}
+
+  const char* name() const override { return kDropPolicyName; }
+
+  void UpdateLocked(UpdateArgs) override {
+    channel_control_helper()->UpdateState(GRPC_CHANNEL_READY, absl::Status(),
+                                          absl::make_unique<DropPicker>());
+  }
+
+  void ResetBackoffLocked() override {}
+  void ShutdownLocked() override {}
+
+ private:
+  class DropPicker : public SubchannelPicker {
+   public:
+    PickResult Pick(PickArgs /*args*/) override {
+      PickResult result;
+      result.type = PickResult::PICK_COMPLETE;
+      return result;
+    }
+  };
+};
+
+class DropLbConfig : public LoadBalancingPolicy::Config {
+ public:
+  const char* name() const override { return kDropPolicyName; }
+};
+
+class DropPolicyFactory : public LoadBalancingPolicyFactory {
+ public:
+  OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
+      LoadBalancingPolicy::Args args) const override {
+    return MakeOrphanable<DropPolicy>(std::move(args));
+  }
+
+  const char* name() const override { return kDropPolicyName; }
+
+  RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
+      const Json& /*json*/, grpc_error_handle* /*error*/) const override {
+    return MakeRefCounted<DropLbConfig>();
+  }
+};
+
+std::vector<PickArgsSeen>* g_pick_args_vector = nullptr;
+
+void RegisterDropPolicy() {
+  LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory(
+      absl::make_unique<DropPolicyFactory>());
+  RegisterTestPickArgsLoadBalancingPolicy(
+      [](const PickArgsSeen& pick_args) {
+        GPR_ASSERT(g_pick_args_vector != nullptr);
+        g_pick_args_vector->push_back(pick_args);
+      },
+      kDropPolicyName);
+}
+
+}  // namespace
+}  // namespace grpc_core
+
+static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we don't retry when retries are disabled via the
+// GRPC_ARG_ENABLE_RETRIES channel arg, even when there is retry
+// configuration in the service config.
+// - 1 retry allowed for ABORTED status
+// - first attempt returns ABORTED but does not retry
+static void test_retry_lb_drop(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+
+  std::vector<grpc_core::PickArgsSeen> pick_args_seen;
+  grpc_core::g_pick_args_vector = &pick_args_seen;
+
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"loadBalancingConfig\": [ {\n"
+              "    \"test_pick_args_lb\": {}\n"
+              "  } ],\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 2,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"UNAVAILABLE\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_lb_drop", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+                               grpc_slice_from_static_string("/service/method"),
+                               nullptr, deadline, nullptr);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details,
+                                     "Call dropped by load balancing policy"));
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+
+  cq_verifier_destroy(cqv);
+
+  gpr_log(GPR_INFO, "NUMBER OF LB PICKS: %" PRIuPTR, pick_args_seen.size());
+  GPR_ASSERT(pick_args_seen.size() == 1);
+
+  grpc_core::g_pick_args_vector = nullptr;
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_lb_drop(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_lb_drop(config);
+}
+
+void retry_lb_drop_pre_init(void) { grpc_core::RegisterDropPolicy(); }
index 5124713..3ad91ea 100644 (file)
@@ -119,25 +119,28 @@ static void test_retry_non_retriable_status(grpc_end2end_test_config config) {
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 2,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 2,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_non_retriable_status", &client_args, nullptr);
 
index 5bdada8..cc854b8 100644 (file)
@@ -122,27 +122,32 @@ test_retry_non_retriable_status_before_recv_trailing_metadata_started(
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 2,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
-  grpc_end2end_test_fixture f =
-      begin_test(config, "retry_non_retriable_status", &client_args, nullptr);
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 2,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
+  grpc_end2end_test_fixture f = begin_test(
+      config,
+      "retry_non_retriable_status_before_recv_trailing_metadata_started",
+      &client_args, nullptr);
 
   cq_verifier* cqv = cq_verifier_create(f.cq);
 
index eae84ee..ac13110 100644 (file)
@@ -120,25 +120,28 @@ static void test_retry_recv_initial_metadata(grpc_end2end_test_config config) {
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 2,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 2,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_recv_initial_metadata", &client_args, nullptr);
 
index f720591..24a33e2 100644 (file)
@@ -120,25 +120,28 @@ static void test_retry_recv_message(grpc_end2end_test_config config) {
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 2,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 2,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_recv_message", &client_args, nullptr);
 
index 122eb49..4990c6f 100644 (file)
@@ -125,25 +125,28 @@ static void test_retry_server_pushback_delay(grpc_end2end_test_config config) {
   pushback_md.key = GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS;
   pushback_md.value = grpc_slice_from_static_string("2000");
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 3,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 3,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_server_pushback_delay", &client_args, nullptr);
 
index 44a37a4..75744d3 100644 (file)
@@ -126,25 +126,28 @@ static void test_retry_server_pushback_disabled(
   pushback_md.key = GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS;
   pushback_md.value = grpc_slice_from_static_string("-1");
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 3,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 3,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f = begin_test(
       config, "retry_server_pushback_disabled", &client_args, nullptr);
 
index 2521910..3d2e9dc 100644 (file)
@@ -138,6 +138,8 @@ static void test_retry_streaming(grpc_end2end_test_config config) {
 
   grpc_arg args[] = {
       grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_integer_create(
           const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
           1024 * 8),
       grpc_channel_arg_integer_create(
index de7d7c3..a3ea534 100644 (file)
@@ -126,25 +126,28 @@ static void test_retry_streaming_after_commit(grpc_end2end_test_config config) {
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 3,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 3,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_streaming_after_commit", &client_args, nullptr);
 
index 866c948..aee927c 100644 (file)
@@ -127,25 +127,28 @@ static void test_retry_streaming_succeeds_before_replay_finished(
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 3,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 3,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_streaming", &client_args, nullptr);
 
index 9fdca88..91c60fa 100644 (file)
@@ -119,32 +119,35 @@ static void test_retry_throttled(grpc_end2end_test_config config) {
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 2,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ],\n"
-      // A single failure will cause us to be throttled.
-      // (This is not a very realistic config, but it works for the
-      // purposes of this test.)
-      "  \"retryThrottling\": {\n"
-      "    \"maxTokens\": 2,\n"
-      "    \"tokenRatio\": 1.0\n"
-      "  }\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 2,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ],\n"
+              // A single failure will cause us to be throttled.
+              // (This is not a very realistic config, but it works for the
+              // purposes of this test.)
+              "  \"retryThrottling\": {\n"
+              "    \"maxTokens\": 2,\n"
+              "    \"tokenRatio\": 1.0\n"
+              "  }\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_throttled", &client_args, nullptr);
 
index 2a8301f..bdb1a67 100644 (file)
@@ -120,25 +120,28 @@ static void test_retry_too_many_attempts(grpc_end2end_test_config config) {
   int was_cancelled = 2;
   char* peer;
 
-  grpc_arg arg;
-  arg.type = GRPC_ARG_STRING;
-  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
-  arg.value.string = const_cast<char*>(
-      "{\n"
-      "  \"methodConfig\": [ {\n"
-      "    \"name\": [\n"
-      "      { \"service\": \"service\", \"method\": \"method\" }\n"
-      "    ],\n"
-      "    \"retryPolicy\": {\n"
-      "      \"maxAttempts\": 2,\n"
-      "      \"initialBackoff\": \"1s\",\n"
-      "      \"maxBackoff\": \"120s\",\n"
-      "      \"backoffMultiplier\": 1.6,\n"
-      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
-      "    }\n"
-      "  } ]\n"
-      "}");
-  grpc_channel_args client_args = {1, &arg};
+  grpc_arg args[] = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_ENABLE_RETRIES), 1),
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+          const_cast<char*>(
+              "{\n"
+              "  \"methodConfig\": [ {\n"
+              "    \"name\": [\n"
+              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "    ],\n"
+              "    \"retryPolicy\": {\n"
+              "      \"maxAttempts\": 2,\n"
+              "      \"initialBackoff\": \"1s\",\n"
+              "      \"maxBackoff\": \"120s\",\n"
+              "      \"backoffMultiplier\": 1.6,\n"
+              "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+              "    }\n"
+              "  } ]\n"
+              "}")),
+  };
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
   grpc_end2end_test_fixture f =
       begin_test(config, "retry_too_many_attempts", &client_args, nullptr);
 
index c0c3b53..caa6f5d 100644 (file)
@@ -194,6 +194,20 @@ grpc_cc_test(
 )
 
 grpc_cc_test(
+    name = "status_helper_test",
+    srcs = ["status_helper_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    language = "C++",
+    uses_polling = False,
+    deps = [
+        "//:gpr",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
     name = "time_util_test",
     srcs = ["time_util_test.cc"],
     external_deps = [
index fefe90b..6e95aa2 100644 (file)
@@ -51,7 +51,7 @@ TEST(RefCounted, ExtraRef) {
   foo->Unref();
 }
 
-class Value : public RefCounted<Value, PolymorphicRefCount, false> {
+class Value : public RefCounted<Value, PolymorphicRefCount, kUnrefNoDelete> {
  public:
   Value(int value, std::set<std::unique_ptr<Value>>* registry) : value_(value) {
     registry->emplace(this);
@@ -104,6 +104,26 @@ TEST(RefCounted, NoDeleteUponUnref) {
   EXPECT_THAT(registry, ::testing::UnorderedElementsAre());
 }
 
+class ValueInExternalAllocation
+    : public RefCounted<ValueInExternalAllocation, PolymorphicRefCount,
+                        kUnrefCallDtor> {
+ public:
+  explicit ValueInExternalAllocation(int value) : value_(value) {}
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+};
+
+TEST(RefCounted, CallDtorUponUnref) {
+  std::aligned_storage<sizeof(ValueInExternalAllocation),
+                       alignof(ValueInExternalAllocation)>::type storage;
+  RefCountedPtr<ValueInExternalAllocation> value(
+      new (&storage) ValueInExternalAllocation(5));
+  EXPECT_EQ(value->value(), 5);
+}
+
 class FooNonPolymorphic
     : public RefCounted<FooNonPolymorphic, NonPolymorphicRefCount> {
  public:
diff --git a/test/core/gprpp/status_helper_test.cc b/test/core/gprpp/status_helper_test.cc
new file mode 100644 (file)
index 0000000..0f59b2a
--- /dev/null
@@ -0,0 +1,170 @@
+//
+// Copyright 2021 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 "src/core/lib/gprpp/status_helper.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "absl/status/status.h"
+#include "absl/strings/str_cat.h"
+#include "absl/time/clock.h"
+#include "google/rpc/status.upb.h"
+#include "upb/upb.hpp"
+
+namespace grpc_core {
+namespace {
+
+TEST(StatusUtilTest, CreateStatus) {
+  absl::Status s =
+      StatusCreate(absl::StatusCode::kUnknown, "Test", DEBUG_LOCATION,
+                   {absl::OkStatus(), absl::CancelledError()});
+  EXPECT_EQ(absl::StatusCode::kUnknown, s.code());
+  EXPECT_EQ("Test", s.message());
+#ifndef NDEBUG
+  EXPECT_EQ(true, StatusGetStr(s, StatusStrProperty::kFile).has_value());
+  EXPECT_EQ(true, StatusGetInt(s, StatusIntProperty::kFileLine).has_value());
+#endif
+  EXPECT_EQ(true, StatusGetTime(s, StatusTimeProperty::kCreated).has_value());
+  EXPECT_THAT(StatusGetChildren(s),
+              ::testing::ElementsAre(absl::CancelledError()));
+}
+
+TEST(StatusUtilTest, SetAndGetInt) {
+  absl::Status s = absl::CancelledError();
+  StatusSetInt(&s, StatusIntProperty::kErrorNo, 2021);
+  EXPECT_EQ(2021, StatusGetInt(s, StatusIntProperty::kErrorNo));
+}
+
+TEST(StatusUtilTest, GetIntNotExistent) {
+  absl::Status s = absl::CancelledError();
+  EXPECT_EQ(absl::optional<intptr_t>(),
+            StatusGetInt(s, StatusIntProperty::kErrorNo));
+}
+
+TEST(StatusUtilTest, SetAndGetStr) {
+  absl::Status s = absl::CancelledError();
+  StatusSetStr(&s, StatusStrProperty::kOsError, "value");
+  EXPECT_EQ("value", StatusGetStr(s, StatusStrProperty::kOsError));
+}
+
+TEST(StatusUtilTest, GetStrNotExistent) {
+  absl::Status s = absl::CancelledError();
+  EXPECT_EQ(absl::optional<std::string>(),
+            StatusGetStr(s, StatusStrProperty::kOsError));
+}
+
+TEST(StatusUtilTest, SetAndGetTime) {
+  absl::Status s = absl::CancelledError();
+  absl::Time t = absl::Now();
+  StatusSetTime(&s, StatusTimeProperty::kCreated, t);
+  EXPECT_EQ(t, StatusGetTime(s, StatusTimeProperty::kCreated));
+}
+
+TEST(StatusUtilTest, GetTimeNotExistent) {
+  absl::Status s = absl::CancelledError();
+  EXPECT_EQ(absl::optional<absl::Time>(),
+            StatusGetTime(s, StatusTimeProperty::kCreated));
+}
+
+TEST(StatusUtilTest, AddAndGetChildren) {
+  absl::Status s = absl::CancelledError();
+  absl::Status child1 = absl::AbortedError("Message1");
+  absl::Status child2 = absl::DeadlineExceededError("Message2");
+  StatusAddChild(&s, child1);
+  StatusAddChild(&s, child2);
+  EXPECT_THAT(StatusGetChildren(s), ::testing::ElementsAre(child1, child2));
+}
+
+TEST(StatusUtilTest, ToAndFromProto) {
+  absl::Status s = absl::CancelledError("Message");
+  StatusSetInt(&s, StatusIntProperty::kErrorNo, 2021);
+  StatusSetStr(&s, StatusStrProperty::kOsError, "value");
+  upb::Arena arena;
+  google_rpc_Status* msg = internal::StatusToProto(s, arena.ptr());
+  absl::Status s2 = internal::StatusFromProto(msg);
+  EXPECT_EQ(s, s2);
+}
+
+TEST(StatusUtilTest, OkToString) {
+  absl::Status s = absl::OkStatus();
+  std::string t = StatusToString(s);
+  EXPECT_EQ("OK", t);
+}
+
+TEST(StatusUtilTest, CancelledErrorToString) {
+  absl::Status s = absl::CancelledError();
+  std::string t = StatusToString(s);
+  EXPECT_EQ("CANCELLED", t);
+}
+
+TEST(StatusUtilTest, ErrorWithIntPropertyToString) {
+  absl::Status s = absl::CancelledError("Message");
+  StatusSetInt(&s, StatusIntProperty::kErrorNo, 2021);
+  std::string t = StatusToString(s);
+  EXPECT_EQ("CANCELLED:Message {errno:2021}", t);
+}
+
+TEST(StatusUtilTest, ErrorWithStrPropertyToString) {
+  absl::Status s = absl::CancelledError("Message");
+  StatusSetStr(&s, StatusStrProperty::kDescription, "Hey");
+  std::string t = StatusToString(s);
+  EXPECT_EQ("CANCELLED:Message {description:\"Hey\"}", t);
+}
+
+TEST(StatusUtilTest, ErrorWithTimePropertyToString) {
+  absl::Status s = absl::CancelledError("Message");
+  absl::Time t = absl::FromCivil(absl::CivilSecond(2021, 4, 29, 8, 56, 30),
+                                 absl::LocalTimeZone());
+  StatusSetTime(&s, StatusTimeProperty::kCreated, t);
+  EXPECT_EQ(StatusToString(s),
+            absl::StrCat("CANCELLED:Message {created_time:\"",
+                         absl::FormatTime(t), "\"}"));
+}
+
+TEST(StatusUtilTest, ComplexErrorWithChildrenToString) {
+  absl::Status s = absl::CancelledError("Message");
+  StatusSetInt(&s, StatusIntProperty::kErrorNo, 2021);
+  absl::Status s1 = absl::AbortedError("Message1");
+  StatusAddChild(&s, s1);
+  absl::Status s2 = absl::AlreadyExistsError("Message2");
+  StatusSetStr(&s2, StatusStrProperty::kOsError, "value");
+  StatusAddChild(&s, s2);
+  std::string t = StatusToString(s);
+  EXPECT_EQ(
+      "CANCELLED:Message {errno:2021, children:["
+      "ABORTED:Message1, ALREADY_EXISTS:Message2 {os_error:\"value\"}]}",
+      t);
+}
+
+TEST(StatusUtilTest, AllocPtr) {
+  absl::Status statuses[] = {absl::OkStatus(), absl::CancelledError(),
+                             absl::AbortedError("Message")};
+  for (const auto& s : statuses) {
+    uintptr_t p = internal::StatusAllocPtr(s);
+    EXPECT_EQ(s, internal::StatusGetFromPtr(p));
+    internal::StatusFreePtr(p);
+  }
+}
+
+}  // namespace
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int ret = RUN_ALL_TESTS();
+  return ret;
+}
index 708b316..ec1cdc4 100644 (file)
@@ -55,7 +55,7 @@ class ReadAheadHandshaker : public Handshaker {
  public:
   ~ReadAheadHandshaker() override {}
   const char* name() const override { return "read_ahead"; }
-  void Shutdown(grpc_error* /*why*/) override {}
+  void Shutdown(grpc_error_handle /*why*/) override {}
   void DoHandshake(grpc_tcp_server_acceptor* /*acceptor*/,
                    grpc_closure* on_handshake_done,
                    HandshakerArgs* args) override {
index a227050..f9fd311 100644 (file)
@@ -41,14 +41,14 @@ static grpc_millis n_seconds_time(int seconds) {
       grpc_timeout_seconds_to_deadline(seconds));
 }
 
-static void on_finish(void* arg, grpc_error* error) {
+static void on_finish(void* arg, grpc_error_handle error) {
   const char* expect =
       "<html><head><title>Hello world!</title></head>"
       "<body><p>This is a test</p></body></html>";
   grpc_http_response* response = static_cast<grpc_http_response*>(arg);
   GPR_ASSERT(response);
   gpr_log(GPR_INFO, "response status=%d error=%s", response->status,
-          grpc_error_string(error));
+          grpc_error_std_string(error).c_str());
   GPR_ASSERT(response->status == 200);
   GPR_ASSERT(response->body_length == strlen(expect));
   GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
@@ -138,7 +138,7 @@ static void test_post(int port) {
   grpc_http_response_destroy(&response);
 }
 
-static void destroy_pops(void* p, grpc_error* /*error*/) {
+static void destroy_pops(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(
       grpc_polling_entity_pollset(static_cast<grpc_polling_entity*>(p)));
 }
index 542fe55..a94a67b 100644 (file)
@@ -44,14 +44,14 @@ static grpc_millis n_seconds_time(int seconds) {
       grpc_timeout_seconds_to_deadline(seconds));
 }
 
-static void on_finish(void* arg, grpc_error* error) {
+static void on_finish(void* arg, grpc_error_handle error) {
   const char* expect =
       "<html><head><title>Hello world!</title></head>"
       "<body><p>This is a test</p></body></html>";
   grpc_http_response* response = static_cast<grpc_http_response*>(arg);
   GPR_ASSERT(response);
   gpr_log(GPR_INFO, "response status=%d error=%s", response->status,
-          grpc_error_string(error));
+          grpc_error_std_string(error).c_str());
   GPR_ASSERT(response->status == 200);
   GPR_ASSERT(response->body_length == strlen(expect));
   GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
@@ -143,7 +143,7 @@ static void test_post(int port) {
   grpc_http_response_destroy(&response);
 }
 
-static void destroy_pops(void* p, grpc_error* /*error*/) {
+static void destroy_pops(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(
       grpc_polling_entity_pollset(static_cast<grpc_polling_entity*>(p)));
 }
index 04afdd2..c08df1d 100644 (file)
@@ -156,7 +156,7 @@ static void test_fails(grpc_slice_split_mode split_mode,
   size_t num_slices;
   size_t i;
   grpc_slice* slices;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_http_response response;
   response = {};
 
@@ -189,7 +189,7 @@ static void test_request_fails(grpc_slice_split_mode split_mode,
   size_t num_slices;
   size_t i;
   grpc_slice* slices;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_http_request request;
   memset(&request, 0, sizeof(request));
 
index 452a0c0..0382757 100644 (file)
@@ -234,20 +234,6 @@ grpc_cc_test(
 )
 
 grpc_cc_test(
-    name = "sockaddr_utils_test",
-    srcs = ["sockaddr_utils_test.cc"],
-    external_deps = [
-        "gtest",
-    ],
-    language = "C++",
-    deps = [
-        "//:gpr",
-        "//:grpc",
-        "//test/core/util:grpc_test_util",
-    ],
-)
-
-grpc_cc_test(
     name = "socket_utils_test",
     srcs = ["socket_utils_test.cc"],
     language = "C++",
@@ -389,27 +375,3 @@ grpc_cc_test(
         "//test/core/util:grpc_test_util",
     ],
 )
-
-grpc_cc_test(
-    name = "parse_address_test",
-    srcs = ["parse_address_test.cc"],
-    language = "C++",
-    deps = [
-        "//:gpr",
-        "//:grpc",
-        "//test/core/util:grpc_test_util",
-    ],
-)
-
-grpc_cc_test(
-    name = "parse_address_with_named_scope_id_test",
-    srcs = ["parse_address_with_named_scope_id_test.cc"],
-    language = "C++",
-    tags = ["no_windows"],
-    uses_polling = False,
-    deps = [
-        "//:gpr",
-        "//:grpc",
-        "//test/core/util:grpc_test_util",
-    ],
-)
index 2c179c4..6df4156 100644 (file)
@@ -28,7 +28,7 @@
 
 static void TestShutdownFlushesListVerifier(void* arg,
                                             grpc_core::Timestamps* /*ts*/,
-                                            grpc_error* error) {
+                                            grpc_error_handle error) {
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(arg != nullptr);
   gpr_atm* done = reinterpret_cast<gpr_atm*>(arg);
@@ -60,7 +60,7 @@ static void TestShutdownFlushesList() {
 
 static void TestVerifierCalledOnAckVerifier(void* arg,
                                             grpc_core::Timestamps* ts,
-                                            grpc_error* error) {
+                                            grpc_error_handle error) {
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(arg != nullptr);
   GPR_ASSERT(ts->acked_time.time.clock_type == GPR_CLOCK_REALTIME);
index fa0a23d..7aa0e1c 100644 (file)
@@ -32,7 +32,7 @@ static void test_no_op(void) {
   GRPC_COMBINER_UNREF(grpc_combiner_create(), "test_no_op");
 }
 
-static void set_event_to_true(void* value, grpc_error* /*error*/) {
+static void set_event_to_true(void* value, grpc_error_handle /*error*/) {
   gpr_event_set(static_cast<gpr_event*>(value), reinterpret_cast<void*>(1));
 }
 
@@ -62,7 +62,7 @@ typedef struct {
   size_t value;
 } ex_args;
 
-static void check_one(void* a, grpc_error* /*error*/) {
+static void check_one(void* a, grpc_error_handle /*error*/) {
   ex_args* args = static_cast<ex_args*>(a);
   GPR_ASSERT(*args->ctr == args->value - 1);
   *args->ctr = args->value;
@@ -114,11 +114,11 @@ static void test_execute_many(void) {
 
 static gpr_event got_in_finally;
 
-static void in_finally(void* /*arg*/, grpc_error* /*error*/) {
+static void in_finally(void* /*arg*/, grpc_error_handle /*error*/) {
   gpr_event_set(&got_in_finally, reinterpret_cast<void*>(1));
 }
 
-static void add_finally(void* arg, grpc_error* /*error*/) {
+static void add_finally(void* arg, grpc_error_handle /*error*/) {
   static_cast<grpc_core::Combiner*>(arg)->Run(
       GRPC_CLOSURE_CREATE(in_finally, arg, nullptr), GRPC_ERROR_NONE);
 }
index 40d676a..fb7686b 100644 (file)
@@ -54,7 +54,7 @@ static grpc_endpoint_test_config configs[] = {
     {"tcp/tcp_socketpair", create_fixture_endpoint_pair, clean_up},
 };
 
-static void destroy_pollset(void* p, grpc_error* /*error*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
index 1a16e84..78a6df6 100644 (file)
@@ -118,14 +118,15 @@ struct read_and_write_test_state {
   grpc_closure write_scheduler;
 };
 
-static void read_scheduler(void* data, grpc_error* /* error */) {
+static void read_scheduler(void* data, grpc_error_handle /* error */) {
   struct read_and_write_test_state* state =
       static_cast<struct read_and_write_test_state*>(data);
   grpc_endpoint_read(state->read_ep, &state->incoming, &state->done_read,
                      /*urgent=*/false);
 }
 
-static void read_and_write_test_read_handler(void* data, grpc_error* error) {
+static void read_and_write_test_read_handler(void* data,
+                                             grpc_error_handle error) {
   struct read_and_write_test_state* state =
       static_cast<struct read_and_write_test_state*>(data);
 
@@ -146,14 +147,15 @@ static void read_and_write_test_read_handler(void* data, grpc_error* error) {
   }
 }
 
-static void write_scheduler(void* data, grpc_error* /* error */) {
+static void write_scheduler(void* data, grpc_error_handle /* error */) {
   struct read_and_write_test_state* state =
       static_cast<struct read_and_write_test_state*>(data);
   grpc_endpoint_write(state->write_ep, &state->outgoing, &state->done_write,
                       nullptr);
 }
 
-static void read_and_write_test_write_handler(void* data, grpc_error* error) {
+static void read_and_write_test_write_handler(void* data,
+                                              grpc_error_handle error) {
   struct read_and_write_test_state* state =
       static_cast<struct read_and_write_test_state*>(data);
   grpc_slice* slices = nullptr;
@@ -272,7 +274,7 @@ static void read_and_write_test(grpc_endpoint_test_config config,
   grpc_endpoint_destroy(state.write_ep);
 }
 
-static void inc_on_failure(void* arg, grpc_error* error) {
+static void inc_on_failure(void* arg, grpc_error_handle error) {
   gpr_mu_lock(g_mu);
   *static_cast<int*>(arg) += (error != GRPC_ERROR_NONE);
   GPR_ASSERT(GRPC_LOG_IF_ERROR("kick", grpc_pollset_kick(g_pollset, nullptr)));
index 3ba9014..e50a5f0 100644 (file)
@@ -27,7 +27,7 @@
 #include "test/core/util/test_config.h"
 
 static void test_set_get_int() {
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test");
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test");
   GPR_ASSERT(error);
   intptr_t i = 0;
   GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_FILE_LINE, &i));
@@ -49,7 +49,7 @@ static void test_set_get_int() {
 }
 
 static void test_set_get_str() {
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test");
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test");
 
   grpc_slice str;
   GPR_ASSERT(!grpc_error_get_str(error, GRPC_ERROR_STR_SYSCALL, &str));
@@ -76,7 +76,7 @@ static void test_set_get_str() {
 
 static void test_copy_and_unref() {
   // error1 has one ref
-  grpc_error* error1 = grpc_error_set_str(
+  grpc_error_handle error1 = grpc_error_set_str(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test"), GRPC_ERROR_STR_GRPC_MESSAGE,
       grpc_slice_from_static_string("message"));
   grpc_slice str;
@@ -87,7 +87,7 @@ static void test_copy_and_unref() {
   // error 1 has two refs
   GRPC_ERROR_REF(error1);
   // this gives error3 a ref to the new error, and decrements error1 to one ref
-  grpc_error* error3 = grpc_error_set_str(
+  grpc_error_handle error3 = grpc_error_set_str(
       error1, GRPC_ERROR_STR_SYSCALL, grpc_slice_from_static_string("syscall"));
   GPR_ASSERT(error3 != error1);  // should not be the same because of extra ref
   GPR_ASSERT(grpc_error_get_str(error3, GRPC_ERROR_STR_GRPC_MESSAGE, &str));
@@ -105,10 +105,10 @@ static void test_copy_and_unref() {
 }
 
 static void test_create_referencing() {
-  grpc_error* child = grpc_error_set_str(
+  grpc_error_handle child = grpc_error_set_str(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Child"),
       GRPC_ERROR_STR_GRPC_MESSAGE, grpc_slice_from_static_string("message"));
-  grpc_error* parent =
+  grpc_error_handle parent =
       GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Parent", &child, 1);
   GPR_ASSERT(parent);
 
@@ -117,7 +117,7 @@ static void test_create_referencing() {
 }
 
 static void test_create_referencing_many() {
-  grpc_error* children[3];
+  grpc_error_handle children[3];
   children[0] = grpc_error_set_str(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Child1"),
       GRPC_ERROR_STR_GRPC_MESSAGE, grpc_slice_from_static_string("message"));
@@ -128,7 +128,7 @@ static void test_create_referencing_many() {
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Child3"),
       GRPC_ERROR_STR_GRPC_MESSAGE, grpc_slice_from_static_string("message 3"));
 
-  grpc_error* parent =
+  grpc_error_handle parent =
       GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Parent", children, 3);
   GPR_ASSERT(parent);
 
@@ -139,18 +139,18 @@ static void test_create_referencing_many() {
 }
 
 static void print_error_string() {
-  grpc_error* error =
+  grpc_error_handle error =
       grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"),
                          GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNIMPLEMENTED);
   error = grpc_error_set_int(error, GRPC_ERROR_INT_SIZE, 666);
   error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE,
                              grpc_slice_from_static_string("message"));
-  // gpr_log(GPR_DEBUG, "%s", grpc_error_string(error));
+  // gpr_log(GPR_DEBUG, "%s", grpc_error_std_string(error).c_str());
   GRPC_ERROR_UNREF(error);
 }
 
 static void print_error_string_reference() {
-  grpc_error* children[2];
+  grpc_error_handle children[2];
   children[0] = grpc_error_set_str(
       grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("1"),
                          GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNIMPLEMENTED),
@@ -162,7 +162,7 @@ static void print_error_string_reference() {
       GRPC_ERROR_STR_GRPC_MESSAGE,
       grpc_slice_from_static_string("message for child 2"));
 
-  grpc_error* parent =
+  grpc_error_handle parent =
       GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Parent", children, 2);
 
   for (size_t i = 0; i < 2; ++i) {
@@ -174,7 +174,7 @@ static void print_error_string_reference() {
 static void test_os_error() {
   int fake_errno = 5;
   const char* syscall = "syscall name";
-  grpc_error* error = GRPC_OS_ERROR(fake_errno, syscall);
+  grpc_error_handle error = GRPC_OS_ERROR(fake_errno, syscall);
 
   intptr_t i = 0;
   GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_ERRNO, &i));
@@ -188,7 +188,7 @@ static void test_os_error() {
 }
 
 static void test_overflow() {
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Overflow");
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Overflow");
 
   for (size_t i = 0; i < 150; ++i) {
     error = grpc_error_add_child(error,
index 5bc5935..35c27ec 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "test/core/util/test_config.h"
 
-static void pollset_destroy(void* ps, grpc_error* /*error*/) {
+static void pollset_destroy(void* ps, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(ps));
   gpr_free(ps);
 }
index 85f5378..9ca837e 100644 (file)
@@ -124,7 +124,7 @@ static void session_shutdown_cb(void* arg, /*session */
 
 /* Called when data become readable in a session. */
 static void session_read_cb(void* arg, /*session */
-                            grpc_error* error) {
+                            grpc_error_handle error) {
   session* se = static_cast<session*>(arg);
   int fd = grpc_fd_wrapped_fd(se->em_fd);
 
@@ -182,7 +182,7 @@ static void listen_shutdown_cb(void* arg /*server*/, int /*success*/) {
 
 /* Called when a new TCP connection request arrives in the listening port. */
 static void listen_cb(void* arg, /*=sv_arg*/
-                      grpc_error* error) {
+                      grpc_error_handle error) {
   server* sv = static_cast<server*>(arg);
   int fd;
   int flags;
@@ -297,7 +297,7 @@ static void client_session_shutdown_cb(void* arg /*client*/, int /*success*/) {
 
 /* Write as much as possible, then register notify_on_write. */
 static void client_session_write(void* arg, /*client */
-                                 grpc_error* error) {
+                                 grpc_error_handle error) {
   client* cl = static_cast<client*>(arg);
   int fd = grpc_fd_wrapped_fd(cl->em_fd);
   ssize_t write_once = 0;
@@ -404,7 +404,7 @@ void init_change_data(fd_change_data* fdc) { fdc->cb_that_ran = nullptr; }
 void destroy_change_data(fd_change_data* /*fdc*/) {}
 
 static void first_read_callback(void* arg /* fd_change_data */,
-                                grpc_error* /*error*/) {
+                                grpc_error_handle /*error*/) {
   fd_change_data* fdc = static_cast<fd_change_data*>(arg);
 
   gpr_mu_lock(g_mu);
@@ -415,7 +415,7 @@ static void first_read_callback(void* arg /* fd_change_data */,
 }
 
 static void second_read_callback(void* arg /* fd_change_data */,
-                                 grpc_error* /*error*/) {
+                                 grpc_error_handle /*error*/) {
   fd_change_data* fdc = static_cast<fd_change_data*>(arg);
 
   gpr_mu_lock(g_mu);
@@ -509,7 +509,7 @@ static void test_grpc_fd_change(void) {
   close(sv[1]);
 }
 
-static void destroy_pollset(void* p, grpc_error* /*error*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
index 24afdd2..a826f04 100644 (file)
@@ -43,7 +43,7 @@ static void finish_connection() {
   gpr_mu_unlock(&g_mu);
 }
 
-static void must_succeed(void* arg, grpc_error* error) {
+static void must_succeed(void* arg, grpc_error_handle error) {
   GPR_ASSERT(g_connecting != nullptr);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   grpc_endpoint_shutdown(g_connecting, GRPC_ERROR_CREATE_FROM_STATIC_STRING("must_succeed called"));
@@ -52,11 +52,10 @@ static void must_succeed(void* arg, grpc_error* error) {
   finish_connection();
 }
 
-static void must_fail(void* arg, grpc_error* error) {
+static void must_fail(void* arg, grpc_error_handle error) {
   GPR_ASSERT(g_connecting == nullptr);
   GPR_ASSERT(error != GRPC_ERROR_NONE);
-  const char* error_str = grpc_error_string(error);
-  NSLog(@"%s", error_str);
+  NSLog(@"%s", grpc_error_std_string(error).c_str());
   finish_connection();
 }
 
index 5cd0d69..a4a8555 100644 (file)
@@ -40,7 +40,7 @@ static const int kBufferSize = 10000;
 
 static const int kRunLoopTimeout = 1;
 
-static void set_atm(void *arg, grpc_error *error) {
+static void set_atm(void *arg, grpc_error_handle error) {
   gpr_atm *p = static_cast<gpr_atm *>(arg);
   gpr_atm_full_cas(p, -1, reinterpret_cast<gpr_atm>(error));
 }
@@ -138,7 +138,7 @@ static bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const ch
 
   /* wait for the connection callback to finish */
   XCTAssertEqual([self waitForEvent:&connected timeout:kConnectTimeout], YES);
-  XCTAssertEqual(reinterpret_cast<grpc_error *>(connected), GRPC_ERROR_NONE);
+  XCTAssertEqual(reinterpret_cast<grpc_error_handle>(connected), GRPC_ERROR_NONE);
 }
 
 - (void)tearDown {
@@ -170,7 +170,7 @@ static bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const ch
   grpc_endpoint_write(ep_, &write_slices, &write_done, nullptr);
 
   XCTAssertEqual([self waitForEvent:&write timeout:kWriteTimeout], YES);
-  XCTAssertEqual(reinterpret_cast<grpc_error *>(write), GRPC_ERROR_NONE);
+  XCTAssertEqual(reinterpret_cast<grpc_error_handle>(write), GRPC_ERROR_NONE);
 
   while (recv_size < kBufferSize) {
     ssize_t size = recv(svr_fd_, read_buffer, kBufferSize, 0);
@@ -189,7 +189,7 @@ static bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const ch
     init_event_closure(&read_done, &read);
     grpc_endpoint_read(ep_, &read_one_slice, &read_done, /*urgent=*/false);
     XCTAssertEqual([self waitForEvent:&read timeout:kReadTimeout], YES);
-    XCTAssertEqual(reinterpret_cast<grpc_error *>(read), GRPC_ERROR_NONE);
+    XCTAssertEqual(reinterpret_cast<grpc_error_handle>(read), GRPC_ERROR_NONE);
     grpc_slice_buffer_move_into(&read_one_slice, &read_slices);
     XCTAssertLessThanOrEqual(read_slices.length, kBufferSize);
   }
@@ -227,7 +227,7 @@ static bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const ch
   grpc_endpoint_write(ep_, &write_slices, &write_done, nullptr);
 
   XCTAssertEqual([self waitForEvent:&write timeout:kWriteTimeout], YES);
-  XCTAssertEqual(reinterpret_cast<grpc_error *>(write), GRPC_ERROR_NONE);
+  XCTAssertEqual(reinterpret_cast<grpc_error_handle>(write), GRPC_ERROR_NONE);
 
   while (recv_size < kBufferSize) {
     ssize_t size = recv(svr_fd_, read_buffer, kBufferSize, 0);
@@ -244,7 +244,7 @@ static bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const ch
 
   grpc_core::ExecCtx::Get()->Flush();
   XCTAssertEqual([self waitForEvent:&read timeout:kReadTimeout], YES);
-  XCTAssertNotEqual(reinterpret_cast<grpc_error *>(read), GRPC_ERROR_NONE);
+  XCTAssertNotEqual(reinterpret_cast<grpc_error_handle>(read), GRPC_ERROR_NONE);
 
   grpc_slice_buffer_reset_and_unref(&read_slices);
   grpc_slice_buffer_reset_and_unref(&write_slices);
@@ -276,7 +276,7 @@ static bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const ch
   grpc_endpoint_write(ep_, &write_slices, &write_done, nullptr);
 
   XCTAssertEqual([self waitForEvent:&write timeout:kWriteTimeout], YES);
-  XCTAssertEqual(reinterpret_cast<grpc_error *>(write), GRPC_ERROR_NONE);
+  XCTAssertEqual(reinterpret_cast<grpc_error_handle>(write), GRPC_ERROR_NONE);
 
   while (recv_size < kBufferSize) {
     ssize_t size = recv(svr_fd_, read_buffer, kBufferSize, 0);
@@ -290,7 +290,7 @@ static bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const ch
   close(svr_fd_);
 
   XCTAssertEqual([self waitForEvent:&read timeout:kReadTimeout], YES);
-  XCTAssertNotEqual(reinterpret_cast<grpc_error *>(read), GRPC_ERROR_NONE);
+  XCTAssertNotEqual(reinterpret_cast<grpc_error_handle>(read), GRPC_ERROR_NONE);
 
   grpc_endpoint_shutdown(ep_, GRPC_ERROR_NONE);
   grpc_slice_buffer_reset_and_unref(&read_slices);
@@ -316,7 +316,7 @@ static bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const ch
   close(svr_fd_);
 
   XCTAssertEqual([self waitForEvent:&read timeout:kReadTimeout], YES);
-  XCTAssertNotEqual(reinterpret_cast<grpc_error *>(read), GRPC_ERROR_NONE);
+  XCTAssertNotEqual(reinterpret_cast<grpc_error_handle>(read), GRPC_ERROR_NONE);
 
   grpc_endpoint_shutdown(ep_, GRPC_ERROR_NONE);
   grpc_slice_buffer_reset_and_unref(&read_slices);
index a0e0e4d..6974ced 100644 (file)
@@ -37,7 +37,7 @@ static void test_load_empty_file(void) {
   FILE* tmp = nullptr;
   grpc_slice slice;
   grpc_slice slice_with_null_term;
-  grpc_error* error;
+  grpc_error_handle error;
   char* tmp_name;
 
   LOG_TEST_NAME("test_load_empty_file");
@@ -65,7 +65,7 @@ static void test_load_empty_file(void) {
 static void test_load_failure(void) {
   FILE* tmp = nullptr;
   grpc_slice slice;
-  grpc_error* error;
+  grpc_error_handle error;
   char* tmp_name;
 
   LOG_TEST_NAME("test_load_failure");
@@ -88,7 +88,7 @@ static void test_load_small_file(void) {
   FILE* tmp = nullptr;
   grpc_slice slice;
   grpc_slice slice_with_null_term;
-  grpc_error* error;
+  grpc_error_handle error;
   char* tmp_name;
   const char* blah = "blah";
 
@@ -120,7 +120,7 @@ static void test_load_small_file(void) {
 static void test_load_big_file(void) {
   FILE* tmp = nullptr;
   grpc_slice slice;
-  grpc_error* error;
+  grpc_error_handle error;
   char* tmp_name;
   static const size_t buffer_size = 124631;
   unsigned char* buffer = static_cast<unsigned char*>(gpr_malloc(buffer_size));
diff --git a/test/core/iomgr/poller/eventmanager_libuv_test.cc b/test/core/iomgr/poller/eventmanager_libuv_test.cc
deleted file mode 100644 (file)
index 82b6de1..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-
-/*
- *
- * 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/core/lib/iomgr/poller/eventmanager_libuv.h"
-
-#include <grpc/grpc.h>
-#include <grpc/support/time.h>
-#include <gtest/gtest.h>
-
-#include "test/core/util/test_config.h"
-
-using grpc::experimental::LibuvEventManager;
-
-namespace grpc_core {
-namespace {
-
-TEST(LibuvEventManager, Allocation) {
-  for (int i = 0; i < 10; i++) {
-    LibuvEventManager* em =
-        new LibuvEventManager(LibuvEventManager::Options(i));
-    gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1));
-    delete em;
-  }
-}
-
-TEST(LibuvEventManager, ShutdownRef) {
-  for (int i = 0; i < 10; i++) {
-    LibuvEventManager* em =
-        new LibuvEventManager(LibuvEventManager::Options(i));
-    for (int j = 0; j < i; j++) {
-      em->ShutdownRef();
-    }
-    gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1));
-    for (int j = 0; j < i; j++) {
-      em->ShutdownUnref();
-    }
-    delete em;
-  }
-}
-
-TEST(LibuvEventManager, ShutdownRefAsync) {
-  for (int i = 0; i < 10; i++) {
-    LibuvEventManager* em =
-        new LibuvEventManager(LibuvEventManager::Options(i));
-    for (int j = 0; j < i; j++) {
-      em->ShutdownRef();
-    }
-    // TSAN doesn't like this approach although this would work. TSAN considers
-    // it dangerous to have a destructor being called while its member function
-    // is called but LibuvEventManager handles this by making LibuvEventManager
-    // wait until all pending operations finish.
-    grpc_core::Thread deleter(
-        "deleter", [](void* em) { delete static_cast<LibuvEventManager*>(em); },
-        em);
-    deleter.Start();
-    gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1));
-    for (int j = 0; j < i; j++) {
-      em->ShutdownUnref();
-    }
-    deleter.Join();
-  }
-}
-
-}  // namespace
-}  // namespace grpc_core
-
-int main(int argc, char** argv) {
-  grpc_init();
-  grpc::testing::TestEnvironment env(argc, argv);
-  ::testing::InitGoogleTest(&argc, argv);
-  int retval = RUN_ALL_TESTS();
-  grpc_shutdown();
-  return retval;
-}
index eed57b1..3357e3b 100644 (file)
@@ -91,7 +91,7 @@ int main(int argc, char** argv) {
 
           // Queue for work and once we're done, make sure to kick the remaining
           // threads.
-          grpc_error* error;
+          grpc_error_handle error;
           error = grpc_pollset_work(&pollset, NULL, GRPC_MILLIS_INF_FUTURE);
           error = grpc_pollset_kick(&pollset, NULL);
 
index 04cf766..6924a35 100644 (file)
@@ -56,7 +56,7 @@ typedef struct args_struct {
   grpc_pollset_set* pollset_set;
 } args_struct;
 
-static void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
+static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 void args_init(args_struct* args) {
   gpr_event_init(&args->ev);
@@ -118,7 +118,7 @@ static void poll_pollset_until_request_done(args_struct* args) {
   args->thd.Start();
 }
 
-static void must_succeed(void* argsp, grpc_error* err) {
+static void must_succeed(void* argsp, grpc_error_handle err) {
   args_struct* args = static_cast<args_struct*>(argsp);
   GPR_ASSERT(err == GRPC_ERROR_NONE);
   GPR_ASSERT(args->addrs != nullptr);
@@ -128,7 +128,7 @@ static void must_succeed(void* argsp, grpc_error* err) {
   GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(args->pollset, nullptr));
 }
 
-static void must_fail(void* argsp, grpc_error* err) {
+static void must_fail(void* argsp, grpc_error_handle err) {
   args_struct* args = static_cast<args_struct*>(argsp);
   GPR_ASSERT(err != GRPC_ERROR_NONE);
   grpc_core::MutexLockForGprMu lock(args->mu);
index b77fd72..c8a4d15 100644 (file)
@@ -48,7 +48,7 @@ typedef struct args_struct {
   grpc_pollset_set* pollset_set;
 } args_struct;
 
-static void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
+static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 void args_init(args_struct* args) {
   gpr_event_init(&args->ev);
@@ -105,7 +105,7 @@ static void poll_pollset_until_request_done(args_struct* args) {
   gpr_event_set(&args->ev, reinterpret_cast<void*>(1));
 }
 
-static void must_succeed(void* argsp, grpc_error* err) {
+static void must_succeed(void* argsp, grpc_error_handle err) {
   args_struct* args = static_cast<args_struct*>(argsp);
   GPR_ASSERT(err == GRPC_ERROR_NONE);
   GPR_ASSERT(args->addrs != nullptr);
@@ -115,7 +115,7 @@ static void must_succeed(void* argsp, grpc_error* err) {
   GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(args->pollset, nullptr));
 }
 
-static void must_fail(void* argsp, grpc_error* err) {
+static void must_fail(void* argsp, grpc_error_handle err) {
   args_struct* args = static_cast<args_struct*>(argsp);
   GPR_ASSERT(err != GRPC_ERROR_NONE);
   grpc_core::MutexLockForGprMu lock(args->mu);
@@ -124,7 +124,7 @@ static void must_fail(void* argsp, grpc_error* err) {
 }
 
 // This test assumes the environment has an ipv6 loopback
-static void must_succeed_with_ipv6_first(void* argsp, grpc_error* err) {
+static void must_succeed_with_ipv6_first(void* argsp, grpc_error_handle err) {
   args_struct* args = static_cast<args_struct*>(argsp);
   GPR_ASSERT(err == GRPC_ERROR_NONE);
   GPR_ASSERT(args->addrs != nullptr);
@@ -137,7 +137,7 @@ static void must_succeed_with_ipv6_first(void* argsp, grpc_error* err) {
   GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(args->pollset, nullptr));
 }
 
-static void must_succeed_with_ipv4_first(void* argsp, grpc_error* err) {
+static void must_succeed_with_ipv4_first(void* argsp, grpc_error_handle err) {
   args_struct* args = static_cast<args_struct*>(argsp);
   GPR_ASSERT(err == GRPC_ERROR_NONE);
   GPR_ASSERT(args->addrs != nullptr);
index 7f516b7..5d71af1 100644 (file)
@@ -28,7 +28,7 @@
 gpr_mu g_mu;
 gpr_cv g_cv;
 
-static void inc_int_cb(void* a, grpc_error* /*error*/) {
+static void inc_int_cb(void* a, grpc_error_handle /*error*/) {
   gpr_mu_lock(&g_mu);
   ++*static_cast<int*>(a);
   gpr_cv_signal(&g_cv);
@@ -44,7 +44,7 @@ static void assert_counter_becomes(int* ctr, int value) {
   gpr_mu_unlock(&g_mu);
 }
 
-static void set_event_cb(void* a, grpc_error* /*error*/) {
+static void set_event_cb(void* a, grpc_error_handle /*error*/) {
   gpr_event_set(static_cast<gpr_event*>(a), reinterpret_cast<void*>(1));
 }
 grpc_closure* set_event(gpr_event* ev) {
@@ -57,7 +57,7 @@ typedef struct {
   grpc_closure* then;
 } reclaimer_args;
 
-static void reclaimer_cb(void* args, grpc_error* error) {
+static void reclaimer_cb(void* args, grpc_error_handle error) {
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   reclaimer_args* a = static_cast<reclaimer_args*>(args);
   grpc_resource_user_free(a->resource_user, a->size);
@@ -75,7 +75,7 @@ grpc_closure* make_reclaimer(grpc_resource_user* resource_user, size_t size,
   return GRPC_CLOSURE_CREATE(reclaimer_cb, a, grpc_schedule_on_exec_ctx);
 }
 
-static void unused_reclaimer_cb(void* arg, grpc_error* error) {
+static void unused_reclaimer_cb(void* arg, grpc_error_handle error) {
   GPR_ASSERT(error == GRPC_ERROR_CANCELLED);
   grpc_core::Closure::Run(DEBUG_LOCATION, static_cast<grpc_closure*>(arg),
                           GRPC_ERROR_NONE);
index d307f04..f6f0b37 100644 (file)
@@ -80,7 +80,7 @@ static const grpc_socket_mutator_vtable mutator_vtable = {
 
 int main(int argc, char** argv) {
   int sock;
-  grpc_error* err;
+  grpc_error_handle err;
   grpc::testing::TestEnvironment env(argc, argv);
 
   sock = socket(PF_INET, SOCK_STREAM, 0);
index 64f2c59..4511823 100644 (file)
 #include "absl/types/optional.h"
 
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/security/credentials/alts/alts_credentials.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/security_connector/alts/alts_security_connector.h"
index d918609..4e21292 100644 (file)
@@ -60,7 +60,7 @@ static void finish_connection() {
   gpr_mu_unlock(g_mu);
 }
 
-static void must_succeed(void* /*arg*/, grpc_error* error) {
+static void must_succeed(void* /*arg*/, grpc_error_handle error) {
   GPR_ASSERT(g_connecting != nullptr);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   grpc_endpoint_shutdown(g_connecting, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -70,7 +70,7 @@ static void must_succeed(void* /*arg*/, grpc_error* error) {
   finish_connection();
 }
 
-static void must_fail(void* /*arg*/, grpc_error* error) {
+static void must_fail(void* /*arg*/, grpc_error_handle error) {
   GPR_ASSERT(g_connecting == nullptr);
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   finish_connection();
@@ -185,7 +185,7 @@ void test_fails(void) {
   gpr_mu_unlock(g_mu);
 }
 
-static void destroy_pollset(void* p, grpc_error* /*error*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
index 35e8d18..6b73833 100644 (file)
@@ -54,7 +54,7 @@ static void finish_connection() {
   gpr_mu_unlock(g_mu);
 }
 
-static void must_succeed(void* arg, grpc_error* error) {
+static void must_succeed(void* arg, grpc_error_handle error) {
   GPR_ASSERT(g_connecting != NULL);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   grpc_endpoint_shutdown(g_connecting, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -64,7 +64,7 @@ static void must_succeed(void* arg, grpc_error* error) {
   finish_connection();
 }
 
-static void must_fail(void* arg, grpc_error* error) {
+static void must_fail(void* arg, grpc_error_handle error) {
   GPR_ASSERT(g_connecting == NULL);
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   finish_connection();
@@ -182,7 +182,7 @@ void test_fails(void) {
   grpc_core::ExecCtx::Get()->Flush();
 }
 
-static void destroy_pollset(void* p, grpc_error* error) {
+static void destroy_pollset(void* p, grpc_error_handle error) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
index 3d995ee..17c81b8 100644 (file)
@@ -172,7 +172,7 @@ static size_t count_slices(grpc_slice* slices, size_t nslices,
   return num_bytes;
 }
 
-static void read_cb(void* user_data, grpc_error* error) {
+static void read_cb(void* user_data, grpc_error_handle error) {
   struct read_socket_state* state =
       static_cast<struct read_socket_state*>(user_data);
   size_t read_bytes;
@@ -330,7 +330,7 @@ static grpc_slice* allocate_blocks(size_t num_bytes, size_t slice_size,
 }
 
 static void write_done(void* user_data /* write_socket_state */,
-                       grpc_error* error) {
+                       grpc_error_handle error) {
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   struct write_socket_state* state =
       static_cast<struct write_socket_state*>(user_data);
@@ -383,7 +383,7 @@ void drain_socket_blocking(int fd, size_t num_bytes, size_t read_size) {
 
 /* Verifier for timestamps callback for write_test */
 void timestamps_verifier(void* arg, grpc_core::Timestamps* ts,
-                         grpc_error* error) {
+                         grpc_error_handle error) {
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(arg != nullptr);
   GPR_ASSERT(ts->sendmsg_time.time.clock_type == GPR_CLOCK_REALTIME);
@@ -473,7 +473,7 @@ static void write_test(size_t num_bytes, size_t slice_size,
   gpr_free(slices);
 }
 
-void on_fd_released(void* arg, grpc_error* /*errors*/) {
+void on_fd_released(void* arg, grpc_error_handle /*errors*/) {
   int* done = static_cast<int*>(arg);
   *done = 1;
   GPR_ASSERT(
@@ -619,7 +619,7 @@ static grpc_endpoint_test_config configs[] = {
     {"tcp/tcp_socketpair", create_fixture_tcp_socketpair, clean_up},
 };
 
-static void destroy_pollset(void* p, grpc_error* /*error*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
index 1441c0d..2e54266 100644 (file)
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
@@ -112,7 +112,7 @@ static void on_connect_result_set(on_connect_result* result,
       result->server, acceptor->port_index, acceptor->fd_index);
 }
 
-static void server_weak_ref_shutdown(void* arg, grpc_error* /*error*/) {
+static void server_weak_ref_shutdown(void* arg, grpc_error_handle /*error*/) {
   server_weak_ref* weak_ref = static_cast<server_weak_ref*>(arg);
   weak_ref->server = nullptr;
 }
@@ -220,8 +220,8 @@ static void test_no_op_with_port_and_start(void) {
   grpc_tcp_server_unref(s);
 }
 
-static grpc_error* tcp_connect(const test_addr* remote,
-                               on_connect_result* result) {
+static grpc_error_handle tcp_connect(const test_addr* remote,
+                                     on_connect_result* result) {
   grpc_millis deadline =
       grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(10));
   int clifd;
@@ -249,7 +249,7 @@ static grpc_error* tcp_connect(const test_addr* remote,
   while (g_nconnects == nconnects_before &&
          deadline > grpc_core::ExecCtx::Get()->Now()) {
     grpc_pollset_worker* worker = nullptr;
-    grpc_error* err;
+    grpc_error_handle err;
     if ((err = grpc_pollset_work(g_pollset, &worker, deadline)) !=
         GRPC_ERROR_NONE) {
       gpr_mu_unlock(g_mu);
@@ -358,7 +358,7 @@ static void test_connect(size_t num_connects,
       for (dst_idx = 0; dst_idx < dst_addrs->naddrs; ++dst_idx) {
         test_addr dst = dst_addrs->addrs[dst_idx];
         on_connect_result result;
-        grpc_error* err;
+        grpc_error_handle err;
         if (dst.addr.len == 0) {
           gpr_log(GPR_DEBUG, "Skipping test of non-functional local IP %s",
                   dst.str);
@@ -373,7 +373,7 @@ static void test_connect(size_t num_connects,
           continue;
         }
         gpr_log(GPR_ERROR, "Failed to connect to %s: %s", dst.str,
-                grpc_error_string(err));
+                grpc_error_std_string(err).c_str());
         GPR_ASSERT(test_dst_addrs);
         dst_addrs->addrs[dst_idx].addr.len = 0;
         GRPC_ERROR_UNREF(err);
@@ -423,7 +423,7 @@ static void test_connect(size_t num_connects,
   GPR_ASSERT(weak_ref.server == nullptr);
 }
 
-static void destroy_pollset(void* p, grpc_error* /*error*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
index a084ccc..0bc0beb 100644 (file)
@@ -33,9 +33,9 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
@@ -74,7 +74,7 @@ static void on_connect_result_set(on_connect_result* result,
   result->fd_index = acceptor->fd_index;
 }
 
-static void server_weak_ref_shutdown(void* arg, grpc_error* error) {
+static void server_weak_ref_shutdown(void* arg, grpc_error_handle error) {
   server_weak_ref* weak_ref = static_cast<server_weak_ref*>(arg);
   weak_ref->server = NULL;
 }
@@ -282,7 +282,7 @@ static void test_connect(unsigned n) {
   GPR_ASSERT(weak_ref.server == NULL);
 }
 
-static void destroy_pollset(void* p, grpc_error* error) {
+static void destroy_pollset(void* p, grpc_error_handle error) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
index a26926d..f4a1b20 100644 (file)
@@ -41,7 +41,7 @@ static int cb_called[MAX_CB][2];
 static const int64_t kMillisIn25Days = 2160000000;
 static const int64_t kHoursIn25Days = 600;
 
-static void cb(void* arg, grpc_error* error) {
+static void cb(void* arg, grpc_error_handle error) {
   cb_called[reinterpret_cast<intptr_t>(arg)][error == GRPC_ERROR_NONE]++;
 }
 
index a0e02e2..a036b0c 100644 (file)
@@ -172,7 +172,7 @@ static test_socket_factory* test_socket_factory_create(void) {
   return factory;
 }
 
-static void destroy_pollset(void* p, grpc_error* /*error*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
index e9eecf2..2925611 100644 (file)
@@ -29,7 +29,7 @@ bool squelch = true;
 bool leak_check = true;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json::Parse(
       absl::string_view(reinterpret_cast<const char*>(data), size), &error);
   GRPC_ERROR_UNREF(error);
index 1e5b404..c724f1b 100644 (file)
@@ -75,9 +75,9 @@ void ValidateValue(const Json& actual, const Json& expected) {
 void RunSuccessTest(const char* input, const Json& expected,
                     const char* expected_output) {
   gpr_log(GPR_INFO, "parsing string \"%s\" - should succeed", input);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(input, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ValidateValue(json, expected);
   std::string output = json.Dump();
   EXPECT_EQ(output, expected_output);
@@ -165,9 +165,9 @@ TEST(Json, Keywords) {
 
 void RunParseFailureTest(const char* input) {
   gpr_log(GPR_INFO, "parsing string \"%s\" - should fail", input);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(input, &error);
-  gpr_log(GPR_INFO, "error: %s", grpc_error_string(error));
+  gpr_log(GPR_INFO, "error: %s", grpc_error_std_string(error).c_str());
   EXPECT_NE(error, GRPC_ERROR_NONE);
   GRPC_ERROR_UNREF(error);
 }
index 78041cb..248e0bb 100644 (file)
@@ -73,8 +73,8 @@ grpc_cc_test(
 )
 
 grpc_cc_test(
-    name = "authorization_engine_test",
-    srcs = ["authorization_engine_test.cc"],
+    name = "cel_authorization_engine_test",
+    srcs = ["cel_authorization_engine_test.cc"],
     external_deps = ["gtest"],
     language = "C++",
     deps = [
@@ -425,3 +425,29 @@ grpc_cc_test(
         "//test/core/util:grpc_test_util",
     ],
 )
+
+grpc_cc_test(
+    name = "authorization_matchers_test",
+    srcs = ["authorization_matchers_test.cc"],
+    external_deps = ["gtest"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc_rbac_engine",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "grpc_authorization_engine_test",
+    srcs = ["grpc_authorization_engine_test.cc"],
+    external_deps = ["gtest"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc_rbac_engine",
+        "//test/core/util:grpc_test_util",
+    ],
+)
diff --git a/test/core/security/authorization_matchers_test.cc b/test/core/security/authorization_matchers_test.cc
new file mode 100644 (file)
index 0000000..36b3862
--- /dev/null
@@ -0,0 +1,420 @@
+// Copyright 2021 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <grpc/support/port_platform.h>
+
+#include <list>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "src/core/lib/security/authorization/evaluate_args.h"
+#include "src/core/lib/security/authorization/matchers.h"
+#include "test/core/util/evaluate_args_test_util.h"
+
+namespace grpc_core {
+
+class AuthorizationMatchersTest : public ::testing::Test {
+ protected:
+  EvaluateArgsTestUtil args_;
+};
+
+TEST_F(AuthorizationMatchersTest, AlwaysAuthorizationMatcher) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AlwaysAuthorizationMatcher matcher;
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotAlwaysAuthorizationMatcher) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AlwaysAuthorizationMatcher matcher(/*not_rule=*/true);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, AndAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("foo", "bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/123));
+  AndAuthorizationMatcher matcher(std::move(rules));
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, AndAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("foo", "not_bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/123));
+  AndAuthorizationMatcher matcher(std::move(rules));
+  // Header rule fails. Expected value "bar", got "not_bar" for key "foo".
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotAndAuthorizationMatcher) {
+  args_.AddPairToMetadata(":path", "/expected/foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  StringMatcher string_matcher =
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"/expected/foo",
+                            /*case_sensitive=*/false)
+          .value();
+  std::vector<std::unique_ptr<Rbac::Permission>> ids;
+  ids.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kPath, std::move(string_matcher)));
+  AndAuthorizationMatcher matcher(std::move(ids), /*not_rule=*/true);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, OrAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("foo", "bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderMatcher header_matcher =
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader, header_matcher));
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/456));
+  OrAuthorizationMatcher matcher(std::move(rules));
+  // Matches as header rule matches even though port rule fails.
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, OrAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("foo", "not_bar");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  OrAuthorizationMatcher matcher(std::move(rules));
+  // Header rule fails. Expected value "bar", got "not_bar" for key "foo".
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotOrAuthorizationMatcher) {
+  args_.AddPairToMetadata("foo", "not_bar");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  OrAuthorizationMatcher matcher(std::move(rules), /*not_rule=*/true);
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, HybridAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("foo", "bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> sub_and_rules;
+  sub_and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  std::vector<std::unique_ptr<Rbac::Permission>> sub_or_rules;
+  sub_or_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/123));
+  std::vector<std::unique_ptr<Rbac::Permission>> and_rules;
+  and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kAnd, std::move(sub_and_rules)));
+  and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kOr, std::move(std::move(sub_or_rules))));
+  AndAuthorizationMatcher matcher(std::move(and_rules));
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, HybridAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("foo", "bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> sub_and_rules;
+  sub_and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  sub_and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"absent_key", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"some_value")
+          .value()));
+  std::vector<std::unique_ptr<Rbac::Permission>> sub_or_rules;
+  sub_or_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/123));
+  std::vector<std::unique_ptr<Rbac::Permission>> and_rules;
+  and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kAnd, std::move(sub_and_rules)));
+  and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kOr, std::move(std::move(sub_or_rules))));
+  AndAuthorizationMatcher matcher(std::move(and_rules));
+  // Fails as "absent_key" header was not present.
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PathAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata(":path", "expected/path");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PathAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"expected/path",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PathAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata(":path", "different/path");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PathAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"expected/path",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotPathAuthorizationMatcher) {
+  args_.AddPairToMetadata(":path", "expected/path");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PathAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact, "expected/path", false)
+          .value(),
+      /*not_rule=*/true);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       PathAuthorizationMatcherFailedMatchMissingPath) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PathAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"expected/path",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, HeaderAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("key123", "foo_xxx");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kPrefix,
+                            /*matcher=*/"foo")
+          .value());
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, HeaderAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("key123", "foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       HeaderAuthorizationMatcherFailedMatchMultivaluedHeader) {
+  args_.AddPairToMetadata("key123", "foo");
+  args_.AddPairToMetadata("key123", "bar");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"foo")
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       HeaderAuthorizationMatcherFailedMatchMissingHeader) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kSuffix,
+                            /*matcher=*/"foo")
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotHeaderAuthorizationMatcher) {
+  args_.AddPairToMetadata("key123", "foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value(),
+      /*not_rule=*/true);
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PortAuthorizationMatcherSuccessfulMatch) {
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PortAuthorizationMatcher matcher(/*port=*/123);
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PortAuthorizationMatcherFailedMatch) {
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PortAuthorizationMatcher matcher(/*port=*/456);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotPortAuthorizationMatcher) {
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PortAuthorizationMatcher matcher(/*port=*/123, /*not_rule=*/true);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       AuthenticatedMatcherUnAuthenticatedConnection) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"foo.com",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       AuthenticatedMatcherAuthenticatedConnectionMatcherUnset) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       AuthenticatedMatcherSuccessfulSpiffeIdMatches) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  args_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME,
+                                 "spiffe://foo.abc");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"spiffe://foo.abc",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedSpiffeIdMatches) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  args_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME,
+                                 "spiffe://bar.abc");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"spiffe://foo.abc",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedNothingMatches) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"foo",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotAuthenticatedMatcher) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact, /*matcher=*/"foo",
+                            /*case_sensitive=*/false)
+          .value(),
+      /*not_rule=*/true);
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PolicyAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("key123", "foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"foo")
+          .value()));
+  PolicyAuthorizationMatcher matcher(Rbac::Policy(
+      Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(rules)),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny)));
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PolicyAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("key123", "foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  PolicyAuthorizationMatcher matcher(Rbac::Policy(
+      Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(rules)),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny)));
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  grpc_init();
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return ret;
+}
index e384183..bc5780f 100644 (file)
@@ -65,7 +65,7 @@ const char* kBotoTestDate = "Mon, 09 Sep 2011 23:36:00 GMT";
 // AWS official example from the developer doc.
 // https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
 TEST(GrpcAwsRequestSignerTest, AWSOfficialExample) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       "AKIDEXAMPLE", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", "", "GET",
       "https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08",
@@ -83,7 +83,7 @@ TEST(GrpcAwsRequestSignerTest, AWSOfficialExample) {
 }
 
 TEST(GrpcAwsRequestSignerTest, GetDescribeRegions) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kAmzTestAccessKeyId, kAmzTestSecretAccessKey, kAmzTestToken, "GET",
       "https://"
@@ -100,7 +100,7 @@ TEST(GrpcAwsRequestSignerTest, GetDescribeRegions) {
 }
 
 TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentity) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kAmzTestAccessKeyId, kAmzTestSecretAccessKey, kAmzTestToken, "POST",
       "https://"
@@ -117,7 +117,7 @@ TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentity) {
 }
 
 TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentityNoToken) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kAmzTestAccessKeyId, kAmzTestSecretAccessKey, "", "POST",
       "https://"
@@ -134,7 +134,7 @@ TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentityNoToken) {
 }
 
 TEST(GrpcAwsRequestSignerTest, GetHost) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(kBotoTestAccessKeyId,
                                      kBotoTestSecretAccessKey, kBotoTestToken,
                                      "GET", "https://host.foo.com", "us-east-1",
@@ -149,7 +149,7 @@ TEST(GrpcAwsRequestSignerTest, GetHost) {
 }
 
 TEST(GrpcAwsRequestSignerTest, GetHostDuplicateQueryParam) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "GET",
       "https://host.foo.com/?foo=Zoo&foo=aha", "us-east-1", "",
@@ -164,7 +164,7 @@ TEST(GrpcAwsRequestSignerTest, GetHostDuplicateQueryParam) {
 }
 
 TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderKey) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/", "us-east-1", "",
@@ -179,7 +179,7 @@ TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderKey) {
 }
 
 TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderValue) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/", "us-east-1", "",
@@ -194,7 +194,7 @@ TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderValue) {
 }
 
 TEST(GrpcAwsRequestSignerTest, SignPostWithHeader) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/", "us-east-1", "",
@@ -209,7 +209,7 @@ TEST(GrpcAwsRequestSignerTest, SignPostWithHeader) {
 }
 
 TEST(GrpcAwsRequestSignerTest, PostWithBodyNoCustomHeaders) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/", "us-east-1", "foo=bar",
@@ -226,7 +226,7 @@ TEST(GrpcAwsRequestSignerTest, PostWithBodyNoCustomHeaders) {
 }
 
 TEST(GrpcAwsRequestSignerTest, SignPostWithQueryString) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/?foo=bar", "us-east-1", "",
@@ -241,7 +241,7 @@ TEST(GrpcAwsRequestSignerTest, SignPostWithQueryString) {
 }
 
 TEST(GrpcAwsRequestSignerTest, InvalidUrl) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer("access_key_id", "secret_access_key",
                                      "token", "POST", "invalid_url",
                                      "us-east-1", "", {}, &error);
@@ -256,7 +256,7 @@ TEST(GrpcAwsRequestSignerTest, InvalidUrl) {
 }
 
 TEST(GrpcAwsRequestSignerTest, DuplicateRequestDate) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       "access_key_id", "secret_access_key", "token", "POST", "invalid_url",
       "us-east-1", "", {{"date", kBotoTestDate}, {"x-amz-date", kAmzTestDate}},
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/core/lib/security/authorization/authorization_engine.h"
+#include "src/core/lib/security/authorization/cel_authorization_engine.h"
 
 #include <gtest/gtest.h>
 
 namespace grpc_core {
 
-class AuthorizationEngineTest : public ::testing::Test {
+class CelAuthorizationEngineTest : public ::testing::Test {
  protected:
   void SetUp() override {
     deny_policy_ = envoy_config_rbac_v3_RBAC_new(arena_.ptr());
@@ -31,44 +31,44 @@ class AuthorizationEngineTest : public ::testing::Test {
   envoy_config_rbac_v3_RBAC* allow_policy_;
 };
 
-TEST_F(AuthorizationEngineTest, CreateEngineSuccessOnePolicy) {
+TEST_F(CelAuthorizationEngineTest, CreateEngineSuccessOnePolicy) {
   std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
   EXPECT_NE(engine, nullptr)
-      << "Error: Failed to create an AuthorizationEngine with one policy.";
+      << "Error: Failed to create CelAuthorizationEngine with one policy.";
 }
 
-TEST_F(AuthorizationEngineTest, CreateEngineSuccessTwoPolicies) {
+TEST_F(CelAuthorizationEngineTest, CreateEngineSuccessTwoPolicies) {
   std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
   EXPECT_NE(engine, nullptr)
-      << "Error: Failed to create an AuthorizationEngine with two policies.";
+      << "Error: Failed to create CelAuthorizationEngine with two policies.";
 }
 
-TEST_F(AuthorizationEngineTest, CreateEngineFailNoPolicies) {
+TEST_F(CelAuthorizationEngineTest, CreateEngineFailNoPolicies) {
   std::vector<envoy_config_rbac_v3_RBAC*> policies{};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
   EXPECT_EQ(engine, nullptr)
-      << "Error: Created an AuthorizationEngine without policies.";
+      << "Error: Created CelAuthorizationEngine without policies.";
 }
 
-TEST_F(AuthorizationEngineTest, CreateEngineFailTooManyPolicies) {
+TEST_F(CelAuthorizationEngineTest, CreateEngineFailTooManyPolicies) {
   std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_,
                                                    deny_policy_};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
   EXPECT_EQ(engine, nullptr)
-      << "Error: Created an AuthorizationEngine with more than two policies.";
+      << "Error: Created CelAuthorizationEngine with more than two policies.";
 }
 
-TEST_F(AuthorizationEngineTest, CreateEngineFailWrongPolicyOrder) {
+TEST_F(CelAuthorizationEngineTest, CreateEngineFailWrongPolicyOrder) {
   std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_, deny_policy_};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
-  EXPECT_EQ(engine, nullptr) << "Error: Created an AuthorizationEngine with "
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
+  EXPECT_EQ(engine, nullptr) << "Error: Created CelAuthorizationEngine with "
                                 "policies in the wrong order.";
 }
 
index 8bed1a0..0533247 100644 (file)
@@ -415,7 +415,7 @@ typedef struct {
 } expected_md;
 
 typedef struct {
-  grpc_error* expected_error;
+  grpc_error_handle expected_error;
   const expected_md* expected;
   size_t expected_size;
   grpc_credentials_mdelem_array md_array;
@@ -443,11 +443,11 @@ static void check_metadata(const expected_md* expected,
   }
 }
 
-static void check_request_metadata(void* arg, grpc_error* error) {
+static void check_request_metadata(void* arg, grpc_error_handle error) {
   request_metadata_state* state = static_cast<request_metadata_state*>(arg);
   gpr_log(GPR_INFO, "expected_error: %s",
-          grpc_error_string(state->expected_error));
-  gpr_log(GPR_INFO, "actual_error: %s", grpc_error_string(error));
+          grpc_error_std_string(state->expected_error).c_str());
+  gpr_log(GPR_INFO, "actual_error: %s", grpc_error_std_string(error).c_str());
   if (state->expected_error == GRPC_ERROR_NONE) {
     GPR_ASSERT(error == GRPC_ERROR_NONE);
   } else {
@@ -470,7 +470,7 @@ static void check_request_metadata(void* arg, grpc_error* error) {
 }
 
 static request_metadata_state* make_request_metadata_state(
-    grpc_error* expected_error, const expected_md* expected,
+    grpc_error_handle expected_error, const expected_md* expected,
     size_t expected_size) {
   request_metadata_state* state =
       static_cast<request_metadata_state*>(gpr_zalloc(sizeof(*state)));
@@ -487,7 +487,7 @@ static request_metadata_state* make_request_metadata_state(
 static void run_request_metadata_test(grpc_call_credentials* creds,
                                       grpc_auth_metadata_context auth_md_ctx,
                                       request_metadata_state* state) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (creds->get_request_metadata(&state->pollent, auth_md_ctx,
                                   &state->md_array, &state->on_request_metadata,
                                   &error)) {
@@ -1674,13 +1674,13 @@ struct fake_call_creds : public grpc_call_credentials {
                             grpc_auth_metadata_context /*context*/,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* /*on_request_metadata*/,
-                            grpc_error** /*error*/) override {
+                            grpc_error_handle* /*error*/) override {
     grpc_credentials_mdelem_array_add(md_array, phony_md_);
     return true;
   }
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* /*md_array*/,
-                                   grpc_error* /*error*/) override {}
+                                   grpc_error_handle /*error*/) override {}
 
  private:
   grpc_mdelem phony_md_;
@@ -2143,6 +2143,9 @@ static void validate_aws_external_account_creds_token_exchage_request(
   // Check that the body is constructed properly.
   GPR_ASSERT(body != nullptr);
   GPR_ASSERT(body_size != 0);
+  // Check that the regional_cred_verification_url got constructed
+  // with the correct AWS Region ("test_regionz" or "test_region").
+  GPR_ASSERT(strstr(body, "regional_cred_verification_url_test_region"));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   std::string get_url_equivalent =
       absl::StrFormat("%s?%s", "https://foo.com:5555/token", body);
@@ -2213,7 +2216,7 @@ class TestExternalAccountCredentials final
  protected:
   void RetrieveSubjectToken(
       HTTPRequestContext* /*ctx*/, const Options& /*options*/,
-      std::function<void(std::string, grpc_error*)> cb) override {
+      std::function<void(std::string, grpc_error_handle)> cb) override {
     cb("test_subject_token", GRPC_ERROR_NONE);
   }
 };
@@ -2337,10 +2340,11 @@ static void test_external_account_creds_failure_invalid_token_url(void) {
   TestExternalAccountCredentials creds(options, {});
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Invalid token url: invalid_token_url.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(&creds, auth_md_ctx, state);
@@ -2371,11 +2375,12 @@ test_external_account_creds_failure_invalid_service_account_impersonation_url(
   TestExternalAccountCredentials creds(options, {});
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             external_account_creds_httpcli_post_success);
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Invalid service account impersonation url: "
       "invalid_service_account_impersonation_url.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(&creds, auth_md_ctx, state);
@@ -2407,12 +2412,13 @@ test_external_account_creds_failure_token_exchange_response_missing_access_token
   grpc_httpcli_set_override(
       httpcli_get_should_not_be_called,
       external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token);
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Missing or invalid access_token in "
       "{\"not_access_token\":\"not_access_token\",\"expires_in\":3599,\"token_"
       "type\":\"Bearer\"}.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(&creds, auth_md_ctx, state);
@@ -2426,7 +2432,7 @@ static void test_url_external_account_creds_success_format_text(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_url_external_account_creds_options_credential_source_format_text,
       &error);
@@ -2463,7 +2469,7 @@ test_url_external_account_creds_success_with_qurey_params_format_text(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_url_external_account_creds_options_credential_source_with_qurey_params_format_text,
       &error);
@@ -2499,7 +2505,7 @@ static void test_url_external_account_creds_success_format_json(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_url_external_account_creds_options_credential_source_format_json,
       &error);
@@ -2532,7 +2538,7 @@ static void test_url_external_account_creds_success_format_json(void) {
 
 static void
 test_url_external_account_creds_failure_invalid_credential_source_url(void) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_url_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2565,7 +2571,7 @@ static void test_file_external_account_creds_success_format_text(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   char* subject_token_path = write_tmp_jwt_file("test_subject_token");
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       absl::StrFormat(
@@ -2606,7 +2612,7 @@ static void test_file_external_account_creds_success_format_json(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   char* subject_token_path =
       write_tmp_jwt_file("{\"access_token\":\"test_subject_token\"}");
   grpc_core::Json credential_source = grpc_core::Json::Parse(
@@ -2654,7 +2660,7 @@ static void test_file_external_account_creds_failure_file_not_found(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source =
       grpc_core::Json::Parse("{\"file\":\"non_exisiting_file\"}", &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2677,8 +2683,9 @@ static void test_file_external_account_creds_failure_file_not_found(void) {
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to load file");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(creds.get(), auth_md_ctx, state);
@@ -2692,7 +2699,7 @@ static void test_file_external_account_creds_failure_invalid_json_content(
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   char* subject_token_path = write_tmp_jwt_file("not_a_valid_json_file");
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       absl::StrFormat(
@@ -2727,8 +2734,9 @@ static void test_file_external_account_creds_failure_invalid_json_content(
                             httpcli_post_should_not_be_called);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "The content of the file is not a valid json object.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(creds.get(), auth_md_ctx, state);
@@ -2743,7 +2751,7 @@ static void test_aws_external_account_creds_success(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_aws_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2780,7 +2788,7 @@ static void test_aws_external_account_creds_success_path_region_env_keys_url(
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
   gpr_setenv("AWS_REGION", "test_regionz");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_aws_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2811,6 +2819,86 @@ static void test_aws_external_account_creds_success_path_region_env_keys_url(
   gpr_unsetenv("AWS_REGION");
 }
 
+static void
+test_aws_external_account_creds_success_path_default_region_env_keys_url(void) {
+  expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
+  grpc_core::ExecCtx exec_ctx;
+  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
+                                            nullptr, nullptr};
+  gpr_setenv("AWS_DEFAULT_REGION", "test_regionz");
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  grpc_core::Json credential_source = grpc_core::Json::Parse(
+      valid_aws_external_account_creds_options_credential_source, &error);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  grpc_core::ExternalAccountCredentials::Options options = {
+      "external_account",                 // type;
+      "audience",                         // audience;
+      "subject_token_type",               // subject_token_type;
+      "",                                 // service_account_impersonation_url;
+      "https://foo.com:5555/token",       // token_url;
+      "https://foo.com:5555/token_info",  // token_info_url;
+      credential_source,                  // credential_source;
+      "quota_project_id",                 // quota_project_id;
+      "client_id",                        // client_id;
+      "client_secret",                    // client_secret;
+  };
+  auto creds =
+      grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
+  GPR_ASSERT(creds != nullptr);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
+  request_metadata_state* state =
+      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
+  grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
+                            aws_external_account_creds_httpcli_post_success);
+  run_request_metadata_test(creds.get(), auth_md_ctx, state);
+  grpc_core::ExecCtx::Get()->Flush();
+  grpc_httpcli_set_override(nullptr, nullptr);
+  gpr_unsetenv("AWS_DEFAULT_REGION");
+}
+
+static void
+test_aws_external_account_creds_success_path_duplicate_region_env_keys_url(
+    void) {
+  expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
+  grpc_core::ExecCtx exec_ctx;
+  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
+                                            nullptr, nullptr};
+  // Make sure that AWS_REGION gets used over AWS_DEFAULT_REGION
+  gpr_setenv("AWS_REGION", "test_regionz");
+  gpr_setenv("AWS_DEFAULT_REGION", "ERROR_REGION");
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  grpc_core::Json credential_source = grpc_core::Json::Parse(
+      valid_aws_external_account_creds_options_credential_source, &error);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  grpc_core::ExternalAccountCredentials::Options options = {
+      "external_account",                 // type;
+      "audience",                         // audience;
+      "subject_token_type",               // subject_token_type;
+      "",                                 // service_account_impersonation_url;
+      "https://foo.com:5555/token",       // token_url;
+      "https://foo.com:5555/token_info",  // token_info_url;
+      credential_source,                  // credential_source;
+      "quota_project_id",                 // quota_project_id;
+      "client_id",                        // client_id;
+      "client_secret",                    // client_secret;
+  };
+  auto creds =
+      grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
+  GPR_ASSERT(creds != nullptr);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
+  request_metadata_state* state =
+      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
+  grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
+                            aws_external_account_creds_httpcli_post_success);
+  run_request_metadata_test(creds.get(), auth_md_ctx, state);
+  grpc_core::ExecCtx::Get()->Flush();
+  grpc_httpcli_set_override(nullptr, nullptr);
+  gpr_unsetenv("AWS_REGION");
+  gpr_unsetenv("AWS_DEFAULT_REGION");
+}
+
 static void test_aws_external_account_creds_success_path_region_url_keys_env(
     void) {
   expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
@@ -2820,7 +2908,7 @@ static void test_aws_external_account_creds_success_path_region_url_keys_env(
   gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
   gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
   gpr_setenv("AWS_SESSION_TOKEN", "test_token");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_aws_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2863,7 +2951,98 @@ static void test_aws_external_account_creds_success_path_region_env_keys_env(
   gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
   gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
   gpr_setenv("AWS_SESSION_TOKEN", "test_token");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  grpc_core::Json credential_source = grpc_core::Json::Parse(
+      valid_aws_external_account_creds_options_credential_source, &error);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  grpc_core::ExternalAccountCredentials::Options options = {
+      "external_account",                 // type;
+      "audience",                         // audience;
+      "subject_token_type",               // subject_token_type;
+      "",                                 // service_account_impersonation_url;
+      "https://foo.com:5555/token",       // token_url;
+      "https://foo.com:5555/token_info",  // token_info_url;
+      credential_source,                  // credential_source;
+      "quota_project_id",                 // quota_project_id;
+      "client_id",                        // client_id;
+      "client_secret",                    // client_secret;
+  };
+  auto creds =
+      grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
+  GPR_ASSERT(creds != nullptr);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
+  request_metadata_state* state =
+      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
+  grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
+                            aws_external_account_creds_httpcli_post_success);
+  run_request_metadata_test(creds.get(), auth_md_ctx, state);
+  grpc_core::ExecCtx::Get()->Flush();
+  grpc_httpcli_set_override(nullptr, nullptr);
+  gpr_unsetenv("AWS_REGION");
+  gpr_unsetenv("AWS_ACCESS_KEY_ID");
+  gpr_unsetenv("AWS_SECRET_ACCESS_KEY");
+  gpr_unsetenv("AWS_SESSION_TOKEN");
+}
+
+static void
+test_aws_external_account_creds_success_path_default_region_env_keys_env(void) {
+  expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
+  grpc_core::ExecCtx exec_ctx;
+  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
+                                            nullptr, nullptr};
+  gpr_setenv("AWS_DEFAULT_REGION", "test_regionz");
+  gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
+  gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
+  gpr_setenv("AWS_SESSION_TOKEN", "test_token");
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  grpc_core::Json credential_source = grpc_core::Json::Parse(
+      valid_aws_external_account_creds_options_credential_source, &error);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  grpc_core::ExternalAccountCredentials::Options options = {
+      "external_account",                 // type;
+      "audience",                         // audience;
+      "subject_token_type",               // subject_token_type;
+      "",                                 // service_account_impersonation_url;
+      "https://foo.com:5555/token",       // token_url;
+      "https://foo.com:5555/token_info",  // token_info_url;
+      credential_source,                  // credential_source;
+      "quota_project_id",                 // quota_project_id;
+      "client_id",                        // client_id;
+      "client_secret",                    // client_secret;
+  };
+  auto creds =
+      grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
+  GPR_ASSERT(creds != nullptr);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
+  request_metadata_state* state =
+      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
+  grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
+                            aws_external_account_creds_httpcli_post_success);
+  run_request_metadata_test(creds.get(), auth_md_ctx, state);
+  grpc_core::ExecCtx::Get()->Flush();
+  grpc_httpcli_set_override(nullptr, nullptr);
+  gpr_unsetenv("AWS_DEFAULT_REGION");
+  gpr_unsetenv("AWS_ACCESS_KEY_ID");
+  gpr_unsetenv("AWS_SECRET_ACCESS_KEY");
+  gpr_unsetenv("AWS_SESSION_TOKEN");
+}
+
+static void
+test_aws_external_account_creds_success_path_duplicate_region_env_keys_env(
+    void) {
+  expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
+  grpc_core::ExecCtx exec_ctx;
+  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
+                                            nullptr, nullptr};
+  // Make sure that AWS_REGION gets used over AWS_DEFAULT_REGION
+  gpr_setenv("AWS_REGION", "test_regionz");
+  gpr_setenv("AWS_DEFAULT_REGION", "ERROR_REGION");
+  gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
+  gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
+  gpr_setenv("AWS_SESSION_TOKEN", "test_token");
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_aws_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2892,6 +3071,7 @@ static void test_aws_external_account_creds_success_path_region_env_keys_env(
   grpc_core::ExecCtx::Get()->Flush();
   grpc_httpcli_set_override(nullptr, nullptr);
   gpr_unsetenv("AWS_REGION");
+  gpr_unsetenv("AWS_DEFAULT_REGION");
   gpr_unsetenv("AWS_ACCESS_KEY_ID");
   gpr_unsetenv("AWS_SECRET_ACCESS_KEY");
   gpr_unsetenv("AWS_SESSION_TOKEN");
@@ -2899,7 +3079,7 @@ static void test_aws_external_account_creds_success_path_region_env_keys_env(
 
 static void test_aws_external_account_creds_failure_unmatched_environment_id(
     void) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_unmatched_environment_id,
       &error);
@@ -2932,7 +3112,7 @@ static void test_aws_external_account_creds_failure_invalid_region_url(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_invalid_region_url,
       &error);
@@ -2956,8 +3136,9 @@ static void test_aws_external_account_creds_failure_invalid_region_url(void) {
   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Invalid region url: invalid_region_url.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
@@ -2972,7 +3153,7 @@ static void test_aws_external_account_creds_failure_invalid_url(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_invalid_url,
       &error);
@@ -2995,8 +3176,9 @@ static void test_aws_external_account_creds_failure_invalid_url(void) {
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid url: invalid_url.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
@@ -3011,7 +3193,7 @@ static void test_aws_external_account_creds_failure_missing_role_name(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_missing_role_name,
       &error);
@@ -3035,8 +3217,9 @@ static void test_aws_external_account_creds_failure_missing_role_name(void) {
   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Missing role name when retrieving signing keys.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
@@ -3053,7 +3236,7 @@ test_aws_external_account_creds_failure_invalid_regional_cred_verification_url(
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_invalid_regional_cred_verification_url,
       &error);
@@ -3077,8 +3260,9 @@ test_aws_external_account_creds_failure_invalid_regional_cred_verification_url(
   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Creating aws request signer failed.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
@@ -3235,8 +3419,12 @@ int main(int argc, char** argv) {
   test_file_external_account_creds_failure_invalid_json_content();
   test_aws_external_account_creds_success();
   test_aws_external_account_creds_success_path_region_env_keys_url();
+  test_aws_external_account_creds_success_path_default_region_env_keys_url();
+  test_aws_external_account_creds_success_path_duplicate_region_env_keys_url();
   test_aws_external_account_creds_success_path_region_url_keys_env();
   test_aws_external_account_creds_success_path_region_env_keys_env();
+  test_aws_external_account_creds_success_path_default_region_env_keys_env();
+  test_aws_external_account_creds_success_path_duplicate_region_env_keys_env();
   test_aws_external_account_creds_failure_unmatched_environment_id();
   test_aws_external_account_creds_failure_invalid_region_url();
   test_aws_external_account_creds_failure_invalid_url();
index 2ddbdde..de98537 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2020 gRPC authors.
+// Copyright 2021 gRPC authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include "absl/strings/string_view.h"
-
 #include "src/core/lib/security/authorization/evaluate_args.h"
-#include "test/core/util/eval_args_mock_endpoint.h"
+#include "test/core/util/evaluate_args_test_util.h"
 #include "test/core/util/test_config.h"
 
 namespace grpc_core {
 
 class EvaluateArgsTest : public ::testing::Test {
  protected:
-  void SetUp() override {
-    local_address_ = "255.255.255.255";
-    peer_address_ = "128.128.128.128";
-    local_port_ = 413;
-    peer_port_ = 314;
-    endpoint_ = CreateEvalArgsMockEndpoint(local_address_.c_str(), local_port_,
-                                           peer_address_.c_str(), peer_port_);
-    evaluate_args_ =
-        absl::make_unique<EvaluateArgs>(nullptr, nullptr, endpoint_);
-  }
-  void TearDown() override { grpc_endpoint_destroy(endpoint_); }
-  grpc_endpoint* endpoint_;
-  std::unique_ptr<EvaluateArgs> evaluate_args_;
-  std::string local_address_;
-  std::string peer_address_;
-  int local_port_;
-  int peer_port_;
+  EvaluateArgsTestUtil util_;
 };
 
-TEST_F(EvaluateArgsTest, TestEvaluateArgsLocalAddress) {
-  absl::string_view src_address = evaluate_args_->GetLocalAddress();
-  EXPECT_EQ(src_address, local_address_);
+TEST_F(EvaluateArgsTest, EmptyMetadata) {
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetPath(), nullptr);
+  EXPECT_EQ(args.GetMethod(), nullptr);
+  EXPECT_EQ(args.GetHost(), nullptr);
+  EXPECT_THAT(args.GetHeaders(), ::testing::ElementsAre());
+  EXPECT_EQ(args.GetHeaderValue("some_key", nullptr), absl::nullopt);
 }
 
-TEST_F(EvaluateArgsTest, TestEvaluateArgsLocalPort) {
-  int src_port = evaluate_args_->GetLocalPort();
-  EXPECT_EQ(src_port, local_port_);
+TEST_F(EvaluateArgsTest, GetPathSuccess) {
+  util_.AddPairToMetadata(":path", "/expected/path");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetPath(), "/expected/path");
 }
 
-TEST_F(EvaluateArgsTest, TestEvaluateArgsPeerAddress) {
-  absl::string_view dest_address = evaluate_args_->GetPeerAddress();
-  EXPECT_EQ(dest_address, peer_address_);
+TEST_F(EvaluateArgsTest, GetHostSuccess) {
+  util_.AddPairToMetadata("host", "host123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetHost(), "host123");
 }
 
-TEST_F(EvaluateArgsTest, TestEvaluateArgsPeerPort) {
-  int dest_port = evaluate_args_->GetPeerPort();
-  EXPECT_EQ(dest_port, peer_port_);
+TEST_F(EvaluateArgsTest, GetMethodSuccess) {
+  util_.AddPairToMetadata(":method", "GET");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetMethod(), "GET");
 }
 
-TEST(EvaluateArgsMetadataTest, HandlesNullMetadata) {
-  EvaluateArgs eval_args(nullptr, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetPath(), nullptr);
-  EXPECT_EQ(eval_args.GetMethod(), nullptr);
-  EXPECT_EQ(eval_args.GetHost(), nullptr);
-  EXPECT_THAT(eval_args.GetHeaders(), ::testing::ElementsAre());
-  EXPECT_EQ(eval_args.GetHeaderValue("some_key", nullptr), absl::nullopt);
+TEST_F(EvaluateArgsTest, GetHeadersSuccess) {
+  util_.AddPairToMetadata("host", "host123");
+  util_.AddPairToMetadata(":path", "/expected/path");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_THAT(args.GetHeaders(),
+              ::testing::UnorderedElementsAre(
+                  ::testing::Pair("host", "host123"),
+                  ::testing::Pair(":path", "/expected/path")));
 }
 
-TEST(EvaluateArgsMetadataTest, HandlesEmptyMetadata) {
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetPath(), nullptr);
-  EXPECT_EQ(eval_args.GetMethod(), nullptr);
-  EXPECT_EQ(eval_args.GetHost(), nullptr);
-  EXPECT_THAT(eval_args.GetHeaders(), ::testing::ElementsAre());
-  EXPECT_EQ(eval_args.GetHeaderValue("some_key", nullptr), absl::nullopt);
-  grpc_metadata_batch_destroy(&metadata);
+TEST_F(EvaluateArgsTest, GetHeaderValueSuccess) {
+  util_.AddPairToMetadata("key123", "value123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  std::string concatenated_value;
+  absl::optional<absl::string_view> value =
+      args.GetHeaderValue("key123", &concatenated_value);
+  ASSERT_TRUE(value.has_value());
+  EXPECT_EQ(value.value(), "value123");
 }
 
-TEST(EvaluateArgsMetadataTest, GetPathSuccess) {
-  grpc_init();
-  const char* kPath = "/some/path";
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  grpc_slice fake_val = grpc_slice_intern(grpc_slice_from_static_string(kPath));
-  grpc_mdelem fake_val_md = grpc_mdelem_from_slices(GRPC_MDSTR_PATH, fake_val);
-  grpc_linked_mdelem storage;
-  storage.md = fake_val_md;
-  ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage),
-            GRPC_ERROR_NONE);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetPath(), kPath);
-  grpc_metadata_batch_destroy(&metadata);
-  grpc_shutdown();
+TEST_F(EvaluateArgsTest, TestIpv4LocalAddressAndPort) {
+  util_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetLocalAddress(), "255.255.255.255");
+  EXPECT_EQ(args.GetLocalPort(), 123);
 }
 
-TEST(EvaluateArgsMetadataTest, GetHostSuccess) {
-  grpc_init();
-  const char* kHost = "host";
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  grpc_slice fake_val = grpc_slice_intern(grpc_slice_from_static_string(kHost));
-  grpc_mdelem fake_val_md = grpc_mdelem_from_slices(GRPC_MDSTR_HOST, fake_val);
-  grpc_linked_mdelem storage;
-  storage.md = fake_val_md;
-  ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage),
-            GRPC_ERROR_NONE);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetHost(), kHost);
-  grpc_metadata_batch_destroy(&metadata);
-  grpc_shutdown();
+TEST_F(EvaluateArgsTest, TestIpv4PeerAddressAndPort) {
+  util_.SetPeerEndpoint("ipv4:128.128.128.128:321");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetPeerAddress(), "128.128.128.128");
+  EXPECT_EQ(args.GetPeerPort(), 321);
 }
 
-TEST(EvaluateArgsMetadataTest, GetMethodSuccess) {
-  grpc_init();
-  const char* kMethod = "GET";
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  grpc_slice fake_val =
-      grpc_slice_intern(grpc_slice_from_static_string(kMethod));
-  grpc_mdelem fake_val_md =
-      grpc_mdelem_from_slices(GRPC_MDSTR_METHOD, fake_val);
-  grpc_linked_mdelem storage;
-  storage.md = fake_val_md;
-  ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage),
-            GRPC_ERROR_NONE);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetMethod(), kMethod);
-  grpc_metadata_batch_destroy(&metadata);
-  grpc_shutdown();
+TEST_F(EvaluateArgsTest, TestIpv6LocalAddressAndPort) {
+  util_.SetLocalEndpoint("ipv6:[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:456");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetLocalAddress(), "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+  EXPECT_EQ(args.GetLocalPort(), 456);
 }
 
-TEST(EvaluateArgsMetadataTest, GetHeadersSuccess) {
-  grpc_init();
-  const char* kPath = "/some/path";
-  const char* kHost = "host";
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  grpc_slice fake_path =
-      grpc_slice_intern(grpc_slice_from_static_string(kPath));
-  grpc_mdelem fake_path_md =
-      grpc_mdelem_from_slices(GRPC_MDSTR_PATH, fake_path);
-  grpc_linked_mdelem storage;
-  storage.md = fake_path_md;
-  ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage, GRPC_BATCH_PATH),
-            GRPC_ERROR_NONE);
-  grpc_slice fake_host =
-      grpc_slice_intern(grpc_slice_from_static_string(kHost));
-  grpc_mdelem fake_host_md =
-      grpc_mdelem_from_slices(GRPC_MDSTR_HOST, fake_host);
-  grpc_linked_mdelem storage2;
-  storage2.md = fake_host_md;
-  ASSERT_EQ(
-      grpc_metadata_batch_link_tail(&metadata, &storage2, GRPC_BATCH_HOST),
-      GRPC_ERROR_NONE);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_THAT(
-      eval_args.GetHeaders(),
-      ::testing::UnorderedElementsAre(
-          ::testing::Pair(StringViewFromSlice(GRPC_MDSTR_HOST), kHost),
-          ::testing::Pair(StringViewFromSlice(GRPC_MDSTR_PATH), kPath)));
-  grpc_metadata_batch_destroy(&metadata);
-  grpc_shutdown();
+TEST_F(EvaluateArgsTest, TestIpv6PeerAddressAndPort) {
+  util_.SetPeerEndpoint("ipv6:[2001:db8::1]:654");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetPeerAddress(), "2001:db8::1");
+  EXPECT_EQ(args.GetPeerPort(), 654);
 }
 
-TEST(EvaluateArgsMetadataTest, GetHeaderValueSuccess) {
-  grpc_init();
-  const char* kKey = "some_key";
-  const char* kValue = "some_value";
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  grpc_linked_mdelem storage;
-  storage.md = grpc_mdelem_from_slices(
-      grpc_slice_intern(grpc_slice_from_static_string(kKey)),
-      grpc_slice_intern(grpc_slice_from_static_string(kValue)));
-  ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage),
-            GRPC_ERROR_NONE);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  std::string concatenated_value;
-  absl::optional<absl::string_view> value =
-      eval_args.GetHeaderValue(kKey, &concatenated_value);
-  ASSERT_TRUE(value.has_value());
-  EXPECT_EQ(value.value(), kValue);
-  grpc_metadata_batch_destroy(&metadata);
-  grpc_shutdown();
+TEST_F(EvaluateArgsTest, EmptyAuthContext) {
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_TRUE(args.GetTransportSecurityType().empty());
+  EXPECT_TRUE(args.GetSpiffeId().empty());
+  EXPECT_TRUE(args.GetCommonName().empty());
 }
 
-TEST(EvaluateArgsAuthContextTest, HandlesNullAuthContext) {
-  EvaluateArgs eval_args(nullptr, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetSpiffeId(), nullptr);
-  EXPECT_EQ(eval_args.GetCertServerName(), nullptr);
+TEST_F(EvaluateArgsTest, GetTransportSecurityTypeSuccessOneProperty) {
+  util_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 "ssl");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetTransportSecurityType(), "ssl");
 }
 
-TEST(EvaluateArgsAuthContextTest, HandlesEmptyAuthCtx) {
-  grpc_auth_context auth_context(nullptr);
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetSpiffeId(), nullptr);
-  EXPECT_EQ(eval_args.GetCertServerName(), nullptr);
+TEST_F(EvaluateArgsTest, GetTransportSecurityTypeFailDuplicateProperty) {
+  util_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 "type1");
+  util_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 "type2");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_TRUE(args.GetTransportSecurityType().empty());
 }
 
-TEST(EvaluateArgsAuthContextTest, GetSpiffeIdSuccessOneProperty) {
-  grpc_auth_context auth_context(nullptr);
-  const char* kId = "spiffeid";
-  auth_context.add_cstring_property(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, kId);
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetSpiffeId(), kId);
+TEST_F(EvaluateArgsTest, GetSpiffeIdSuccessOneProperty) {
+  util_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetSpiffeId(), "id123");
 }
 
-TEST(EvaluateArgsAuthContextTest, GetSpiffeIdFailDuplicateProperty) {
-  grpc_auth_context auth_context(nullptr);
-  auth_context.add_cstring_property(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id1");
-  auth_context.add_cstring_property(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id2");
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetSpiffeId(), nullptr);
+TEST_F(EvaluateArgsTest, GetSpiffeIdFailDuplicateProperty) {
+  util_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id123");
+  util_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id456");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_TRUE(args.GetSpiffeId().empty());
 }
 
-TEST(EvaluateArgsAuthContextTest, GetCertServerNameSuccessOneProperty) {
-  grpc_auth_context auth_context(nullptr);
-  const char* kServer = "server";
-  auth_context.add_cstring_property(GRPC_X509_CN_PROPERTY_NAME, kServer);
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetCertServerName(), kServer);
+TEST_F(EvaluateArgsTest, GetCommonNameSuccessOneProperty) {
+  util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetCommonName(), "server123");
 }
 
-TEST(EvaluateArgsAuthContextTest, GetCertServerNameFailDuplicateProperty) {
-  grpc_auth_context auth_context(nullptr);
-  auth_context.add_cstring_property(GRPC_X509_CN_PROPERTY_NAME, "server1");
-  auth_context.add_cstring_property(GRPC_X509_CN_PROPERTY_NAME, "server2");
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetCertServerName(), nullptr);
+TEST_F(EvaluateArgsTest, GetCommonNameFailDuplicateProperty) {
+  util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server123");
+  util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server456");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_TRUE(args.GetCommonName().empty());
 }
 
 }  // namespace grpc_core
@@ -245,5 +157,8 @@ TEST(EvaluateArgsAuthContextTest, GetCertServerNameFailDuplicateProperty) {
 int main(int argc, char** argv) {
   grpc::testing::TestEnvironment env(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  grpc_init();
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return ret;
 }
diff --git a/test/core/security/grpc_authorization_engine_test.cc b/test/core/security/grpc_authorization_engine_test.cc
new file mode 100644 (file)
index 0000000..a2b5e11
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright 2021 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <grpc/support/port_platform.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "src/core/lib/security/authorization/grpc_authorization_engine.h"
+
+namespace grpc_core {
+
+TEST(GrpcAuthorizationEngineTest, AllowEngineWithMatchingPolicy) {
+  Rbac::Policy policy1(
+      Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true));
+  Rbac::Policy policy2((Rbac::Permission(Rbac::Permission::RuleType::kAny)),
+                       (Rbac::Principal(Rbac::Principal::RuleType::kAny)));
+  std::map<std::string, Rbac::Policy> policies;
+  policies["policy1"] = std::move(policy1);
+  policies["policy2"] = std::move(policy2);
+  Rbac rbac(Rbac::Action::kAllow, std::move(policies));
+  GrpcAuthorizationEngine engine(std::move(rbac));
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
+  EXPECT_EQ(decision.matching_policy_name, "policy2");
+}
+
+TEST(GrpcAuthorizationEngineTest, AllowEngineWithNoMatchingPolicy) {
+  Rbac::Policy policy1(
+      Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true));
+  std::map<std::string, Rbac::Policy> policies;
+  policies["policy1"] = std::move(policy1);
+  Rbac rbac(Rbac::Action::kAllow, std::move(policies));
+  GrpcAuthorizationEngine engine(std::move(rbac));
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
+  EXPECT_TRUE(decision.matching_policy_name.empty());
+}
+
+TEST(GrpcAuthorizationEngineTest, AllowEngineWithEmptyPolicies) {
+  GrpcAuthorizationEngine engine(Rbac::Action::kAllow);
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
+  EXPECT_TRUE(decision.matching_policy_name.empty());
+}
+
+TEST(GrpcAuthorizationEngineTest, DenyEngineWithMatchingPolicy) {
+  Rbac::Policy policy1(
+      Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true));
+  Rbac::Policy policy2((Rbac::Permission(Rbac::Permission::RuleType::kAny)),
+                       (Rbac::Principal(Rbac::Principal::RuleType::kAny)));
+  std::map<std::string, Rbac::Policy> policies;
+  policies["policy1"] = std::move(policy1);
+  policies["policy2"] = std::move(policy2);
+  Rbac rbac(Rbac::Action::kDeny, std::move(policies));
+  GrpcAuthorizationEngine engine(std::move(rbac));
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
+  EXPECT_EQ(decision.matching_policy_name, "policy2");
+}
+
+TEST(GrpcAuthorizationEngineTest, DenyEngineWithNoMatchingPolicy) {
+  Rbac::Policy policy1(
+      Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true));
+  std::map<std::string, Rbac::Policy> policies;
+  policies["policy1"] = std::move(policy1);
+  Rbac rbac(Rbac::Action::kDeny, std::move(policies));
+  GrpcAuthorizationEngine engine(std::move(rbac));
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
+  EXPECT_TRUE(decision.matching_policy_name.empty());
+}
+
+TEST(GrpcAuthorizationEngineTest, DenyEngineWithEmptyPolicies) {
+  GrpcAuthorizationEngine engine(Rbac::Action::kDeny);
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
+  EXPECT_TRUE(decision.matching_policy_name.empty());
+}
+
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
index b0a0445..92123a1 100644 (file)
@@ -129,8 +129,8 @@ class GrpcTlsCertificateDistributorTest : public ::testing::Test {
                                              std::move(updated_identity));
     }
 
-    void OnError(grpc_error* root_cert_error,
-                 grpc_error* identity_cert_error) override {
+    void OnError(grpc_error_handle root_cert_error,
+                 grpc_error_handle identity_cert_error) override {
       GPR_ASSERT(root_cert_error != GRPC_ERROR_NONE ||
                  identity_cert_error != GRPC_ERROR_NONE);
       std::string root_error_str;
index 5055357..9d67556 100644 (file)
@@ -131,8 +131,8 @@ class GrpcTlsCertificateProviderTest : public ::testing::Test {
                                              std::move(updated_identity));
     }
 
-    void OnError(grpc_error* root_cert_error,
-                 grpc_error* identity_cert_error) override {
+    void OnError(grpc_error_handle root_cert_error,
+                 grpc_error_handle identity_cert_error) override {
       MutexLock lock(&state_->mu);
       GPR_ASSERT(root_cert_error != GRPC_ERROR_NONE ||
                  identity_cert_error != GRPC_ERROR_NONE);
index 6b032bb..1ded259 100644 (file)
@@ -215,11 +215,12 @@ static Json parse_json_part_from_jwt(const char* str, size_t len) {
   grpc_slice slice = grpc_base64_decode(b64, 1);
   gpr_free(b64);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(slice));
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   absl::string_view string = grpc_core::StringViewFromSlice(slice);
   Json json = Json::Parse(string, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
   }
   grpc_slice_unref(slice);
index 71178cb..21ed63f 100644 (file)
@@ -207,10 +207,11 @@ static void test_jwt_issuer_email_domain(void) {
 
 static void test_claims_success(void) {
   grpc_jwt_claims* claims;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(claims_without_time_constraint, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
@@ -229,10 +230,11 @@ static void test_claims_success(void) {
 
 static void test_expired_claims_failure(void) {
   grpc_jwt_claims* claims;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(expired_claims, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
@@ -257,10 +259,11 @@ static void test_expired_claims_failure(void) {
 }
 
 static void test_invalid_claims_failure(void) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(invalid_claims, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
@@ -270,10 +273,11 @@ static void test_invalid_claims_failure(void) {
 
 static void test_bad_audience_claims_failure(void) {
   grpc_jwt_claims* claims;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(claims_without_time_constraint, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
@@ -287,10 +291,11 @@ static void test_bad_audience_claims_failure(void) {
 
 static void test_bad_subject_claims_failure(void) {
   grpc_jwt_claims* claims;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(claims_with_bad_subject, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
index 25a0978..0bacd16 100644 (file)
@@ -20,7 +20,7 @@ namespace grpc_core {
 
 TEST(StringMatcherTest, ExactMatchCaseSensitive) {
   auto string_matcher =
-      StringMatcher::Create(StringMatcher::Type::EXACT,
+      StringMatcher::Create(StringMatcher::Type::kExact,
                             /*matcher=*/"exact", /*case_sensitive=*/true);
   ASSERT_TRUE(string_matcher.ok());
   EXPECT_TRUE(string_matcher->Match("exact"));
@@ -30,7 +30,7 @@ TEST(StringMatcherTest, ExactMatchCaseSensitive) {
 
 TEST(StringMatcherTest, ExactMatchCaseInsensitive) {
   auto string_matcher =
-      StringMatcher::Create(StringMatcher::Type::EXACT,
+      StringMatcher::Create(StringMatcher::Type::kExact,
                             /*matcher=*/"exact", /*case_sensitive=*/false);
   ASSERT_TRUE(string_matcher.ok());
   EXPECT_TRUE(string_matcher->Match("Exact"));
@@ -38,7 +38,7 @@ TEST(StringMatcherTest, ExactMatchCaseInsensitive) {
 }
 
 TEST(StringMatcherTest, PrefixMatchCaseSensitive) {
-  auto string_matcher = StringMatcher::Create(StringMatcher::Type::PREFIX,
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kPrefix,
                                               /*matcher=*/"prefix",
                                               /*case_sensitive=*/true);
   ASSERT_TRUE(string_matcher.ok());
@@ -49,7 +49,7 @@ TEST(StringMatcherTest, PrefixMatchCaseSensitive) {
 }
 
 TEST(StringMatcherTest, PrefixMatchCaseInsensitive) {
-  auto string_matcher = StringMatcher::Create(StringMatcher::Type::PREFIX,
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kPrefix,
                                               /*matcher=*/"prefix",
                                               /*case_sensitive=*/false);
   ASSERT_TRUE(string_matcher.ok());
@@ -59,7 +59,7 @@ TEST(StringMatcherTest, PrefixMatchCaseInsensitive) {
 }
 
 TEST(StringMatcherTest, SuffixMatchCaseSensitive) {
-  auto string_matcher = StringMatcher::Create(StringMatcher::Type::SUFFIX,
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSuffix,
                                               /*matcher=*/"suffix",
                                               /*case_sensitive=*/true);
   ASSERT_TRUE(string_matcher.ok());
@@ -70,7 +70,7 @@ TEST(StringMatcherTest, SuffixMatchCaseSensitive) {
 }
 
 TEST(StringMatcherTest, SuffixMatchCaseInSensitive) {
-  auto string_matcher = StringMatcher::Create(StringMatcher::Type::SUFFIX,
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSuffix,
                                               /*matcher=*/"suffix",
                                               /*case_sensitive=*/false);
   ASSERT_TRUE(string_matcher.ok());
@@ -80,7 +80,7 @@ TEST(StringMatcherTest, SuffixMatchCaseInSensitive) {
 }
 
 TEST(StringMatcherTest, InvalidRegex) {
-  auto string_matcher = StringMatcher::Create(StringMatcher::Type::SAFE_REGEX,
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSafeRegex,
                                               /*matcher=*/"a[b-a]",
                                               /*case_sensitive=*/true);
   EXPECT_FALSE(string_matcher.ok());
@@ -90,7 +90,7 @@ TEST(StringMatcherTest, InvalidRegex) {
 }
 
 TEST(StringMatcherTest, SafeRegexMatchCaseSensitive) {
-  auto string_matcher = StringMatcher::Create(StringMatcher::Type::SAFE_REGEX,
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSafeRegex,
                                               /*matcher=*/"regex.*",
                                               /*case_sensitive=*/true);
   ASSERT_TRUE(string_matcher.ok());
@@ -101,7 +101,7 @@ TEST(StringMatcherTest, SafeRegexMatchCaseSensitive) {
 }
 
 TEST(StringMatcherTest, SafeRegexMatchCaseInSensitive) {
-  auto string_matcher = StringMatcher::Create(StringMatcher::Type::SAFE_REGEX,
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSafeRegex,
                                               /*matcher=*/"regex.*",
                                               /*case_sensitive=*/false);
   ASSERT_TRUE(string_matcher.ok());
@@ -112,7 +112,7 @@ TEST(StringMatcherTest, SafeRegexMatchCaseInSensitive) {
 }
 
 TEST(StringMatcherTest, ContainsMatchCaseSensitive) {
-  auto string_matcher = StringMatcher::Create(StringMatcher::Type::CONTAINS,
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kContains,
                                               /*matcher=*/"contains",
                                               /*case_sensitive=*/true);
   ASSERT_TRUE(string_matcher.ok());
@@ -123,7 +123,7 @@ TEST(StringMatcherTest, ContainsMatchCaseSensitive) {
 }
 
 TEST(StringMatcherTest, ContainsMatchCaseInSensitive) {
-  auto string_matcher = StringMatcher::Create(StringMatcher::Type::CONTAINS,
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kContains,
                                               /*matcher=*/"contains",
                                               /*case_sensitive=*/false);
   ASSERT_TRUE(string_matcher.ok());
@@ -134,7 +134,7 @@ TEST(StringMatcherTest, ContainsMatchCaseInSensitive) {
 
 TEST(HeaderMatcherTest, StringMatcher) {
   auto header_matcher =
-      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::EXACT,
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kExact,
                             /*matcher=*/"exact");
   ASSERT_TRUE(header_matcher.ok());
   EXPECT_TRUE(header_matcher->Match("exact"));
@@ -144,7 +144,7 @@ TEST(HeaderMatcherTest, StringMatcher) {
 
 TEST(HeaderMatcherTest, StringMatcherWithInvertMatch) {
   auto header_matcher =
-      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::EXACT,
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kExact,
                             /*matcher=*/"exact",
                             /*range_start=*/0, /*range_end=*/0,
                             /*present_match=*/false, /*invert_match=*/true);
@@ -156,7 +156,7 @@ TEST(HeaderMatcherTest, StringMatcherWithInvertMatch) {
 
 TEST(HeaderMatcherTest, InvalidRegex) {
   auto header_matcher =
-      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::SAFE_REGEX,
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kSafeRegex,
                             /*matcher=*/"a[b-a]",
                             /*range_start=*/0, /*range_end=*/0,
                             /*present_match=*/false, /*invert_match=*/true);
@@ -168,7 +168,7 @@ TEST(HeaderMatcherTest, InvalidRegex) {
 
 TEST(HeaderMatcherTest, RangeMatcherValidRange) {
   auto header_matcher =
-      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::RANGE,
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kRange,
                             /*matcher=*/"", /*range_start=*/10,
                             /*range_end*/ 20);
   ASSERT_TRUE(header_matcher.ok());
@@ -180,7 +180,7 @@ TEST(HeaderMatcherTest, RangeMatcherValidRange) {
 
 TEST(HeaderMatcherTest, RangeMatcherInvalidRange) {
   auto header_matcher =
-      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::RANGE,
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kRange,
                             /*matcher=*/"", /*range_start=*/20,
                             /*range_end*/ 10);
   EXPECT_FALSE(header_matcher.ok());
@@ -192,7 +192,7 @@ TEST(HeaderMatcherTest, RangeMatcherInvalidRange) {
 
 TEST(HeaderMatcherTest, PresentMatcherTrue) {
   auto header_matcher =
-      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::PRESENT,
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kPresent,
                             /*matcher=*/"", /*range_start=*/0,
                             /*range_end=*/0, /*present_match=*/true);
   ASSERT_TRUE(header_matcher.ok());
@@ -202,7 +202,7 @@ TEST(HeaderMatcherTest, PresentMatcherTrue) {
 
 TEST(HeaderMatcherTest, PresentMatcherFalse) {
   auto header_matcher =
-      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::PRESENT,
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kPresent,
                             /*matcher=*/"", /*range_start=*/0,
                             /*range_end=*/0, /*present_match=*/false);
   ASSERT_TRUE(header_matcher.ok());
index 0885a1a..536696b 100644 (file)
@@ -40,12 +40,13 @@ typedef struct {
   grpc_closure closure;
 } oauth2_request;
 
-static void on_oauth2_response(void* arg, grpc_error* error) {
+static void on_oauth2_response(void* arg, grpc_error_handle error) {
   oauth2_request* request = static_cast<oauth2_request*>(arg);
   char* token = nullptr;
   grpc_slice token_slice;
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "Fetching token failed: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "Fetching token failed: %s",
+            grpc_error_std_string(error).c_str());
   } else {
     GPR_ASSERT(request->md_array.size == 1);
     token_slice = GRPC_MDVALUE(request->md_array.md[0]);
@@ -64,7 +65,7 @@ static void on_oauth2_response(void* arg, grpc_error* error) {
   gpr_mu_unlock(request->mu);
 }
 
-static void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
+static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 char* grpc_test_fetch_oauth2_token_with_credentials(
     grpc_call_credentials* creds) {
@@ -86,7 +87,7 @@ char* grpc_test_fetch_oauth2_token_with_credentials(
   GRPC_CLOSURE_INIT(&request.closure, on_oauth2_response, &request,
                     grpc_schedule_on_exec_ctx);
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (creds->get_request_metadata(&request.pops, null_ctx, &request.md_array,
                                   &request.closure, &error)) {
     // Synchronous result; invoke callback directly.
index 398c58c..0d6c7b7 100644 (file)
@@ -41,10 +41,11 @@ typedef struct {
   grpc_closure on_request_metadata;
 } synchronizer;
 
-static void on_metadata_response(void* arg, grpc_error* error) {
+static void on_metadata_response(void* arg, grpc_error_handle error) {
   synchronizer* sync = static_cast<synchronizer*>(arg);
   if (error != GRPC_ERROR_NONE) {
-    fprintf(stderr, "Fetching token failed: %s\n", grpc_error_string(error));
+    fprintf(stderr, "Fetching token failed: %s\n",
+            grpc_error_std_string(error).c_str());
     fflush(stderr);
   } else {
     char* token;
@@ -70,7 +71,7 @@ int main(int argc, char** argv) {
   grpc_auth_metadata_context context;
   gpr_cmdline* cl = gpr_cmdline_create("print_google_default_creds_token");
   grpc_pollset* pollset = nullptr;
-  grpc_error* error = nullptr;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   gpr_cmdline_add_string(cl, "service_url",
                          "Service URL for the token request.", &service_url);
   gpr_cmdline_parse(cl, argc, argv);
index f036233..337f471 100644 (file)
@@ -23,20 +23,20 @@ namespace {
 
 MATCHER_P2(EqualsPrincipalName, expected_matcher_type, expected_matcher_value,
            "") {
-  return arg->type == Rbac::Principal::RuleType::PRINCIPAL_NAME &&
+  return arg->type == Rbac::Principal::RuleType::kPrincipalName &&
          arg->string_matcher.type() == expected_matcher_type &&
          arg->string_matcher.string_matcher() == expected_matcher_value;
 }
 
 MATCHER_P2(EqualsPath, expected_matcher_type, expected_matcher_value, "") {
-  return arg->type == Rbac::Permission::RuleType::PATH &&
+  return arg->type == Rbac::Permission::RuleType::kPath &&
          arg->string_matcher.type() == expected_matcher_type &&
          arg->string_matcher.string_matcher() == expected_matcher_value;
 }
 
 MATCHER_P3(EqualsHeader, expected_name, expected_matcher_type,
            expected_matcher_value, "") {
-  return arg->type == Rbac::Permission::RuleType::HEADER &&
+  return arg->type == Rbac::Permission::RuleType::kHeader &&
          arg->header_matcher.name() == expected_name &&
          arg->header_matcher.type() == expected_matcher_type &&
          arg->header_matcher.string_matcher() == expected_matcher_value;
@@ -96,7 +96,7 @@ TEST(GenerateRbacPoliciesTest, MissingDenyRules) {
       "}";
   auto rbac_policies = GenerateRbacPolicies(authz_policy);
   ASSERT_TRUE(rbac_policies.ok());
-  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
   EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty());
 }
 
@@ -176,19 +176,20 @@ TEST(GenerateRbacPoliciesTest, MissingSourceAndRequest) {
       "}";
   auto rbac_policies = GenerateRbacPolicies(authz_policy);
   ASSERT_TRUE(rbac_policies.ok());
-  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
-  EXPECT_THAT(rbac_policies.value().allow_policy.policies,
-              ::testing::ElementsAre(::testing::Pair(
-                  "authz_allow_policy",
-                  ::testing::AllOf(
-                      ::testing::Field(
-                          &Rbac::Policy::permissions,
-                          ::testing::Field(&Rbac::Permission::type,
-                                           Rbac::Permission::RuleType::ANY)),
-                      ::testing::Field(
-                          &Rbac::Policy::principals,
-                          ::testing::Field(&Rbac::Principal::type,
-                                           Rbac::Principal::RuleType::ANY))))));
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
+  EXPECT_THAT(
+      rbac_policies.value().allow_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_allow_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
+                  ::testing::Field(&Rbac::Permission::type,
+                                   Rbac::Permission::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::Field(&Rbac::Principal::type,
+                                   Rbac::Principal::RuleType::kAny))))));
 }
 
 TEST(GenerateRbacPoliciesTest, EmptySourceAndRequest) {
@@ -205,19 +206,20 @@ TEST(GenerateRbacPoliciesTest, EmptySourceAndRequest) {
       "}";
   auto rbac_policies = GenerateRbacPolicies(authz_policy);
   ASSERT_TRUE(rbac_policies.ok());
-  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
-  EXPECT_THAT(rbac_policies.value().allow_policy.policies,
-              ::testing::ElementsAre(::testing::Pair(
-                  "authz_allow_policy",
-                  ::testing::AllOf(
-                      ::testing::Field(
-                          &Rbac::Policy::permissions,
-                          ::testing::Field(&Rbac::Permission::type,
-                                           Rbac::Permission::RuleType::ANY)),
-                      ::testing::Field(
-                          &Rbac::Policy::principals,
-                          ::testing::Field(&Rbac::Principal::type,
-                                           Rbac::Principal::RuleType::ANY))))));
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
+  EXPECT_THAT(
+      rbac_policies.value().allow_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_allow_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
+                  ::testing::Field(&Rbac::Permission::type,
+                                   Rbac::Permission::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::Field(&Rbac::Principal::type,
+                                   Rbac::Principal::RuleType::kAny))))));
 }
 
 TEST(GenerateRbacPoliciesTest, IncorrectSourceType) {
@@ -289,7 +291,7 @@ TEST(GenerateRbacPoliciesTest, ParseSourceSuccess) {
       "}";
   auto rbac_policies = GenerateRbacPolicies(authz_policy);
   ASSERT_TRUE(rbac_policies.ok());
-  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
   EXPECT_THAT(
       rbac_policies.value().allow_policy.policies,
       ::testing::ElementsAre(::testing::Pair(
@@ -298,33 +300,33 @@ TEST(GenerateRbacPoliciesTest, ParseSourceSuccess) {
               ::testing::Field(
                   &Rbac::Policy::permissions,
                   ::testing::Field(&Rbac::Permission::type,
-                                   Rbac::Permission::RuleType::ANY)),
+                                   Rbac::Permission::RuleType::kAny)),
               ::testing::Field(
                   &Rbac::Policy::principals,
                   ::testing::AllOf(
                       ::testing::Field(&Rbac::Principal::type,
-                                       Rbac::Principal::RuleType::AND),
+                                       Rbac::Principal::RuleType::kAnd),
                       ::testing::Field(
                           &Rbac::Principal::principals,
                           ::testing::ElementsAre(::testing::AllOf(
                               ::testing::Pointee(::testing::Field(
                                   &Rbac::Principal::type,
-                                  Rbac::Principal::RuleType::OR)),
+                                  Rbac::Principal::RuleType::kOr)),
                               ::testing::Pointee(::testing::Field(
                                   &Rbac::Principal::principals,
                                   ::testing::ElementsAre(
                                       EqualsPrincipalName(
-                                          StringMatcher::Type::EXACT,
+                                          StringMatcher::Type::kExact,
                                           "spiffe://foo.abc"),
                                       EqualsPrincipalName(
-                                          StringMatcher::Type::PREFIX,
+                                          StringMatcher::Type::kPrefix,
                                           "spiffe://bar"),
                                       EqualsPrincipalName(
-                                          StringMatcher::Type::SUFFIX, "baz"),
+                                          StringMatcher::Type::kSuffix, "baz"),
                                       EqualsPrincipalName(
-                                          StringMatcher::Type::EXACT,
+                                          StringMatcher::Type::kExact,
                                           "spiffe://abc.*.com")))))))))))));
-  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
   EXPECT_THAT(
       rbac_policies.value().deny_policy.policies,
       ::testing::ElementsAre(::testing::Pair(
@@ -333,22 +335,22 @@ TEST(GenerateRbacPoliciesTest, ParseSourceSuccess) {
               ::testing::Field(
                   &Rbac::Policy::permissions,
                   ::testing::Field(&Rbac::Permission::type,
-                                   Rbac::Permission::RuleType::ANY)),
+                                   Rbac::Permission::RuleType::kAny)),
               ::testing::Field(
                   &Rbac::Policy::principals,
                   ::testing::AllOf(
                       ::testing::Field(&Rbac::Principal::type,
-                                       Rbac::Principal::RuleType::AND),
+                                       Rbac::Principal::RuleType::kAnd),
                       ::testing::Field(
                           &Rbac::Principal::principals,
                           ::testing::ElementsAre(::testing::AllOf(
                               ::testing::Pointee(::testing::Field(
                                   &Rbac::Principal::type,
-                                  Rbac::Principal::RuleType::OR)),
+                                  Rbac::Principal::RuleType::kOr)),
                               ::testing::Pointee(::testing::Field(
                                   &Rbac::Principal::principals,
                                   ::testing::ElementsAre(EqualsPrincipalName(
-                                      StringMatcher::Type::PREFIX,
+                                      StringMatcher::Type::kPrefix,
                                       "")))))))))))));
 }
 
@@ -420,7 +422,7 @@ TEST(GenerateRbacPoliciesTest, ParseRequestPathsSuccess) {
       "}";
   auto rbac_policies = GenerateRbacPolicies(authz_policy);
   ASSERT_TRUE(rbac_policies.ok());
-  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
   EXPECT_THAT(
       rbac_policies.value().deny_policy.policies,
       ::testing::ElementsAre(::testing::Pair(
@@ -429,52 +431,53 @@ TEST(GenerateRbacPoliciesTest, ParseRequestPathsSuccess) {
               ::testing::Field(
                   &Rbac::Policy::principals,
                   ::testing::Field(&Rbac::Principal::type,
-                                   Rbac::Principal::RuleType::ANY)),
+                                   Rbac::Principal::RuleType::kAny)),
               ::testing::Field(
                   &Rbac::Policy::permissions,
                   ::testing::AllOf(
                       ::testing::Field(&Rbac::Permission::type,
-                                       Rbac::Permission::RuleType::AND),
+                                       Rbac::Permission::RuleType::kAnd),
                       ::testing::Field(
                           &Rbac::Permission::permissions,
                           ::testing::ElementsAre(::testing::AllOf(
                               ::testing::Pointee(::testing::Field(
                                   &Rbac::Permission::type,
-                                  Rbac::Permission::RuleType::OR)),
+                                  Rbac::Permission::RuleType::kOr)),
                               ::testing::Pointee(::testing::Field(
                                   &Rbac::Permission::permissions,
                                   ::testing::ElementsAre(
-                                      EqualsPath(StringMatcher::Type::EXACT,
+                                      EqualsPath(StringMatcher::Type::kExact,
                                                  "path-foo"),
-                                      EqualsPath(StringMatcher::Type::PREFIX,
+                                      EqualsPath(StringMatcher::Type::kPrefix,
                                                  "path-bar"),
-                                      EqualsPath(StringMatcher::Type::SUFFIX,
+                                      EqualsPath(StringMatcher::Type::kSuffix,
                                                  "baz")))))))))))));
-  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
-  EXPECT_THAT(rbac_policies.value().allow_policy.policies,
-              ::testing::ElementsAre(::testing::Pair(
-                  "authz_allow_policy",
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
+  EXPECT_THAT(
+      rbac_policies.value().allow_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_allow_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::Field(&Rbac::Principal::type,
+                                   Rbac::Principal::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
                   ::testing::AllOf(
+                      ::testing::Field(&Rbac::Permission::type,
+                                       Rbac::Permission::RuleType::kAnd),
                       ::testing::Field(
-                          &Rbac::Policy::principals,
-                          ::testing::Field(&Rbac::Principal::type,
-                                           Rbac::Principal::RuleType::ANY)),
-                      ::testing::Field(
-                          &Rbac::Policy::permissions,
-                          ::testing::AllOf(
-                              ::testing::Field(&Rbac::Permission::type,
-                                               Rbac::Permission::RuleType::AND),
-                              ::testing::Field(
+                          &Rbac::Permission::permissions,
+                          ::testing::ElementsAre(::testing::AllOf(
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Permission::type,
+                                  Rbac::Permission::RuleType::kOr)),
+                              ::testing::Pointee(::testing::Field(
                                   &Rbac::Permission::permissions,
-                                  ::testing::ElementsAre(::testing::AllOf(
-                                      ::testing::Pointee(::testing::Field(
-                                          &Rbac::Permission::type,
-                                          Rbac::Permission::RuleType::OR)),
-                                      ::testing::Pointee(::testing::Field(
-                                          &Rbac::Permission::permissions,
-                                          ::testing::ElementsAre(EqualsPath(
-                                              StringMatcher::Type::PREFIX,
-                                              "")))))))))))));
+                                  ::testing::ElementsAre(
+                                      EqualsPath(StringMatcher::Type::kPrefix,
+                                                 "")))))))))))));
 }
 
 TEST(GenerateRbacPoliciesTest, IncorrectHeaderType) {
@@ -657,9 +660,9 @@ TEST(GenerateRbacPoliciesTest, ParseRequestHeadersSuccess) {
       "}";
   auto rbac_policies = GenerateRbacPolicies(authz_policy);
   ASSERT_TRUE(rbac_policies.ok());
-  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
   EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty());
-  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
   EXPECT_THAT(
       rbac_policies.value().allow_policy.policies,
       ::testing::ElementsAre(::testing::Pair(
@@ -668,51 +671,53 @@ TEST(GenerateRbacPoliciesTest, ParseRequestHeadersSuccess) {
               ::testing::Field(
                   &Rbac::Policy::principals,
                   ::testing::Field(&Rbac::Principal::type,
-                                   Rbac::Principal::RuleType::ANY)),
+                                   Rbac::Principal::RuleType::kAny)),
               ::testing::Field(
                   &Rbac::Policy::permissions,
                   ::testing::AllOf(
                       ::testing::Field(&Rbac::Permission::type,
-                                       Rbac::Permission::RuleType::AND),
+                                       Rbac::Permission::RuleType::kAnd),
                       ::testing::Field(
                           &Rbac::Permission::permissions,
                           ::testing::ElementsAre(::testing::AllOf(
                               ::testing::Pointee(::testing::Field(
                                   &Rbac::Permission::type,
-                                  Rbac::Permission::RuleType::AND)),
+                                  Rbac::Permission::RuleType::kAnd)),
                               ::testing::Pointee(::testing::Field(
                                   &Rbac::Permission::permissions,
                                   ::testing::ElementsAre(
                                       ::testing::AllOf(
                                           ::testing::Pointee(::testing::Field(
                                               &Rbac::Permission::type,
-                                              Rbac::Permission::RuleType::OR)),
+                                              Rbac::Permission::RuleType::kOr)),
                                           ::testing::Pointee(::testing::Field(
                                               &Rbac::Permission::permissions,
                                               ::testing::ElementsAre(
-                                                  EqualsHeader("key-1",
-                                                               HeaderMatcher::
-                                                                   Type::PREFIX,
-                                                               ""))))),
+                                                  EqualsHeader(
+                                                      "key-1",
+                                                      HeaderMatcher::Type::
+                                                          kPrefix,
+                                                      ""))))),
                                       ::testing::AllOf(
                                           ::testing::Pointee(::testing::Field(
                                               &Rbac::Permission::type,
-                                              Rbac::Permission::RuleType::OR)),
+                                              Rbac::Permission::RuleType::kOr)),
                                           ::testing::Pointee(::testing::Field(
                                               &Rbac::Permission::permissions,
                                               ::testing::ElementsAre(
                                                   EqualsHeader("key-2",
                                                                HeaderMatcher::
-                                                                   Type::EXACT,
+                                                                   Type::kExact,
                                                                "foo"),
-                                                  EqualsHeader("key-2",
-                                                               HeaderMatcher::
-                                                                   Type::PREFIX,
-                                                               "bar"),
                                                   EqualsHeader(
                                                       "key-2",
                                                       HeaderMatcher::Type::
-                                                          SUFFIX,
+                                                          kPrefix,
+                                                      "bar"),
+                                                  EqualsHeader(
+                                                      "key-2",
+                                                      HeaderMatcher::Type::
+                                                          kSuffix,
                                                       "baz")))))))))))))))));
 }
 
@@ -741,9 +746,9 @@ TEST(GenerateRbacPoliciesTest, ParseRulesArraySuccess) {
       "}";
   auto rbac_policies = GenerateRbacPolicies(authz_policy);
   ASSERT_TRUE(rbac_policies.ok());
-  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
   EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty());
-  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
   EXPECT_THAT(
       rbac_policies.value().allow_policy.policies,
       ::testing::ElementsAre(
@@ -754,34 +759,34 @@ TEST(GenerateRbacPoliciesTest, ParseRulesArraySuccess) {
                       &Rbac::Policy::permissions,
                       ::testing::AllOf(
                           ::testing::Field(&Rbac::Permission::type,
-                                           Rbac::Permission::RuleType::AND),
+                                           Rbac::Permission::RuleType::kAnd),
                           ::testing::Field(
                               &Rbac::Permission::permissions,
                               ::testing::ElementsAre(::testing::AllOf(
                                   ::testing::Pointee(::testing::Field(
                                       &Rbac::Permission::type,
-                                      Rbac::Permission::RuleType::OR)),
+                                      Rbac::Permission::RuleType::kOr)),
                                   ::testing::Pointee(::testing::Field(
                                       &Rbac::Permission::permissions,
-                                      ::testing::ElementsAre(
-                                          EqualsPath(StringMatcher::Type::EXACT,
-                                                     "foo"))))))))),
+                                      ::testing::ElementsAre(EqualsPath(
+                                          StringMatcher::Type::kExact,
+                                          "foo"))))))))),
                   ::testing::Field(
                       &Rbac::Policy::principals,
                       ::testing::AllOf(
                           ::testing::Field(&Rbac::Principal::type,
-                                           Rbac::Principal::RuleType::AND),
+                                           Rbac::Principal::RuleType::kAnd),
                           ::testing::Field(
                               &Rbac::Principal::principals,
                               ::testing::ElementsAre(::testing::AllOf(
                                   ::testing::Pointee(::testing::Field(
                                       &Rbac::Principal::type,
-                                      Rbac::Principal::RuleType::OR)),
+                                      Rbac::Principal::RuleType::kOr)),
                                   ::testing::Pointee(::testing::Field(
                                       &Rbac::Principal::principals,
                                       ::testing::ElementsAre(
                                           EqualsPrincipalName(
-                                              StringMatcher::Type::EXACT,
+                                              StringMatcher::Type::kExact,
                                               "spiffe://foo.abc"))))))))))),
           ::testing::Pair(
               "authz_allow_policy_2",
@@ -789,11 +794,11 @@ TEST(GenerateRbacPoliciesTest, ParseRulesArraySuccess) {
                   ::testing::Field(
                       &Rbac::Policy::permissions,
                       ::testing::Field(&Rbac::Permission::type,
-                                       Rbac::Permission::RuleType::ANY)),
+                                       Rbac::Permission::RuleType::kAny)),
                   ::testing::Field(
                       &Rbac::Policy::principals,
                       ::testing::Field(&Rbac::Principal::type,
-                                       Rbac::Principal::RuleType::ANY))))));
+                                       Rbac::Principal::RuleType::kAny))))));
 }
 
 }  // namespace grpc_core
index 50c3694..c5621d9 100644 (file)
@@ -166,7 +166,7 @@ static grpc_endpoint_test_config configs[] = {
      clean_up},
 };
 
-static void inc_call_ctr(void* arg, grpc_error* /*error*/) {
+static void inc_call_ctr(void* arg, grpc_error_handle /*error*/) {
   ++*static_cast<int*>(arg);
 }
 
@@ -202,7 +202,7 @@ static void test_leftover(grpc_endpoint_test_config config, size_t slice_size) {
   clean_up();
 }
 
-static void destroy_pollset(void* p, grpc_error* /*error*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
index 2049832..da7f2f0 100644 (file)
@@ -222,6 +222,32 @@ static int check_x509_pem_cert_chain(const grpc_auth_context* ctx,
   return 1;
 }
 
+static int check_sans(
+    const grpc_auth_context* ctx, const char* expected_property_name,
+    const std::vector<std::string>& expected_property_values) {
+  grpc_auth_property_iterator it =
+      grpc_auth_context_find_properties_by_name(ctx, expected_property_name);
+  for (const auto& property_value : expected_property_values) {
+    const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
+    if (prop == nullptr) {
+      gpr_log(GPR_ERROR, "Expected value %s not found.",
+              property_value.c_str());
+      return 0;
+    }
+    if (strncmp(prop->value, property_value.c_str(), prop->value_length) != 0) {
+      gpr_log(GPR_ERROR, "Expected peer %s and got %s.", property_value.c_str(),
+              prop->value);
+      return 0;
+    }
+  }
+  if (grpc_auth_property_iterator_next(&it) != nullptr) {
+    gpr_log(GPR_ERROR, "Expected only %zu property values.",
+            expected_property_values.size());
+    return 0;
+  }
+  return 1;
+}
+
 static int check_spiffe_id(const grpc_auth_context* ctx,
                            const char* expected_spiffe_id,
                            bool expect_spiffe_id) {
@@ -444,6 +470,59 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
   ctx.reset(DEBUG_LOCATION, "test");
 }
 
+static void test_dns_peer_to_auth_context(void) {
+  tsi_peer peer;
+  const std::vector<std::string> expected_dns = {"dns1", "dns2", "dns3"};
+  GPR_ASSERT(tsi_construct_peer(expected_dns.size(), &peer) == TSI_OK);
+  for (size_t i = 0; i < expected_dns.size(); ++i) {
+    GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                   TSI_X509_DNS_PEER_PROPERTY, expected_dns[i].c_str(),
+                   &peer.properties[i]) == TSI_OK);
+  }
+  grpc_core::RefCountedPtr<grpc_auth_context> ctx =
+      grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  GPR_ASSERT(ctx != nullptr);
+  GPR_ASSERT(check_sans(ctx.get(), GRPC_PEER_DNS_PROPERTY_NAME, expected_dns));
+  tsi_peer_destruct(&peer);
+  ctx.reset(DEBUG_LOCATION, "test");
+}
+
+static void test_email_peer_to_auth_context(void) {
+  tsi_peer peer;
+  const std::vector<std::string> expected_emails = {"email1", "email2"};
+  GPR_ASSERT(tsi_construct_peer(expected_emails.size(), &peer) == TSI_OK);
+  for (size_t i = 0; i < expected_emails.size(); ++i) {
+    GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                   TSI_X509_EMAIL_PEER_PROPERTY, expected_emails[i].c_str(),
+                   &peer.properties[i]) == TSI_OK);
+  }
+  grpc_core::RefCountedPtr<grpc_auth_context> ctx =
+      grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  GPR_ASSERT(ctx != nullptr);
+  GPR_ASSERT(
+      check_sans(ctx.get(), GRPC_PEER_EMAIL_PROPERTY_NAME, expected_emails));
+  tsi_peer_destruct(&peer);
+  ctx.reset(DEBUG_LOCATION, "test");
+}
+
+static void test_ip_peer_to_auth_context(void) {
+  tsi_peer peer;
+  const std::vector<std::string> expected_ips = {"128.128.128.128",
+                                                 "255.255.255.255"};
+  GPR_ASSERT(tsi_construct_peer(expected_ips.size(), &peer) == TSI_OK);
+  for (size_t i = 0; i < expected_ips.size(); ++i) {
+    GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                   TSI_X509_IP_PEER_PROPERTY, expected_ips[i].c_str(),
+                   &peer.properties[i]) == TSI_OK);
+  }
+  grpc_core::RefCountedPtr<grpc_auth_context> ctx =
+      grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  GPR_ASSERT(ctx != nullptr);
+  GPR_ASSERT(check_sans(ctx.get(), GRPC_PEER_IP_PROPERTY_NAME, expected_ips));
+  tsi_peer_destruct(&peer);
+  ctx.reset(DEBUG_LOCATION, "test");
+}
+
 static void test_spiffe_id_peer_to_auth_context(void) {
   // Invalid SPIFFE IDs should not be plumbed.
   std::string long_id(2050, 'x');
@@ -558,6 +637,7 @@ static void test_ipv6_address_san(void) {
   }
   tsi_peer_destruct(&peer);
 }
+
 namespace grpc_core {
 namespace {
 
@@ -637,7 +717,7 @@ static void test_peer_alpn_check(void) {
   GPR_ASSERT(tsi_construct_string_peer_property("wrong peer property name",
                                                 alpn, strlen(alpn),
                                                 &peer.properties[0]) == TSI_OK);
-  grpc_error* error = grpc_ssl_check_alpn(&peer);
+  grpc_error_handle error = grpc_ssl_check_alpn(&peer);
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   tsi_peer_destruct(&peer);
   GRPC_ERROR_UNREF(error);
@@ -672,6 +752,9 @@ int main(int argc, char** argv) {
   test_cn_and_one_san_ssl_peer_to_auth_context();
   test_cn_and_multiple_sans_ssl_peer_to_auth_context();
   test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context();
+  test_dns_peer_to_auth_context();
+  test_email_peer_to_auth_context();
+  test_ip_peer_to_auth_context();
   test_spiffe_id_peer_to_auth_context();
   test_ipv6_address_san();
   test_default_ssl_roots();
index cdd00e0..6401f8e 100644 (file)
@@ -42,7 +42,7 @@ struct handshake_state {
   bool done_callback_called;
 };
 
-static void on_handshake_done(void* arg, grpc_error* error) {
+static void on_handshake_done(void* arg, grpc_error_handle error) {
   grpc_core::HandshakerArgs* args =
       static_cast<grpc_core::HandshakerArgs*>(arg);
   struct handshake_state* state =
index 5c94e89..c041fd9 100644 (file)
@@ -352,7 +352,8 @@ TEST_F(TlsSecurityConnectorTest, TlsCheckHostNameSuccess) {
   GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
                  TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, target_name,
                  &peer.properties[0]) == TSI_OK);
-  grpc_error* error = grpc_core::internal::TlsCheckHostName(target_name, &peer);
+  grpc_error_handle error =
+      grpc_core::internal::TlsCheckHostName(target_name, &peer);
   tsi_peer_destruct(&peer);
   EXPECT_EQ(error, GRPC_ERROR_NONE);
   GRPC_ERROR_UNREF(error);
@@ -366,7 +367,8 @@ TEST_F(TlsSecurityConnectorTest, TlsCheckHostNameFail) {
   GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
                  TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, another_name,
                  &peer.properties[0]) == TSI_OK);
-  grpc_error* error = grpc_core::internal::TlsCheckHostName(target_name, &peer);
+  grpc_error_handle error =
+      grpc_core::internal::TlsCheckHostName(target_name, &peer);
   tsi_peer_destruct(&peer);
   EXPECT_NE(error, GRPC_ERROR_NONE);
   GRPC_ERROR_UNREF(error);
index 3e27fba..c055972 100644 (file)
@@ -30,29 +30,29 @@ namespace testing {
 namespace {
 
 StringMatcher ExactMatcher(const char* string) {
-  return StringMatcher::Create(StringMatcher::Type::EXACT, string).value();
+  return StringMatcher::Create(StringMatcher::Type::kExact, string).value();
 }
 
 StringMatcher PrefixMatcher(const char* string, bool case_sensitive = true) {
-  return StringMatcher::Create(StringMatcher::Type::PREFIX, string,
+  return StringMatcher::Create(StringMatcher::Type::kPrefix, string,
                                case_sensitive)
       .value();
 }
 
 StringMatcher SuffixMatcher(const char* string, bool case_sensitive = true) {
-  return StringMatcher::Create(StringMatcher::Type::SUFFIX, string,
+  return StringMatcher::Create(StringMatcher::Type::kSuffix, string,
                                case_sensitive)
       .value();
 }
 
 StringMatcher ContainsMatcher(const char* string, bool case_sensitive = true) {
-  return StringMatcher::Create(StringMatcher::Type::CONTAINS, string,
+  return StringMatcher::Create(StringMatcher::Type::kContains, string,
                                case_sensitive)
       .value();
 }
 
 StringMatcher SafeRegexMatcher(const char* string) {
-  return StringMatcher::Create(StringMatcher::Type::SAFE_REGEX, string).value();
+  return StringMatcher::Create(StringMatcher::Type::kSafeRegex, string).value();
 }
 
 TEST(XdsSanMatchingTest, EmptySansList) {
index 11bcaa0..5cf6931 100644 (file)
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 
 #include "test/core/util/port.h"
@@ -137,7 +137,7 @@ void bad_server_thread(void* vargs) {
   grpc_sockaddr* addr = reinterpret_cast<grpc_sockaddr*>(resolved_addr.addr);
   int port;
   grpc_tcp_server* s;
-  grpc_error* error = grpc_tcp_server_create(nullptr, nullptr, &s);
+  grpc_error_handle error = grpc_tcp_server_create(nullptr, nullptr, &s);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   memset(&resolved_addr, 0, sizeof(resolved_addr));
   addr->sa_family = GRPC_AF_INET;
@@ -168,7 +168,7 @@ void bad_server_thread(void* vargs) {
   grpc_tcp_server_unref(s);
 }
 
-static void done_pollset_shutdown(void* pollset, grpc_error* /*error*/) {
+static void done_pollset_shutdown(void* pollset, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(pollset));
   gpr_free(pollset);
 }
index bac7ee0..bd443a7 100644 (file)
@@ -40,7 +40,7 @@ static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }
 
 static grpc_closure transport_op_cb;
 
-static void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
+static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 void test_transport_op(grpc_channel* channel) {
   grpc_core::ExecCtx exec_ctx;
index 0e829c2..2aa962a 100644 (file)
@@ -132,7 +132,7 @@ void test_bind_server_to_addr(const char* host, bool secure) {
 
 static int external_dns_works(const char* host) {
   grpc_resolved_addresses* res = nullptr;
-  grpc_error* error = grpc_blocking_resolve_address(host, "80", &res);
+  grpc_error_handle error = grpc_blocking_resolve_address(host, "80", &res);
   GRPC_ERROR_UNREF(error);
   if (res != nullptr) {
     grpc_resolved_addresses_destroy(res);
index 1bec5af..3eeb4f9 100644 (file)
@@ -64,6 +64,20 @@ grpc_cc_test(
 )
 
 grpc_cc_test(
+    name = "error_utils_test",
+    srcs = ["error_utils_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
     name = "metadata_test",
     srcs = ["metadata_test.cc"],
     language = "C++",
index 1629407..32ee73f 100644 (file)
@@ -37,7 +37,7 @@ namespace {
 // SliceBufferByteStream tests
 //
 
-void NotCalledClosure(void* /*arg*/, grpc_error* /*error*/) {
+void NotCalledClosure(void* /*arg*/, grpc_error_handle /*error*/) {
   GPR_ASSERT(false);
 }
 
@@ -64,7 +64,7 @@ TEST(SliceBufferByteStream, Basic) {
   for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
     ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
     grpc_slice output;
-    grpc_error* error = stream.Pull(&output);
+    grpc_error_handle error = stream.Pull(&output);
     EXPECT_TRUE(error == GRPC_ERROR_NONE);
     EXPECT_TRUE(grpc_slice_eq(input[i], output));
     grpc_slice_unref_internal(output);
@@ -95,12 +95,12 @@ TEST(SliceBufferByteStream, Shutdown) {
   // Read the first slice.
   ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
   grpc_slice output;
-  grpc_error* error = stream.Pull(&output);
+  grpc_error_handle error = stream.Pull(&output);
   EXPECT_TRUE(error == GRPC_ERROR_NONE);
   EXPECT_TRUE(grpc_slice_eq(input[0], output));
   grpc_slice_unref_internal(output);
   // Now shutdown.
-  grpc_error* shutdown_error =
+  grpc_error_handle shutdown_error =
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("shutdown error");
   stream.Shutdown(GRPC_ERROR_REF(shutdown_error));
   // After shutdown, the next pull() should return the error.
@@ -142,7 +142,7 @@ TEST(CachingByteStream, Basic) {
   for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
     ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
     grpc_slice output;
-    grpc_error* error = stream.Pull(&output);
+    grpc_error_handle error = stream.Pull(&output);
     EXPECT_TRUE(error == GRPC_ERROR_NONE);
     EXPECT_TRUE(grpc_slice_eq(input[i], output));
     grpc_slice_unref_internal(output);
@@ -175,7 +175,7 @@ TEST(CachingByteStream, Reset) {
   // Read one slice.
   ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
   grpc_slice output;
-  grpc_error* error = stream.Pull(&output);
+  grpc_error_handle error = stream.Pull(&output);
   EXPECT_TRUE(error == GRPC_ERROR_NONE);
   EXPECT_TRUE(grpc_slice_eq(input[0], output));
   grpc_slice_unref_internal(output);
@@ -218,7 +218,7 @@ TEST(CachingByteStream, SharedCache) {
   // Read one slice from stream1.
   EXPECT_TRUE(stream1.Next(~(size_t)0, &closure));
   grpc_slice output;
-  grpc_error* error = stream1.Pull(&output);
+  grpc_error_handle error = stream1.Pull(&output);
   EXPECT_TRUE(error == GRPC_ERROR_NONE);
   EXPECT_TRUE(grpc_slice_eq(input[0], output));
   grpc_slice_unref_internal(output);
index 9f0ffeb..d88d66c 100644 (file)
@@ -39,7 +39,7 @@ const uint32_t kByteOffset = 123;
 void* PhonyArgsCopier(void* arg) { return arg; }
 
 void TestExecuteFlushesListVerifier(void* arg, grpc_core::Timestamps* ts,
-                                    grpc_error* error) {
+                                    grpc_error_handle error) {
   ASSERT_NE(arg, nullptr);
   EXPECT_EQ(error, GRPC_ERROR_NONE);
   if (ts) {
index 22465db..e86cdef 100644 (file)
@@ -30,7 +30,7 @@
 bool squelch = true;
 bool leak_check = true;
 
-static grpc_error* onhdr(void* /*ud*/, grpc_mdelem md) {
+static grpc_error_handle onhdr(void* /*ud*/, grpc_mdelem md) {
   GRPC_MDELEM_UNREF(md);
   return GRPC_ERROR_NONE;
 }
index 4782d48..bc48881 100644 (file)
@@ -34,7 +34,7 @@ typedef struct {
   va_list args;
 } test_checker;
 
-static grpc_error* onhdr(void* ud, grpc_mdelem md) {
+static grpc_error_handle onhdr(void* ud, grpc_mdelem md) {
   const char *ekey, *evalue;
   test_checker* chk = static_cast<test_checker*>(ud);
   ekey = va_arg(chk->args, char*);
index 8164231..b979020 100644 (file)
@@ -104,9 +104,9 @@ class Client {
   void Connect() {
     grpc_core::ExecCtx exec_ctx;
     grpc_resolved_addresses* server_addresses = nullptr;
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_blocking_resolve_address(server_address_, "80", &server_addresses);
-    ASSERT_EQ(GRPC_ERROR_NONE, error) << grpc_error_string(error);
+    ASSERT_EQ(GRPC_ERROR_NONE, error) << grpc_error_std_string(error);
     ASSERT_GE(server_addresses->naddrs, 1UL);
     pollset_ = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
     grpc_pollset_init(pollset_, &mu_);
@@ -177,11 +177,12 @@ class Client {
     bool done() const { return gpr_atm_acq_load(&done_atm_) != 0; }
 
     // Caller does NOT take ownership of the error.
-    grpc_error* error() const { return error_; }
+    grpc_error_handle error() const { return error_; }
 
    private:
-    static void OnEventDone(void* arg, grpc_error* error) {
-      gpr_log(GPR_INFO, "OnEventDone(): %s", grpc_error_string(error));
+    static void OnEventDone(void* arg, grpc_error_handle error) {
+      gpr_log(GPR_INFO, "OnEventDone(): %s",
+              grpc_error_std_string(error).c_str());
       EventState* state = static_cast<EventState*>(arg);
       state->error_ = GRPC_ERROR_REF(error);
       gpr_atm_rel_store(&state->done_atm_, 1);
@@ -189,7 +190,7 @@ class Client {
 
     grpc_closure closure_;
     gpr_atm done_atm_ = 0;
-    grpc_error* error_ = GRPC_ERROR_NONE;
+    grpc_error_handle error_ = GRPC_ERROR_NONE;
   };
 
   // Returns true if done, or false if deadline exceeded.
@@ -209,7 +210,7 @@ class Client {
     }
   }
 
-  static void PollsetDestroy(void* arg, grpc_error* /*error*/) {
+  static void PollsetDestroy(void* arg, grpc_error_handle /*error*/) {
     grpc_pollset* pollset = static_cast<grpc_pollset*>(arg);
     grpc_pollset_destroy(pollset);
     gpr_free(pollset);
index e5cdde7..57e5fa8 100644 (file)
 
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/security/credentials/alts/alts_credentials.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/security_connector/alts/alts_security_connector.h"
diff --git a/test/core/transport/error_utils_test.cc b/test/core/transport/error_utils_test.cc
new file mode 100644 (file)
index 0000000..909a5b8
--- /dev/null
@@ -0,0 +1,95 @@
+//
+// Copyright 2021 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "src/core/lib/transport/error_utils.h"
+
+#include <gtest/gtest.h>
+#include "absl/status/status.h"
+
+#include "src/core/lib/slice/slice_internal.h"
+#include "test/core/util/test_config.h"
+
+namespace {
+
+// ---- Ok Status ----
+TEST(ErrorUtilsTest, AbslOkToGrpcError) {
+  grpc_error_handle error = absl_status_to_grpc_error(absl::OkStatus());
+  ASSERT_EQ(GRPC_ERROR_NONE, error);
+  GRPC_ERROR_UNREF(error);
+}
+
+TEST(ErrorUtilsTest, GrpcSpecialErrorNoneToAbslStatus) {
+  absl::Status status = grpc_error_to_absl_status(GRPC_ERROR_NONE);
+  ASSERT_TRUE(status.ok());
+  ASSERT_EQ(status.message(), "");
+}
+
+// ---- Asymmetry of conversions of "Special" errors ----
+TEST(ErrorUtilsTest, AbslStatusToGrpcErrorDoesNotReturnSpecialVariables) {
+  grpc_error_handle error =
+      absl_status_to_grpc_error(absl::CancelledError("Cancelled"));
+  ASSERT_NE(error, GRPC_ERROR_CANCELLED);
+  GRPC_ERROR_UNREF(error);
+}
+
+TEST(ErrorUtilsTest, GrpcSpecialErrorCancelledToAbslStatus) {
+  absl::Status status = grpc_error_to_absl_status(GRPC_ERROR_CANCELLED);
+  ASSERT_TRUE(absl::IsCancelled(status));
+  ASSERT_EQ(status.message(), "Cancelled");
+}
+
+TEST(ErrorUtilsTest, GrpcSpecialErrorOOMToAbslStatus) {
+  absl::Status status = grpc_error_to_absl_status(GRPC_ERROR_OOM);
+  ASSERT_TRUE(absl::IsResourceExhausted(status));
+  ASSERT_EQ(status.message(), "Out of memory");
+}
+
+// ---- Ordinary statuses ----
+TEST(ErrorUtilsTest, AbslUnavailableToGrpcError) {
+  grpc_error_handle error =
+      absl_status_to_grpc_error(absl::UnavailableError("Making tea"));
+  // Status code checks
+  intptr_t code;
+  ASSERT_TRUE(grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &code));
+  ASSERT_EQ(static_cast<grpc_status_code>(code), GRPC_STATUS_UNAVAILABLE);
+  // Status message checks
+  grpc_slice message;
+  ASSERT_TRUE(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION, &message));
+  absl::string_view str = grpc_core::StringViewFromSlice(message);
+  ASSERT_EQ(str, "Making tea");
+  grpc_slice_unref(message);
+  GRPC_ERROR_UNREF(error);
+}
+
+TEST(ErrorUtilsTest, GrpcErrorUnavailableToAbslStatus) {
+  grpc_error_handle error = grpc_error_set_int(
+      GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "weighted_target: all children report state TRANSIENT_FAILURE"),
+      GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
+  absl::Status status = grpc_error_to_absl_status(error);
+  ASSERT_TRUE(absl::IsUnavailable(status));
+  ASSERT_EQ(status.message(),
+            "weighted_target: all children report state TRANSIENT_FAILURE");
+  GRPC_ERROR_UNREF(error);
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  grpc::testing::TestEnvironment env(argc, argv);
+  return RUN_ALL_TESTS();
+};
index 62ce964..ca8140c 100644 (file)
@@ -23,7 +23,7 @@
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 
-static void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
+static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 int main(int argc, char** argv) {
   grpc::testing::TestEnvironment env(argc, argv);
index 104ba4d..87f8dfb 100644 (file)
@@ -253,13 +253,13 @@ void check_server0_peer(tsi_peer* peer) {
   tsi_peer_destruct(peer);
 }
 
-static bool check_subject_alt_name(tsi_peer* peer, const char* name) {
+static bool check_property(tsi_peer* peer, const char* property_name,
+                           const char* property_value) {
   for (size_t i = 0; i < peer->property_count; i++) {
     const tsi_peer_property* prop = &peer->properties[i];
-    if (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) ==
-        0) {
-      if (strlen(name) == prop->value.length &&
-          memcmp(prop->value.data, name, prop->value.length) == 0) {
+    if (strcmp(prop->name, property_name) == 0) {
+      if (strlen(property_value) == prop->value.length &&
+          memcmp(prop->value.data, property_value, prop->value.length) == 0) {
         return true;
       }
     }
@@ -267,17 +267,25 @@ static bool check_subject_alt_name(tsi_peer* peer, const char* name) {
   return false;
 }
 
+static bool check_subject_alt_name(tsi_peer* peer, const char* name) {
+  return check_property(peer, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
+                        name);
+}
+
+static bool check_dns(tsi_peer* peer, const char* name) {
+  return check_property(peer, TSI_X509_DNS_PEER_PROPERTY, name);
+}
+
 static bool check_uri(tsi_peer* peer, const char* name) {
-  for (size_t i = 0; i < peer->property_count; i++) {
-    const tsi_peer_property* prop = &peer->properties[i];
-    if (strcmp(prop->name, TSI_X509_URI_PEER_PROPERTY) == 0) {
-      if (strlen(name) == prop->value.length &&
-          memcmp(prop->value.data, name, prop->value.length) == 0) {
-        return true;
-      }
-    }
-  }
-  return false;
+  return check_property(peer, TSI_X509_URI_PEER_PROPERTY, name);
+}
+
+static bool check_email(tsi_peer* peer, const char* name) {
+  return check_property(peer, TSI_X509_EMAIL_PEER_PROPERTY, name);
+}
+
+static bool check_ip(tsi_peer* peer, const char* name) {
+  return check_property(peer, TSI_X509_IP_PEER_PROPERTY, name);
 }
 
 void check_server1_peer(tsi_peer* peer) {
@@ -329,12 +337,20 @@ static void ssl_test_check_handshaker_peers(tsi_test_fixture* fixture) {
   // and send an alert to the client as the first application data message. In
   // TLS 1.2, the client-side handshake will fail if the client sends a bad
   // certificate.
+  //
+  // For OpenSSL versions < 1.1, TLS 1.3 is not supported, so the client-side
+  // handshake should succeed precisely when the server-side handshake
+  // succeeds.
   bool expect_server_success =
       !(key_cert_lib->use_bad_server_cert ||
         (key_cert_lib->use_bad_client_cert && ssl_fixture->force_client_auth));
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
   bool expect_client_success = test_tls_version == tsi_tls_version::TSI_TLS1_2
                                    ? expect_server_success
                                    : !key_cert_lib->use_bad_server_cert;
+#else
+  bool expect_client_success = expect_server_success;
+#endif
   if (expect_client_success) {
     GPR_ASSERT(tsi_handshaker_result_extract_peer(
                    ssl_fixture->base.client_result, &peer) == TSI_OK);
@@ -693,7 +709,7 @@ static bool is_slow_build() {
 #if defined(GPR_ARCH_32) || defined(__APPLE__)
   return true;
 #else
-  return BuiltUnderMsan();
+  return BuiltUnderMsan() || BuiltUnderTsan();
 #endif
 }
 
@@ -701,11 +717,11 @@ void ssl_tsi_test_do_round_trip_odd_buffer_size() {
   gpr_log(GPR_INFO, "ssl_tsi_test_do_round_trip_odd_buffer_size");
   const size_t odd_sizes[] = {1025, 2051, 4103, 8207, 16409};
   size_t size = sizeof(odd_sizes) / sizeof(size_t);
-  // 1. avoid test being extremely slow under MSAN
-  // 2. on 32-bit, the test is much slower (probably due to lack of boringssl
-  // asm optimizations) so we only run a subset of tests to avoid timeout
-  // 3. on Mac OS, we have slower testing machines so we only run a subset
-  // of tests to avoid timeout
+  // 1. This test is extremely slow under MSAN and TSAN.
+  // 2. On 32-bit, the test is much slower (probably due to lack of boringssl
+  // asm optimizations) so we only run a subset of tests to avoid timeout.
+  // 3. On Mac OS, we have slower testing machines so we only run a subset
+  // of tests to avoid timeout.
   if (is_slow_build()) {
     size = 1;
   }
@@ -902,8 +918,9 @@ void ssl_tsi_test_extract_x509_subject_names() {
   GPR_ASSERT(tsi_ssl_extract_x509_subject_names_from_pem_cert(cert, &peer) ==
              TSI_OK);
   // tsi_peer should include one common name, one certificate, one security
-  // level, seven SAN fields, three URI fields.
-  size_t expected_property_count = 12;
+  // level, ten SAN fields, two DNS SAN fields, three URI fields, two email
+  // addresses and two IP addresses.
+  size_t expected_property_count = 21;
   GPR_ASSERT(peer.property_count == expected_property_count);
   // Check common name
   const char* expected_cn = "xpigors";
@@ -919,6 +936,8 @@ void ssl_tsi_test_extract_x509_subject_names() {
   // Check DNS
   GPR_ASSERT(check_subject_alt_name(&peer, "foo.test.domain.com") == 1);
   GPR_ASSERT(check_subject_alt_name(&peer, "bar.test.domain.com") == 1);
+  GPR_ASSERT(check_dns(&peer, "foo.test.domain.com") == 1);
+  GPR_ASSERT(check_dns(&peer, "bar.test.domain.com") == 1);
   // Check URI
   // Note that a valid SPIFFE certificate should only have one URI.
   GPR_ASSERT(check_subject_alt_name(&peer, "spiffe://foo.com/bar/baz") == 1);
@@ -932,6 +951,15 @@ void ssl_tsi_test_extract_x509_subject_names() {
   // Check email address
   GPR_ASSERT(check_subject_alt_name(&peer, "foo@test.domain.com") == 1);
   GPR_ASSERT(check_subject_alt_name(&peer, "bar@test.domain.com") == 1);
+  GPR_ASSERT(check_email(&peer, "foo@test.domain.com") == 1);
+  GPR_ASSERT(check_email(&peer, "bar@test.domain.com") == 1);
+  // Check ip address
+  GPR_ASSERT(check_subject_alt_name(&peer, "192.168.7.1") == 1);
+  GPR_ASSERT(check_subject_alt_name(&peer, "13::17") == 1);
+  GPR_ASSERT(check_ip(&peer, "192.168.7.1") == 1);
+  GPR_ASSERT(check_ip(&peer, "13::17") == 1);
+  // Check other fields
+  GPR_ASSERT(check_subject_alt_name(&peer, "other types of SAN") == 1);
   // Free memory
   gpr_free(cert);
   tsi_peer_destruct(&peer);
@@ -956,7 +984,11 @@ void ssl_tsi_test_extract_cert_chain() {
     X509_INFO* certInfo = sk_X509_INFO_value(certInfos, i);
     if (certInfo->x509 != nullptr) {
       GPR_ASSERT(sk_X509_push(cert_chain, certInfo->x509) != 0);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
       X509_up_ref(certInfo->x509);
+#else
+      certInfo->x509->references += 1;
+#endif
     }
   }
   tsi_peer_property chain_property;
index 0bfa27b..f0c428a 100644 (file)
@@ -50,7 +50,7 @@ typedef struct handshaker_args {
   bool is_client;
   bool transferred_data;
   bool appended_unused_bytes;
-  grpc_error* error;
+  grpc_error_handle error;
 } handshaker_args;
 
 static handshaker_args* handshaker_args_create(tsi_test_fixture* fixture,
@@ -289,15 +289,14 @@ void tsi_test_frame_protector_receive_message_from_peer(
   gpr_free(message_buffer);
 }
 
-grpc_error* on_handshake_next_done(tsi_result result, void* user_data,
-                                   const unsigned char* bytes_to_send,
-                                   size_t bytes_to_send_size,
-                                   tsi_handshaker_result* handshaker_result) {
+grpc_error_handle on_handshake_next_done(
+    tsi_result result, void* user_data, const unsigned char* bytes_to_send,
+    size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result) {
   handshaker_args* args = static_cast<handshaker_args*>(user_data);
   GPR_ASSERT(args != nullptr);
   GPR_ASSERT(args->fixture != nullptr);
   tsi_test_fixture* fixture = args->fixture;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   /* Read more data if we need to. */
   if (result == TSI_INCOMPLETE_DATA) {
     GPR_ASSERT(bytes_to_send_size == 0);
index ec79a63..5f8fcee 100644 (file)
@@ -16,8 +16,6 @@
  *
  */
 
-// TODO(hork): rewrite with googletest
-
 #include "src/core/lib/uri/uri_parser.h"
 
 #include "absl/strings/str_join.h"
index 7dff488..765037e 100644 (file)
@@ -25,7 +25,6 @@ grpc_cc_library(
     name = "grpc_test_util_base",
     srcs = [
         "cmdline.cc",
-        "eval_args_mock_endpoint.cc",
         "fuzzer_util.cc",
         "grpc_profiler.cc",
         "histogram.cc",
@@ -48,11 +47,12 @@ grpc_cc_library(
     ],
     hdrs = [
         "cmdline.h",
-        "eval_args_mock_endpoint.h",
+        "evaluate_args_test_util.h",
         "fuzzer_util.h",
         "grpc_profiler.h",
         "histogram.h",
         "memory_counters.h",
+        "mock_authorization_endpoint.h",
         "mock_endpoint.h",
         "parse_hexstring.h",
         "passthru_endpoint.h",
diff --git a/test/core/util/eval_args_mock_endpoint.cc b/test/core/util/eval_args_mock_endpoint.cc
deleted file mode 100644 (file)
index 6f0de72..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2020 gRPC authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <grpc/support/port_platform.h>
-
-#include "test/core/util/eval_args_mock_endpoint.h"
-
-#include <inttypes.h>
-
-#include <string>
-
-#include "absl/strings/str_format.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-#include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-
-namespace grpc_core {
-
-class EvalArgsMockEndpoint {
- public:
-  EvalArgsMockEndpoint(absl::string_view local_uri, absl::string_view peer_uri)
-      : local_address_(local_uri), peer_(peer_uri) {
-    base_.vtable = &vtable_;
-  }
-  grpc_endpoint* base() const { return const_cast<grpc_endpoint*>(&base_); }
-  static void Read(grpc_endpoint* /*ep*/, grpc_slice_buffer* /*slices*/,
-                   grpc_closure* /*cb*/, bool /*unused*/) {}
-  static void Write(grpc_endpoint* /*ep*/, grpc_slice_buffer* /*slices*/,
-                    grpc_closure* /*cb*/, void* /*unused*/) {}
-  static void AddToPollset(grpc_endpoint* /*ep*/, grpc_pollset* /*unused*/) {}
-  static void AddToPollsetSet(grpc_endpoint* /*ep*/,
-                              grpc_pollset_set* /*unused*/) {}
-  static void DeleteFromPollsetSet(grpc_endpoint* /*ep*/,
-                                   grpc_pollset_set* /*unused*/) {}
-  static void Shutdown(grpc_endpoint* /*ep*/, grpc_error* /*why*/) {}
-  static void Destroy(grpc_endpoint* ep) {
-    EvalArgsMockEndpoint* m = reinterpret_cast<EvalArgsMockEndpoint*>(ep);
-    delete m;
-  }
-
-  static absl::string_view GetPeer(grpc_endpoint* ep) {
-    EvalArgsMockEndpoint* m = reinterpret_cast<EvalArgsMockEndpoint*>(ep);
-    return m->peer_;
-  }
-
-  static absl::string_view GetLocalAddress(grpc_endpoint* ep) {
-    EvalArgsMockEndpoint* m = reinterpret_cast<EvalArgsMockEndpoint*>(ep);
-    return m->local_address_;
-  }
-
-  static grpc_resource_user* GetResourceUser(grpc_endpoint* /*ep*/) {
-    return nullptr;
-  }
-
-  static int GetFd(grpc_endpoint* /*unused*/) { return -1; }
-  static bool CanTrackErr(grpc_endpoint* /*unused*/) { return false; }
-
- private:
-  static constexpr grpc_endpoint_vtable vtable_ = {
-      EvalArgsMockEndpoint::Read,
-      EvalArgsMockEndpoint::Write,
-      EvalArgsMockEndpoint::AddToPollset,
-      EvalArgsMockEndpoint::AddToPollsetSet,
-      EvalArgsMockEndpoint::DeleteFromPollsetSet,
-      EvalArgsMockEndpoint::Shutdown,
-      EvalArgsMockEndpoint::Destroy,
-      EvalArgsMockEndpoint::GetResourceUser,
-      EvalArgsMockEndpoint::GetPeer,
-      EvalArgsMockEndpoint::GetLocalAddress,
-      EvalArgsMockEndpoint::GetFd,
-      EvalArgsMockEndpoint::CanTrackErr};
-  grpc_endpoint base_;
-  std::string local_address_;
-  std::string peer_;
-};
-
-constexpr grpc_endpoint_vtable EvalArgsMockEndpoint::vtable_;
-
-namespace {
-
-std::string NameAndPortToURI(const char* addr, const int port) {
-  grpc_sockaddr_in address;
-  memset(&address, 0, sizeof(address));
-  address.sin_family = AF_INET;
-  address.sin_port = htons(port);
-  inet_pton(AF_INET, addr, &address.sin_addr);
-  grpc_resolved_address resolved;
-  memset(&resolved, 0, sizeof(resolved));
-  memcpy(resolved.addr, &address, sizeof(address));
-  resolved.len = sizeof(address);
-  return grpc_sockaddr_to_uri(&resolved);
-}
-
-}  // namespace
-
-grpc_endpoint* CreateEvalArgsMockEndpoint(const char* local_address,
-                                          const int local_port,
-                                          const char* peer_address,
-                                          const int peer_port) {
-  EvalArgsMockEndpoint* m =
-      new EvalArgsMockEndpoint(NameAndPortToURI(local_address, local_port),
-                               NameAndPortToURI(peer_address, peer_port));
-  return m->base();
-}
-
-}  // namespace grpc_core
diff --git a/test/core/util/evaluate_args_test_util.h b/test/core/util/evaluate_args_test_util.h
new file mode 100644 (file)
index 0000000..a28f3fd
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2021 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef GRPC_TEST_CORE_UTIL_EVALUATE_ARGS_TEST_UTIL_H
+#define GRPC_TEST_CORE_UTIL_EVALUATE_ARGS_TEST_UTIL_H
+
+#include <grpc/support/port_platform.h>
+
+#include <list>
+
+#include <gtest/gtest.h>
+
+#include "src/core/lib/security/authorization/evaluate_args.h"
+#include "test/core/util/mock_authorization_endpoint.h"
+
+namespace grpc_core {
+
+class EvaluateArgsTestUtil {
+ public:
+  EvaluateArgsTestUtil() { grpc_metadata_batch_init(&metadata_); }
+
+  ~EvaluateArgsTestUtil() {
+    grpc_metadata_batch_destroy(&metadata_);
+    delete channel_args_;
+  }
+
+  void AddPairToMetadata(const char* key, const char* value) {
+    metadata_storage_.emplace_back();
+    auto& storage = metadata_storage_.back();
+    ASSERT_EQ(grpc_metadata_batch_add_tail(
+                  &metadata_, &storage,
+                  grpc_mdelem_from_slices(
+                      grpc_slice_intern(grpc_slice_from_static_string(key)),
+                      grpc_slice_intern(grpc_slice_from_static_string(value)))),
+              GRPC_ERROR_NONE);
+  }
+
+  void SetLocalEndpoint(absl::string_view local_uri) {
+    endpoint_.SetLocalAddress(local_uri);
+  }
+
+  void SetPeerEndpoint(absl::string_view peer_uri) {
+    endpoint_.SetPeer(peer_uri);
+  }
+
+  void AddPropertyToAuthContext(const char* name, const char* value) {
+    auth_context_.add_cstring_property(name, value);
+  }
+
+  EvaluateArgs MakeEvaluateArgs() {
+    channel_args_ =
+        new EvaluateArgs::PerChannelArgs(&auth_context_, &endpoint_);
+    return EvaluateArgs(&metadata_, channel_args_);
+  }
+
+ private:
+  std::list<grpc_linked_mdelem> metadata_storage_;
+  grpc_metadata_batch metadata_;
+  MockAuthorizationEndpoint endpoint_{/*local_uri=*/"", /*peer_uri=*/""};
+  grpc_auth_context auth_context_{nullptr};
+  EvaluateArgs::PerChannelArgs* channel_args_ = nullptr;
+};
+
+}  // namespace grpc_core
+
+#endif  // GRPC_TEST_CORE_UTIL_EVALUATE_ARGS_TEST_UTIL_H
diff --git a/test/core/util/mock_authorization_endpoint.h b/test/core/util/mock_authorization_endpoint.h
new file mode 100644 (file)
index 0000000..7e6a712
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2021 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef GRPC_TEST_CORE_UTIL_MOCK_AUTHORIZATION_ENDPOINT_H
+#define GRPC_TEST_CORE_UTIL_MOCK_AUTHORIZATION_ENDPOINT_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/endpoint.h"
+
+namespace grpc_core {
+
+class MockAuthorizationEndpoint : public grpc_endpoint {
+ public:
+  MockAuthorizationEndpoint(absl::string_view local_uri,
+                            absl::string_view peer_uri)
+      : local_address_(local_uri), peer_address_(peer_uri) {
+    static constexpr grpc_endpoint_vtable vtable = {
+        nullptr, nullptr, nullptr, nullptr,         nullptr, nullptr,
+        nullptr, nullptr, GetPeer, GetLocalAddress, nullptr, nullptr};
+    grpc_endpoint::vtable = &vtable;
+  }
+
+  static absl::string_view GetPeer(grpc_endpoint* ep) {
+    MockAuthorizationEndpoint* m =
+        reinterpret_cast<MockAuthorizationEndpoint*>(ep);
+    return m->peer_address_;
+  }
+
+  static absl::string_view GetLocalAddress(grpc_endpoint* ep) {
+    MockAuthorizationEndpoint* m =
+        reinterpret_cast<MockAuthorizationEndpoint*>(ep);
+    return m->local_address_;
+  }
+
+  void SetPeer(absl::string_view peer_address) {
+    peer_address_ = std::string(peer_address);
+  }
+
+  void SetLocalAddress(absl::string_view local_address) {
+    local_address_ = std::string(local_address);
+  }
+
+ private:
+  std::string local_address_;
+  std::string peer_address_;
+};
+
+}  // namespace grpc_core
+
+#endif  // GRPC_TEST_CORE_UTIL_MOCK_AUTHORIZATION_ENDPOINT_H
index b62613b..af24d5f 100644 (file)
@@ -76,7 +76,7 @@ static void me_add_to_pollset_set(grpc_endpoint* /*ep*/,
 static void me_delete_from_pollset_set(grpc_endpoint* /*ep*/,
                                        grpc_pollset_set* /*pollset*/) {}
 
-static void me_shutdown(grpc_endpoint* ep, grpc_error* why) {
+static void me_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   mock_endpoint* m = reinterpret_cast<mock_endpoint*>(ep);
   gpr_mu_lock(&m->mu);
   if (m->on_read) {
index f856481..635b0ba 100644 (file)
@@ -84,7 +84,7 @@ static void me_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
                      grpc_closure* cb, void* /*arg*/) {
   half* m = other_half(reinterpret_cast<half*>(ep));
   gpr_mu_lock(&m->parent->mu);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   gpr_atm_no_barrier_fetch_add(&m->parent->stats->num_writes, (gpr_atm)1);
   if (m->parent->shutdown) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Endpoint already shutdown");
@@ -113,7 +113,7 @@ static void me_add_to_pollset_set(grpc_endpoint* /*ep*/,
 static void me_delete_from_pollset_set(grpc_endpoint* /*ep*/,
                                        grpc_pollset_set* /*pollset*/) {}
 
-static void me_shutdown(grpc_endpoint* ep, grpc_error* why) {
+static void me_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   half* m = reinterpret_cast<half*>(ep);
   gpr_mu_lock(&m->parent->mu);
   m->parent->shutdown = true;
index eae4fbf..391f472 100644 (file)
@@ -31,9 +31,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/http/httpcli.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "test/core/util/port_server_client.h"
 
 static int* chosen_ports = nullptr;
index 973068d..3747187 100644 (file)
@@ -40,14 +40,14 @@ typedef struct freereq {
   int done = 0;
 } freereq;
 
-static void destroy_pops_and_shutdown(void* p, grpc_error* /*error*/) {
+static void destroy_pops_and_shutdown(void* p, grpc_error_handle /*error*/) {
   grpc_pollset* pollset =
       grpc_polling_entity_pollset(static_cast<grpc_polling_entity*>(p));
   grpc_pollset_destroy(pollset);
   gpr_free(pollset);
 }
 
-static void freed_port_from_server(void* arg, grpc_error* /*error*/) {
+static void freed_port_from_server(void* arg, grpc_error_handle /*error*/) {
   freereq* pr = static_cast<freereq*>(arg);
   gpr_mu_lock(pr->mu);
   pr->done = 1;
@@ -127,7 +127,7 @@ typedef struct portreq {
   grpc_httpcli_response response = {};
 } portreq;
 
-static void got_port_from_server(void* arg, grpc_error* error) {
+static void got_port_from_server(void* arg, grpc_error_handle error) {
   size_t i;
   int port = 0;
   portreq* pr = static_cast<portreq*>(arg);
@@ -136,9 +136,8 @@ static void got_port_from_server(void* arg, grpc_error* error) {
 
   if (error != GRPC_ERROR_NONE) {
     failed = 1;
-    const char* msg = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "failed port pick from server: retrying [%s]", msg);
-
+    gpr_log(GPR_DEBUG, "failed port pick from server: retrying [%s]",
+            grpc_error_std_string(error).c_str());
   } else if (response->status != 200) {
     failed = 1;
     gpr_log(GPR_DEBUG, "failed port pick from server: status=%d",
index b465b75..bf3f621 100644 (file)
@@ -33,7 +33,7 @@ gpr_once g_resolve_localhost_ipv46 = GPR_ONCE_INIT;
 
 void InitResolveLocalhost() {
   grpc_resolved_addresses* addresses;
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_blocking_resolve_address("localhost", "https", &addresses);
   GPR_ASSERT(err == GRPC_ERROR_NONE);
   for (size_t i = 0; i < addresses->naddrs; i++) {
index 32645ae..452212e 100644 (file)
@@ -1,20 +1,18 @@
-/*
- *
- * 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.
- *
- */
+//
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 
 #include "test/core/util/test_lb_policies.h"
 
@@ -50,14 +48,14 @@ class ForwardingLoadBalancingPolicy : public LoadBalancingPolicy {
  public:
   ForwardingLoadBalancingPolicy(
       std::unique_ptr<ChannelControlHelper> delegating_helper, Args args,
-      const std::string& delegate_policy_name, intptr_t initial_refcount = 1)
+      const char* delegate_policy_name, intptr_t initial_refcount = 1)
       : LoadBalancingPolicy(std::move(args), initial_refcount) {
     Args delegate_args;
     delegate_args.work_serializer = work_serializer();
     delegate_args.channel_control_helper = std::move(delegating_helper);
     delegate_args.args = args.args;
     delegate_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
-        delegate_policy_name.c_str(), std::move(delegate_args));
+        delegate_policy_name, std::move(delegate_args));
     grpc_pollset_set_add_pollset_set(delegate_->interested_parties(),
                                      interested_parties());
   }
@@ -99,11 +97,11 @@ constexpr char kTestPickArgsLbPolicyName[] = "test_pick_args_lb";
 
 class TestPickArgsLb : public ForwardingLoadBalancingPolicy {
  public:
-  TestPickArgsLb(Args args, TestPickArgsCallback cb)
+  TestPickArgsLb(Args args, TestPickArgsCallback cb,
+                 const char* delegate_policy_name)
       : ForwardingLoadBalancingPolicy(
             absl::make_unique<Helper>(RefCountedPtr<TestPickArgsLb>(this), cb),
-            std::move(args),
-            /*delegate_policy_name=*/"pick_first",
+            std::move(args), delegate_policy_name,
             /*initial_refcount=*/2) {}
 
   ~TestPickArgsLb() override = default;
@@ -171,23 +169,26 @@ class TestPickArgsLbConfig : public LoadBalancingPolicy::Config {
 
 class TestPickArgsLbFactory : public LoadBalancingPolicyFactory {
  public:
-  explicit TestPickArgsLbFactory(TestPickArgsCallback cb)
-      : cb_(std::move(cb)) {}
+  explicit TestPickArgsLbFactory(TestPickArgsCallback cb,
+                                 const char* delegate_policy_name)
+      : cb_(std::move(cb)), delegate_policy_name_(delegate_policy_name) {}
 
   OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
       LoadBalancingPolicy::Args args) const override {
-    return MakeOrphanable<TestPickArgsLb>(std::move(args), cb_);
+    return MakeOrphanable<TestPickArgsLb>(std::move(args), cb_,
+                                          delegate_policy_name_);
   }
 
   const char* name() const override { return kTestPickArgsLbPolicyName; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& /*json*/, grpc_error** /*error*/) const override {
+      const Json& /*json*/, grpc_error_handle* /*error*/) const override {
     return MakeRefCounted<TestPickArgsLbConfig>();
   }
 
  private:
   TestPickArgsCallback cb_;
+  const char* delegate_policy_name_;
 };
 
 //
@@ -279,7 +280,7 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy
     TrailingMetadataHandler(PickResult* result,
                             InterceptRecvTrailingMetadataCallback cb)
         : cb_(std::move(cb)) {
-      result->recv_trailing_metadata_ready = [this](grpc_error* error,
+      result->recv_trailing_metadata_ready = [this](grpc_error_handle error,
                                                     MetadataInterface* metadata,
                                                     CallState* call_state) {
         RecordRecvTrailingMetadata(error, metadata, call_state);
@@ -287,7 +288,7 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy
     }
 
    private:
-    void RecordRecvTrailingMetadata(grpc_error* /*error*/,
+    void RecordRecvTrailingMetadata(grpc_error_handle /*error*/,
                                     MetadataInterface* recv_trailing_metadata,
                                     CallState* call_state) {
       TrailingMetadataArgsSeen args_seen;
@@ -325,7 +326,7 @@ class InterceptTrailingFactory : public LoadBalancingPolicyFactory {
   }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& /*json*/, grpc_error** /*error*/) const override {
+      const Json& /*json*/, grpc_error_handle* /*error*/) const override {
     return MakeRefCounted<InterceptTrailingConfig>();
   }
 
@@ -406,7 +407,7 @@ class AddressTestFactory : public LoadBalancingPolicyFactory {
   const char* name() const override { return kAddressTestLbPolicyName; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& /*json*/, grpc_error** /*error*/) const override {
+      const Json& /*json*/, grpc_error_handle* /*error*/) const override {
     return MakeRefCounted<AddressTestConfig>();
   }
 
@@ -416,9 +417,11 @@ class AddressTestFactory : public LoadBalancingPolicyFactory {
 
 }  // namespace
 
-void RegisterTestPickArgsLoadBalancingPolicy(TestPickArgsCallback cb) {
+void RegisterTestPickArgsLoadBalancingPolicy(TestPickArgsCallback cb,
+                                             const char* delegate_policy_name) {
   LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory(
-      absl::make_unique<TestPickArgsLbFactory>(std::move(cb)));
+      absl::make_unique<TestPickArgsLbFactory>(std::move(cb),
+                                               delegate_policy_name));
 }
 
 void RegisterInterceptRecvTrailingMetadataLoadBalancingPolicy(
index e125bb8..e583abc 100644 (file)
@@ -1,20 +1,18 @@
-/*
- *
- * 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.
- *
- */
+//
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 
 #ifndef GRPC_TEST_CORE_UTIL_TEST_LB_POLICIES_H
 #define GRPC_TEST_CORE_UTIL_TEST_LB_POLICIES_H
@@ -32,9 +30,10 @@ struct PickArgsSeen {
 
 using TestPickArgsCallback = std::function<void(const PickArgsSeen&)>;
 
-// Registers an LB policy called "test_pick_args_lb" that checks the args
-// passed to SubchannelPicker::Pick().
-void RegisterTestPickArgsLoadBalancingPolicy(TestPickArgsCallback cb);
+// Registers an LB policy called "test_pick_args_lb" that passes the args
+// passed to SubchannelPicker::Pick() to cb.
+void RegisterTestPickArgsLoadBalancingPolicy(
+    TestPickArgsCallback cb, const char* delegate_policy_name = "pick_first");
 
 struct TrailingMetadataArgsSeen {
   const LoadBalancingPolicy::BackendMetricData* backend_metric_data;
index 9dd1e2a..0004369 100644 (file)
@@ -34,7 +34,7 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
-static void on_server_destroyed(void* data, grpc_error* /*error*/) {
+static void on_server_destroyed(void* data, grpc_error_handle /*error*/) {
   test_tcp_server* server = static_cast<test_tcp_server*>(data);
   server->shutdown = true;
 }
@@ -64,8 +64,8 @@ void test_tcp_server_start(test_tcp_server* server, int port) {
   addr->sin_port = grpc_htons(static_cast<uint16_t>(port));
   memset(&addr->sin_addr, 0, sizeof(addr->sin_addr));
 
-  grpc_error* error = grpc_tcp_server_create(&server->shutdown_complete,
-                                             nullptr, &server->tcp_server);
+  grpc_error_handle error = grpc_tcp_server_create(
+      &server->shutdown_complete, nullptr, &server->tcp_server);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   error =
       grpc_tcp_server_add_port(server->tcp_server, &resolved_addr, &port_added);
@@ -88,8 +88,8 @@ void test_tcp_server_poll(test_tcp_server* server, int milliseconds) {
   gpr_mu_unlock(server->mu);
 }
 
-static void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
-static void finish_pollset(void* arg, grpc_error* /*error*/) {
+static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
+static void finish_pollset(void* arg, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(arg));
 }
 
index 603b51a..5b5199b 100644 (file)
@@ -41,7 +41,7 @@ typedef struct {
   gpr_mu mu;
   grpc_slice_buffer write_buffer;
   grpc_slice_buffer writing_buffer;
-  grpc_error* error;
+  grpc_error_handle error;
   bool writing;
   grpc_closure* write_cb;
 } trickle_endpoint;
@@ -96,7 +96,7 @@ static void te_delete_from_pollset_set(grpc_endpoint* ep,
   grpc_endpoint_delete_from_pollset_set(te->wrapped, pollset_set);
 }
 
-static void te_shutdown(grpc_endpoint* ep, grpc_error* why) {
+static void te_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   gpr_mu_lock(&te->mu);
   if (te->error == GRPC_ERROR_NONE) {
@@ -139,7 +139,7 @@ static int te_get_fd(grpc_endpoint* ep) {
 
 static bool te_can_track_err(grpc_endpoint* /*ep*/) { return false; }
 
-static void te_finish_write(void* arg, grpc_error* /*error*/) {
+static void te_finish_write(void* arg, grpc_error_handle /*error*/) {
   trickle_endpoint* te = static_cast<trickle_endpoint*>(arg);
   gpr_mu_lock(&te->mu);
   te->writing = false;
index 6df39ff..211e46e 100644 (file)
@@ -58,7 +58,7 @@ class FakeCertificateProviderFactory1 : public CertificateProviderFactory {
 
   RefCountedPtr<CertificateProviderFactory::Config>
   CreateCertificateProviderConfig(const Json& /*config_json*/,
-                                  grpc_error** /*error*/) override {
+                                  grpc_error_handle* /*error*/) override {
     return MakeRefCounted<Config>();
   }
 
@@ -81,7 +81,7 @@ class FakeCertificateProviderFactory2 : public CertificateProviderFactory {
 
   RefCountedPtr<CertificateProviderFactory::Config>
   CreateCertificateProviderConfig(const Json& /*config_json*/,
-                                  grpc_error** /*error*/) override {
+                                  grpc_error_handle* /*error*/) override {
     return MakeRefCounted<Config>();
   }
 
index 0ecb012..5157634 100644 (file)
@@ -45,12 +45,12 @@ TEST(FileWatcherConfigTest, Basic) {
       "  \"refresh_interval\": \"%ds\""
       "}",
       kIdentityCertFile, kPrivateKeyFile, kRootCertFile, kRefreshInterval);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       FileWatcherCertificateProviderFactory::Config::Parse(json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(config->identity_cert_file(), kIdentityCertFile);
   EXPECT_EQ(config->private_key_file(), kPrivateKeyFile);
   EXPECT_EQ(config->root_cert_file(), kRootCertFile);
@@ -65,12 +65,12 @@ TEST(FileWatcherConfigTest, DefaultRefreshInterval) {
       "  \"ca_certificate_file\": \"%s\""
       "}",
       kIdentityCertFile, kPrivateKeyFile, kRootCertFile);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       FileWatcherCertificateProviderFactory::Config::Parse(json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(config->identity_cert_file(), kIdentityCertFile);
   EXPECT_EQ(config->private_key_file(), kPrivateKeyFile);
   EXPECT_EQ(config->root_cert_file(), kRootCertFile);
@@ -83,12 +83,12 @@ TEST(FileWatcherConfigTest, OnlyRootCertificatesFileProvided) {
       "  \"ca_certificate_file\": \"%s\""
       "}",
       kRootCertFile);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       FileWatcherCertificateProviderFactory::Config::Parse(json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_TRUE(config->identity_cert_file().empty());
   EXPECT_TRUE(config->private_key_file().empty());
   EXPECT_EQ(config->root_cert_file(), kRootCertFile);
@@ -102,12 +102,12 @@ TEST(FileWatcherConfigTest, OnlyIdenityCertificatesAndPrivateKeyProvided) {
       "  \"private_key_file\": \"%s\""
       "}",
       kIdentityCertFile, kPrivateKeyFile);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       FileWatcherCertificateProviderFactory::Config::Parse(json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(config->identity_cert_file(), kIdentityCertFile);
   EXPECT_EQ(config->private_key_file(), kPrivateKeyFile);
   EXPECT_TRUE(config->root_cert_file().empty());
@@ -122,12 +122,12 @@ TEST(FileWatcherConfigTest, WrongTypes) {
       "  \"ca_certificate_file\": 123,"
       "  \"refresh_interval\": 123"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       FileWatcherCertificateProviderFactory::Config::Parse(json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "field:certificate_file error:type should be STRING.*"
                   "field:private_key_file error:type should be STRING.*"
@@ -144,12 +144,12 @@ TEST(FileWatcherConfigTest, IdentityCertProvidedButPrivateKeyMissing) {
       "  \"certificate_file\": \"%s\""
       "}",
       kIdentityCertFile);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       FileWatcherCertificateProviderFactory::Config::Parse(json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "fields \"certificate_file\" and \"private_key_file\" must "
                   "be both set or both unset."));
@@ -162,12 +162,12 @@ TEST(FileWatcherConfigTest, PrivateKeyProvidedButIdentityCertMissing) {
       "  \"private_key_file\": \"%s\""
       "}",
       kPrivateKeyFile);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       FileWatcherCertificateProviderFactory::Config::Parse(json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "fields \"certificate_file\" and \"private_key_file\" must "
                   "be both set or both unset."));
@@ -176,13 +176,13 @@ TEST(FileWatcherConfigTest, PrivateKeyProvidedButIdentityCertMissing) {
 
 TEST(FileWatcherConfigTest, EmptyJsonObject) {
   std::string json_str = absl::StrFormat("{}");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       FileWatcherCertificateProviderFactory::Config::Parse(json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("At least one of \"certificate_file\" and "
                                "\"ca_certificate_file\" must be specified."));
   GRPC_ERROR_UNREF(error);
index 8d336c3..bf72df2 100644 (file)
@@ -67,12 +67,12 @@ TEST(GoogleMeshCaConfigTest, Basic) {
       "\"https://container.googleapis.com/v1/project/test-project1/locations/"
       "test-zone2/clusters/test-cluster3\""
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(config->endpoint(), "newmeshca.googleapis.com");
   EXPECT_EQ(config->sts_config().token_exchange_service_uri,
             "newsecuretoken.googleapis.com");
@@ -120,12 +120,12 @@ TEST(GoogleMeshCaConfigTest, Defaults) {
       "\"https://container.googleapis.com/v1/project/test-project1/locations/"
       "test-zone2/clusters/test-cluster3\""
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(config->endpoint(), "meshca.googleapis.com");
   EXPECT_EQ(config->sts_config().token_exchange_service_uri,
             "securetoken.googleapis.com");
@@ -172,13 +172,13 @@ TEST(GoogleMeshCaConfigTest, WrongExpectedValues) {
       "\"https://container.googleapis.com/v1/project/test-project1/locations/"
       "test-zone2/clusters/test-cluster3\""
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("field:api_type error:Only GRPC is supported.*"
                                "field:key_type error:Only RSA is supported"));
   GRPC_ERROR_UNREF(error);
@@ -215,13 +215,13 @@ TEST(GoogleMeshCaConfigTest, WrongTypes) {
       "  \"key_size\": \"1024\","
       "  \"location\": 123"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex(
           "field:server.*field:api_type error:type should be STRING.*"
           "field:grpc_services.*field:google_grpc.*field:target_uri "
@@ -259,13 +259,13 @@ TEST(GoogleMeshCaConfigTest, GrpcServicesNotAnArray) {
       "\"https://container.googleapis.com/v1/project/test-project1/locations/"
       "test-zone2/clusters/test-cluster3\""
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex(
           "field:server.*field:grpc_services error:type should be ARRAY"));
   GRPC_ERROR_UNREF(error);
@@ -284,13 +284,13 @@ TEST(GoogleMeshCaConfigTest, GoogleGrpcNotAnObject) {
       "\"https://container.googleapis.com/v1/project/test-project1/locations/"
       "test-zone2/clusters/test-cluster3\""
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("field:server.*field:grpc_services.*field:"
                                "google_grpc error:type should be OBJECT"));
   GRPC_ERROR_UNREF(error);
@@ -311,12 +311,12 @@ TEST(GoogleMeshCaConfigTest, CallCredentialsNotAnArray) {
       "\"https://container.googleapis.com/v1/project/test-project1/locations/"
       "test-zone2/clusters/test-cluster3\""
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "field:server.*field:grpc_services.*field:google_grpc.*"
                   "field:call_credentials error:type should be ARRAY"));
@@ -340,13 +340,13 @@ TEST(GoogleMeshCaConfigTest, StsServiceNotAnObject) {
       "\"https://container.googleapis.com/v1/project/test-project1/locations/"
       "test-zone2/clusters/test-cluster3\""
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   auto config =
       GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex(
           "field:server.*field:grpc_services.*field:google_grpc.*field:"
           "call_credentials.*field:sts_service error:type should be OBJECT"));
index 29b8277..09c8dd4 100644 (file)
@@ -113,11 +113,11 @@ TEST_P(XdsBootstrapTest, Basic) {
       "  \"server_listener_resource_name_template\": \"example/resource\","
       "  \"ignore\": {}"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
   EXPECT_EQ(bootstrap.server().channel_creds_type, "fake");
   EXPECT_EQ(bootstrap.server().channel_creds_config.type(),
@@ -155,11 +155,11 @@ TEST_P(XdsBootstrapTest, ValidWithoutNode) {
       "    }"
       "  ]"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
   EXPECT_EQ(bootstrap.server().channel_creds_type, "fake");
   EXPECT_EQ(bootstrap.node(), nullptr);
@@ -175,11 +175,11 @@ TEST_P(XdsBootstrapTest, InsecureCreds) {
       "    }"
       "  ]"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
   EXPECT_EQ(bootstrap.server().channel_creds_type, "insecure");
   EXPECT_EQ(bootstrap.node(), nullptr);
@@ -211,11 +211,11 @@ TEST_P(XdsBootstrapTest, GoogleDefaultCreds) {
       "    }"
       "  ]"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
   EXPECT_EQ(bootstrap.server().channel_creds_type, "google_default");
   EXPECT_EQ(bootstrap.node(), nullptr);
@@ -230,11 +230,11 @@ TEST_P(XdsBootstrapTest, MissingChannelCreds) {
       "    }"
       "  ]"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex("\"channel_creds\" field not present"));
   GRPC_ERROR_UNREF(error);
 }
@@ -249,22 +249,22 @@ TEST_P(XdsBootstrapTest, NoKnownChannelCreds) {
       "    }"
       "  ]"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex(
                   "no known creds type found in \"channel_creds\""));
   GRPC_ERROR_UNREF(error);
 }
 
 TEST_P(XdsBootstrapTest, MissingXdsServers) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse("{}", &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex("\"xds_servers\" field not present"));
   GRPC_ERROR_UNREF(error);
 }
@@ -277,17 +277,17 @@ TEST_P(XdsBootstrapTest, TopFieldsWrongTypes) {
       "  \"server_listener_resource_name_template\":1,"
       "  \"certificate_providers\":1"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex("\"xds_servers\" field is not an array.*"
                                        "\"node\" field is not an object.*"
                                        "\"server_listener_resource_name_"
                                        "template\" field is not a string.*"));
   if (GetParam().parse_xds_certificate_providers()) {
-    EXPECT_THAT(grpc_error_string(error),
+    EXPECT_THAT(grpc_error_std_string(error),
                 ::testing::ContainsRegex(
                     "\"certificate_providers\" field is not an object"));
   }
@@ -299,11 +299,11 @@ TEST_P(XdsBootstrapTest, XdsServerMissingServerUri) {
       "{"
       "  \"xds_servers\":[{}]"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
                                        "errors parsing index 0.*"
                                        "\"server_uri\" field not present"));
@@ -320,12 +320,12 @@ TEST_P(XdsBootstrapTest, XdsServerUriAndCredsWrongTypes) {
       "    }"
       "  ]"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
                                "errors parsing index 0.*"
                                "\"server_uri\" field is not a string.*"
@@ -348,12 +348,12 @@ TEST_P(XdsBootstrapTest, ChannelCredsFieldsWrongTypes) {
       "    }"
       "  ]"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
   EXPECT_THAT(
-      grpc_error_string(error),
+      grpc_error_std_string(error),
       ::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
                                "errors parsing index 0.*"
                                "errors parsing \"channel_creds\" array.*"
@@ -373,11 +373,11 @@ TEST_P(XdsBootstrapTest, NodeFieldsWrongTypes) {
       "    \"metadata\":0"
       "  }"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex("errors parsing \"node\" object.*"
                                        "\"id\" field is not a string.*"
                                        "\"cluster\" field is not a string.*"
@@ -397,11 +397,11 @@ TEST_P(XdsBootstrapTest, LocalityFieldsWrongType) {
       "    }"
       "  }"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  EXPECT_THAT(grpc_error_string(error),
+  EXPECT_THAT(grpc_error_std_string(error),
               ::testing::ContainsRegex("errors parsing \"node\" object.*"
                                        "errors parsing \"locality\" object.*"
                                        "\"region\" field is not a string.*"
@@ -423,17 +423,17 @@ TEST_P(XdsBootstrapTest, CertificateProvidersElementWrongType) {
       "    \"plugin\":1"
       "  }"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
   if (GetParam().parse_xds_certificate_providers()) {
-    EXPECT_THAT(grpc_error_string(error),
+    EXPECT_THAT(grpc_error_std_string(error),
                 ::testing::ContainsRegex(
                     "errors parsing \"certificate_providers\" object.*"
                     "element \"plugin\" is not an object"));
   } else {
-    EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+    EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   }
   GRPC_ERROR_UNREF(error);
 }
@@ -453,18 +453,18 @@ TEST_P(XdsBootstrapTest, CertificateProvidersPluginNameWrongType) {
       "    }"
       "  }"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
   if (GetParam().parse_xds_certificate_providers()) {
-    EXPECT_THAT(grpc_error_string(error),
+    EXPECT_THAT(grpc_error_std_string(error),
                 ::testing::ContainsRegex(
                     "errors parsing \"certificate_providers\" object.*"
                     "errors parsing element \"plugin\".*"
                     "\"plugin_name\" field is not a string"));
   } else {
-    EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+    EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   }
   GRPC_ERROR_UNREF(error);
 }
@@ -495,8 +495,8 @@ class FakeCertificateProviderFactory : public CertificateProviderFactory {
 
   RefCountedPtr<CertificateProviderFactory::Config>
   CreateCertificateProviderConfig(const Json& config_json,
-                                  grpc_error** error) override {
-    std::vector<grpc_error*> error_list;
+                                  grpc_error_handle* error) override {
+    std::vector<grpc_error_handle> error_list;
     EXPECT_EQ(config_json.type(), Json::Type::OBJECT);
     auto it = config_json.object_value().find("value");
     if (it == config_json.object_value().end()) {
@@ -538,18 +538,18 @@ TEST_P(XdsBootstrapTest, CertificateProvidersFakePluginParsingError) {
       "    }"
       "  }"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
   if (GetParam().parse_xds_certificate_providers()) {
-    EXPECT_THAT(grpc_error_string(error),
+    EXPECT_THAT(grpc_error_std_string(error),
                 ::testing::ContainsRegex(
                     "errors parsing \"certificate_providers\" object.*"
                     "errors parsing element \"fake_plugin\".*"
                     "field:config field:value not of type number"));
   } else {
-    EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+    EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   }
   GRPC_ERROR_UNREF(error);
 }
@@ -574,11 +574,11 @@ TEST_P(XdsBootstrapTest, CertificateProvidersFakePluginParsingSuccess) {
       "    }"
       "  }"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  ASSERT_TRUE(error == GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_TRUE(error == GRPC_ERROR_NONE) << grpc_error_std_string(error);
   if (GetParam().parse_xds_certificate_providers()) {
     const CertificateProviderStore::PluginDefinition& fake_plugin =
         bootstrap.certificate_providers().at("fake_plugin");
@@ -611,11 +611,11 @@ TEST_P(XdsBootstrapTest, CertificateProvidersFakePluginEmptyConfig) {
       "    }"
       "  }"
       "}";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_str, &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   XdsBootstrap bootstrap(std::move(json), &error);
-  ASSERT_TRUE(error == GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_TRUE(error == GRPC_ERROR_NONE) << grpc_error_std_string(error);
   if (GetParam().parse_xds_certificate_providers()) {
     const CertificateProviderStore::PluginDefinition& fake_plugin =
         bootstrap.certificate_providers().at("fake_plugin");
index 8f6c8f3..32e2bcb 100644 (file)
@@ -73,8 +73,8 @@ class TestCertificatesWatcher
     }
   }
 
-  void OnError(grpc_error* root_cert_error,
-               grpc_error* identity_cert_error) override {
+  void OnError(grpc_error_handle root_cert_error,
+               grpc_error_handle identity_cert_error) override {
     GRPC_ERROR_UNREF(root_cert_error_);
     root_cert_error_ = root_cert_error;
     GRPC_ERROR_UNREF(identity_cert_error_);
@@ -87,15 +87,15 @@ class TestCertificatesWatcher
     return key_cert_pairs_;
   }
 
-  grpc_error* root_cert_error() const { return root_cert_error_; }
+  grpc_error_handle root_cert_error() const { return root_cert_error_; }
 
-  grpc_error* identity_cert_error() const { return identity_cert_error_; }
+  grpc_error_handle identity_cert_error() const { return identity_cert_error_; }
 
  private:
   absl::optional<std::string> root_certs_;
   absl::optional<PemKeyCertPairList> key_cert_pairs_;
-  grpc_error* root_cert_error_ = GRPC_ERROR_NONE;
-  grpc_error* identity_cert_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle root_cert_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle identity_cert_error_ = GRPC_ERROR_NONE;
 };
 
 TEST(
@@ -149,16 +149,16 @@ TEST(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_EQ(watcher->root_certs(), kRootCert2);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(kRootErrorMessage));
-  EXPECT_THAT(grpc_error_string(watcher->identity_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->identity_cert_error()),
               ::testing::HasSubstr(kIdentityErrorMessage));
   // Send an update for root certs. Test that the root cert error is reset.
   root_cert_distributor->SetKeyMaterials("root", kRootCert1, absl::nullopt);
   EXPECT_EQ(watcher->root_certs(), kRootCert1);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
   EXPECT_EQ(watcher->root_cert_error(), GRPC_ERROR_NONE);
-  EXPECT_THAT(grpc_error_string(watcher->identity_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->identity_cert_error()),
               ::testing::HasSubstr(kIdentityErrorMessage));
   // Send an update for identity certs. Test that the identity cert error is
   // reset.
@@ -217,16 +217,16 @@ TEST(XdsCertificateProviderTest,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_EQ(watcher->root_certs(), kRootCert2);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(kRootErrorMessage));
-  EXPECT_THAT(grpc_error_string(watcher->identity_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->identity_cert_error()),
               ::testing::HasSubstr(kIdentityErrorMessage));
   // Send an update for root certs. Test that the root cert error is reset.
   root_cert_distributor->SetKeyMaterials("test", kRootCert1, absl::nullopt);
   EXPECT_EQ(watcher->root_certs(), kRootCert1);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
   EXPECT_EQ(watcher->root_cert_error(), GRPC_ERROR_NONE);
-  EXPECT_THAT(grpc_error_string(watcher->identity_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->identity_cert_error()),
               ::testing::HasSubstr(kIdentityErrorMessage));
   // Send an update for identity certs. Test that the identity cert error is
   // reset.
@@ -281,7 +281,7 @@ TEST(XdsCertificateProviderTest,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage));
   EXPECT_EQ(watcher->root_certs(), kRootCert2);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(kRootErrorMessage));
   EXPECT_EQ(watcher->identity_cert_error(), GRPC_ERROR_NONE);
   distributor->SetErrorForCert(
@@ -289,16 +289,16 @@ TEST(XdsCertificateProviderTest,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_EQ(watcher->root_certs(), kRootCert2);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(kRootErrorMessage));
-  EXPECT_THAT(grpc_error_string(watcher->identity_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->identity_cert_error()),
               ::testing::HasSubstr(kIdentityErrorMessage));
   // Send an update for root
   distributor->SetKeyMaterials("root", kRootCert1, MakeKeyCertPairsType1());
   EXPECT_EQ(watcher->root_certs(), kRootCert1);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
   EXPECT_EQ(watcher->root_cert_error(), GRPC_ERROR_NONE);
-  EXPECT_THAT(grpc_error_string(watcher->identity_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->identity_cert_error()),
               ::testing::HasSubstr(kIdentityErrorMessage));
   // Send an update for identity
   distributor->SetKeyMaterials("identity", kRootCert2, MakeKeyCertPairsType1());
@@ -345,7 +345,7 @@ TEST(XdsCertificateProviderTest,
       absl::nullopt);
   EXPECT_EQ(watcher->root_certs(), kRootCert2);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(kRootErrorMessage));
   EXPECT_EQ(watcher->identity_cert_error(), GRPC_ERROR_NONE);
   // Set error for identity
@@ -354,16 +354,16 @@ TEST(XdsCertificateProviderTest,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_EQ(watcher->root_certs(), kRootCert2);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(kRootErrorMessage));
-  EXPECT_THAT(grpc_error_string(watcher->identity_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->identity_cert_error()),
               ::testing::HasSubstr(kIdentityErrorMessage));
   // Send an update for root
   distributor->SetKeyMaterials("", kRootCert1, absl::nullopt);
   EXPECT_EQ(watcher->root_certs(), kRootCert1);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
   EXPECT_EQ(watcher->root_cert_error(), GRPC_ERROR_NONE);
-  EXPECT_THAT(grpc_error_string(watcher->identity_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->identity_cert_error()),
               ::testing::HasSubstr(kIdentityErrorMessage));
   // Send an update for identity
   distributor->SetKeyMaterials("", absl::nullopt, MakeKeyCertPairsType1());
@@ -383,11 +383,11 @@ TEST(XdsCertificateProviderTest, SwapOutDistributorsMultipleTimes) {
   // Initially there are no certificate providers.
   EXPECT_EQ(watcher->root_certs(), absl::nullopt);
   EXPECT_EQ(watcher->key_cert_pairs(), absl::nullopt);
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(
                   "No certificate provider available for root certificates"));
   EXPECT_THAT(
-      grpc_error_string(watcher->identity_cert_error()),
+      grpc_error_std_string(watcher->identity_cert_error()),
       ::testing::HasSubstr(
           "No certificate provider available for identity certificates"));
   // Update root cert distributor.
@@ -396,7 +396,7 @@ TEST(XdsCertificateProviderTest, SwapOutDistributorsMultipleTimes) {
   EXPECT_EQ(watcher->key_cert_pairs(), absl::nullopt);
   EXPECT_EQ(watcher->root_cert_error(), GRPC_ERROR_NONE);
   EXPECT_THAT(
-      grpc_error_string(watcher->identity_cert_error()),
+      grpc_error_std_string(watcher->identity_cert_error()),
       ::testing::HasSubstr(
           "No certificate provider available for identity certificates"));
   // Update identity cert distributor
@@ -417,9 +417,9 @@ TEST(XdsCertificateProviderTest, SwapOutDistributorsMultipleTimes) {
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_EQ(watcher->root_certs(), kRootCert2);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(kRootErrorMessage));
-  EXPECT_THAT(grpc_error_string(watcher->identity_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->identity_cert_error()),
               ::testing::HasSubstr(kIdentityErrorMessage));
   // Send an update again
   distributor->SetKeyMaterials("", kRootCert1, MakeKeyCertPairsType1());
@@ -432,7 +432,7 @@ TEST(XdsCertificateProviderTest, SwapOutDistributorsMultipleTimes) {
   distributor->SetKeyMaterials("", kRootCert2, MakeKeyCertPairsType2());
   EXPECT_EQ(watcher->root_certs(), kRootCert1);  // not updated
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(
                   "No certificate provider available for root certificates"));
   EXPECT_EQ(watcher->identity_cert_error(), GRPC_ERROR_NONE);
@@ -441,11 +441,11 @@ TEST(XdsCertificateProviderTest, SwapOutDistributorsMultipleTimes) {
   distributor->SetKeyMaterials("", kRootCert1, MakeKeyCertPairsType1());
   EXPECT_EQ(watcher->root_certs(), kRootCert1);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());  // not updated
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(
                   "No certificate provider available for root certificates"));
   EXPECT_THAT(
-      grpc_error_string(watcher->identity_cert_error()),
+      grpc_error_std_string(watcher->identity_cert_error()),
       ::testing::HasSubstr(
           "No certificate provider available for identity certificates"));
   // Change certificate names being watched, without any certificate updates.
@@ -453,11 +453,11 @@ TEST(XdsCertificateProviderTest, SwapOutDistributorsMultipleTimes) {
   provider.UpdateIdentityCertNameAndDistributor("", "identity", distributor);
   EXPECT_EQ(watcher->root_certs(), kRootCert1);
   EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(
                   "No certificate provider available for root certificates"));
   EXPECT_THAT(
-      grpc_error_string(watcher->identity_cert_error()),
+      grpc_error_std_string(watcher->identity_cert_error()),
       ::testing::HasSubstr(
           "No certificate provider available for identity certificates"));
   // Send out certificate updates.
@@ -509,11 +509,11 @@ TEST(XdsCertificateProviderTest, MultipleCertNames) {
       std::unique_ptr<TestCertificatesWatcher>(watcher1), "test1", "test1");
   EXPECT_EQ(watcher1->root_certs(), absl::nullopt);
   EXPECT_EQ(watcher1->key_cert_pairs(), absl::nullopt);
-  EXPECT_THAT(grpc_error_string(watcher1->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher1->root_cert_error()),
               ::testing::HasSubstr(
                   "No certificate provider available for root certificates"));
   EXPECT_THAT(
-      grpc_error_string(watcher1->identity_cert_error()),
+      grpc_error_std_string(watcher1->identity_cert_error()),
       ::testing::HasSubstr(
           "No certificate provider available for identity certificates"));
   // Add distributor for "test1".  This will return data to the watcher.
@@ -557,11 +557,11 @@ TEST(XdsCertificateProviderTest, UnknownCertName) {
   auto* watcher = new TestCertificatesWatcher;
   provider.distributor()->WatchTlsCertificates(
       std::unique_ptr<TestCertificatesWatcher>(watcher), "test", "test");
-  EXPECT_THAT(grpc_error_string(watcher->root_cert_error()),
+  EXPECT_THAT(grpc_error_std_string(watcher->root_cert_error()),
               ::testing::HasSubstr(
                   "No certificate provider available for root certificates"));
   EXPECT_THAT(
-      grpc_error_string(watcher->identity_cert_error()),
+      grpc_error_std_string(watcher->identity_cert_error()),
       ::testing::HasSubstr(
           "No certificate provider available for identity certificates"));
 }
index 011dd4f..a3c5ed2 100644 (file)
@@ -41,9 +41,9 @@
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h"
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/thd.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/transport/authority_override.h"
 
@@ -242,7 +242,7 @@ class ClientChannelStressTest {
   static grpc_core::Resolver::Result MakeResolverResult(
       const std::vector<AddressData>& balancer_address_data) {
     grpc_core::Resolver::Result result;
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     result.service_config = grpc_core::ServiceConfig::Create(
         nullptr, "{\"loadBalancingConfig\":[{\"grpclb\":{}}]}", &error);
     GPR_ASSERT(error == GRPC_ERROR_NONE);
index f58db7e..ab458d4 100644 (file)
@@ -40,9 +40,9 @@
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h"
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/thd.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 
 #include "test/core/util/port.h"
@@ -68,10 +68,10 @@ void TryConnectAndDestroy() {
   grpc_core::ServerAddressList addresses;
   addresses.emplace_back(address.addr, address.len, nullptr);
   grpc_core::Resolver::Result lb_address_result;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   lb_address_result.service_config = grpc_core::ServiceConfig::Create(
       nullptr, "{\"loadBalancingConfig\":[{\"grpclb\":{}}]}", &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   grpc_arg arg = grpc_core::CreateGrpclbBalancerAddressesArg(&addresses);
   lb_address_result.args = grpc_channel_args_copy_and_add(nullptr, &arg, 1);
   response_generator->SetResponse(lb_address_result);
index 2bcd72d..6662d78 100644 (file)
@@ -165,7 +165,7 @@ class ServiceA final {
   };
   class Stub final : public StubInterface {
    public:
-    Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);
+    Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
     ::grpc::Status MethodA1(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::testing::Response* response) override;
     std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>> AsyncMethodA1(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) {
       return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>>(AsyncMethodA1Raw(context, request, cq));
@@ -922,7 +922,7 @@ class ServiceB final {
   };
   class Stub final : public StubInterface {
    public:
-    Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);
+    Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
     ::grpc::Status MethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::testing::Response* response) override;
     std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>> AsyncMethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) {
       return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>>(AsyncMethodB1Raw(context, request, cq));
index 230737e..c077930 100644 (file)
@@ -28,8 +28,8 @@ class MyChannelData : public ChannelData {
  public:
   MyChannelData() {}
 
-  grpc_error* Init(grpc_channel_element* /*elem*/,
-                   grpc_channel_element_args* args) override {
+  grpc_error_handle Init(grpc_channel_element* /*elem*/,
+                         grpc_channel_element_args* args) override {
     (void)args->channel_args;  // Make sure field is available.
     return GRPC_ERROR_NONE;
   }
@@ -39,8 +39,8 @@ class MyCallData : public CallData {
  public:
   MyCallData() {}
 
-  grpc_error* Init(grpc_call_element* /*elem*/,
-                   const grpc_call_element_args* args) override {
+  grpc_error_handle Init(grpc_call_element* /*elem*/,
+                         const grpc_call_element_args* args) override {
     (void)args->path;  // Make sure field is available.
     return GRPC_ERROR_NONE;
   }
index 4836905..f6ff40f 100644 (file)
@@ -90,7 +90,7 @@ TEST_P(TimeJumpTest, TimerRunning) {
   grpc_timer timer;
   grpc_timer_init(&timer, grpc_core::ExecCtx::Get()->Now() + 3000,
                   GRPC_CLOSURE_CREATE(
-                      [](void*, grpc_error* error) {
+                      [](void*, grpc_error_handle error) {
                         GPR_ASSERT(error == GRPC_ERROR_CANCELLED);
                       },
                       nullptr, grpc_schedule_on_exec_ctx));
index 63c0757..dca0215 100644 (file)
@@ -84,7 +84,7 @@ TEST_F(TimerTest, OneTimerExpires) {
   int timer_fired = 0;
   grpc_timer_init(&timer, grpc_core::ExecCtx::Get()->Now() + 500,
                   GRPC_CLOSURE_CREATE(
-                      [](void* arg, grpc_error*) {
+                      [](void* arg, grpc_error_handle) {
                         int* timer_fired = static_cast<int*>(arg);
                         ++*timer_fired;
                       },
@@ -109,7 +109,7 @@ TEST_F(TimerTest, MultipleTimersExpire) {
   for (int i = 0; i < kNumTimers; ++i) {
     grpc_timer_init(&timers[i], grpc_core::ExecCtx::Get()->Now() + 500 + i,
                     GRPC_CLOSURE_CREATE(
-                        [](void* arg, grpc_error*) {
+                        [](void* arg, grpc_error_handle) {
                           int* timer_fired = static_cast<int*>(arg);
                           ++*timer_fired;
                         },
@@ -136,7 +136,7 @@ TEST_F(TimerTest, CancelSomeTimers) {
   for (int i = 0; i < kNumTimers; ++i) {
     grpc_timer_init(&timers[i], grpc_core::ExecCtx::Get()->Now() + 500 + i,
                     GRPC_CLOSURE_CREATE(
-                        [](void* arg, grpc_error* error) {
+                        [](void* arg, grpc_error_handle error) {
                           if (error == GRPC_ERROR_CANCELLED) {
                             return;
                           }
@@ -166,7 +166,7 @@ TEST_F(TimerTest, DISABLED_TimerNotCanceled) {
   grpc_core::ExecCtx exec_ctx;
   grpc_timer timer;
   grpc_timer_init(&timer, grpc_core::ExecCtx::Get()->Now() + 10000,
-                  GRPC_CLOSURE_CREATE([](void*, grpc_error*) {}, nullptr,
+                  GRPC_CLOSURE_CREATE([](void*, grpc_error_handle) {}, nullptr,
                                       grpc_schedule_on_exec_ctx));
 }
 
@@ -181,7 +181,7 @@ TEST_F(TimerTest, DISABLED_CancelRace) {
     grpc_timer* arg = (i != 0) ? &timers[i - 1] : nullptr;
     grpc_timer_init(&timers[i], grpc_core::ExecCtx::Get()->Now() + 100,
                     GRPC_CLOSURE_CREATE(
-                        [](void* arg, grpc_error* /*error*/) {
+                        [](void* arg, grpc_error_handle /*error*/) {
                           grpc_timer* timer = static_cast<grpc_timer*>(arg);
                           if (timer) {
                             grpc_timer_cancel(timer);
@@ -211,7 +211,7 @@ TEST_F(TimerTest, DISABLED_CancelNextTimer) {
     }
     grpc_timer_init(&timers[i], grpc_core::ExecCtx::Get()->Now() + 100,
                     GRPC_CLOSURE_CREATE(
-                        [](void* arg, grpc_error* /*error*/) {
+                        [](void* arg, grpc_error_handle /*error*/) {
                           grpc_timer* timer = static_cast<grpc_timer*>(arg);
                           if (timer) {
                             grpc_timer_cancel(timer);
index cdd40fa..af4fc4e 100644 (file)
@@ -12,9 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-licenses(["notice"])
+load("//bazel:grpc_build_system.bzl", "grpc_cc_binary", "grpc_cc_library", "grpc_cc_test", "grpc_package")
 
-load("//bazel:grpc_build_system.bzl", "grpc_cc_binary", "grpc_cc_library", "grpc_cc_test", "grpc_cc_test_xds", "grpc_package")
+licenses(["notice"])
 
 grpc_package(
     name = "test/cpp/end2end",
@@ -510,7 +510,7 @@ grpc_cc_test(
     ],
 )
 
-grpc_cc_test_xds(
+grpc_cc_test(
     name = "xds_end2end_test",
     size = "large",
     srcs = ["xds_end2end_test.cc"],
@@ -874,7 +874,7 @@ grpc_cc_test(
     ],
 )
 
-grpc_cc_test_xds(
+grpc_cc_test(
     name = "admin_services_end2end_test",
     srcs = ["admin_services_end2end_test.cc"],
     external_deps = [
index 31fc7f3..4d9c389 100644 (file)
@@ -28,7 +28,6 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
-#ifndef DISABLED_XDS_PROTO_IN_CC
 #include <grpcpp/ext/admin_services.h>
 
 namespace grpc {
@@ -73,32 +72,28 @@ class AdminServicesTest : public ::testing::Test {
       stream_;
 };
 
-#ifndef GRPC_NO_XDS
-// The ifndef conflicts with TEST_F and EXPECT_THAT macros, so we better isolate
-// the condition at test case level.
-TEST_F(AdminServicesTest, XdsEnabled) {
+TEST_F(AdminServicesTest, ValidateRegisteredServices) {
+  // Using Contains here, because the server builder might register other
+  // services in certain environments.
+  EXPECT_THAT(
+      GetServiceList(),
+      ::testing::AllOf(
+          ::testing::Contains("grpc.channelz.v1.Channelz"),
+          ::testing::Contains("grpc.reflection.v1alpha.ServerReflection")));
+#if defined(GRPC_NO_XDS) || defined(DISABLED_XDS_PROTO_IN_CC)
   EXPECT_THAT(GetServiceList(),
-              ::testing::UnorderedElementsAre(
-                  "envoy.service.status.v3.ClientStatusDiscoveryService",
-                  "grpc.channelz.v1.Channelz",
-                  "grpc.reflection.v1alpha.ServerReflection"));
-}
-#endif  // GRPC_NO_XDS
-
-#ifdef GRPC_NO_XDS
-TEST_F(AdminServicesTest, XdsDisabled) {
+              ::testing::Not(::testing::Contains(
+                  "envoy.service.status.v3.ClientStatusDiscoveryService")));
+#else
   EXPECT_THAT(GetServiceList(),
-              ::testing::UnorderedElementsAre(
-                  "grpc.channelz.v1.Channelz",
-                  "grpc.reflection.v1alpha.ServerReflection"));
+              ::testing::Contains(
+                  "envoy.service.status.v3.ClientStatusDiscoveryService"));
+#endif  // GRPC_NO_XDS or DISABLED_XDS_PROTO_IN_CC
 }
-#endif  // GRPC_NO_XDS
 
 }  // namespace testing
 }  // namespace grpc
 
-#endif  // DISABLED_XDS_PROTO_IN_CC
-
 int main(int argc, char** argv) {
   grpc::testing::TestEnvironment env(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
index 573b15f..45f30eb 100644 (file)
@@ -121,10 +121,14 @@ class ClientCallbackEnd2endTest
     is_server_started_ = true;
   }
 
-  void ResetStub() {
+  void ResetStub(
+      std::unique_ptr<experimental::ClientInterceptorFactoryInterface>
+          interceptor = nullptr) {
     ChannelArguments args;
     auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
         GetParam().credentials_type, &args);
+    auto interceptors = CreatePhonyClientInterceptors();
+    if (interceptor != nullptr) interceptors.push_back(std::move(interceptor));
     switch (GetParam().protocol) {
       case Protocol::TCP:
         if (!GetParam().use_interceptors) {
@@ -133,7 +137,7 @@ class ClientCallbackEnd2endTest
         } else {
           channel_ = CreateCustomChannelWithInterceptors(
               server_address_.str(), channel_creds, args,
-              CreatePhonyClientInterceptors());
+              std::move(interceptors));
         }
         break;
       case Protocol::INPROC:
@@ -141,7 +145,7 @@ class ClientCallbackEnd2endTest
           channel_ = server_->InProcessChannel(args);
         } else {
           channel_ = server_->experimental().InProcessChannelWithInterceptors(
-              args, CreatePhonyClientInterceptors());
+              args, std::move(interceptors));
         }
         break;
       default:
@@ -212,7 +216,8 @@ class ClientCallbackEnd2endTest
     }
   }
 
-  void SendRpcsGeneric(int num_rpcs, bool maybe_except) {
+  void SendRpcsGeneric(int num_rpcs, bool maybe_except,
+                       const char* suffix_for_stats) {
     const std::string kMethodName("/grpc.testing.EchoTestService/Echo");
     std::string test_string("");
     for (int i = 0; i < num_rpcs; i++) {
@@ -228,8 +233,9 @@ class ClientCallbackEnd2endTest
       std::mutex mu;
       std::condition_variable cv;
       bool done = false;
+      StubOptions options(suffix_for_stats);
       generic_stub_->experimental().UnaryCall(
-          &cli_ctx, kMethodName, send_buf.get(), &recv_buf,
+          &cli_ctx, kMethodName, options, send_buf.get(), &recv_buf,
           [&request, &recv_buf, &done, &mu, &cv, maybe_except](Status s) {
             GPR_ASSERT(s.ok());
 
@@ -254,7 +260,8 @@ class ClientCallbackEnd2endTest
     }
   }
 
-  void SendGenericEchoAsBidi(int num_rpcs, int reuses, bool do_writes_done) {
+  void SendGenericEchoAsBidi(int num_rpcs, int reuses, bool do_writes_done,
+                             const char* suffix_for_stats) {
     const std::string kMethodName("/grpc.testing.EchoTestService/Echo");
     std::string test_string("");
     for (int i = 0; i < num_rpcs; i++) {
@@ -263,14 +270,16 @@ class ClientCallbackEnd2endTest
                                                                   ByteBuffer> {
        public:
         Client(ClientCallbackEnd2endTest* test, const std::string& method_name,
-               const std::string& test_str, int reuses, bool do_writes_done)
+               const char* suffix_for_stats, const std::string& test_str,
+               int reuses, bool do_writes_done)
             : reuses_remaining_(reuses), do_writes_done_(do_writes_done) {
-          activate_ = [this, test, method_name, test_str] {
+          activate_ = [this, test, method_name, suffix_for_stats, test_str] {
             if (reuses_remaining_ > 0) {
               cli_ctx_ = absl::make_unique<ClientContext>();
               reuses_remaining_--;
+              StubOptions options(suffix_for_stats);
               test->generic_stub_->experimental().PrepareBidiStreamingCall(
-                  cli_ctx_.get(), method_name, this);
+                  cli_ctx_.get(), method_name, options, this);
               request_.set_message(test_str);
               send_buf_ = SerializeToByteBuffer(&request_);
               StartWrite(send_buf_.get());
@@ -317,7 +326,8 @@ class ClientCallbackEnd2endTest
         const bool do_writes_done_;
       };
 
-      Client rpc(this, kMethodName, test_string, reuses, do_writes_done);
+      Client rpc(this, kMethodName, suffix_for_stats, test_string, reuses,
+                 do_writes_done);
 
       rpc.Await();
     }
@@ -501,29 +511,46 @@ TEST_P(ClientCallbackEnd2endTest, SequentialRpcsWithVariedBinaryMetadataValue) {
 }
 
 TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcs) {
-  ResetStub();
-  SendRpcsGeneric(10, false);
+  ResetStub(absl::make_unique<TestInterceptorFactory>(
+      "/grpc.testing.EchoTestService/Echo", nullptr));
+  SendRpcsGeneric(10, false, /*suffix_for_stats=*/nullptr);
+}
+
+TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcsWithSuffix) {
+  ResetStub(absl::make_unique<TestInterceptorFactory>(
+      "/grpc.testing.EchoTestService/Echo", "TestSuffix"));
+  SendRpcsGeneric(10, false, "TestSuffix");
 }
 
 TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcsAsBidi) {
-  ResetStub();
-  SendGenericEchoAsBidi(10, 1, /*do_writes_done=*/true);
+  ResetStub(absl::make_unique<TestInterceptorFactory>(
+      "/grpc.testing.EchoTestService/Echo", nullptr));
+  SendGenericEchoAsBidi(10, 1, /*do_writes_done=*/true,
+                        /*suffix_for_stats=*/nullptr);
+}
+
+TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcsAsBidiWithSuffix) {
+  ResetStub(absl::make_unique<TestInterceptorFactory>(
+      "/grpc.testing.EchoTestService/Echo", "TestSuffix"));
+  SendGenericEchoAsBidi(10, 1, /*do_writes_done=*/true, "TestSuffix");
 }
 
 TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcsAsBidiWithReactorReuse) {
   ResetStub();
-  SendGenericEchoAsBidi(10, 10, /*do_writes_done=*/true);
+  SendGenericEchoAsBidi(10, 10, /*do_writes_done=*/true,
+                        /*suffix_for_stats=*/nullptr);
 }
 
 TEST_P(ClientCallbackEnd2endTest, GenericRpcNoWritesDone) {
   ResetStub();
-  SendGenericEchoAsBidi(1, 1, /*do_writes_done=*/false);
+  SendGenericEchoAsBidi(1, 1, /*do_writes_done=*/false,
+                        /*suffix_for_stats=*/nullptr);
 }
 
 #if GRPC_ALLOW_EXCEPTIONS
 TEST_P(ClientCallbackEnd2endTest, ExceptingRpc) {
   ResetStub();
-  SendRpcsGeneric(10, true);
+  SendRpcsGeneric(10, true, nullptr);
 }
 #endif
 
@@ -822,18 +849,22 @@ TEST_P(ClientCallbackEnd2endTest, UnaryReactor) {
 }
 
 TEST_P(ClientCallbackEnd2endTest, GenericUnaryReactor) {
-  ResetStub();
   const std::string kMethodName("/grpc.testing.EchoTestService/Echo");
+  constexpr char kSuffixForStats[] = "TestSuffixForStats";
+  ResetStub(
+      absl::make_unique<TestInterceptorFactory>(kMethodName, kSuffixForStats));
   class UnaryClient : public grpc::experimental::ClientUnaryReactor {
    public:
-    UnaryClient(grpc::GenericStub* stub, const std::string& method_name) {
+    UnaryClient(grpc::GenericStub* stub, const std::string& method_name,
+                const char* suffix_for_stats) {
       cli_ctx_.AddMetadata("key1", "val1");
       cli_ctx_.AddMetadata("key2", "val2");
       request_.mutable_param()->set_echo_metadata_initially(true);
       request_.set_message("Hello metadata");
       send_buf_ = SerializeToByteBuffer(&request_);
 
-      stub->experimental().PrepareUnaryCall(&cli_ctx_, method_name,
+      StubOptions options(suffix_for_stats);
+      stub->experimental().PrepareUnaryCall(&cli_ctx_, method_name, options,
                                             send_buf_.get(), &recv_buf_, this);
       StartCall();
     }
@@ -878,7 +909,7 @@ TEST_P(ClientCallbackEnd2endTest, GenericUnaryReactor) {
     bool initial_metadata_done_{false};
   };
 
-  UnaryClient test{generic_stub_.get(), kMethodName};
+  UnaryClient test{generic_stub_.get(), kMethodName, kSuffixForStats};
   test.Await();
   // Make sure that the server interceptors were not notified of a cancel
   if (GetParam().use_interceptors) {
index 5d9451c..79b272c 100644 (file)
@@ -76,6 +76,7 @@ class HijackingInterceptor : public experimental::Interceptor {
     info_ = info;
     // Make sure it is the right method
     EXPECT_EQ(strcmp("/grpc.testing.EchoTestService/Echo", info->method()), 0);
+    EXPECT_EQ(info->suffix_for_stats(), nullptr);
     EXPECT_EQ(info->type(), experimental::ClientRpcInfo::Type::UNARY);
   }
 
@@ -183,6 +184,7 @@ class HijackingInterceptorMakesAnotherCall : public experimental::Interceptor {
     info_ = info;
     // Make sure it is the right method
     EXPECT_EQ(strcmp("/grpc.testing.EchoTestService/Echo", info->method()), 0);
+    EXPECT_EQ(strcmp("TestSuffixForStats", info->suffix_for_stats()), 0);
   }
 
   void Intercept(experimental::InterceptorBatchMethods* methods) override {
@@ -304,6 +306,7 @@ class BidiStreamingRpcHijackingInterceptor : public experimental::Interceptor {
   explicit BidiStreamingRpcHijackingInterceptor(
       experimental::ClientRpcInfo* info) {
     info_ = info;
+    EXPECT_EQ(info->suffix_for_stats(), nullptr);
   }
 
   void Intercept(experimental::InterceptorBatchMethods* methods) override {
@@ -375,6 +378,10 @@ class ClientStreamingRpcHijackingInterceptor
   explicit ClientStreamingRpcHijackingInterceptor(
       experimental::ClientRpcInfo* info) {
     info_ = info;
+    EXPECT_EQ(
+        strcmp("/grpc.testing.EchoTestService/RequestStream", info->method()),
+        0);
+    EXPECT_EQ(strcmp("TestSuffixForStats", info->suffix_for_stats()), 0);
   }
   void Intercept(experimental::InterceptorBatchMethods* methods) override {
     bool hijack = false;
@@ -431,6 +438,7 @@ class ServerStreamingRpcHijackingInterceptor
       experimental::ClientRpcInfo* info) {
     info_ = info;
     got_failed_message_ = false;
+    EXPECT_EQ(info->suffix_for_stats(), nullptr);
   }
 
   void Intercept(experimental::InterceptorBatchMethods* methods) override {
@@ -931,7 +939,7 @@ TEST_F(ClientInterceptorsEnd2endTest,
   auto channel = server_->experimental().InProcessChannelWithInterceptors(
       args, std::move(creators));
 
-  MakeCall(channel);
+  MakeCall(channel, StubOptions("TestSuffixForStats"));
   // Make sure all interceptors were run once, since the hijacking interceptor
   // makes an RPC on the intercepted channel
   EXPECT_EQ(PhonyInterceptor::GetNumTimesRun(), 12);
@@ -1059,7 +1067,8 @@ TEST_F(ClientInterceptorsStreamingEnd2endTest, ClientStreamingHijackingTest) {
   auto channel = experimental::CreateCustomChannelWithInterceptors(
       server_address_, InsecureChannelCredentials(), args, std::move(creators));
 
-  auto stub = grpc::testing::EchoTestService::NewStub(channel);
+  auto stub = grpc::testing::EchoTestService::NewStub(
+      channel, StubOptions("TestSuffixForStats"));
   ClientContext ctx;
   EchoRequest req;
   EchoResponse resp;
index f6ca7d6..33f882b 100644 (file)
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gprpp/debug_location.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "src/cpp/client/secure_credentials.h"
index 0d8f1d7..535ee29 100644 (file)
@@ -101,8 +101,8 @@ int GetCallCounterValue() {
 
 class ChannelDataImpl : public ChannelData {
  public:
-  grpc_error* Init(grpc_channel_element* /*elem*/,
-                   grpc_channel_element_args* /*args*/) override {
+  grpc_error_handle Init(grpc_channel_element* /*elem*/,
+                         grpc_channel_element_args* /*args*/) override {
     IncrementConnectionCounter();
     return GRPC_ERROR_NONE;
   }
index d5ff33c..8b6affa 100644 (file)
@@ -44,9 +44,9 @@
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "src/core/lib/transport/authority_override.h"
@@ -564,7 +564,7 @@ class GrpclbEnd2endTest : public ::testing::Test {
     grpc_core::Resolver::Result result;
     result.addresses =
         CreateLbAddressesFromAddressDataList(backend_address_data);
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     result.service_config =
         grpc_core::ServiceConfig::Create(nullptr, service_config_json, &error);
     GPR_ASSERT(error == GRPC_ERROR_NONE);
index 875ae8f..b90c8dc 100644 (file)
@@ -27,8 +27,9 @@ std::atomic<int> PhonyInterceptor::num_times_run_;
 std::atomic<int> PhonyInterceptor::num_times_run_reverse_;
 std::atomic<int> PhonyInterceptor::num_times_cancel_;
 
-void MakeCall(const std::shared_ptr<Channel>& channel) {
-  auto stub = grpc::testing::EchoTestService::NewStub(channel);
+void MakeCall(const std::shared_ptr<Channel>& channel,
+              const StubOptions& options) {
+  auto stub = grpc::testing::EchoTestService::NewStub(channel, options);
   ClientContext ctx;
   EchoRequest req;
   req.mutable_param()->set_echo_metadata(true);
index b6ffd7e..2c394bf 100644 (file)
@@ -82,6 +82,42 @@ class PhonyInterceptorFactory
   }
 };
 
+/* This interceptor can be used to test the interception mechanism. */
+class TestInterceptor : public experimental::Interceptor {
+ public:
+  TestInterceptor(const std::string& method, const char* suffix_for_stats,
+                  experimental::ClientRpcInfo* info) {
+    EXPECT_EQ(info->method(), method);
+
+    if (suffix_for_stats == nullptr || info->suffix_for_stats() == nullptr) {
+      EXPECT_EQ(info->suffix_for_stats(), suffix_for_stats);
+    } else {
+      EXPECT_EQ(strcmp(info->suffix_for_stats(), suffix_for_stats), 0);
+    }
+  }
+
+  void Intercept(experimental::InterceptorBatchMethods* methods) override {
+    methods->Proceed();
+  }
+};
+
+class TestInterceptorFactory
+    : public experimental::ClientInterceptorFactoryInterface {
+ public:
+  TestInterceptorFactory(const std::string& method,
+                         const char* suffix_for_stats)
+      : method_(method), suffix_for_stats_(suffix_for_stats) {}
+
+  experimental::Interceptor* CreateClientInterceptor(
+      experimental::ClientRpcInfo* info) override {
+    return new TestInterceptor(method_, suffix_for_stats_, info);
+  }
+
+ private:
+  std::string method_;
+  const char* suffix_for_stats_;
+};
+
 /* This interceptor factory returns nullptr on interceptor creation */
 class NullInterceptorFactory
     : public experimental::ClientInterceptorFactoryInterface,
@@ -164,7 +200,8 @@ class EchoTestServiceStreamingImpl : public EchoTestService::Service {
 
 constexpr int kNumStreamingMessages = 10;
 
-void MakeCall(const std::shared_ptr<Channel>& channel);
+void MakeCall(const std::shared_ptr<Channel>& channel,
+              const StubOptions& options = StubOptions());
 
 void MakeClientStreamingCall(const std::shared_ptr<Channel>& channel);
 
index f342bd0..e9fa826 100644 (file)
@@ -148,7 +148,7 @@ class TestTcpServer {
     self->OnConnect(tcp, accepting_pollset, acceptor);
   }
 
-  static void OnFdReleased(void* arg, grpc_error* err) {
+  static void OnFdReleased(void* arg, grpc_error_handle err) {
     auto* self = static_cast<TestTcpServer*>(arg);
     self->OnFdReleased(err);
   }
@@ -165,7 +165,7 @@ class TestTcpServer {
     grpc_tcp_destroy_and_release_fd(tcp, &fd_, &on_fd_released_);
   }
 
-  void OnFdReleased(grpc_error* err) {
+  void OnFdReleased(grpc_error_handle err) {
     EXPECT_EQ(GRPC_ERROR_NONE, err);
     experimental::ExternalConnectionAcceptor::NewConnectionParameters p;
     p.listener_fd = listener_fd_;
index ceae2ed..67e02bc 100644 (file)
 #include "src/core/ext/filters/client_channel/global_subchannel_pool.h"
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/debug_location.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "src/cpp/client/secure_credentials.h"
index 5bf243e..2a80c54 100644 (file)
@@ -56,6 +56,7 @@
 #include "src/core/ext/xds/xds_api.h"
 #include "src/core/ext/xds/xds_channel_args.h"
 #include "src/core/ext/xds/xds_client.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
@@ -65,7 +66,6 @@
 #include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/gprpp/time_util.h"
 #include "src/core/lib/iomgr/load_file.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "src/cpp/client/secure_credentials.h"
@@ -480,22 +480,30 @@ class AdsServiceImpl : public std::enable_shared_from_this<AdsServiceImpl> {
   };
 
   struct EdsResourceArgs {
+    struct Endpoint {
+      explicit Endpoint(int port,
+                        HealthStatus health_status = HealthStatus::UNKNOWN,
+                        int lb_weight = 1)
+          : port(port), health_status(health_status), lb_weight(lb_weight) {}
+
+      int port;
+      HealthStatus health_status;
+      int lb_weight;
+    };
+
     struct Locality {
-      Locality(std::string sub_zone, std::vector<int> ports,
+      Locality(std::string sub_zone, std::vector<Endpoint> endpoints,
                int lb_weight = kDefaultLocalityWeight,
-               int priority = kDefaultLocalityPriority,
-               std::vector<HealthStatus> health_statuses = {})
+               int priority = kDefaultLocalityPriority)
           : sub_zone(std::move(sub_zone)),
-            ports(std::move(ports)),
+            endpoints(std::move(endpoints)),
             lb_weight(lb_weight),
-            priority(priority),
-            health_statuses(std::move(health_statuses)) {}
+            priority(priority) {}
 
       const std::string sub_zone;
-      std::vector<int> ports;
+      std::vector<Endpoint> endpoints;
       int lb_weight;
       int priority;
-      std::vector<HealthStatus> health_statuses;
     };
 
     EdsResourceArgs() = default;
@@ -1322,6 +1330,12 @@ class TestType {
     kRouteOverride,
   };
 
+  enum BootstrapSource {
+    kBootstrapFromChannelArg,
+    kBootstrapFromFile,
+    kBootstrapFromEnvVar,
+  };
+
   TestType& set_use_fake_resolver() {
     use_fake_resolver_ = true;
     return *this;
@@ -1352,20 +1366,24 @@ class TestType {
     return *this;
   }
 
-  TestType& set_filter_config_setup(const FilterConfigSetup& setup) {
+  TestType& set_filter_config_setup(FilterConfigSetup setup) {
     filter_config_setup_ = setup;
     return *this;
   }
 
+  TestType& set_bootstrap_source(BootstrapSource bootstrap_source) {
+    bootstrap_source_ = bootstrap_source;
+    return *this;
+  }
+
   bool use_fake_resolver() const { return use_fake_resolver_; }
   bool enable_load_reporting() const { return enable_load_reporting_; }
   bool enable_rds_testing() const { return enable_rds_testing_; }
   bool use_v2() const { return use_v2_; }
   bool use_xds_credentials() const { return use_xds_credentials_; }
   bool use_csds_streaming() const { return use_csds_streaming_; }
-  const FilterConfigSetup& filter_config_setup() const {
-    return filter_config_setup_;
-  }
+  FilterConfigSetup filter_config_setup() const { return filter_config_setup_; }
+  BootstrapSource bootstrap_source() const { return bootstrap_source_; }
 
   std::string AsString() const {
     std::string retval = (use_fake_resolver_ ? "FakeResolver" : "XdsResolver");
@@ -1377,6 +1395,11 @@ class TestType {
     if (filter_config_setup_ == kRouteOverride) {
       retval += "FilterPerRouteOverride";
     }
+    if (bootstrap_source_ == kBootstrapFromFile) {
+      retval += "BootstrapFromFile";
+    } else if (bootstrap_source_ == kBootstrapFromEnvVar) {
+      retval += "BootstrapFromEnvVar";
+    }
     return retval;
   }
 
@@ -1388,6 +1411,7 @@ class TestType {
   bool use_xds_credentials_ = false;
   bool use_csds_streaming_ = false;
   FilterConfigSetup filter_config_setup_ = kHTTPConnectionManagerOriginal;
+  BootstrapSource bootstrap_source_ = kBootstrapFromChannelArg;
 };
 
 std::string ReadFile(const char* file_path) {
@@ -1426,7 +1450,7 @@ class FakeCertificateProvider final : public grpc_tls_certificate_provider {
       if (!root_being_watched && !identity_being_watched) return;
       auto it = cert_data_map_.find(cert_name);
       if (it == cert_data_map_.end()) {
-        grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrCat("No certificates available for cert_name \"",
                          cert_name, "\"")
                 .c_str());
@@ -1487,7 +1511,7 @@ class FakeCertificateProviderFactory
 
   grpc_core::RefCountedPtr<grpc_core::CertificateProviderFactory::Config>
   CreateCertificateProviderConfig(const grpc_core::Json& /*config_json*/,
-                                  grpc_error** /*error*/) override {
+                                  grpc_error_handle* /*error*/) override {
     return grpc_core::MakeRefCounted<Config>(name_);
   }
 
@@ -1581,26 +1605,6 @@ class NoOpHttpFilter : public grpc_core::XdsHttpFilterImpl {
   const bool supported_on_servers_;
 };
 
-namespace {
-
-void* response_generator_arg_copy(void* p) {
-  auto* generator = static_cast<grpc_core::FakeResolverResponseGenerator*>(p);
-  generator->Ref().release();
-  return p;
-}
-
-void response_generator_arg_destroy(void* p) {
-  auto* generator = static_cast<grpc_core::FakeResolverResponseGenerator*>(p);
-  generator->Unref();
-}
-
-int response_generator_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
-
-const grpc_arg_pointer_vtable
-    kLogicalDnsClusterResolverResponseGeneratorVtable = {
-        response_generator_arg_copy, response_generator_arg_destroy,
-        response_generator_cmp};
-
 // There is slight difference between time fetched by GPR and by C++ system
 // clock API. It's unclear if they are using the same syscall, but we do know
 // GPR round the number at millisecond-level. This creates a 1ms difference,
@@ -1610,7 +1614,51 @@ grpc_millis NowFromCycleCounter() {
   return grpc_cycle_counter_to_millis_round_up(now);
 }
 
-}  // namespace
+// Returns the number of RPCs needed to pass error_tolerance at 99.99% chance.
+// Rolling dices in drop/fault-injection generates a binomial distribution (if
+// our code is not horribly wrong). Let's make "n" the number of samples, "p"
+// the probabilty. If we have np>5 & n(1-p)>5, we can approximately treat the
+// binomial distribution as a normal distribution.
+//
+// For normal distribution, we can easily look up how many standard deviation we
+// need to reach 99.99%. Based on Wiki's table
+// https://en.wikipedia.org/wiki/Standard_normal_table, we need 3.89 sigma
+// (standard deviation) to cover the probability area of 99.99%. In another
+// word, for a sample with size "n" probability "p" error-tolerance "k", we want
+// the error always land within 3.89 sigma. The sigma of binominal distribution
+// and be computed as sqrt(np(1-p)). Hence, we have the equation:
+//
+//   kn <= 3.89 * sqrt(np(1-p))
+//
+// E.g., with p=0.5 k=0.1, n >= 378; with p=0.5 k=0.05, n >= 1513; with p=0.5
+// k=0.01, n >= 37830.
+size_t ComputeIdealNumRpcs(double p, double error_tolerance) {
+  GPR_ASSERT(p >= 0 && p <= 1);
+  size_t num_rpcs =
+      ceil(p * (1 - p) * 3.89 * 3.89 / error_tolerance / error_tolerance);
+  gpr_log(GPR_INFO,
+          "Sending %" PRIuPTR " RPCs for percentage=%.3f error_tolerance=%.3f",
+          num_rpcs, p, error_tolerance);
+  return num_rpcs;
+}
+
+// Channel arg pointer vtable for storing xDS channel args in the parent
+// channel's channel args.
+void* ChannelArgsArgCopy(void* p) {
+  auto* args = static_cast<grpc_channel_args*>(p);
+  return grpc_channel_args_copy(args);
+}
+void ChannelArgsArgDestroy(void* p) {
+  auto* args = static_cast<grpc_channel_args*>(p);
+  grpc_channel_args_destroy(args);
+}
+int ChannelArgsArgCmp(void* a, void* b) {
+  auto* args_a = static_cast<grpc_channel_args*>(a);
+  auto* args_b = static_cast<grpc_channel_args*>(b);
+  return grpc_channel_args_compare(args_a, args_b);
+}
+const grpc_arg_pointer_vtable kChannelArgsArgVtable = {
+    ChannelArgsArgCopy, ChannelArgsArgDestroy, ChannelArgsArgCmp};
 
 class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
  protected:
@@ -1625,24 +1673,14 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
   // balancers that it needs, so that we aren't wasting resources.
   XdsEnd2endTest(size_t num_backends, size_t num_balancers,
                  int client_load_reporting_interval_seconds = 100,
-                 bool use_xds_enabled_server = false,
-                 bool bootstrap_contents_from_env_var = false)
+                 bool use_xds_enabled_server = false)
       : num_backends_(num_backends),
         num_balancers_(num_balancers),
         client_load_reporting_interval_seconds_(
             client_load_reporting_interval_seconds),
-        use_xds_enabled_server_(use_xds_enabled_server),
-        bootstrap_contents_from_env_var_(bootstrap_contents_from_env_var) {}
+        use_xds_enabled_server_(use_xds_enabled_server) {}
 
   void SetUp() override {
-    if (bootstrap_contents_from_env_var_) {
-      gpr_setenv("GRPC_XDS_BOOTSTRAP_CONFIG",
-                 GetParam().use_v2() ? kBootstrapFileV2 : kBootstrapFileV3);
-    } else {
-      gpr_setenv("GRPC_XDS_BOOTSTRAP", GetParam().use_v2()
-                                           ? g_bootstrap_file_v2
-                                           : g_bootstrap_file_v3);
-    }
     bool localhost_resolves_to_ipv4 = false;
     bool localhost_resolves_to_ipv6 = false;
     grpc_core::LocalhostResolves(&localhost_resolves_to_ipv4,
@@ -1679,28 +1717,29 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
     }
     // Start the load balancers.
     for (size_t i = 0; i < num_balancers_; ++i) {
-      balancers_.emplace_back(
-          new BalancerServerThread(GetParam().enable_load_reporting()
-                                       ? client_load_reporting_interval_seconds_
-                                       : 0));
+      balancers_.emplace_back(new BalancerServerThread(
+          this, GetParam().enable_load_reporting()
+                    ? client_load_reporting_interval_seconds_
+                    : 0));
       balancers_.back()->Start();
       // Initialize resources.
       SetListenerAndRouteConfiguration(i, default_listener_,
                                        default_route_config_);
       balancers_.back()->ads_service()->SetCdsResource(default_cluster_);
     }
-    // Initialize XdsClient state.
-    response_generator_ =
+    // Create fake resolver response generators used by client.
+    if (GetParam().use_fake_resolver()) {
+      response_generator_ =
+          grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
+    }
+    logical_dns_cluster_resolver_response_generator_ =
         grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
-    // Inject xDS channel response generator.
     lb_channel_response_generator_ =
         grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
+    // Construct channel args for XdsClient.
     xds_channel_args_to_add_.emplace_back(
         grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
             lb_channel_response_generator_.get()));
-    // Inject xDS logical cluster resolver response generator.
-    logical_dns_cluster_resolver_response_generator_ =
-        grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
     if (xds_resource_does_not_exist_timeout_ms_ > 0) {
       xds_channel_args_to_add_.emplace_back(grpc_channel_arg_integer_create(
           const_cast<char*>(GRPC_ARG_XDS_RESOURCE_DOES_NOT_EXIST_TIMEOUT_MS),
@@ -1708,18 +1747,36 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
     }
     xds_channel_args_.num_args = xds_channel_args_to_add_.size();
     xds_channel_args_.args = xds_channel_args_to_add_.data();
-    grpc_core::internal::SetXdsChannelArgsForTest(&xds_channel_args_);
-    // Make sure each test creates a new XdsClient instance rather than
-    // reusing the one from the previous test.  This avoids spurious failures
-    // caused when a load reporting test runs after a non-load reporting test
-    // and the XdsClient is still talking to the old LRS server, which fails
-    // because it's not expecting the client to connect.  It also
-    // ensures that each test can independently set the global channel
-    // args for the xDS channel.
-    grpc_core::internal::UnsetGlobalXdsClientForTest();
+    // Initialize XdsClient state.
+    // TODO(roth): Consider changing this to dynamically generate the
+    // bootstrap config in each individual test instead of hard-coding
+    // the contents here.  That would allow us to use an ipv4: or ipv6:
+    // URI for the xDS server instead of using the fake resolver.
+    if (GetParam().bootstrap_source() == TestType::kBootstrapFromEnvVar) {
+      gpr_setenv("GRPC_XDS_BOOTSTRAP_CONFIG",
+                 GetParam().use_v2() ? kBootstrapFileV2 : kBootstrapFileV3);
+    } else if (GetParam().bootstrap_source() == TestType::kBootstrapFromFile) {
+      gpr_setenv("GRPC_XDS_BOOTSTRAP", GetParam().use_v2()
+                                           ? g_bootstrap_file_v2
+                                           : g_bootstrap_file_v3);
+    }
+    if (GetParam().bootstrap_source() != TestType::kBootstrapFromChannelArg) {
+      // If getting bootstrap from channel arg, we'll pass these args in
+      // via the parent channel args in CreateChannel() instead.
+      grpc_core::internal::SetXdsChannelArgsForTest(&xds_channel_args_);
+      // Make sure each test creates a new XdsClient instance rather than
+      // reusing the one from the previous test.  This avoids spurious failures
+      // caused when a load reporting test runs after a non-load reporting test
+      // and the XdsClient is still talking to the old LRS server, which fails
+      // because it's not expecting the client to connect.  It also
+      // ensures that each test can independently set the global channel
+      // args for the xDS channel.
+      grpc_core::internal::UnsetGlobalXdsClientForTest();
+    }
     // Start the backends.
     for (size_t i = 0; i < num_backends_; ++i) {
-      backends_.emplace_back(new BackendServerThread(use_xds_enabled_server_));
+      backends_.emplace_back(
+          new BackendServerThread(this, use_xds_enabled_server_));
       backends_.back()->Start();
     }
     // Create channel and stub.
@@ -1762,7 +1819,8 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
 
   std::shared_ptr<Channel> CreateChannel(
       int failover_timeout = 0, const char* server_name = kServerName,
-      grpc_core::FakeResolverResponseGenerator* response_generator = nullptr) {
+      grpc_core::FakeResolverResponseGenerator* response_generator = nullptr,
+      grpc_channel_args* xds_channel_args = nullptr) {
     ChannelArguments args;
     if (failover_timeout > 0) {
       args.SetInt(GRPC_ARG_PRIORITY_FAILOVER_TIMEOUT_MS, failover_timeout);
@@ -1773,13 +1831,25 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
       if (response_generator == nullptr) {
         response_generator = response_generator_.get();
       }
-      args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
-                      response_generator);
+      args.SetPointerWithVtable(
+          GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR, response_generator,
+          &grpc_core::FakeResolverResponseGenerator::kChannelArgPointerVtable);
+    }
+    if (GetParam().bootstrap_source() == TestType::kBootstrapFromChannelArg) {
+      // We're getting the bootstrap from a channel arg, so we do the
+      // same thing for the response generator to use for the xDS
+      // channel and the xDS resource-does-not-exist timeout value.
+      args.SetString(GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG,
+                     GetParam().use_v2() ? kBootstrapFileV2 : kBootstrapFileV3);
+      if (xds_channel_args == nullptr) xds_channel_args = &xds_channel_args_;
+      args.SetPointerWithVtable(
+          GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS,
+          xds_channel_args, &kChannelArgsArgVtable);
     }
     args.SetPointerWithVtable(
         GRPC_ARG_XDS_LOGICAL_DNS_CLUSTER_FAKE_RESOLVER_RESPONSE_GENERATOR,
         logical_dns_cluster_resolver_response_generator_.get(),
-        &kLogicalDnsClusterResolverResponseGeneratorVtable);
+        &grpc_core::FakeResolverResponseGenerator::kChannelArgPointerVtable);
     std::string uri = absl::StrCat(
         GetParam().use_fake_resolver() ? "fake" : "xds", ":///", server_name);
     std::shared_ptr<ChannelCredentials> channel_creds =
@@ -1904,26 +1974,34 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
     }
   }
 
+  bool SeenBackend(size_t backend_idx,
+                   const RpcService rpc_service = SERVICE_ECHO) {
+    switch (rpc_service) {
+      case SERVICE_ECHO:
+        if (backends_[backend_idx]->backend_service()->request_count() == 0) {
+          return false;
+        }
+        break;
+      case SERVICE_ECHO1:
+        if (backends_[backend_idx]->backend_service1()->request_count() == 0) {
+          return false;
+        }
+        break;
+      case SERVICE_ECHO2:
+        if (backends_[backend_idx]->backend_service2()->request_count() == 0) {
+          return false;
+        }
+        break;
+    }
+    return true;
+  }
+
   bool SeenAllBackends(size_t start_index = 0, size_t stop_index = 0,
-                       const RpcOptions& rpc_options = RpcOptions()) {
+                       const RpcService rpc_service = SERVICE_ECHO) {
     if (stop_index == 0) stop_index = backends_.size();
     for (size_t i = start_index; i < stop_index; ++i) {
-      switch (rpc_options.service) {
-        case SERVICE_ECHO:
-          if (backends_[i]->backend_service()->request_count() == 0) {
-            return false;
-          }
-          break;
-        case SERVICE_ECHO1:
-          if (backends_[i]->backend_service1()->request_count() == 0) {
-            return false;
-          }
-          break;
-        case SERVICE_ECHO2:
-          if (backends_[i]->backend_service2()->request_count() == 0) {
-            return false;
-          }
-          break;
+      if (!SeenBackend(i, rpc_service)) {
+        return false;
       }
     }
     return true;
@@ -1947,39 +2025,58 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
     ++*num_total;
   }
 
+  struct WaitForBackendOptions {
+    bool reset_counters = true;
+    bool allow_failures = false;
+
+    WaitForBackendOptions() {}
+
+    WaitForBackendOptions& set_reset_counters(bool enable) {
+      reset_counters = enable;
+      return *this;
+    }
+
+    WaitForBackendOptions& set_allow_failures(bool enable) {
+      allow_failures = enable;
+      return *this;
+    }
+  };
+
   std::tuple<int, int, int> WaitForAllBackends(
-      size_t start_index = 0, size_t stop_index = 0, bool reset_counters = true,
-      const RpcOptions& rpc_options = RpcOptions(),
-      bool allow_failures = false) {
+      size_t start_index = 0, size_t stop_index = 0,
+      const WaitForBackendOptions& wait_options = WaitForBackendOptions(),
+      const RpcOptions& rpc_options = RpcOptions()) {
     int num_ok = 0;
     int num_failure = 0;
     int num_drops = 0;
     int num_total = 0;
-    while (!SeenAllBackends(start_index, stop_index, rpc_options)) {
+    while (!SeenAllBackends(start_index, stop_index, rpc_options.service)) {
       SendRpcAndCount(&num_total, &num_ok, &num_failure, &num_drops,
                       rpc_options);
     }
-    if (reset_counters) ResetBackendCounters();
+    if (wait_options.reset_counters) ResetBackendCounters();
     gpr_log(GPR_INFO,
             "Performed %d warm up requests against the backends. "
             "%d succeeded, %d failed, %d dropped.",
             num_total, num_ok, num_failure, num_drops);
-    if (!allow_failures) EXPECT_EQ(num_failure, 0);
+    if (!wait_options.allow_failures) EXPECT_EQ(num_failure, 0);
     return std::make_tuple(num_ok, num_failure, num_drops);
   }
 
-  void WaitForBackend(size_t backend_idx, bool reset_counters = true,
-                      bool require_success = false) {
+  void WaitForBackend(
+      size_t backend_idx,
+      const WaitForBackendOptions& wait_options = WaitForBackendOptions(),
+      const RpcOptions& rpc_options = RpcOptions()) {
     gpr_log(GPR_INFO, "========= WAITING FOR BACKEND %lu ==========",
             static_cast<unsigned long>(backend_idx));
     do {
-      Status status = SendRpc();
-      if (require_success) {
+      Status status = SendRpc(rpc_options);
+      if (!wait_options.allow_failures) {
         EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
                                  << " message=" << status.error_message();
       }
-    } while (backends_[backend_idx]->backend_service()->request_count() == 0);
-    if (reset_counters) ResetBackendCounters();
+    } while (!SeenBackend(backend_idx, rpc_options.service));
+    if (wait_options.reset_counters) ResetBackendCounters();
     gpr_log(GPR_INFO, "========= BACKEND %lu READY ==========",
             static_cast<unsigned long>(backend_idx));
   }
@@ -2005,14 +2102,14 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
     grpc_core::ExecCtx exec_ctx;
     grpc_core::Resolver::Result result;
     result.addresses = CreateAddressListFromPortList(ports);
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     const char* service_config_json =
         GetParam().enable_load_reporting()
             ? kDefaultServiceConfig
             : kDefaultServiceConfigWithoutLoadReporting;
     result.service_config =
         grpc_core::ServiceConfig::Create(nullptr, service_config_json, &error);
-    ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+    ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
     ASSERT_NE(result.service_config.get(), nullptr);
     if (response_generator == nullptr) {
       response_generator = response_generator_.get();
@@ -2022,26 +2119,29 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
 
   void SetNextResolutionForLbChannelAllBalancers(
       const char* service_config_json = nullptr,
-      const char* expected_targets = nullptr) {
+      const char* expected_targets = nullptr,
+      grpc_core::FakeResolverResponseGenerator* response_generator = nullptr) {
     std::vector<int> ports;
     for (size_t i = 0; i < balancers_.size(); ++i) {
       ports.emplace_back(balancers_[i]->port());
     }
-    SetNextResolutionForLbChannel(ports, service_config_json, expected_targets);
+    SetNextResolutionForLbChannel(ports, service_config_json, expected_targets,
+                                  response_generator);
   }
 
-  void SetNextResolutionForLbChannel(const std::vector<int>& ports,
-                                     const char* service_config_json = nullptr,
-                                     const char* expected_targets = nullptr) {
+  void SetNextResolutionForLbChannel(
+      const std::vector<int>& ports, const char* service_config_json = nullptr,
+      const char* expected_targets = nullptr,
+      grpc_core::FakeResolverResponseGenerator* response_generator = nullptr) {
     grpc_core::ExecCtx exec_ctx;
     grpc_core::Resolver::Result result;
     result.addresses = CreateAddressListFromPortList(ports);
     if (service_config_json != nullptr) {
-      grpc_error* error = GRPC_ERROR_NONE;
+      grpc_error_handle error = GRPC_ERROR_NONE;
       result.service_config = grpc_core::ServiceConfig::Create(
           nullptr, service_config_json, &error);
       ASSERT_NE(result.service_config.get(), nullptr);
-      ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+      ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
     }
     if (expected_targets != nullptr) {
       grpc_arg expected_targets_arg = grpc_channel_arg_string_create(
@@ -2050,7 +2150,10 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
       result.args =
           grpc_channel_args_copy_and_add(nullptr, &expected_targets_arg, 1);
     }
-    lb_channel_response_generator_->SetResponse(std::move(result));
+    if (response_generator == nullptr) {
+      response_generator = lb_channel_response_generator_.get();
+    }
+    response_generator->SetResponse(std::move(result));
   }
 
   void SetNextReresolutionResponse(const std::vector<int>& ports) {
@@ -2133,6 +2236,23 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
     return listener;
   }
 
+  std::vector<AdsServiceImpl::EdsResourceArgs::Endpoint>
+  CreateEndpointsForBackends(size_t start_index = 0, size_t stop_index = 0,
+                             HealthStatus health_status = HealthStatus::UNKNOWN,
+                             int lb_weight = 1) {
+    if (stop_index == 0) stop_index = backends_.size();
+    std::vector<AdsServiceImpl::EdsResourceArgs::Endpoint> endpoints;
+    for (size_t i = start_index; i < stop_index; ++i) {
+      endpoints.emplace_back(backends_[i]->port(), health_status, lb_weight);
+    }
+    return endpoints;
+  }
+
+  AdsServiceImpl::EdsResourceArgs::Endpoint MakeNonExistantEndpoint() {
+    return AdsServiceImpl::EdsResourceArgs::Endpoint(
+        grpc_pick_unused_port_or_die());
+  }
+
   ClusterLoadAssignment BuildEdsResource(
       const AdsServiceImpl::EdsResourceArgs& args,
       const char* eds_service_name = kDefaultEdsServiceName) {
@@ -2145,12 +2265,12 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
       endpoints->mutable_locality()->set_region(kDefaultLocalityRegion);
       endpoints->mutable_locality()->set_zone(kDefaultLocalityZone);
       endpoints->mutable_locality()->set_sub_zone(locality.sub_zone);
-      for (size_t i = 0; i < locality.ports.size(); ++i) {
-        const int& port = locality.ports[i];
+      for (size_t i = 0; i < locality.endpoints.size(); ++i) {
+        const int& port = locality.endpoints[i].port;
         auto* lb_endpoints = endpoints->add_lb_endpoints();
-        if (locality.health_statuses.size() > i &&
-            locality.health_statuses[i] != HealthStatus::UNKNOWN) {
-          lb_endpoints->set_health_status(locality.health_statuses[i]);
+        if (locality.endpoints.size() > i &&
+            locality.endpoints[i].health_status != HealthStatus::UNKNOWN) {
+          lb_endpoints->set_health_status(locality.endpoints[i].health_status);
         }
         auto* endpoint = lb_endpoints->mutable_endpoint();
         auto* address = endpoint->mutable_address();
@@ -2224,7 +2344,7 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
   class XdsServingStatusNotifier
       : public grpc::experimental::XdsServerServingStatusNotifierInterface {
    public:
-    void OnServingStatusChange(std::string uri, grpc::Status status) override {
+    void OnServingStatusUpdate(std::string uri, grpc::Status status) override {
       grpc_core::MutexLock lock(&mu_);
       status_map[uri] = status;
       cond_.Signal();
@@ -2248,8 +2368,10 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
 
   class ServerThread {
    public:
-    explicit ServerThread(bool use_xds_enabled_server = false)
-        : port_(grpc_pick_unused_port_or_die()),
+    explicit ServerThread(XdsEnd2endTest* test_obj,
+                          bool use_xds_enabled_server = false)
+        : test_obj_(test_obj),
+          port_(grpc_pick_unused_port_or_die()),
           use_xds_enabled_server_(use_xds_enabled_server) {}
     virtual ~ServerThread(){};
 
@@ -2277,6 +2399,11 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
       server_address << "localhost:" << port_;
       if (use_xds_enabled_server_) {
         experimental::XdsServerBuilder builder;
+        if (GetParam().bootstrap_source() ==
+            TestType::kBootstrapFromChannelArg) {
+          builder.SetOption(
+              absl::make_unique<XdsChannelArgsServerBuilderOption>(test_obj_));
+        }
         builder.set_status_notifier(&notifier_);
         builder.AddListeningPort(server_address.str(), Credentials());
         RegisterAllServices(&builder);
@@ -2312,12 +2439,36 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
     XdsServingStatusNotifier* notifier() { return &notifier_; }
 
    private:
+    class XdsChannelArgsServerBuilderOption
+        : public ::grpc::ServerBuilderOption {
+     public:
+      explicit XdsChannelArgsServerBuilderOption(XdsEnd2endTest* test_obj)
+          : test_obj_(test_obj) {}
+
+      void UpdateArguments(grpc::ChannelArguments* args) override {
+        args->SetString(
+            GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG,
+            GetParam().use_v2() ? kBootstrapFileV2 : kBootstrapFileV3);
+        args->SetPointerWithVtable(
+            GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS,
+            &test_obj_->xds_channel_args_, &kChannelArgsArgVtable);
+      }
+
+      void UpdatePlugins(
+          std::vector<std::unique_ptr<grpc::ServerBuilderPlugin>>* /*plugins*/)
+          override {}
+
+     private:
+      XdsEnd2endTest* test_obj_;
+    };
+
     virtual void RegisterAllServices(ServerBuilder* builder) = 0;
     virtual void StartAllServices() = 0;
     virtual void ShutdownAllServices() = 0;
 
     virtual const char* Type() = 0;
 
+    XdsEnd2endTest* test_obj_;
     const int port_;
     std::unique_ptr<Server> server_;
     XdsServingStatusNotifier notifier_;
@@ -2328,8 +2479,9 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
 
   class BackendServerThread : public ServerThread {
    public:
-    explicit BackendServerThread(bool use_xds_enabled_server)
-        : ServerThread(use_xds_enabled_server) {}
+    explicit BackendServerThread(XdsEnd2endTest* test_obj,
+                                 bool use_xds_enabled_server)
+        : ServerThread(test_obj, use_xds_enabled_server) {}
 
     BackendServiceImpl<::grpc::testing::EchoTestService::Service>*
     backend_service() {
@@ -2403,8 +2555,10 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
 
   class BalancerServerThread : public ServerThread {
    public:
-    explicit BalancerServerThread(int client_load_reporting_interval = 0)
-        : ads_service_(new AdsServiceImpl()),
+    explicit BalancerServerThread(XdsEnd2endTest* test_obj,
+                                  int client_load_reporting_interval = 0)
+        : ServerThread(test_obj),
+          ads_service_(new AdsServiceImpl()),
           lrs_service_(new LrsServiceImpl(client_load_reporting_interval)) {}
 
     AdsServiceImpl* ads_service() { return ads_service_.get(); }
@@ -2436,6 +2590,10 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
 
 #ifndef DISABLED_XDS_PROTO_IN_CC
   class AdminServerThread : public ServerThread {
+   public:
+    explicit AdminServerThread(XdsEnd2endTest* test_obj)
+        : ServerThread(test_obj) {}
+
    private:
     void RegisterAllServices(ServerBuilder* builder) override {
       builder->RegisterService(&csds_service_);
@@ -2453,8 +2611,8 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
    public:
     void StartRpc(grpc::testing::EchoTestService::Stub* stub,
                   const RpcOptions& rpc_options =
-                      RpcOptions().set_client_cancel_after_us(1 * 1000 *
-                                                              1000)) {
+                      RpcOptions().set_timeout_ms(0).set_client_cancel_after_us(
+                          1 * 1000 * 1000)) {
       sender_thread_ = std::thread([this, stub, rpc_options]() {
         EchoRequest request;
         EchoResponse response;
@@ -2479,6 +2637,49 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
     Status status_;
   };
 
+  struct ConcurrentRpc {
+    ClientContext context;
+    Status status;
+    grpc_millis elapsed_time;
+    EchoResponse response;
+  };
+
+  std::vector<ConcurrentRpc> SendConcurrentRpcs(
+      grpc::testing::EchoTestService::Stub* stub, size_t num_rpcs,
+      const RpcOptions& rpc_options) {
+    // Variables for RPCs.
+    std::vector<ConcurrentRpc> rpcs(num_rpcs);
+    EchoRequest request;
+    // Variables for synchronization
+    absl::Mutex mu;
+    absl::CondVar cv;
+    size_t completed = 0;
+    // Set-off callback RPCs
+    for (size_t i = 0; i < num_rpcs; i++) {
+      ConcurrentRpc* rpc = &rpcs[i];
+      rpc_options.SetupRpc(&rpc->context, &request);
+      grpc_millis t0 = NowFromCycleCounter();
+      stub->experimental_async()->Echo(
+          &rpc->context, &request, &rpc->response,
+          [rpc, &mu, &completed, &cv, num_rpcs, t0](Status s) {
+            rpc->status = s;
+            rpc->elapsed_time = NowFromCycleCounter() - t0;
+            bool done;
+            {
+              absl::MutexLock lock(&mu);
+              done = (++completed) == num_rpcs;
+            }
+            if (done) cv.Signal();
+          });
+    }
+    {
+      absl::MutexLock lock(&mu);
+      cv.Wait(&mu);
+    }
+    EXPECT_EQ(completed, num_rpcs);
+    return rpcs;
+  }
+
   const size_t num_backends_;
   const size_t num_balancers_;
   const int client_load_reporting_interval_seconds_;
@@ -2518,7 +2719,7 @@ TEST_P(BasicTest, Vanilla) {
   SetNextResolutionForLbChannelAllBalancers();
   const size_t kNumRpcsPerAddress = 100;
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -2544,12 +2745,11 @@ TEST_P(BasicTest, IgnoresUnhealthyEndpoints) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   const size_t kNumRpcsPerAddress = 100;
+  auto endpoints = CreateEndpointsForBackends();
+  endpoints[0].health_status = HealthStatus::DRAINING;
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0",
-       GetBackendPorts(),
-       kDefaultLocalityWeight,
-       kDefaultLocalityPriority,
-       {HealthStatus::DRAINING}},
+      {"locality0", std::move(endpoints), kDefaultLocalityWeight,
+       kDefaultLocalityPriority},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -2572,9 +2772,10 @@ TEST_P(BasicTest, SameBackendListedMultipleTimes) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Same backend listed twice.
-  std::vector<int> ports(2, backends_[0]->port());
+  auto endpoints = CreateEndpointsForBackends(0, 1);
+  endpoints.push_back(endpoints.front());
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", ports},
+      {"locality0", endpoints},
   });
   const size_t kNumRpcsPerAddress = 10;
   balancers_[0]->ads_service()->SetEdsResource(
@@ -2582,9 +2783,9 @@ TEST_P(BasicTest, SameBackendListedMultipleTimes) {
   // We need to wait for the backend to come online.
   WaitForBackend(0);
   // Send kNumRpcsPerAddress RPCs per server.
-  CheckRpcSendOk(kNumRpcsPerAddress * ports.size());
+  CheckRpcSendOk(kNumRpcsPerAddress * endpoints.size());
   // Backend should have gotten 20 requests.
-  EXPECT_EQ(kNumRpcsPerAddress * ports.size(),
+  EXPECT_EQ(kNumRpcsPerAddress * endpoints.size(),
             backends_[0]->backend_service()->request_count());
   // And they should have come from a single client port, because of
   // subchannel sharing.
@@ -2606,7 +2807,7 @@ TEST_P(BasicTest, InitiallyEmptyServerlist) {
       BuildEdsResource(args, DefaultEdsServiceName()));
   // Send non-empty serverlist only after kServerlistDelayMs.
   args = AdsServiceImpl::EdsResourceArgs({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   std::thread delayed_resource_setter(std::bind(
       &BasicTest::SetEdsResourceWithDelay, this, 0,
@@ -2629,20 +2830,25 @@ TEST_P(BasicTest, InitiallyEmptyServerlist) {
 // Tests that RPCs will fail with UNAVAILABLE instead of DEADLINE_EXCEEDED if
 // all the servers are unreachable.
 TEST_P(BasicTest, AllServersUnreachableFailFast) {
+  // Set Rpc timeout to 5 seconds to ensure there is enough time
+  // for communication with the xDS server to take place upon test start up.
+  const uint32_t kRpcTimeoutMs = 5000;
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   const size_t kNumUnreachableServers = 5;
-  std::vector<int> ports;
+  std::vector<AdsServiceImpl::EdsResourceArgs::Endpoint> endpoints;
   for (size_t i = 0; i < kNumUnreachableServers; ++i) {
-    ports.push_back(grpc_pick_unused_port_or_die());
+    endpoints.emplace_back(grpc_pick_unused_port_or_die());
   }
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", ports},
+      {"locality0", endpoints},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
-  const Status status = SendRpc();
-  // The error shouldn't be DEADLINE_EXCEEDED.
+  const Status status = SendRpc(RpcOptions().set_timeout_ms(kRpcTimeoutMs));
+  // The error shouldn't be DEADLINE_EXCEEDED because timeout is set to 5
+  // seconds, and we should disocver in that time that the target backend is
+  // down.
   EXPECT_EQ(StatusCode::UNAVAILABLE, status.error_code());
 }
 
@@ -2652,7 +2858,7 @@ TEST_P(BasicTest, BackendsRestart) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -2679,7 +2885,7 @@ TEST_P(BasicTest, IgnoresDuplicateUpdates) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -2708,7 +2914,7 @@ TEST_P(XdsResolverOnlyTest, ResourceTypeVersionPersistsAcrossStreamRestarts) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   // Wait for backends to come online.
@@ -2723,7 +2929,7 @@ TEST_P(XdsResolverOnlyTest, ResourceTypeVersionPersistsAcrossStreamRestarts) {
   // Update backend, just so we can be sure that the client has
   // reconnected to the balancer.
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args2));
   // Restart balancer.
@@ -2739,14 +2945,14 @@ TEST_P(XdsResolverOnlyTest, ChangeClusters) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 2)},
+      {"locality0", CreateEndpointsForBackends(0, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   // We need to wait for all backends to come online.
   WaitForAllBackends(0, 2);
   // Populate new EDS resource.
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 4)},
+      {"locality0", CreateEndpointsForBackends(2, 4)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args2, kNewEdsServiceName));
@@ -2774,7 +2980,7 @@ TEST_P(XdsResolverOnlyTest, ClusterRemoved) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   // We need to wait for all backends to come online.
@@ -2810,7 +3016,7 @@ TEST_P(XdsResolverOnlyTest, RestartsRequestsUponReconnection) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 2)},
+      {"locality0", CreateEndpointsForBackends(0, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   // We need to wait for all backends to come online.
@@ -2824,7 +3030,7 @@ TEST_P(XdsResolverOnlyTest, RestartsRequestsUponReconnection) {
   CheckRpcSendOk(100);
   // Populate new EDS resource.
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 4)},
+      {"locality0", CreateEndpointsForBackends(2, 4)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args2, kNewEdsServiceName));
@@ -2857,7 +3063,7 @@ TEST_P(XdsResolverOnlyTest, DefaultRouteSpecifiesSlashPrefix) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   // We need to wait for all backends to come online.
@@ -2870,7 +3076,7 @@ TEST_P(XdsResolverOnlyTest, CircuitBreaking) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   // Update CDS resource to set max concurrent request.
@@ -2912,7 +3118,7 @@ TEST_P(XdsResolverOnlyTest, CircuitBreakingMultipleChannelsShareCallCounter) {
   constexpr size_t kMaxConcurrentRequests = 10;
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   // Update CDS resource to set max concurrent request.
@@ -2925,14 +3131,21 @@ TEST_P(XdsResolverOnlyTest, CircuitBreakingMultipleChannelsShareCallCounter) {
   // Create second channel.
   auto response_generator2 =
       grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
+  auto lb_response_generator2 =
+      grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
+  grpc_arg xds_arg = grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
+      lb_response_generator2.get());
+  grpc_channel_args xds_channel_args2 = {1, &xds_arg};
   auto channel2 = CreateChannel(
       /*failover_timeout=*/0, /*server_name=*/kServerName,
-      response_generator2.get());
+      response_generator2.get(), &xds_channel_args2);
   auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
   // Set resolution results for both channels and for the xDS channel.
   SetNextResolution({});
   SetNextResolution({}, response_generator2.get());
   SetNextResolutionForLbChannelAllBalancers();
+  SetNextResolutionForLbChannelAllBalancers(nullptr, nullptr,
+                                            lb_response_generator2.get());
   // Send exactly max_concurrent_requests long RPCs, alternating between
   // the two channels.
   LongRunningRpc rpcs[kMaxConcurrentRequests];
@@ -2962,7 +3175,51 @@ TEST_P(XdsResolverOnlyTest, CircuitBreakingMultipleChannelsShareCallCounter) {
             backends_[0]->backend_service()->request_count());
 }
 
-TEST_P(XdsResolverOnlyTest, MultipleChannelsShareXdsClient) {
+TEST_P(XdsResolverOnlyTest, ClusterChangeAfterAdsCallFails) {
+  const char* kNewEdsResourceName = "new_eds_resource_name";
+  // Populate EDS resources.
+  AdsServiceImpl::EdsResourceArgs args({
+      {"locality0", CreateEndpointsForBackends(0, 1)},
+  });
+  balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
+  SetNextResolutionForLbChannelAllBalancers();
+  // Check that the channel is working.
+  CheckRpcSendOk();
+  // Stop and restart the balancer.
+  balancers_[0]->Shutdown();
+  balancers_[0]->Start();
+  // Create new EDS resource.
+  AdsServiceImpl::EdsResourceArgs args2({
+      {"locality0", CreateEndpointsForBackends(1, 2)},
+  });
+  balancers_[0]->ads_service()->SetEdsResource(
+      BuildEdsResource(args2, kNewEdsResourceName));
+  // Change CDS resource to point to new EDS resource.
+  auto cluster = default_cluster_;
+  cluster.mutable_eds_cluster_config()->set_service_name(kNewEdsResourceName);
+  balancers_[0]->ads_service()->SetCdsResource(cluster);
+  // Make sure client sees the change.
+  // TODO(roth): This should not be allowing errors.  The errors are
+  // being caused by a bug that triggers in the following situation:
+  //
+  // 1. xDS call fails.
+  // 2. When xDS call is restarted, the server sends the updated CDS
+  //    resource that points to the new EDS resource name.
+  // 3. When the client receives the CDS update, it does two things:
+  //    - Sends the update to the CDS LB policy, which creates a new
+  //      xds_cluster_resolver policy using the new EDS service name.
+  //    - Notices that the CDS update no longer refers to the old EDS
+  //      service name, so removes that resource, notifying the old
+  //      xds_cluster_resolver policy that the resource no longer exists.
+  //
+  // Need to figure out a way to fix this bug, and then change this to
+  // not allow failures.
+  WaitForBackend(1, WaitForBackendOptions().set_allow_failures(true));
+}
+
+using GlobalXdsClientTest = BasicTest;
+
+TEST_P(GlobalXdsClientTest, MultipleChannelsShareXdsClient) {
   const char* kNewServerName = "new-server.example.com";
   Listener listener = default_listener_;
   listener.set_name(kNewServerName);
@@ -2970,7 +3227,7 @@ TEST_P(XdsResolverOnlyTest, MultipleChannelsShareXdsClient) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   WaitForAllBackends();
@@ -2983,6 +3240,38 @@ TEST_P(XdsResolverOnlyTest, MultipleChannelsShareXdsClient) {
   EXPECT_EQ(1UL, balancers_[0]->ads_service()->clients().size());
 }
 
+// Tests that the NACK for multiple bad LDS resources includes both errors.
+TEST_P(GlobalXdsClientTest, MultipleBadResources) {
+  constexpr char kServerName2[] = "server.other.com";
+  auto listener = default_listener_;
+  listener.clear_api_listener();
+  balancers_[0]->ads_service()->SetLdsResource(listener);
+  listener.set_name(kServerName2);
+  balancers_[0]->ads_service()->SetLdsResource(listener);
+  SetNextResolutionForLbChannelAllBalancers();
+  CheckRpcSendFailure();
+  // Need to create a second channel to subscribe to a second LDS resource.
+  auto channel2 = CreateChannel(0, kServerName2);
+  auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
+  ClientContext context;
+  EchoRequest request;
+  request.set_message(kRequestMessage);
+  EchoResponse response;
+  grpc::Status status = stub2->Echo(&context, request, &response);
+  EXPECT_FALSE(status.ok());
+  const auto response_state =
+      balancers_[0]->ads_service()->lds_response_state();
+  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED);
+  EXPECT_THAT(
+      response_state.error_message,
+      ::testing::AllOf(
+          ::testing::HasSubstr(absl::StrCat(
+              kServerName, ": Listener has neither address nor ApiListener")),
+          ::testing::HasSubstr(
+              absl::StrCat(kServerName2,
+                           ": Listener has neither address nor ApiListener"))));
+}
+
 class XdsResolverLoadReportingOnlyTest : public XdsEnd2endTest {
  public:
   XdsResolverLoadReportingOnlyTest() : XdsEnd2endTest(4, 1, 3) {}
@@ -2998,12 +3287,12 @@ TEST_P(XdsResolverLoadReportingOnlyTest, ChangeClusters) {
   SetNextResolutionForLbChannelAllBalancers();
   // cluster kDefaultClusterName -> locality0 -> backends 0 and 1
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 2)},
+      {"locality0", CreateEndpointsForBackends(0, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   // cluster kNewClusterName -> locality1 -> backends 2 and 3
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality1", GetBackendPorts(2, 4)},
+      {"locality1", CreateEndpointsForBackends(2, 4)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args2, kNewEdsServiceName));
@@ -3123,7 +3412,7 @@ TEST_P(SecureNamingTest, TargetNameIsExpected) {
   SetNextResolution({});
   SetNextResolutionForLbChannel({balancers_[0]->port()}, nullptr, "xds_server");
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -3137,7 +3426,7 @@ TEST_P(SecureNamingTest, TargetNameIsUnexpected) {
   SetNextResolutionForLbChannel({balancers_[0]->port()}, nullptr,
                                 "incorrect_server_name");
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -3236,38 +3525,6 @@ TEST_P(LdsTest, RdsConfigSourceDoesNotSpecifyAds) {
           "HttpConnectionManager ConfigSource for RDS does not specify ADS."));
 }
 
-// Tests that the NACK for multiple bad LDS resources includes both errors.
-TEST_P(LdsTest, MultipleBadResources) {
-  constexpr char kServerName2[] = "server.other.com";
-  auto listener = default_listener_;
-  listener.clear_api_listener();
-  balancers_[0]->ads_service()->SetLdsResource(listener);
-  listener.set_name(kServerName2);
-  balancers_[0]->ads_service()->SetLdsResource(listener);
-  SetNextResolutionForLbChannelAllBalancers();
-  CheckRpcSendFailure();
-  // Need to create a second channel to subscribe to a second LDS resource.
-  auto channel2 = CreateChannel(0, kServerName2);
-  auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
-  ClientContext context;
-  EchoRequest request;
-  request.set_message(kRequestMessage);
-  EchoResponse response;
-  grpc::Status status = stub2->Echo(&context, request, &response);
-  EXPECT_FALSE(status.ok());
-  const auto response_state =
-      balancers_[0]->ads_service()->lds_response_state();
-  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED);
-  EXPECT_THAT(
-      response_state.error_message,
-      ::testing::AllOf(
-          ::testing::HasSubstr(absl::StrCat(
-              kServerName, ": Listener has neither address nor ApiListener")),
-          ::testing::HasSubstr(
-              absl::StrCat(kServerName2,
-                           ": Listener has neither address nor ApiListener"))));
-}
-
 // Tests that we ignore filters after the router filter.
 TEST_P(LdsTest, IgnoresHttpFiltersAfterRouterFilter) {
   SetNextResolutionForLbChannelAllBalancers();
@@ -3283,7 +3540,7 @@ TEST_P(LdsTest, IgnoresHttpFiltersAfterRouterFilter) {
       http_connection_manager);
   SetListenerAndRouteConfiguration(0, listener, default_route_config_);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -3302,7 +3559,7 @@ TEST_P(LdsTest, FailRpcsIfNoHttpRouterFilter) {
       http_connection_manager);
   SetListenerAndRouteConfiguration(0, listener, default_route_config_);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -3410,7 +3667,7 @@ TEST_P(LdsTest, IgnoresOptionalUnknownHttpFilterType) {
       http_connection_manager);
   SetListenerAndRouteConfiguration(0, listener, default_route_config_);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -3459,7 +3716,7 @@ TEST_P(LdsTest, IgnoresOptionalHttpFilterWithoutConfig) {
       http_connection_manager);
   SetListenerAndRouteConfiguration(0, listener, default_route_config_);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -3544,7 +3801,7 @@ TEST_P(LdsTest, IgnoresOptionalHttpFiltersNotSupportedOnClients) {
       http_connection_manager);
   SetListenerAndRouteConfiguration(0, listener, default_route_config_);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -3573,7 +3830,7 @@ TEST_P(LdsV2Test, IgnoresHttpFilters) {
       http_connection_manager);
   SetListenerAndRouteConfiguration(0, listener, default_route_config_);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -3603,7 +3860,7 @@ TEST_P(LdsRdsTest, ListenerRemoved) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   // We need to wait for all backends to come online.
@@ -4067,13 +4324,13 @@ TEST_P(LdsRdsTest, XdsRoutingPathMatching) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 2)},
+      {"locality0", CreateEndpointsForBackends(0, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(3, 4)},
+      {"locality0", CreateEndpointsForBackends(3, 4)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4142,13 +4399,13 @@ TEST_P(LdsRdsTest, XdsRoutingPathMatchingCaseInsensitive) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4207,13 +4464,13 @@ TEST_P(LdsRdsTest, XdsRoutingPrefixMatching) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 2)},
+      {"locality0", CreateEndpointsForBackends(0, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(3, 4)},
+      {"locality0", CreateEndpointsForBackends(3, 4)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4277,13 +4534,13 @@ TEST_P(LdsRdsTest, XdsRoutingPrefixMatchingCaseInsensitive) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4342,13 +4599,13 @@ TEST_P(LdsRdsTest, XdsRoutingPathRegexMatching) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 2)},
+      {"locality0", CreateEndpointsForBackends(0, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(3, 4)},
+      {"locality0", CreateEndpointsForBackends(3, 4)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4414,13 +4671,13 @@ TEST_P(LdsRdsTest, XdsRoutingPathRegexMatchingCaseInsensitive) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4475,21 +4732,25 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedCluster) {
   const char* kNewCluster2Name = "new_cluster_2";
   const char* kNewEdsService2Name = "new_eds_service_name_2";
   const char* kNotUsedClusterName = "not_used_cluster";
-  const size_t kNumEcho1Rpcs = 1000;
-  const size_t kNumEchoRpcs = 10;
+  const size_t kNumEchoRpcs = 10;  // RPCs that will go to a fixed backend.
   const size_t kWeight75 = 75;
   const size_t kWeight25 = 25;
+  const double kErrorTolerance = 0.05;
+  const double kWeight75Percent = static_cast<double>(kWeight75) / 100;
+  const double kWeight25Percent = static_cast<double>(kWeight25) / 100;
+  const size_t kNumEcho1Rpcs =
+      ComputeIdealNumRpcs(kWeight75Percent, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4533,7 +4794,8 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedCluster) {
   default_route->mutable_route()->set_cluster(kDefaultClusterName);
   SetRouteConfiguration(0, new_route_config);
   WaitForAllBackends(0, 1);
-  WaitForAllBackends(1, 3, true, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  WaitForAllBackends(1, 3, WaitForBackendOptions(),
+                     RpcOptions().set_rpc_service(SERVICE_ECHO1));
   CheckRpcSendOk(kNumEchoRpcs);
   CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions().set_rpc_service(SERVICE_ECHO1));
   // Make sure RPCs all go to the correct backend.
@@ -4545,24 +4807,12 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedCluster) {
   EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
   const int weight_25_request_count =
       backends_[2]->backend_service1()->request_count();
-  const double kErrorTolerance = 0.2;
-  EXPECT_THAT(
-      weight_75_request_count,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight75 / 100 * (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight75 / 100 * (1 + kErrorTolerance))));
-  // TODO(@donnadionne): Reduce tolerance: increased the tolerance to keep the
-  // test from flaking while debugging potential root cause.
-  const double kErrorToleranceSmallLoad = 0.3;
   gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
           weight_75_request_count, weight_25_request_count);
-  EXPECT_THAT(weight_25_request_count,
-              ::testing::AllOf(
-                  ::testing::Ge(static_cast<double>(kNumEcho1Rpcs) * kWeight25 /
-                                100 * (1 - kErrorToleranceSmallLoad)),
-                  ::testing::Le(static_cast<double>(kNumEcho1Rpcs) * kWeight25 /
-                                100 * (1 + kErrorToleranceSmallLoad))));
+  EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEcho1Rpcs,
+              ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
+  EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEcho1Rpcs,
+              ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
 }
 
 TEST_P(LdsRdsTest, RouteActionWeightedTargetDefaultRoute) {
@@ -4570,20 +4820,24 @@ TEST_P(LdsRdsTest, RouteActionWeightedTargetDefaultRoute) {
   const char* kNewEdsService1Name = "new_eds_service_name_1";
   const char* kNewCluster2Name = "new_cluster_2";
   const char* kNewEdsService2Name = "new_eds_service_name_2";
-  const size_t kNumEchoRpcs = 1000;
   const size_t kWeight75 = 75;
   const size_t kWeight25 = 25;
+  const double kErrorTolerance = 0.05;
+  const double kWeight75Percent = static_cast<double>(kWeight75) / 100;
+  const double kWeight25Percent = static_cast<double>(kWeight25) / 100;
+  const size_t kNumEchoRpcs =
+      ComputeIdealNumRpcs(kWeight75Percent, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4626,24 +4880,12 @@ TEST_P(LdsRdsTest, RouteActionWeightedTargetDefaultRoute) {
       backends_[1]->backend_service()->request_count();
   const int weight_25_request_count =
       backends_[2]->backend_service()->request_count();
-  const double kErrorTolerance = 0.2;
-  EXPECT_THAT(
-      weight_75_request_count,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumEchoRpcs) *
-                                     kWeight75 / 100 * (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumEchoRpcs) *
-                                     kWeight75 / 100 * (1 + kErrorTolerance))));
-  // TODO(@donnadionne): Reduce tolerance: increased the tolerance to keep the
-  // test from flaking while debugging potential root cause.
-  const double kErrorToleranceSmallLoad = 0.3;
   gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
           weight_75_request_count, weight_25_request_count);
-  EXPECT_THAT(weight_25_request_count,
-              ::testing::AllOf(
-                  ::testing::Ge(static_cast<double>(kNumEchoRpcs) * kWeight25 /
-                                100 * (1 - kErrorToleranceSmallLoad)),
-                  ::testing::Le(static_cast<double>(kNumEchoRpcs) * kWeight25 /
-                                100 * (1 + kErrorToleranceSmallLoad))));
+  EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEchoRpcs,
+              ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
+  EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEchoRpcs,
+              ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
 }
 
 TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateWeights) {
@@ -4653,25 +4895,32 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateWeights) {
   const char* kNewEdsService2Name = "new_eds_service_name_2";
   const char* kNewCluster3Name = "new_cluster_3";
   const char* kNewEdsService3Name = "new_eds_service_name_3";
-  const size_t kNumEcho1Rpcs = 1000;
   const size_t kNumEchoRpcs = 10;
   const size_t kWeight75 = 75;
   const size_t kWeight25 = 25;
   const size_t kWeight50 = 50;
+  const double kErrorTolerance = 0.05;
+  const double kWeight75Percent = static_cast<double>(kWeight75) / 100;
+  const double kWeight25Percent = static_cast<double>(kWeight25) / 100;
+  const double kWeight50Percent = static_cast<double>(kWeight50) / 100;
+  const size_t kNumEcho1Rpcs7525 =
+      ComputeIdealNumRpcs(kWeight75Percent, kErrorTolerance);
+  const size_t kNumEcho1Rpcs5050 =
+      ComputeIdealNumRpcs(kWeight50Percent, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   AdsServiceImpl::EdsResourceArgs args3({
-      {"locality0", GetBackendPorts(3, 4)},
+      {"locality0", CreateEndpointsForBackends(3, 4)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4717,9 +4966,11 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateWeights) {
   default_route->mutable_route()->set_cluster(kDefaultClusterName);
   SetRouteConfiguration(0, new_route_config);
   WaitForAllBackends(0, 1);
-  WaitForAllBackends(1, 3, true, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  WaitForAllBackends(1, 3, WaitForBackendOptions(),
+                     RpcOptions().set_rpc_service(SERVICE_ECHO1));
   CheckRpcSendOk(kNumEchoRpcs);
-  CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  CheckRpcSendOk(kNumEcho1Rpcs7525,
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
   // Make sure RPCs all go to the correct backend.
   EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
   EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
@@ -4732,24 +4983,12 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateWeights) {
       backends_[2]->backend_service1()->request_count();
   EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
   EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
-  const double kErrorTolerance = 0.2;
-  EXPECT_THAT(
-      weight_75_request_count,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight75 / 100 * (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight75 / 100 * (1 + kErrorTolerance))));
-  // TODO(@donnadionne): Reduce tolerance: increased the tolerance to keep the
-  // test from flaking while debugging potential root cause.
-  const double kErrorToleranceSmallLoad = 0.3;
   gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
           weight_75_request_count, weight_25_request_count);
-  EXPECT_THAT(weight_25_request_count,
-              ::testing::AllOf(
-                  ::testing::Ge(static_cast<double>(kNumEcho1Rpcs) * kWeight25 /
-                                100 * (1 - kErrorToleranceSmallLoad)),
-                  ::testing::Le(static_cast<double>(kNumEcho1Rpcs) * kWeight25 /
-                                100 * (1 + kErrorToleranceSmallLoad))));
+  EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEcho1Rpcs7525,
+              ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
+  EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEcho1Rpcs7525,
+              ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
   // Change Route Configurations: same clusters different weights.
   weighted_cluster1->mutable_weight()->set_value(kWeight50);
   weighted_cluster2->mutable_weight()->set_value(kWeight50);
@@ -4760,7 +4999,8 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateWeights) {
   ResetBackendCounters();
   WaitForAllBackends(3, 4);
   CheckRpcSendOk(kNumEchoRpcs);
-  CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  CheckRpcSendOk(kNumEcho1Rpcs5050,
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
   // Make sure RPCs all go to the correct backend.
   EXPECT_EQ(0, backends_[0]->backend_service()->request_count());
   EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
@@ -4773,17 +5013,11 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateWeights) {
   EXPECT_EQ(kNumEchoRpcs, backends_[3]->backend_service()->request_count());
   EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
   EXPECT_THAT(
-      weight_50_request_count_1,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight50 / 100 * (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight50 / 100 * (1 + kErrorTolerance))));
+      static_cast<double>(weight_50_request_count_1) / kNumEcho1Rpcs5050,
+      ::testing::DoubleNear(kWeight50Percent, kErrorTolerance));
   EXPECT_THAT(
-      weight_50_request_count_2,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight50 / 100 * (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight50 / 100 * (1 + kErrorTolerance))));
+      static_cast<double>(weight_50_request_count_2) / kNumEcho1Rpcs5050,
+      ::testing::DoubleNear(kWeight50Percent, kErrorTolerance));
 }
 
 TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) {
@@ -4793,25 +5027,32 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) {
   const char* kNewEdsService2Name = "new_eds_service_name_2";
   const char* kNewCluster3Name = "new_cluster_3";
   const char* kNewEdsService3Name = "new_eds_service_name_3";
-  const size_t kNumEcho1Rpcs = 1000;
   const size_t kNumEchoRpcs = 10;
   const size_t kWeight75 = 75;
   const size_t kWeight25 = 25;
   const size_t kWeight50 = 50;
+  const double kErrorTolerance = 0.05;
+  const double kWeight75Percent = static_cast<double>(kWeight75) / 100;
+  const double kWeight25Percent = static_cast<double>(kWeight25) / 100;
+  const double kWeight50Percent = static_cast<double>(kWeight50) / 100;
+  const size_t kNumEcho1Rpcs7525 =
+      ComputeIdealNumRpcs(kWeight75Percent, kErrorTolerance);
+  const size_t kNumEcho1Rpcs5050 =
+      ComputeIdealNumRpcs(kWeight50Percent, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   AdsServiceImpl::EdsResourceArgs args3({
-      {"locality0", GetBackendPorts(3, 4)},
+      {"locality0", CreateEndpointsForBackends(3, 4)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -4856,10 +5097,12 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) {
   default_route->mutable_match()->set_prefix("");
   default_route->mutable_route()->set_cluster(kDefaultClusterName);
   SetRouteConfiguration(0, new_route_config);
-  WaitForAllBackends(0, 1);
-  WaitForAllBackends(1, 2, true, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  WaitForBackend(0);
+  WaitForBackend(1, WaitForBackendOptions(),
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
   CheckRpcSendOk(kNumEchoRpcs);
-  CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  CheckRpcSendOk(kNumEcho1Rpcs7525,
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
   // Make sure RPCs all go to the correct backend.
   EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
   int weight_25_request_count =
@@ -4871,33 +5114,23 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) {
   EXPECT_EQ(0, backends_[2]->backend_service1()->request_count());
   EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
   EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
-  const double kErrorTolerance = 0.2;
-  EXPECT_THAT(
-      weight_75_request_count,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight75 / 100 * (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight75 / 100 * (1 + kErrorTolerance))));
-  // TODO(@donnadionne): Reduce tolerance: increased the tolerance to keep the
-  // test from flaking while debugging potential root cause.
-  const double kErrorToleranceSmallLoad = 0.3;
   gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
           weight_75_request_count, weight_25_request_count);
-  EXPECT_THAT(weight_25_request_count,
-              ::testing::AllOf(
-                  ::testing::Ge(static_cast<double>(kNumEcho1Rpcs) * kWeight25 /
-                                100 * (1 - kErrorToleranceSmallLoad)),
-                  ::testing::Le(static_cast<double>(kNumEcho1Rpcs) * kWeight25 /
-                                100 * (1 + kErrorToleranceSmallLoad))));
+  EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEcho1Rpcs7525,
+              ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
+  EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEcho1Rpcs7525,
+              ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
   // Change Route Configurations: new set of clusters with different weights.
   weighted_cluster1->mutable_weight()->set_value(kWeight50);
   weighted_cluster2->set_name(kNewCluster2Name);
   weighted_cluster2->mutable_weight()->set_value(kWeight50);
   SetRouteConfiguration(0, new_route_config);
   ResetBackendCounters();
-  WaitForAllBackends(2, 3, true, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  WaitForBackend(2, WaitForBackendOptions(),
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
   CheckRpcSendOk(kNumEchoRpcs);
-  CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  CheckRpcSendOk(kNumEcho1Rpcs5050,
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
   // Make sure RPCs all go to the correct backend.
   EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
   EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
@@ -4910,26 +5143,22 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) {
   EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
   EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
   EXPECT_THAT(
-      weight_50_request_count_1,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight50 / 100 * (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight50 / 100 * (1 + kErrorTolerance))));
+      static_cast<double>(weight_50_request_count_1) / kNumEcho1Rpcs5050,
+      ::testing::DoubleNear(kWeight50Percent, kErrorTolerance));
   EXPECT_THAT(
-      weight_50_request_count_2,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight50 / 100 * (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight50 / 100 * (1 + kErrorTolerance))));
+      static_cast<double>(weight_50_request_count_2) / kNumEcho1Rpcs5050,
+      ::testing::DoubleNear(kWeight50Percent, kErrorTolerance));
   // Change Route Configurations.
   weighted_cluster1->mutable_weight()->set_value(kWeight75);
   weighted_cluster2->set_name(kNewCluster3Name);
   weighted_cluster2->mutable_weight()->set_value(kWeight25);
   SetRouteConfiguration(0, new_route_config);
   ResetBackendCounters();
-  WaitForAllBackends(3, 4, true, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  WaitForBackend(3, WaitForBackendOptions(),
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
   CheckRpcSendOk(kNumEchoRpcs);
-  CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  CheckRpcSendOk(kNumEcho1Rpcs7525,
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
   // Make sure RPCs all go to the correct backend.
   EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
   EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
@@ -4939,22 +5168,12 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) {
   EXPECT_EQ(0, backends_[2]->backend_service1()->request_count());
   EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
   weight_25_request_count = backends_[3]->backend_service1()->request_count();
-  EXPECT_THAT(
-      weight_75_request_count,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight75 / 100 * (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumEcho1Rpcs) *
-                                     kWeight75 / 100 * (1 + kErrorTolerance))));
-  // TODO(@donnadionne): Reduce tolerance: increased the tolerance to keep the
-  // test from flaking while debugging potential root cause.
   gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
           weight_75_request_count, weight_25_request_count);
-  EXPECT_THAT(weight_25_request_count,
-              ::testing::AllOf(
-                  ::testing::Ge(static_cast<double>(kNumEcho1Rpcs) * kWeight25 /
-                                100 * (1 - kErrorToleranceSmallLoad)),
-                  ::testing::Le(static_cast<double>(kNumEcho1Rpcs) * kWeight25 /
-                                100 * (1 + kErrorToleranceSmallLoad))));
+  EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEcho1Rpcs7525,
+              ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
+  EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEcho1Rpcs7525,
+              ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
 }
 
 TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClusters) {
@@ -4965,10 +5184,10 @@ TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClusters) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -5004,10 +5223,10 @@ TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClustersWithPickingDelays) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -5041,7 +5260,9 @@ TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClustersWithPickingDelays) {
   SetRouteConfiguration(0, new_route_config);
   // Wait for RPCs to go to the new backend: 1, this ensures that the client has
   // processed the update.
-  WaitForAllBackends(1, 2, false, RpcOptions(), true);
+  WaitForBackend(
+      1, WaitForBackendOptions().set_reset_counters(false).set_allow_failures(
+             true));
   // Bring up the previous backend: 0, this will allow the delayed RPC to
   // finally call on_call_committed upon completion.
   StartBackend(0);
@@ -5067,18 +5288,14 @@ TEST_P(LdsRdsTest, XdsRoutingApplyXdsTimeout) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {grpc_pick_unused_port_or_die()}},
-  });
-  AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", {grpc_pick_unused_port_or_die()}},
-  });
-  AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", {grpc_pick_unused_port_or_die()}},
-  });
-  AdsServiceImpl::EdsResourceArgs args3({
-      {"locality0", {grpc_pick_unused_port_or_die()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", {MakeNonExistantEndpoint()}}});
+  AdsServiceImpl::EdsResourceArgs args1(
+      {{"locality0", {MakeNonExistantEndpoint()}}});
+  AdsServiceImpl::EdsResourceArgs args2(
+      {{"locality0", {MakeNonExistantEndpoint()}}});
+  AdsServiceImpl::EdsResourceArgs args3(
+      {{"locality0", {MakeNonExistantEndpoint()}}});
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args1, kNewEdsService1Name));
@@ -5198,15 +5415,12 @@ TEST_P(LdsRdsTest, XdsRoutingApplyApplicationTimeoutWhenXdsTimeoutExplicit0) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {grpc_pick_unused_port_or_die()}},
-  });
-  AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", {grpc_pick_unused_port_or_die()}},
-  });
-  AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", {grpc_pick_unused_port_or_die()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", {MakeNonExistantEndpoint()}}});
+  AdsServiceImpl::EdsResourceArgs args1(
+      {{"locality0", {MakeNonExistantEndpoint()}}});
+  AdsServiceImpl::EdsResourceArgs args2(
+      {{"locality0", {MakeNonExistantEndpoint()}}});
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args1, kNewEdsService1Name));
@@ -5295,9 +5509,8 @@ TEST_P(LdsRdsTest, XdsRoutingApplyApplicationTimeoutWhenHttpTimeoutExplicit0) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {grpc_pick_unused_port_or_die()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", {MakeNonExistantEndpoint()}}});
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   auto listener = default_listener_;
   HttpConnectionManager http_connection_manager;
@@ -5334,9 +5547,8 @@ TEST_P(LdsRdsTest, XdsRoutingWithOnlyApplicationTimeout) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {grpc_pick_unused_port_or_die()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", {MakeNonExistantEndpoint()}}});
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   auto t0 = system_clock::now();
   CheckRpcSendFailure(1,
@@ -5359,10 +5571,10 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatching) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -5420,8 +5632,8 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatching) {
                                             .set_rpc_method(METHOD_ECHO1)
                                             .set_metadata(std::move(metadata));
   // Make sure all backends are up.
-  WaitForAllBackends(0, 1);
-  WaitForAllBackends(1, 2, true, header_match_rpc_options);
+  WaitForBackend(0);
+  WaitForBackend(1, WaitForBackendOptions(), header_match_rpc_options);
   // Send RPCs.
   CheckRpcSendOk(kNumEchoRpcs);
   CheckRpcSendOk(kNumEcho1Rpcs, header_match_rpc_options);
@@ -5443,10 +5655,10 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialHeaderContentType) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -5490,10 +5702,10 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -5533,15 +5745,20 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
 TEST_P(LdsRdsTest, XdsRoutingRuntimeFractionMatching) {
   const char* kNewClusterName = "new_cluster";
   const char* kNewEdsServiceName = "new_eds_service_name";
-  const size_t kNumRpcs = 1000;
+  const double kErrorTolerance = 0.05;
+  const size_t kRouteMatchNumerator = 25;
+  const double kRouteMatchPercent =
+      static_cast<double>(kRouteMatchNumerator) / 100;
+  const size_t kNumRpcs =
+      ComputeIdealNumRpcs(kRouteMatchPercent, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -5558,7 +5775,7 @@ TEST_P(LdsRdsTest, XdsRoutingRuntimeFractionMatching) {
   route1->mutable_match()
       ->mutable_runtime_fraction()
       ->mutable_default_value()
-      ->set_numerator(25);
+      ->set_numerator(kRouteMatchNumerator);
   route1->mutable_route()->set_cluster(kNewClusterName);
   auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
   default_route->mutable_match()->set_prefix("");
@@ -5570,19 +5787,10 @@ TEST_P(LdsRdsTest, XdsRoutingRuntimeFractionMatching) {
       backends_[0]->backend_service()->request_count();
   const int matched_backend_count =
       backends_[1]->backend_service()->request_count();
-  const double kErrorTolerance = 0.2;
-  EXPECT_THAT(
-      default_backend_count,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumRpcs) * 75 / 100 *
-                                     (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumRpcs) * 75 / 100 *
-                                     (1 + kErrorTolerance))));
-  EXPECT_THAT(
-      matched_backend_count,
-      ::testing::AllOf(::testing::Ge(static_cast<double>(kNumRpcs) * 25 / 100 *
-                                     (1 - kErrorTolerance)),
-                       ::testing::Le(static_cast<double>(kNumRpcs) * 25 / 100 *
-                                     (1 + kErrorTolerance))));
+  EXPECT_THAT(static_cast<double>(default_backend_count) / kNumRpcs,
+              ::testing::DoubleNear(1 - kRouteMatchPercent, kErrorTolerance));
+  EXPECT_THAT(static_cast<double>(matched_backend_count) / kNumRpcs,
+              ::testing::DoubleNear(kRouteMatchPercent, kErrorTolerance));
   const auto response_state = RouteConfigurationResponseState(0);
   EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED);
 }
@@ -5600,16 +5808,16 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingUnmatchCases) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   AdsServiceImpl::EdsResourceArgs args3({
-      {"locality0", GetBackendPorts(3, 4)},
+      {"locality0", CreateEndpointsForBackends(3, 4)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -5693,10 +5901,10 @@ TEST_P(LdsRdsTest, XdsRoutingChangeRoutesWithoutChangingClusters) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   balancers_[0]->ads_service()->SetEdsResource(
@@ -5718,9 +5926,11 @@ TEST_P(LdsRdsTest, XdsRoutingChangeRoutesWithoutChangingClusters) {
   SetRouteConfiguration(0, route_config);
   // Make sure all backends are up and that requests for each RPC
   // service go to the right backends.
-  WaitForAllBackends(0, 1, false);
-  WaitForAllBackends(1, 2, false, RpcOptions().set_rpc_service(SERVICE_ECHO1));
-  WaitForAllBackends(0, 1, false, RpcOptions().set_rpc_service(SERVICE_ECHO2));
+  WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false));
+  WaitForBackend(1, WaitForBackendOptions().set_reset_counters(false),
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false),
+                 RpcOptions().set_rpc_service(SERVICE_ECHO2));
   // Requests for services Echo and Echo2 should have gone to backend 0.
   EXPECT_EQ(1, backends_[0]->backend_service()->request_count());
   EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
@@ -5733,12 +5943,15 @@ TEST_P(LdsRdsTest, XdsRoutingChangeRoutesWithoutChangingClusters) {
   // different RPC service, and wait for the client to make the change.
   route1->mutable_match()->set_prefix("/grpc.testing.EchoTest2Service/");
   SetRouteConfiguration(0, route_config);
-  WaitForAllBackends(1, 2, true, RpcOptions().set_rpc_service(SERVICE_ECHO2));
+  WaitForBackend(1, WaitForBackendOptions(),
+                 RpcOptions().set_rpc_service(SERVICE_ECHO2));
   // Now repeat the earlier test, making sure all traffic goes to the
   // right place.
-  WaitForAllBackends(0, 1, false);
-  WaitForAllBackends(0, 1, false, RpcOptions().set_rpc_service(SERVICE_ECHO1));
-  WaitForAllBackends(1, 2, false, RpcOptions().set_rpc_service(SERVICE_ECHO2));
+  WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false));
+  WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false),
+                 RpcOptions().set_rpc_service(SERVICE_ECHO1));
+  WaitForBackend(1, WaitForBackendOptions().set_reset_counters(false),
+                 RpcOptions().set_rpc_service(SERVICE_ECHO2));
   // Requests for services Echo and Echo1 should have gone to backend 0.
   EXPECT_EQ(1, backends_[0]->backend_service()->request_count());
   EXPECT_EQ(1, backends_[0]->backend_service1()->request_count());
@@ -5783,7 +5996,7 @@ TEST_P(LdsRdsTest, IgnoresOptionalUnknownHttpFilterTypeInVirtualHost) {
   (*per_filter_config)["unknown"].PackFrom(filter_config);
   SetListenerAndRouteConfiguration(0, default_listener_, route_config);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -5850,7 +6063,7 @@ TEST_P(LdsRdsTest, IgnoresOptionalHttpFilterWithoutConfigInVirtualHost) {
   (*per_filter_config)["unknown"].PackFrom(filter_config);
   SetListenerAndRouteConfiguration(0, default_listener_, route_config);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -5920,7 +6133,7 @@ TEST_P(LdsRdsTest, IgnoresOptionalUnknownHttpFilterTypeInRoute) {
   (*per_filter_config)["unknown"].PackFrom(filter_config);
   SetListenerAndRouteConfiguration(0, default_listener_, route_config);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -5990,7 +6203,7 @@ TEST_P(LdsRdsTest, IgnoresOptionalHttpFilterWithoutConfigInRoute) {
   (*per_filter_config)["unknown"].PackFrom(filter_config);
   SetListenerAndRouteConfiguration(0, default_listener_, route_config);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -6071,7 +6284,7 @@ TEST_P(LdsRdsTest, IgnoresOptionalUnknownHttpFilterTypeInClusterWeight) {
   (*per_filter_config)["unknown"].PackFrom(filter_config);
   SetListenerAndRouteConfiguration(0, default_listener_, route_config);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -6157,7 +6370,7 @@ TEST_P(LdsRdsTest, IgnoresOptionalHttpFilterWithoutConfigInClusterWeight) {
   (*per_filter_config)["unknown"].PackFrom(filter_config);
   SetListenerAndRouteConfiguration(0, default_listener_, route_config);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -6242,10 +6455,10 @@ TEST_P(CdsTest, AggregateClusterType) {
   SetNextResolutionForLbChannelAllBalancers();
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args1, kNewEdsService1Name));
@@ -6275,7 +6488,7 @@ TEST_P(CdsTest, AggregateClusterType) {
   WaitForBackend(1);
   // Shutdown backend 1 and wait for all traffic to go to backend 2.
   ShutdownBackend(1);
-  WaitForBackend(2);
+  WaitForBackend(2, WaitForBackendOptions().set_allow_failures(true));
   EXPECT_EQ(balancers_[0]->ads_service()->cds_response_state().state,
             AdsServiceImpl::ResponseState::ACKED);
   // Bring backend 1 back and ensure all traffic go back to it.
@@ -6295,7 +6508,7 @@ TEST_P(CdsTest, AggregateClusterEdsToLogicalDns) {
   const char* kLogicalDNSClusterName = "logical_dns_cluster";
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args1({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args1, kNewEdsService1Name));
@@ -6331,7 +6544,7 @@ TEST_P(CdsTest, AggregateClusterEdsToLogicalDns) {
   WaitForBackend(1);
   // Shutdown backend 1 and wait for all traffic to go to backend 2.
   ShutdownBackend(1);
-  WaitForBackend(2);
+  WaitForBackend(2, WaitForBackendOptions().set_allow_failures(true));
   EXPECT_EQ(balancers_[0]->ads_service()->cds_response_state().state,
             AdsServiceImpl::ResponseState::ACKED);
   // Bring backend 1 back and ensure all traffic go back to it.
@@ -6351,7 +6564,7 @@ TEST_P(CdsTest, AggregateClusterLogicalDnsToEds) {
   const char* kLogicalDNSClusterName = "logical_dns_cluster";
   // Populate new EDS resources.
   AdsServiceImpl::EdsResourceArgs args2({
-      {"locality0", GetBackendPorts(2, 3)},
+      {"locality0", CreateEndpointsForBackends(2, 3)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args2, kNewEdsService2Name));
@@ -6387,7 +6600,7 @@ TEST_P(CdsTest, AggregateClusterLogicalDnsToEds) {
   WaitForBackend(1);
   // Shutdown backend 1 and wait for all traffic to go to backend 2.
   ShutdownBackend(1);
-  WaitForBackend(2);
+  WaitForBackend(2, WaitForBackendOptions().set_allow_failures(true));
   EXPECT_EQ(balancers_[0]->ads_service()->cds_response_state().state,
             AdsServiceImpl::ResponseState::ACKED);
   // Bring backend 1 back and ensure all traffic go back to it.
@@ -6567,7 +6780,7 @@ class XdsSecurityTest : public BasicTest {
                                         "waterzooi.test.google.be",
                                         "*.test.youtube.com", "192.168.1.3"};
     AdsServiceImpl::EdsResourceArgs args({
-        {"locality0", GetBackendPorts(0, 1)},
+        {"locality0", CreateEndpointsForBackends(0, 1)},
     });
     balancers_[0]->ads_service()->SetEdsResource(
         BuildEdsResource(args, DefaultEdsServiceName()));
@@ -6643,7 +6856,7 @@ class XdsSecurityTest : public BasicTest {
           continue;
         }
       } else {
-        WaitForBackend(0);
+        WaitForBackend(0, WaitForBackendOptions().set_allow_failures(true));
         Status status = SendRpc();
         if (!status.ok()) {
           gpr_log(GPR_ERROR, "RPC failed. code=%d message=%s Trying again.",
@@ -7159,7 +7372,7 @@ class XdsEnabledServerTest : public XdsEnd2endTest {
   void SetUp() override {
     XdsEnd2endTest::SetUp();
     AdsServiceImpl::EdsResourceArgs args({
-        {"locality0", GetBackendPorts(0, 1)},
+        {"locality0", CreateEndpointsForBackends(0, 1)},
     });
     balancers_[0]->ads_service()->SetEdsResource(
         BuildEdsResource(args, DefaultEdsServiceName()));
@@ -7254,7 +7467,6 @@ TEST_P(XdsEnabledServerTest, UnsupportedL4Filter) {
 }
 
 TEST_P(XdsEnabledServerTest, UnsupportedHttpFilter) {
-  // Set env var to enable filters parsing.
   Listener listener;
   listener.set_name(
       absl::StrCat("grpc/server?xds.resource.listening_address=",
@@ -7288,7 +7500,6 @@ TEST_P(XdsEnabledServerTest, UnsupportedHttpFilter) {
 }
 
 TEST_P(XdsEnabledServerTest, HttpFilterNotSupportedOnServer) {
-  // Set env var to enable filters parsing.
   Listener listener;
   listener.set_name(
       absl::StrCat("grpc/server?xds.resource.listening_address=",
@@ -7324,7 +7535,6 @@ TEST_P(XdsEnabledServerTest, HttpFilterNotSupportedOnServer) {
 
 TEST_P(XdsEnabledServerTest,
        HttpFilterNotSupportedOnServerIgnoredWhenOptional) {
-  // Set env var to enable filters parsing.
   Listener listener;
   listener.set_name(
       absl::StrCat("grpc/server?xds.resource.listening_address=",
@@ -7432,7 +7642,7 @@ class XdsServerSecurityTest : public XdsEnd2endTest {
                                       "waterzooi.test.google.be",
                                       "*.test.youtube.com", "192.168.1.3"};
     AdsServiceImpl::EdsResourceArgs args({
-        {"locality0", GetBackendPorts(0, 1)},
+        {"locality0", CreateEndpointsForBackends(0, 1)},
     });
     balancers_[0]->ads_service()->SetEdsResource(
         BuildEdsResource(args, DefaultEdsServiceName()));
@@ -7452,11 +7662,12 @@ class XdsServerSecurityTest : public XdsEnd2endTest {
                     absl::string_view identity_certificate_name,
                     bool require_client_certificates) {
     Listener listener;
-    listener.set_name(
-        absl::StrCat("grpc/server?xds.resource.listening_address=127.0.0.1:",
-                     backends_[0]->port()));
+    listener.set_name(absl::StrCat(
+        ipv6_only_ ? "grpc/server?xds.resource.listening_address=[::1]:"
+                   : "grpc/server?xds.resource.listening_address=127.0.0.1:",
+        backends_[0]->port()));
     listener.mutable_address()->mutable_socket_address()->set_address(
-        "127.0.0.1");
+        ipv6_only_ ? "[::1]" : "127.0.0.1");
     listener.mutable_address()->mutable_socket_address()->set_port_value(
         backends_[0]->port());
     auto* filter_chain = listener.add_filter_chains();
@@ -7488,11 +7699,6 @@ class XdsServerSecurityTest : public XdsEnd2endTest {
           downstream_tls_context);
     }
     balancers_[0]->ads_service()->SetLdsResource(listener);
-    listener.set_name(
-        absl::StrCat("grpc/server?xds.resource.listening_address=[::1]:",
-                     backends_[0]->port()));
-    listener.mutable_address()->mutable_socket_address()->set_address("[::1]");
-    balancers_[0]->ads_service()->SetLdsResource(listener);
   }
 
   std::shared_ptr<grpc::Channel> CreateMtlsChannel() {
@@ -7575,7 +7781,7 @@ class XdsServerSecurityTest : public XdsEnd2endTest {
                bool test_expects_failure = false) {
     gpr_log(GPR_INFO, "Sending RPC");
     int num_tries = 0;
-    constexpr int kRetryCount = 10;
+    constexpr int kRetryCount = 100;
     for (; num_tries < kRetryCount; num_tries++) {
       auto channel = channel_creator();
       auto stub = grpc::testing::EchoTestService::NewStub(channel);
@@ -8236,11 +8442,11 @@ TEST_P(XdsServerFilterChainMatchTest,
       HttpConnectionManager());
   auto* prefix_range =
       filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(4);
   prefix_range =
       filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(16);
   filter_chain->mutable_filter_chain_match()->add_server_names("server_name");
   // Add filter chain with two prefix ranges (length 8 and 24). Since 24 is the
@@ -8250,11 +8456,11 @@ TEST_P(XdsServerFilterChainMatchTest,
       HttpConnectionManager());
   prefix_range =
       filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(8);
   prefix_range =
       filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(24);
   // Add another filter chain with a non-matching prefix range (with length 30)
   filter_chain = listener.add_filter_chains();
@@ -8331,11 +8537,11 @@ TEST_P(XdsServerFilterChainMatchTest,
       HttpConnectionManager());
   auto* source_prefix_range =
       filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
-  source_prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   source_prefix_range->mutable_prefix_len()->set_value(4);
   source_prefix_range =
       filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
-  source_prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   source_prefix_range->mutable_prefix_len()->set_value(16);
   filter_chain->mutable_filter_chain_match()->add_source_ports(
       backends_[0]->port());
@@ -8346,11 +8552,11 @@ TEST_P(XdsServerFilterChainMatchTest,
       HttpConnectionManager());
   source_prefix_range =
       filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
-  source_prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   source_prefix_range->mutable_prefix_len()->set_value(8);
   source_prefix_range =
       filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
-  source_prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   source_prefix_range->mutable_prefix_len()->set_value(24);
   // Add another filter chain with a non-matching source prefix range (with
   // length 30) and bad source port
@@ -8428,15 +8634,14 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchNacked) {
   filter_chain->add_filters()->mutable_typed_config()->PackFrom(
       HttpConnectionManager());
   balancers_[0]->ads_service()->SetLdsResource(listener);
+  auto initial_time = absl::Now();
   do {
     CheckRpcSendFailure();
-  } while (balancers_[0]->ads_service()->lds_response_state().state ==
-           AdsServiceImpl::ResponseState::SENT);
-  const auto response_state =
-      balancers_[0]->ads_service()->lds_response_state();
-  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED);
+  } while (balancers_[0]->ads_service()->lds_response_state().state !=
+               AdsServiceImpl::ResponseState::NACKED &&
+           initial_time + absl::Seconds(60) > absl::Now());
   EXPECT_THAT(
-      response_state.error_message,
+      balancers_[0]->ads_service()->lds_response_state().error_message,
       ::testing::HasSubstr(
           "Duplicate matching rules detected when adding filter chain: {}"));
 }
@@ -8455,11 +8660,11 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnPrefixRangesNacked) {
       HttpConnectionManager());
   auto* prefix_range =
       filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(16);
   prefix_range =
       filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(24);
   // Add a filter chain with a duplicate prefix range entry
   filter_chain = listener.add_filter_chains();
@@ -8467,26 +8672,34 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnPrefixRangesNacked) {
       HttpConnectionManager());
   prefix_range =
       filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(16);
   prefix_range =
       filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(32);
   balancers_[0]->ads_service()->SetLdsResource(listener);
+  auto initial_time = absl::Now();
   do {
     CheckRpcSendFailure();
-  } while (balancers_[0]->ads_service()->lds_response_state().state ==
-           AdsServiceImpl::ResponseState::SENT);
-  const auto response_state =
-      balancers_[0]->ads_service()->lds_response_state();
-  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED);
-  EXPECT_THAT(
-      response_state.error_message,
-      ::testing::HasSubstr(
-          "Duplicate matching rules detected when adding filter chain: "
-          "{prefix_ranges={{address_prefix=127.0.0.0:0, prefix_len=16}, "
-          "{address_prefix=127.0.0.1:0, prefix_len=32}}}"));
+  } while (balancers_[0]->ads_service()->lds_response_state().state !=
+               AdsServiceImpl::ResponseState::NACKED &&
+           initial_time + absl::Seconds(60) > absl::Now());
+  if (ipv6_only_) {
+    EXPECT_THAT(
+        balancers_[0]->ads_service()->lds_response_state().error_message,
+        ::testing::HasSubstr(
+            "Duplicate matching rules detected when adding filter chain: "
+            "{prefix_ranges={{address_prefix=[::]:0, prefix_len=16}, "
+            "{address_prefix=[::]:0, prefix_len=32}}}"));
+  } else {
+    EXPECT_THAT(
+        balancers_[0]->ads_service()->lds_response_state().error_message,
+        ::testing::HasSubstr(
+            "Duplicate matching rules detected when adding filter chain: "
+            "{prefix_ranges={{address_prefix=127.0.0.0:0, prefix_len=16}, "
+            "{address_prefix=127.0.0.1:0, prefix_len=32}}}"));
+  }
 }
 
 TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnTransportProtocolNacked) {
@@ -8511,15 +8724,14 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnTransportProtocolNacked) {
   filter_chain->mutable_filter_chain_match()->set_transport_protocol(
       "raw_buffer");
   balancers_[0]->ads_service()->SetLdsResource(listener);
+  auto initial_time = absl::Now();
   do {
     CheckRpcSendFailure();
-  } while (balancers_[0]->ads_service()->lds_response_state().state ==
-           AdsServiceImpl::ResponseState::SENT);
-  const auto response_state =
-      balancers_[0]->ads_service()->lds_response_state();
-  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED);
+  } while (balancers_[0]->ads_service()->lds_response_state().state !=
+               AdsServiceImpl::ResponseState::NACKED &&
+           initial_time + absl::Seconds(60) > absl::Now());
   EXPECT_THAT(
-      response_state.error_message,
+      balancers_[0]->ads_service()->lds_response_state().error_message,
       ::testing::HasSubstr("Duplicate matching rules detected when adding "
                            "filter chain: {transport_protocol=raw_buffer}"));
 }
@@ -8545,15 +8757,14 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnLocalSourceTypeNacked) {
   filter_chain->mutable_filter_chain_match()->set_source_type(
       FilterChainMatch::SAME_IP_OR_LOOPBACK);
   balancers_[0]->ads_service()->SetLdsResource(listener);
+  auto initial_time = absl::Now();
   do {
     CheckRpcSendFailure();
-  } while (balancers_[0]->ads_service()->lds_response_state().state ==
-           AdsServiceImpl::ResponseState::SENT);
-  const auto response_state =
-      balancers_[0]->ads_service()->lds_response_state();
-  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED);
+  } while (balancers_[0]->ads_service()->lds_response_state().state !=
+               AdsServiceImpl::ResponseState::NACKED &&
+           initial_time + absl::Seconds(60) > absl::Now());
   EXPECT_THAT(
-      response_state.error_message,
+      balancers_[0]->ads_service()->lds_response_state().error_message,
       ::testing::HasSubstr("Duplicate matching rules detected when adding "
                            "filter chain: {source_type=SAME_IP_OR_LOOPBACK}"));
 }
@@ -8580,15 +8791,14 @@ TEST_P(XdsServerFilterChainMatchTest,
   filter_chain->mutable_filter_chain_match()->set_source_type(
       FilterChainMatch::EXTERNAL);
   balancers_[0]->ads_service()->SetLdsResource(listener);
+  auto initial_time = absl::Now();
   do {
     CheckRpcSendFailure();
-  } while (balancers_[0]->ads_service()->lds_response_state().state ==
-           AdsServiceImpl::ResponseState::SENT);
-  const auto response_state =
-      balancers_[0]->ads_service()->lds_response_state();
-  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED);
+  } while (balancers_[0]->ads_service()->lds_response_state().state !=
+               AdsServiceImpl::ResponseState::NACKED &&
+           initial_time + absl::Seconds(60) > absl::Now());
   EXPECT_THAT(
-      response_state.error_message,
+      balancers_[0]->ads_service()->lds_response_state().error_message,
       ::testing::HasSubstr("Duplicate matching rules detected when adding "
                            "filter chain: {source_type=EXTERNAL}"));
 }
@@ -8608,11 +8818,11 @@ TEST_P(XdsServerFilterChainMatchTest,
       HttpConnectionManager());
   auto* prefix_range =
       filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(16);
   prefix_range =
       filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(24);
   // Add a filter chain with a duplicate source prefix range entry
   filter_chain = listener.add_filter_chains();
@@ -8620,26 +8830,35 @@ TEST_P(XdsServerFilterChainMatchTest,
       HttpConnectionManager());
   prefix_range =
       filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(16);
   prefix_range =
       filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
-  prefix_range->set_address_prefix(ipv6_only_ ? "[::1]" : "127.0.0.1");
+  prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
   prefix_range->mutable_prefix_len()->set_value(32);
   balancers_[0]->ads_service()->SetLdsResource(listener);
+  auto initial_time = absl::Now();
   do {
     CheckRpcSendFailure();
-  } while (balancers_[0]->ads_service()->lds_response_state().state ==
-           AdsServiceImpl::ResponseState::SENT);
-  const auto response_state =
-      balancers_[0]->ads_service()->lds_response_state();
-  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED);
-  EXPECT_THAT(
-      response_state.error_message,
-      ::testing::HasSubstr(
-          "Duplicate matching rules detected when adding filter chain: "
-          "{source_prefix_ranges={{address_prefix=127.0.0.0:0, prefix_len=16}, "
-          "{address_prefix=127.0.0.1:0, prefix_len=32}}}"));
+  } while (balancers_[0]->ads_service()->lds_response_state().state !=
+               AdsServiceImpl::ResponseState::NACKED &&
+           initial_time + absl::Seconds(60) > absl::Now());
+  if (ipv6_only_) {
+    EXPECT_THAT(
+        balancers_[0]->ads_service()->lds_response_state().error_message,
+        ::testing::HasSubstr(
+            "Duplicate matching rules detected when adding filter chain: "
+            "{source_prefix_ranges={{address_prefix=[::]:0, prefix_len=16}, "
+            "{address_prefix=[::]:0, prefix_len=32}}}"));
+  } else {
+    EXPECT_THAT(
+        balancers_[0]->ads_service()->lds_response_state().error_message,
+        ::testing::HasSubstr(
+            "Duplicate matching rules detected when adding filter chain: "
+            "{source_prefix_ranges={{address_prefix=127.0.0.0:0, "
+            "prefix_len=16}, "
+            "{address_prefix=127.0.0.1:0, prefix_len=32}}}"));
+  }
 }
 
 TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnSourcePortNacked) {
@@ -8661,15 +8880,14 @@ TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnSourcePortNacked) {
       HttpConnectionManager());
   filter_chain->mutable_filter_chain_match()->add_source_ports(8080);
   balancers_[0]->ads_service()->SetLdsResource(listener);
+  auto initial_time = absl::Now();
   do {
     CheckRpcSendFailure();
-  } while (balancers_[0]->ads_service()->lds_response_state().state ==
-           AdsServiceImpl::ResponseState::SENT);
-  const auto response_state =
-      balancers_[0]->ads_service()->lds_response_state();
-  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED);
+  } while (balancers_[0]->ads_service()->lds_response_state().state !=
+               AdsServiceImpl::ResponseState::NACKED &&
+           initial_time + absl::Seconds(60) > absl::Now());
   EXPECT_THAT(
-      response_state.error_message,
+      balancers_[0]->ads_service()->lds_response_state().error_message,
       ::testing::HasSubstr("Duplicate matching rules detected when adding "
                            "filter chain: {source_ports={8080}}"));
 }
@@ -8682,7 +8900,7 @@ TEST_P(EdsTest, NacksSparsePriorityList) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(), kDefaultLocalityWeight, 1},
+      {"locality0", CreateEndpointsForBackends(), kDefaultLocalityWeight, 1},
   });
   balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
   CheckRpcSendFailure();
@@ -8700,7 +8918,7 @@ TEST_P(EdsTest, NacksSparsePriorityList) {
 // cluster name if not specified in the CDS resource.
 TEST_P(EdsTest, EdsServiceNameDefaultsToClusterName) {
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, kDefaultClusterName));
@@ -8757,7 +8975,6 @@ using LocalityMapTest = BasicTest;
 TEST_P(LocalityMapTest, WeightedRoundRobin) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  const size_t kNumRpcs = 5000;
   const int kLocalityWeight0 = 2;
   const int kLocalityWeight1 = 8;
   const int kTotalLocalityWeight = kLocalityWeight0 + kLocalityWeight1;
@@ -8765,10 +8982,13 @@ TEST_P(LocalityMapTest, WeightedRoundRobin) {
       static_cast<double>(kLocalityWeight0) / kTotalLocalityWeight;
   const double kLocalityWeightRate1 =
       static_cast<double>(kLocalityWeight1) / kTotalLocalityWeight;
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs =
+      ComputeIdealNumRpcs(kLocalityWeightRate0, kErrorTolerance);
   // ADS response contains 2 localities, each of which contains 1 backend.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1), kLocalityWeight0},
-      {"locality1", GetBackendPorts(1, 2), kLocalityWeight1},
+      {"locality0", CreateEndpointsForBackends(0, 1), kLocalityWeight0},
+      {"locality1", CreateEndpointsForBackends(1, 2), kLocalityWeight1},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -8783,15 +9003,10 @@ TEST_P(LocalityMapTest, WeightedRoundRobin) {
   const double locality_picked_rate_1 =
       static_cast<double>(backends_[1]->backend_service()->request_count()) /
       kNumRpcs;
-  const double kErrorTolerance = 0.2;
   EXPECT_THAT(locality_picked_rate_0,
-              ::testing::AllOf(
-                  ::testing::Ge(kLocalityWeightRate0 * (1 - kErrorTolerance)),
-                  ::testing::Le(kLocalityWeightRate0 * (1 + kErrorTolerance))));
+              ::testing::DoubleNear(kLocalityWeightRate0, kErrorTolerance));
   EXPECT_THAT(locality_picked_rate_1,
-              ::testing::AllOf(
-                  ::testing::Ge(kLocalityWeightRate1 * (1 - kErrorTolerance)),
-                  ::testing::Le(kLocalityWeightRate1 * (1 + kErrorTolerance))));
+              ::testing::DoubleNear(kLocalityWeightRate1, kErrorTolerance));
 }
 
 // Tests that we correctly handle a locality containing no endpoints.
@@ -8801,7 +9016,7 @@ TEST_P(LocalityMapTest, LocalityContainingNoEndpoints) {
   const size_t kNumRpcs = 5000;
   // EDS response contains 2 localities, one with no endpoints.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
       {"locality1", {}},
   });
   balancers_[0]->ads_service()->SetEdsResource(
@@ -8838,27 +9053,29 @@ TEST_P(LocalityMapTest, StressTest) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   const size_t kNumLocalities = 100;
+  const uint32_t kRpcTimeoutMs = 5000;
   // The first ADS response contains kNumLocalities localities, each of which
   // contains backend 0.
   AdsServiceImpl::EdsResourceArgs args;
   for (size_t i = 0; i < kNumLocalities; ++i) {
     std::string name = absl::StrCat("locality", i);
-    AdsServiceImpl::EdsResourceArgs::Locality locality(name,
-                                                       {backends_[0]->port()});
+    AdsServiceImpl::EdsResourceArgs::Locality locality(
+        name, CreateEndpointsForBackends(0, 1));
     args.locality_list.emplace_back(std::move(locality));
   }
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   // The second ADS response contains 1 locality, which contains backend 1.
   args = AdsServiceImpl::EdsResourceArgs({
-      {"locality0", GetBackendPorts(1, 2)},
+      {"locality0", CreateEndpointsForBackends(1, 2)},
   });
   std::thread delayed_resource_setter(
       std::bind(&BasicTest::SetEdsResourceWithDelay, this, 0,
                 BuildEdsResource(args, DefaultEdsServiceName()), 60 * 1000));
   // Wait until backend 0 is ready, before which kNumLocalities localities are
   // received and handled by the xds policy.
-  WaitForBackend(0, /*reset_counters=*/false);
+  WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false),
+                 RpcOptions().set_timeout_ms(kRpcTimeoutMs));
   EXPECT_EQ(0U, backends_[1]->backend_service()->request_count());
   // Wait until backend 1 is ready, before which kNumLocalities localities are
   // removed by the xds policy.
@@ -8892,9 +9109,9 @@ TEST_P(LocalityMapTest, UpdateMap) {
     locality_weight_rate_1.push_back(weight / kTotalLocalityWeight1);
   }
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1), 2},
-      {"locality1", GetBackendPorts(1, 2), 3},
-      {"locality2", GetBackendPorts(2, 3), 4},
+      {"locality0", CreateEndpointsForBackends(0, 1), 2},
+      {"locality1", CreateEndpointsForBackends(1, 2), 3},
+      {"locality2", CreateEndpointsForBackends(2, 3), 4},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -8923,9 +9140,9 @@ TEST_P(LocalityMapTest, UpdateMap) {
             ::testing::Le(locality_weight_rate_0[i] * (1 + kErrorTolerance))));
   }
   args = AdsServiceImpl::EdsResourceArgs({
-      {"locality1", GetBackendPorts(1, 2), 3},
-      {"locality2", GetBackendPorts(2, 3), 2},
-      {"locality3", GetBackendPorts(3, 4), 6},
+      {"locality1", CreateEndpointsForBackends(1, 2), 3},
+      {"locality2", CreateEndpointsForBackends(2, 3), 2},
+      {"locality3", CreateEndpointsForBackends(3, 4), 6},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -8965,12 +9182,12 @@ TEST_P(LocalityMapTest, ReplaceAllLocalitiesInPriority) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1)},
+      {"locality0", CreateEndpointsForBackends(0, 1)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   args = AdsServiceImpl::EdsResourceArgs({
-      {"locality1", GetBackendPorts(1, 2)},
+      {"locality1", CreateEndpointsForBackends(1, 2)},
   });
   std::thread delayed_resource_setter(
       std::bind(&BasicTest::SetEdsResourceWithDelay, this, 0,
@@ -8980,7 +9197,7 @@ TEST_P(LocalityMapTest, ReplaceAllLocalitiesInPriority) {
   // Keep sending RPCs until we switch over to backend 1, which tells us
   // that we received the update.  No RPCs should fail during this
   // transition.
-  WaitForBackend(1, /*reset_counters=*/true, /*require_success=*/true);
+  WaitForBackend(1);
   delayed_resource_setter.join();
 }
 
@@ -8997,14 +9214,18 @@ TEST_P(FailoverTest, ChooseHighestPriority) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 1},
-      {"locality1", GetBackendPorts(1, 2), kDefaultLocalityWeight, 2},
-      {"locality2", GetBackendPorts(2, 3), kDefaultLocalityWeight, 3},
-      {"locality3", GetBackendPorts(3, 4), kDefaultLocalityWeight, 0},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       1},
+      {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
+       2},
+      {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
+       3},
+      {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
+       0},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
-  WaitForBackend(3, false);
+  WaitForBackend(3, WaitForBackendOptions().set_reset_counters(false));
   for (size_t i = 0; i < 3; ++i) {
     EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
   }
@@ -9015,14 +9236,17 @@ TEST_P(FailoverTest, DoesNotUsePriorityWithNoEndpoints) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 1},
-      {"locality1", GetBackendPorts(1, 2), kDefaultLocalityWeight, 2},
-      {"locality2", GetBackendPorts(2, 3), kDefaultLocalityWeight, 3},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       1},
+      {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
+       2},
+      {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
+       3},
       {"locality3", {}, kDefaultLocalityWeight, 0},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
-  WaitForBackend(0, false);
+  WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false));
   for (size_t i = 1; i < 3; ++i) {
     EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
   }
@@ -9034,7 +9258,7 @@ TEST_P(FailoverTest, DoesNotUseLocalityWithNoEndpoints) {
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
       {"locality0", {}, kDefaultLocalityWeight, 0},
-      {"locality1", GetBackendPorts(), kDefaultLocalityWeight, 0},
+      {"locality1", CreateEndpointsForBackends(), kDefaultLocalityWeight, 0},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -9050,16 +9274,20 @@ TEST_P(FailoverTest, Failover) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 1},
-      {"locality1", GetBackendPorts(1, 2), kDefaultLocalityWeight, 2},
-      {"locality2", GetBackendPorts(2, 3), kDefaultLocalityWeight, 3},
-      {"locality3", GetBackendPorts(3, 4), kDefaultLocalityWeight, 0},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       1},
+      {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
+       2},
+      {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
+       3},
+      {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
+       0},
   });
   ShutdownBackend(3);
   ShutdownBackend(0);
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
-  WaitForBackend(1, false);
+  WaitForBackend(1, WaitForBackendOptions().set_reset_counters(false));
   for (size_t i = 0; i < 4; ++i) {
     if (i == 1) continue;
     EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
@@ -9073,17 +9301,23 @@ TEST_P(FailoverTest, SwitchBackToHigherPriority) {
   SetNextResolutionForLbChannelAllBalancers();
   const size_t kNumRpcs = 100;
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 1},
-      {"locality1", GetBackendPorts(1, 2), kDefaultLocalityWeight, 2},
-      {"locality2", GetBackendPorts(2, 3), kDefaultLocalityWeight, 3},
-      {"locality3", GetBackendPorts(3, 4), kDefaultLocalityWeight, 0},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       1},
+      {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
+       2},
+      {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
+       3},
+      {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
+       0},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   WaitForBackend(3);
   ShutdownBackend(3);
   ShutdownBackend(0);
-  WaitForBackend(1, false);
+  WaitForBackend(
+      1, WaitForBackendOptions().set_reset_counters(false).set_allow_failures(
+             true));
   for (size_t i = 0; i < 4; ++i) {
     if (i == 1) continue;
     EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
@@ -9100,16 +9334,22 @@ TEST_P(FailoverTest, UpdateInitialUnavailable) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 0},
-      {"locality1", GetBackendPorts(1, 2), kDefaultLocalityWeight, 1},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       0},
+      {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
+       1},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   args = AdsServiceImpl::EdsResourceArgs({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 0},
-      {"locality1", GetBackendPorts(1, 2), kDefaultLocalityWeight, 1},
-      {"locality2", GetBackendPorts(2, 3), kDefaultLocalityWeight, 2},
-      {"locality3", GetBackendPorts(3, 4), kDefaultLocalityWeight, 3},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       0},
+      {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
+       1},
+      {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
+       2},
+      {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
+       3},
   });
   ShutdownBackend(0);
   ShutdownBackend(1);
@@ -9122,7 +9362,9 @@ TEST_P(FailoverTest, UpdateInitialUnavailable) {
   do {
     CheckRpcSendFailure();
   } while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0);
-  WaitForBackend(2, false);
+  WaitForBackend(
+      2, WaitForBackendOptions().set_reset_counters(false).set_allow_failures(
+             true));
   for (size_t i = 0; i < 4; ++i) {
     if (i == 2) continue;
     EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
@@ -9137,23 +9379,31 @@ TEST_P(FailoverTest, UpdatePriority) {
   SetNextResolutionForLbChannelAllBalancers();
   const size_t kNumRpcs = 100;
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 1},
-      {"locality1", GetBackendPorts(1, 2), kDefaultLocalityWeight, 2},
-      {"locality2", GetBackendPorts(2, 3), kDefaultLocalityWeight, 3},
-      {"locality3", GetBackendPorts(3, 4), kDefaultLocalityWeight, 0},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       1},
+      {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
+       2},
+      {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
+       3},
+      {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
+       0},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   args = AdsServiceImpl::EdsResourceArgs({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 2},
-      {"locality1", GetBackendPorts(1, 2), kDefaultLocalityWeight, 0},
-      {"locality2", GetBackendPorts(2, 3), kDefaultLocalityWeight, 1},
-      {"locality3", GetBackendPorts(3, 4), kDefaultLocalityWeight, 3},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       2},
+      {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
+       0},
+      {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
+       1},
+      {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
+       3},
   });
   std::thread delayed_resource_setter(
       std::bind(&BasicTest::SetEdsResourceWithDelay, this, 0,
                 BuildEdsResource(args, DefaultEdsServiceName()), 1000));
-  WaitForBackend(3, false);
+  WaitForBackend(3, WaitForBackendOptions().set_reset_counters(false));
   for (size_t i = 0; i < 3; ++i) {
     EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
   }
@@ -9172,8 +9422,10 @@ TEST_P(FailoverTest, MoveAllLocalitiesInCurrentPriorityToHigherPriority) {
   // - Priority 1 is locality 1, containing backends 1 and 2, which are up.
   ShutdownBackend(0);
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 0},
-      {"locality1", GetBackendPorts(1, 3), kDefaultLocalityWeight, 1},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       0},
+      {"locality1", CreateEndpointsForBackends(1, 3), kDefaultLocalityWeight,
+       1},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -9183,8 +9435,10 @@ TEST_P(FailoverTest, MoveAllLocalitiesInCurrentPriorityToHigherPriority) {
   // - We add backend 3 to locality 1, just so we have a way to know
   //   when the update has been seen by the client.
   args = AdsServiceImpl::EdsResourceArgs({
-      {"locality0", GetBackendPorts(0, 1), kDefaultLocalityWeight, 0},
-      {"locality1", GetBackendPorts(1, 4), kDefaultLocalityWeight, 0},
+      {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
+       0},
+      {"locality1", CreateEndpointsForBackends(1, 4), kDefaultLocalityWeight,
+       0},
   });
   std::thread delayed_resource_setter(
       std::bind(&BasicTest::SetEdsResourceWithDelay, this, 0,
@@ -9192,7 +9446,7 @@ TEST_P(FailoverTest, MoveAllLocalitiesInCurrentPriorityToHigherPriority) {
   // When we get the first update, all backends in priority 0 are down,
   // so we will create priority 1.  Backends 1 and 2 should have traffic,
   // but backend 3 should not.
-  WaitForAllBackends(1, 3, false);
+  WaitForAllBackends(1, 3, WaitForBackendOptions().set_reset_counters(false));
   EXPECT_EQ(0UL, backends_[3]->backend_service()->request_count());
   // When backend 3 gets traffic, we know the second update has been seen.
   WaitForBackend(3);
@@ -9208,16 +9462,18 @@ using DropTest = BasicTest;
 TEST_P(DropTest, Vanilla) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  const size_t kNumRpcs = 5000;
   const uint32_t kDropPerMillionForLb = 100000;
   const uint32_t kDropPerMillionForThrottle = 200000;
   const double kDropRateForLb = kDropPerMillionForLb / 1000000.0;
   const double kDropRateForThrottle = kDropPerMillionForThrottle / 1000000.0;
-  const double KDropRateForLbAndThrottle =
+  const double kDropRateForLbAndThrottle =
       kDropRateForLb + (1 - kDropRateForLb) * kDropRateForThrottle;
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs =
+      ComputeIdealNumRpcs(kDropRateForLbAndThrottle, kErrorTolerance);
   // The ADS response contains two drop categories.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   args.drop_categories = {{kLbDropType, kDropPerMillionForLb},
                           {kThrottleDropType, kDropPerMillionForThrottle}};
@@ -9240,24 +9496,21 @@ TEST_P(DropTest, Vanilla) {
   }
   // The drop rate should be roughly equal to the expectation.
   const double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
-  const double kErrorTolerance = 0.2;
-  EXPECT_THAT(
-      seen_drop_rate,
-      ::testing::AllOf(
-          ::testing::Ge(KDropRateForLbAndThrottle * (1 - kErrorTolerance)),
-          ::testing::Le(KDropRateForLbAndThrottle * (1 + kErrorTolerance))));
+  EXPECT_THAT(seen_drop_rate, ::testing::DoubleNear(kDropRateForLbAndThrottle,
+                                                    kErrorTolerance));
 }
 
 // Tests that drop config is converted correctly from per hundred.
 TEST_P(DropTest, DropPerHundred) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  const size_t kNumRpcs = 5000;
   const uint32_t kDropPerHundredForLb = 10;
   const double kDropRateForLb = kDropPerHundredForLb / 100.0;
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs = ComputeIdealNumRpcs(kDropRateForLb, kErrorTolerance);
   // The ADS response contains one drop category.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   args.drop_categories = {{kLbDropType, kDropPerHundredForLb}};
   args.drop_denominator = FractionalPercent::HUNDRED;
@@ -9280,23 +9533,21 @@ TEST_P(DropTest, DropPerHundred) {
   }
   // The drop rate should be roughly equal to the expectation.
   const double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
-  const double kErrorTolerance = 0.2;
-  EXPECT_THAT(
-      seen_drop_rate,
-      ::testing::AllOf(::testing::Ge(kDropRateForLb * (1 - kErrorTolerance)),
-                       ::testing::Le(kDropRateForLb * (1 + kErrorTolerance))));
+  EXPECT_THAT(seen_drop_rate,
+              ::testing::DoubleNear(kDropRateForLb, kErrorTolerance));
 }
 
 // Tests that drop config is converted correctly from per ten thousand.
 TEST_P(DropTest, DropPerTenThousand) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  const size_t kNumRpcs = 5000;
   const uint32_t kDropPerTenThousandForLb = 1000;
   const double kDropRateForLb = kDropPerTenThousandForLb / 10000.0;
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs = ComputeIdealNumRpcs(kDropRateForLb, kErrorTolerance);
   // The ADS response contains one drop category.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   args.drop_categories = {{kLbDropType, kDropPerTenThousandForLb}};
   args.drop_denominator = FractionalPercent::TEN_THOUSAND;
@@ -9319,36 +9570,37 @@ TEST_P(DropTest, DropPerTenThousand) {
   }
   // The drop rate should be roughly equal to the expectation.
   const double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
-  const double kErrorTolerance = 0.2;
-  EXPECT_THAT(
-      seen_drop_rate,
-      ::testing::AllOf(::testing::Ge(kDropRateForLb * (1 - kErrorTolerance)),
-                       ::testing::Le(kDropRateForLb * (1 + kErrorTolerance))));
+  EXPECT_THAT(seen_drop_rate,
+              ::testing::DoubleNear(kDropRateForLb, kErrorTolerance));
 }
 
 // Tests that drop is working correctly after update.
 TEST_P(DropTest, Update) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  const size_t kNumRpcs = 3000;
   const uint32_t kDropPerMillionForLb = 100000;
   const uint32_t kDropPerMillionForThrottle = 200000;
+  const double kErrorTolerance = 0.05;
   const double kDropRateForLb = kDropPerMillionForLb / 1000000.0;
   const double kDropRateForThrottle = kDropPerMillionForThrottle / 1000000.0;
-  const double KDropRateForLbAndThrottle =
+  const double kDropRateForLbAndThrottle =
       kDropRateForLb + (1 - kDropRateForLb) * kDropRateForThrottle;
+  const size_t kNumRpcsLbOnly =
+      ComputeIdealNumRpcs(kDropRateForLb, kErrorTolerance);
+  const size_t kNumRpcsBoth =
+      ComputeIdealNumRpcs(kDropRateForLbAndThrottle, kErrorTolerance);
   // The first ADS response contains one drop category.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   args.drop_categories = {{kLbDropType, kDropPerMillionForLb}};
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   WaitForAllBackends();
-  // Send kNumRpcs RPCs and count the drops.
+  // Send kNumRpcsLbOnly RPCs and count the drops.
   size_t num_drops = 0;
   gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
-  for (size_t i = 0; i < kNumRpcs; ++i) {
+  for (size_t i = 0; i < kNumRpcsLbOnly; ++i) {
     EchoResponse response;
     const Status status = SendRpc(RpcOptions(), &response);
     if (!status.ok() &&
@@ -9362,13 +9614,10 @@ TEST_P(DropTest, Update) {
   }
   gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH ==========");
   // The drop rate should be roughly equal to the expectation.
-  double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
+  double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcsLbOnly;
   gpr_log(GPR_INFO, "First batch drop rate %f", seen_drop_rate);
-  const double kErrorTolerance = 0.3;
-  EXPECT_THAT(
-      seen_drop_rate,
-      ::testing::AllOf(::testing::Ge(kDropRateForLb * (1 - kErrorTolerance)),
-                       ::testing::Le(kDropRateForLb * (1 + kErrorTolerance))));
+  EXPECT_THAT(seen_drop_rate,
+              ::testing::DoubleNear(kDropRateForLb, kErrorTolerance));
   // The second ADS response contains two drop categories, send an update EDS
   // response.
   args.drop_categories = {{kLbDropType, kDropPerMillionForLb},
@@ -9378,8 +9627,8 @@ TEST_P(DropTest, Update) {
   // Wait until the drop rate increases to the middle of the two configs, which
   // implies that the update has been in effect.
   const double kDropRateThreshold =
-      (kDropRateForLb + KDropRateForLbAndThrottle) / 2;
-  size_t num_rpcs = kNumRpcs;
+      (kDropRateForLb + kDropRateForLbAndThrottle) / 2;
+  size_t num_rpcs = kNumRpcsBoth;
   while (seen_drop_rate < kDropRateThreshold) {
     EchoResponse response;
     const Status status = SendRpc(RpcOptions(), &response);
@@ -9394,10 +9643,10 @@ TEST_P(DropTest, Update) {
     }
     seen_drop_rate = static_cast<double>(num_drops) / num_rpcs;
   }
-  // Send kNumRpcs RPCs and count the drops.
+  // Send kNumRpcsBoth RPCs and count the drops.
   num_drops = 0;
   gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH ==========");
-  for (size_t i = 0; i < kNumRpcs; ++i) {
+  for (size_t i = 0; i < kNumRpcsBoth; ++i) {
     EchoResponse response;
     const Status status = SendRpc(RpcOptions(), &response);
     if (!status.ok() &&
@@ -9411,13 +9660,10 @@ TEST_P(DropTest, Update) {
   }
   gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH ==========");
   // The new drop rate should be roughly equal to the expectation.
-  seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
+  seen_drop_rate = static_cast<double>(num_drops) / kNumRpcsBoth;
   gpr_log(GPR_INFO, "Second batch drop rate %f", seen_drop_rate);
-  EXPECT_THAT(
-      seen_drop_rate,
-      ::testing::AllOf(
-          ::testing::Ge(KDropRateForLbAndThrottle * (1 - kErrorTolerance)),
-          ::testing::Le(KDropRateForLbAndThrottle * (1 + kErrorTolerance))));
+  EXPECT_THAT(seen_drop_rate, ::testing::DoubleNear(kDropRateForLbAndThrottle,
+                                                    kErrorTolerance));
 }
 
 // Tests that all the RPCs are dropped if any drop category drops 100%.
@@ -9452,14 +9698,12 @@ class BalancerUpdateTest : public XdsEnd2endTest {
 TEST_P(BalancerUpdateTest, UpdateBalancersButKeepUsingOriginalBalancer) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {backends_[0]->port()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", CreateEndpointsForBackends(0, 1)}});
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
-  args = AdsServiceImpl::EdsResourceArgs({
-      {"locality0", {backends_[1]->port()}},
-  });
+  args = AdsServiceImpl::EdsResourceArgs(
+      {{"locality0", CreateEndpointsForBackends(1, 2)}});
   balancers_[1]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   // Wait until the first backend is ready.
@@ -9515,14 +9759,12 @@ TEST_P(BalancerUpdateTest, UpdateBalancersButKeepUsingOriginalBalancer) {
 TEST_P(BalancerUpdateTest, Repeated) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {backends_[0]->port()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", CreateEndpointsForBackends(0, 1)}});
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
-  args = AdsServiceImpl::EdsResourceArgs({
-      {"locality0", {backends_[1]->port()}},
-  });
+  args = AdsServiceImpl::EdsResourceArgs(
+      {{"locality0", CreateEndpointsForBackends(1, 2)}});
   balancers_[1]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   // Wait until the first backend is ready.
@@ -9585,14 +9827,12 @@ TEST_P(BalancerUpdateTest, Repeated) {
 TEST_P(BalancerUpdateTest, DeadUpdate) {
   SetNextResolution({});
   SetNextResolutionForLbChannel({balancers_[0]->port()});
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {backends_[0]->port()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", CreateEndpointsForBackends(0, 1)}});
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
-  args = AdsServiceImpl::EdsResourceArgs({
-      {"locality0", {backends_[1]->port()}},
-  });
+  args = AdsServiceImpl::EdsResourceArgs(
+      {{"locality0", CreateEndpointsForBackends(1, 2)}});
   balancers_[1]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   // Start servers and send 10 RPCs per server.
@@ -9681,7 +9921,7 @@ TEST_P(ClientLoadReportingTest, Vanilla) {
   // TODO(juanlishen): Partition the backends after multiple localities is
   // tested.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -9728,7 +9968,7 @@ TEST_P(ClientLoadReportingTest, SendAllClusters) {
   // TODO(juanlishen): Partition the backends after multiple localities is
   // tested.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -9773,7 +10013,7 @@ TEST_P(ClientLoadReportingTest, HonorsClustersRequestedByLrsServer) {
   SetNextResolutionForLbChannel({balancers_[0]->port()});
   const size_t kNumRpcsPerAddress = 100;
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -9810,7 +10050,7 @@ TEST_P(ClientLoadReportingTest, BalancerRestart) {
   const size_t kNumBackendsSecondPass =
       backends_.size() - kNumBackendsFirstPass;
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts(0, kNumBackendsFirstPass)},
+      {"locality0", CreateEndpointsForBackends(0, kNumBackendsFirstPass)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -9848,7 +10088,7 @@ TEST_P(ClientLoadReportingTest, BalancerRestart) {
   // Now restart the balancer, this time pointing to the new backends.
   balancers_[0]->Start();
   args = AdsServiceImpl::EdsResourceArgs({
-      {"locality0", GetBackendPorts(kNumBackendsFirstPass)},
+      {"locality0", CreateEndpointsForBackends(kNumBackendsFirstPass)},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -9882,16 +10122,18 @@ TEST_P(ClientLoadReportingWithDropTest, Vanilla) {
   }
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  const size_t kNumRpcs = 3000;
   const uint32_t kDropPerMillionForLb = 100000;
   const uint32_t kDropPerMillionForThrottle = 200000;
+  const double kErrorTolerance = 0.05;
   const double kDropRateForLb = kDropPerMillionForLb / 1000000.0;
   const double kDropRateForThrottle = kDropPerMillionForThrottle / 1000000.0;
-  const double KDropRateForLbAndThrottle =
+  const double kDropRateForLbAndThrottle =
       kDropRateForLb + (1 - kDropRateForLb) * kDropRateForThrottle;
+  const size_t kNumRpcs =
+      ComputeIdealNumRpcs(kDropRateForLbAndThrottle, kErrorTolerance);
   // The ADS response contains two drop categories.
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   args.drop_categories = {{kLbDropType, kDropPerMillionForLb},
                           {kThrottleDropType, kDropPerMillionForThrottle}};
@@ -9917,12 +10159,8 @@ TEST_P(ClientLoadReportingWithDropTest, Vanilla) {
   }
   // The drop rate should be roughly equal to the expectation.
   const double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
-  const double kErrorTolerance = 0.2;
-  EXPECT_THAT(
-      seen_drop_rate,
-      ::testing::AllOf(
-          ::testing::Ge(KDropRateForLbAndThrottle * (1 - kErrorTolerance)),
-          ::testing::Le(KDropRateForLbAndThrottle * (1 + kErrorTolerance))));
+  EXPECT_THAT(seen_drop_rate, ::testing::DoubleNear(kDropRateForLbAndThrottle,
+                                                    kErrorTolerance));
   // Check client stats.
   const size_t total_rpc = num_warmup + kNumRpcs;
   ClientStats client_stats;
@@ -9936,17 +10174,13 @@ TEST_P(ClientLoadReportingWithDropTest, Vanilla) {
                client_stats.total_dropped_requests() <
            total_rpc);
   EXPECT_EQ(num_drops, client_stats.total_dropped_requests());
+  EXPECT_THAT(static_cast<double>(client_stats.dropped_requests(kLbDropType)) /
+                  total_rpc,
+              ::testing::DoubleNear(kDropRateForLb, kErrorTolerance));
   EXPECT_THAT(
-      client_stats.dropped_requests(kLbDropType),
-      ::testing::AllOf(
-          ::testing::Ge(total_rpc * kDropRateForLb * (1 - kErrorTolerance)),
-          ::testing::Le(total_rpc * kDropRateForLb * (1 + kErrorTolerance))));
-  EXPECT_THAT(client_stats.dropped_requests(kThrottleDropType),
-              ::testing::AllOf(
-                  ::testing::Ge(total_rpc * (1 - kDropRateForLb) *
-                                kDropRateForThrottle * (1 - kErrorTolerance)),
-                  ::testing::Le(total_rpc * (1 - kDropRateForLb) *
-                                kDropRateForThrottle * (1 + kErrorTolerance))));
+      static_cast<double>(client_stats.dropped_requests(kThrottleDropType)) /
+          (total_rpc * (1 - kDropRateForLb)),
+      ::testing::DoubleNear(kDropRateForThrottle, kErrorTolerance));
 }
 
 class FaultInjectionTest : public XdsEnd2endTest {
@@ -10030,7 +10264,7 @@ TEST_P(FaultInjectionTest, XdsFaultInjectionWithoutListenerFilter) {
   SetNextResolutionForLbChannelAllBalancers();
   // Create an EDS resource
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -10050,15 +10284,15 @@ TEST_P(FaultInjectionTest, XdsFaultInjectionWithoutListenerFilter) {
 }
 
 TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageAbort) {
-  const size_t kNumRpcs = 100;
   const uint32_t kAbortPercentagePerHundred = 50;
   const double kAbortRate = kAbortPercentagePerHundred / 100.0;
-  const double kErrorTolerance = 0.2;
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Create an EDS resource
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -10082,21 +10316,20 @@ TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageAbort) {
   // The abort rate should be roughly equal to the expectation.
   const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
   EXPECT_THAT(seen_abort_rate,
-              ::testing::AllOf(::testing::Ge(kAbortRate - kErrorTolerance),
-                               ::testing::Le(kAbortRate + kErrorTolerance)));
+              ::testing::DoubleNear(kAbortRate, kErrorTolerance));
 }
 
 TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageAbortViaHeaders) {
-  const size_t kNumRpcs = 100;
   const uint32_t kAbortPercentageCap = 100;
   const uint32_t kAbortPercentage = 50;
   const double kAbortRate = kAbortPercentage / 100.0;
-  const double kErrorTolerance = 0.2;
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Create an EDS resource
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -10123,24 +10356,21 @@ TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageAbortViaHeaders) {
   // The abort rate should be roughly equal to the expectation.
   const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
   EXPECT_THAT(seen_abort_rate,
-              ::testing::AllOf(::testing::Ge(kAbortRate - kErrorTolerance),
-                               ::testing::Le(kAbortRate + kErrorTolerance)));
+              ::testing::DoubleNear(kAbortRate, kErrorTolerance));
 }
 
-// TODO(lidiz) reduce the error tolerance to a lower level without dramatically
-// increase the duration of fault injection tests.
 TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageDelay) {
-  const size_t kNumRpcs = 100;
+  const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 3000;
   const uint32_t kFixedDelaySeconds = 100;
-  const uint32_t kRpcTimeoutMilliseconds = 10;  // 10 ms
-  const uint32_t kDelayPercentagePerHundred = 95;
+  const uint32_t kDelayPercentagePerHundred = 50;
   const double kDelayRate = kDelayPercentagePerHundred / 100.0;
-  const double kErrorTolerance = 0.2;
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs = ComputeIdealNumRpcs(kDelayRate, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Create an EDS resource
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -10154,35 +10384,36 @@ TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageDelay) {
   // Config fault injection via different setup
   SetFilterConfig(http_fault);
   // Send kNumRpcs RPCs and count the delays.
-  int num_total = 0, num_ok = 0, num_delayed = 0, num_dropped = 0;
-  RpcOptions options = RpcOptions()
-                           .set_timeout_ms(kRpcTimeoutMilliseconds)
-                           .set_skip_cancelled_check(true);
-  for (size_t i = 0; i < kNumRpcs; ++i) {
-    SendRpcAndCount(&num_total, &num_ok, &num_delayed, &num_dropped, options);
+  RpcOptions rpc_options = RpcOptions()
+                               .set_timeout_ms(kRpcTimeoutMilliseconds)
+                               .set_skip_cancelled_check(true);
+  std::vector<ConcurrentRpc> rpcs =
+      SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
+  size_t num_delayed = 0;
+  for (auto& rpc : rpcs) {
+    if (rpc.status.error_code() == StatusCode::OK) continue;
+    EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
+    ++num_delayed;
   }
-  EXPECT_EQ(kNumRpcs, num_total);
-  EXPECT_EQ(0, num_dropped);
   // The delay rate should be roughly equal to the expectation.
   const double seen_delay_rate = static_cast<double>(num_delayed) / kNumRpcs;
   EXPECT_THAT(seen_delay_rate,
-              ::testing::AllOf(::testing::Ge(kDelayRate - kErrorTolerance),
-                               ::testing::Le(kDelayRate + kErrorTolerance)));
+              ::testing::DoubleNear(kDelayRate, kErrorTolerance));
 }
 
 TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageDelayViaHeaders) {
-  const size_t kNumRpcs = 100;
-  const uint32_t kFixedDelayMilliseconds = 100000;  // 100 seconds
-  const uint32_t kRpcTimeoutMilliseconds = 10;      // 10 ms
+  const uint32_t kFixedDelayMilliseconds = 100000;
+  const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 3000;
   const uint32_t kDelayPercentageCap = 100;
   const uint32_t kDelayPercentage = 50;
   const double kDelayRate = kDelayPercentage / 100.0;
-  const double kErrorTolerance = 0.2;
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs = ComputeIdealNumRpcs(kDelayRate, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Create an EDS resource
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -10199,32 +10430,38 @@ TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageDelayViaHeaders) {
       {"x-envoy-fault-delay-request-percentage",
        std::to_string(kDelayPercentage)},
   };
-  int num_total = 0, num_ok = 0, num_delayed = 0, num_dropped = 0;
-  RpcOptions options = RpcOptions()
-                           .set_metadata(metadata)
-                           .set_timeout_ms(kRpcTimeoutMilliseconds)
-                           .set_skip_cancelled_check(true);
-  for (size_t i = 0; i < kNumRpcs; ++i) {
-    SendRpcAndCount(&num_total, &num_ok, &num_delayed, &num_dropped, options);
+  RpcOptions rpc_options = RpcOptions()
+                               .set_metadata(metadata)
+                               .set_timeout_ms(kRpcTimeoutMilliseconds)
+                               .set_skip_cancelled_check(true);
+  std::vector<ConcurrentRpc> rpcs =
+      SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
+  size_t num_delayed = 0;
+  for (auto& rpc : rpcs) {
+    if (rpc.status.error_code() == StatusCode::OK) continue;
+    EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
+    ++num_delayed;
   }
   // The delay rate should be roughly equal to the expectation.
   const double seen_delay_rate = static_cast<double>(num_delayed) / kNumRpcs;
   EXPECT_THAT(seen_delay_rate,
-              ::testing::AllOf(::testing::Ge(kDelayRate - kErrorTolerance),
-                               ::testing::Le(kDelayRate + kErrorTolerance)));
+              ::testing::DoubleNear(kDelayRate, kErrorTolerance));
 }
 
 TEST_P(FaultInjectionTest, XdsFaultInjectionAlwaysDelayPercentageAbort) {
-  const size_t kNumRpcs = 100;
   const uint32_t kAbortPercentagePerHundred = 50;
   const double kAbortRate = kAbortPercentagePerHundred / 100.0;
-  const uint32_t kFixedDelayNanos = 10 * 1000 * 1000;  // 10 ms
-  const double kErrorTolerance = 0.2;
+  const uint32_t kFixedDelaySeconds = 1;
+  const uint32_t kRpcTimeoutMilliseconds = 100 * 1000;  // 100s should not reach
+  const uint32_t kConnectionTimeoutMilliseconds =
+      10 * 1000;  // 10s should not reach
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Create an EDS resource
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -10239,25 +10476,29 @@ TEST_P(FaultInjectionTest, XdsFaultInjectionAlwaysDelayPercentageAbort) {
   delay_percentage->set_numerator(1000000);  // Always inject DELAY!
   delay_percentage->set_denominator(FractionalPercent::MILLION);
   auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
-  fixed_delay->set_nanos(kFixedDelayNanos);
+  fixed_delay->set_seconds(kFixedDelaySeconds);
   // Config fault injection via different setup
   SetFilterConfig(http_fault);
+  // Allow the channel to connect to one backends, so the herd of queued RPCs
+  // won't be executed on the same ExecCtx object and using the cached Now()
+  // value, which causes millisecond level delay error.
+  channel_->WaitForConnected(
+      grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds));
   // Send kNumRpcs RPCs and count the aborts.
-  int num_total = 0, num_ok = 0, num_failure = 0, num_aborted = 0;
-  for (size_t i = 0; i < kNumRpcs; ++i) {
-    grpc_millis t0 = NowFromCycleCounter();
-    SendRpcAndCount(&num_total, &num_ok, &num_failure, &num_aborted,
-                    RpcOptions(), "Fault injected");
-    grpc_millis t1 = NowFromCycleCounter();
-    EXPECT_GE(t1, t0 + kFixedDelayNanos / 1000 / 1000);
+  int num_aborted = 0;
+  RpcOptions rpc_options = RpcOptions().set_timeout_ms(kRpcTimeoutMilliseconds);
+  std::vector<ConcurrentRpc> rpcs =
+      SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
+  for (auto& rpc : rpcs) {
+    EXPECT_GE(rpc.elapsed_time, kFixedDelaySeconds * 1000);
+    if (rpc.status.error_code() == StatusCode::OK) continue;
+    EXPECT_EQ("Fault injected", rpc.status.error_message());
+    ++num_aborted;
   }
-  EXPECT_EQ(kNumRpcs, num_total);
-  EXPECT_EQ(0, num_failure);
   // The abort rate should be roughly equal to the expectation.
   const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
   EXPECT_THAT(seen_abort_rate,
-              ::testing::AllOf(::testing::Ge(kAbortRate - kErrorTolerance),
-                               ::testing::Le(kAbortRate + kErrorTolerance)));
+              ::testing::DoubleNear(kAbortRate, kErrorTolerance));
 }
 
 // This test and the above test apply different denominators to delay and abort.
@@ -10265,16 +10506,19 @@ TEST_P(FaultInjectionTest, XdsFaultInjectionAlwaysDelayPercentageAbort) {
 // in our code.
 TEST_P(FaultInjectionTest,
        XdsFaultInjectionAlwaysDelayPercentageAbortSwitchDenominator) {
-  const size_t kNumRpcs = 100;
   const uint32_t kAbortPercentagePerMillion = 500000;
   const double kAbortRate = kAbortPercentagePerMillion / 1000000.0;
-  const uint32_t kFixedDelayNanos = 10 * 1000 * 1000;  // 10 ms
-  const double kErrorTolerance = 0.2;
+  const uint32_t kFixedDelaySeconds = 1;                // 1s
+  const uint32_t kRpcTimeoutMilliseconds = 100 * 1000;  // 100s should not reach
+  const uint32_t kConnectionTimeoutMilliseconds =
+      10 * 1000;  // 10s should not reach
+  const double kErrorTolerance = 0.05;
+  const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Create an EDS resource
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -10289,38 +10533,42 @@ TEST_P(FaultInjectionTest,
   delay_percentage->set_numerator(100);  // Always inject DELAY!
   delay_percentage->set_denominator(FractionalPercent::HUNDRED);
   auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
-  fixed_delay->set_nanos(kFixedDelayNanos);
+  fixed_delay->set_seconds(kFixedDelaySeconds);
   // Config fault injection via different setup
   SetFilterConfig(http_fault);
+  // Allow the channel to connect to one backends, so the herd of queued RPCs
+  // won't be executed on the same ExecCtx object and using the cached Now()
+  // value, which causes millisecond level delay error.
+  channel_->WaitForConnected(
+      grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds));
   // Send kNumRpcs RPCs and count the aborts.
-  int num_total = 0, num_ok = 0, num_failure = 0, num_aborted = 0;
-  for (size_t i = 0; i < kNumRpcs; ++i) {
-    grpc_millis t0 = NowFromCycleCounter();
-    SendRpcAndCount(&num_total, &num_ok, &num_failure, &num_aborted,
-                    RpcOptions(), "Fault injected");
-    grpc_millis t1 = NowFromCycleCounter();
-    EXPECT_GE(t1, t0 + kFixedDelayNanos / 1000 / 1000);
+  int num_aborted = 0;
+  RpcOptions rpc_options = RpcOptions().set_timeout_ms(kRpcTimeoutMilliseconds);
+  std::vector<ConcurrentRpc> rpcs =
+      SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
+  for (auto& rpc : rpcs) {
+    EXPECT_GE(rpc.elapsed_time, kFixedDelaySeconds * 1000);
+    if (rpc.status.error_code() == StatusCode::OK) continue;
+    EXPECT_EQ("Fault injected", rpc.status.error_message());
+    ++num_aborted;
   }
-  EXPECT_EQ(kNumRpcs, num_total);
-  EXPECT_EQ(0, num_failure);
   // The abort rate should be roughly equal to the expectation.
   const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
   EXPECT_THAT(seen_abort_rate,
-              ::testing::AllOf(::testing::Ge(kAbortRate - kErrorTolerance),
-                               ::testing::Le(kAbortRate + kErrorTolerance)));
+              ::testing::DoubleNear(kAbortRate, kErrorTolerance));
 }
 
 TEST_P(FaultInjectionTest, XdsFaultInjectionMaxFault) {
   const uint32_t kMaxFault = 10;
   const uint32_t kNumRpcs = 30;  // kNumRpcs should be bigger than kMaxFault
-  const uint32_t kRpcTimeoutMs = 2000;     // 2 seconds
+  const uint32_t kRpcTimeoutMs = 4000;     // 4 seconds
   const uint32_t kLongDelaySeconds = 100;  // 100 seconds
   const uint32_t kAlwaysDelayPercentage = 100;
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   // Create an EDS resource
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -10337,37 +10585,29 @@ TEST_P(FaultInjectionTest, XdsFaultInjectionMaxFault) {
   SetFilterConfig(http_fault);
   // Sends a batch of long running RPCs with long timeout to consume all
   // active faults quota.
-  int num_ok = 0, num_delayed = 0;
-  LongRunningRpc rpcs[kNumRpcs];
+  int num_delayed = 0;
   RpcOptions rpc_options = RpcOptions().set_timeout_ms(kRpcTimeoutMs);
-  for (size_t i = 0; i < kNumRpcs; ++i) {
-    rpcs[i].StartRpc(stub_.get(), rpc_options);
-  }
-  for (size_t i = 0; i < kNumRpcs; ++i) {
-    Status status = rpcs[i].GetStatus();
-    if (status.ok()) {
-      ++num_ok;
-    } else {
-      EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, status.error_code());
-      ++num_delayed;
-    }
+  std::vector<ConcurrentRpc> rpcs =
+      SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
+  for (auto& rpc : rpcs) {
+    if (rpc.status.error_code() == StatusCode::OK) continue;
+    EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
+    ++num_delayed;
   }
   // Only kMaxFault number of RPC should be fault injected..
   EXPECT_EQ(kMaxFault, num_delayed);
-  // Other RPCs should be ok.
-  EXPECT_EQ(kNumRpcs - kMaxFault, num_ok);
 }
 
-class BootstrapContentsFromEnvVarTest : public XdsEnd2endTest {
+class BootstrapSourceTest : public XdsEnd2endTest {
  public:
-  BootstrapContentsFromEnvVarTest() : XdsEnd2endTest(4, 1, 100, false, true) {}
+  BootstrapSourceTest() : XdsEnd2endTest(4, 1) {}
 };
 
-TEST_P(BootstrapContentsFromEnvVarTest, Vanilla) {
+TEST_P(BootstrapSourceTest, Vanilla) {
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
   AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", GetBackendPorts()},
+      {"locality0", CreateEndpointsForBackends()},
   });
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
@@ -10381,7 +10621,7 @@ class ClientStatusDiscoveryServiceTest : public XdsEnd2endTest {
 
   void SetUp() override {
     XdsEnd2endTest::SetUp();
-    admin_server_thread_ = absl::make_unique<AdminServerThread>();
+    admin_server_thread_ = absl::make_unique<AdminServerThread>(this);
     admin_server_thread_->Start();
     std::string admin_server_address = absl::StrCat(
         ipv6_only_ ? "[::1]:" : "127.0.0.1:", admin_server_thread_->port());
@@ -10745,9 +10985,8 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpVanilla) {
   const size_t kNumRpcs = 5;
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {backends_[0]->port()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", CreateEndpointsForBackends(0, 1)}});
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   // Send several RPCs to ensure the xDS setup works
@@ -10817,9 +11056,8 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpListenerError) {
   int kFetchIntervalMilliseconds = 200;
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {backends_[0]->port()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", CreateEndpointsForBackends(0, 1)}});
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   // Ensure the xDS resolver has working configs.
@@ -10865,9 +11103,8 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpRouteError) {
   int kFetchIntervalMilliseconds = 200;
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {backends_[0]->port()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", CreateEndpointsForBackends(0, 1)}});
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   // Ensure the xDS resolver has working configs.
@@ -10922,9 +11159,8 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpClusterError) {
   int kFetchIntervalMilliseconds = 200;
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {backends_[0]->port()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", CreateEndpointsForBackends(0, 1)}});
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   // Ensure the xDS resolver has working configs.
@@ -10962,9 +11198,8 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpEndpointError) {
   int kFetchIntervalMilliseconds = 200;
   SetNextResolution({});
   SetNextResolutionForLbChannelAllBalancers();
-  AdsServiceImpl::EdsResourceArgs args({
-      {"locality0", {backends_[0]->port()}},
-  });
+  AdsServiceImpl::EdsResourceArgs args(
+      {{"locality0", CreateEndpointsForBackends(0, 1)}});
   balancers_[0]->ads_service()->SetEdsResource(
       BuildEdsResource(args, DefaultEdsServiceName()));
   // Ensure the xDS resolver has working configs.
@@ -11006,7 +11241,7 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpListenerRequested) {
   int kTimeoutMillisecond = 1000;
   balancers_[0]->ads_service()->UnsetResource(kLdsTypeUrl, kServerName);
   CheckRpcSendFailure(1, RpcOptions().set_timeout_ms(kTimeoutMillisecond),
-                      grpc::DEADLINE_EXCEEDED);
+                      StatusCode::DEADLINE_EXCEEDED);
   auto csds_response = FetchCsdsResponse();
   EXPECT_THAT(csds_response.config(0).xds_config(),
               ::testing::Contains(::testing::Property(
@@ -11040,7 +11275,7 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpClusterRequested) {
   SetRouteConfiguration(0, route_config);
   // Try to get the configs plumb through
   CheckRpcSendFailure(1, RpcOptions().set_timeout_ms(kTimeoutMillisecond),
-                      grpc::DEADLINE_EXCEEDED);
+                      StatusCode::DEADLINE_EXCEEDED);
   auto csds_response = FetchCsdsResponse();
   EXPECT_THAT(csds_response.config(0).xds_config(),
               ::testing::Contains(::testing::Property(
@@ -11059,7 +11294,7 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpClusterRequested) {
 class CsdsShortAdsTimeoutTest : public ClientStatusDiscoveryServiceTest {
   void SetUp() override {
     // Shorten the ADS subscription timeout to speed up the test run.
-    xds_resource_does_not_exist_timeout_ms_ = 500;
+    xds_resource_does_not_exist_timeout_ms_ = 2000;
     ClientStatusDiscoveryServiceTest::SetUp();
   }
 };
@@ -11189,8 +11424,13 @@ INSTANTIATE_TEST_SUITE_P(
     ::testing::Values(TestType().set_use_xds_credentials()), &TestTypeName);
 
 // We are only testing the server here.
+// Run with bootstrap from env var, so that we use a global XdsClient
+// instance.  Otherwise, we would need to use a separate fake resolver
+// result generator on the client and server sides.
 INSTANTIATE_TEST_SUITE_P(XdsTest, XdsEnabledServerTest,
-                         ::testing::Values(TestType()), &TestTypeName);
+                         ::testing::Values(TestType().set_bootstrap_source(
+                             TestType::kBootstrapFromEnvVar)),
+                         &TestTypeName);
 
 // We are only testing the server here.
 INSTANTIATE_TEST_SUITE_P(XdsTest, XdsServerSecurityTest,
@@ -11234,6 +11474,16 @@ INSTANTIATE_TEST_SUITE_P(
     ::testing::Values(TestType(), TestType().set_enable_load_reporting()),
     &TestTypeName);
 
+// Runs with bootstrap from env var, so that there's a global XdsClient.
+INSTANTIATE_TEST_SUITE_P(
+    XdsTest, GlobalXdsClientTest,
+    ::testing::Values(
+        TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
+        TestType()
+            .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
+            .set_enable_load_reporting()),
+    &TestTypeName);
+
 // XdsResolverLoadReprtingOnlyTest depends on XdsResolver and load reporting.
 INSTANTIATE_TEST_SUITE_P(
     XdsTest, XdsResolverLoadReportingOnlyTest,
@@ -11297,25 +11547,46 @@ INSTANTIATE_TEST_SUITE_P(
             TestType::FilterConfigSetup::kRouteOverride)),
     &TestTypeName);
 
-INSTANTIATE_TEST_SUITE_P(XdsTest, BootstrapContentsFromEnvVarTest,
-                         ::testing::Values(TestType()), &TestTypeName);
+INSTANTIATE_TEST_SUITE_P(
+    XdsTest, BootstrapSourceTest,
+    ::testing::Values(
+        TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
+        TestType().set_bootstrap_source(TestType::kBootstrapFromFile)),
+    &TestTypeName);
 
 #ifndef DISABLED_XDS_PROTO_IN_CC
 // Run CSDS tests with RDS enabled and disabled.
+// These need to run with the bootstrap from an env var instead of from
+// a channel arg, since there needs to be a global XdsClient instance.
 INSTANTIATE_TEST_SUITE_P(
     XdsTest, ClientStatusDiscoveryServiceTest,
     ::testing::Values(
-        TestType(), TestType().set_enable_rds_testing(),
-        TestType().set_use_csds_streaming(),
-        TestType().set_enable_rds_testing().set_use_csds_streaming()),
+        TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
+        TestType()
+            .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
+            .set_enable_rds_testing(),
+        TestType()
+            .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
+            .set_use_csds_streaming(),
+        TestType()
+            .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
+            .set_enable_rds_testing()
+            .set_use_csds_streaming()),
     &TestTypeName);
-
 INSTANTIATE_TEST_SUITE_P(
     XdsTest, CsdsShortAdsTimeoutTest,
     ::testing::Values(
-        TestType(), TestType().set_enable_rds_testing(),
-        TestType().set_use_csds_streaming(),
-        TestType().set_enable_rds_testing().set_use_csds_streaming()),
+        TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
+        TestType()
+            .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
+            .set_enable_rds_testing(),
+        TestType()
+            .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
+            .set_use_csds_streaming(),
+        TestType()
+            .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
+            .set_enable_rds_testing()
+            .set_use_csds_streaming()),
     &TestTypeName);
 #endif  // DISABLED_XDS_PROTO_IN_CC
 
index 80bbe1a..0623280 100644 (file)
@@ -24,8 +24,8 @@
 #include <gtest/gtest.h>
 
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/proto/grpc/lb/v1/load_balancer.pb.h"  // C++ version
 
 #include "test/core/util/test_config.h"
index 28c358b..caa86fc 100644 (file)
@@ -150,11 +150,8 @@ int TcpUserTimeoutCompare(grpc_socket_mutator* /*a*/,
 void TcpUserTimeoutDestroy(grpc_socket_mutator* mutator) { gpr_free(mutator); }
 
 const grpc_socket_mutator_vtable kTcpUserTimeoutMutatorVtable =
-    grpc_socket_mutator_vtable{
-        .mutate_fd = TcpUserTimeoutMutateFd,
-        .compare = TcpUserTimeoutCompare,
-        .destroy = TcpUserTimeoutDestroy,
-    };
+    grpc_socket_mutator_vtable{TcpUserTimeoutMutateFd, TcpUserTimeoutCompare,
+                               TcpUserTimeoutDestroy};
 
 std::unique_ptr<TestService::Stub> CreateFallbackTestStub() {
   grpc::ChannelArguments channel_args;
index ab0c02a..81351f7 100644 (file)
@@ -312,9 +312,11 @@ static void BM_LameChannelCallCreateCoreSeparateBatch(benchmark::State& state) {
 }
 BENCHMARK(BM_LameChannelCallCreateCoreSeparateBatch);
 
-static void FilterDestroy(void* arg, grpc_error* /*error*/) { gpr_free(arg); }
+static void FilterDestroy(void* arg, grpc_error_handle /*error*/) {
+  gpr_free(arg);
+}
 
-static void DoNothing(void* /*arg*/, grpc_error* /*error*/) {}
+static void DoNothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 class FakeClientChannelFactory : public grpc_core::ClientChannelFactory {
  public:
@@ -351,8 +353,8 @@ static void StartTransportStreamOp(grpc_call_element* /*elem*/,
 static void StartTransportOp(grpc_channel_element* /*elem*/,
                              grpc_transport_op* /*op*/) {}
 
-static grpc_error* InitCallElem(grpc_call_element* /*elem*/,
-                                const grpc_call_element_args* /*args*/) {
+static grpc_error_handle InitCallElem(grpc_call_element* /*elem*/,
+                                      const grpc_call_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
@@ -363,8 +365,8 @@ static void DestroyCallElem(grpc_call_element* /*elem*/,
                             const grpc_call_final_info* /*final_info*/,
                             grpc_closure* /*then_sched_closure*/) {}
 
-grpc_error* InitChannelElem(grpc_channel_element* /*elem*/,
-                            grpc_channel_element_args* /*args*/) {
+grpc_error_handle InitChannelElem(grpc_channel_element* /*elem*/,
+                                  grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
@@ -568,7 +570,8 @@ BENCHMARK_TEMPLATE(BM_IsolatedFilter, NoFilter, NoOp);
 typedef Fixture<&phony_filter::phony_filter, 0> PhonyFilter;
 BENCHMARK_TEMPLATE(BM_IsolatedFilter, PhonyFilter, NoOp);
 BENCHMARK_TEMPLATE(BM_IsolatedFilter, PhonyFilter, SendEmptyMetadata);
-typedef Fixture<&grpc_client_channel_filter, 0> ClientChannelFilter;
+typedef Fixture<&grpc_core::ClientChannel::kFilterVtable, 0>
+    ClientChannelFilter;
 BENCHMARK_TEMPLATE(BM_IsolatedFilter, ClientChannelFilter, NoOp);
 typedef Fixture<&grpc_message_compress_filter, CHECKS_NOT_LAST> CompressFilter;
 BENCHMARK_TEMPLATE(BM_IsolatedFilter, CompressFilter, NoOp);
@@ -641,8 +644,8 @@ static void StartTransportOp(grpc_channel_element* /*elem*/,
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->on_consumed, GRPC_ERROR_NONE);
 }
 
-static grpc_error* InitCallElem(grpc_call_element* elem,
-                                const grpc_call_element_args* args) {
+static grpc_error_handle InitCallElem(grpc_call_element* elem,
+                                      const grpc_call_element_args* args) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->call_combiner = args->call_combiner;
   return GRPC_ERROR_NONE;
@@ -657,8 +660,8 @@ static void DestroyCallElem(grpc_call_element* /*elem*/,
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, then_sched_closure, GRPC_ERROR_NONE);
 }
 
-grpc_error* InitChannelElem(grpc_channel_element* /*elem*/,
-                            grpc_channel_element_args* /*args*/) {
+grpc_error_handle InitChannelElem(grpc_channel_element* /*elem*/,
+                                  grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
index 063b7fc..1a1de05 100644 (file)
@@ -452,12 +452,12 @@ static void BM_HpackParserInitDestroy(benchmark::State& state) {
 }
 BENCHMARK(BM_HpackParserInitDestroy);
 
-static grpc_error* UnrefHeader(void* /*user_data*/, grpc_mdelem md) {
+static grpc_error_handle UnrefHeader(void* /*user_data*/, grpc_mdelem md) {
   GRPC_MDELEM_UNREF(md);
   return GRPC_ERROR_NONE;
 }
 
-template <class Fixture, grpc_error* (*OnHeader)(void*, grpc_mdelem)>
+template <class Fixture, grpc_error_handle (*OnHeader)(void*, grpc_mdelem)>
 static void BM_HpackParserParseHeader(benchmark::State& state) {
   TrackCounters track_counters;
   grpc_core::ExecCtx exec_ctx;
@@ -784,7 +784,7 @@ class RepresentativeServerTrailingMetadata {
 static void free_timeout(void* p) { gpr_free(p); }
 
 // Benchmark the current on_initial_header implementation
-static grpc_error* OnInitialHeader(void* user_data, grpc_mdelem md) {
+static grpc_error_handle OnInitialHeader(void* user_data, grpc_mdelem md) {
   // Setup for benchmark. This will bloat the absolute values of this benchmark
   grpc_chttp2_incoming_metadata_buffer buffer(
       static_cast<grpc_core::Arena*>(user_data));
@@ -825,7 +825,8 @@ static grpc_error* OnInitialHeader(void* user_data, grpc_mdelem md) {
     if (!seen_error) {
       buffer.size = new_size;
     }
-    grpc_error* error = grpc_chttp2_incoming_metadata_buffer_add(&buffer, md);
+    grpc_error_handle error =
+        grpc_chttp2_incoming_metadata_buffer_add(&buffer, md);
     if (error != GRPC_ERROR_NONE) {
       GPR_ASSERT(0);
     }
@@ -834,7 +835,7 @@ static grpc_error* OnInitialHeader(void* user_data, grpc_mdelem md) {
 }
 
 // Benchmark timeout handling
-static grpc_error* OnHeaderTimeout(void* /*user_data*/, grpc_mdelem md) {
+static grpc_error_handle OnHeaderTimeout(void* /*user_data*/, grpc_mdelem md) {
   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));
index 2e16542..92c6ccd 100644 (file)
@@ -111,7 +111,7 @@ class PhonyEndpoint : public grpc_endpoint {
   static void delete_from_pollset_set(grpc_endpoint* /*ep*/,
                                       grpc_pollset_set* /*pollset*/) {}
 
-  static void shutdown(grpc_endpoint* ep, grpc_error* why) {
+  static void shutdown(grpc_endpoint* ep, grpc_error_handle why) {
     grpc_resource_user_shutdown(static_cast<PhonyEndpoint*>(ep)->ru_);
     grpc_core::ExecCtx::Run(DEBUG_LOCATION,
                             static_cast<PhonyEndpoint*>(ep)->read_cb_, why);
@@ -171,7 +171,7 @@ std::unique_ptr<TestClosure> MakeTestClosure(F f) {
       GRPC_CLOSURE_INIT(this, Execute, this, nullptr);
     }
     F f_;
-    static void Execute(void* arg, grpc_error* error) {
+    static void Execute(void* arg, grpc_error_handle error) {
       static_cast<C*>(arg)->f_(error);
     }
   };
@@ -183,7 +183,7 @@ grpc_closure* MakeOnceClosure(F f) {
   struct C : public grpc_closure {
     explicit C(const F& f) : f_(f) {}
     F f_;
-    static void Execute(void* arg, grpc_error* error) {
+    static void Execute(void* arg, grpc_error_handle error) {
       static_cast<C*>(arg)->f_(error);
       delete static_cast<C*>(arg);
     }
@@ -239,7 +239,7 @@ class Stream {
   }
 
  private:
-  static void FinishDestroy(void* arg, grpc_error* /*error*/) {
+  static void FinishDestroy(void* arg, grpc_error_handle /*error*/) {
     auto stream = static_cast<Stream*>(arg);
     grpc_transport_destroy_stream(stream->f_->transport(),
                                   static_cast<grpc_stream*>(stream->stream_),
@@ -273,7 +273,7 @@ static void BM_StreamCreateDestroy(benchmark::State& state) {
   op.payload = &op_payload;
   op_payload.cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
   std::unique_ptr<TestClosure> next =
-      MakeTestClosure([&, s](grpc_error* /*error*/) {
+      MakeTestClosure([&, s](grpc_error_handle /*error*/) {
         if (!state.KeepRunning()) {
           delete s;
           return;
@@ -339,7 +339,7 @@ static void BM_StreamCreateSendInitialMetadataDestroy(benchmark::State& state) {
   f.FlushExecCtx();
   gpr_event bm_done;
   gpr_event_init(&bm_done);
-  start = MakeTestClosure([&, s](grpc_error* /*error*/) {
+  start = MakeTestClosure([&, s](grpc_error_handle /*error*/) {
     if (!state.KeepRunning()) {
       delete s;
       gpr_event_set(&bm_done, (void*)1);
@@ -352,7 +352,7 @@ static void BM_StreamCreateSendInitialMetadataDestroy(benchmark::State& state) {
     op.payload->send_initial_metadata.send_initial_metadata = &b;
     s->Op(&op);
   });
-  done = MakeTestClosure([&](grpc_error* /*error*/) {
+  done = MakeTestClosure([&](grpc_error_handle /*error*/) {
     reset_op();
     op.cancel_stream = true;
     op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
@@ -380,12 +380,13 @@ static void BM_TransportEmptyOp(benchmark::State& state) {
     op = {};
     op.payload = &op_payload;
   };
-  std::unique_ptr<TestClosure> c = MakeTestClosure([&](grpc_error* /*error*/) {
-    if (!state.KeepRunning()) return;
-    reset_op();
-    op.on_complete = c.get();
-    s->Op(&op);
-  });
+  std::unique_ptr<TestClosure> c =
+      MakeTestClosure([&](grpc_error_handle /*error*/) {
+        if (!state.KeepRunning()) return;
+        reset_op();
+        op.on_complete = c.get();
+        s->Op(&op);
+      });
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, c.get(), GRPC_ERROR_NONE);
   f.FlushExecCtx();
   reset_op();
@@ -394,7 +395,7 @@ static void BM_TransportEmptyOp(benchmark::State& state) {
   gpr_event* stream_cancel_done = new gpr_event;
   gpr_event_init(stream_cancel_done);
   std::unique_ptr<TestClosure> stream_cancel_closure =
-      MakeTestClosure([&](grpc_error* error) {
+      MakeTestClosure([&](grpc_error_handle error) {
         GPR_ASSERT(error == GRPC_ERROR_NONE);
         gpr_event_set(stream_cancel_done, reinterpret_cast<void*>(1));
       });
@@ -403,7 +404,8 @@ static void BM_TransportEmptyOp(benchmark::State& state) {
   f.FlushExecCtx();
   gpr_event_wait(stream_cancel_done, gpr_inf_future(GPR_CLOCK_REALTIME));
   done_events.emplace_back(stream_cancel_done);
-  s->DestroyThen(MakeOnceClosure([s](grpc_error* /*error*/) { delete s; }));
+  s->DestroyThen(
+      MakeOnceClosure([s](grpc_error_handle /*error*/) { delete s; }));
   f.FlushExecCtx();
   track_counters.Finish(state);
 }
@@ -442,25 +444,26 @@ static void BM_TransportStreamSend(benchmark::State& state) {
   gpr_event* bm_done = new gpr_event;
   gpr_event_init(bm_done);
 
-  std::unique_ptr<TestClosure> c = MakeTestClosure([&](grpc_error* /*error*/) {
-    if (!state.KeepRunning()) {
-      gpr_event_set(bm_done, reinterpret_cast<void*>(1));
-      return;
-    }
-    grpc_slice_buffer send_buffer;
-    grpc_slice_buffer_init(&send_buffer);
-    grpc_slice_buffer_add(&send_buffer, grpc_slice_ref(send_slice));
-    send_stream.Init(&send_buffer, 0);
-    grpc_slice_buffer_destroy(&send_buffer);
-    // force outgoing window to be yuge
-    s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
-    f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
-    reset_op();
-    op.on_complete = c.get();
-    op.send_message = true;
-    op.payload->send_message.send_message.reset(send_stream.get());
-    s->Op(&op);
-  });
+  std::unique_ptr<TestClosure> c =
+      MakeTestClosure([&](grpc_error_handle /*error*/) {
+        if (!state.KeepRunning()) {
+          gpr_event_set(bm_done, reinterpret_cast<void*>(1));
+          return;
+        }
+        grpc_slice_buffer send_buffer;
+        grpc_slice_buffer_init(&send_buffer);
+        grpc_slice_buffer_add(&send_buffer, grpc_slice_ref(send_slice));
+        send_stream.Init(&send_buffer, 0);
+        grpc_slice_buffer_destroy(&send_buffer);
+        // force outgoing window to be yuge
+        s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
+        f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
+        reset_op();
+        op.on_complete = c.get();
+        op.send_message = true;
+        op.payload->send_message.send_message.reset(send_stream.get());
+        s->Op(&op);
+      });
 
   reset_op();
   op.send_initial_metadata = true;
@@ -478,7 +481,7 @@ static void BM_TransportStreamSend(benchmark::State& state) {
   gpr_event* stream_cancel_done = new gpr_event;
   gpr_event_init(stream_cancel_done);
   std::unique_ptr<TestClosure> stream_cancel_closure =
-      MakeTestClosure([&](grpc_error* error) {
+      MakeTestClosure([&](grpc_error_handle error) {
         GPR_ASSERT(error == GRPC_ERROR_NONE);
         gpr_event_set(stream_cancel_done, reinterpret_cast<void*>(1));
       });
@@ -487,7 +490,8 @@ static void BM_TransportStreamSend(benchmark::State& state) {
   f.FlushExecCtx();
   gpr_event_wait(stream_cancel_done, gpr_inf_future(GPR_CLOCK_REALTIME));
   done_events.emplace_back(stream_cancel_done);
-  s->DestroyThen(MakeOnceClosure([s](grpc_error* /*error*/) { delete s; }));
+  s->DestroyThen(
+      MakeOnceClosure([s](grpc_error_handle /*error*/) { delete s; }));
   f.FlushExecCtx();
   track_counters.Finish(state);
   grpc_metadata_batch_destroy(&b);
@@ -582,7 +586,7 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
   }
 
   std::unique_ptr<TestClosure> do_nothing =
-      MakeTestClosure([](grpc_error* /*error*/) {});
+      MakeTestClosure([](grpc_error_handle /*error*/) {});
 
   uint32_t received;
 
@@ -591,22 +595,23 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
   std::unique_ptr<TestClosure> drain_continue;
   grpc_slice recv_slice;
 
-  std::unique_ptr<TestClosure> c = MakeTestClosure([&](grpc_error* /*error*/) {
-    if (!state.KeepRunning()) return;
-    // force outgoing window to be yuge
-    s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
-    f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
-    received = 0;
-    reset_op();
-    op.on_complete = do_nothing.get();
-    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);
-    f.PushInput(grpc_slice_ref(incoming_data));
-  });
+  std::unique_ptr<TestClosure> c =
+      MakeTestClosure([&](grpc_error_handle /*error*/) {
+        if (!state.KeepRunning()) return;
+        // force outgoing window to be yuge
+        s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
+        f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
+        received = 0;
+        reset_op();
+        op.on_complete = do_nothing.get();
+        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);
+        f.PushInput(grpc_slice_ref(incoming_data));
+      });
 
-  drain_start = MakeTestClosure([&](grpc_error* /*error*/) {
+  drain_start = MakeTestClosure([&](grpc_error_handle /*error*/) {
     if (recv_stream == nullptr) {
       GPR_ASSERT(!state.KeepRunning());
       return;
@@ -614,7 +619,7 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
     grpc_core::Closure::Run(DEBUG_LOCATION, drain.get(), GRPC_ERROR_NONE);
   });
 
-  drain = MakeTestClosure([&](grpc_error* /*error*/) {
+  drain = MakeTestClosure([&](grpc_error_handle /*error*/) {
     do {
       if (received == recv_stream->length()) {
         recv_stream.reset();
@@ -628,7 +633,7 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
               grpc_slice_unref_internal(recv_slice), true));
   });
 
-  drain_continue = MakeTestClosure([&](grpc_error* /*error*/) {
+  drain_continue = MakeTestClosure([&](grpc_error_handle /*error*/) {
     recv_stream->Pull(&recv_slice);
     received += GRPC_SLICE_LENGTH(recv_slice);
     grpc_slice_unref_internal(recv_slice);
@@ -664,7 +669,7 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
   gpr_event* stream_cancel_done = new gpr_event;
   gpr_event_init(stream_cancel_done);
   std::unique_ptr<TestClosure> stream_cancel_closure =
-      MakeTestClosure([&](grpc_error* error) {
+      MakeTestClosure([&](grpc_error_handle error) {
         GPR_ASSERT(error == GRPC_ERROR_NONE);
         gpr_event_set(stream_cancel_done, reinterpret_cast<void*>(1));
       });
@@ -673,7 +678,8 @@ static void BM_TransportStreamRecv(benchmark::State& state) {
   f.FlushExecCtx();
   gpr_event_wait(stream_cancel_done, gpr_inf_future(GPR_CLOCK_REALTIME));
   done_events.emplace_back(stream_cancel_done);
-  s->DestroyThen(MakeOnceClosure([s](grpc_error* /*error*/) { delete s; }));
+  s->DestroyThen(
+      MakeOnceClosure([s](grpc_error_handle /*error*/) { delete s; }));
   grpc_metadata_batch_destroy(&b);
   grpc_metadata_batch_destroy(&b_recv);
   f.FlushExecCtx();
index 440eac0..e38f95f 100644 (file)
@@ -51,7 +51,7 @@ static void BM_WellFlushed(benchmark::State& state) {
 }
 BENCHMARK(BM_WellFlushed);
 
-static void DoNothing(void* /*arg*/, grpc_error* /*error*/) {}
+static void DoNothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 static void BM_ClosureInitAgainstExecCtx(benchmark::State& state) {
   TrackCounters track_counters;
@@ -369,7 +369,7 @@ class Rescheduler {
   benchmark::State& state_;
   grpc_closure closure_;
 
-  static void Step(void* arg, grpc_error* /*error*/) {
+  static void Step(void* arg, grpc_error_handle /*error*/) {
     Rescheduler* self = static_cast<Rescheduler*>(arg);
     if (self->state_.KeepRunning()) {
       grpc_core::ExecCtx::Run(DEBUG_LOCATION, &self->closure_, GRPC_ERROR_NONE);
index f008249..d57a021 100644 (file)
@@ -56,8 +56,8 @@ static void pollset_init(grpc_pollset* ps, gpr_mu** mu) {
 
 static void pollset_destroy(grpc_pollset* ps) { gpr_mu_destroy(&ps->mu); }
 
-static grpc_error* pollset_kick(grpc_pollset* /*p*/,
-                                grpc_pollset_worker* /*worker*/) {
+static grpc_error_handle pollset_kick(grpc_pollset* /*p*/,
+                                      grpc_pollset_worker* /*worker*/) {
   return GRPC_ERROR_NONE;
 }
 
@@ -68,9 +68,9 @@ static void cq_done_cb(void* /*done_arg*/, grpc_cq_completion* cq_completion) {
 
 /* Queues a completion tag if deadline is > 0.
  * Does nothing if deadline is 0 (i.e gpr_time_0(GPR_CLOCK_MONOTONIC)) */
-static grpc_error* pollset_work(grpc_pollset* ps,
-                                grpc_pollset_worker** /*worker*/,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* ps,
+                                      grpc_pollset_worker** /*worker*/,
+                                      grpc_millis deadline) {
   if (deadline == 0) {
     gpr_log(GPR_DEBUG, "no-op");
     return GRPC_ERROR_NONE;
@@ -98,8 +98,10 @@ static const grpc_event_engine_vtable* init_engine_vtable(bool) {
   g_vtable.pollset_work = pollset_work;
   g_vtable.pollset_kick = pollset_kick;
   g_vtable.is_any_background_poller_thread = [] { return false; };
-  g_vtable.add_closure_to_background_poller =
-      [](grpc_closure* /*closure*/, grpc_error* /*error*/) { return false; };
+  g_vtable.add_closure_to_background_poller = [](grpc_closure* /*closure*/,
+                                                 grpc_error_handle /*error*/) {
+    return false;
+  };
   g_vtable.shutdown_background_closure = [] {};
   g_vtable.shutdown_engine = [] {};
 
index ce42f33..ecc39ac 100644 (file)
@@ -30,7 +30,7 @@
 
 class ErrorDeleter {
  public:
-  void operator()(grpc_error* error) { GRPC_ERROR_UNREF(error); }
+  void operator()(grpc_error_handle error) { GRPC_ERROR_UNREF(error); }
 };
 typedef std::unique_ptr<grpc_error, ErrorDeleter> ErrorPtr;
 
@@ -78,7 +78,7 @@ BENCHMARK(BM_ErrorCreateAndSetIntAndStr);
 
 static void BM_ErrorCreateAndSetIntLoop(benchmark::State& state) {
   TrackCounters track_counters;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
   int n = 0;
   for (auto _ : state) {
     error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, n++);
@@ -90,7 +90,7 @@ BENCHMARK(BM_ErrorCreateAndSetIntLoop);
 
 static void BM_ErrorCreateAndSetStrLoop(benchmark::State& state) {
   TrackCounters track_counters;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
   const char* str = "hello";
   for (auto _ : state) {
     error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE,
@@ -103,7 +103,7 @@ BENCHMARK(BM_ErrorCreateAndSetStrLoop);
 
 static void BM_ErrorRefUnref(benchmark::State& state) {
   TrackCounters track_counters;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
   for (auto _ : state) {
     GRPC_ERROR_UNREF(GRPC_ERROR_REF(error));
   }
@@ -158,7 +158,7 @@ BENCHMARK(BM_ErrorGetPresentInt);
 class ErrorNone {
  public:
   grpc_millis deadline() const { return deadline_; }
-  grpc_error* error() const { return GRPC_ERROR_NONE; }
+  grpc_error_handle error() const { return GRPC_ERROR_NONE; }
 
  private:
   const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
@@ -167,7 +167,7 @@ class ErrorNone {
 class ErrorCancelled {
  public:
   grpc_millis deadline() const { return deadline_; }
-  grpc_error* error() const { return GRPC_ERROR_CANCELLED; }
+  grpc_error_handle error() const { return GRPC_ERROR_CANCELLED; }
 
  private:
   const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
@@ -176,7 +176,7 @@ class ErrorCancelled {
 class SimpleError {
  public:
   grpc_millis deadline() const { return deadline_; }
-  grpc_error* error() const { return error_.get(); }
+  grpc_error_handle error() const { return error_.get(); }
 
  private:
   const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
@@ -186,7 +186,7 @@ class SimpleError {
 class ErrorWithGrpcStatus {
  public:
   grpc_millis deadline() const { return deadline_; }
-  grpc_error* error() const { return error_.get(); }
+  grpc_error_handle error() const { return error_.get(); }
 
  private:
   const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
@@ -198,7 +198,7 @@ class ErrorWithGrpcStatus {
 class ErrorWithHttpError {
  public:
   grpc_millis deadline() const { return deadline_; }
-  grpc_error* error() const { return error_.get(); }
+  grpc_error_handle error() const { return error_.get(); }
 
  private:
   const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
@@ -210,14 +210,14 @@ class ErrorWithHttpError {
 class ErrorWithNestedGrpcStatus {
  public:
   grpc_millis deadline() const { return deadline_; }
-  grpc_error* error() const { return error_.get(); }
+  grpc_error_handle error() const { return error_.get(); }
 
  private:
   const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
   ErrorPtr nested_error_{grpc_error_set_int(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_GRPC_STATUS,
       GRPC_STATUS_UNIMPLEMENTED)};
-  grpc_error* nested_errors_[1] = {nested_error_.get()};
+  grpc_error_handle nested_errors_[1] = {nested_error_.get()};
   ErrorPtr error_{GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
       "Error", nested_errors_, 1)};
 };
index 928b587..ee813aa 100644 (file)
@@ -41,7 +41,7 @@
 #include <unistd.h>
 #endif
 
-static void shutdown_ps(void* ps, grpc_error* /*error*/) {
+static void shutdown_ps(void* ps, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(ps));
 }
 
@@ -167,7 +167,7 @@ template <class F>
 TestClosure* MakeTestClosure(F f) {
   struct C : public TestClosure {
     explicit C(F f) : f_(f) { GRPC_CLOSURE_INIT(this, C::cbfn, this, nullptr); }
-    static void cbfn(void* arg, grpc_error* /*error*/) {
+    static void cbfn(void* arg, grpc_error_handle /*error*/) {
       C* p = static_cast<C*>(arg);
       p->f_();
     }
index 3b0e0e2..60bf65d 100644 (file)
@@ -47,8 +47,9 @@ static void BM_InitCancelTimer(benchmark::State& state) {
   for (auto _ : state) {
     TimerClosure* timer_closure = &timer_closures[i++ % kTimerCount];
     GRPC_CLOSURE_INIT(
-        &timer_closure->closure, [](void* /*args*/, grpc_error* /*err*/) {},
-        nullptr, grpc_schedule_on_exec_ctx);
+        &timer_closure->closure,
+        [](void* /*args*/, grpc_error_handle /*err*/) {}, nullptr,
+        grpc_schedule_on_exec_ctx);
     grpc_timer_init(&timer_closure->timer, GRPC_MILLIS_INF_FUTURE,
                     &timer_closure->closure);
     grpc_timer_cancel(&timer_closure->timer);
@@ -76,8 +77,9 @@ static void BM_TimerBatch(benchmark::State& state) {
     for (grpc_millis deadline = start; deadline != end; deadline += increment) {
       TimerClosure* timer_closure = &timer_closures[deadline % kTimerCount];
       GRPC_CLOSURE_INIT(
-          &timer_closure->closure, [](void* /*args*/, grpc_error* /*err*/) {},
-          nullptr, grpc_schedule_on_exec_ctx);
+          &timer_closure->closure,
+          [](void* /*args*/, grpc_error_handle /*err*/) {}, nullptr,
+          grpc_schedule_on_exec_ctx);
 
       grpc_timer_init(&timer_closure->timer, deadline, &timer_closure->closure);
     }
index edcee21..e2b56c9 100644 (file)
@@ -35,6 +35,7 @@
 #include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/host_port.h"
@@ -42,7 +43,6 @@
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/subprocess.h"
index 371e3e5..239d7d4 100644 (file)
@@ -96,7 +96,7 @@ void ArgsInit(ArgsStruct* args) {
   args->channel_args = nullptr;
 }
 
-void DoNothing(void* /*arg*/, grpc_error* /*error*/) {}
+void DoNothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 void ArgsFinish(ArgsStruct* args) {
   grpc_pollset_set_del_pollset(args->pollset_set, args->pollset);
@@ -146,7 +146,7 @@ class AssertFailureResultHandler : public grpc_core::Resolver::ResultHandler {
     GPR_ASSERT(false);
   }
 
-  void ReturnError(grpc_error* /*error*/) override { GPR_ASSERT(false); }
+  void ReturnError(grpc_error_handle /*error*/) override { GPR_ASSERT(false); }
 
  private:
   ArgsStruct* args_;
index 1fdc38d..a8c39fc 100644 (file)
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_utils.h"
 #include "src/core/lib/iomgr/work_serializer.h"
 #include "test/core/util/port.h"
@@ -210,7 +210,7 @@ void ArgsInit(ArgsStruct* args) {
   args->channel_args = nullptr;
 }
 
-void DoNothing(void* /*arg*/, grpc_error* /*error*/) {}
+void DoNothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 void ArgsFinish(ArgsStruct* args) {
   GPR_ASSERT(gpr_event_wait(&args->ev, TestDeadline()));
@@ -260,7 +260,7 @@ void PollPollsetUntilRequestDone(ArgsStruct* args) {
 }
 
 void CheckServiceConfigResultLocked(const char* service_config_json,
-                                    grpc_error* service_config_error,
+                                    grpc_error_handle service_config_error,
                                     ArgsStruct* args) {
   if (!args->expected_service_config_string.empty()) {
     GPR_ASSERT(service_config_json != nullptr);
@@ -269,7 +269,7 @@ void CheckServiceConfigResultLocked(const char* service_config_json,
   if (args->expected_service_config_error.empty()) {
     EXPECT_EQ(service_config_error, GRPC_ERROR_NONE);
   } else {
-    EXPECT_THAT(grpc_error_string(service_config_error),
+    EXPECT_THAT(grpc_error_std_string(service_config_error),
                 testing::HasSubstr(args->expected_service_config_error));
   }
   GRPC_ERROR_UNREF(service_config_error);
@@ -435,8 +435,9 @@ class ResultHandler : public grpc_core::Resolver::ResultHandler {
     gpr_mu_unlock(args_->mu);
   }
 
-  void ReturnError(grpc_error* error) override {
-    gpr_log(GPR_ERROR, "resolver returned error: %s", grpc_error_string(error));
+  void ReturnError(grpc_error_handle error) override {
+    gpr_log(GPR_ERROR, "resolver returned error: %s",
+            grpc_error_std_string(error).c_str());
     GPR_ASSERT(false);
   }
 
index e970c6b..6c6b94b 100644 (file)
@@ -22,6 +22,23 @@ grpc_package(
 )
 
 grpc_cc_test(
+    name = "mock_stream_test",
+    srcs = ["mock_stream_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//:grpc++_test",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/core/util:grpc_test_util",
+        "//test/cpp/util:test_util",
+    ],
+)
+
+grpc_cc_test(
     name = "server_context_test_spouse_test",
     srcs = ["server_context_test_spouse_test.cc"],
     external_deps = [
diff --git a/test/cpp/test/mock_stream_test.cc b/test/cpp/test/mock_stream_test.cc
new file mode 100644 (file)
index 0000000..6545762
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *
+ * Copyright 2020 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 <grpcpp/test/mock_stream.h>
+#include <gtest/gtest.h>
+
+#include "absl/memory/memory.h"
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+
+using grpc::testing::EchoRequest;
+using grpc::testing::EchoResponse;
+
+TEST(MockStreamTest, Basic) {
+  auto cr = absl::make_unique<grpc::testing::MockClientReader<EchoResponse>>();
+  ASSERT_NE(cr, nullptr);
+
+  auto cw = absl::make_unique<grpc::testing::MockClientWriter<EchoResponse>>();
+  ASSERT_NE(cw, nullptr);
+
+  auto crw = absl::make_unique<
+      grpc::testing::MockClientReaderWriter<EchoResponse, EchoResponse>>();
+  ASSERT_NE(crw, nullptr);
+
+  auto carr = absl::make_unique<
+      grpc::testing::MockClientAsyncResponseReader<EchoResponse>>();
+  ASSERT_NE(carr, nullptr);
+
+  auto car =
+      absl::make_unique<grpc::testing::MockClientAsyncReader<EchoResponse>>();
+  ASSERT_NE(car, nullptr);
+
+  auto caw =
+      absl::make_unique<grpc::testing::MockClientAsyncWriter<EchoResponse>>();
+  ASSERT_NE(caw, nullptr);
+
+  auto carw = absl::make_unique<
+      grpc::testing::MockClientAsyncReaderWriter<EchoRequest, EchoResponse>>();
+  ASSERT_NE(carw, nullptr);
+}
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
index 88fb7e4..2e1c7be 100644 (file)
@@ -58,10 +58,10 @@ void VaidateProtoJsonTranslation(const std::string& json_str) {
   EXPECT_TRUE(s.ok());
   // Parse JSON and re-dump to string, to make sure formatting is the
   // same as what would be generated by our JSON library.
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json parsed_json =
       grpc_core::Json::Parse(proto_json_str.c_str(), &error);
-  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+  ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
   ASSERT_EQ(parsed_json.type(), grpc_core::Json::Type::OBJECT);
   proto_json_str = parsed_json.Dump();
   // uncomment these to compare the json strings.
index a6102f6..0ca30f4 100755 (executable)
@@ -20,6 +20,6 @@ cd "$(dirname "$0")"
 cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz .
 
 find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
-    xargs pecl install
+    MAKEFLAGS=-j xargs pecl install
 
 php -d extension=grpc.so -d max_execution_time=300 distribtest.php
index 8def049..1ec38c6 100755 (executable)
@@ -20,6 +20,6 @@ cd "$(dirname "$0")"
 cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz .
 
 find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
-    xargs sudo pecl install
+    xargs sudo MAKEFLAGS=-j pecl install
 
 php -d extension=grpc.so -d max_execution_time=300 distribtest.php
index 1144786..0fc2854 100644 (file)
@@ -18,4 +18,4 @@ import grpc
 # which is what we are testing here.
 channel = grpc.insecure_channel('localhost:1000')
 del channel
-print 'Success!'
+print('Success!')
index 473b542..b93570f 100644 (file)
@@ -81,9 +81,9 @@ git commit -m "update submodule boringssl-with-bazel with origin/master-with-baz
 
 - Run `tools/buildgen/generate_projects.sh` to regenerate the generated files
     - Because `sha256` in `bazel/grpc_deps.bzl` was left empty, you will get a DEBUG msg like this one:
-```
-Rule 'boringssl' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = "SHA value"
-```
+      ```
+      Rule 'boringssl' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = "SHA value"
+      ```
     - Commit the regenrated files `git commit -m "regenerate files"`
     - Update `bazel/grpc_deps.bzl` with the SHA value shown in the above debug msg. Commit again `git commit -m "Updated sha256"`
 
@@ -105,3 +105,10 @@ Rule 'boringssl' indicated that a canonical reproducible form can be obtained by
 ### Updating third_party/protobuf
 
 See http://go/grpc-third-party-protobuf-update-instructions (internal only)
+
+### Updating third_party/envoy-api
+
+Apart from the above steps, please perform the following two steps to generate the Python `xds-protos` package:
+
+1. Bump the version in the `tools/distrib/python/xds_protos/setup.py`;
+2. Run `tools/distrib/python/xds_protos/build_validate_upload.sh` to upload the built wheel.
index 7922086..f7ff1dd 100644 (file)
@@ -5,7 +5,7 @@ index 97ac28028..8b7585d9d 100644
 @@ -31,3 +31,9 @@
  # Copyright 2007 Google Inc. All Rights Reserved.
 
- __version__ = '3.15.2'
+ __version__ = '3.15.8'
 +
 +if __name__ != '__main__':
 +  try:
index e69de29..6ab5124 100644 (file)
@@ -0,0 +1,5 @@
+exports_files([
+    "BUILD.tpl",
+    "python_configure.bzl",
+    "variety.tpl"
+])
index 88fcb10..fa47d89 100644 (file)
@@ -348,7 +348,7 @@ def _python_autoconf_impl(repository_ctx):
         repository_ctx,
         "_python2",
         _PYTHON2_BIN_PATH,
-        "python",
+        "python2",
         _PYTHON2_LIB_PATH,
         True
     )
index 0797658..baf3c3d 100644 (file)
@@ -66,12 +66,12 @@ build:tsan --test_env=TSAN_OPTIONS=report_atomic_races=0
 build:tsan --action_env=TSAN_OPTIONS=suppressions=test/core/util/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
 
 build:ubsan --strip=never
-build:ubsan --copt=-fsanitize=undefined
+build:ubsan --copt=-fsanitize-link-c++-runtime
 build:ubsan --copt=-fno-omit-frame-pointer
 build:ubsan --copt=-DGRPC_UBSAN
 build:ubsan --copt=-DNDEBUG
 build:ubsan --copt=-fno-sanitize=function,vptr
-build:ubsan --linkopt=-fsanitize=undefined
+build:ubsan --linkopt=-fsanitize-link-c++-runtime
 build:ubsan --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1:suppressions=test/core/util/ubsan_suppressions.txt
 # For some reasons, these two stopped being propagated, so, redeclaring them here.
 # That's a hack that needs to be removed once we understand what's going on.
index 69b6605..77c3c49 100755 (executable)
@@ -49,7 +49,7 @@ def showhelp() -> None:
 
 def render_template(template: Template, context: Context) -> None:
     """Render the mako template with given context.
-    
+
     Prints an error template to indicate where and what in the template caused
     the render failure.
     """
index 5154fa2..d34251c 100755 (executable)
@@ -48,9 +48,12 @@ class GuardValidator(object):
         self.endif_re = re.compile(r'#endif  // ([A-Z][A-Z_1-9]*)')
         self.failed = False
 
+    def _is_c_core_header(self, fpath):
+        return 'include' in fpath and not ('grpc++' in fpath or 'grpcpp'
+                                           in fpath or 'event_engine' in fpath)
+
     def fail(self, fpath, regexp, fcontents, match_txt, correct, fix):
-        c_core_header = 'include' in fpath and not ('grpc++' in fpath or
-                                                    'grpcpp' in fpath)
+        c_core_header = self._is_c_core_header(fpath)
         self.failed = True
         invalid_guards_msg_template = (
             '{0}: Missing preprocessor guards (RE {1}). '
@@ -81,8 +84,7 @@ class GuardValidator(object):
         return fcontents
 
     def check(self, fpath, fix):
-        c_core_header = 'include' in fpath and not ('grpc++' in fpath or
-                                                    'grpcpp' in fpath)
+        c_core_header = self._is_c_core_header(fpath)
         valid_guard = build_valid_guard(fpath)
 
         fcontents = load(fpath)
@@ -149,8 +151,8 @@ class GuardValidator(object):
                     flines[-1], '', '', False)
         elif match.group(1) != running_guard:
             # Is the #endif guard the same as the #ifndef and #define guards?
-            fcontents = self.fail(fpath, endif_re, fcontents, match.group(1),
-                                  valid_guard, fix)
+            fcontents = self.fail(fpath, self.endif_re, fcontents,
+                                  match.group(1), valid_guard, fix)
             if fix:
                 save(fpath, fcontents)
 
index 8ff3b08..266a230 100644 (file)
@@ -1 +1,9 @@
 distrib_virtualenv/
+__init__.py
+generated_file_import_test.py
+envoy/
+udpa/
+validate/
+google/
+opencensus/
+xds/
index 864971f..c685a1e 100644 (file)
@@ -134,6 +134,16 @@ def main():
                     name_long='gRPC Health Checking',
                     destination_package='grpcio-health-checking'))
 
+    generate_package(
+        PackageMeta(name='grpc-csds',
+                    name_long='gRPC Client Status Discovery Service',
+                    destination_package='grpcio-csds'))
+
+    generate_package(
+        PackageMeta(name='grpc-admin',
+                    name_long='gRPC Admin Interface',
+                    destination_package='grpcio-admin'))
+
 
 if __name__ == "__main__":
     logging.basicConfig(level=logging.INFO)
index b351be4..8a17e74 100644 (file)
@@ -14,5 +14,5 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION = '1.37.1'
-PROTOBUF_VERSION = '3.15.2'
+VERSION = '1.38.0'
+PROTOBUF_VERSION = '3.15.8'
index 48f853a..0982451 100644 (file)
@@ -42,6 +42,7 @@ def main(command_arguments):
 if sys.version_info >= (3, 5, 0):
     import contextlib
     import importlib
+    import importlib.abc
     import importlib.machinery
     import threading
 
index d608a5b..0b3c4c8 100644 (file)
@@ -14,5 +14,5 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION = '1.37.1'
-PROTOBUF_VERSION = '3.15.2'
+VERSION = '1.38.0'
+PROTOBUF_VERSION = '3.15.8'
index abdd9a7..66b5270 100644 (file)
@@ -20,4 +20,4 @@ PROTO_FILES=['google/protobuf/wrappers.proto', 'google/protobuf/type.proto', 'go
 CC_INCLUDE='third_party/protobuf/src'
 PROTO_INCLUDE='third_party/protobuf/src'
 
-PROTOBUF_SUBMODULE_VERSION="d7e943b8d2bc444a8c770644e73d090b486f8b37"
+PROTOBUF_SUBMODULE_VERSION="436bd7880e458532901c58f4d9d1ea23fa7edd52"
diff --git a/tools/distrib/python/xds_protos/README.rst b/tools/distrib/python/xds_protos/README.rst
new file mode 100644 (file)
index 0000000..698144e
--- /dev/null
@@ -0,0 +1,10 @@
+Package "xds-protos" is a collection of ProtoBuf generated Python files for xDS protos (or the `data-plane-api <https://github.com/envoyproxy/data-plane-api>`_). You can find the source code of this project in `grpc/grpc <https://github.com/grpc/grpc>`_. For any question or suggestion, please post to https://github.com/grpc/grpc/issues.
+
+Each generated Python file can be imported according to their proto package. For example, if we are trying to import a proto located at "envoy/service/status/v3/csds.proto", whose proto package is "package envoy.service.status.v3", then we can import it as:
+
+::
+
+  # Import the message definitions
+  from envoy.service.status.v3 import csds_pb2
+  # Import the gRPC service and stub
+  from envoy.service.status.v3 import csds_pb2_grpc
diff --git a/tools/distrib/python/xds_protos/build.py b/tools/distrib/python/xds_protos/build.py
new file mode 100644 (file)
index 0000000..8b793f2
--- /dev/null
@@ -0,0 +1,139 @@
+#! /usr/bin/env python3
+# Copyright 2021 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.
+"""Builds the content of xds-protos package"""
+
+import os
+import pkg_resources
+from grpc_tools import protoc
+
+# We might not want to compile all the protos
+EXCLUDE_PROTO_PACKAGES_LIST = [
+    # Requires extra dependency to Prometheus protos
+    'envoy/service/metrics/v2',
+    'envoy/service/metrics/v3',
+    'envoy/service/metrics/v4alpha',
+]
+
+# Compute the pathes
+WORK_DIR = os.path.dirname(os.path.abspath(__file__))
+GRPC_ROOT = os.path.abspath(os.path.join(WORK_DIR, '..', '..', '..', '..'))
+XDS_PROTO_ROOT = os.path.join(GRPC_ROOT, 'third_party', 'envoy-api')
+UDPA_PROTO_ROOT = os.path.join(GRPC_ROOT, 'third_party', 'udpa')
+GOOGLEAPIS_ROOT = os.path.join(GRPC_ROOT, 'third_party', 'googleapis')
+VALIDATE_ROOT = os.path.join(GRPC_ROOT, 'third_party', 'protoc-gen-validate')
+OPENCENSUS_PROTO_ROOT = os.path.join(GRPC_ROOT, 'third_party',
+                                     'opencensus-proto', 'src')
+WELL_KNOWN_PROTOS_INCLUDE = pkg_resources.resource_filename(
+    'grpc_tools', '_proto')
+OUTPUT_PATH = WORK_DIR
+
+# Prepare the test file generation
+TEST_FILE_NAME = 'generated_file_import_test.py'
+TEST_IMPORTS = []
+
+# The pkgutil-style namespace packaging __init__.py
+PKGUTIL_STYLE_INIT = "__path__ = __import__('pkgutil').extend_path(__path__, __name__)\n"
+NAMESPACE_PACKAGES = ["google"]
+
+
+def add_test_import(proto_package_path: str,
+                    file_name: str,
+                    service: bool = False):
+    TEST_IMPORTS.append("from %s import %s\n" % (proto_package_path.replace(
+        '/', '.'), file_name.replace('.proto', '_pb2')))
+    if service:
+        TEST_IMPORTS.append("from %s import %s\n" % (proto_package_path.replace(
+            '/', '.'), file_name.replace('.proto', '_pb2_grpc')))
+
+
+# Prepare Protoc command
+COMPILE_PROTO_ONLY = [
+    'grpc_tools.protoc',
+    '--proto_path={}'.format(XDS_PROTO_ROOT),
+    '--proto_path={}'.format(UDPA_PROTO_ROOT),
+    '--proto_path={}'.format(GOOGLEAPIS_ROOT),
+    '--proto_path={}'.format(VALIDATE_ROOT),
+    '--proto_path={}'.format(WELL_KNOWN_PROTOS_INCLUDE),
+    '--proto_path={}'.format(OPENCENSUS_PROTO_ROOT),
+    '--python_out={}'.format(OUTPUT_PATH),
+]
+COMPILE_BOTH = COMPILE_PROTO_ONLY + ['--grpc_python_out={}'.format(OUTPUT_PATH)]
+
+
+def has_grpc_service(proto_package_path: str) -> bool:
+    return proto_package_path.startswith('envoy/service')
+
+
+def compile_protos(proto_root: str, sub_dir: str = '.') -> None:
+    for root, _, files in os.walk(os.path.join(proto_root, sub_dir)):
+        proto_package_path = os.path.relpath(root, proto_root)
+        if proto_package_path in EXCLUDE_PROTO_PACKAGES_LIST:
+            print(f'Skipping package {proto_package_path}')
+            continue
+        for file_name in files:
+            if file_name.endswith('.proto'):
+                # Compile proto
+                if has_grpc_service(proto_package_path):
+                    return_code = protoc.main(COMPILE_BOTH +
+                                              [os.path.join(root, file_name)])
+                    add_test_import(proto_package_path, file_name, service=True)
+                else:
+                    return_code = protoc.main(COMPILE_PROTO_ONLY +
+                                              [os.path.join(root, file_name)])
+                    add_test_import(proto_package_path,
+                                    file_name,
+                                    service=False)
+                if return_code != 0:
+                    raise Exception('error: {} failed'.format(COMPILE_BOTH))
+
+
+def create_init_file(path: str, package_path: str = "") -> None:
+    with open(os.path.join(path, "__init__.py"), 'w') as f:
+        # Apply the pkgutil-style namespace packaging, which is compatible for 2
+        # and 3. Here is the full table of namespace compatibility:
+        # https://github.com/pypa/sample-namespace-packages/blob/master/table.md
+        if package_path in NAMESPACE_PACKAGES:
+            f.write(PKGUTIL_STYLE_INIT)
+
+
+def main():
+    # Compile xDS protos
+    compile_protos(XDS_PROTO_ROOT)
+    compile_protos(UDPA_PROTO_ROOT)
+    # We don't want to compile the entire GCP surface API, just the essential ones
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'api'))
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'rpc'))
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'longrunning'))
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'logging'))
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'type'))
+    compile_protos(VALIDATE_ROOT, 'validate')
+    compile_protos(OPENCENSUS_PROTO_ROOT)
+
+    # Generate __init__.py files for all modules
+    create_init_file(WORK_DIR)
+    for proto_root_module in [
+            'envoy', 'google', 'opencensus', 'udpa', 'validate', 'xds'
+    ]:
+        for root, _, _ in os.walk(os.path.join(WORK_DIR, proto_root_module)):
+            package_path = os.path.relpath(root, WORK_DIR)
+            create_init_file(root, package_path)
+
+    # Generate test file
+    with open(os.path.join(WORK_DIR, TEST_FILE_NAME), 'w') as f:
+        f.writelines(TEST_IMPORTS)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/tools/distrib/python/xds_protos/build_validate_upload.sh b/tools/distrib/python/xds_protos/build_validate_upload.sh
new file mode 100755 (executable)
index 0000000..4218940
--- /dev/null
@@ -0,0 +1,47 @@
+#! /bin/bash
+# Copyright 2021 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.
+
+set -ex
+
+WORK_DIR=$(pwd)/"$(dirname "$0")"
+cd ${WORK_DIR}
+
+# Remove existing wheels
+rm -rf ${WORK_DIR}/dist
+
+# Generate the package content then build the source wheel
+python3 build.py
+python3 setup.py sdist
+python2 setup.py bdist_wheel
+python3 setup.py bdist_wheel
+
+# Run the tests to ensure all protos are importable, also avoid confusing normal
+# imports with relative imports
+pushd $(mktemp -d '/tmp/test_xds_protos.XXXXXX')
+python2 -m virtualenv env
+env/bin/python -m pip install ${WORK_DIR}/dist/xds-protos-*.tar.gz
+cp ${WORK_DIR}/generated_file_import_test.py generated_file_import_test.py
+env/bin/python generated_file_import_test.py
+popd
+pushd $(mktemp -d '/tmp/test_xds_protos.XXXXXX')
+python3 -m virtualenv env
+env/bin/python -m pip install ${WORK_DIR}/dist/xds-protos-*.tar.gz
+cp ${WORK_DIR}/generated_file_import_test.py generated_file_import_test.py
+env/bin/python generated_file_import_test.py
+popd
+
+# Upload the package
+python3 -m twine check dist/*
+python3 -m twine upload dist/*
diff --git a/tools/distrib/python/xds_protos/setup.py b/tools/distrib/python/xds_protos/setup.py
new file mode 100644 (file)
index 0000000..2ed04c4
--- /dev/null
@@ -0,0 +1,52 @@
+#! /usr/bin/env python3
+# Copyright 2021 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.
+"""A PyPI package for xDS protos generated Python code."""
+
+import os
+import setuptools
+
+WORK_DIR = os.path.dirname(os.path.abspath(__file__))
+EXCLUDE_PYTHON_FILES = ['generated_file_import_test.py', 'build.py']
+
+# Use setuptools to build Python package
+with open(os.path.join(WORK_DIR, 'README.rst'), 'r') as f:
+    LONG_DESCRIPTION = f.read()
+PACKAGES = setuptools.find_packages(where=".", exclude=EXCLUDE_PYTHON_FILES)
+CLASSIFIERS = [
+    'Development Status :: 3 - Alpha',
+    'Programming Language :: Python',
+    'Programming Language :: Python :: 2',
+    'Programming Language :: Python :: 3',
+    'License :: OSI Approved :: Apache Software License',
+]
+INSTALL_REQUIRES = [
+    'grpcio',
+    'protobuf',
+]
+SETUP_REQUIRES = INSTALL_REQUIRES + ['grpcio-tools']
+setuptools.setup(
+    name='xds-protos',
+    version='0.0.8',
+    packages=PACKAGES,
+    description='Generated Python code from envoyproxy/data-plane-api',
+    long_description_content_type='text/x-rst',
+    long_description=LONG_DESCRIPTION,
+    author='The gRPC Authors',
+    author_email='grpc-io@googlegroups.com',
+    url='https://grpc.io',
+    license='Apache License 2.0',
+    install_requires=INSTALL_REQUIRES,
+    setup_requires=SETUP_REQUIRES,
+    classifiers=CLASSIFIERS)
diff --git a/tools/dockerfile/distribtest/python_python38_buster_aarch64/Dockerfile b/tools/dockerfile/distribtest/python_python38_buster_aarch64/Dockerfile
new file mode 100644 (file)
index 0000000..8b14a43
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright 2021 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.
+
+# this an aarch64 image, qemu emulator will be used to run the tests
+FROM arm64v8/python:3.8-buster
+
+RUN pip install virtualenv
index f1a5c79..d00c7b4 100644 (file)
@@ -16,4 +16,10 @@ FROM ubuntu:16.04
 
 RUN apt-get update -y && apt-get install -y python python-pip
 
-RUN pip install virtualenv
+# Necessary to fix virtualenv compatibility problems with python2.7
+RUN pip install --upgrade pip==19.3.1
+
+# Ubuntu's python-pip package installs pip to /usr/bin, whereas the upgraded
+# pip lives at /usr/local/bin/pip. We'll use the absolute path for now, since
+# this will all be replaced with python3.
+RUN /usr/local/bin/pip install virtualenv
index dfde245..3863cde 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015 gRPC authors.
+# Copyright 2021 The gRPC Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM golang:1.11
+FROM golang:1.16
 
 # Using login shell removes Go from path, so we add it.
 RUN ln -s /usr/local/go/bin/go /usr/local/bin
diff --git a/tools/dockerfile/interoptest/grpc_interop_go1.16/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go1.16/Dockerfile
new file mode 100644 (file)
index 0000000..3863cde
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright 2021 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 golang:1.16
+
+# Using login shell removes Go from path, so we add it.
+RUN ln -s /usr/local/go/bin/go /usr/local/bin
+
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-setuptools
+
+# Install Python packages from PyPI
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
+RUN pip install --upgrade pip==19.3.1
+RUN pip install virtualenv==16.7.9
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh
new file mode 100644 (file)
index 0000000..309340c
--- /dev/null
@@ -0,0 +1,33 @@
+#!/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 Go interop server and client in a base image.
+set -e
+
+# Turn on support for Go modules.
+export GO111MODULE=on
+
+# Clone just the grpc-go source code without any dependencies.
+# We are cloning from a local git repo that contains the right revision
+# to test instead of using "go get" to download from Github directly.
+git clone --recursive /var/local/jenkins/grpc-go src/google.golang.org/grpc
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+# Build the interop client and server
+(cd src/google.golang.org/grpc/interop/client && go install)
+(cd src/google.golang.org/grpc/interop/server && go install)
+  
index e9b93f8..2ce385e 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.37.1
+PROJECT_NUMBER         = 1.38.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
@@ -881,6 +881,10 @@ include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/event_engine/channel_args.h \
+include/grpc/event_engine/event_engine.h \
+include/grpc/event_engine/port.h \
+include/grpc/event_engine/slice_allocator.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
index c1e4ae1..0e0fdbd 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.37.1
+PROJECT_NUMBER         = 1.38.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
@@ -881,6 +881,10 @@ include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/event_engine/channel_args.h \
+include/grpc/event_engine/event_engine.h \
+include/grpc/event_engine/port.h \
+include/grpc/event_engine/slice_allocator.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
@@ -1131,6 +1135,10 @@ src/core/ext/filters/client_channel/resolver_registry.cc \
 src/core/ext/filters/client_channel/resolver_registry.h \
 src/core/ext/filters/client_channel/resolver_result_parsing.cc \
 src/core/ext/filters/client_channel/resolver_result_parsing.h \
+src/core/ext/filters/client_channel/retry_filter.cc \
+src/core/ext/filters/client_channel/retry_filter.h \
+src/core/ext/filters/client_channel/retry_service_config.cc \
+src/core/ext/filters/client_channel/retry_service_config.h \
 src/core/ext/filters/client_channel/retry_throttle.cc \
 src/core/ext/filters/client_channel/retry_throttle.h \
 src/core/ext/filters/client_channel/server_address.cc \
@@ -1630,6 +1638,10 @@ src/core/ext/xds/xds_http_fault_filter.h \
 src/core/ext/xds/xds_http_filters.cc \
 src/core/ext/xds/xds_http_filters.h \
 src/core/ext/xds/xds_server_config_fetcher.cc \
+src/core/lib/address_utils/parse_address.cc \
+src/core/lib/address_utils/parse_address.h \
+src/core/lib/address_utils/sockaddr_utils.cc \
+src/core/lib/address_utils/sockaddr_utils.h \
 src/core/lib/avl/avl.cc \
 src/core/lib/avl/avl.h \
 src/core/lib/backoff/backoff.cc \
@@ -1676,6 +1688,8 @@ src/core/lib/debug/stats_data.cc \
 src/core/lib/debug/stats_data.h \
 src/core/lib/debug/trace.cc \
 src/core/lib/debug/trace.h \
+src/core/lib/event_engine/slice_allocator.cc \
+src/core/lib/event_engine/sockaddr.cc \
 src/core/lib/gpr/alloc.cc \
 src/core/lib/gpr/alloc.h \
 src/core/lib/gpr/arena.h \
@@ -1749,6 +1763,8 @@ src/core/lib/gprpp/ref_counted_ptr.h \
 src/core/lib/gprpp/stat.h \
 src/core/lib/gprpp/stat_posix.cc \
 src/core/lib/gprpp/stat_windows.cc \
+src/core/lib/gprpp/status_helper.cc \
+src/core/lib/gprpp/status_helper.h \
 src/core/lib/gprpp/sync.h \
 src/core/lib/gprpp/thd.h \
 src/core/lib/gprpp/thd_posix.cc \
@@ -1836,10 +1852,6 @@ src/core/lib/iomgr/load_file.h \
 src/core/lib/iomgr/lockfree_event.cc \
 src/core/lib/iomgr/lockfree_event.h \
 src/core/lib/iomgr/nameser.h \
-src/core/lib/iomgr/parse_address.cc \
-src/core/lib/iomgr/parse_address.h \
-src/core/lib/iomgr/poller/eventmanager_libuv.cc \
-src/core/lib/iomgr/poller/eventmanager_libuv.h \
 src/core/lib/iomgr/polling_entity.cc \
 src/core/lib/iomgr/polling_entity.h \
 src/core/lib/iomgr/pollset.cc \
@@ -1869,8 +1881,6 @@ src/core/lib/iomgr/resource_quota.h \
 src/core/lib/iomgr/sockaddr.h \
 src/core/lib/iomgr/sockaddr_custom.h \
 src/core/lib/iomgr/sockaddr_posix.h \
-src/core/lib/iomgr/sockaddr_utils.cc \
-src/core/lib/iomgr/sockaddr_utils.h \
 src/core/lib/iomgr/sockaddr_windows.h \
 src/core/lib/iomgr/socket_factory_posix.cc \
 src/core/lib/iomgr/socket_factory_posix.h \
index bc67610..1db9688 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Core"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 15.0.0
+PROJECT_NUMBER         = 16.0.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
@@ -811,6 +811,10 @@ include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/event_engine/channel_args.h \
+include/grpc/event_engine/event_engine.h \
+include/grpc/event_engine/port.h \
+include/grpc/event_engine/slice_allocator.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
index d912a73..ebf1a4d 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Core"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 15.0.0
+PROJECT_NUMBER         = 16.0.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
@@ -811,6 +811,10 @@ include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/event_engine/channel_args.h \
+include/grpc/event_engine/event_engine.h \
+include/grpc/event_engine/port.h \
+include/grpc/event_engine/slice_allocator.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
@@ -959,6 +963,10 @@ src/core/ext/filters/client_channel/resolver_registry.cc \
 src/core/ext/filters/client_channel/resolver_registry.h \
 src/core/ext/filters/client_channel/resolver_result_parsing.cc \
 src/core/ext/filters/client_channel/resolver_result_parsing.h \
+src/core/ext/filters/client_channel/retry_filter.cc \
+src/core/ext/filters/client_channel/retry_filter.h \
+src/core/ext/filters/client_channel/retry_service_config.cc \
+src/core/ext/filters/client_channel/retry_service_config.h \
 src/core/ext/filters/client_channel/retry_throttle.cc \
 src/core/ext/filters/client_channel/retry_throttle.h \
 src/core/ext/filters/client_channel/server_address.cc \
@@ -1466,6 +1474,10 @@ src/core/ext/xds/xds_http_filters.cc \
 src/core/ext/xds/xds_http_filters.h \
 src/core/ext/xds/xds_server_config_fetcher.cc \
 src/core/lib/README.md \
+src/core/lib/address_utils/parse_address.cc \
+src/core/lib/address_utils/parse_address.h \
+src/core/lib/address_utils/sockaddr_utils.cc \
+src/core/lib/address_utils/sockaddr_utils.h \
 src/core/lib/avl/avl.cc \
 src/core/lib/avl/avl.h \
 src/core/lib/backoff/backoff.cc \
@@ -1513,6 +1525,8 @@ src/core/lib/debug/stats_data.cc \
 src/core/lib/debug/stats_data.h \
 src/core/lib/debug/trace.cc \
 src/core/lib/debug/trace.h \
+src/core/lib/event_engine/slice_allocator.cc \
+src/core/lib/event_engine/sockaddr.cc \
 src/core/lib/gpr/README.md \
 src/core/lib/gpr/alloc.cc \
 src/core/lib/gpr/alloc.h \
@@ -1588,6 +1602,8 @@ src/core/lib/gprpp/ref_counted_ptr.h \
 src/core/lib/gprpp/stat.h \
 src/core/lib/gprpp/stat_posix.cc \
 src/core/lib/gprpp/stat_windows.cc \
+src/core/lib/gprpp/status_helper.cc \
+src/core/lib/gprpp/status_helper.h \
 src/core/lib/gprpp/sync.h \
 src/core/lib/gprpp/thd.h \
 src/core/lib/gprpp/thd_posix.cc \
@@ -1676,10 +1692,6 @@ src/core/lib/iomgr/load_file.h \
 src/core/lib/iomgr/lockfree_event.cc \
 src/core/lib/iomgr/lockfree_event.h \
 src/core/lib/iomgr/nameser.h \
-src/core/lib/iomgr/parse_address.cc \
-src/core/lib/iomgr/parse_address.h \
-src/core/lib/iomgr/poller/eventmanager_libuv.cc \
-src/core/lib/iomgr/poller/eventmanager_libuv.h \
 src/core/lib/iomgr/polling_entity.cc \
 src/core/lib/iomgr/polling_entity.h \
 src/core/lib/iomgr/pollset.cc \
@@ -1709,8 +1721,6 @@ src/core/lib/iomgr/resource_quota.h \
 src/core/lib/iomgr/sockaddr.h \
 src/core/lib/iomgr/sockaddr_custom.h \
 src/core/lib/iomgr/sockaddr_posix.h \
-src/core/lib/iomgr/sockaddr_utils.cc \
-src/core/lib/iomgr/sockaddr_utils.h \
 src/core/lib/iomgr/sockaddr_windows.h \
 src/core/lib/iomgr/socket_factory_posix.cc \
 src/core/lib/iomgr/socket_factory_posix.h \
index d936870..d137440 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Objective-C"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.37.1
+PROJECT_NUMBER         = 1.38.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
index a9ece75..6e72d91 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Objective-C"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.37.1
+PROJECT_NUMBER         = 1.38.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
index 238762d..09797ba 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC PHP"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.37.1
+PROJECT_NUMBER         = 1.38.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
diff --git a/tools/internal_ci/helper_scripts/prepare_qemu_rc b/tools/internal_ci/helper_scripts/prepare_qemu_rc
new file mode 100644 (file)
index 0000000..55bffcc
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2021 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.
+
+# Source this rc script to setup and configure qemu userspace emulator on kokoro worker so that we can seamlessly emulate processes running
+# inside docker containers.
+
+# show pre-existing qemu registration
+cat /proc/sys/fs/binfmt_misc/qemu-aarch64
+
+# Kokoro ubuntu1604 workers have already qemu-user and qemu-user-static packages installed, but it's and old version that:
+# * prints warning about some syscalls (e.g "qemu: Unsupported syscall: 278")
+# * doesn't register with binfmt_misc with the persistent ("F") flag we need (see below)
+#
+# To overcome the above limitations, we use the https://github.com/multiarch/qemu-user-static
+# docker image to provide a new enough version of qemu-user-static and register it with
+# the desired binfmt_misc flags. The most important flag we need is "F" (set by "--persistent yes"),
+# which allows the qemu-aarch64-static binary to be loaded eagerly at the time of registration with binfmt_misc.
+# That way, we can emulate aarch64 binaries running inside docker containers transparently, without needing the emulator
+# binary to be accessible from the docker image we're emulating.
+# Note that on newer distributions (such as glinux), simply "apt install qemu-user-static" is sufficient
+# to install qemu-user-static with the right flags.
+docker run --rm --privileged multiarch/qemu-user-static:5.2.0-2 --reset --credential yes --persistent yes
+
+# Print current qemu reqistration to make sure everything is setup correctly.
+cat /proc/sys/fs/binfmt_misc/qemu-aarch64
index ea96edc..58aa5e7 100755 (executable)
@@ -55,4 +55,4 @@ fi
 # commit so that changes are passed to Docker
 git -c user.name='foo' -c user.email='foo@google.com' commit -a -m 'Update submodule' --allow-empty
 
-tools/run_tests/run_tests_matrix.py -f linux --inner_jobs 4 -j 4 --internal_ci --build_only
+tools/run_tests/run_tests_matrix.py -f linux --inner_jobs 8 -j 4 --internal_ci --build_only
index 47e4bf8..b2ec2bf 100644 (file)
@@ -20,6 +20,11 @@ cd $(dirname $0)/../../..
 
 source tools/internal_ci/helper_scripts/prepare_build_linux_rc
 
+# some distribtests use a pre-registered binfmt_misc hook
+# to automatically execute foreign binaries (such as aarch64)
+# under qemu emulator.
+source tools/internal_ci/helper_scripts/prepare_qemu_rc
+
 set +ex
 [[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
 set -e  # rvm commands are very verbose
diff --git a/tools/internal_ci/linux/grpc_distribtests_python.cfg b/tools/internal_ci/linux/grpc_distribtests_python.cfg
new file mode 100644 (file)
index 0000000..307b3b6
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_distribtests_python.sh"
+timeout_mins: 240
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.*"
+    regex: "github/grpc/reports/**"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/internal_ci/linux/grpc_distribtests_python.sh b/tools/internal_ci/linux/grpc_distribtests_python.sh
new file mode 100755 (executable)
index 0000000..aef9181
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/bash
+# Copyright 2021 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.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# some distribtests use a pre-registered binfmt_misc hook
+# to automatically execute foreign binaries (such as aarch64)
+# under qemu emulator.
+source tools/internal_ci/helper_scripts/prepare_qemu_rc
+
+# Build all python linux artifacts (this step actually builds all the binary wheels and source archives)
+tools/run_tests/task_runner.py -f artifact linux python -j 6 -x build_artifacts/sponge_log.xml || FAILED="true"
+
+# the next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/* input_artifacts/ || true
+rm -rf artifacts_from_build_artifacts_step
+mv artifacts artifacts_from_build_artifacts_step || true
+
+# This step mostly just copies artifacts from input_artifacts (but it also does some wheel stripping)
+tools/run_tests/task_runner.py -f package linux python -x build_packages/sponge_log.xml || FAILED="true"
+
+# the next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+# in addition to that, preserve the contents of "artifacts" directory since we want kokoro
+# to upload its contents as job output artifacts
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/* input_artifacts/ || true
+
+# Run all python linux distribtests
+# We run the distribtests even if some of the artifacts have failed to build, since that gives
+# a better signal about which distribtest are affected by the currently broken artifact builds.
+tools/run_tests/task_runner.py -f distribtest linux python -j 6 -x distribtests/sponge_log.xml || FAILED="true"
+
+if [ "$FAILED" != "" ]
+then
+  exit 1
+fi
index c743e5b..63d2650 100755 (executable)
@@ -19,5 +19,37 @@ cd $(dirname $0)/../../..
 
 source tools/internal_ci/helper_scripts/prepare_build_linux_rc
 
-echo "TODO: Add gRPC OSS Benchmarks here..."
+# This is to ensure we can push and pull images from gcr.io. We do not
+# necessarily need it to run load tests, but will need it when we employ
+# pre-built images in the optimization.
+gcloud auth configure-docker
 
+# Connect to benchmarks-prod cluster.
+gcloud config set project grpc-testing
+gcloud container clusters get-credentials benchmarks-prod \
+    --zone us-central1-b --project grpc-testing
+
+# This is subject to change. Runs a single test and does not wait for the
+# result.
+tools/run_tests/performance/loadtest_config.py -l c++ -l go \
+    -t ./tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml \
+    -s client_pool=workers-8core -s server_pool=workers-8core \
+    -s big_query_table=e2e_benchmarks.experimental_results \
+    -s timeout_seconds=900 --prefix="kokoro-test" -u "$(date +%Y%m%d%H%M%S)" \
+    -r '(go_generic_sync_streaming_ping_pong_secure|go_protobuf_sync_unary_ping_pong_secure|cpp_protobuf_async_streaming_qps_unconstrained_secure)$' \
+    -o ./loadtest.yaml
+
+# Dump the contents of the loadtest.yaml (since loadtest_config.py doesn't
+# list the scenarios that will be run).
+cat ./loadtest.yaml
+
+# The original version of the client is a bit old, update to the latest release
+# version v1.21.0.
+kubectl version --client
+curl -sSL -O https://dl.k8s.io/release/v1.21.0/bin/linux/amd64/kubectl
+sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
+chmod +x kubectl
+sudo mv kubectl $(which kubectl)
+kubectl version --client
+
+kubectl apply -f ./loadtest.yaml
index fab9dde..c4fa6c6 100644 (file)
@@ -26,5 +26,5 @@ action {
 
 env_vars {
   key: "RUN_TESTS_FLAGS"
-  value: "-f portability linux --inner_jobs 4 -j 4 --internal_ci --build_only"
+  value: "-f portability linux --inner_jobs 8 -j 4 --internal_ci --build_only"
 }
index f2af857..2a7cbdd 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds.sh"
-timeout_mins: 180
+timeout_mins: 360
 env_vars {
   key: "BAZEL_SCRIPT"
   value: "tools/internal_ci/linux/grpc_xds_bazel_test_in_docker.sh"
index a38837d..0208f9b 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_csharp.sh"
-timeout_mins: 180
+timeout_mins: 360
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
index 8de4c18..c59a357 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_k8s.sh"
-timeout_mins: 180
+timeout_mins: 120
 action {
   define_artifacts {
     regex: "artifacts/**/*sponge_log.xml"
index b14c66f..a8cbf5d 100755 (executable)
@@ -18,15 +18,13 @@ set -ex -o igncr || set -ex
 # Constants
 readonly GITHUB_REPOSITORY_NAME="grpc"
 # GKE Cluster
-readonly GKE_CLUSTER_NAME="interop-test-psm-sec-testing-api"
-readonly GKE_CLUSTER_ZONE="us-west1-b"
-export CLOUDSDK_API_ENDPOINT_OVERRIDES_CONTAINER="https://test-container.sandbox.googleapis.com/"
+readonly GKE_CLUSTER_NAME="interop-test-psm-sec-v2-us-central1-a"
+readonly GKE_CLUSTER_ZONE="us-central1-a"
 ## xDS test server/client Docker images
 readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-server"
 readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-client"
 readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}"
 readonly BUILD_APP_PATH="interop-testing/build/install/grpc-interop-testing"
-readonly TEST_DRIVER_REPO_DIR_USE_EXISTING=1
 
 #######################################
 # Builds test app Docker images and pushes them to GCR
index 34979b0..d7f50fb 100644 (file)
@@ -308,7 +308,8 @@ kokoro_setup_test_driver() {
   # Kokoro clones repo to ${KOKORO_ARTIFACTS_DIR}/github/${GITHUB_REPOSITORY}
   local github_root="${KOKORO_ARTIFACTS_DIR}/github"
   readonly SRC_DIR="${github_root}/${src_repository_name}"
-  local test_driver_repo_dir="${github_root}/${TEST_DRIVER_REPO_NAME}"
+  local test_driver_repo_dir
+  test_driver_repo_dir="${TEST_DRIVER_REPO_DIR:-$(mktemp -d)/${TEST_DRIVER_REPO_NAME}}"
   parse_src_repo_git_info SRC_DIR
   kokoro_write_sponge_properties
   kokoro_setup_python_virtual_environment
diff --git a/tools/internal_ci/linux/grpc_xds_k8s_python.cfg b/tools/internal_ci/linux/grpc_xds_k8s_python.cfg
new file mode 100644 (file)
index 0000000..82826f1
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_xds_k8s_python.sh"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "artifacts/**/*sponge_log.xml"
+    regex: "artifacts/**/*sponge_log.log"
+    strip_prefix: "artifacts"
+  }
+}
diff --git a/tools/internal_ci/linux/grpc_xds_k8s_python.sh b/tools/internal_ci/linux/grpc_xds_k8s_python.sh
new file mode 100755 (executable)
index 0000000..b6bbfc2
--- /dev/null
@@ -0,0 +1,163 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+set -ex -o igncr || set -ex
+
+# Constants
+readonly GITHUB_REPOSITORY_NAME="grpc"
+# GKE Cluster
+readonly GKE_CLUSTER_NAME="interop-test-psm-sec-v2-us-central1-a"
+readonly GKE_CLUSTER_ZONE="us-central1-a"
+## xDS test server/client Docker images
+readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-server"
+readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-client"
+readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}"
+readonly BUILD_APP_PATH="interop-testing/build/install/grpc-interop-testing"
+readonly LANGUAGE_NAME="Python"
+
+#######################################
+# Builds test app Docker images and pushes them to GCR
+# Globals:
+#   BUILD_APP_PATH
+#   SERVER_IMAGE_NAME: Test server Docker image name
+#   CLIENT_IMAGE_NAME: Test client Docker image name
+#   GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of `gcloud builds submit` to stdout, stderr
+#######################################
+build_test_app_docker_images() {
+  echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images"
+
+  pushd "${SRC_DIR}"
+  docker build \
+    -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client \
+    -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+    .
+
+  docker build \
+    -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.server \
+    -t "${SERVER_IMAGE_NAME}:${GIT_COMMIT}" \
+    .
+
+  popd
+
+  gcloud -q auth configure-docker
+
+  docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}"
+  docker push "${SERVER_IMAGE_NAME}:${GIT_COMMIT}"
+}
+
+#######################################
+# Builds test app and its docker images unless they already exist
+# Globals:
+#   SERVER_IMAGE_NAME: Test server Docker image name
+#   CLIENT_IMAGE_NAME: Test client Docker image name
+#   GIT_COMMIT: SHA-1 of git commit being built
+#   FORCE_IMAGE_BUILD
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output to stdout, stderr
+#######################################
+build_docker_images_if_needed() {
+  # Check if images already exist
+  server_tags="$(gcloud_gcr_list_image_tags "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}")"
+  printf "Server image: %s:%s\n" "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}"
+  echo "${server_tags:-Server image not found}"
+
+  client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")"
+  printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}"
+  echo "${client_tags:-Client image not found}"
+
+  # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1
+  if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${server_tags}" || -z "${client_tags}" ]]; then
+    build_test_app_docker_images
+  else
+    echo "Skipping ${LANGUAGE_NAME} test app build"
+  fi
+}
+
+#######################################
+# Executes the test case
+# Globals:
+#   TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile
+#   KUBE_CONTEXT: The name of kubectl context with GKE cluster access
+#   TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report
+#   SERVER_IMAGE_NAME: Test server Docker image name
+#   CLIENT_IMAGE_NAME: Test client Docker image name
+#   GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+#   Test case name
+# Outputs:
+#   Writes the output of test execution to stdout, stderr
+#   Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml
+#######################################
+run_test() {
+  # Test driver usage:
+  # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage
+  local test_name="${1:?Usage: run_test test_name}"
+  set -x
+  python -m "tests.${test_name}" \
+    --flagfile="${TEST_DRIVER_FLAGFILE}" \
+    --kube_context="${KUBE_CONTEXT}" \
+    --server_image="${SERVER_IMAGE_NAME}:${GIT_COMMIT}" \
+    --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+    --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \
+    --force_cleanup \
+    --nocheck_local_certs
+  set +x
+}
+
+#######################################
+# Main function: provision software necessary to execute tests, and run them
+# Globals:
+#   KOKORO_ARTIFACTS_DIR
+#   GITHUB_REPOSITORY_NAME
+#   SRC_DIR: Populated with absolute path to the source repo
+#   TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+#                         the test driver
+#   TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+#   TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+#   TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+#   GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+#   GIT_COMMIT: Populated with the SHA-1 of git commit being built
+#   GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+#   KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of test execution to stdout, stderr
+#######################################
+main() {
+  local script_dir
+  script_dir="$(dirname "$0")"
+  # shellcheck source=tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh
+  source "${script_dir}/grpc_xds_k8s_install_test_driver.sh"
+  set -x
+  if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then
+    kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}"
+  else
+    local_setup_test_driver "${script_dir}"
+  fi
+  build_docker_images_if_needed
+  # Run tests
+  cd "${TEST_DRIVER_FULL_DIR}"
+  run_test baseline_test
+  run_test security_test
+}
+
+main "$@"
index f7a12b4..af8d24c 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_php.sh"
-timeout_mins: 180
+timeout_mins: 360
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
index f52a220..88a7ae5 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds.sh"
-timeout_mins: 180
+timeout_mins: 360
 env_vars {
   key: "BAZEL_SCRIPT"
   value: "tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh"
index 87401ba..d723f85 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_ruby.sh"
-timeout_mins: 180
+timeout_mins: 360
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
index 4e0f5ab..56aaa3a 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds.sh"
-timeout_mins: 180
+timeout_mins: 360
 env_vars {
   key: "BAZEL_SCRIPT"
   value: "tools/internal_ci/linux/grpc_xds_v3_bazel_test_in_docker.sh"
index 8ad65d6..5ca9153 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_v3_csharp.sh"
-timeout_mins: 180
+timeout_mins: 360
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
index 8b19570..39f6406 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_v3_php.sh"
-timeout_mins: 180
+timeout_mins: 360
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
index 87e843d..fc9078a 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds.sh"
-timeout_mins: 180
+timeout_mins: 360
 env_vars {
   key: "BAZEL_SCRIPT"
   value: "tools/internal_ci/linux/grpc_xds_v3_bazel_python_test_in_docker.sh"
index 2ab6f16..f512b59 100644 (file)
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_v3_ruby.sh"
-timeout_mins: 180
+timeout_mins: 360
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
index 2b37ee7..20913f5 100644 (file)
@@ -17,7 +17,9 @@ We have continuous nightly test setup to test gRPC backward compatibility betwee
 - 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: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.
+- Commit the change and create a PR to upstream/master.
+- Trigger an adhoc run of interop matrix tests: https://fusion.corp.google.com/projectanalysis/summary/KOKORO/prod:grpc%2Fcore%2Fexperimental%2Flinux%2Fgrpc_interop_matrix_adhoc
+- Once tests pass, request a PR review.
 - (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 957e166..5cd532e 100644 (file)
@@ -54,7 +54,7 @@ def should_build_docker_interop_image_from_release_tag(lang):
 # Dictionary of default runtimes per language
 LANG_RUNTIME_MATRIX = {
     'cxx': ['cxx'],  # This is actually debian8.
-    'go': ['go1.8', 'go1.11'],
+    'go': ['go1.8', 'go1.11', 'go1.16'],
     'java': ['java'],
     'python': ['python', 'pythonasyncio'],
     'node': ['node'],
@@ -112,6 +112,7 @@ LANG_RELEASE_MATRIX = {
             ('v1.34.0', ReleaseInfo()),
             ('v1.35.0', ReleaseInfo()),
             ('v1.36.3', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
     'go':
         OrderedDict([
@@ -184,6 +185,8 @@ LANG_RELEASE_MATRIX = {
             ('v1.34.0', ReleaseInfo(runtimes=['go1.11'])),
             ('v1.35.0', ReleaseInfo(runtimes=['go1.11'])),
             ('v1.36.0', ReleaseInfo(runtimes=['go1.11'])),
+            ('v1.37.0', ReleaseInfo(runtimes=['go1.11'])),
+            # NOTE: starting from release v1.38.0, use runtimes=['go1.16']
         ]),
     'java':
         OrderedDict([
@@ -252,8 +255,9 @@ LANG_RELEASE_MATRIX = {
             ('v1.32.3', ReleaseInfo()),
             ('v1.33.1', ReleaseInfo()),
             ('v1.34.1', ReleaseInfo()),
-            ('v1.35.0', ReleaseInfo()),
-            ('v1.36.0', ReleaseInfo()),
+            ('v1.35.1', ReleaseInfo()),
+            ('v1.36.1', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
     'python':
         OrderedDict([
@@ -316,6 +320,7 @@ LANG_RELEASE_MATRIX = {
             ('v1.34.0', ReleaseInfo(runtimes=['python'])),
             ('v1.35.0', ReleaseInfo(runtimes=['python'])),
             ('v1.36.3', ReleaseInfo(runtimes=['python'])),
+            ('v1.37.0', ReleaseInfo(runtimes=['python'])),
         ]),
     'node':
         OrderedDict([
@@ -381,6 +386,7 @@ LANG_RELEASE_MATRIX = {
             ('v1.34.0', ReleaseInfo()),
             ('v1.35.0', ReleaseInfo()),
             ('v1.36.3', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
     'php':
         OrderedDict([
@@ -419,6 +425,7 @@ LANG_RELEASE_MATRIX = {
             ('v1.34.0', ReleaseInfo()),
             ('v1.35.0', ReleaseInfo()),
             ('v1.36.3', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
     'csharp':
         OrderedDict([
@@ -462,5 +469,6 @@ LANG_RELEASE_MATRIX = {
             ('v1.34.0', ReleaseInfo()),
             ('v1.35.0', ReleaseInfo()),
             ('v1.36.3', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
 }
index 13e3d84..7ba3269 100644 (file)
@@ -254,6 +254,7 @@ class CSharpExtArtifact:
                 'tools\\run_tests\\artifacts\\build_artifact_csharp.bat',
                 self.arch
             ],
+                                  timeout_seconds=45 * 60,
                                   use_workspace=True)
         else:
             if self.platform == 'linux':
index 7e5abcc..64f68cf 100755 (executable)
@@ -154,30 +154,49 @@ then
   "${PIP}" install grpcio --no-index --find-links "file://$ARTIFACT_DIR/"
   "${PIP}" install grpcio-tools --no-index --find-links "file://$ARTIFACT_DIR/"
 
+  # Note(lidiz) setuptools's "sdist" command creates a source tarball, which
+  # demands an extra step of building the wheel. The building step is merely ran
+  # through setup.py, but we can optimize it with "bdist_wheel" command, which
+  # skips the wheel building step.
+
   # Build grpcio_testing source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_testing/setup.py preprocess \
-      sdist
+      sdist bdist_wheel
   cp -r src/python/grpcio_testing/dist/* "$ARTIFACT_DIR"
 
   # Build grpcio_channelz source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_channelz/setup.py \
-      preprocess build_package_protos sdist
+      preprocess build_package_protos sdist bdist_wheel
   cp -r src/python/grpcio_channelz/dist/* "$ARTIFACT_DIR"
 
   # Build grpcio_health_checking source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_health_checking/setup.py \
-      preprocess build_package_protos sdist
+      preprocess build_package_protos sdist bdist_wheel
   cp -r src/python/grpcio_health_checking/dist/* "$ARTIFACT_DIR"
 
   # Build grpcio_reflection source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_reflection/setup.py \
-      preprocess build_package_protos sdist
+      preprocess build_package_protos sdist bdist_wheel
   cp -r src/python/grpcio_reflection/dist/* "$ARTIFACT_DIR"
 
   # Build grpcio_status source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_status/setup.py \
-      preprocess sdist
+      preprocess sdist bdist_wheel
   cp -r src/python/grpcio_status/dist/* "$ARTIFACT_DIR"
+
+  # Build grpcio_csds source distribution
+  ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_csds/setup.py \
+      sdist bdist_wheel
+  cp -r src/python/grpcio_csds/dist/* "$ARTIFACT_DIR"
+
+  # Build grpcio_admin source distribution and it needs the cutting-edge version
+  # of Channelz and CSDS to be installed.
+  "${PIP}" install --upgrade xds-protos==0.0.8
+  "${PIP}" install grpcio-channelz --no-index --find-links "file://$ARTIFACT_DIR/"
+  "${PIP}" install grpcio-csds --no-index --find-links "file://$ARTIFACT_DIR/"
+  ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_admin/setup.py \
+      sdist bdist_wheel
+  cp -r src/python/grpcio_admin/dist/* "$ARTIFACT_DIR"
 fi
 
 if [ "$GRPC_SKIP_TWINE_CHECK" == "" ]
index cfbd290..a2c8d6b 100644 (file)
@@ -353,6 +353,7 @@ def targets():
         PythonDistribTest('linux', 'x64', 'arch'),
         PythonDistribTest('linux', 'x64', 'ubuntu1604'),
         PythonDistribTest('linux', 'x64', 'ubuntu1804'),
+        PythonDistribTest('linux', 'aarch64', 'python38_buster'),
         PythonDistribTest('linux', 'x64', 'alpine3.7', source=True),
         PythonDistribTest('linux', 'x64', 'jessie', source=True),
         PythonDistribTest('linux', 'x86', 'jessie', source=True),
index cc5cf1a..3f129ce 100755 (executable)
@@ -58,7 +58,12 @@ docker run \
   -e "KOKORO_BUILD_NUMBER=$KOKORO_BUILD_NUMBER" \
   -e "KOKORO_BUILD_URL=$KOKORO_BUILD_URL" \
   -e "KOKORO_JOB_NAME=$KOKORO_JOB_NAME" \
+  -e "KOKORO_ARTIFACTS_DIR=$KOKORO_ARTIFACTS_DIR" \
+  -e "GIT_ORIGIN_URL=$(git -C $git_root remote get-url origin)" \
+  -e "GIT_COMMIT_SHORT=$(git -C $git_root rev-parse --short HEAD)" \
+  -e "TESTGRID_EXCLUDE=$TESTGRID_EXCLUDE" \
   -v "$git_root:/var/local/jenkins/grpc:ro" \
+  -v "$KOKORO_ARTIFACTS_DIR:$KOKORO_ARTIFACTS_DIR" \
   -w /var/local/git/grpc \
   --name="$CONTAINER_NAME" \
   $EXTRA_DOCKER_ARGS \
index 354360d..b0e7f96 100644 (file)
     "flaky": false,
     "gtest": true,
     "language": "c++",
-    "name": "authorization_engine_test",
+    "name": "authorization_matchers_test",
     "platforms": [
       "linux",
       "mac",
     "flaky": false,
     "gtest": true,
     "language": "c++",
+    "name": "cel_authorization_engine_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": "certificate_provider_registry_test",
     "platforms": [
       "linux",
     "flaky": false,
     "gtest": true,
     "language": "c++",
-    "name": "evaluate_args_test",
+    "name": "error_utils_test",
     "platforms": [
       "linux",
       "mac",
     "flaky": false,
     "gtest": true,
     "language": "c++",
-    "name": "eventmanager_libuv_test",
+    "name": "evaluate_args_test",
     "platforms": [
       "linux",
       "mac",
       "posix",
       "windows"
     ],
-    "uses_polling": false
+    "uses_polling": true
   },
   {
     "args": [],
     "flaky": false,
     "gtest": true,
     "language": "c++",
+    "name": "grpc_authorization_engine_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": "grpc_tls_certificate_distributor_test",
     "platforms": [
       "linux",
     "flaky": false,
     "gtest": true,
     "language": "c++",
+    "name": "mock_stream_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": "mock_test",
     "platforms": [
       "linux",
     "flaky": false,
     "gtest": true,
     "language": "c++",
+    "name": "status_helper_test",
+    "platforms": [
+      "linux",
+      "mac",
+      "posix",
+      "windows"
+    ],
+    "uses_polling": false
+  },
+  {
+    "args": [],
+    "benchmark": false,
+    "ci_platforms": [
+      "linux",
+      "mac",
+      "posix",
+      "windows"
+    ],
+    "cpu_cost": 1.0,
+    "exclude_configs": [],
+    "exclude_iomgrs": [],
+    "flaky": false,
+    "gtest": true,
+    "language": "c++",
     "name": "status_metadata_test",
     "platforms": [
       "linux",
index 408d5f5..7b928d1 100755 (executable)
@@ -220,6 +220,12 @@ $VENV_PYTHON "$ROOT/src/python/grpcio_status/setup.py" preprocess
 $VENV_PYTHON "$ROOT/src/python/grpcio_status/setup.py" build_package_protos
 pip_install_dir "$ROOT/src/python/grpcio_status"
 
+# Build/install csds
+pip_install_dir "$ROOT/src/python/grpcio_csds"
+
+# Build/install admin
+pip_install_dir "$ROOT/src/python/grpcio_admin"
+
 # Install testing
 pip_install_dir "$ROOT/src/python/grpcio_testing"
 
index 1d09498..8e3ab27 100644 (file)
@@ -1,38 +1,49 @@
 # Overview of performance test suite, with steps for manual runs:
 
-For design of the tests, see
-https://grpc.io/docs/guides/benchmarking.
+For design of the tests, see https://grpc.io/docs/guides/benchmarking.
+
+For scripts related to the GKE-based performance test suite (in development),
+see [gRPC OSS benchmarks](#grpc-oss-benchmarks).
 
 ## Pre-reqs for running these manually:
+
 In general the benchmark workers and driver build scripts expect
-[linux_performance_worker_init.sh](../../gce/linux_performance_worker_init.sh) to have been ran already.
+[linux_performance_worker_init.sh](../../gce/linux_performance_worker_init.sh)
+to have been ran already.
 
 ### To run benchmarks locally:
-* From the grpc repo root, start the
-[run_performance_tests.py](../run_performance_tests.py) runner script.
+
+- From the grpc repo root, start the
+  [run_performance_tests.py](../run_performance_tests.py) runner script.
 
 ### On remote machines, to start the driver and workers manually:
-The [run_performance_test.py](../run_performance_tests.py) top-level runner script can also
-be used with remote machines, but for e.g., profiling the server,
-it might be useful to run workers manually.
 
-1. You'll need a "driver" and separate "worker" machines.
-For example, you might use one GCE "driver" machine and 3 other
-GCE "worker" machines that are in the same zone.
+The [run_performance_test.py](../run_performance_tests.py) top-level runner
+script can also be used with remote machines, but for e.g., profiling the
+server, it might be useful to run workers manually.
+
+1. You'll need a "driver" and separate "worker" machines. For example, you might
+   use one GCE "driver" machine and 3 other GCE "worker" machines that are in
+   the same zone.
 
-2. Connect to each worker machine and start up a benchmark worker with a "driver_port".
-  * For example, to start the grpc-go benchmark worker:
-  [grpc-go worker main.go](https://github.com/grpc/grpc-go/blob/master/benchmark/worker/main.go) --driver_port <driver_port>
+2. Connect to each worker machine and start up a benchmark worker with a
+   "driver_port".
+
+- For example, to start the grpc-go benchmark worker:
+  [grpc-go worker main.go](https://github.com/grpc/grpc-go/blob/master/benchmark/worker/main.go)
+  --driver_port <driver_port>
 
 #### Commands to start workers in different languages:
- * Note that these commands are what the top-level
-   [run_performance_test.py](../run_performance_tests.py) script uses to
-   build and run different workers through the
-   [build_performance.sh](./build_performance.sh) script and "run worker"
-   scripts (such as the [run_worker_java.sh](./run_worker_java.sh)).
+
+- Note that these commands are what the top-level
+  [run_performance_test.py](../run_performance_tests.py) script uses to build
+  and run different workers through the
+  [build_performance.sh](./build_performance.sh) script and "run worker" scripts
+  (such as the [run_worker_java.sh](./run_worker_java.sh)).
 
 ##### Running benchmark workers for C-core wrapped languages (C++, Python, C#, Node, Ruby):
-   * These are more simple since they all live in the main grpc repo.
+
+- These are more simple since they all live in the main grpc repo.
 
 ```
 $ cd <grpc_repo_root>
@@ -40,11 +51,12 @@ $ tools/run_tests/performance/build_performance.sh
 $ tools/run_tests/performance/run_worker_<language>.sh
 ```
 
-   * Note that there is one "run_worker" script per language, e.g.,
-     [run_worker_csharp.sh](./run_worker_csharp.sh) for c#.
+- Note that there is one "run_worker" script per language, e.g.,
+  [run_worker_csharp.sh](./run_worker_csharp.sh) for c#.
 
 ##### Running benchmark workers for gRPC-Java:
-   * You'll need the [grpc-java](https://github.com/grpc/grpc-java) repo.
+
+- You'll need the [grpc-java](https://github.com/grpc/grpc-java) repo.
 
 ```
 $ cd <grpc-java-repo>
@@ -53,7 +65,8 @@ $ benchmarks/build/install/grpc-benchmarks/bin/benchmark_worker --driver_port <d
 ```
 
 ##### Running benchmark workers for gRPC-Go:
-   * You'll need the [grpc-go repo](https://github.com/grpc/grpc-go)
+
+- You'll need the [grpc-go repo](https://github.com/grpc/grpc-go)
 
 ```
 $ cd <grpc-go-repo>/benchmark/worker && go install
@@ -62,27 +75,34 @@ $ $GOPATH/bin/worker --driver_port <driver_port>
 ```
 
 #### Build the driver:
-* Connect to the driver machine (if using a remote driver) and from the grpc repo root:
+
+- Connect to the driver machine (if using a remote driver) and from the grpc
+  repo root:
+
 ```
 $ tools/run_tests/performance/build_performance.sh
 ```
 
 #### Run the driver:
+
 1. Get the 'scenario_json' relevant for the scenario to run. Note that "scenario
-  json" configs are generated from [scenario_config.py](./scenario_config.py).
-  The [driver](../../../test/cpp/qps/qps_json_driver.cc) takes a list of these configs as a json string of the form: `{scenario: <json_list_of_scenarios> }`
-  in its `--scenarios_json` command argument.
-  One quick way to get a valid json string to pass to the driver is by running
-  the [run_performance_tests.py](./run_performance_tests.py) locally and copying the logged scenario json command arg.
+   json" configs are generated from [scenario_config.py](./scenario_config.py).
+   The [driver](../../../test/cpp/qps/qps_json_driver.cc) takes a list of these
+   configs as a json string of the form: `{scenario: <json_list_of_scenarios> }`
+   in its `--scenarios_json` command argument. One quick way to get a valid json
+   string to pass to the driver is by running the
+   [run_performance_tests.py](./run_performance_tests.py) locally and copying
+   the logged scenario json command arg.
 
 2. From the grpc repo root:
 
-* Set `QPS_WORKERS` environment variable to a comma separated list of worker
-machines. Note that the driver will start the "benchmark server" on the first
-entry in the list, and the rest will be told to run as clients against the
-benchmark server.
+- Set `QPS_WORKERS` environment variable to a comma separated list of worker
+  machines. Note that the driver will start the "benchmark server" on the first
+  entry in the list, and the rest will be told to run as clients against the
+  benchmark server.
 
 Example running and profiling of go benchmark server:
+
 ```
 $ export QPS_WORKERS=<host1>:<10000>,<host2>,10000,<host3>:10000
 $ bins/opt/qps_json_driver --scenario_json='<scenario_json_scenario_config_string>'
@@ -93,42 +113,269 @@ $ bins/opt/qps_json_driver --scenario_json='<scenario_json_scenario_config_strin
 While running the benchmark, a profiler can be attached to the server.
 
 Example to count syscalls in grpc-go server during a benchmark:
-* Connect to server machine and run:
+
+- Connect to server machine and run:
+
 ```
 $ netstat -tulpn | grep <driver_port> # to get pid of worker
 $ perf stat -p <worker_pid> -e syscalls:sys_enter_write # stop after test complete
 ```
 
 Example memory profile of grpc-go server, with `go tools pprof`:
-* After a run is done on the server, see its alloc profile with:
+
+- After a run is done on the server, see its alloc profile with:
+
 ```
 $ go tool pprof --text --alloc_space http://localhost:<pprof_port>/debug/heap
 ```
 
 ### Configuration environment variables:
 
-* QPS_WORKER_CHANNEL_CONNECT_TIMEOUT
+- QPS_WORKER_CHANNEL_CONNECT_TIMEOUT
 
   Consuming process: qps_worker
 
   Type: integer (number of seconds)
 
-  This can be used to configure the amount of time that benchmark
-  clients wait for channels to the benchmark server to become ready.
-  This is useful in certain benchmark environments in which the
-  server can take a long time to become ready. Note: if setting
-  this to a high value, then the scenario config under test should
-  probably also have a large "warmup_seconds".
+  This can be used to configure the amount of time that benchmark clients wait
+  for channels to the benchmark server to become ready. This is useful in
+  certain benchmark environments in which the server can take a long time to
+  become ready. Note: if setting this to a high value, then the scenario config
+  under test should probably also have a large "warmup_seconds".
 
-* QPS_WORKERS
+- QPS_WORKERS
 
   Consuming process: qps_json_driver
 
   Type: comma separated list of host:port
 
-  Set this to a comma separated list of QPS worker processes/machines.
-  Each scenario in a scenario config has specifies a certain number
-  of servers, `num_servers`, and the driver will start
-  "benchmark servers"'s on the first `num_server` `host:port` pairs in
-  the comma separated list. The rest will be told to run as clients
-  against the benchmark server.
+  Set this to a comma separated list of QPS worker processes/machines. Each
+  scenario in a scenario config has specifies a certain number of servers,
+  `num_servers`, and the driver will start "benchmark servers"'s on the first
+  `num_server` `host:port` pairs in the comma separated list. The rest will be
+  told to run as clients against the benchmark server.
+
+## gRPC OSS benchmarks
+
+The scripts in this section generate LoadTest configurations for the GKE-based
+gRPC OSS benchmarks framework. This framework is stored in a separate
+repository, [grpc/test-infra](https://github.com/grpc/test-infra).
+
+### Generating scenarios
+
+The benchmarks framework uses the same test scenarios as the legacy one. These
+script [scenario_config_exporter.py](./scenario_config_exporter.py) can be used
+to export these scenarios to files, and also to count and analyze existing
+scenarios.
+
+The language(s) and category of the scenarios are of particular importance to
+the tests. Continuous runs will typically run tests in the `scalable` category.
+
+The following example counts scenarios in the `scalable` category:
+
+```
+$ ./tools/run_tests/performance/scenario_config_exporter.py --count_scenarios --category=scalable
+Scenario count for all languages (category: scalable):
+Count  Language         Client   Server   Categories
+   77  c++                                scalable
+   19  python_asyncio                     scalable
+   16  java                               scalable
+   12  go                                 scalable
+   12  node                      node     scalable
+   12  node_purejs               node     scalable
+    9  csharp                             scalable
+    7  python                             scalable
+    5  ruby                               scalable
+    4  csharp                    c++      scalable
+    4  php7                      c++      scalable
+    4  php7_protobuf_c           c++      scalable
+    3  python_asyncio            c++      scalable
+    2  ruby                      c++      scalable
+    2  python                    c++      scalable
+    1  csharp           c++               scalable
+
+  189  total scenarios (category: scalable)
+```
+
+Client and server languages are only set for cross-language scenarios, where the
+client or server language do not match the scenario language.
+
+### Generating load test configurations
+
+The benchmarks framework uses LoadTest resources configured by YAML files. Each
+LoadTest resource specifies a driver, a server, and one or more clients to run
+the test. Each test runs one scenario. The scenario configuration is embedded in
+the LoadTest configuration. Example configurations for various languages can be
+found here:
+
+https://github.com/grpc/test-infra/tree/master/config/samples
+
+The script [loadtest_config.py](./loadtest_config.py) generates LoadTest
+configurations for tests running a set of scenarios. The configurations are
+written in multipart YAML format, either to a file or to stdout. Each
+configuration contains a single embedded scenario.
+
+The LoadTest configurations are generated from a template. Any configuration can
+be used as a template, as long as it contains the languages required by the set
+of scenarios we intend to run (for instance, if we are generating configurations
+to run go scenarios, the template must contain a go client and a go server; if
+we are generating configurations for cross-language scenarios that need a go
+client and a C++ server, the template must also contain a C++ server; and the
+same for all other languages).
+
+The LoadTests specified in the script output all have unique names and can be
+run by applying the test to a cluster running the LoadTest controller with
+`kubectl apply`:
+
+```
+$ kubectl apply -f loadtest_config.yaml
+```
+
+A basic template for generating tests in various languages can be found here:
+[loadtest_template_basic_all_languages.yaml](./templates/loadtest_template_basic_all_languages.yaml).
+The following example generates configurations for C# and Java tests using this
+template, including tests against C++ clients and servers, and running each test
+twice:
+
+```
+$ ./tools/run_tests/performance/loadtest_config.py -l go -l java \
+    -t ./tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml \
+    -s client_pool=workers-8core -s server_pool=workers-8core \
+    -s big_query_table=grpc-testing.e2e_benchmarks.experimental_results \
+    -s timeout_seconds=3600 --category=scalable \
+    -d --allow_client_language=c++ --allow_server_language=c++ \
+    --runs_per_test=2 -o ./loadtest.yaml
+```
+
+The script `loadtest_config.py` takes the following options:
+
+- `-l`, `--language`<br> Language to benchmark. May be repeated.
+- `-t`, `--template`<br> Template file. A template is a configuration file that
+  may contain multiple client and server configuration, and may also include
+  substitution keys.
+- `p`, `--prefix`<br> Test names consist of a prefix_joined with a uuid with a
+  dash. Test names are stored in `metadata.name`. The prefix is also added as
+  the `prefix` label in `metadata.labels`. The prefix defaults to the user name
+  if not set.
+- `-u`, `--uniquifier_element`<br> Uniquifier elements may be passed to the test
+  to make the test name unique. This option may be repeated to add multiple
+  elements. The uniquifier elements (plus a date string and a run index, if
+  applicable) are joined with a dash to form a _uniquifier_. The test name uuid
+  is derived from the scenario name and the uniquifier. The uniquifier is also
+  added as the `uniquifier` annotation in `metadata.annotations`.
+- `-d`<br> This option is a shorthand for the addition of a date string as a
+  uniquifier element.
+- `-a`, `--annotation`<br> Metadata annotation to be stored in
+  `metadata.annotations`, in the form key=value. May be repeated.
+- `-r`, `--regex`<br> Regex to select scenarios to run. Each scenario is
+  embedded in a LoadTest configuration containing a client and server of the
+  language(s) required for the test. Defaults to `.*`, i.e., select all
+  scenarios.
+- `--category`<br> Select scenarios of a specified _category_, or of all
+  categories. Defaults to `all`. Continuous runs typically run tests in the
+  `scalable` category.
+- `--allow_client_language`<br> Allows cross-language scenarios where the client
+  is of a specified language, different from the scenario language. This is
+  typically `c++`. This flag may be repeated.
+- `--allow_server_language`<br> Allows cross-language scenarios where the server
+  is of a specified language, different from the scenario language. This is
+  typically `node` or `c++`. This flag may be repeated.
+- `--runs_per_test`<br> This option specifies that each test should be repeated
+  `n` times, where `n` is the value of the flag. If `n` > 1, the index of each
+  test run is added as a uniquifier element for that run.
+- `-o`, `--output`<br> Output file name. The LoadTest configurations are added
+  to this file, in multipart YAML format. Output is streamed to `sys.stdout` if
+  not set.
+
+The script adds labels and annotations to the metadata of each LoadTest
+configuration:
+
+The following labels are added to `metadata.labels`:
+
+- `language`<br> The language of the LoadTest scenario.
+- `prefix`<br> The prefix used in `metadata.name`.
+
+The following annotations are added to `metadata.annotations`:
+
+- `scenario`<br> The name of the LoadTest scenario.
+- `uniquifier`<br> The uniquifier used to generate the LoadTest name, including
+  the run index if applicable.
+
+[Labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/)
+can be used in selectors in resource queries. Adding the prefix, in particular,
+allows the user (or an automation script) to select the resources started from a
+given run of the config generator.
+
+[Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/)
+contain additional information that is available to the user (or an automation
+script) but is not indexed and cannot be used to select objects. Scenario name
+and uniquifier are added to provide the elements of the LoadTest name uuid in
+human-readable form. Additional annotations may be added later for automation.
+
+### Concatenating load test configurations
+
+The LoadTest configuration generator can process multiple languages at a time,
+assuming that they are supported by the template. The convenience script
+[loadtest_concat_yaml.py](./loadtest_concat_yaml.py) is provided to concatenate
+several YAML files into one, so configurations generated by multiple generator
+invocations can be concatenated into one and run with a single command. The
+script can be invoked as follows:
+
+```
+$ loadtest_concat_yaml.py -i infile1.yaml infile2.yaml -o outfile.yaml
+```
+
+### Generating configuration templates
+
+The script [loadtest_template.py](./loadtest_template.py) generates a load test
+configuration template from a set of load test configurations. The source files
+may be load test configurations or load test configuration templates. The
+generated template supports all languages supported in any of the input
+configurations or templates.
+
+The example template in
+[loadtest_template_basic_template_all_languages.yaml](./templates/loadtest_template_basic_all_languages.yaml)
+was generated from the example configurations in
+[grpc/test-infra](https://github.com/grpc/test-infra) by the following command:
+
+```
+$ ./tools/run_tests/performance/loadtest_template.py \
+    -i ../test-infra/config/samples/*.yaml \
+    --inject_client_pool --inject_server_pool --inject_big_query_table \
+    --inject_timeout_seconds \
+    -o ./tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml \
+    --name basic_all_languages
+```
+
+The script `loadtest_template.py` takes the following options:
+
+- `-i`, `--inputs`<br> Space-separated list of the names of input files
+  containing LoadTest configurations. May be repeated.
+- `-o`, `--output`<br> Output file name. Outputs to `sys.stdout` if not set.
+- `--inject_client_pool`<br> If this option is set, the pool attribute of all
+  clients in `spec.clients` is set to `${client_pool}`, for later substitution.
+- `--inject_server_pool`<br> If this option is set, the pool attribute of all
+  servers in `spec.servers` is set to `${server_pool}`, for later substitution.
+- `--inject_big_query_table`<br> If this option is set,
+  spec.results.bigQueryTable is set to `${big_query_table}`.
+- `--inject_timeout_seconds`<br> If this option is set, `spec.timeoutSeconds` is
+  set to `${timeout_seconds}`.
+- `--inject_ttl_seconds`<br> If this option is set, `spec.ttlSeconds` is set to
+  `${ttl_seconds}`.
+- `-n`, `--name`<br> Name to be set in `metadata.name`.
+- `-a`, `--annotation`<br> Metadata annotation to be stored in
+  `metadata.annotations`, in the form key=value. May be repeated.
+
+The four options that inject substitution keys are the most useful for template
+reuse. When running tests on different node pools, it becomes necessary to set
+the pool, and usually also to store the data on a different table. When running
+as part of a larger collection of tests, it may also be necessary to adjust test
+timeout and time-to-live, to ensure that all tests have time to complete.
+
+The template name is replaced again by `loadtest_config.py`, and so is set only
+as a human-readable memo.
+
+Annotations, on the other hand, are passed on to the test configurations, and
+may be set to values or to substitution keys in themselves, allowing future
+automation scripts to process the tests generated from these configurations in
+different ways.
diff --git a/tools/run_tests/performance/loadtest_concat_yaml.py b/tools/run_tests/performance/loadtest_concat_yaml.py
new file mode 100755 (executable)
index 0000000..bf64fdc
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+# Copyright 2021 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.
+
+# Helper script to concatenate YAML files.
+#
+# This script concatenates multiple YAML files into a single multipart file.
+# Input files are not parsed but processed as strings. This is a convenience
+# script to concatenate output files generated by multiple runs of
+# loadtest_config.py.
+
+import argparse
+import sys
+
+from typing import Iterable
+
+
+def gen_content_strings(input_files: Iterable[str]) -> Iterable[str]:
+    if not input_files:
+        return
+
+    with open(input_files[0]) as f:
+        content = f.read()
+    yield content
+
+    for input_file in input_files[1:]:
+        with open(input_file) as f:
+            content = f.read()
+        yield '---\n'
+        yield content
+
+
+def main() -> None:
+    argp = argparse.ArgumentParser(description='Concatenates YAML files.')
+    argp.add_argument('-i',
+                      '--inputs',
+                      action='extend',
+                      nargs='+',
+                      type=str,
+                      required=True,
+                      help='Input files.')
+    argp.add_argument(
+        '-o',
+        '--output',
+        type=str,
+        help='Concatenated output file. Output to stdout if not set.')
+    args = argp.parse_args()
+
+    with open(args.output, 'w') if args.output else sys.stdout as f:
+        for content in gen_content_strings(args.inputs):
+            print(content, file=f, sep='', end='')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/run_tests/performance/loadtest_config.py b/tools/run_tests/performance/loadtest_config.py
new file mode 100755 (executable)
index 0000000..b91b2ca
--- /dev/null
@@ -0,0 +1,383 @@
+#!/usr/bin/env python3
+# Copyright 2021 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.
+
+# Script to generate test configurations for the OSS benchmarks framework.
+#
+# This script filters test scenarios and generates uniquely named configurations
+# for each test. Configurations are dumped in multipart YAML format.
+#
+# See documentation below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md#grpc-oss-benchmarks
+
+import argparse
+import copy
+import datetime
+import itertools
+import os
+import string
+import sys
+import uuid
+
+from typing import Any, Dict, Iterable, Mapping, Optional, Type
+
+import json
+import yaml
+
+import scenario_config
+import scenario_config_exporter
+
+CONFIGURATION_FILE_HEADER_COMMENT = """
+# Load test configurations generated from a template by loadtest_config.py.
+# See documentation below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md#grpc-oss-benchmarks
+"""
+
+# TODO(paulosjca): Merge label_language and image_language into one function.
+# These functions are necessary because 'c++' is not allowed as a label value in
+# kubernetes, and because languages share images in the existing templates. Once
+# the templates are reorganized and most image mapping is removed, the two
+# functions can be merged into one.
+
+
+def label_language(language: str) -> str:
+    """Convert scenario language to place in a resource label."""
+    return {
+        'c++': 'cxx',
+    }.get(language, language)
+
+
+def image_language(language: str) -> str:
+    """Convert scenario languages to image languages."""
+    return {
+        'c++': 'cxx',
+        'node_purejs': 'node',
+        'php7': 'php',
+        'php7_protobuf_c': 'php',
+        'python_asyncio': 'python',
+    }.get(language, language)
+
+
+def default_prefix() -> str:
+    """Constructs and returns a default prefix for LoadTest names."""
+    return os.environ.get('USER', 'loadtest')
+
+
+def now_string() -> str:
+    """Returns the current date and time in string format."""
+    return datetime.datetime.now().strftime('%Y%m%d%H%M%S')
+
+
+def validate_loadtest_name(name: str) -> None:
+    """Validates that a LoadTest name is in the expected format."""
+    if len(name) > 63:
+        raise ValueError(
+            'LoadTest name must be less than 63 characters long: %s' % name)
+    if not all((s.isalnum() for s in name.split('-'))):
+        raise ValueError('Invalid elements in LoadTest name: %s' % name)
+
+
+def loadtest_base_name(scenario_name: str,
+                       uniquifier_elements: Iterable[str]) -> str:
+    """Constructs and returns the base name for a LoadTest resource."""
+    name_elements = scenario_name.split('_')
+    name_elements.extend(uniquifier_elements)
+    return '-'.join(name_elements)
+
+
+def loadtest_name(prefix: str, scenario_name: str,
+                  uniquifier_elements: Iterable[str]) -> str:
+    """Constructs and returns a valid name for a LoadTest resource."""
+    base_name = loadtest_base_name(scenario_name, uniquifier_elements)
+    name_elements = []
+    if prefix:
+        name_elements.append(prefix)
+    name_elements.append(str(uuid.uuid5(uuid.NAMESPACE_DNS, base_name)))
+    name = '-'.join(name_elements)
+    validate_loadtest_name(name)
+    return name
+
+
+def validate_annotations(annotations: Dict[str, str]) -> None:
+    """Validates that annotations do not contain reserved names.
+
+    These names are automatically added by the config generator.
+    """
+    names = set(('scenario', 'uniquifier')).intersection(annotations)
+    if names:
+        raise ValueError('Annotations contain reserved names: %s' % names)
+
+
+def gen_run_indices(runs_per_test: int) -> Iterable[str]:
+    """Generates run indices for multiple runs, as formatted strings."""
+    if runs_per_test < 2:
+        yield ''
+        return
+    prefix_length = len('{:d}'.format(runs_per_test - 1))
+    prefix_fmt = '{{:{:d}d}}'.format(prefix_length)
+    for i in range(runs_per_test):
+        yield prefix_fmt.format(i)
+
+
+def gen_loadtest_configs(
+        base_config: Mapping[str, Any],
+        base_config_clients: Iterable[Mapping[str, Any]],
+        base_config_servers: Iterable[Mapping[str, Any]],
+        scenario_name_regex: str,
+        language_config: scenario_config_exporter.LanguageConfig,
+        loadtest_name_prefix: str,
+        uniquifier_elements: Iterable[str],
+        annotations: Mapping[str, str],
+        runs_per_test: int = 1) -> Iterable[Dict[str, Any]]:
+    """Generates LoadTest configurations for a given language config.
+
+    The LoadTest configurations are generated as YAML objects.
+    """
+    validate_annotations(annotations)
+    prefix = loadtest_name_prefix or default_prefix()
+    cl = image_language(language_config.client_language or
+                        language_config.language)
+    sl = image_language(language_config.server_language or
+                        language_config.language)
+    scenario_filter = scenario_config_exporter.scenario_filter(
+        scenario_name_regex=scenario_name_regex,
+        category=language_config.category,
+        client_language=language_config.client_language,
+        server_language=language_config.server_language)
+    scenarios = scenario_config_exporter.gen_scenarios(language_config.language,
+                                                       scenario_filter)
+
+    for scenario in scenarios:
+        for run_index in gen_run_indices(runs_per_test):
+            uniq = (uniquifier_elements +
+                    [run_index] if run_index else uniquifier_elements)
+            name = loadtest_name(prefix, scenario['name'], uniq)
+            scenario_str = json.dumps({'scenarios': scenario},
+                                      indent='  ') + '\n'
+
+            config = copy.deepcopy(base_config)
+
+            metadata = config['metadata']
+            metadata['name'] = name
+            if 'labels' not in metadata:
+                metadata['labels'] = dict()
+            metadata['labels']['language'] = label_language(
+                language_config.language)
+            metadata['labels']['prefix'] = prefix
+            if 'annotations' not in metadata:
+                metadata['annotations'] = dict()
+            metadata['annotations'].update(annotations)
+            metadata['annotations'].update({
+                'scenario': scenario['name'],
+                'uniquifier': '-'.join(uniq),
+            })
+
+            spec = config['spec']
+
+            # Select clients with the required language.
+            spec['clients'] = [
+                client for client in base_config_clients
+                if client['language'] == cl
+            ]
+            if not spec['clients']:
+                raise IndexError('Client language not found in template: %s' %
+                                 cl)
+
+            # Select servers with the required language.
+            spec['servers'] = [
+                server for server in base_config_servers
+                if server['language'] == sl
+            ]
+            if not spec['servers']:
+                raise IndexError('Server language not found in template: %s' %
+                                 sl)
+
+            spec['scenariosJSON'] = scenario_str
+
+            yield config
+
+
+def parse_key_value_args(args: Optional[Iterable[str]]) -> Dict[str, str]:
+    """Parses arguments in the form key=value into a dictionary."""
+    d = dict()
+    if args is None:
+        return d
+    for arg in args:
+        key, equals, value = arg.partition('=')
+        if equals != '=':
+            raise ValueError('Expected key=value: ' + value)
+        d[key] = value
+    return d
+
+
+def config_dumper(header_comment: str) -> Type[yaml.SafeDumper]:
+    """Returns a custom dumper to dump configurations in the expected format."""
+
+    class ConfigDumper(yaml.SafeDumper):
+
+        def expect_stream_start(self):
+            super().expect_stream_start()
+            if isinstance(self.event, yaml.StreamStartEvent):
+                self.write_indent()
+                self.write_indicator(header_comment, need_whitespace=False)
+
+        def expect_block_sequence(self):
+            super().expect_block_sequence()
+            self.increase_indent()
+
+        def expect_block_sequence_item(self, first=False):
+            if isinstance(self.event, yaml.SequenceEndEvent):
+                self.indent = self.indents.pop()
+            super().expect_block_sequence_item(first)
+
+    def str_presenter(dumper, data):
+        if '\n' in data:
+            return dumper.represent_scalar('tag:yaml.org,2002:str',
+                                           data,
+                                           style='|')
+        return dumper.represent_scalar('tag:yaml.org,2002:str', data)
+
+    ConfigDumper.add_representer(str, str_presenter)
+
+    return ConfigDumper
+
+
+def main() -> None:
+    language_choices = sorted(scenario_config.LANGUAGES.keys())
+    argp = argparse.ArgumentParser(
+        description='Generates load test configs from a template.',
+        fromfile_prefix_chars='@')
+    argp.add_argument('-l',
+                      '--language',
+                      action='append',
+                      choices=language_choices,
+                      required=True,
+                      help='Language(s) to benchmark.',
+                      dest='languages')
+    argp.add_argument('-t',
+                      '--template',
+                      type=str,
+                      required=True,
+                      help='LoadTest configuration yaml file template.')
+    argp.add_argument('-s',
+                      '--substitution',
+                      action='append',
+                      default=[],
+                      help='Template substitution(s), in the form key=value.',
+                      dest='substitutions')
+    argp.add_argument('-p',
+                      '--prefix',
+                      default='',
+                      type=str,
+                      help='Test name prefix.')
+    argp.add_argument('-u',
+                      '--uniquifier_element',
+                      action='append',
+                      default=[],
+                      help='String element(s) to make the test name unique.',
+                      dest='uniquifier_elements')
+    argp.add_argument(
+        '-d',
+        action='store_true',
+        help='Use creation date and time as an additional uniquifier element.')
+    argp.add_argument('-a',
+                      '--annotation',
+                      action='append',
+                      default=[],
+                      help='metadata.annotation(s), in the form key=value.',
+                      dest='annotations')
+    argp.add_argument('-r',
+                      '--regex',
+                      default='.*',
+                      type=str,
+                      help='Regex to select scenarios to run.')
+    argp.add_argument(
+        '--category',
+        choices=['all', 'inproc', 'scalable', 'smoketest', 'sweep'],
+        default='all',
+        help='Select a category of tests to run.')
+    argp.add_argument(
+        '--allow_client_language',
+        action='append',
+        choices=language_choices,
+        default=[],
+        help='Allow cross-language scenarios with this client language.',
+        dest='allow_client_languages')
+    argp.add_argument(
+        '--allow_server_language',
+        action='append',
+        choices=language_choices,
+        default=[],
+        help='Allow cross-language scenarios with this server language.',
+        dest='allow_server_languages')
+    argp.add_argument('--runs_per_test',
+                      default=1,
+                      type=int,
+                      help='Number of copies to generate for each test.')
+    argp.add_argument('-o',
+                      '--output',
+                      type=str,
+                      help='Output file name. Output to stdout if not set.')
+    args = argp.parse_args()
+
+    substitutions = parse_key_value_args(args.substitutions)
+
+    uniquifier_elements = args.uniquifier_elements
+    if args.d:
+        uniquifier_elements.append(now_string())
+
+    annotations = parse_key_value_args(args.annotations)
+
+    with open(args.template) as f:
+        base_config = yaml.safe_load(
+            string.Template(f.read()).substitute(substitutions))
+
+    spec = base_config['spec']
+    base_config_clients = spec['clients']
+    del spec['clients']
+    base_config_servers = spec['servers']
+    del spec['servers']
+
+    client_languages = [''] + args.allow_client_languages
+    server_languages = [''] + args.allow_server_languages
+    config_generators = []
+    for l, cl, sl in itertools.product(args.languages, client_languages,
+                                       server_languages):
+        language_config = scenario_config_exporter.LanguageConfig(
+            category=args.category,
+            language=l,
+            client_language=cl,
+            server_language=sl)
+        config_generators.append(
+            gen_loadtest_configs(base_config,
+                                 base_config_clients,
+                                 base_config_servers,
+                                 args.regex,
+                                 language_config,
+                                 loadtest_name_prefix=args.prefix,
+                                 uniquifier_elements=uniquifier_elements,
+                                 annotations=annotations,
+                                 runs_per_test=args.runs_per_test))
+    configs = (config for config in itertools.chain(*config_generators))
+
+    with open(args.output, 'w') if args.output else sys.stdout as f:
+        yaml.dump_all(configs,
+                      stream=f,
+                      Dumper=config_dumper(
+                          CONFIGURATION_FILE_HEADER_COMMENT.strip()),
+                      default_flow_style=False)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/run_tests/performance/loadtest_template.py b/tools/run_tests/performance/loadtest_template.py
new file mode 100755 (executable)
index 0000000..9684bb9
--- /dev/null
@@ -0,0 +1,216 @@
+#!/usr/bin/env python3
+# Copyright 2021 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.
+
+# This script generates a load test configuration template from a collection of
+# load test configurations.
+#
+# Configuration templates contain client and server configurations for multiple
+# languages, and may contain template substitution keys. These templates are
+# used to generate load test configurations by selecting clients and servers for
+# the required languages. The source files for template generation may be load
+# test configurations or load test configuration templates. Load test
+# configuration generation is performed by loadtest_config.py. See documentation
+# below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md
+
+import argparse
+import sys
+
+from typing import Any, Dict, Iterable, Mapping, Type
+
+import yaml
+
+import loadtest_config
+
+TEMPLATE_FILE_HEADER_COMMENT = """
+# Template generated from load test configurations by loadtest_template.py.
+#
+# Configuration templates contain client and server configurations for multiple
+# languages, and may contain template substitution keys. These templates are
+# used to generate load test configurations by selecting clients and servers for
+# the required languages. The source files for template generation may be load
+# test configurations or load test configuration templates. Load test
+# configuration generation is performed by loadtest_config.py. See documentation
+# below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md
+"""
+
+
+def loadtest_template(
+        input_file_names: Iterable[str],
+        metadata: Mapping[str, Any],
+        inject_client_pool: bool,
+        inject_server_pool: bool,
+        inject_big_query_table: bool,
+        inject_timeout_seconds: bool,
+        inject_ttl_seconds: bool) -> Dict[str, Any]:  # yapf: disable
+    """Generates the load test template."""
+    clients = list()
+    servers = list()
+    spec = dict()
+    client_languages = set()
+    server_languages = set()
+    template = {
+        'apiVersion': 'e2etest.grpc.io/v1',
+        'kind': 'LoadTest',
+        'metadata': metadata,
+    }
+    for input_file_name in input_file_names:
+        with open(input_file_name) as f:
+            input_config = yaml.safe_load(f.read())
+
+            if input_config.get('apiVersion') != template['apiVersion']:
+                raise ValueError('Unexpected api version in file {}: {}'.format(
+                    input_file_name, input_config.get('apiVersion')))
+            if input_config.get('kind') != template['kind']:
+                raise ValueError('Unexpected kind in file {}: {}'.format(
+                    input_file_name, input_config.get('kind')))
+
+            for client in input_config['spec']['clients']:
+                if client['language'] in client_languages:
+                    continue
+                if inject_client_pool:
+                    client['pool'] = '${client_pool}'
+                clients.append(client)
+                client_languages.add(client['language'])
+
+            for server in input_config['spec']['servers']:
+                if server['language'] in server_languages:
+                    continue
+                if inject_server_pool:
+                    server['pool'] = '${server_pool}'
+                servers.append(server)
+                server_languages.add(server['language'])
+
+            input_spec = input_config['spec']
+            del input_spec['clients']
+            del input_spec['servers']
+            del input_spec['scenariosJSON']
+            spec.update(input_config['spec'])
+
+    clients.sort(key=lambda x: x['language'])
+    servers.sort(key=lambda x: x['language'])
+
+    spec.update({
+        'clients': clients,
+        'servers': servers,
+    })
+
+    if inject_big_query_table:
+        if 'results' not in spec:
+            spec['results'] = dict()
+        spec['results']['bigQueryTable'] = '${big_query_table}'
+    if inject_timeout_seconds:
+        spec['timeoutSeconds'] = '${timeout_seconds}'
+    if inject_ttl_seconds:
+        spec['ttlSeconds'] = '${ttl_seconds}'
+
+    template['spec'] = spec
+
+    return template
+
+
+def template_dumper(header_comment: str) -> Type[yaml.SafeDumper]:
+    """Returns a custom dumper to dump templates in the expected format."""
+
+    class TemplateDumper(yaml.SafeDumper):
+
+        def expect_stream_start(self):
+            super().expect_stream_start()
+            if isinstance(self.event, yaml.StreamStartEvent):
+                self.write_indent()
+                self.write_indicator(header_comment, need_whitespace=False)
+
+        def expect_block_sequence(self):
+            super().expect_block_sequence()
+            self.increase_indent()
+
+        def expect_block_sequence_item(self, first=False):
+            if isinstance(self.event, yaml.SequenceEndEvent):
+                self.indent = self.indents.pop()
+            super().expect_block_sequence_item(first)
+
+    return TemplateDumper
+
+
+def main() -> None:
+    argp = argparse.ArgumentParser(
+        description='Creates a load test config generator template.',
+        fromfile_prefix_chars='@')
+    argp.add_argument('-i',
+                      '--inputs',
+                      action='extend',
+                      nargs='+',
+                      type=str,
+                      help='Input files.')
+    argp.add_argument('-o',
+                      '--output',
+                      type=str,
+                      help='Output file. Outputs to stdout if not set.')
+    argp.add_argument(
+        '--inject_client_pool',
+        action='store_true',
+        help='Set spec.client(s).pool values to \'${client_pool}\'.')
+    argp.add_argument(
+        '--inject_server_pool',
+        action='store_true',
+        help='Set spec.server(s).pool values to \'${server_pool}\'.')
+    argp.add_argument(
+        '--inject_big_query_table',
+        action='store_true',
+        help='Set spec.results.bigQueryTable to \'${big_query_table}\'.')
+    argp.add_argument('--inject_timeout_seconds',
+                      action='store_true',
+                      help='Set spec.timeoutSeconds to \'${timeout_seconds}\'.')
+    argp.add_argument('--inject_ttl_seconds',
+                      action='store_true',
+                      help='Set timeout ')
+    argp.add_argument('-n',
+                      '--name',
+                      default='',
+                      type=str,
+                      help='metadata.name.')
+    argp.add_argument('-a',
+                      '--annotation',
+                      action='append',
+                      type=str,
+                      help='metadata.annotation(s), in the form key=value.',
+                      dest='annotations')
+    args = argp.parse_args()
+
+    annotations = loadtest_config.parse_key_value_args(args.annotations)
+
+    metadata = {'name': args.name}
+    if annotations:
+        metadata['annotations'] = annotations
+
+    template = loadtest_template(
+        input_file_names=args.inputs,
+        metadata=metadata,
+        inject_client_pool=args.inject_client_pool,
+        inject_server_pool=args.inject_server_pool,
+        inject_big_query_table=args.inject_big_query_table,
+        inject_timeout_seconds=args.inject_timeout_seconds,
+        inject_ttl_seconds=args.inject_ttl_seconds)
+
+    with open(args.output, 'w') if args.output else sys.stdout as f:
+        yaml.dump(template,
+                  stream=f,
+                  Dumper=template_dumper(TEMPLATE_FILE_HEADER_COMMENT.strip()),
+                  default_flow_style=False)
+
+
+if __name__ == '__main__':
+    main()
index d9e685c..ed2b532 100644 (file)
@@ -53,8 +53,11 @@ def _get_secargs(is_secure):
 
 
 def remove_nonproto_fields(scenario):
-    """Remove special-purpose that contains some extra info about the scenario
-  but don't belong to the ScenarioConfig protobuf message"""
+    """Removes special-purpose fields that don't belong in the protobuf.
+
+    This function removes additional information about the scenario that is not
+    included in the ScenarioConfig protobuf message.
+    """
     scenario.pop('CATEGORIES', None)
     scenario.pop('CLIENT_LANGUAGE', None)
     scenario.pop('SERVER_LANGUAGE', None)
index 23aad5c..d8837fd 100755 (executable)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Helper script to extract JSON scenario definitions from scenario_config.py
-# Useful to construct "ScenariosJSON" configuration accepted by the OSS benchmarks framework
+# Library to extract scenario definitions from scenario_config.py.
+#
+# Contains functions to filter, analyze and dump scenario definitions.
+#
+# This library is used in loadtest_config.py to generate the "scenariosJSON"
+# field in the format accepted by the OSS benchmarks framework.
 # See https://github.com/grpc/test-infra/blob/master/config/samples/cxx_example_loadtest.yaml
+#
+# It can also be used to dump scenarios to files, to count scenarios by
+# language, and to export scenario languages in a format that can be used for
+# automation.
+#
+# Example usage:
+#
+# scenario_config.py --export_scenarios -l cxx -f cxx_scenario_ -r '.*' \
+#     --category=scalable
+#
+# scenario_config.py --count_scenarios
+#
+# scenario_config.py --count_scenarios --category=scalable
+#
+# For usage of the language config output, see loadtest_config.py.
 
+import argparse
+import collections
 import json
 import re
-import scenario_config
 import sys
 
+from typing import Any, Callable, Dict, Iterable, NamedTuple
+
+import scenario_config
+
+# Language parameters for load test config generation.
+LanguageConfig = NamedTuple('LanguageConfig', [('category', str),
+                                               ('language', str),
+                                               ('client_language', str),
+                                               ('server_language', str)])
+
+
+def as_dict_no_empty_values(self):
+    """Returns the parameters as a dictionary, ignoring empty values."""
+    return dict((item for item in self._asdict().items() if item[1]))
+
+
+def category_string(categories: Iterable[str], category: str) -> str:
+    """Converts a list of categories into a single string for counting."""
+    if category != 'all':
+        return category if category in categories else ''
+
+    main_categories = ('scalable', 'smoketest')
+    s = set(categories)
+
+    c = [m for m in main_categories if m in s]
+    s.difference_update(main_categories)
+    c.extend(s)
+    return ' '.join(c)
 
-def get_json_scenarios(language_name, scenario_name_regex='.*', category='all'):
-    """Returns list of scenarios that match given constraints."""
-    result = []
-    scenarios = scenario_config.LANGUAGES[language_name].scenarios()
-    for scenario_json in scenarios:
-        if re.search(scenario_name_regex, scenario_json['name']):
-            # if the 'CATEGORIES' key is missing, treat scenario as part of 'scalable' and 'smoketest'
-            # this matches the behavior of run_performance_tests.py
-            scenario_categories = scenario_json.get('CATEGORIES',
-                                                    ['scalable', 'smoketest'])
-            # TODO(jtattermusch): consider adding filtering for 'CLIENT_LANGUAGE' and 'SERVER_LANGUAGE'
-            # fields, before the get stripped away.
-            if category in scenario_categories or category == 'all':
-                scenario_json_stripped = scenario_config.remove_nonproto_fields(
-                    scenario_json)
-                result.append(scenario_json_stripped)
-    return result
-
-
-def dump_to_json_files(json_scenarios, filename_prefix='scenario_dump_'):
-    """Dump a list of json scenarios to json files"""
-    for scenario in json_scenarios:
-        filename = "%s%s.json" % (filename_prefix, scenario['name'])
-        print('Writing file %s' % filename, file=sys.stderr)
+
+def gen_scenario_languages(category: str) -> Iterable[LanguageConfig]:
+    """Generates tuples containing the languages specified in each scenario."""
+    for language in scenario_config.LANGUAGES:
+        for scenario in scenario_config.LANGUAGES[language].scenarios():
+            client_language = scenario.get('CLIENT_LANGUAGE', '')
+            server_language = scenario.get('SERVER_LANGUAGE', '')
+            categories = scenario.get('CATEGORIES', [])
+            if category != 'all' and category not in categories:
+                continue
+            cat = category_string(categories, category)
+            yield LanguageConfig(category=cat,
+                                 language=language,
+                                 client_language=client_language,
+                                 server_language=server_language)
+
+
+def scenario_filter(
+    scenario_name_regex: str = '.*',
+    category: str = 'all',
+    client_language: str = '',
+    server_language: str = '',
+) -> Callable[[Dict[str, Any]], bool]:
+    """Returns a function to filter scenarios to process."""
+
+    def filter_scenario(scenario: Dict[str, Any]) -> bool:
+        """Filters scenarios that match specified criteria."""
+        if not re.search(scenario_name_regex, scenario["name"]):
+            return False
+        # if the 'CATEGORIES' key is missing, treat scenario as part of
+        # 'scalable' and 'smoketest'. This matches the behavior of
+        # run_performance_tests.py.
+        scenario_categories = scenario.get('CATEGORIES',
+                                           ['scalable', 'smoketest'])
+        if category not in scenario_categories and category != 'all':
+            return False
+
+        scenario_client_language = scenario.get('CLIENT_LANGUAGE', '')
+        if client_language != scenario_client_language:
+            return False
+
+        scenario_server_language = scenario.get('SERVER_LANGUAGE', '')
+        if server_language != scenario_server_language:
+            return False
+
+        return True
+
+    return filter_scenario
+
+
+def gen_scenarios(
+    language_name: str, scenario_filter_function: Callable[[Dict[str, Any]],
+                                                           bool]
+) -> Iterable[Dict[str, Any]]:
+    """Generates scenarios that match a given filter function."""
+    return map(
+        scenario_config.remove_nonproto_fields,
+        filter(scenario_filter_function,
+               scenario_config.LANGUAGES[language_name].scenarios()))
+
+
+def dump_to_json_files(scenarios: Iterable[Dict[str, Any]],
+                       filename_prefix: str) -> None:
+    """Dumps a list of scenarios to JSON files"""
+    count = 0
+    for scenario in scenarios:
+        filename = '{}{}.json'.format(filename_prefix, scenario['name'])
+        print('Writing file {}'.format(filename), file=sys.stderr)
         with open(filename, 'w') as outfile:
-            # the dump file should have {"scenarios" : []} as the top level element
+            # The dump file should have {"scenarios" : []} as the top level
+            # element, when embedded in a LoadTest configuration YAML file.
             json.dump({'scenarios': [scenario]}, outfile, indent=2)
+        count += 1
+    print('Wrote {} scenarios'.format(count), file=sys.stderr)
+
+
+def main() -> None:
+    language_choices = sorted(scenario_config.LANGUAGES.keys())
+    argp = argparse.ArgumentParser(description='Exports scenarios to files.')
+    argp.add_argument('--export_scenarios',
+                      action='store_true',
+                      help='Export scenarios to JSON files.')
+    argp.add_argument('--count_scenarios',
+                      action='store_true',
+                      help='Count scenarios for all test languages.')
+    argp.add_argument('-l',
+                      '--language',
+                      choices=language_choices,
+                      help='Language to export.')
+    argp.add_argument('-f',
+                      '--filename_prefix',
+                      default='scenario_dump_',
+                      type=str,
+                      help='Prefix for exported JSON file names.')
+    argp.add_argument('-r',
+                      '--regex',
+                      default='.*',
+                      type=str,
+                      help='Regex to select scenarios to run.')
+    argp.add_argument(
+        '--category',
+        default='all',
+        choices=['all', 'inproc', 'scalable', 'smoketest', 'sweep'],
+        help='Select scenarios for a category of tests.')
+    argp.add_argument(
+        '--client_language',
+        default='',
+        choices=language_choices,
+        help='Select only scenarios with a specified client language.')
+    argp.add_argument(
+        '--server_language',
+        default='',
+        choices=language_choices,
+        help='Select only scenarios with a specified server language.')
+    args = argp.parse_args()
+
+    if args.export_scenarios and not args.language:
+        print('Dumping scenarios requires a specified language.',
+              file=sys.stderr)
+        argp.print_usage(file=sys.stderr)
+        return
+
+    if args.export_scenarios:
+        s_filter = scenario_filter(scenario_name_regex=args.regex,
+                                   category=args.category,
+                                   client_language=args.client_language,
+                                   server_language=args.server_language)
+        scenarios = gen_scenarios(args.language, s_filter)
+        dump_to_json_files(scenarios, args.filename_prefix)
+
+    if args.count_scenarios:
+        print('Scenario count for all languages (category: {}):'.format(
+            args.category))
+        print('{:>5}  {:16} {:8} {:8} {}'.format('Count', 'Language', 'Client',
+                                                 'Server', 'Categories'))
+        c = collections.Counter(gen_scenario_languages(args.category))
+        total = 0
+        for ((cat, l, cl, sl), count) in c.most_common():
+            print('{count:5}  {l:16} {cl:8} {sl:8} {cat}'.format(l=l,
+                                                                 cl=cl,
+                                                                 sl=sl,
+                                                                 count=count,
+                                                                 cat=cat))
+            total += count
+
+        print('\n{:>5}  total scenarios (category: {})'.format(
+            total, args.category))
 
 
 if __name__ == "__main__":
-    # example usage: extract C# scenarios and dump them as .json files
-    scenarios = get_json_scenarios('csharp',
-                                   scenario_name_regex='.*',
-                                   category='scalable')
-    dump_to_json_files(scenarios, 'scenario_dump_')
+    main()
diff --git a/tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml b/tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml
new file mode 100644 (file)
index 0000000..fb1d633
--- /dev/null
@@ -0,0 +1,259 @@
+# Template generated from load test configurations by loadtest_template.py.
+#
+# Configuration templates contain client and server configurations for multiple
+# languages, and may contain template substitution keys. These templates are
+# used to generate load test configurations by selecting clients and servers for
+# the required languages. The source files for template generation may be load
+# test configurations or load test configuration templates. Load test
+# configuration generation is performed by loadtest_config.py. See documentation
+# below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md
+apiVersion: e2etest.grpc.io/v1
+kind: LoadTest
+metadata:
+  name: basic_all_languages
+spec:
+  clients:
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: csharp
+      pool: ${client_pool}
+      run:
+        args:
+          - exec
+          - qps_worker/Grpc.IntegrationTesting.QpsWorker.dll
+        command:
+          - dotnet
+    - build:
+        args:
+          - build
+          - //test/cpp/qps:qps_worker
+        command:
+          - bazel
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: cxx
+      pool: ${client_pool}
+      run:
+        command:
+          - bazel-bin/test/cpp/qps/qps_worker
+    - build:
+        args:
+          - build
+          - -o
+          - /src/workspace/bin/worker
+          - ./benchmark/worker
+        command:
+          - go
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-go.git
+      language: go
+      pool: ${client_pool}
+      run:
+        command:
+          - /src/workspace/bin/worker
+    - build:
+        args:
+          - -PskipAndroid=true
+          - -PskipCodegen=true
+          - :grpc-benchmarks:installDist
+        command:
+          - gradle
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-java.git
+      language: java
+      pool: ${client_pool}
+      run:
+        command:
+          - benchmarks/build/install/grpc-benchmarks/bin/benchmark_worker
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-node.git
+      language: node
+      pool: ${client_pool}
+      run:
+        args:
+          - -r
+          - ./test/fixtures/native_native.js
+          - test/performance/worker.js
+          - --benchmark_impl=grpc
+        command:
+          - node
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: php
+      pool: ${client_pool}
+      run:
+        command:
+          - bash
+          - /run_scripts/run_worker.sh
+    - build:
+        args:
+          - build
+          - //src/python/grpcio_tests/tests/qps:qps_worker
+        command:
+          - bazel
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: python
+      pool: ${client_pool}
+      run:
+        command:
+          - bazel-bin/src/python/grpcio_tests/tests/qps/qps_worker
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc
+      language: ruby
+      pool: ${client_pool}
+      run:
+        args:
+          - src/ruby/qps/worker.rb
+        command:
+          - ruby
+  results:
+    bigQueryTable: ${big_query_table}
+  servers:
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: csharp
+      pool: ${server_pool}
+      run:
+        args:
+          - exec
+          - qps_worker/Grpc.IntegrationTesting.QpsWorker.dll
+        command:
+          - dotnet
+    - build:
+        args:
+          - build
+          - //test/cpp/qps:qps_worker
+        command:
+          - bazel
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: cxx
+      pool: ${server_pool}
+      run:
+        args:
+          - --server_port=10010
+        command:
+          - bazel-bin/test/cpp/qps/qps_worker
+    - build:
+        args:
+          - build
+          - -o
+          - /src/workspace/bin/worker
+          - ./benchmark/worker
+        command:
+          - go
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-go.git
+      language: go
+      pool: ${server_pool}
+      run:
+        command:
+          - /src/workspace/bin/worker
+    - build:
+        args:
+          - -PskipAndroid=true
+          - -PskipCodegen=true
+          - :grpc-benchmarks:installDist
+        command:
+          - gradle
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-java.git
+      language: java
+      pool: ${server_pool}
+      run:
+        command:
+          - benchmarks/build/install/grpc-benchmarks/bin/benchmark_worker
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-node.git
+      language: node
+      pool: ${server_pool}
+      run:
+        args:
+          - -r
+          - ./test/fixtures/native_native.js
+          - test/performance/worker.js
+          - --benchmark_impl=grpc
+        command:
+          - node
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: php
+      pool: ${server_pool}
+      run:
+        command:
+          - bash
+          - /run_scripts/run_worker.sh
+    - build:
+        args:
+          - build
+          - //src/python/grpcio_tests/tests/qps:qps_worker
+        command:
+          - bazel
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: python
+      pool: ${server_pool}
+      run:
+        command:
+          - bazel-bin/src/python/grpcio_tests/tests/qps/qps_worker
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc
+      language: ruby
+      pool: ${server_pool}
+      run:
+        args:
+          - src/ruby/qps/worker.rb
+        command:
+          - ruby
+  timeoutSeconds: ${timeout_seconds}
+  ttlSeconds: 86400
index 1fd6f8a..c8574ad 100644 (file)
@@ -87,6 +87,7 @@ _ALLOWLIST_DICT = {
     '^test/distrib/python/': [_PYTHON_TEST_SUITE],
     '^test/distrib/ruby/': [_RUBY_TEST_SUITE],
     '^tools/run_tests/xds_k8s_test_driver/': [],
+    '^tools/internal_ci/linux/grpc_xds_k8s.*': [],
     '^vsprojects/': [_WINDOWS_TEST_SUITE],
     'composer\.json$': [_PHP_TEST_SUITE],
     'config\.m4$': [_PHP_TEST_SUITE],
index 76b7ade..7743df1 100755 (executable)
@@ -30,8 +30,8 @@ import tempfile
 import time
 import uuid
 
-from google.protobuf import json_format
 from oauth2client.client import GoogleCredentials
+from google.protobuf import json_format
 
 import python_utils.jobset as jobset
 import python_utils.report_utils as report_utils
@@ -64,6 +64,13 @@ logger.handlers = []
 logger.addHandler(console_handler)
 logger.setLevel(logging.WARNING)
 
+# Suppress excessive logs for gRPC Python
+original_grpc_trace = os.environ.pop('GRPC_TRACE', None)
+original_grpc_verbosity = os.environ.pop('GRPC_VERBOSITY', None)
+# Suppress not-essential logs for GCP clients
+logging.getLogger('google_auth_httplib2').setLevel(logging.WARNING)
+logging.getLogger('googleapiclient.discovery').setLevel(logging.WARNING)
+
 _TEST_CASES = [
     'backends_restart',
     'change_backend_service',
@@ -77,6 +84,9 @@ _TEST_CASES = [
     'traffic_splitting',
     'path_matching',
     'header_matching',
+    'forwarding_rule_port_match',
+    'forwarding_rule_default_port',
+    'metadata_filter',
 ]
 
 # Valid test cases, but not in all. So the tests can only run manually, and
@@ -88,6 +98,7 @@ _ADDITIONAL_TEST_CASES = [
     'timeout',
     'fault_injection',
     'csds',
+    'api_listener',  # TODO(b/187352987) Relieve quota pressure
 ]
 
 # Test cases that require the V3 API.  Skipped in older runs.
@@ -207,8 +218,9 @@ argp.add_argument(
 argp.add_argument('--network',
                   default='global/networks/default',
                   help='GCP network to use')
+_DEFAULT_PORT_RANGE = '8080:8280'
 argp.add_argument('--service_port_range',
-                  default='8080:8280',
+                  default=_DEFAULT_PORT_RANGE,
                   type=parse_port_range,
                   help='Listening port for created gRPC backends. Specified as '
                   'either a single int or as a range in the format min:max, in '
@@ -267,14 +279,23 @@ CLIENT_HOSTS = []
 if args.client_hosts:
     CLIENT_HOSTS = args.client_hosts.split(',')
 
+# Each of the config propagation in the control plane should finish within 600s.
+# Otherwise, it indicates a bug in the control plane. The config propagation
+# includes all kinds of traffic config update, like updating urlMap, creating
+# the resources for the first time, updating BackendService, and changing the
+# status of endpoints in BackendService.
+_WAIT_FOR_URL_MAP_PATCH_SEC = 600
+# In general, fetching load balancing stats only takes ~10s. However, slow
+# config update could lead to empty EDS or similar symptoms causing the
+# connection to hang for a long period of time. So, we want to extend the stats
+# wait time to be the same as urlMap patch time.
+_WAIT_FOR_STATS_SEC = _WAIT_FOR_URL_MAP_PATCH_SEC
+
 _DEFAULT_SERVICE_PORT = 80
 _WAIT_FOR_BACKEND_SEC = args.wait_for_backend_sec
 _WAIT_FOR_OPERATION_SEC = 1200
 _INSTANCE_GROUP_SIZE = args.instance_group_size
 _NUM_TEST_RPCS = 10 * args.qps
-_WAIT_FOR_STATS_SEC = 360
-_WAIT_FOR_VALID_CONFIG_SEC = 60
-_WAIT_FOR_URL_MAP_PATCH_SEC = 300
 _CONNECTION_TIMEOUT_SEC = 60
 _GCP_API_RETRIES = 5
 _BOOTSTRAP_TEMPLATE = """
@@ -282,7 +303,8 @@ _BOOTSTRAP_TEMPLATE = """
   "node": {{
     "id": "{node_id}",
     "metadata": {{
-      "TRAFFICDIRECTOR_NETWORK_NAME": "%s"
+      "TRAFFICDIRECTOR_NETWORK_NAME": "%s",
+      "com.googleapis.trafficdirector.config_time_trace": "TRUE"
     }},
     "locality": {{
       "zone": "%s"
@@ -348,7 +370,8 @@ def get_client_stats(num_rpcs, timeout_sec):
             response = stub.GetClientStats(request,
                                            wait_for_ready=True,
                                            timeout=rpc_timeout)
-            logger.debug('Invoked GetClientStats RPC to %s: %s', host, response)
+            logger.debug('Invoked GetClientStats RPC to %s: %s', host,
+                         json_format.MessageToJson(response))
             return response
 
 
@@ -470,6 +493,21 @@ def wait_until_all_rpcs_go_to_given_backends(backends,
                                    allow_failures=False)
 
 
+def wait_until_no_rpcs_go_to_given_backends(backends, timeout_sec):
+    start_time = time.time()
+    while time.time() - start_time <= timeout_sec:
+        stats = get_client_stats(_NUM_TEST_RPCS, timeout_sec)
+        error_msg = None
+        rpcs_by_peer = stats.rpcs_by_peer
+        for backend in backends:
+            if backend in rpcs_by_peer:
+                error_msg = 'Unexpected backend %s receives load' % backend
+                break
+        if not error_msg:
+            return
+    raise Exception('Unexpected RPCs going to given backends')
+
+
 def wait_until_rpcs_in_flight(rpc_type, timeout_sec, num_rpcs, threshold):
     '''Block until the test client reaches the state with the given number
     of RPCs being outstanding stably.
@@ -942,6 +980,303 @@ def prepare_services_for_urlmap_tests(gcp, original_backend_service,
     return original_backend_instances, alternate_backend_instances
 
 
+def test_metadata_filter(gcp, original_backend_service, instance_group,
+                         alternate_backend_service, same_zone_instance_group):
+    logger.info("Running test_metadata_filter")
+    wait_for_healthy_backends(gcp, original_backend_service, instance_group)
+    original_backend_instances = get_instance_names(gcp, instance_group)
+    alternate_backend_instances = get_instance_names(gcp,
+                                                     same_zone_instance_group)
+    patch_backend_service(gcp, alternate_backend_service,
+                          [same_zone_instance_group])
+    wait_for_healthy_backends(gcp, alternate_backend_service,
+                              same_zone_instance_group)
+    try:
+        with open(bootstrap_path) as f:
+            md = json.load(f)['node']['metadata']
+            match_labels = []
+            for k, v in md.items():
+                match_labels.append({'name': k, 'value': v})
+
+        not_match_labels = [{'name': 'fake', 'value': 'fail'}]
+        test_route_rules = [
+            # test MATCH_ALL
+            [
+                {
+                    'priority': 0,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ALL',
+                            'filterLabels': not_match_labels
+                        }]
+                    }],
+                    'service': original_backend_service.url
+                },
+                {
+                    'priority': 1,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ALL',
+                            'filterLabels': match_labels
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                },
+            ],
+            # test mixing MATCH_ALL and MATCH_ANY
+            # test MATCH_ALL: super set labels won't match
+            [
+                {
+                    'priority': 0,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ALL',
+                            'filterLabels': not_match_labels + match_labels
+                        }]
+                    }],
+                    'service': original_backend_service.url
+                },
+                {
+                    'priority': 1,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ANY',
+                            'filterLabels': not_match_labels + match_labels
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                },
+            ],
+            # test MATCH_ANY
+            [
+                {
+                    'priority': 0,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ANY',
+                            'filterLabels': not_match_labels
+                        }]
+                    }],
+                    'service': original_backend_service.url
+                },
+                {
+                    'priority': 1,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ANY',
+                            'filterLabels': not_match_labels + match_labels
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                },
+            ],
+            # test match multiple route rules
+            [
+                {
+                    'priority': 0,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ANY',
+                            'filterLabels': match_labels
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                },
+                {
+                    'priority': 1,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ALL',
+                            'filterLabels': match_labels
+                        }]
+                    }],
+                    'service': original_backend_service.url
+                },
+            ]
+        ]
+
+        for route_rules in test_route_rules:
+            wait_until_all_rpcs_go_to_given_backends(original_backend_instances,
+                                                     _WAIT_FOR_STATS_SEC)
+            patch_url_map_backend_service(gcp,
+                                          original_backend_service,
+                                          route_rules=route_rules)
+            wait_until_no_rpcs_go_to_given_backends(original_backend_instances,
+                                                    _WAIT_FOR_STATS_SEC)
+            wait_until_all_rpcs_go_to_given_backends(
+                alternate_backend_instances, _WAIT_FOR_STATS_SEC)
+            patch_url_map_backend_service(gcp, original_backend_service)
+    finally:
+        patch_backend_service(gcp, alternate_backend_service, [])
+
+
+def test_api_listener(gcp, backend_service, instance_group,
+                      alternate_backend_service):
+    logger.info("Running api_listener")
+    try:
+        wait_for_healthy_backends(gcp, backend_service, instance_group)
+        backend_instances = get_instance_names(gcp, instance_group)
+        wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                 _WAIT_FOR_STATS_SEC)
+        # create a second suite of map+tp+fr with the same host name in host rule
+        # and we have to disable proxyless validation because it needs `0.0.0.0`
+        # ip address in fr for proxyless and also we violate ip:port uniqueness
+        # for test purpose. See https://github.com/grpc/grpc-java/issues/8009
+        new_config_suffix = '2'
+        create_url_map(gcp, url_map_name + new_config_suffix, backend_service,
+                       service_host_name)
+        create_target_proxy(gcp, target_proxy_name + new_config_suffix, False)
+        if not gcp.service_port:
+            raise Exception(
+                'Faied to find a valid port for the forwarding rule')
+        potential_ip_addresses = []
+        max_attempts = 10
+        for i in range(max_attempts):
+            potential_ip_addresses.append('10.10.10.%d' %
+                                          (random.randint(0, 255)))
+        create_global_forwarding_rule(gcp,
+                                      forwarding_rule_name + new_config_suffix,
+                                      [gcp.service_port],
+                                      potential_ip_addresses)
+        if gcp.service_port != _DEFAULT_SERVICE_PORT:
+            patch_url_map_host_rule_with_port(gcp,
+                                              url_map_name + new_config_suffix,
+                                              backend_service,
+                                              service_host_name)
+        wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                 _WAIT_FOR_STATS_SEC)
+
+        delete_global_forwarding_rule(gcp, forwarding_rule_name)
+        delete_target_proxy(gcp, target_proxy_name)
+        delete_url_map(gcp, url_map_name)
+        verify_attempts = int(_WAIT_FOR_URL_MAP_PATCH_SEC / _NUM_TEST_RPCS *
+                              args.qps)
+        for i in range(verify_attempts):
+            wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                     _WAIT_FOR_STATS_SEC)
+        # delete host rule for the original host name
+        patch_url_map_backend_service(gcp, alternate_backend_service)
+        wait_until_no_rpcs_go_to_given_backends(backend_instances,
+                                                _WAIT_FOR_STATS_SEC)
+
+    finally:
+        delete_global_forwarding_rule(gcp,
+                                      forwarding_rule_name + new_config_suffix)
+        delete_target_proxy(gcp, target_proxy_name + new_config_suffix)
+        delete_url_map(gcp, url_map_name + new_config_suffix)
+        create_url_map(gcp, url_map_name, backend_service, service_host_name)
+        create_target_proxy(gcp, target_proxy_name)
+        create_global_forwarding_rule(gcp, forwarding_rule_name,
+                                      potential_service_ports)
+        if gcp.service_port != _DEFAULT_SERVICE_PORT:
+            patch_url_map_host_rule_with_port(gcp, url_map_name,
+                                              backend_service,
+                                              service_host_name)
+            server_uri = service_host_name + ':' + str(gcp.service_port)
+        else:
+            server_uri = service_host_name
+        return server_uri
+
+
+def test_forwarding_rule_port_match(gcp, backend_service, instance_group):
+    logger.info("Running test_forwarding_rule_port_match")
+    try:
+        wait_for_healthy_backends(gcp, backend_service, instance_group)
+        backend_instances = get_instance_names(gcp, instance_group)
+        wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                 _WAIT_FOR_STATS_SEC)
+        delete_global_forwarding_rule(gcp)
+        create_global_forwarding_rule(gcp, forwarding_rule_name, [
+            x for x in parse_port_range(_DEFAULT_PORT_RANGE)
+            if x != gcp.service_port
+        ])
+        wait_until_no_rpcs_go_to_given_backends(backend_instances,
+                                                _WAIT_FOR_STATS_SEC)
+    finally:
+        delete_global_forwarding_rule(gcp)
+        create_global_forwarding_rule(gcp, forwarding_rule_name,
+                                      potential_service_ports)
+        if gcp.service_port != _DEFAULT_SERVICE_PORT:
+            patch_url_map_host_rule_with_port(gcp, url_map_name,
+                                              backend_service,
+                                              service_host_name)
+            server_uri = service_host_name + ':' + str(gcp.service_port)
+        else:
+            server_uri = service_host_name
+        return server_uri
+
+
+def test_forwarding_rule_default_port(gcp, backend_service, instance_group):
+    logger.info("Running test_forwarding_rule_default_port")
+    try:
+        wait_for_healthy_backends(gcp, backend_service, instance_group)
+        backend_instances = get_instance_names(gcp, instance_group)
+        if gcp.service_port == _DEFAULT_SERVICE_PORT:
+            wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                     _WAIT_FOR_STATS_SEC)
+            delete_global_forwarding_rule(gcp)
+            create_global_forwarding_rule(gcp, forwarding_rule_name,
+                                          parse_port_range(_DEFAULT_PORT_RANGE))
+            patch_url_map_host_rule_with_port(gcp, url_map_name,
+                                              backend_service,
+                                              service_host_name)
+        wait_until_no_rpcs_go_to_given_backends(backend_instances,
+                                                _WAIT_FOR_STATS_SEC)
+        # expect success when no port in client request service uri, and no port in url-map
+        delete_global_forwarding_rule(gcp)
+        delete_target_proxy(gcp)
+        delete_url_map(gcp)
+        create_url_map(gcp, url_map_name, backend_service, service_host_name)
+        create_target_proxy(gcp, gcp.target_proxy.name, False)
+        potential_ip_addresses = []
+        max_attempts = 10
+        for i in range(max_attempts):
+            potential_ip_addresses.append('10.10.10.%d' %
+                                          (random.randint(0, 255)))
+        create_global_forwarding_rule(gcp, forwarding_rule_name, [80],
+                                      potential_ip_addresses)
+        wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                 _WAIT_FOR_STATS_SEC)
+
+        # expect failure when no port in client request uri, but specify port in url-map
+        patch_url_map_host_rule_with_port(gcp, url_map_name, backend_service,
+                                          service_host_name)
+        wait_until_no_rpcs_go_to_given_backends(backend_instances,
+                                                _WAIT_FOR_STATS_SEC)
+    finally:
+        delete_global_forwarding_rule(gcp)
+        delete_target_proxy(gcp)
+        delete_url_map(gcp)
+        create_url_map(gcp, url_map_name, backend_service, service_host_name)
+        create_target_proxy(gcp, target_proxy_name)
+        create_global_forwarding_rule(gcp, forwarding_rule_name,
+                                      potential_service_ports)
+        if gcp.service_port != _DEFAULT_SERVICE_PORT:
+            patch_url_map_host_rule_with_port(gcp, url_map_name,
+                                              backend_service,
+                                              service_host_name)
+            server_uri = service_host_name + ':' + str(gcp.service_port)
+        else:
+            server_uri = service_host_name
+        return server_uri
+
+
 def test_traffic_splitting(gcp, original_backend_service, instance_group,
                            alternate_backend_service, same_zone_instance_group):
     # This test start with all traffic going to original_backend_service. Then
@@ -1533,58 +1868,59 @@ def test_timeout(gcp, original_backend_service, instance_group):
     # A list of tuples (testcase_name, {client_config}, {expected_results})
     test_cases = [
         (
-            'app_timeout_exceeded',
-            # UnaryCall only with sleep-2; timeout=1s; calls timeout.
+            'timeout_exceeded (UNARY_CALL), timeout_different_route (EMPTY_CALL)',
+            # UnaryCall and EmptyCall both sleep-4.
+            # UnaryCall timeouts, EmptyCall succeeds.
             {
                 'rpc_types': [
                     messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
+                    messages_pb2.ClientConfigureRequest.RpcType.EMPTY_CALL,
                 ],
                 'metadata': [
                     (messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
-                     'rpc-behavior', 'sleep-2'),
+                     'rpc-behavior', 'sleep-4'),
+                    (messages_pb2.ClientConfigureRequest.RpcType.EMPTY_CALL,
+                     'rpc-behavior', 'sleep-4'),
                 ],
-                'timeout_sec': 1,
             },
             {
                 'UNARY_CALL': 4,  # DEADLINE_EXCEEDED
+                'EMPTY_CALL': 0,
             },
         ),
         (
-            'timeout_not_exceeded',
-            # UnaryCall only with no sleep; calls succeed.
+            'app_timeout_exceeded',
+            # UnaryCall only with sleep-2; timeout=1s; calls timeout.
             {
                 'rpc_types': [
                     messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
                 ],
+                'metadata': [
+                    (messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
+                     'rpc-behavior', 'sleep-2'),
+                ],
+                'timeout_sec': 1,
             },
             {
-                'UNARY_CALL': 0,
+                'UNARY_CALL': 4,  # DEADLINE_EXCEEDED
             },
         ),
         (
-            'timeout_exceeded (UNARY_CALL), timeout_different_route (EMPTY_CALL)',
-            # UnaryCall and EmptyCall both sleep-4.
-            # UnaryCall timeouts, EmptyCall succeeds.
+            'timeout_not_exceeded',
+            # UnaryCall only with no sleep; calls succeed.
             {
                 'rpc_types': [
                     messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
-                    messages_pb2.ClientConfigureRequest.RpcType.EMPTY_CALL,
-                ],
-                'metadata': [
-                    (messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
-                     'rpc-behavior', 'sleep-4'),
-                    (messages_pb2.ClientConfigureRequest.RpcType.EMPTY_CALL,
-                     'rpc-behavior', 'sleep-4'),
                 ],
             },
             {
-                'UNARY_CALL': 4,  # DEADLINE_EXCEEDED
-                'EMPTY_CALL': 0,
+                'UNARY_CALL': 0,
             },
-        ),
+        )
     ]
 
     try:
+        first_case = True
         for (testcase_name, client_config, expected_results) in test_cases:
             logger.info('starting case %s', testcase_name)
             configure_client(**client_config)
@@ -1596,6 +1932,9 @@ def test_timeout(gcp, original_backend_service, instance_group):
             # Each attempt takes 10 seconds; 20 attempts is equivalent to 200
             # second timeout.
             attempt_count = 20
+            if first_case:
+                attempt_count = 120
+                first_case = False
             before_stats = get_client_accumulated_stats()
             if not before_stats.stats_per_method:
                 raise ValueError(
@@ -1899,6 +2238,31 @@ def test_csds(gcp, original_backend_service, instance_group, server_uri):
                        test_csds_timeout_s)
 
 
+def maybe_write_sponge_properties():
+    """Writing test infos to enable more advanced testgrid searches."""
+    if 'KOKORO_ARTIFACTS_DIR' not in os.environ:
+        return
+    if 'GIT_ORIGIN_URL' not in os.environ:
+        return
+    if 'GIT_COMMIT_SHORT' not in os.environ:
+        return
+    properties = [
+        # Technically, 'TESTS_FORMAT_VERSION' is not required for run_xds_tests.
+        # We keep it here so one day we may merge the process of writing sponge
+        # properties.
+        'TESTS_FORMAT_VERSION,2',
+        'TESTGRID_EXCLUDE,%s' % os.environ.get('TESTGRID_EXCLUDE', 0),
+        'GIT_ORIGIN_URL,%s' % os.environ['GIT_ORIGIN_URL'],
+        'GIT_COMMIT_SHORT,%s' % os.environ['GIT_COMMIT_SHORT'],
+    ]
+    logger.info('Writing Sponge configs: %s', properties)
+    with open(
+            os.path.join(os.environ['KOKORO_ARTIFACTS_DIR'],
+                         "custom_sponge_config.csv"), 'w') as f:
+        f.write("\n".join(properties))
+        f.write("\n")
+
+
 def set_validate_for_proxyless(gcp, validate_for_proxyless):
     if not gcp.alpha_compute:
         logger.debug(
@@ -2166,34 +2530,39 @@ def create_target_proxy(gcp, name, validate_for_proxyless=True):
     gcp.target_proxy = GcpResource(config['name'], result['targetLink'])
 
 
-def create_global_forwarding_rule(gcp, name, potential_ports):
+def create_global_forwarding_rule(gcp,
+                                  name,
+                                  potential_ports,
+                                  potential_ip_addresses=['0.0.0.0']):
     if gcp.alpha_compute:
         compute_to_use = gcp.alpha_compute
     else:
         compute_to_use = gcp.compute
     for port in potential_ports:
-        try:
-            config = {
-                'name': name,
-                'loadBalancingScheme': 'INTERNAL_SELF_MANAGED',
-                'portRange': str(port),
-                'IPAddress': '0.0.0.0',
-                'network': args.network,
-                'target': gcp.target_proxy.url,
-            }
-            logger.debug('Sending GCP request with body=%s', config)
-            result = compute_to_use.globalForwardingRules().insert(
-                project=gcp.project,
-                body=config).execute(num_retries=_GCP_API_RETRIES)
-            wait_for_global_operation(gcp, result['name'])
-            gcp.global_forwarding_rule = GcpResource(config['name'],
-                                                     result['targetLink'])
-            gcp.service_port = port
-            return
-        except googleapiclient.errors.HttpError as http_error:
-            logger.warning(
-                'Got error %s when attempting to create forwarding rule to '
-                '0.0.0.0:%d. Retrying with another port.' % (http_error, port))
+        for ip_address in potential_ip_addresses:
+            try:
+                config = {
+                    'name': name,
+                    'loadBalancingScheme': 'INTERNAL_SELF_MANAGED',
+                    'portRange': str(port),
+                    'IPAddress': ip_address,
+                    'network': args.network,
+                    'target': gcp.target_proxy.url,
+                }
+                logger.debug('Sending GCP request with body=%s', config)
+                result = compute_to_use.globalForwardingRules().insert(
+                    project=gcp.project,
+                    body=config).execute(num_retries=_GCP_API_RETRIES)
+                wait_for_global_operation(gcp, result['name'])
+                gcp.global_forwarding_rule = GcpResource(
+                    config['name'], result['targetLink'])
+                gcp.service_port = port
+                return
+            except googleapiclient.errors.HttpError as http_error:
+                logger.warning(
+                    'Got error %s when attempting to create forwarding rule to '
+                    '%s:%d. Retrying with another port.' %
+                    (http_error, ip_address, port))
 
 
 def get_health_check(gcp, health_check_name):
@@ -2257,39 +2626,49 @@ def get_instance_group(gcp, zone, instance_group_name):
     return instance_group
 
 
-def delete_global_forwarding_rule(gcp):
+def delete_global_forwarding_rule(gcp, name=None):
+    if name:
+        forwarding_rule_to_delete = name
+    else:
+        forwarding_rule_to_delete = gcp.global_forwarding_rule.name
     try:
         result = gcp.compute.globalForwardingRules().delete(
             project=gcp.project,
-            forwardingRule=gcp.global_forwarding_rule.name).execute(
+            forwardingRule=forwarding_rule_to_delete).execute(
                 num_retries=_GCP_API_RETRIES)
         wait_for_global_operation(gcp, result['name'])
     except googleapiclient.errors.HttpError as http_error:
         logger.info('Delete failed: %s', http_error)
 
 
-def delete_target_proxy(gcp):
+def delete_target_proxy(gcp, name=None):
+    if name:
+        proxy_to_delete = name
+    else:
+        proxy_to_delete = gcp.target_proxy.name
     try:
         if gcp.alpha_compute:
             result = gcp.alpha_compute.targetGrpcProxies().delete(
-                project=gcp.project,
-                targetGrpcProxy=gcp.target_proxy.name).execute(
+                project=gcp.project, targetGrpcProxy=proxy_to_delete).execute(
                     num_retries=_GCP_API_RETRIES)
         else:
             result = gcp.compute.targetHttpProxies().delete(
-                project=gcp.project,
-                targetHttpProxy=gcp.target_proxy.name).execute(
+                project=gcp.project, targetHttpProxy=proxy_to_delete).execute(
                     num_retries=_GCP_API_RETRIES)
         wait_for_global_operation(gcp, result['name'])
     except googleapiclient.errors.HttpError as http_error:
         logger.info('Delete failed: %s', http_error)
 
 
-def delete_url_map(gcp):
+def delete_url_map(gcp, name=None):
+    if name:
+        url_map_to_delete = name
+    else:
+        url_map_to_delete = gcp.url_map.name
     try:
         result = gcp.compute.urlMaps().delete(
             project=gcp.project,
-            urlMap=gcp.url_map.name).execute(num_retries=_GCP_API_RETRIES)
+            urlMap=url_map_to_delete).execute(num_retries=_GCP_API_RETRIES)
         wait_for_global_operation(gcp, result['name'])
     except googleapiclient.errors.HttpError as http_error:
         logger.info('Delete failed: %s', http_error)
@@ -2600,6 +2979,7 @@ class GcpState(object):
         self.instance_groups = []
 
 
+maybe_write_sponge_properties()
 alpha_compute = None
 if args.compute_discovery_document:
     with open(args.compute_discovery_document, 'r') as discovery_doc:
@@ -2707,7 +3087,12 @@ try:
 
     if args.test_case:
         client_env = dict(os.environ)
+        if original_grpc_trace:
+            client_env['GRPC_TRACE'] = original_grpc_trace
+        if original_grpc_verbosity:
+            client_env['GRPC_VERBOSITY'] = original_grpc_verbosity
         bootstrap_server_features = []
+
         if gcp.service_port == _DEFAULT_SERVICE_PORT:
             server_uri = service_host_name
         else:
@@ -2742,6 +3127,17 @@ try:
                 logger.info('skipping test %s due to missing alpha support',
                             test_case)
                 continue
+            if test_case in [
+                    'api_listener', 'forwarding_rule_port_match',
+                    'forwarding_rule_default_port'
+            ] and CLIENT_HOSTS:
+                logger.info(
+                    'skipping test %s because test configuration is'
+                    'not compatible with client processes on existing'
+                    'client hosts', test_case)
+                continue
+            if test_case == 'forwarding_rule_default_port':
+                server_uri = service_host_name
             result = jobset.JobResult()
             log_dir = os.path.join(_TEST_LOG_BASE_DIR, test_case)
             if not os.path.exists(log_dir):
@@ -2850,6 +3246,20 @@ try:
                     test_timeout(gcp, backend_service, instance_group)
                 elif test_case == 'fault_injection':
                     test_fault_injection(gcp, backend_service, instance_group)
+                elif test_case == 'api_listener':
+                    server_uri = test_api_listener(gcp, backend_service,
+                                                   instance_group,
+                                                   alternate_backend_service)
+                elif test_case == 'forwarding_rule_port_match':
+                    server_uri = test_forwarding_rule_port_match(
+                        gcp, backend_service, instance_group)
+                elif test_case == 'forwarding_rule_default_port':
+                    server_uri = test_forwarding_rule_default_port(
+                        gcp, backend_service, instance_group)
+                elif test_case == 'metadata_filter':
+                    test_metadata_filter(gcp, backend_service, instance_group,
+                                         alternate_backend_service,
+                                         same_zone_instance_group)
                 elif test_case == 'csds':
                     test_csds(gcp, backend_service, instance_group, server_uri)
                 else:
index 5b1455c..530c5bf 100755 (executable)
@@ -24,23 +24,23 @@ cd "$(dirname "$0")/../../.."
 submodules=$(mktemp /tmp/submXXXXXX)
 want_submodules=$(mktemp /tmp/submXXXXXX)
 
-git submodule | awk '{ print $1 }' | sort > "$submodules"
-cat << EOF | awk '{ print $1 }' | sort > "$want_submodules"
- 6f9d96a1f41439ac172ee2ef7ccd8edf0e5d068c third_party/abseil-cpp (heads/master)
- 73d4d5e8d6d449fc8663765a42aa8aeeee844489 third_party/benchmark (v1.5.2)
- 73594cde8c9a52a102c4341c244c833aa61b9c06 third_party/bloaty (remotes/origin/wide-14-g73594cd)
- 1a7359455220f7010def8c63f7c7e041ce6707c6 third_party/boringssl-with-bazel (remotes/origin/master-with-bazel)
- e982924acee7f7313b4baa4ee5ec000c5e373c30 third_party/cares/cares (cares-1_15_0)
- 18b54850c9b7ba29a4ab67cbd7ed7eab7b0bbdb2 third_party/envoy-api (remotes/origin/main)
- 82944da21578a53b74e547774cf62ed31a05b841 third_party/googleapis (common-protos-1_3_1-915-g80ed4d0bb)
- c9ccac7cb7345901884aabf5d1a786cfa6e2f397 third_party/googletest (6e2f397)
- 15ae750151ac9341e5945eb38f8982d59fb99201 third_party/libuv (v1.34.0)
- 4aa53e15cbf1a47bc9087e6cfdca214c1eea4e89 third_party/opencensus-proto (v0.3.0)
- d7e943b8d2bc444a8c770644e73d090b486f8b37 third_party/protobuf (v3.15.2)
- 872b28c457822ed9c2a5405da3c33f386ac0e86f third_party/protoc-gen-validate (v0.4.1)
- aecba11114cf1fac5497aeb844b6966106de3eb6 third_party/re2 (heads/master)
- cc1b757b3eddccaaaf0743cbb107742bb7e3ee4f third_party/udpa (heads/master)
- cacf7f1d4e3d44d871b605da3b647f07d718623f third_party/zlib (v1.2.11)
+git submodule | awk '{ print $2 " " $1 }' | sort > "$submodules"
+cat << EOF | sort > "$want_submodules"
+third_party/abseil-cpp 997aaf3a28308eba1b9156aa35ab7bca9688e9f6
+third_party/benchmark 73d4d5e8d6d449fc8663765a42aa8aeeee844489
+third_party/bloaty 73594cde8c9a52a102c4341c244c833aa61b9c06
+third_party/boringssl-with-bazel 688fc5cf5428868679d2ae1072cad81055752068
+third_party/cares/cares e982924acee7f7313b4baa4ee5ec000c5e373c30
+third_party/envoy-api 18b54850c9b7ba29a4ab67cbd7ed7eab7b0bbdb2
+third_party/googleapis 82944da21578a53b74e547774cf62ed31a05b841
+third_party/googletest c9ccac7cb7345901884aabf5d1a786cfa6e2f397
+third_party/libuv 15ae750151ac9341e5945eb38f8982d59fb99201
+third_party/opencensus-proto 4aa53e15cbf1a47bc9087e6cfdca214c1eea4e89
+third_party/protobuf 436bd7880e458532901c58f4d9d1ea23fa7edd52
+third_party/protoc-gen-validate 872b28c457822ed9c2a5405da3c33f386ac0e86f
+third_party/re2 aecba11114cf1fac5497aeb844b6966106de3eb6
+third_party/udpa cc1b757b3eddccaaaf0743cbb107742bb7e3ee4f
+third_party/zlib cacf7f1d4e3d44d871b605da3b647f07d718623f
 EOF
 
 diff -u "$submodules" "$want_submodules"
index b9a9d77..aa18806 100755 (executable)
@@ -13,6 +13,9 @@
 # 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.
+"""Explicitly ban select functions from being used in src/core/**.
+
+Most of these functions have internal versions that should be used instead."""
 
 import os
 import sys
index ab18004..d54a5c5 100755 (executable)
@@ -73,6 +73,11 @@ argp.add_argument('-t',
                   default=False,
                   action='store_const',
                   const=True)
+argp.add_argument('-x',
+                  '--xml_report',
+                  default='report_taskrunner_sponge_log.xml',
+                  type=str,
+                  help='Filename for the JUnit-compatible XML report')
 
 args = argp.parse_args()
 
@@ -109,7 +114,7 @@ num_failures, resultset = jobset.run(build_jobs,
                                      newline_on_success=True,
                                      maxjobs=args.jobs)
 report_utils.render_junit_xml_report(resultset,
-                                     'report_taskrunner_sponge_log.xml',
+                                     args.xml_report,
                                      suite_name='tasks')
 if num_failures == 0:
     jobset.message('SUCCESS',
index 266f7f2..ebacd4b 100644 (file)
@@ -3,7 +3,7 @@
 Proxyless Security Mesh Interop Tests executed on Kubernetes.
 
 ### Experimental
-Work in progress. Internal APIs may and will change. Please refrain from making 
+Work in progress. Internal APIs may and will change. Please refrain from making
 changes to this codebase at the moment.
 
 ### Stabilization roadmap 
@@ -11,10 +11,11 @@ changes to this codebase at the moment.
 - [ ] Generate namespace for each test to prevent resource name conflicts and
       allow running tests in parallel
 - [ ] Security: run server and client in separate namespaces
-- [ ] Make framework.infrastructure.gcp resources [first-class citizen](https://en.wikipedia.org/wiki/First-class_citizen),
-      support simpler CRUD
-- [ ] Security: manage `roles/iam.workloadIdentityUser` role grant lifecycle
-      for dynamically-named namespaces 
+- [ ] Make framework.infrastructure.gcp resources [first-class
+      citizen](https://en.wikipedia.org/wiki/First-class_citizen), support
+      simpler CRUD
+- [ ] Security: manage `roles/iam.workloadIdentityUser` role grant lifecycle for
+      dynamically-named namespaces 
 - [ ] Restructure `framework.test_app` and `framework.xds_k8s*` into a module
       containing xDS-interop-specific logic
 - [ ] Address inline TODOs in code
@@ -25,6 +26,12 @@ changes to this codebase at the moment.
 #### Requirements
 1. Python v3.6+
 2. [Google Cloud SDK](https://cloud.google.com/sdk/docs/install)
+3. A GKE cluster (must enable "Enable VPC-native traffic routing" to use it with
+   the Traffic Director)
+    * Otherwise, you will see error logs when you inspect Kubernetes virtual
+      service
+    * (In `grpc-testing`, you will need a metadata tag
+      `--tags=allow-health-checks` to allow UHC to reach your resources.)
 
 #### Configure GKE cluster access
 
@@ -63,11 +70,16 @@ python -m grpc_tools.protoc --proto_path=../../../ \
 
 ### xDS Baseline Tests
 
-Test suite meant to confirm that basic xDS features work as expected.
-Executing it before other test suites will help to identify whether test failure
-related to specific features under test, or caused by unrelated infrastructure
+Test suite meant to confirm that basic xDS features work as expected. Executing
+it before other test suites will help to identify whether test failure related
+to specific features under test, or caused by unrelated infrastructure
 disturbances.
 
+The client and server images are created based on Git commit hashes, but not
+every single one of them. It is triggered nightly and per-release. For example,
+the commit we are using below (`d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf`) comes
+from branch `v1.37.x` in `grpc-java` repo.
+
 ```sh
 # Help
 python -m tests.baseline_test --help
@@ -77,8 +89,8 @@ python -m tests.baseline_test --helpful
 python -m tests.baseline_test \
   --flagfile="config/grpc-testing.cfg" \
   --kube_context="${KUBE_CONTEXT}" \
-  --server_image="gcr.io/grpc-testing/xds-k8s-test-server-java:latest" \
-  --client_image="gcr.io/grpc-testing/xds-k8s-test-client-java:latest" \
+  --server_image="gcr.io/grpc-testing/xds-interop/java-server:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf" \
+  --client_image="gcr.io/grpc-testing/xds-interop/java-client:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf"
 ```
 
 ### xDS Security Tests
@@ -91,6 +103,44 @@ python -m tests.security_test --helpful
 python -m tests.security_test \
   --flagfile="config/grpc-testing.cfg" \
   --kube_context="${KUBE_CONTEXT}" \
-  --server_image="gcr.io/grpc-testing/xds-k8s-test-server-java:latest" \
-  --client_image="gcr.io/grpc-testing/xds-k8s-test-client-java:latest" \
+  --server_image="gcr.io/grpc-testing/xds-interop/java-server:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf" \
+  --client_image="gcr.io/grpc-testing/xds-interop/java-client:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf"
+```
+
+### Test namespace
+
+It's possible to run multiple xDS interop test workloads in the same project.
+But we need to ensure the name of the global resources won't conflict. This can
+be solved by supplying `--namespace` and `--server_xds_port`. The xDS port needs
+to be unique across the entire project (default port range is [8080, 8280],
+avoid if possible). Here is an example:
+
+```shell
+python3 -m tests.baseline_test \
+  --flagfile="config/grpc-testing.cfg" \
+  --kube_context="${KUBE_CONTEXT}" \
+  --server_image="gcr.io/grpc-testing/xds-interop/java-server:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf" \
+  --client_image="gcr.io/grpc-testing/xds-interop/java-client:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf" \
+  --namespace="box-$(date +"%F-%R")" \
+  --server_xds_port="$(($RANDOM%1000 + 34567))"
+```
+
+### Setup test configuration
+
+There are many arguments to be passed into the test run. You can save the
+arguments to a config file for your development environment. Please take a look
+at
+https://github.com/grpc/grpc/blob/master/tools/run_tests/xds_k8s_test_driver/config/local-dev.cfg.example.
+You can create your own config by:
+
+```shell
+cp config/local-dev.cfg.example config/local-dev.cfg
+```
+
+### Clean-up resources
+
+```shell
+python -m bin.run_td_setup --cmd=cleanup --flagfile=config/local-dev.cfg && \
+python -m bin.run_test_client --cmd=cleanup --flagfile=config/local-dev.cfg && \
+python -m bin.run_test_server --cmd=cleanup --cleanup_namespace --flagfile=config/local-dev.cfg
 ```
index 248c5b6..4ea4e90 100644 (file)
@@ -30,11 +30,15 @@ retryers_logger = logging.getLogger(__name__)
 # Type aliases
 timedelta = datetime.timedelta
 Retrying = tenacity.Retrying
+RetryError = tenacity.RetryError
 _after_log = tenacity.after_log
 _before_sleep_log = tenacity.before_sleep_log
 _retry_if_exception_type = tenacity.retry_if_exception_type
+_stop_after_attempt = tenacity.stop_after_attempt
 _stop_after_delay = tenacity.stop_after_delay
+_stop_any = tenacity.stop_any
 _wait_exponential = tenacity.wait_exponential
+_wait_fixed = tenacity.wait_fixed
 
 
 def _retry_on_exceptions(retry_on_exceptions: Optional[List[Any]] = None):
@@ -61,3 +65,28 @@ def exponential_retryer_with_timeout(
                                            max=wait_max.total_seconds()),
                     stop=_stop_after_delay(timeout.total_seconds()),
                     before_sleep=_before_sleep_log(logger, log_level))
+
+
+def constant_retryer(*,
+                     wait_fixed: timedelta,
+                     attempts: int = 0,
+                     timeout: timedelta = None,
+                     retry_on_exceptions: Optional[List[Any]] = None,
+                     logger: Optional[logging.Logger] = None,
+                     log_level: Optional[int] = logging.DEBUG) -> Retrying:
+    if logger is None:
+        logger = retryers_logger
+    if log_level is None:
+        log_level = logging.DEBUG
+    if attempts < 1 and timeout is None:
+        raise ValueError('The number of attempts or the timeout must be set')
+    stops = []
+    if attempts > 0:
+        stops.append(_stop_after_attempt(attempts))
+    if timeout is not None:
+        stops.append(_stop_after_delay.total_seconds())
+
+    return Retrying(retry=_retry_on_exceptions(retry_on_exceptions),
+                    wait=_wait_fixed(wait_fixed.total_seconds()),
+                    stop=_stop_any(*stops),
+                    before_sleep=_before_sleep_log(logger, log_level))
index 6044f72..0606ba9 100644 (file)
@@ -23,6 +23,7 @@ from absl.testing import absltest
 
 from framework import xds_flags
 from framework import xds_k8s_flags
+from framework.helpers import retryers
 from framework.infrastructure import gcp
 from framework.infrastructure import k8s
 from framework.infrastructure import traffic_director
@@ -114,6 +115,15 @@ class XdsKubernetesTestCase(absltest.TestCase):
 
     def tearDown(self):
         logger.info('----- TestMethod %s teardown -----', self.id())
+        retryer = retryers.constant_retryer(wait_fixed=_timedelta(seconds=10),
+                                            attempts=3,
+                                            log_level=logging.INFO)
+        try:
+            retryer(self._cleanup)
+        except retryers.RetryError:
+            logger.exception('Got error during teardown')
+
+    def _cleanup(self):
         self.td.cleanup(force=self.force_cleanup)
         self.client_runner.cleanup(force=self.force_cleanup)
         self.server_runner.cleanup(force=self.force_cleanup,