Merge remote-tracking branch 'upstream/master' into interceptor-3

pull/18852/head
Muxi Yan 6 years ago
commit 335bc4a1c8
  1. 3
      BUILD
  2. 3
      BUILD.gn
  3. 6
      CMakeLists.txt
  4. 6
      Makefile
  5. 6
      bazel/generate_cc.bzl
  6. 8
      bazel/grpc_deps.bzl
  7. 2
      bazel/python_rules.bzl
  8. 3
      build.yaml
  9. 3
      gRPC-C++.podspec
  10. 2
      gRPC-Core.podspec
  11. 1
      grpc.gemspec
  12. 2
      grpc.gyp
  13. 1
      include/grpcpp/impl/codegen/core_codegen_interface.h
  14. 36
      include/grpcpp/support/validate_service_config.h
  15. 1
      package.xml
  16. 283
      src/core/ext/filters/client_channel/client_channel.cc
  17. 18
      src/core/ext/filters/client_channel/lb_policy.cc
  18. 160
      src/core/ext/filters/client_channel/lb_policy.h
  19. 49
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  20. 24
      src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
  21. 24
      src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
  22. 91
      src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
  23. 67
      src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
  24. 2
      src/core/ext/filters/client_channel/lb_policy_factory.h
  25. 2
      src/core/ext/filters/client_channel/lb_policy_registry.cc
  26. 2
      src/core/ext/filters/client_channel/lb_policy_registry.h
  27. 2
      src/core/ext/filters/client_channel/resolver_result_parsing.cc
  28. 6
      src/core/ext/filters/client_channel/resolver_result_parsing.h
  29. 11
      src/core/ext/filters/client_channel/resolving_lb_policy.cc
  30. 11
      src/core/ext/filters/client_channel/resolving_lb_policy.h
  31. 26
      src/core/ext/filters/client_channel/subchannel.cc
  32. 46
      src/core/ext/filters/client_channel/subchannel.h
  33. 109
      src/core/ext/filters/client_channel/subchannel_interface.h
  34. 123
      src/core/ext/transport/chttp2/transport/hpack_encoder.cc
  35. 21
      src/core/ext/transport/chttp2/transport/hpack_parser.cc
  36. 17
      src/core/ext/transport/chttp2/transport/hpack_table.cc
  37. 11
      src/core/ext/transport/chttp2/transport/hpack_table.h
  38. 5
      src/core/ext/transport/cronet/transport/cronet_transport.cc
  39. 6
      src/core/lib/iomgr/error.cc
  40. 12
      src/core/lib/iomgr/error.h
  41. 2
      src/core/lib/iomgr/iomgr.cc
  42. 3
      src/core/lib/iomgr/timer.h
  43. 2
      src/core/lib/security/credentials/plugin/plugin_credentials.cc
  44. 3
      src/core/lib/slice/slice.cc
  45. 4
      src/core/lib/slice/slice_hash_table.h
  46. 21
      src/core/lib/slice/slice_intern.cc
  47. 31
      src/core/lib/slice/slice_internal.h
  48. 2
      src/core/lib/slice/slice_string_helpers.cc
  49. 2
      src/core/lib/slice/slice_string_helpers.h
  50. 4
      src/core/lib/slice/slice_weak_hash_table.h
  51. 16
      src/core/lib/surface/call.cc
  52. 57
      src/core/lib/surface/channel.cc
  53. 66
      src/core/lib/surface/channel.h
  54. 85
      src/core/lib/surface/completion_queue.cc
  55. 3
      src/core/lib/surface/completion_queue.h
  56. 12
      src/core/lib/surface/server.cc
  57. 16
      src/core/lib/surface/validate_metadata.cc
  58. 15
      src/core/lib/surface/validate_metadata.h
  59. 82
      src/core/lib/transport/metadata.cc
  60. 161
      src/core/lib/transport/metadata.h
  61. 434
      src/core/lib/transport/static_metadata.cc
  62. 435
      src/core/lib/transport/static_metadata.h
  63. 40
      src/cpp/common/validate_service_config.cc
  64. 4
      src/cpp/thread_manager/thread_manager.h
  65. 2
      src/objective-c/GRPCClient/GRPCCall.m
  66. 22
      src/objective-c/tests/APIv2Tests/Info.plist
  67. 22
      src/objective-c/tests/ChannelTests/Info.plist
  68. 21
      src/objective-c/tests/ConfigureCronet.h
  69. 39
      src/objective-c/tests/ConfigureCronet.m
  70. 24
      src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist
  71. 10
      src/objective-c/tests/CronetTests/CoreCronetEnd2EndTests.mm
  72. 14
      src/objective-c/tests/CronetTests/CronetUnitTests.mm
  73. 4
      src/objective-c/tests/CronetTests/InteropTestsRemoteWithCronet.m
  74. 24
      src/objective-c/tests/CronetUnitTests/Info.plist
  75. 5
      src/objective-c/tests/InteropTests/InteropTests.h
  76. 15
      src/objective-c/tests/InteropTests/InteropTests.m
  77. 33
      src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.h
  78. 80
      src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.m
  79. 0
      src/objective-c/tests/InteropTests/InteropTestsLocalCleartext.m
  80. 0
      src/objective-c/tests/InteropTests/InteropTestsLocalSSL.m
  81. 291
      src/objective-c/tests/InteropTests/InteropTestsMultipleChannels.m
  82. 0
      src/objective-c/tests/InteropTests/InteropTestsRemote.m
  83. 22
      src/objective-c/tests/InteropTestsCallOptions/Info.plist
  84. 116
      src/objective-c/tests/InteropTestsCallOptions/InteropTestsCallOptions.m
  85. 22
      src/objective-c/tests/InteropTestsMultipleChannels/Info.plist
  86. 259
      src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m
  87. 24
      src/objective-c/tests/InteropTestsRemoteWithCronet/Info.plist
  88. 79
      src/objective-c/tests/Podfile
  89. 3993
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  90. 90
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme
  91. 110
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme
  92. 90
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme
  93. 101
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
  94. 60
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme
  95. 59
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme
  96. 48
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CronetTests.xcscheme
  97. 56
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CronetUnitTests.xcscheme
  98. 46
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTests.xcscheme
  99. 56
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsCallOptions.xcscheme
  100. 95
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme
  101. Some files were not shown because too many files have changed in this diff Show More

@ -137,6 +137,7 @@ GRPCXX_SRCS = [
"src/cpp/common/resource_quota_cc.cc",
"src/cpp/common/rpc_method.cc",
"src/cpp/common/version_cc.cc",
"src/cpp/common/validate_service_config.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/channel_argument_option.cc",
"src/cpp/server/create_default_thread_pool.cc",
@ -286,6 +287,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/stub_options.h",
"include/grpcpp/support/sync_stream.h",
"include/grpcpp/support/time.h",
"include/grpcpp/support/validate_service_config.h",
]
grpc_cc_library(
@ -1141,6 +1143,7 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/server_address.h",
"src/core/ext/filters/client_channel/service_config.h",
"src/core/ext/filters/client_channel/subchannel.h",
"src/core/ext/filters/client_channel/subchannel_interface.h",
"src/core/ext/filters/client_channel/subchannel_pool_interface.h",
],
language = "c++",

@ -345,6 +345,7 @@ config("grpc_config") {
"src/core/ext/filters/client_channel/service_config.h",
"src/core/ext/filters/client_channel/subchannel.cc",
"src/core/ext/filters/client_channel/subchannel.h",
"src/core/ext/filters/client_channel/subchannel_interface.h",
"src/core/ext/filters/client_channel/subchannel_pool_interface.cc",
"src/core/ext/filters/client_channel/subchannel_pool_interface.h",
"src/core/ext/filters/deadline/deadline_filter.cc",
@ -1139,6 +1140,7 @@ config("grpc_config") {
"include/grpcpp/support/stub_options.h",
"include/grpcpp/support/sync_stream.h",
"include/grpcpp/support/time.h",
"include/grpcpp/support/validate_service_config.h",
"src/core/ext/transport/inproc/inproc_transport.h",
"src/core/lib/avl/avl.h",
"src/core/lib/backoff/backoff.h",
@ -1338,6 +1340,7 @@ config("grpc_config") {
"src/cpp/common/secure_auth_context.h",
"src/cpp/common/secure_channel_arguments.cc",
"src/cpp/common/secure_create_auth_context.cc",
"src/cpp/common/validate_service_config.cc",
"src/cpp/common/version_cc.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/channel_argument_option.cc",

@ -3043,6 +3043,7 @@ add_library(grpc++
src/cpp/common/core_codegen.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/channel_argument_option.cc
@ -3218,6 +3219,7 @@ foreach(_hdr
include/grpcpp/support/stub_options.h
include/grpcpp/support/sync_stream.h
include/grpcpp/support/time.h
include/grpcpp/support/validate_service_config.h
include/grpc/support/alloc.h
include/grpc/support/atm.h
include/grpc/support/atm_gcc_atomic.h
@ -3440,6 +3442,7 @@ add_library(grpc++_cronet
src/cpp/common/core_codegen.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/channel_argument_option.cc
@ -3835,6 +3838,7 @@ foreach(_hdr
include/grpcpp/support/stub_options.h
include/grpcpp/support/sync_stream.h
include/grpcpp/support/time.h
include/grpcpp/support/validate_service_config.h
include/grpc/support/alloc.h
include/grpc/support/atm.h
include/grpc/support/atm_gcc_atomic.h
@ -4652,6 +4656,7 @@ add_library(grpc++_unsecure
src/cpp/common/core_codegen.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/channel_argument_option.cc
@ -4826,6 +4831,7 @@ foreach(_hdr
include/grpcpp/support/stub_options.h
include/grpcpp/support/sync_stream.h
include/grpcpp/support/time.h
include/grpcpp/support/validate_service_config.h
include/grpc/support/alloc.h
include/grpc/support/atm.h
include/grpc/support/atm_gcc_atomic.h

@ -5435,6 +5435,7 @@ LIBGRPC++_SRC = \
src/cpp/common/core_codegen.cc \
src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/common/validate_service_config.cc \
src/cpp/common/version_cc.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/channel_argument_option.cc \
@ -5575,6 +5576,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
include/grpc/support/alloc.h \
include/grpc/support/atm.h \
include/grpc/support/atm_gcc_atomic.h \
@ -5841,6 +5843,7 @@ LIBGRPC++_CRONET_SRC = \
src/cpp/common/core_codegen.cc \
src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/common/validate_service_config.cc \
src/cpp/common/version_cc.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/channel_argument_option.cc \
@ -6200,6 +6203,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
include/grpc/support/alloc.h \
include/grpc/support/atm.h \
include/grpc/support/atm_gcc_atomic.h \
@ -7000,6 +7004,7 @@ LIBGRPC++_UNSECURE_SRC = \
src/cpp/common/core_codegen.cc \
src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/common/validate_service_config.cc \
src/cpp/common/version_cc.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/channel_argument_option.cc \
@ -7140,6 +7145,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
include/grpc/support/alloc.h \
include/grpc/support/atm.h \
include/grpc/support/atm_gcc_atomic.h \

@ -41,11 +41,11 @@ def _join_directories(directories):
def generate_cc_impl(ctx):
"""Implementation of the generate_cc rule."""
protos = [f for src in ctx.attr.srcs for f in src.proto.check_deps_sources]
protos = [f for src in ctx.attr.srcs for f in src.proto.check_deps_sources.to_list()]
includes = [
f
for src in ctx.attr.srcs
for f in src.proto.transitive_imports
for f in src.proto.transitive_imports.to_list()
]
outs = []
proto_root = get_proto_root(
@ -128,7 +128,7 @@ def generate_cc_impl(ctx):
arguments += ["-I{0}".format(f + "/../..")]
well_known_proto_files = [
f
for f in ctx.attr.well_known_protos.files
for f in ctx.attr.well_known_protos.files.to_list()
]
ctx.actions.run(

@ -186,11 +186,11 @@ def grpc_deps():
if "bazel_toolchains" not in native.existing_rules():
http_archive(
name = "bazel_toolchains",
sha256 = "67335b3563d9b67dc2550b8f27cc689b64fadac491e69ce78763d9ba894cc5cc",
strip_prefix = "bazel-toolchains-cddc376d428ada2927ad359211c3e356bd9c9fbb",
sha256 = "88e818f9f03628eef609c8429c210ecf265ffe46c2af095f36c7ef8b1855fef5",
strip_prefix = "bazel-toolchains-92dd8a7a518a2fb7ba992d47c8b38299fe0be825",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/cddc376d428ada2927ad359211c3e356bd9c9fbb.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/cddc376d428ada2927ad359211c3e356bd9c9fbb.tar.gz",
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/92dd8a7a518a2fb7ba992d47c8b38299fe0be825.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/92dd8a7a518a2fb7ba992d47c8b38299fe0be825.tar.gz",
],
)

@ -33,7 +33,7 @@ def _generate_py_impl(context):
includes = [
file
for src in context.attr.deps
for file in src.proto.transitive_imports
for file in src.proto.transitive_imports.to_list()
]
proto_root = get_proto_root(context.label.workspace_root)
format_str = (_GENERATED_GRPC_PROTO_FORMAT if context.executable.plugin else _GENERATED_PROTO_FORMAT)

@ -595,6 +595,7 @@ filegroups:
- src/core/ext/filters/client_channel/server_address.h
- src/core/ext/filters/client_channel/service_config.h
- src/core/ext/filters/client_channel/subchannel.h
- src/core/ext/filters/client_channel/subchannel_interface.h
- src/core/ext/filters/client_channel/subchannel_pool_interface.h
src:
- src/core/ext/filters/client_channel/backup_poller.cc
@ -1426,6 +1427,7 @@ filegroups:
- include/grpcpp/support/stub_options.h
- include/grpcpp/support/sync_stream.h
- include/grpcpp/support/time.h
- include/grpcpp/support/validate_service_config.h
headers:
- src/cpp/client/create_channel_internal.h
- src/cpp/common/channel_filter.h
@ -1450,6 +1452,7 @@ filegroups:
- src/cpp/common/core_codegen.cc
- src/cpp/common/resource_quota_cc.cc
- src/cpp/common/rpc_method.cc
- src/cpp/common/validate_service_config.cc
- src/cpp/common/version_cc.cc
- src/cpp/server/async_generic_service.cc
- src/cpp/server/channel_argument_option.cc

@ -148,6 +148,7 @@ Pod::Spec.new do |s|
'include/grpcpp/support/stub_options.h',
'include/grpcpp/support/sync_stream.h',
'include/grpcpp/support/time.h',
'include/grpcpp/support/validate_service_config.h',
'include/grpcpp/impl/codegen/async_generic_service.h',
'include/grpcpp/impl/codegen/async_stream.h',
'include/grpcpp/impl/codegen/async_unary_call.h',
@ -234,6 +235,7 @@ Pod::Spec.new do |s|
'src/cpp/common/core_codegen.cc',
'src/cpp/common/resource_quota_cc.cc',
'src/cpp/common/rpc_method.cc',
'src/cpp/common/validate_service_config.cc',
'src/cpp/common/version_cc.cc',
'src/cpp/server/async_generic_service.cc',
'src/cpp/server/channel_argument_option.cc',
@ -397,6 +399,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/server_address.h',
'src/core/ext/filters/client_channel/service_config.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_interface.h',
'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/client_channel/health/health.pb.h',

@ -371,6 +371,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/server_address.h',
'src/core/ext/filters/client_channel/service_config.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_interface.h',
'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/client_channel/health/health.pb.h',
@ -1023,6 +1024,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/server_address.h',
'src/core/ext/filters/client_channel/service_config.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_interface.h',
'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/client_channel/health/health.pb.h',

@ -305,6 +305,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/server_address.h )
s.files += %w( src/core/ext/filters/client_channel/service_config.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_interface.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_pool_interface.h )
s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
s.files += %w( src/core/ext/filters/client_channel/health/health.pb.h )

@ -1463,6 +1463,7 @@
'src/cpp/common/core_codegen.cc',
'src/cpp/common/resource_quota_cc.cc',
'src/cpp/common/rpc_method.cc',
'src/cpp/common/validate_service_config.cc',
'src/cpp/common/version_cc.cc',
'src/cpp/server/async_generic_service.cc',
'src/cpp/server/channel_argument_option.cc',
@ -1619,6 +1620,7 @@
'src/cpp/common/core_codegen.cc',
'src/cpp/common/resource_quota_cc.cc',
'src/cpp/common/rpc_method.cc',
'src/cpp/common/validate_service_config.cc',
'src/cpp/common/version_cc.cc',
'src/cpp/server/async_generic_service.cc',
'src/cpp/server/channel_argument_option.cc',

@ -19,6 +19,7 @@
#ifndef GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
#define GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
#include <grpc/impl/codegen/byte_buffer.h>
#include <grpc/impl/codegen/byte_buffer_reader.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/impl/codegen/sync.h>

@ -0,0 +1,36 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H
#define GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H
#include <grpcpp/support/config.h>
namespace grpc {
namespace experimental {
/// Validates \a service_config_json. If valid, returns an empty string.
/// Otherwise, returns the validation error.
/// TODO(yashykt): Promote it to out of experimental once it is proved useful
/// and gRFC is accepted.
grpc::string ValidateServiceConfigJSON(const grpc::string& service_config_json);
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H

@ -310,6 +310,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/server_address.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/service_config.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_interface.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_pool_interface.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/health/health.pb.h" role="src" />

@ -51,6 +51,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/inlined_vector.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/map.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/iomgr.h"
@ -105,7 +106,6 @@ namespace {
class ChannelData {
public:
struct QueuedPick {
LoadBalancingPolicy::PickArgs pick;
grpc_call_element* elem;
QueuedPick* next = nullptr;
};
@ -175,6 +175,7 @@ class ChannelData {
private:
class ConnectivityStateAndPickerSetter;
class ServiceConfigSetter;
class GrpcSubchannel;
class ClientChannelControlHelper;
class ExternalConnectivityWatcher {
@ -222,8 +223,8 @@ class ChannelData {
~ChannelData();
static bool ProcessResolverResultLocked(
void* arg, Resolver::Result* result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
void* arg, const Resolver::Result& result, const char** lb_policy_name,
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
grpc_error** service_config_error);
grpc_error* DoPingLocked(grpc_transport_op* op);
@ -236,7 +237,7 @@ class ChannelData {
const Resolver::Result& resolver_result,
const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
UniquePtr<char>* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config);
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config);
//
// Fields set at construction and never modified.
@ -271,6 +272,7 @@ class ChannelData {
OrphanablePtr<LoadBalancingPolicy> resolving_lb_policy_;
grpc_connectivity_state_tracker state_tracker_;
ExternalConnectivityWatcher::WatcherList external_connectivity_watcher_list_;
UniquePtr<char> health_check_service_name_;
RefCountedPtr<ServiceConfig> saved_service_config_;
bool received_first_resolver_result_ = false;
@ -314,6 +316,16 @@ class CallData {
private:
class QueuedPickCanceller;
class LbCallState : public LoadBalancingPolicy::CallState {
public:
explicit LbCallState(CallData* calld) : calld_(calld) {}
void* Alloc(size_t size) override { return calld_->arena_->Alloc(size); }
private:
CallData* calld_;
};
// State used for starting a retryable batch on a subchannel call.
// This provides its own grpc_transport_stream_op_batch and other data
// structures needed to populate the ops in the batch.
@ -449,8 +461,9 @@ class CallData {
grpc_call_element* elem, SubchannelCallBatchData* batch_data,
SubchannelCallRetryState* retry_state);
static void MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
const LoadBalancingPolicy::PickArgs& pick,
static void RecvTrailingMetadataReadyForLoadBalancingPolicy(
void* arg, grpc_error* error);
void MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
grpc_transport_stream_op_batch* batch);
// Returns the index into pending_batches_ to be used for batch.
@ -640,8 +653,19 @@ class CallData {
bool pick_queued_ = false;
bool service_config_applied_ = false;
QueuedPickCanceller* pick_canceller_ = nullptr;
LbCallState lb_call_state_;
RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
void (*lb_recv_trailing_metadata_ready_)(
void* user_data, grpc_metadata_batch* recv_trailing_metadata,
LoadBalancingPolicy::CallState* call_state) = nullptr;
void* lb_recv_trailing_metadata_ready_user_data_ = nullptr;
grpc_closure pick_closure_;
// For intercepting recv_trailing_metadata_ready for the LB policy.
grpc_metadata_batch* recv_trailing_metadata_ = nullptr;
grpc_closure recv_trailing_metadata_ready_;
grpc_closure* original_recv_trailing_metadata_ready_ = nullptr;
grpc_polling_entity* pollent_ = nullptr;
// Batches are added to this list when received from above.
@ -933,6 +957,65 @@ void ChannelData::ExternalConnectivityWatcher::WatchConnectivityStateLocked(
&self->chand_->state_tracker_, self->state_, &self->my_closure_);
}
//
// ChannelData::GrpcSubchannel
//
// This class is a wrapper for Subchannel that hides details of the
// channel's implementation (such as the health check service name) from
// the LB policy API.
//
// Note that no synchronization is needed here, because even if the
// underlying subchannel is shared between channels, this wrapper will only
// be used within one channel, so it will always be synchronized by the
// control plane combiner.
class ChannelData::GrpcSubchannel : public SubchannelInterface {
public:
GrpcSubchannel(Subchannel* subchannel,
UniquePtr<char> health_check_service_name)
: subchannel_(subchannel),
health_check_service_name_(std::move(health_check_service_name)) {}
~GrpcSubchannel() { GRPC_SUBCHANNEL_UNREF(subchannel_, "unref from LB"); }
grpc_connectivity_state CheckConnectivityState(
RefCountedPtr<ConnectedSubchannelInterface>* connected_subchannel)
override {
RefCountedPtr<ConnectedSubchannel> tmp;
auto retval = subchannel_->CheckConnectivityState(
health_check_service_name_.get(), &tmp);
*connected_subchannel = std::move(tmp);
return retval;
}
void WatchConnectivityState(
grpc_connectivity_state initial_state,
UniquePtr<ConnectivityStateWatcher> watcher) override {
subchannel_->WatchConnectivityState(
initial_state,
UniquePtr<char>(gpr_strdup(health_check_service_name_.get())),
std::move(watcher));
}
void CancelConnectivityStateWatch(
ConnectivityStateWatcher* watcher) override {
subchannel_->CancelConnectivityStateWatch(health_check_service_name_.get(),
watcher);
}
void AttemptToConnect() override { subchannel_->AttemptToConnect(); }
channelz::SubchannelNode* channelz_node() override {
return subchannel_->channelz_node();
}
void ResetBackoff() override { subchannel_->ResetBackoff(); }
private:
Subchannel* subchannel_;
UniquePtr<char> health_check_service_name_;
};
//
// ChannelData::ClientChannelControlHelper
//
@ -949,15 +1032,26 @@ class ChannelData::ClientChannelControlHelper
"ClientChannelControlHelper");
}
Subchannel* CreateSubchannel(const grpc_channel_args& args) override {
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override {
bool inhibit_health_checking = grpc_channel_arg_get_bool(
grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false);
UniquePtr<char> health_check_service_name;
if (!inhibit_health_checking) {
health_check_service_name.reset(
gpr_strdup(chand_->health_check_service_name_.get()));
}
static const char* args_to_remove[] = {GRPC_ARG_INHIBIT_HEALTH_CHECKING};
grpc_arg arg = SubchannelPoolInterface::CreateChannelArg(
chand_->subchannel_pool_.get());
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add(&args, &arg, 1);
grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
&args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &arg, 1);
Subchannel* subchannel =
chand_->client_channel_factory_->CreateSubchannel(new_args);
grpc_channel_args_destroy(new_args);
return subchannel;
if (subchannel == nullptr) return nullptr;
return MakeRefCounted<GrpcSubchannel>(subchannel,
std::move(health_check_service_name));
}
grpc_channel* CreateChannel(const char* target,
@ -1143,7 +1237,7 @@ void ChannelData::ProcessLbPolicy(
const Resolver::Result& resolver_result,
const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
UniquePtr<char>* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config) {
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config) {
// Prefer the LB policy name found in the service config.
if (parsed_service_config != nullptr &&
parsed_service_config->parsed_lb_config() != nullptr) {
@ -1190,14 +1284,14 @@ void ChannelData::ProcessLbPolicy(
// Synchronous callback from ResolvingLoadBalancingPolicy to process a
// resolver result update.
bool ChannelData::ProcessResolverResultLocked(
void* arg, Resolver::Result* result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
void* arg, const Resolver::Result& result, const char** lb_policy_name,
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
grpc_error** service_config_error) {
ChannelData* chand = static_cast<ChannelData*>(arg);
RefCountedPtr<ServiceConfig> service_config;
// If resolver did not return a service config or returned an invalid service
// config, we need a fallback service config.
if (result->service_config_error != GRPC_ERROR_NONE) {
if (result.service_config_error != GRPC_ERROR_NONE) {
// If the service config was invalid, then fallback to the saved service
// config. If there is no saved config either, use the default service
// config.
@ -1218,7 +1312,7 @@ bool ChannelData::ProcessResolverResultLocked(
}
service_config = chand->default_service_config_;
}
} else if (result->service_config == nullptr) {
} else if (result.service_config == nullptr) {
if (chand->default_service_config_ != nullptr) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
@ -1229,11 +1323,11 @@ bool ChannelData::ProcessResolverResultLocked(
service_config = chand->default_service_config_;
}
} else {
service_config = result->service_config;
service_config = result.service_config;
}
*service_config_error = GRPC_ERROR_REF(result->service_config_error);
*service_config_error = GRPC_ERROR_REF(result.service_config_error);
if (service_config == nullptr &&
result->service_config_error != GRPC_ERROR_NONE) {
result.service_config_error != GRPC_ERROR_NONE) {
return false;
}
// Process service config.
@ -1246,19 +1340,6 @@ bool ChannelData::ProcessResolverResultLocked(
service_config->GetGlobalParsedConfig(
internal::ClientChannelServiceConfigParser::ParserIndex()));
}
// TODO(roth): Eliminate this hack as part of hiding health check
// service name from LB policy API. As part of this, change the API
// for this function to pass in result as a const reference.
if (parsed_service_config != nullptr &&
parsed_service_config->health_check_service_name() != nullptr) {
grpc_arg new_arg = grpc_channel_arg_string_create(
const_cast<char*>("grpc.temp.health_check"),
const_cast<char*>(parsed_service_config->health_check_service_name()));
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add(result->args, &new_arg, 1);
grpc_channel_args_destroy(result->args);
result->args = new_args;
}
// Check if the config has changed.
const bool service_config_changed =
((service_config == nullptr) !=
@ -1275,6 +1356,14 @@ bool ChannelData::ProcessResolverResultLocked(
"chand=%p: resolver returned updated service config: \"%s\"",
chand, service_config_json.get());
}
// Save health check service name.
if (service_config != nullptr) {
chand->health_check_service_name_.reset(
gpr_strdup(parsed_service_config->health_check_service_name()));
} else {
chand->health_check_service_name_.reset();
}
// Save service config.
chand->saved_service_config_ = std::move(service_config);
}
// We want to set the service config at least once. This should not really be
@ -1293,7 +1382,7 @@ bool ChannelData::ProcessResolverResultLocked(
chand->saved_service_config_);
}
UniquePtr<char> processed_lb_policy_name;
chand->ProcessLbPolicy(*result, parsed_service_config,
chand->ProcessLbPolicy(result, parsed_service_config,
&processed_lb_policy_name, lb_policy_config);
// Swap out the data used by GetChannelInfo().
{
@ -1312,19 +1401,19 @@ grpc_error* ChannelData::DoPingLocked(grpc_transport_op* op) {
if (grpc_connectivity_state_check(&state_tracker_) != GRPC_CHANNEL_READY) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("channel not connected");
}
LoadBalancingPolicy::PickArgs pick;
grpc_error* error = GRPC_ERROR_NONE;
picker_->Pick(&pick, &error);
if (pick.connected_subchannel != nullptr) {
pick.connected_subchannel->Ping(op->send_ping.on_initiate,
op->send_ping.on_ack);
LoadBalancingPolicy::PickResult result =
picker_->Pick(LoadBalancingPolicy::PickArgs());
if (result.connected_subchannel != nullptr) {
ConnectedSubchannel* connected_subchannel =
static_cast<ConnectedSubchannel*>(result.connected_subchannel.get());
connected_subchannel->Ping(op->send_ping.on_initiate, op->send_ping.on_ack);
} else {
if (error == GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
if (result.error == GRPC_ERROR_NONE) {
result.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"LB policy dropped call on ping");
}
}
return error;
return result.error;
}
void ChannelData::StartTransportOpLocked(void* arg, grpc_error* ignored) {
@ -1505,6 +1594,7 @@ CallData::CallData(grpc_call_element* elem, const ChannelData& chand,
owning_call_(args.call_stack),
call_combiner_(args.call_combiner),
call_context_(args.context),
lb_call_state_(this),
pending_send_initial_metadata_(false),
pending_send_message_(false),
pending_send_trailing_metadata_(false),
@ -1737,18 +1827,30 @@ void CallData::FreeCachedSendOpDataForCompletedBatch(
// LB recv_trailing_metadata_ready handling
//
void CallData::RecvTrailingMetadataReadyForLoadBalancingPolicy(
void* arg, grpc_error* error) {
CallData* calld = static_cast<CallData*>(arg);
// Invoke callback to LB policy.
calld->lb_recv_trailing_metadata_ready_(
calld->lb_recv_trailing_metadata_ready_user_data_,
calld->recv_trailing_metadata_, &calld->lb_call_state_);
// Chain to original callback.
GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready_,
GRPC_ERROR_REF(error));
}
void CallData::MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
const LoadBalancingPolicy::PickArgs& pick,
grpc_transport_stream_op_batch* batch) {
if (pick.recv_trailing_metadata_ready != nullptr) {
*pick.original_recv_trailing_metadata_ready =
if (lb_recv_trailing_metadata_ready_ != nullptr) {
recv_trailing_metadata_ =
batch->payload->recv_trailing_metadata.recv_trailing_metadata;
original_recv_trailing_metadata_ready_ =
batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready_,
RecvTrailingMetadataReadyForLoadBalancingPolicy, this,
grpc_schedule_on_exec_ctx);
batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
pick.recv_trailing_metadata_ready;
if (pick.recv_trailing_metadata != nullptr) {
*pick.recv_trailing_metadata =
batch->payload->recv_trailing_metadata.recv_trailing_metadata;
}
&recv_trailing_metadata_ready_;
}
}
@ -1894,8 +1996,7 @@ void CallData::PendingBatchesFail(
grpc_transport_stream_op_batch* batch = pending->batch;
if (batch != nullptr) {
if (batch->recv_trailing_metadata) {
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(pick_.pick,
batch);
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(batch);
}
batch->handler_private.extra_arg = this;
GRPC_CLOSURE_INIT(&batch->handler_private.closure,
@ -1949,8 +2050,7 @@ void CallData::PendingBatchesResume(grpc_call_element* elem) {
grpc_transport_stream_op_batch* batch = pending->batch;
if (batch != nullptr) {
if (batch->recv_trailing_metadata) {
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(pick_.pick,
batch);
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(batch);
}
batch->handler_private.extra_arg = subchannel_call_.get();
GRPC_CLOSURE_INIT(&batch->handler_private.closure,
@ -2011,7 +2111,7 @@ void CallData::DoRetry(grpc_call_element* elem,
GPR_ASSERT(retry_policy != nullptr);
// Reset subchannel call and connected subchannel.
subchannel_call_.reset();
pick_.pick.connected_subchannel.reset();
connected_subchannel_.reset();
// Compute backoff delay.
grpc_millis next_attempt_time;
if (server_pushback_ms >= 0) {
@ -2868,7 +2968,7 @@ void CallData::AddRetriableRecvTrailingMetadataOp(
.recv_trailing_metadata_ready =
&retry_state->recv_trailing_metadata_ready;
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
pick_.pick, &batch_data->batch);
&batch_data->batch);
}
void CallData::StartInternalRecvTrailingMetadata(grpc_call_element* elem) {
@ -3135,8 +3235,7 @@ void CallData::CreateSubchannelCall(grpc_call_element* elem) {
// need to use a separate call context for each subchannel call.
call_context_, call_combiner_, parent_data_size};
grpc_error* error = GRPC_ERROR_NONE;
subchannel_call_ =
pick_.pick.connected_subchannel->CreateCall(call_args, &error);
subchannel_call_ = connected_subchannel_->CreateCall(call_args, &error);
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO, "chand=%p calld=%p: create subchannel_call=%p: error=%s",
chand, this, subchannel_call_.get(), grpc_error_string(error));
@ -3297,13 +3396,14 @@ void CallData::MaybeApplyServiceConfigToCallLocked(grpc_call_element* elem) {
}
}
const char* PickResultName(LoadBalancingPolicy::PickResult result) {
switch (result) {
case LoadBalancingPolicy::PICK_COMPLETE:
const char* PickResultTypeName(
LoadBalancingPolicy::PickResult::ResultType type) {
switch (type) {
case LoadBalancingPolicy::PickResult::PICK_COMPLETE:
return "COMPLETE";
case LoadBalancingPolicy::PICK_QUEUE:
case LoadBalancingPolicy::PickResult::PICK_QUEUE:
return "QUEUE";
case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE:
case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE:
return "TRANSIENT_FAILURE";
}
GPR_UNREACHABLE_CODE(return "UNKNOWN");
@ -3313,8 +3413,10 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
CallData* calld = static_cast<CallData*>(elem->call_data);
ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
GPR_ASSERT(calld->pick_.pick.connected_subchannel == nullptr);
GPR_ASSERT(calld->connected_subchannel_ == nullptr);
GPR_ASSERT(calld->subchannel_call_ == nullptr);
// Apply service config to call if needed.
calld->MaybeApplyServiceConfigToCallLocked(elem);
// If this is a retry, use the send_initial_metadata payload that
// we've cached; otherwise, use the pending batch. The
// send_initial_metadata batch will be the first pending batch in the
@ -3325,58 +3427,58 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
// allocate the subchannel batch earlier so that we can give the
// subchannel's copy of the metadata batch (which is copied for each
// attempt) to the LB policy instead the one from the parent channel.
calld->pick_.pick.initial_metadata =
LoadBalancingPolicy::PickArgs pick_args;
pick_args.call_state = &calld->lb_call_state_;
pick_args.initial_metadata =
calld->seen_send_initial_metadata_
? &calld->send_initial_metadata_
: calld->pending_batches_[0]
.batch->payload->send_initial_metadata.send_initial_metadata;
uint32_t* send_initial_metadata_flags =
// Grab initial metadata flags so that we can check later if the call has
// wait_for_ready enabled.
const uint32_t send_initial_metadata_flags =
calld->seen_send_initial_metadata_
? &calld->send_initial_metadata_flags_
: &calld->pending_batches_[0]
.batch->payload->send_initial_metadata
.send_initial_metadata_flags;
// Apply service config to call if needed.
calld->MaybeApplyServiceConfigToCallLocked(elem);
? calld->send_initial_metadata_flags_
: calld->pending_batches_[0]
.batch->payload->send_initial_metadata
.send_initial_metadata_flags;
// When done, we schedule this closure to leave the data plane combiner.
GRPC_CLOSURE_INIT(&calld->pick_closure_, PickDone, elem,
grpc_schedule_on_exec_ctx);
// Attempt pick.
error = GRPC_ERROR_NONE;
auto pick_result = chand->picker()->Pick(&calld->pick_.pick, &error);
auto result = chand->picker()->Pick(pick_args);
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p calld=%p: LB pick returned %s (connected_subchannel=%p, "
"error=%s)",
chand, calld, PickResultName(pick_result),
calld->pick_.pick.connected_subchannel.get(),
grpc_error_string(error));
chand, calld, PickResultTypeName(result.type),
result.connected_subchannel.get(), grpc_error_string(result.error));
}
switch (pick_result) {
case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE: {
switch (result.type) {
case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE: {
// If we're shutting down, fail all RPCs.
grpc_error* disconnect_error = chand->disconnect_error();
if (disconnect_error != GRPC_ERROR_NONE) {
GRPC_ERROR_UNREF(error);
GRPC_ERROR_UNREF(result.error);
GRPC_CLOSURE_SCHED(&calld->pick_closure_,
GRPC_ERROR_REF(disconnect_error));
break;
}
// If wait_for_ready is false, then the error indicates the RPC
// attempt's final status.
if ((*send_initial_metadata_flags &
if ((send_initial_metadata_flags &
GRPC_INITIAL_METADATA_WAIT_FOR_READY) == 0) {
// Retry if appropriate; otherwise, fail.
grpc_status_code status = GRPC_STATUS_OK;
grpc_error_get_status(error, calld->deadline_, &status, nullptr,
grpc_error_get_status(result.error, calld->deadline_, &status, nullptr,
nullptr, nullptr);
if (!calld->enable_retries_ ||
!calld->MaybeRetry(elem, nullptr /* batch_data */, status,
nullptr /* server_pushback_md */)) {
grpc_error* new_error =
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Failed to pick subchannel", &error, 1);
GRPC_ERROR_UNREF(error);
"Failed to pick subchannel", &result.error, 1);
GRPC_ERROR_UNREF(result.error);
GRPC_CLOSURE_SCHED(&calld->pick_closure_, new_error);
}
if (calld->pick_queued_) calld->RemoveCallFromQueuedPicksLocked(elem);
@ -3384,19 +3486,24 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
}
// If wait_for_ready is true, then queue to retry when we get a new
// picker.
GRPC_ERROR_UNREF(error);
GRPC_ERROR_UNREF(result.error);
}
// Fallthrough
case LoadBalancingPolicy::PICK_QUEUE:
case LoadBalancingPolicy::PickResult::PICK_QUEUE:
if (!calld->pick_queued_) calld->AddCallToQueuedPicksLocked(elem);
break;
default: // PICK_COMPLETE
// Handle drops.
if (GPR_UNLIKELY(calld->pick_.pick.connected_subchannel == nullptr)) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
if (GPR_UNLIKELY(result.connected_subchannel == nullptr)) {
result.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Call dropped by load balancing policy");
}
GRPC_CLOSURE_SCHED(&calld->pick_closure_, error);
calld->connected_subchannel_ = std::move(result.connected_subchannel);
calld->lb_recv_trailing_metadata_ready_ =
result.recv_trailing_metadata_ready;
calld->lb_recv_trailing_metadata_ready_user_data_ =
result.recv_trailing_metadata_ready_user_data;
GRPC_CLOSURE_SCHED(&calld->pick_closure_, result.error);
if (calld->pick_queued_) calld->RemoveCallFromQueuedPicksLocked(elem);
}
}

@ -105,7 +105,7 @@ LoadBalancingPolicy::UpdateArgs& LoadBalancingPolicy::UpdateArgs::operator=(
//
LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
PickArgs* pick, grpc_error** error) {
PickArgs args) {
// We invoke the parent's ExitIdleLocked() via a closure instead
// of doing it directly here, for two reasons:
// 1. ExitIdleLocked() may cause the policy's state to change and
@ -125,7 +125,9 @@ LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
grpc_combiner_scheduler(parent_->combiner())),
GRPC_ERROR_NONE);
}
return PICK_QUEUE;
PickResult result;
result.type = PickResult::PICK_QUEUE;
return result;
}
void LoadBalancingPolicy::QueuePicker::CallExitIdle(void* arg,
@ -135,4 +137,16 @@ void LoadBalancingPolicy::QueuePicker::CallExitIdle(void* arg,
parent->Unref();
}
//
// LoadBalancingPolicy::TransientFailurePicker
//
LoadBalancingPolicy::PickResult
LoadBalancingPolicy::TransientFailurePicker::Pick(PickArgs args) {
PickResult result;
result.type = PickResult::PICK_TRANSIENT_FAILURE;
result.error = GRPC_ERROR_REF(error_);
return result;
}
} // namespace grpc_core

@ -24,7 +24,7 @@
#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/ext/filters/client_channel/service_config.h"
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/ext/filters/client_channel/subchannel_interface.h"
#include "src/core/lib/gprpp/abstract.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
@ -32,21 +32,9 @@
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/transport/connectivity_state.h"
extern grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
namespace grpc_core {
/// Interface for parsed forms of load balancing configs found in a service
/// config.
class ParsedLoadBalancingConfig : public RefCounted<ParsedLoadBalancingConfig> {
public:
virtual ~ParsedLoadBalancingConfig() = default;
// Returns the load balancing policy name
virtual const char* name() const GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS;
};
extern DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
/// Interface for load balancing policies.
///
@ -89,66 +77,77 @@ class ParsedLoadBalancingConfig : public RefCounted<ParsedLoadBalancingConfig> {
// interested_parties() hooks from the API.
class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
public:
/// Interface for accessing per-call state.
class CallState {
public:
CallState() = default;
virtual ~CallState() = default;
/// Allocates memory associated with the call, which will be
/// automatically freed when the call is complete.
/// It is more efficient to use this than to allocate memory directly
/// for allocations that need to be made on a per-call basis.
virtual void* Alloc(size_t size) GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
/// Arguments used when picking a subchannel for an RPC.
struct PickArgs {
///
/// Input parameters.
///
/// Initial metadata associated with the picking call.
/// The LB policy may use the existing metadata to influence its routing
/// decision, and it may add new metadata elements to be sent with the
/// call to the chosen backend.
// TODO(roth): Provide a more generic metadata API here.
grpc_metadata_batch* initial_metadata = nullptr;
/// Storage for LB token in \a initial_metadata, or nullptr if not used.
// TODO(roth): Remove this from the API. Maybe have the LB policy
// allocate this on the arena instead?
grpc_linked_mdelem lb_token_mdelem_storage;
///
/// Output parameters.
///
/// Will be set to the selected subchannel, or nullptr on failure or when
/// the LB policy decides to drop the call.
RefCountedPtr<ConnectedSubchannel> connected_subchannel;
/// Callback set by lb policy to be notified of trailing metadata.
/// The callback must be scheduled on grpc_schedule_on_exec_ctx.
// TODO(roth): Provide a cleaner callback API.
grpc_closure* recv_trailing_metadata_ready = nullptr;
/// The address that will be set to point to the original
/// recv_trailing_metadata_ready callback, to be invoked by the LB
/// policy's recv_trailing_metadata_ready callback when complete.
/// Must be non-null if recv_trailing_metadata_ready is non-null.
// TODO(roth): Consider making the recv_trailing_metadata closure a
// synchronous callback, in which case it is not responsible for
// chaining to the next callback, so this can be removed from the API.
grpc_closure** original_recv_trailing_metadata_ready = nullptr;
/// If this is not nullptr, then the client channel will point it to the
/// call's trailing metadata before invoking recv_trailing_metadata_ready.
/// If this is nullptr, then the callback will still be called.
/// The lb does not have ownership of the metadata.
// TODO(roth): If we make this a synchronous callback, then this can
// be passed to the callback as a parameter and can be removed from
// the API here.
grpc_metadata_batch** recv_trailing_metadata = nullptr;
/// An interface for accessing call state. Can be used to allocate
/// data associated with the call in an efficient way.
CallState* call_state;
};
/// The result of picking a subchannel for an RPC.
enum PickResult {
// Pick complete. If connected_subchannel is non-null, client channel
// can immediately proceed with the call on connected_subchannel;
// otherwise, call should be dropped.
PICK_COMPLETE,
// Pick cannot be completed until something changes on the control
// plane. Client channel will queue the pick and try again the
// next time the picker is updated.
PICK_QUEUE,
// LB policy is in transient failure. If the pick is wait_for_ready,
// client channel will wait for the next picker and try again;
// otherwise, the call will be failed immediately (although it may
// be retried if the client channel is configured to do so).
// The Pick() method will set its error parameter if this value is
// returned.
PICK_TRANSIENT_FAILURE,
struct PickResult {
enum ResultType {
/// Pick complete. If connected_subchannel is non-null, client channel
/// can immediately proceed with the call on connected_subchannel;
/// otherwise, call should be dropped.
PICK_COMPLETE,
/// Pick cannot be completed until something changes on the control
/// plane. Client channel will queue the pick and try again the
/// next time the picker is updated.
PICK_QUEUE,
/// LB policy is in transient failure. If the pick is wait_for_ready,
/// client channel will wait for the next picker and try again;
/// otherwise, the call will be failed immediately (although it may
/// be retried if the client channel is configured to do so).
/// The Pick() method will set its error parameter if this value is
/// returned.
PICK_TRANSIENT_FAILURE,
};
ResultType type;
/// Used only if type is PICK_COMPLETE. Will be set to the selected
/// subchannel, or nullptr if the LB policy decides to drop the call.
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel;
/// Used only if type is PICK_TRANSIENT_FAILURE.
/// Error to be set when returning a transient failure.
// TODO(roth): Replace this with something similar to grpc::Status,
// so that we don't expose grpc_error to this API.
grpc_error* error = GRPC_ERROR_NONE;
/// Used only if type is PICK_COMPLETE.
/// Callback set by lb policy to be notified of trailing metadata.
/// The user_data argument will be set to the
/// recv_trailing_metadata_ready_user_data field.
/// recv_trailing_metadata will be set to the metadata, which may be
/// modified by the callback. The callback does not take ownership,
/// however, so any data that needs to be used after returning must
/// be copied.
void (*recv_trailing_metadata_ready)(
void* user_data, grpc_metadata_batch* recv_trailing_metadata,
CallState* call_state) = nullptr;
void* recv_trailing_metadata_ready_user_data = nullptr;
};
/// A subchannel picker is the object used to pick the subchannel to
@ -162,17 +161,14 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
/// live in the LB policy object itself.
///
/// Currently, pickers are always accessed from within the
/// client_channel combiner, so they do not have to be thread-safe.
// TODO(roth): In a subsequent PR, split the data plane work (i.e.,
// the interaction with the picker) and the control plane work (i.e.,
// the interaction with the LB policy) into two different
// synchronization mechanisms, to avoid lock contention between the two.
/// client_channel data plane combiner, so they do not have to be
/// thread-safe.
class SubchannelPicker {
public:
SubchannelPicker() = default;
virtual ~SubchannelPicker() = default;
virtual PickResult Pick(PickArgs* pick, grpc_error** error) GRPC_ABSTRACT;
virtual PickResult Pick(PickArgs args) GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
@ -188,8 +184,8 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
virtual ~ChannelControlHelper() = default;
/// Creates a new subchannel with the specified channel args.
virtual Subchannel* CreateSubchannel(const grpc_channel_args& args)
GRPC_ABSTRACT;
virtual RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) GRPC_ABSTRACT;
/// Creates a channel with the specified target and channel args.
/// This can be used in cases where the LB policy needs to create a
@ -208,11 +204,24 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
GRPC_ABSTRACT_BASE_CLASS
};
/// Interface for configuration data used by an LB policy implementation.
/// Individual implementations will create a subclass that adds methods to
/// return the parameters they need.
class Config : public RefCounted<Config> {
public:
virtual ~Config() = default;
// Returns the load balancing policy name
virtual const char* name() const GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
/// Data passed to the UpdateLocked() method when new addresses and
/// config are available.
struct UpdateArgs {
ServerAddressList addresses;
RefCountedPtr<ParsedLoadBalancingConfig> config;
RefCountedPtr<Config> config;
const grpc_channel_args* args = nullptr;
// TODO(roth): Remove everything below once channel args is
@ -291,7 +300,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
explicit QueuePicker(RefCountedPtr<LoadBalancingPolicy> parent)
: parent_(std::move(parent)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) override;
PickResult Pick(PickArgs args) override;
private:
static void CallExitIdle(void* arg, grpc_error* error);
@ -306,10 +315,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
explicit TransientFailurePicker(grpc_error* error) : error_(error) {}
~TransientFailurePicker() override { GRPC_ERROR_UNREF(error_); }
PickResult Pick(PickArgs* pick, grpc_error** error) override {
*error = GRPC_ERROR_REF(error_);
return PICK_TRANSIENT_FAILURE;
}
PickResult Pick(PickArgs args) override;
private:
grpc_error* error_;

@ -118,19 +118,19 @@ namespace {
constexpr char kGrpclb[] = "grpclb";
class ParsedGrpcLbConfig : public ParsedLoadBalancingConfig {
class ParsedGrpcLbConfig : public LoadBalancingPolicy::Config {
public:
explicit ParsedGrpcLbConfig(
RefCountedPtr<ParsedLoadBalancingConfig> child_policy)
RefCountedPtr<LoadBalancingPolicy::Config> child_policy)
: child_policy_(std::move(child_policy)) {}
const char* name() const override { return kGrpclb; }
RefCountedPtr<ParsedLoadBalancingConfig> child_policy() const {
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
return child_policy_;
}
private:
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
};
class GrpcLb : public LoadBalancingPolicy {
@ -274,7 +274,7 @@ class GrpcLb : public LoadBalancingPolicy {
child_picker_(std::move(child_picker)),
client_stats_(std::move(client_stats)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) override;
PickResult Pick(PickArgs args) override;
private:
// Storing the address for logging, but not holding a ref.
@ -293,7 +293,8 @@ class GrpcLb : public LoadBalancingPolicy {
explicit Helper(RefCountedPtr<GrpcLb> parent)
: parent_(std::move(parent)) {}
Subchannel* CreateSubchannel(const grpc_channel_args& args) override;
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override;
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args& args) override;
void UpdateState(grpc_connectivity_state state,
@ -394,7 +395,7 @@ class GrpcLb : public LoadBalancingPolicy {
// until it reports READY, at which point it will be moved to child_policy_.
OrphanablePtr<LoadBalancingPolicy> pending_child_policy_;
// The child policy config.
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_config_;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_config_;
// Child policy in state READY.
bool child_policy_ready_ = false;
};
@ -561,7 +562,8 @@ const char* GrpcLb::Serverlist::ShouldDrop() {
// GrpcLb::Picker
//
GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs args) {
PickResult result;
// Check if we should drop the call.
const char* drop_token = serverlist_->ShouldDrop();
if (drop_token != nullptr) {
@ -573,26 +575,28 @@ GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
if (client_stats_ != nullptr) {
client_stats_->AddCallDropped(drop_token);
}
return PICK_COMPLETE;
result.type = PickResult::PICK_COMPLETE;
return result;
}
// Forward pick to child policy.
PickResult result = child_picker_->Pick(pick, error);
result = child_picker_->Pick(args);
// If pick succeeded, add LB token to initial metadata.
if (result == PickResult::PICK_COMPLETE &&
pick->connected_subchannel != nullptr) {
if (result.type == PickResult::PICK_COMPLETE &&
result.connected_subchannel != nullptr) {
const grpc_arg* arg = grpc_channel_args_find(
pick->connected_subchannel->args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN);
result.connected_subchannel->args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN);
if (arg == nullptr) {
gpr_log(GPR_ERROR,
"[grpclb %p picker %p] No LB token for connected subchannel "
"pick %p",
parent_, this, pick);
"[grpclb %p picker %p] No LB token for connected subchannel %p",
parent_, this, result.connected_subchannel.get());
abort();
}
grpc_mdelem lb_token = {reinterpret_cast<uintptr_t>(arg->value.pointer.p)};
GPR_ASSERT(!GRPC_MDISNULL(lb_token));
grpc_linked_mdelem* mdelem_storage = static_cast<grpc_linked_mdelem*>(
args.call_state->Alloc(sizeof(grpc_linked_mdelem)));
GPR_ASSERT(grpc_metadata_batch_add_tail(
pick->initial_metadata, &pick->lb_token_mdelem_storage,
args.initial_metadata, mdelem_storage,
GRPC_MDELEM_REF(lb_token)) == GRPC_ERROR_NONE);
GrpcLbClientStats* client_stats = static_cast<GrpcLbClientStats*>(
grpc_mdelem_get_user_data(lb_token, GrpcLbClientStats::Destroy));
@ -617,7 +621,8 @@ bool GrpcLb::Helper::CalledByCurrentChild() const {
return child_ == parent_->child_policy_.get();
}
Subchannel* GrpcLb::Helper::CreateSubchannel(const grpc_channel_args& args) {
RefCountedPtr<SubchannelInterface> GrpcLb::Helper::CreateSubchannel(
const grpc_channel_args& args) {
if (parent_->shutting_down_ ||
(!CalledByPendingChild() && !CalledByCurrentChild())) {
return nullptr;
@ -1800,15 +1805,15 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kGrpclb; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
if (json == nullptr) {
return RefCountedPtr<ParsedLoadBalancingConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(
New<ParsedGrpcLbConfig>(nullptr));
}
InlinedVector<grpc_error*, 2> error_list;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
for (const grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) continue;
@ -1826,7 +1831,7 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
}
}
if (error_list.empty()) {
return RefCountedPtr<ParsedLoadBalancingConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(
New<ParsedGrpcLbConfig>(std::move(child_policy)));
} else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("GrpcLb Parser", &error_list);

@ -68,8 +68,9 @@ class PickFirst : public LoadBalancingPolicy {
PickFirstSubchannelData(
SubchannelList<PickFirstSubchannelList, PickFirstSubchannelData>*
subchannel_list,
const ServerAddress& address, Subchannel* subchannel)
: SubchannelData(subchannel_list, address, subchannel) {}
const ServerAddress& address,
RefCountedPtr<SubchannelInterface> subchannel)
: SubchannelData(subchannel_list, address, std::move(subchannel)) {}
void ProcessConnectivityChangeLocked(
grpc_connectivity_state connectivity_state) override;
@ -112,16 +113,19 @@ class PickFirst : public LoadBalancingPolicy {
class Picker : public SubchannelPicker {
public:
explicit Picker(RefCountedPtr<ConnectedSubchannel> connected_subchannel)
explicit Picker(
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel)
: connected_subchannel_(std::move(connected_subchannel)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) override {
pick->connected_subchannel = connected_subchannel_;
return PICK_COMPLETE;
PickResult Pick(PickArgs args) override {
PickResult result;
result.type = PickResult::PICK_COMPLETE;
result.connected_subchannel = connected_subchannel_;
return result;
}
private:
RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel_;
};
// Helper class to ensure that any function that modifies the child refs
@ -527,7 +531,7 @@ void PickFirst::PickFirstSubchannelData::
}
}
class ParsedPickFirstConfig : public ParsedLoadBalancingConfig {
class ParsedPickFirstConfig : public LoadBalancingPolicy::Config {
public:
const char* name() const override { return kPickFirst; }
};
@ -545,12 +549,12 @@ class PickFirstFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kPickFirst; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
if (json != nullptr) {
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
}
return RefCountedPtr<ParsedLoadBalancingConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(
New<ParsedPickFirstConfig>());
}
};

@ -83,8 +83,9 @@ class RoundRobin : public LoadBalancingPolicy {
RoundRobinSubchannelData(
SubchannelList<RoundRobinSubchannelList, RoundRobinSubchannelData>*
subchannel_list,
const ServerAddress& address, Subchannel* subchannel)
: SubchannelData(subchannel_list, address, subchannel) {}
const ServerAddress& address,
RefCountedPtr<SubchannelInterface> subchannel)
: SubchannelData(subchannel_list, address, std::move(subchannel)) {}
grpc_connectivity_state connectivity_state() const {
return last_connectivity_state_;
@ -149,14 +150,14 @@ class RoundRobin : public LoadBalancingPolicy {
public:
Picker(RoundRobin* parent, RoundRobinSubchannelList* subchannel_list);
PickResult Pick(PickArgs* pick, grpc_error** error) override;
PickResult Pick(PickArgs args) override;
private:
// Using pointer value only, no ref held -- do not dereference!
RoundRobin* parent_;
size_t last_picked_index_;
InlinedVector<RefCountedPtr<ConnectedSubchannel>, 10> subchannels_;
InlinedVector<RefCountedPtr<ConnectedSubchannelInterface>, 10> subchannels_;
};
// Helper class to ensure that any function that modifies the child refs
@ -220,8 +221,7 @@ RoundRobin::Picker::Picker(RoundRobin* parent,
}
}
RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs* pick,
grpc_error** error) {
RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs args) {
last_picked_index_ = (last_picked_index_ + 1) % subchannels_.size();
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) {
gpr_log(GPR_INFO,
@ -230,8 +230,10 @@ RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs* pick,
parent_, this, last_picked_index_,
subchannels_[last_picked_index_].get());
}
pick->connected_subchannel = subchannels_[last_picked_index_];
return PICK_COMPLETE;
PickResult result;
result.type = PickResult::PICK_COMPLETE;
result.connected_subchannel = subchannels_[last_picked_index_];
return result;
}
//
@ -503,7 +505,7 @@ void RoundRobin::UpdateLocked(UpdateArgs args) {
}
}
class ParsedRoundRobinConfig : public ParsedLoadBalancingConfig {
class ParsedRoundRobinConfig : public LoadBalancingPolicy::Config {
public:
const char* name() const override { return kRoundRobin; }
};
@ -521,12 +523,12 @@ class RoundRobinFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kRoundRobin; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
if (json != nullptr) {
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
}
return RefCountedPtr<ParsedLoadBalancingConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(
New<ParsedRoundRobinConfig>());
}
};

@ -27,7 +27,10 @@
#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/ext/filters/client_channel/server_address.h"
// TODO(roth): Should not need the include of subchannel.h here, since
// that implementation should be hidden from the LB policy API.
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/ext/filters/client_channel/subchannel_interface.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/abstract.h"
@ -88,11 +91,11 @@ class SubchannelData {
}
// Returns a pointer to the subchannel.
Subchannel* subchannel() const { return subchannel_; }
SubchannelInterface* subchannel() const { return subchannel_.get(); }
// Returns the connected subchannel. Will be null if the subchannel
// is not connected.
ConnectedSubchannel* connected_subchannel() const {
ConnectedSubchannelInterface* connected_subchannel() const {
return connected_subchannel_.get();
}
@ -102,8 +105,8 @@ class SubchannelData {
// calling CancelConnectivityWatchLocked()).
grpc_connectivity_state CheckConnectivityStateLocked() {
GPR_ASSERT(pending_watcher_ == nullptr);
connectivity_state_ = subchannel()->CheckConnectivityState(
subchannel_list_->health_check_service_name(), &connected_subchannel_);
connectivity_state_ =
subchannel()->CheckConnectivityState(&connected_subchannel_);
return connectivity_state_;
}
@ -128,7 +131,8 @@ class SubchannelData {
protected:
SubchannelData(
SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list,
const ServerAddress& address, Subchannel* subchannel);
const ServerAddress& address,
RefCountedPtr<SubchannelInterface> subchannel);
virtual ~SubchannelData();
@ -140,7 +144,7 @@ class SubchannelData {
private:
// Watcher for subchannel connectivity state.
class Watcher : public Subchannel::ConnectivityStateWatcher {
class Watcher : public SubchannelInterface::ConnectivityStateWatcher {
public:
Watcher(
SubchannelData<SubchannelListType, SubchannelDataType>* subchannel_data,
@ -150,9 +154,9 @@ class SubchannelData {
~Watcher() { subchannel_list_.reset(DEBUG_LOCATION, "Watcher dtor"); }
void OnConnectivityStateChange(
grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannel> connected_subchannel) override;
void OnConnectivityStateChange(grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannelInterface>
connected_subchannel) override;
grpc_pollset_set* interested_parties() override {
return subchannel_list_->policy()->interested_parties();
@ -169,7 +173,7 @@ class SubchannelData {
RefCountedPtr<SubchannelList<SubchannelListType, SubchannelDataType>>
subchannel_list,
grpc_connectivity_state state,
RefCountedPtr<ConnectedSubchannel> connected_subchannel);
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel);
~Updater() {
subchannel_list_.reset(DEBUG_LOCATION, "Watcher::Updater dtor");
@ -182,7 +186,7 @@ class SubchannelData {
RefCountedPtr<SubchannelList<SubchannelListType, SubchannelDataType>>
subchannel_list_;
const grpc_connectivity_state state_;
RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel_;
grpc_closure closure_;
};
@ -196,12 +200,12 @@ class SubchannelData {
// Backpointer to owning subchannel list. Not owned.
SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list_;
// The subchannel.
Subchannel* subchannel_;
RefCountedPtr<SubchannelInterface> subchannel_;
// Will be non-null when the subchannel's state is being watched.
Subchannel::ConnectivityStateWatcher* pending_watcher_ = nullptr;
SubchannelInterface::ConnectivityStateWatcher* pending_watcher_ = nullptr;
// Data updated by the watcher.
grpc_connectivity_state connectivity_state_;
RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel_;
};
// A list of subchannels.
@ -235,9 +239,6 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
// Accessors.
LoadBalancingPolicy* policy() const { return policy_; }
TraceFlag* tracer() const { return tracer_; }
const char* health_check_service_name() const {
return health_check_service_name_.get();
}
// Resets connection backoff of all subchannels.
// TODO(roth): We will probably need to rethink this as part of moving
@ -275,8 +276,6 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
TraceFlag* tracer_;
UniquePtr<char> health_check_service_name_;
grpc_combiner* combiner_;
// The list of subchannels.
@ -300,7 +299,7 @@ template <typename SubchannelListType, typename SubchannelDataType>
void SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::
OnConnectivityStateChange(
grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannel> connected_subchannel) {
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel) {
// Will delete itself.
New<Updater>(subchannel_data_,
subchannel_list_->Ref(DEBUG_LOCATION, "Watcher::Updater"),
@ -314,7 +313,7 @@ SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::Updater::
RefCountedPtr<SubchannelList<SubchannelListType, SubchannelDataType>>
subchannel_list,
grpc_connectivity_state state,
RefCountedPtr<ConnectedSubchannel> connected_subchannel)
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel)
: subchannel_data_(subchannel_data),
subchannel_list_(std::move(subchannel_list)),
state_(state),
@ -336,7 +335,7 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::Updater::
"connected_subchannel=%p, shutting_down=%d, pending_watcher=%p",
sd->subchannel_list_->tracer()->name(),
sd->subchannel_list_->policy(), sd->subchannel_list_, sd->Index(),
sd->subchannel_list_->num_subchannels(), sd->subchannel_,
sd->subchannel_list_->num_subchannels(), sd->subchannel_.get(),
grpc_connectivity_state_name(self->state_),
self->connected_subchannel_.get(),
sd->subchannel_list_->shutting_down(), sd->pending_watcher_);
@ -360,9 +359,9 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::Updater::
template <typename SubchannelListType, typename SubchannelDataType>
SubchannelData<SubchannelListType, SubchannelDataType>::SubchannelData(
SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list,
const ServerAddress& address, Subchannel* subchannel)
const ServerAddress& address, RefCountedPtr<SubchannelInterface> subchannel)
: subchannel_list_(subchannel_list),
subchannel_(subchannel),
subchannel_(std::move(subchannel)),
// We assume that the current state is IDLE. If not, we'll get a
// callback telling us that.
connectivity_state_(GRPC_CHANNEL_IDLE) {}
@ -382,10 +381,9 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
" (subchannel %p): unreffing subchannel",
subchannel_list_->tracer()->name(), subchannel_list_->policy(),
subchannel_list_, Index(), subchannel_list_->num_subchannels(),
subchannel_);
subchannel_.get());
}
GRPC_SUBCHANNEL_UNREF(subchannel_, reason);
subchannel_ = nullptr;
subchannel_.reset();
connected_subchannel_.reset();
}
}
@ -407,16 +405,16 @@ void SubchannelData<SubchannelListType,
" (subchannel %p): starting watch (from %s)",
subchannel_list_->tracer()->name(), subchannel_list_->policy(),
subchannel_list_, Index(), subchannel_list_->num_subchannels(),
subchannel_, grpc_connectivity_state_name(connectivity_state_));
subchannel_.get(),
grpc_connectivity_state_name(connectivity_state_));
}
GPR_ASSERT(pending_watcher_ == nullptr);
pending_watcher_ =
New<Watcher>(this, subchannel_list()->Ref(DEBUG_LOCATION, "Watcher"));
subchannel_->WatchConnectivityState(
connectivity_state_,
UniquePtr<char>(
gpr_strdup(subchannel_list_->health_check_service_name())),
UniquePtr<Subchannel::ConnectivityStateWatcher>(pending_watcher_));
UniquePtr<SubchannelInterface::ConnectivityStateWatcher>(
pending_watcher_));
}
template <typename SubchannelListType, typename SubchannelDataType>
@ -428,11 +426,10 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
" (subchannel %p): canceling connectivity watch (%s)",
subchannel_list_->tracer()->name(), subchannel_list_->policy(),
subchannel_list_, Index(), subchannel_list_->num_subchannels(),
subchannel_, reason);
subchannel_.get(), reason);
}
if (pending_watcher_ != nullptr) {
subchannel_->CancelConnectivityStateWatch(
subchannel_list_->health_check_service_name(), pending_watcher_);
subchannel_->CancelConnectivityStateWatch(pending_watcher_);
pending_watcher_ = nullptr;
}
}
@ -463,25 +460,12 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
tracer_->name(), policy, this, addresses.size());
}
subchannels_.reserve(addresses.size());
// Find health check service name.
const bool inhibit_health_checking = grpc_channel_arg_get_bool(
grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false);
if (!inhibit_health_checking) {
const char* health_check_service_name = grpc_channel_arg_get_string(
grpc_channel_args_find(&args, "grpc.temp.health_check"));
if (health_check_service_name != nullptr) {
health_check_service_name_.reset(gpr_strdup(health_check_service_name));
}
}
// We need to remove the LB addresses in order to be able to compare the
// subchannel keys of subchannels from a different batch of addresses.
// We also remove the health-checking-related args, since we are
// handling that here.
// We remove the service config, since it will be passed into the
// subchannel via call context.
static const char* keys_to_remove[] = {
GRPC_ARG_SUBCHANNEL_ADDRESS, "grpc.temp.health_check",
GRPC_ARG_INHIBIT_HEALTH_CHECKING, GRPC_ARG_SERVICE_CONFIG};
static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS,
GRPC_ARG_SERVICE_CONFIG};
// Create a subchannel for each address.
for (size_t i = 0; i < addresses.size(); i++) {
// TODO(roth): we should ideally hide this from the LB policy code. In
@ -504,7 +488,8 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
&args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove),
args_to_add.data(), args_to_add.size());
gpr_free(args_to_add[subchannel_address_arg_index].value.string);
Subchannel* subchannel = helper->CreateSubchannel(*new_args);
RefCountedPtr<SubchannelInterface> subchannel =
helper->CreateSubchannel(*new_args);
grpc_channel_args_destroy(new_args);
if (subchannel == nullptr) {
// Subchannel could not be created.
@ -523,11 +508,11 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
gpr_log(GPR_INFO,
"[%s %p] subchannel list %p index %" PRIuPTR
": Created subchannel %p for address uri %s",
tracer_->name(), policy_, this, subchannels_.size(), subchannel,
address_uri);
tracer_->name(), policy_, this, subchannels_.size(),
subchannel.get(), address_uri);
gpr_free(address_uri);
}
subchannels_.emplace_back(this, addresses[i], subchannel);
subchannels_.emplace_back(this, addresses[i], std::move(subchannel));
}
}

@ -120,11 +120,11 @@ constexpr char kXds[] = "xds_experimental";
constexpr char kDefaultLocalityName[] = "xds_default_locality";
constexpr uint32_t kDefaultLocalityWeight = 3;
class ParsedXdsConfig : public ParsedLoadBalancingConfig {
class ParsedXdsConfig : public LoadBalancingPolicy::Config {
public:
ParsedXdsConfig(const char* balancer_name,
RefCountedPtr<ParsedLoadBalancingConfig> child_policy,
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy)
RefCountedPtr<LoadBalancingPolicy::Config> child_policy,
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy)
: balancer_name_(balancer_name),
child_policy_(std::move(child_policy)),
fallback_policy_(std::move(fallback_policy)) {}
@ -133,18 +133,18 @@ class ParsedXdsConfig : public ParsedLoadBalancingConfig {
const char* balancer_name() const { return balancer_name_; };
RefCountedPtr<ParsedLoadBalancingConfig> child_policy() const {
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
return child_policy_;
}
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy() const {
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy() const {
return fallback_policy_;
}
private:
const char* balancer_name_ = nullptr;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_;
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy_;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy_;
};
class XdsLb : public LoadBalancingPolicy {
@ -300,9 +300,7 @@ class XdsLb : public LoadBalancingPolicy {
public:
explicit PickerRef(UniquePtr<SubchannelPicker> picker)
: picker_(std::move(picker)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) {
return picker_->Pick(pick, error);
}
PickResult Pick(PickArgs args) { return picker_->Pick(args); }
private:
UniquePtr<SubchannelPicker> picker_;
@ -322,12 +320,11 @@ class XdsLb : public LoadBalancingPolicy {
: client_stats_(std::move(client_stats)),
pickers_(std::move(pickers)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) override;
PickResult Pick(PickArgs args) override;
private:
// Calls the picker of the locality that the key falls within
PickResult PickFromLocality(const uint32_t key, PickArgs* pick,
grpc_error** error);
PickResult PickFromLocality(const uint32_t key, PickArgs args);
RefCountedPtr<XdsLbClientStats> client_stats_;
PickerList pickers_;
};
@ -337,7 +334,8 @@ class XdsLb : public LoadBalancingPolicy {
explicit FallbackHelper(RefCountedPtr<XdsLb> parent)
: parent_(std::move(parent)) {}
Subchannel* CreateSubchannel(const grpc_channel_args& args) override;
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override;
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args& args) override;
void UpdateState(grpc_connectivity_state state,
@ -363,7 +361,7 @@ class XdsLb : public LoadBalancingPolicy {
~LocalityEntry() = default;
void UpdateLocked(xds_grpclb_serverlist* serverlist,
ParsedLoadBalancingConfig* child_policy_config,
LoadBalancingPolicy::Config* child_policy_config,
const grpc_channel_args* args);
void ShutdownLocked();
void ResetBackoffLocked();
@ -377,7 +375,8 @@ class XdsLb : public LoadBalancingPolicy {
explicit Helper(RefCountedPtr<LocalityEntry> entry)
: entry_(std::move(entry)) {}
Subchannel* CreateSubchannel(const grpc_channel_args& args) override;
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override;
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args& args) override;
void UpdateState(grpc_connectivity_state state,
@ -410,7 +409,7 @@ class XdsLb : public LoadBalancingPolicy {
};
void UpdateLocked(const LocalityList& locality_list,
ParsedLoadBalancingConfig* child_policy_config,
LoadBalancingPolicy::Config* child_policy_config,
const grpc_channel_args* args, XdsLb* parent);
void ShutdownLocked();
void ResetBackoffLocked();
@ -506,7 +505,7 @@ class XdsLb : public LoadBalancingPolicy {
grpc_closure lb_on_fallback_;
// The policy to use for the fallback backends.
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy_config_;
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy_config_;
// Lock held when modifying the value of fallback_policy_ or
// pending_fallback_policy_.
Mutex fallback_policy_mu_;
@ -515,7 +514,7 @@ class XdsLb : public LoadBalancingPolicy {
OrphanablePtr<LoadBalancingPolicy> pending_fallback_policy_;
// The policy to use for the backends.
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_config_;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_config_;
// Map of policies to use in the backend
LocalityMap locality_map_;
// TODO(mhaidry) : Add support for multiple maps of localities
@ -530,25 +529,24 @@ class XdsLb : public LoadBalancingPolicy {
// XdsLb::Picker
//
XdsLb::PickResult XdsLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
XdsLb::PickResult XdsLb::Picker::Pick(PickArgs args) {
// TODO(roth): Add support for drop handling.
// Generate a random number between 0 and the total weight
const uint32_t key =
(rand() * pickers_[pickers_.size() - 1].first) / RAND_MAX;
// Forward pick to whichever locality maps to the range in which the
// random number falls in.
PickResult result = PickFromLocality(key, pick, error);
PickResult result = PickFromLocality(key, args);
// If pick succeeded, add client stats.
if (result == PickResult::PICK_COMPLETE &&
pick->connected_subchannel != nullptr && client_stats_ != nullptr) {
if (result.type == PickResult::PICK_COMPLETE &&
result.connected_subchannel != nullptr && client_stats_ != nullptr) {
// TODO(roth): Add support for client stats.
}
return result;
}
XdsLb::PickResult XdsLb::Picker::PickFromLocality(const uint32_t key,
PickArgs* pick,
grpc_error** error) {
PickArgs args) {
size_t mid = 0;
size_t start_index = 0;
size_t end_index = pickers_.size() - 1;
@ -566,7 +564,7 @@ XdsLb::PickResult XdsLb::Picker::PickFromLocality(const uint32_t key,
}
if (index == 0) index = start_index;
GPR_ASSERT(pickers_[index].first > key);
return pickers_[index].second->Pick(pick, error);
return pickers_[index].second->Pick(args);
}
//
@ -583,7 +581,7 @@ bool XdsLb::FallbackHelper::CalledByCurrentFallback() const {
return child_ == parent_->fallback_policy_.get();
}
Subchannel* XdsLb::FallbackHelper::CreateSubchannel(
RefCountedPtr<SubchannelInterface> XdsLb::FallbackHelper::CreateSubchannel(
const grpc_channel_args& args) {
if (parent_->shutting_down_ ||
(!CalledByPendingFallback() && !CalledByCurrentFallback())) {
@ -1744,7 +1742,7 @@ void XdsLb::LocalityMap::PruneLocalities(const LocalityList& locality_list) {
void XdsLb::LocalityMap::UpdateLocked(
const LocalityList& locality_serverlist,
ParsedLoadBalancingConfig* child_policy_config,
LoadBalancingPolicy::Config* child_policy_config,
const grpc_channel_args* args, XdsLb* parent) {
if (parent->shutting_down_) return;
for (size_t i = 0; i < locality_serverlist.size(); i++) {
@ -1839,7 +1837,7 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked(
void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
xds_grpclb_serverlist* serverlist,
ParsedLoadBalancingConfig* child_policy_config,
LoadBalancingPolicy::Config* child_policy_config,
const grpc_channel_args* args_in) {
if (parent_->shutting_down_) return;
// Construct update args.
@ -2001,7 +1999,8 @@ bool XdsLb::LocalityMap::LocalityEntry::Helper::CalledByCurrentChild() const {
return child_ == entry_->child_policy_.get();
}
Subchannel* XdsLb::LocalityMap::LocalityEntry::Helper::CreateSubchannel(
RefCountedPtr<SubchannelInterface>
XdsLb::LocalityMap::LocalityEntry::Helper::CreateSubchannel(
const grpc_channel_args& args) {
if (entry_->parent_->shutting_down_ ||
(!CalledByPendingChild() && !CalledByCurrentChild())) {
@ -2158,7 +2157,7 @@ class XdsFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kXds; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
if (json == nullptr) {
@ -2174,8 +2173,8 @@ class XdsFactory : public LoadBalancingPolicyFactory {
InlinedVector<grpc_error*, 3> error_list;
const char* balancer_name = nullptr;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy;
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy;
for (const grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) continue;
@ -2221,7 +2220,7 @@ class XdsFactory : public LoadBalancingPolicyFactory {
"field:balancerName error:not found"));
}
if (error_list.empty()) {
return RefCountedPtr<ParsedLoadBalancingConfig>(New<ParsedXdsConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(New<ParsedXdsConfig>(
balancer_name, std::move(child_policy), std::move(fallback_policy)));
} else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Xds Parser", &error_list);

@ -37,7 +37,7 @@ class LoadBalancingPolicyFactory {
/// Caller does NOT take ownership of result.
virtual const char* name() const GRPC_ABSTRACT;
virtual RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
virtual RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const GRPC_ABSTRACT;
virtual ~LoadBalancingPolicyFactory() {}

@ -176,7 +176,7 @@ grpc_json* ParseLoadBalancingConfigHelper(const grpc_json* lb_config_array,
}
} // namespace
RefCountedPtr<ParsedLoadBalancingConfig>
RefCountedPtr<LoadBalancingPolicy::Config>
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const grpc_json* json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);

@ -56,7 +56,7 @@ class LoadBalancingPolicyRegistry {
/// Returns a parsed object of the load balancing policy to be used from a
/// LoadBalancingConfig array \a json.
static RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
static RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error);
};

@ -268,7 +268,7 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
InlinedVector<grpc_error*, 4> error_list;
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config;
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
UniquePtr<char> lb_policy_name;
Optional<ClientChannelGlobalParsedConfig::RetryThrottling> retry_throttling;
const char* health_check_service_name = nullptr;

@ -45,7 +45,7 @@ class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
};
ClientChannelGlobalParsedConfig(
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config,
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config,
UniquePtr<char> parsed_deprecated_lb_policy,
const Optional<RetryThrottling>& retry_throttling,
const char* health_check_service_name)
@ -58,7 +58,7 @@ class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
return retry_throttling_;
}
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config() const {
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config() const {
return parsed_lb_config_;
}
@ -71,7 +71,7 @@ class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
}
private:
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config_;
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_;
UniquePtr<char> parsed_deprecated_lb_policy_;
Optional<RetryThrottling> retry_throttling_;
const char* health_check_service_name_;

@ -106,7 +106,8 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
RefCountedPtr<ResolvingLoadBalancingPolicy> parent)
: parent_(std::move(parent)) {}
Subchannel* CreateSubchannel(const grpc_channel_args& args) override {
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override {
if (parent_->resolver_ == nullptr) return nullptr; // Shutting down.
if (!CalledByCurrentChild() && !CalledByPendingChild()) return nullptr;
return parent_->channel_control_helper()->CreateSubchannel(args);
@ -184,7 +185,7 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy(
Args args, TraceFlag* tracer, UniquePtr<char> target_uri,
UniquePtr<char> child_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config,
RefCountedPtr<LoadBalancingPolicy::Config> child_lb_config,
grpc_error** error)
: LoadBalancingPolicy(std::move(args)),
tracer_(tracer),
@ -333,7 +334,7 @@ void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) {
void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked(
const char* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config,
RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
Resolver::Result result, TraceStringVector* trace_strings) {
// If the child policy name changes, we need to create a new child
// policy. When this happens, we leave child_policy_ as-is and store
@ -530,13 +531,13 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
const bool resolution_contains_addresses = result.addresses.size() > 0;
// Process the resolver result.
const char* lb_policy_name = nullptr;
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config;
RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config;
bool service_config_changed = false;
char* service_config_error_string = nullptr;
if (process_resolver_result_ != nullptr) {
grpc_error* service_config_error = GRPC_ERROR_NONE;
service_config_changed = process_resolver_result_(
process_resolver_result_user_data_, &result, &lb_policy_name,
process_resolver_result_user_data_, result, &lb_policy_name,
&lb_policy_config, &service_config_error);
if (service_config_error != GRPC_ERROR_NONE) {
service_config_error_string =

@ -57,7 +57,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
ResolvingLoadBalancingPolicy(
Args args, TraceFlag* tracer, UniquePtr<char> target_uri,
UniquePtr<char> child_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config,
RefCountedPtr<LoadBalancingPolicy::Config> child_lb_config,
grpc_error** error);
// Private ctor, to be used by client_channel only!
@ -69,8 +69,9 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
// empty, it means that we don't have a valid service config to use, and we
// should set the channel to be in TRANSIENT_FAILURE.
typedef bool (*ProcessResolverResultCallback)(
void* user_data, Resolver::Result* result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
void* user_data, const Resolver::Result& result,
const char** lb_policy_name,
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
grpc_error** service_config_error);
// If error is set when this returns, then construction failed, and
// the caller may not use the new object.
@ -109,7 +110,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
void OnResolverError(grpc_error* error);
void CreateOrUpdateLbPolicyLocked(
const char* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config,
RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
Resolver::Result result, TraceStringVector* trace_strings);
OrphanablePtr<LoadBalancingPolicy> CreateLbPolicyLocked(
const char* lb_policy_name, const grpc_channel_args& args,
@ -126,7 +127,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
ProcessResolverResultCallback process_resolver_result_ = nullptr;
void* process_resolver_result_user_data_ = nullptr;
UniquePtr<char> child_policy_name_;
RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config_;
RefCountedPtr<LoadBalancingPolicy::Config> child_lb_config_;
// Resolver and associated state.
OrphanablePtr<Resolver> resolver_;

@ -83,7 +83,7 @@ ConnectedSubchannel::ConnectedSubchannel(
grpc_channel_stack* channel_stack, const grpc_channel_args* args,
RefCountedPtr<channelz::SubchannelNode> channelz_subchannel,
intptr_t socket_uuid)
: RefCounted<ConnectedSubchannel>(&grpc_trace_stream_refcount),
: ConnectedSubchannelInterface(&grpc_trace_stream_refcount),
channel_stack_(channel_stack),
args_(grpc_channel_args_copy(args)),
channelz_subchannel_(std::move(channelz_subchannel)),
@ -376,25 +376,17 @@ class Subchannel::ConnectedSubchannelStateWatcher {
void Subchannel::ConnectivityStateWatcherList::AddWatcherLocked(
UniquePtr<ConnectivityStateWatcher> watcher) {
watcher->next_ = head_;
head_ = watcher.release();
watchers_.insert(MakePair(watcher.get(), std::move(watcher)));
}
void Subchannel::ConnectivityStateWatcherList::RemoveWatcherLocked(
ConnectivityStateWatcher* watcher) {
for (ConnectivityStateWatcher** w = &head_; *w != nullptr; w = &(*w)->next_) {
if (*w == watcher) {
*w = watcher->next_;
Delete(watcher);
return;
}
}
GPR_UNREACHABLE_CODE(return );
watchers_.erase(watcher);
}
void Subchannel::ConnectivityStateWatcherList::NotifyLocked(
Subchannel* subchannel, grpc_connectivity_state state) {
for (ConnectivityStateWatcher* w = head_; w != nullptr; w = w->next_) {
for (const auto& p : watchers_) {
RefCountedPtr<ConnectedSubchannel> connected_subchannel;
if (state == GRPC_CHANNEL_READY) {
connected_subchannel = subchannel->connected_subchannel_;
@ -407,15 +399,7 @@ void Subchannel::ConnectivityStateWatcherList::NotifyLocked(
// the notification into the client_channel control-plane combiner
// before processing it. But if we ever have any other callers here,
// we will probably need to change this.
w->OnConnectivityStateChange(state, std::move(connected_subchannel));
}
}
void Subchannel::ConnectivityStateWatcherList::Clear() {
while (head_ != nullptr) {
ConnectivityStateWatcher* next = head_->next_;
Delete(head_);
head_ = next;
p.second->OnConnectivityStateChange(state, std::move(connected_subchannel));
}
}

@ -23,6 +23,7 @@
#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
#include "src/core/ext/filters/client_channel/connector.h"
#include "src/core/ext/filters/client_channel/subchannel_interface.h"
#include "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
#include "src/core/lib/backoff/backoff.h"
#include "src/core/lib/channel/channel_stack.h"
@ -69,7 +70,7 @@ namespace grpc_core {
class SubchannelCall;
class ConnectedSubchannel : public RefCounted<ConnectedSubchannel> {
class ConnectedSubchannel : public ConnectedSubchannelInterface {
public:
struct CallArgs {
grpc_polling_entity* pollent;
@ -96,7 +97,7 @@ class ConnectedSubchannel : public RefCounted<ConnectedSubchannel> {
grpc_error** error);
grpc_channel_stack* channel_stack() const { return channel_stack_; }
const grpc_channel_args* args() const { return args_; }
const grpc_channel_args* args() const override { return args_; }
channelz::SubchannelNode* channelz_subchannel() const {
return channelz_subchannel_.get();
}
@ -176,37 +177,9 @@ class SubchannelCall {
// A subchannel that knows how to connect to exactly one target address. It
// provides a target for load balancing.
class Subchannel {
private:
class ConnectivityStateWatcherList; // Forward declaration.
public:
class ConnectivityStateWatcher {
public:
virtual ~ConnectivityStateWatcher() = default;
// Will be invoked whenever the subchannel's connectivity state
// changes. There will be only one invocation of this method on a
// given watcher instance at any given time.
//
// When the state changes to READY, connected_subchannel will
// contain a ref to the connected subchannel. When it changes from
// READY to some other state, the implementation must release its
// ref to the connected subchannel.
virtual void OnConnectivityStateChange(
grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannel> connected_subchannel) // NOLINT
GRPC_ABSTRACT;
virtual grpc_pollset_set* interested_parties() GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
private:
// For access to next_.
friend class Subchannel::ConnectivityStateWatcherList;
ConnectivityStateWatcher* next_ = nullptr;
};
typedef SubchannelInterface::ConnectivityStateWatcher
ConnectivityStateWatcher;
// The ctor and dtor are not intended to use directly.
Subchannel(SubchannelKey* key, grpc_connector* connector,
@ -296,12 +269,15 @@ class Subchannel {
// Notifies all watchers in the list about a change to state.
void NotifyLocked(Subchannel* subchannel, grpc_connectivity_state state);
void Clear();
void Clear() { watchers_.clear(); }
bool empty() const { return head_ == nullptr; }
bool empty() const { return watchers_.empty(); }
private:
ConnectivityStateWatcher* head_ = nullptr;
// TODO(roth): This could be a set instead of a map if we had a set
// implementation.
Map<ConnectivityStateWatcher*, UniquePtr<ConnectivityStateWatcher>>
watchers_;
};
// A map that tracks ConnectivityStateWatchers using a particular health

@ -0,0 +1,109 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
namespace grpc_core {
// TODO(roth): In a subsequent PR, remove this from this API.
class ConnectedSubchannelInterface
: public RefCounted<ConnectedSubchannelInterface> {
public:
virtual const grpc_channel_args* args() const GRPC_ABSTRACT;
protected:
template <typename TraceFlagT = TraceFlag>
explicit ConnectedSubchannelInterface(TraceFlagT* trace_flag = nullptr)
: RefCounted<ConnectedSubchannelInterface>(trace_flag) {}
};
class SubchannelInterface : public RefCounted<SubchannelInterface> {
public:
class ConnectivityStateWatcher {
public:
virtual ~ConnectivityStateWatcher() = default;
// Will be invoked whenever the subchannel's connectivity state
// changes. There will be only one invocation of this method on a
// given watcher instance at any given time.
//
// When the state changes to READY, connected_subchannel will
// contain a ref to the connected subchannel. When it changes from
// READY to some other state, the implementation must release its
// ref to the connected subchannel.
virtual void OnConnectivityStateChange(
grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannelInterface>
connected_subchannel) // NOLINT
GRPC_ABSTRACT;
// TODO(roth): Remove this as soon as we move to EventManager-based
// polling.
virtual grpc_pollset_set* interested_parties() GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
virtual ~SubchannelInterface() = default;
// Returns the current connectivity state of the subchannel.
virtual grpc_connectivity_state CheckConnectivityState(
RefCountedPtr<ConnectedSubchannelInterface>* connected_subchannel)
GRPC_ABSTRACT;
// Starts watching the subchannel's connectivity state.
// The first callback to the watcher will be delivered when the
// subchannel's connectivity state becomes a value other than
// initial_state, which may happen immediately.
// Subsequent callbacks will be delivered as the subchannel's state
// changes.
// The watcher will be destroyed either when the subchannel is
// destroyed or when CancelConnectivityStateWatch() is called.
// There can be only one watcher of a given subchannel. It is not
// valid to call this method a second time without first cancelling
// the previous watcher using CancelConnectivityStateWatch().
virtual void WatchConnectivityState(
grpc_connectivity_state initial_state,
UniquePtr<ConnectivityStateWatcher> watcher) GRPC_ABSTRACT;
// Cancels a connectivity state watch.
// If the watcher has already been destroyed, this is a no-op.
virtual void CancelConnectivityStateWatch(ConnectivityStateWatcher* watcher)
GRPC_ABSTRACT;
// Attempt to connect to the backend. Has no effect if already connected.
virtual void AttemptToConnect() GRPC_ABSTRACT;
// TODO(roth): These methods should be removed from this interface to
// bettter hide grpc-specific functionality from the LB policy API.
virtual channelz::SubchannelNode* channelz_node() GRPC_ABSTRACT;
virtual void ResetBackoff() GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_H */

@ -37,6 +37,7 @@
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/timeout_encoding.h"
@ -56,7 +57,10 @@
/* don't consider adding anything bigger than this to the hpack table */
#define MAX_DECODER_SPACE_USAGE 512
static grpc_slice_refcount terminal_slice_refcount;
#define DATA_FRAME_HEADER_SIZE 9
static grpc_slice_refcount terminal_slice_refcount(
grpc_slice_refcount::Type::STATIC);
static const grpc_slice terminal_slice = {
&terminal_slice_refcount, /* refcount */
{{0, nullptr}} /* data.refcounted */
@ -80,7 +84,8 @@ typedef struct {
bool use_true_binary_metadata;
} framer_state;
/* fills p (which is expected to be 9 bytes long) with a data frame header */
/* fills p (which is expected to be DATA_FRAME_HEADER_SIZE bytes long)
* with a data frame header */
static void fill_header(uint8_t* p, uint8_t type, uint32_t id, size_t len,
uint8_t flags) {
GPR_ASSERT(len < 16777316);
@ -107,15 +112,17 @@ static void finish_frame(framer_state* st, int is_header_boundary,
static_cast<uint8_t>(
(is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
(is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
st->stats->framing_bytes += 9;
st->stats->framing_bytes += DATA_FRAME_HEADER_SIZE;
st->is_first_frame = 0;
}
/* begin a new frame: reserve off header space, remember how many bytes we'd
output before beginning */
static void begin_frame(framer_state* st) {
st->header_idx =
grpc_slice_buffer_add_indexed(st->output, GRPC_SLICE_MALLOC(9));
grpc_slice reserved;
reserved.refcount = nullptr;
reserved.data.inlined.length = DATA_FRAME_HEADER_SIZE;
st->header_idx = grpc_slice_buffer_add_indexed(st->output, reserved);
st->output_length_at_start_of_frame = st->output->length;
}
@ -188,8 +195,9 @@ static void evict_entry(grpc_chttp2_hpack_compressor* c) {
static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
size_t elem_size) {
uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
GPR_ASSERT(elem_size < 65536);
GPR_DEBUG_ASSERT(elem_size < 65536);
// TODO(arjunroy): Re-examine semantics
if (elem_size > c->max_table_size) {
while (c->table_size > 0) {
evict_entry(c);
@ -203,6 +211,7 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
while (c->table_size + elem_size > c->max_table_size) {
evict_entry(c);
}
// TODO(arjunroy): Are we conflating size in bytes vs. membership?
GPR_ASSERT(c->table_elems < c->max_table_size);
c->table_elem_size[new_index % c->cap_table_elems] =
static_cast<uint16_t>(elem_size);
@ -215,19 +224,19 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
// Add a key to the dynamic table. Both key and value will be added to table at
// the decoder.
static void add_key_with_index(grpc_chttp2_hpack_compressor* c,
grpc_mdelem elem, uint32_t new_index) {
grpc_mdelem elem, uint32_t new_index,
uint32_t key_hash) {
if (new_index == 0) {
return;
}
uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
/* Store the key into {entries,indices}_keys */
if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
GRPC_MDKEY(elem))) {
if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem))) {
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
} else if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
GRPC_MDKEY(elem))) {
} else if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_3(key_hash)],
GRPC_MDKEY(elem))) {
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
} else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)].refcount ==
&terminal_slice_refcount) {
@ -255,22 +264,20 @@ static void add_key_with_index(grpc_chttp2_hpack_compressor* c,
/* add an element to the decoder table */
static void add_elem_with_index(grpc_chttp2_hpack_compressor* c,
grpc_mdelem elem, uint32_t new_index) {
grpc_mdelem elem, uint32_t new_index,
uint32_t elem_hash, uint32_t key_hash) {
if (new_index == 0) {
return;
}
GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
/* Store this element into {entries,indices}_elem */
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) {
if (grpc_mdelem_both_interned_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)],
elem)) {
/* already there: update with new index */
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
} else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)],
elem)) {
} else if (grpc_mdelem_both_interned_eq(
c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem)) {
/* already there (cuckoo): update with new index */
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
} else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) {
@ -294,19 +301,19 @@ static void add_elem_with_index(grpc_chttp2_hpack_compressor* c,
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
}
add_key_with_index(c, elem, new_index);
add_key_with_index(c, elem, new_index, key_hash);
}
static void add_elem(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
size_t elem_size) {
size_t elem_size, uint32_t elem_hash, uint32_t key_hash) {
uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
add_elem_with_index(c, elem, new_index);
add_elem_with_index(c, elem, new_index, elem_hash, key_hash);
}
static void add_key(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
size_t elem_size) {
size_t elem_size, uint32_t key_hash) {
uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
add_key_with_index(c, elem, new_index);
add_key_with_index(c, elem, new_index, key_hash);
}
static void emit_indexed(grpc_chttp2_hpack_compressor* c, uint32_t elem_index,
@ -323,9 +330,14 @@ typedef struct {
bool insert_null_before_wire_value;
} wire_value;
template <bool mdkey_definitely_interned>
static wire_value get_wire_value(grpc_mdelem elem, bool true_binary_enabled) {
wire_value wire_val;
if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
bool is_bin_hdr =
mdkey_definitely_interned
? grpc_is_refcounted_slice_binary_header(GRPC_MDKEY(elem))
: grpc_is_binary_header_internal(GRPC_MDKEY(elem));
if (is_bin_hdr) {
if (true_binary_enabled) {
GRPC_STATS_INC_HPACK_SEND_BINARY();
wire_val.huffman_prefix = 0x00;
@ -363,7 +375,7 @@ static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor* c,
framer_state* st) {
GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX();
uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
wire_value value = get_wire_value<true>(elem, st->use_true_binary_metadata);
size_t len_val = wire_value_length(value);
uint32_t len_val_len;
GPR_ASSERT(len_val <= UINT32_MAX);
@ -380,7 +392,7 @@ static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor* c,
framer_state* st) {
GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX();
uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
wire_value value = get_wire_value<false>(elem, st->use_true_binary_metadata);
size_t len_val = wire_value_length(value);
uint32_t len_val_len;
GPR_ASSERT(len_val <= UINT32_MAX);
@ -399,7 +411,7 @@ static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor* c,
GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX_V();
GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED();
uint32_t len_key = static_cast<uint32_t> GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
wire_value value = get_wire_value<true>(elem, st->use_true_binary_metadata);
uint32_t len_val = static_cast<uint32_t>(wire_value_length(value));
uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
@ -421,7 +433,7 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor* c,
GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX_V();
GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED();
uint32_t len_key = static_cast<uint32_t> GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
wire_value value = get_wire_value<false>(elem, st->use_true_binary_metadata);
uint32_t len_val = static_cast<uint32_t>(wire_value_length(value));
uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
@ -464,7 +476,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
char* k = grpc_slice_to_c_string(GRPC_MDKEY(elem));
char* v = nullptr;
if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
if (grpc_is_binary_header_internal(GRPC_MDKEY(elem))) {
v = grpc_dump_slice(GRPC_MDVALUE(elem), GPR_DUMP_HEX);
} else {
v = grpc_slice_to_c_string(GRPC_MDVALUE(elem));
@ -488,27 +500,33 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
return;
}
uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
uint32_t elem_hash = 0;
if (elem_interned) {
uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
if (GRPC_MDELEM_STORAGE(elem) == GRPC_MDELEM_STORAGE_INTERNED) {
elem_hash =
reinterpret_cast<grpc_core::InternedMetadata*>(GRPC_MDELEM_DATA(elem))
->hash();
} else {
elem_hash =
reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(elem))
->hash();
}
inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum,
c->filter_elems);
/* is this elem currently in the decoders table? */
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) &&
if (grpc_mdelem_both_interned_eq(
c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (first cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
st);
return;
}
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) &&
if (grpc_mdelem_both_interned_eq(
c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (second cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
@ -527,11 +545,12 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
uint32_t key_hash = GRPC_MDKEY(elem).refcount->Hash(GRPC_MDKEY(elem));
auto emit_maybe_add = [&should_add_elem, &elem, &st, &c, &indices_key,
&decoder_space_usage] {
&decoder_space_usage, &elem_hash, &key_hash] {
if (should_add_elem) {
emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
add_elem(c, elem, decoder_space_usage);
add_elem(c, elem, decoder_space_usage, elem_hash, key_hash);
} else {
emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
}
@ -539,8 +558,8 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
/* no hits for the elem... maybe there's a key? */
indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
GRPC_MDKEY(elem)) &&
if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
emit_maybe_add();
@ -548,8 +567,8 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
}
indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
GRPC_MDKEY(elem)) &&
if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_3(key_hash)], GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
emit_maybe_add();
@ -565,9 +584,9 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
emit_lithdr_noidx_v(c, 0, elem, st);
}
if (should_add_elem) {
add_elem(c, elem, decoder_space_usage);
add_elem(c, elem, decoder_space_usage, elem_hash, key_hash);
} else if (should_add_key) {
add_key(c, elem, decoder_space_usage);
add_key(c, elem, decoder_space_usage, key_hash);
}
}
@ -692,18 +711,18 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor* c,
}
for (size_t i = 0; i < extra_headers_size; ++i) {
grpc_mdelem md = *extra_headers[i];
uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(md);
uintptr_t static_index = grpc_chttp2_get_static_hpack_table_index(md);
if (static_index) {
emit_indexed(c, static_index, &st);
emit_indexed(c, static_cast<uint32_t>(static_index), &st);
} else {
hpack_enc(c, md, &st);
}
}
grpc_metadata_batch_assert_ok(metadata);
for (grpc_linked_mdelem* l = metadata->list.head; l; l = l->next) {
uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md);
uintptr_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md);
if (static_index) {
emit_indexed(c, static_index, &st);
emit_indexed(c, static_cast<uint32_t>(static_index), &st);
} else {
hpack_enc(c, l->md, &st);
}

@ -35,6 +35,7 @@
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/http2_errors.h"
typedef enum {
@ -627,7 +628,7 @@ static grpc_error* on_hdr(grpc_chttp2_hpack_parser* p, grpc_mdelem md,
if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
char* k = grpc_slice_to_c_string(GRPC_MDKEY(md));
char* v = nullptr;
if (grpc_is_binary_header(GRPC_MDKEY(md))) {
if (grpc_is_binary_header_internal(GRPC_MDKEY(md))) {
v = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX);
} else {
v = grpc_slice_to_c_string(GRPC_MDVALUE(md));
@ -1494,7 +1495,13 @@ static grpc_error* parse_key_string(grpc_chttp2_hpack_parser* p,
/* check if a key represents a binary header or not */
static bool is_binary_literal_header(grpc_chttp2_hpack_parser* p) {
return grpc_is_binary_header(
/* We know that either argument here is a reference counter slice.
* 1. If a result of grpc_slice_from_static_buffer, the refcount is set to
* NoopRefcount.
* 2. If it's p->key.data.referenced, then p->key.copied was set to false,
* which occurs in begin_parse_string() - where the refcount is set to
* p->current_slice_refcount, which is not null. */
return grpc_is_refcounted_slice_binary_header(
p->key.copied ? grpc_slice_from_static_buffer(p->key.data.copied.str,
p->key.data.copied.length)
: p->key.data.referenced);
@ -1511,7 +1518,15 @@ static grpc_error* is_binary_indexed_header(grpc_chttp2_hpack_parser* p,
static_cast<intptr_t>(p->index)),
GRPC_ERROR_INT_SIZE, static_cast<intptr_t>(p->table.num_ents));
}
*is = grpc_is_binary_header(GRPC_MDKEY(elem));
/* We know that GRPC_MDKEY(elem) points to a reference counted slice since:
* 1. elem was a result of grpc_chttp2_hptbl_lookup
* 2. An item in this table is either static (see entries with
* index < GRPC_CHTTP2_LAST_STATIC_ENTRY or added via
* grpc_chttp2_hptbl_add).
* 3. If added via grpc_chttp2_hptbl_add, the entry is either static or
* interned.
* 4. Both static and interned element slices have non-null refcounts. */
*is = grpc_is_refcounted_slice_binary_header(GRPC_MDKEY(elem));
return GRPC_ERROR_NONE;
}

@ -29,6 +29,7 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/murmur_hash.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/static_metadata.h"
extern grpc_core::TraceFlag grpc_http_trace;
@ -375,9 +376,11 @@ static size_t get_base64_encoded_size(size_t raw_length) {
size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
bool use_true_binary_metadata) {
size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
const uint8_t* key_buf = GRPC_SLICE_START_PTR(GRPC_MDKEY(elem));
size_t key_len = GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
size_t overhead_and_key = 32 + key_len;
size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
if (grpc_key_is_binary_header(key_buf, key_len)) {
return overhead_and_key + (use_true_binary_metadata
? value_len + 1
: get_base64_encoded_size(value_len));
@ -385,13 +388,3 @@ size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
return overhead_and_key + value_len;
}
}
uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md) {
if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
uint8_t index = GRPC_MDELEM_DATA(md) - grpc_static_mdelem_table;
if (index < GRPC_CHTTP2_LAST_STATIC_ENTRY) {
return index + 1; // Hpack static metadata element indices start at 1
}
}
return 0;
}

@ -24,6 +24,7 @@
#include <grpc/slice.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
/* HPACK header table */
@ -90,7 +91,15 @@ size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
/* Returns the static hpack table index that corresponds to /a elem. Returns 0
if /a elem is not statically stored or if it is not in the static hpack
table */
uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md);
inline uintptr_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md) {
uintptr_t index =
reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(md)) -
grpc_static_mdelem_table;
if (index < GRPC_CHTTP2_LAST_STATIC_ENTRY) {
return index + 1; // Hpack static metadata element indices start at 1
}
return 0;
}
/* Find a key/value pair in the table... returns the index in the table of the
most similar entry, or 0 if the value was not found */

@ -38,6 +38,7 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/transport_impl.h"
@ -419,7 +420,7 @@ static void convert_cronet_array_to_metadata(
grpc_slice key = grpc_slice_intern(
grpc_slice_from_static_string(header_array->headers[i].key));
grpc_slice value;
if (grpc_is_binary_header(key)) {
if (grpc_is_refcounted_slice_binary_header(key)) {
value = grpc_slice_from_static_string(header_array->headers[i].value);
value = grpc_slice_intern(grpc_chttp2_base64_decode_with_length(
value, grpc_chttp2_base64_infer_length_after_decode(value)));
@ -746,7 +747,7 @@ static void convert_metadata_to_cronet_headers(
curr = curr->next;
char* key = grpc_slice_to_c_string(GRPC_MDKEY(mdelem));
char* value;
if (grpc_is_binary_header(GRPC_MDKEY(mdelem))) {
if (grpc_is_binary_header_internal(GRPC_MDKEY(mdelem))) {
grpc_slice wire_value = grpc_chttp2_base64_encode(GRPC_MDVALUE(mdelem));
value = grpc_slice_to_c_string(wire_value);
grpc_slice_unref_internal(wire_value);

@ -795,9 +795,9 @@ grpc_error* grpc_wsa_error(const char* file, int line, int err,
}
#endif
bool grpc_log_if_error(const char* what, grpc_error* error, const char* file,
int line) {
if (error == GRPC_ERROR_NONE) return true;
bool grpc_log_error(const char* what, grpc_error* error, const char* file,
int line) {
GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
const char* msg = grpc_error_string(error);
gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg);
GRPC_ERROR_UNREF(error);

@ -261,9 +261,15 @@ grpc_error* grpc_wsa_error(const char* file, int line, int err,
#define GRPC_WSA_ERROR(err, call_name) \
grpc_wsa_error(__FILE__, __LINE__, err, call_name)
bool grpc_log_if_error(const char* what, grpc_error* error, const char* file,
int line);
bool grpc_log_error(const char* what, grpc_error* error, const char* file,
int line);
inline bool grpc_log_if_error(const char* what, grpc_error* error,
const char* file, int line) {
return error == GRPC_ERROR_NONE ? true
: grpc_log_error(what, error, file, line);
}
#define GRPC_LOG_IF_ERROR(what, error) \
grpc_log_if_error((what), (error), __FILE__, __LINE__)
(grpc_log_if_error((what), (error), __FILE__, __LINE__))
#endif /* GRPC_CORE_LIB_IOMGR_ERROR_H */

@ -57,10 +57,10 @@ void grpc_iomgr_init() {
gpr_mu_init(&g_mu);
gpr_cv_init(&g_rcv);
grpc_core::Executor::InitAll();
grpc_timer_list_init();
g_root_object.next = g_root_object.prev = &g_root_object;
g_root_object.name = (char*)"root";
grpc_iomgr_platform_init();
grpc_timer_list_init();
grpc_core::grpc_errqueue_init();
}

@ -29,7 +29,8 @@
typedef struct grpc_timer {
grpc_millis deadline;
uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */
// Uninitialized if not using heap, or INVALID_HEAP_INDEX if not in heap.
uint32_t heap_index;
bool pending;
struct grpc_timer* next;
struct grpc_timer* prev;

@ -85,7 +85,7 @@ static grpc_error* process_plugin_result(
grpc_validate_header_key_is_legal(md[i].key))) {
seen_illegal_header = true;
break;
} else if (!grpc_is_binary_header(md[i].key) &&
} else if (!grpc_is_binary_header_internal(md[i].key) &&
!GRPC_LOG_IF_ERROR(
"validate_metadata_from_plugin",
grpc_validate_header_nonbin_value_is_legal(md[i].value))) {

@ -68,7 +68,8 @@ void grpc_slice_unref(grpc_slice slice) {
/* grpc_slice_from_static_string support structure - a refcount that does
nothing */
static grpc_slice_refcount NoopRefcount;
static grpc_slice_refcount NoopRefcount =
grpc_slice_refcount(grpc_slice_refcount::Type::NOP);
size_t grpc_slice_memory_usage(grpc_slice s) {
if (s.refcount == nullptr || s.refcount == &NoopRefcount) {

@ -138,7 +138,7 @@ SliceHashTable<T>::~SliceHashTable() {
template <typename T>
void SliceHashTable<T>::Add(const grpc_slice& key, T& value) {
const size_t hash = grpc_slice_hash(key);
const size_t hash = grpc_slice_hash_internal(key);
for (size_t offset = 0; offset < size_; ++offset) {
const size_t idx = (hash + offset) % size_;
if (!entries_[idx].is_set) {
@ -156,7 +156,7 @@ void SliceHashTable<T>::Add(const grpc_slice& key, T& value) {
template <typename T>
const T* SliceHashTable<T>::Get(const grpc_slice& key) const {
const size_t hash = grpc_slice_hash(key);
const size_t hash = grpc_slice_hash_internal(key);
// We cap the number of probes at the max number recorded when
// populating the table.
for (size_t offset = 0; offset <= max_num_probes_; ++offset) {

@ -128,10 +128,7 @@ int grpc_static_slice_eq(grpc_slice a, grpc_slice b) {
return GRPC_STATIC_METADATA_INDEX(a) == GRPC_STATIC_METADATA_INDEX(b);
}
uint32_t grpc_slice_hash(grpc_slice s) {
return s.refcount == nullptr ? grpc_slice_default_hash_impl(s)
: s.refcount->Hash(s);
}
uint32_t grpc_slice_hash(grpc_slice s) { return grpc_slice_hash_internal(s); }
grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
bool* returned_slice_is_different) {
@ -139,7 +136,7 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
return slice;
}
uint32_t hash = grpc_slice_hash(slice);
uint32_t hash = grpc_slice_hash_internal(slice);
for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
static_metadata_hash_ent ent =
static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)];
@ -154,19 +151,13 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
return slice;
}
bool grpc_slice_is_interned(const grpc_slice& slice) {
return (slice.refcount &&
(slice.refcount->GetType() == grpc_slice_refcount::Type::INTERNED ||
GRPC_IS_STATIC_METADATA_STRING(slice)));
}
grpc_slice grpc_slice_intern(grpc_slice slice) {
GPR_TIMER_SCOPE("grpc_slice_intern", 0);
if (GRPC_IS_STATIC_METADATA_STRING(slice)) {
return slice;
}
uint32_t hash = grpc_slice_hash(slice);
uint32_t hash = grpc_slice_hash_internal(slice);
for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
static_metadata_hash_ent ent =
@ -238,7 +229,7 @@ void grpc_slice_intern_init(void) {
max_static_metadata_hash_probe = 0;
for (size_t i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
grpc_static_metadata_hash_values[i] =
grpc_slice_default_hash_impl(grpc_static_slice_table[i]);
grpc_slice_default_hash_internal(grpc_static_slice_table[i]);
for (size_t j = 0; j < GPR_ARRAY_SIZE(static_metadata_hash); j++) {
size_t slot = (grpc_static_metadata_hash_values[i] + j) %
GPR_ARRAY_SIZE(static_metadata_hash);
@ -252,6 +243,10 @@ void grpc_slice_intern_init(void) {
}
}
}
// Handle KV hash for all static mdelems.
for (size_t i = 0; i < GRPC_STATIC_MDELEM_COUNT; ++i) {
grpc_static_mdelem_table[i].HashInit();
}
}
void grpc_slice_intern_shutdown(void) {

@ -99,12 +99,15 @@ struct grpc_slice_refcount {
enum class Type {
STATIC, // Refcount for a static metadata slice.
INTERNED, // Refcount for an interned slice.
NOP, // No-Op
REGULAR // Refcount for non-static-metadata, non-interned slices.
};
typedef void (*DestroyerFn)(void*);
grpc_slice_refcount() = default;
explicit grpc_slice_refcount(Type t) : ref_type_(t) {}
explicit grpc_slice_refcount(grpc_slice_refcount* sub) : sub_refcount_(sub) {}
// Regular constructor for grpc_slice_refcount.
//
@ -200,6 +203,7 @@ inline int grpc_slice_refcount::Eq(const grpc_slice& a, const grpc_slice& b) {
return GRPC_STATIC_METADATA_INDEX(a) == GRPC_STATIC_METADATA_INDEX(b);
case Type::INTERNED:
return a.refcount == b.refcount;
case Type::NOP:
case Type::REGULAR:
break;
}
@ -217,6 +221,7 @@ inline uint32_t grpc_slice_refcount::Hash(const grpc_slice& slice) {
case Type::INTERNED:
return reinterpret_cast<grpc_core::InternedSliceRefcount*>(slice.refcount)
->hash;
case Type::NOP:
case Type::REGULAR:
break;
}
@ -258,6 +263,17 @@ void grpc_slice_buffer_sub_first(grpc_slice_buffer* sb, size_t begin,
/* Check if a slice is interned */
bool grpc_slice_is_interned(const grpc_slice& slice);
inline bool grpc_slice_is_interned(const grpc_slice& slice) {
return (slice.refcount &&
(slice.refcount->GetType() == grpc_slice_refcount::Type::INTERNED ||
slice.refcount->GetType() == grpc_slice_refcount::Type::STATIC));
}
inline bool grpc_slice_static_interned_equal(const grpc_slice& a,
const grpc_slice& b) {
GPR_DEBUG_ASSERT(grpc_slice_is_interned(a) && grpc_slice_is_interned(b));
return a.refcount == b.refcount;
}
void grpc_slice_intern_init(void);
void grpc_slice_intern_shutdown(void);
@ -271,6 +287,21 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
uint32_t grpc_static_slice_hash(grpc_slice s);
int grpc_static_slice_eq(grpc_slice a, grpc_slice b);
inline uint32_t grpc_slice_hash_refcounted(const grpc_slice& s) {
GPR_DEBUG_ASSERT(s.refcount != nullptr);
return s.refcount->Hash(s);
}
inline uint32_t grpc_slice_default_hash_internal(const grpc_slice& s) {
return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s),
g_hash_seed);
}
inline uint32_t grpc_slice_hash_internal(const grpc_slice& s) {
return s.refcount == nullptr ? grpc_slice_default_hash_internal(s)
: grpc_slice_hash_refcounted(s);
}
// Returns the memory used by this slice, not counting the slice structure
// itself. This means that inlined and slices from static strings will return
// 0. All other slices will return the size of the allocated chars.

@ -27,7 +27,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/slice/slice_internal.h"
char* grpc_dump_slice(grpc_slice s, uint32_t flags) {
char* grpc_dump_slice(const grpc_slice& s, uint32_t flags) {
return gpr_dump(reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s),
GRPC_SLICE_LENGTH(s), flags);
}

@ -30,7 +30,7 @@
#include "src/core/lib/gpr/string.h"
/* Calls gpr_dump on a slice. */
char* grpc_dump_slice(grpc_slice slice, uint32_t flags);
char* grpc_dump_slice(const grpc_slice& slice, uint32_t flags);
/** Split \a str by the separator \a sep. Results are stored in \a dst, which
* should be a properly initialized instance. */

@ -47,7 +47,7 @@ class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> {
/// Add a mapping from \a key to \a value, taking ownership of \a key. This
/// operation will always succeed. It may discard older entries.
void Add(const grpc_slice& key, T value) {
const size_t idx = grpc_slice_hash(key) % Size;
const size_t idx = grpc_slice_hash_internal(key) % Size;
entries_[idx].Set(key, std::move(value));
return;
}
@ -55,7 +55,7 @@ class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> {
/// Returns the value from the table associated with / \a key or null if not
/// found.
const T* Get(const grpc_slice& key) const {
const size_t idx = grpc_slice_hash(key) % Size;
const size_t idx = grpc_slice_hash_internal(key) % Size;
const auto& entry = entries_[idx];
return grpc_slice_eq(entry.key(), key) ? entry.value() : nullptr;
}

@ -74,7 +74,7 @@
#define ESTIMATED_MDELEM_COUNT 16
struct batch_control {
batch_control() { gpr_ref_init(&steps_to_complete, 0); }
batch_control() = default;
grpc_call* call = nullptr;
grpc_transport_stream_op_batch op;
@ -99,8 +99,14 @@ struct batch_control {
} completion_data;
grpc_closure start_batch;
grpc_closure finish_batch;
gpr_refcount steps_to_complete;
grpc_core::Atomic<intptr_t> steps_to_complete;
gpr_atm batch_error = reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE);
void set_num_steps_to_complete(uintptr_t steps) {
steps_to_complete.Store(steps, grpc_core::MemoryOrder::RELEASE);
}
bool completed_batch_step() {
return steps_to_complete.FetchSub(1, grpc_core::MemoryOrder::ACQ_REL) == 1;
}
};
struct parent_call {
@ -899,7 +905,7 @@ static int prepare_application_metadata(grpc_call* call, int count,
if (!GRPC_LOG_IF_ERROR("validate_metadata",
grpc_validate_header_key_is_legal(md->key))) {
break;
} else if (!grpc_is_binary_header(md->key) &&
} else if (!grpc_is_binary_header_internal(md->key) &&
!GRPC_LOG_IF_ERROR(
"validate_metadata",
grpc_validate_header_nonbin_value_is_legal(md->value))) {
@ -1225,7 +1231,7 @@ static void post_batch_completion(batch_control* bctl) {
}
static void finish_batch_step(batch_control* bctl) {
if (GPR_UNLIKELY(gpr_unref(&bctl->steps_to_complete))) {
if (GPR_UNLIKELY(bctl->completed_batch_step())) {
post_batch_completion(bctl);
}
}
@ -1866,7 +1872,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
if (!is_notify_tag_closure) {
GPR_ASSERT(grpc_cq_begin_op(call->cq, notify_tag));
}
gpr_ref_init(&bctl->steps_to_complete, (has_send_ops ? 1 : 0) + num_recv_ops);
bctl->set_num_steps_to_complete((has_send_ops ? 1 : 0) + num_recv_ops);
if (has_send_ops) {
GRPC_CLOSURE_INIT(&bctl->finish_batch, finish_batch, bctl,

@ -59,23 +59,6 @@ typedef struct registered_call {
struct registered_call* next;
} registered_call;
struct grpc_channel {
int is_client;
grpc_compression_options compression_options;
gpr_atm call_size_estimate;
grpc_resource_user* resource_user;
gpr_mu registered_call_mu;
registered_call* registered_calls;
grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_channel;
char* target;
};
#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack*)((c) + 1))
static void destroy_channel(void* arg, grpc_error* error);
grpc_channel* grpc_channel_create_with_builder(
@ -214,11 +197,6 @@ static grpc_channel_args* build_channel_args(
return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args);
}
grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
grpc_channel* channel) {
return channel->channelz_channel.get();
}
grpc_channel* grpc_channel_create(const char* target,
const grpc_channel_args* input_args,
grpc_channel_stack_type channel_stack_type,
@ -421,21 +399,6 @@ grpc_call* grpc_channel_create_registered_call(
return call;
}
#ifndef NDEBUG
#define REF_REASON reason
#define REF_ARG , const char* reason
#else
#define REF_REASON ""
#define REF_ARG
#endif
void grpc_channel_internal_ref(grpc_channel* c REF_ARG) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
}
void grpc_channel_internal_unref(grpc_channel* c REF_ARG) {
GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
}
static void destroy_channel(void* arg, grpc_error* error) {
grpc_channel* channel = static_cast<grpc_channel*>(arg);
if (channel->channelz_channel != nullptr) {
@ -475,25 +438,9 @@ void grpc_channel_destroy(grpc_channel* channel) {
GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel");
}
grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
grpc_compression_options grpc_channel_compression_options(
const grpc_channel* channel) {
return channel->compression_options;
}
grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel, int i) {
grpc_mdelem grpc_channel_get_reffed_status_elem_slowpath(grpc_channel* channel,
int i) {
char tmp[GPR_LTOA_MIN_BUFSIZE];
switch (i) {
case 0:
return GRPC_MDELEM_GRPC_STATUS_0;
case 1:
return GRPC_MDELEM_GRPC_STATUS_1;
case 2:
return GRPC_MDELEM_GRPC_STATUS_2;
}
gpr_ltoa(i, tmp);
return grpc_mdelem_from_slices(GRPC_MDSTR_GRPC_STATUS,
grpc_slice_from_copied_string(tmp));

@ -59,22 +59,76 @@ grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
status_code.
The returned elem is owned by the caller. */
grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel,
int status_code);
grpc_mdelem grpc_channel_get_reffed_status_elem_slowpath(grpc_channel* channel,
int status_code);
inline grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel,
int status_code) {
switch (status_code) {
case 0:
return GRPC_MDELEM_GRPC_STATUS_0;
case 1:
return GRPC_MDELEM_GRPC_STATUS_1;
case 2:
return GRPC_MDELEM_GRPC_STATUS_2;
}
return grpc_channel_get_reffed_status_elem_slowpath(channel, status_code);
}
size_t grpc_channel_get_call_size_estimate(grpc_channel* channel);
void grpc_channel_update_call_size_estimate(grpc_channel* channel, size_t size);
struct registered_call;
struct grpc_channel {
int is_client;
grpc_compression_options compression_options;
gpr_atm call_size_estimate;
grpc_resource_user* resource_user;
gpr_mu registered_call_mu;
registered_call* registered_calls;
grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_channel;
char* target;
};
#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack*)((c) + 1))
inline grpc_compression_options grpc_channel_compression_options(
const grpc_channel* channel) {
return channel->compression_options;
}
inline grpc_channel_stack* grpc_channel_get_channel_stack(
grpc_channel* channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
inline grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
grpc_channel* channel) {
return channel->channelz_channel.get();
}
#ifndef NDEBUG
void grpc_channel_internal_ref(grpc_channel* channel, const char* reason);
void grpc_channel_internal_unref(grpc_channel* channel, const char* reason);
inline void grpc_channel_internal_ref(grpc_channel* channel,
const char* reason) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(channel), reason);
}
inline void grpc_channel_internal_unref(grpc_channel* channel,
const char* reason) {
GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CHANNEL(channel), reason);
}
#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
grpc_channel_internal_ref(channel, reason)
#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
grpc_channel_internal_unref(channel, reason)
#else
void grpc_channel_internal_ref(grpc_channel* channel);
void grpc_channel_internal_unref(grpc_channel* channel);
inline void grpc_channel_internal_ref(grpc_channel* channel) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(channel), "unused");
}
inline void grpc_channel_internal_unref(grpc_channel* channel) {
GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CHANNEL(channel), "unused");
}
#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
grpc_channel_internal_ref(channel)
#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \

@ -34,6 +34,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gprpp/atomic.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/profiling/timers.h"
@ -200,7 +201,7 @@ struct cq_vtable {
bool (*begin_op)(grpc_completion_queue* cq, void* tag);
void (*end_op)(grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
void* done_arg, grpc_cq_completion* storage, bool internal);
grpc_event (*next)(grpc_completion_queue* cq, gpr_timespec deadline,
void* reserved);
grpc_event (*pluck)(grpc_completion_queue* cq, void* tag,
@ -354,23 +355,20 @@ static bool cq_begin_op_for_callback(grpc_completion_queue* cq, void* tag);
// queue. The done argument is a callback that will be invoked when it is
// safe to free up that storage. The storage MUST NOT be freed until the
// done callback is invoked.
static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
static void cq_end_op_for_callback(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
static void cq_end_op_for_next(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal);
static void cq_end_op_for_pluck(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal);
static void cq_end_op_for_callback(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal);
static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline,
void* reserved);
@ -674,11 +672,10 @@ bool grpc_cq_begin_op(grpc_completion_queue* cq, void* tag) {
/* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a
* completion
* type of GRPC_CQ_NEXT) */
static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage) {
static void cq_end_op_for_next(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal) {
GPR_TIMER_SCOPE("cq_end_op_for_next", 0);
if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
@ -754,11 +751,10 @@ static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
/* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a
* completion
* type of GRPC_CQ_PLUCK) */
static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage) {
static void cq_end_op_for_pluck(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal) {
GPR_TIMER_SCOPE("cq_end_op_for_pluck", 0);
cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
@ -821,15 +817,19 @@ static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
GRPC_ERROR_UNREF(error);
}
static void functor_callback(void* arg, grpc_error* error) {
auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(arg);
functor->functor_run(functor, error == GRPC_ERROR_NONE);
}
/* Complete an event on a completion queue of type GRPC_CQ_CALLBACK */
static void cq_end_op_for_callback(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage) {
grpc_cq_completion* storage, bool internal) {
GPR_TIMER_SCOPE("cq_end_op_for_callback", 0);
cq_callback_data* cqd = static_cast<cq_callback_data*> DATA_FROM_CQ(cq);
bool is_success = (error == GRPC_ERROR_NONE);
if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
(GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
@ -856,16 +856,25 @@ static void cq_end_op_for_callback(
cq_finish_shutdown_callback(cq);
}
GRPC_ERROR_UNREF(error);
auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(tag);
grpc_core::ApplicationCallbackExecCtx::Enqueue(functor, is_success);
if (internal) {
grpc_core::ApplicationCallbackExecCtx::Enqueue(functor,
(error == GRPC_ERROR_NONE));
GRPC_ERROR_UNREF(error);
} else {
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(
functor_callback, functor,
grpc_core::Executor::Scheduler(grpc_core::ExecutorJobType::SHORT)),
error);
}
}
void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage) {
cq->vtable->end_op(cq, tag, error, done, done_arg, storage);
void* done_arg, grpc_cq_completion* storage,
bool internal) {
cq->vtable->end_op(cq, tag, error, done, done_arg, storage, internal);
}
typedef struct {
@ -1343,7 +1352,11 @@ static void cq_finish_shutdown_callback(grpc_completion_queue* cq) {
GPR_ASSERT(cqd->shutdown_called);
cq->poller_vtable->shutdown(POLLSET_FROM_CQ(cq), &cq->pollset_shutdown_done);
grpc_core::ApplicationCallbackExecCtx::Enqueue(callback, true);
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(
functor_callback, callback,
grpc_core::Executor::Scheduler(grpc_core::ExecutorJobType::SHORT)),
GRPC_ERROR_NONE);
}
static void cq_shutdown_callback(grpc_completion_queue* cq) {

@ -77,7 +77,8 @@ bool grpc_cq_begin_op(grpc_completion_queue* cc, void* tag);
grpc_cq_begin_op */
void grpc_cq_end_op(grpc_completion_queue* cc, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
void* done_arg, grpc_cq_completion* storage,
bool internal = false);
grpc_pollset* grpc_cq_pollset(grpc_completion_queue* cc);

@ -513,7 +513,7 @@ static void publish_call(grpc_server* server, call_data* calld, size_t cq_idx,
}
grpc_cq_end_op(calld->cq_new, rc->tag, GRPC_ERROR_NONE, done_request_event,
rc, &rc->completion);
rc, &rc->completion, true);
}
static void publish_new_rpc(void* arg, grpc_error* error) {
@ -625,8 +625,8 @@ static void start_new_rpc(grpc_call_element* elem) {
if (chand->registered_methods && calld->path_set && calld->host_set) {
/* TODO(ctiller): unify these two searches */
/* check for an exact match with host */
hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(calld->host),
grpc_slice_hash(calld->path));
hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash_internal(calld->host),
grpc_slice_hash_internal(calld->path));
for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots];
@ -644,7 +644,7 @@ static void start_new_rpc(grpc_call_element* elem) {
return;
}
/* check for a wildcard method definition (no host set) */
hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash(calld->path));
hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash_internal(calld->path));
for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots];
@ -1200,8 +1200,8 @@ void grpc_server_setup_transport(
has_host = false;
}
method = grpc_slice_intern(grpc_slice_from_static_string(rm->method));
hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash(host) : 0,
grpc_slice_hash(method));
hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash_internal(host) : 0,
grpc_slice_hash_internal(method));
for (probes = 0; chand->registered_methods[(hash + probes) % slots]
.server_registered_method != nullptr;
probes++)

@ -29,7 +29,8 @@
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/validate_metadata.h"
static grpc_error* conforms_to(grpc_slice slice, const uint8_t* legal_bits,
static grpc_error* conforms_to(const grpc_slice& slice,
const uint8_t* legal_bits,
const char* err_desc) {
const uint8_t* p = GRPC_SLICE_START_PTR(slice);
const uint8_t* e = GRPC_SLICE_END_PTR(slice);
@ -57,7 +58,7 @@ static int error2int(grpc_error* error) {
return r;
}
grpc_error* grpc_validate_header_key_is_legal(grpc_slice slice) {
grpc_error* grpc_validate_header_key_is_legal(const grpc_slice& slice) {
static const uint8_t legal_header_bits[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00,
0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -77,7 +78,8 @@ int grpc_header_key_is_legal(grpc_slice slice) {
return error2int(grpc_validate_header_key_is_legal(slice));
}
grpc_error* grpc_validate_header_nonbin_value_is_legal(grpc_slice slice) {
grpc_error* grpc_validate_header_nonbin_value_is_legal(
const grpc_slice& slice) {
static const uint8_t legal_header_bits[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -89,7 +91,11 @@ int grpc_header_nonbin_value_is_legal(grpc_slice slice) {
return error2int(grpc_validate_header_nonbin_value_is_legal(slice));
}
int grpc_is_binary_header_internal(const grpc_slice& slice) {
return grpc_key_is_binary_header(GRPC_SLICE_START_PTR(slice),
GRPC_SLICE_LENGTH(slice));
}
int grpc_is_binary_header(grpc_slice slice) {
if (GRPC_SLICE_LENGTH(slice) < 5) return 0;
return 0 == memcmp(GRPC_SLICE_END_PTR(slice) - 4, "-bin", 4);
return grpc_is_binary_header_internal(slice);
}

@ -24,7 +24,18 @@
#include <grpc/slice.h>
#include "src/core/lib/iomgr/error.h"
grpc_error* grpc_validate_header_key_is_legal(grpc_slice slice);
grpc_error* grpc_validate_header_nonbin_value_is_legal(grpc_slice slice);
grpc_error* grpc_validate_header_key_is_legal(const grpc_slice& slice);
grpc_error* grpc_validate_header_nonbin_value_is_legal(const grpc_slice& slice);
int grpc_is_binary_header_internal(const grpc_slice& slice);
inline int grpc_key_is_binary_header(const uint8_t* buf, size_t length) {
if (length < 5) return 0;
return 0 == memcmp(buf + length - 4, "-bin", 4);
}
inline int grpc_is_refcounted_slice_binary_header(const grpc_slice& slice) {
GPR_DEBUG_ASSERT(slice.refcount != nullptr);
return grpc_key_is_binary_header(slice.data.refcounted.bytes,
slice.data.refcounted.length);
}
#endif /* GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H */

@ -43,6 +43,7 @@
using grpc_core::AllocatedMetadata;
using grpc_core::InternedMetadata;
using grpc_core::StaticMetadata;
using grpc_core::UserData;
/* There are two kinds of mdelem and mdstr instances.
@ -100,15 +101,20 @@ void grpc_mdelem_trace_unref(void* md, const grpc_slice& key,
#define TABLE_IDX(hash, capacity) (((hash) >> (LOG2_SHARD_COUNT)) % (capacity))
#define SHARD_IDX(hash) ((hash) & ((1 << (LOG2_SHARD_COUNT)) - 1))
void StaticMetadata::HashInit() {
uint32_t k_hash = grpc_slice_hash_internal(kv_.key);
uint32_t v_hash = grpc_slice_hash_internal(kv_.value);
hash_ = GRPC_MDSTR_KV_HASH(k_hash, v_hash);
}
AllocatedMetadata::AllocatedMetadata(const grpc_slice& key,
const grpc_slice& value)
: key_(grpc_slice_ref_internal(key)),
value_(grpc_slice_ref_internal(value)),
refcnt_(1) {
: RefcountedMdBase(grpc_slice_ref_internal(key),
grpc_slice_ref_internal(value)) {
#ifndef NDEBUG
if (grpc_trace_metadata.enabled()) {
char* key_str = grpc_slice_to_c_string(key_);
char* value_str = grpc_slice_to_c_string(value_);
char* key_str = grpc_slice_to_c_string(key);
char* value_str = grpc_slice_to_c_string(value);
gpr_log(GPR_DEBUG, "ELM ALLOC:%p:%" PRIdPTR ": '%s' = '%s'", this,
RefValue(), key_str, value_str);
gpr_free(key_str);
@ -118,8 +124,8 @@ AllocatedMetadata::AllocatedMetadata(const grpc_slice& key,
}
AllocatedMetadata::~AllocatedMetadata() {
grpc_slice_unref_internal(key_);
grpc_slice_unref_internal(value_);
grpc_slice_unref_internal(key());
grpc_slice_unref_internal(value());
void* user_data = user_data_.data.Load(grpc_core::MemoryOrder::RELAXED);
if (user_data) {
destroy_user_data_func destroy_user_data =
@ -131,15 +137,13 @@ AllocatedMetadata::~AllocatedMetadata() {
InternedMetadata::InternedMetadata(const grpc_slice& key,
const grpc_slice& value, uint32_t hash,
InternedMetadata* next)
: key_(grpc_slice_ref_internal(key)),
value_(grpc_slice_ref_internal(value)),
refcnt_(1),
hash_(hash),
: RefcountedMdBase(grpc_slice_ref_internal(key),
grpc_slice_ref_internal(value), hash),
link_(next) {
#ifndef NDEBUG
if (grpc_trace_metadata.enabled()) {
char* key_str = grpc_slice_to_c_string(key_);
char* value_str = grpc_slice_to_c_string(value_);
char* key_str = grpc_slice_to_c_string(key);
char* value_str = grpc_slice_to_c_string(value);
gpr_log(GPR_DEBUG, "ELM NEW:%p:%" PRIdPTR ": '%s' = '%s'", this,
RefValue(), key_str, value_str);
gpr_free(key_str);
@ -149,8 +153,8 @@ InternedMetadata::InternedMetadata(const grpc_slice& key,
}
InternedMetadata::~InternedMetadata() {
grpc_slice_unref_internal(key_);
grpc_slice_unref_internal(value_);
grpc_slice_unref_internal(key());
grpc_slice_unref_internal(value());
void* user_data = user_data_.data.Load(grpc_core::MemoryOrder::RELAXED);
if (user_data) {
destroy_user_data_func destroy_user_data =
@ -223,17 +227,20 @@ void grpc_mdctx_global_shutdown() {
}
}
#ifndef NDEBUG
static int is_mdelem_static(grpc_mdelem e) {
return GRPC_MDELEM_DATA(e) >= &grpc_static_mdelem_table[0] &&
GRPC_MDELEM_DATA(e) <
return reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(e)) >=
&grpc_static_mdelem_table[0] &&
reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(e)) <
&grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
}
#endif
void InternedMetadata::RefWithShardLocked(mdtab_shard* shard) {
#ifndef NDEBUG
if (grpc_trace_metadata.enabled()) {
char* key_str = grpc_slice_to_c_string(key_);
char* value_str = grpc_slice_to_c_string(value_);
char* key_str = grpc_slice_to_c_string(key());
char* value_str = grpc_slice_to_c_string(value());
intptr_t value = RefValue();
gpr_log(__FILE__, __LINE__, GPR_LOG_SEVERITY_DEBUG,
"ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", this, value,
@ -323,8 +330,8 @@ grpc_mdelem grpc_mdelem_create(
}
}
uint32_t hash =
GRPC_MDSTR_KV_HASH(grpc_slice_hash(key), grpc_slice_hash(value));
uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash_refcounted(key),
grpc_slice_hash_refcounted(value));
InternedMetadata* md;
mdtab_shard* shard = &g_shards[SHARD_IDX(hash)];
size_t idx;
@ -391,8 +398,11 @@ void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*destroy_func)(void*)) {
case GRPC_MDELEM_STORAGE_EXTERNAL:
return nullptr;
case GRPC_MDELEM_STORAGE_STATIC:
return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
grpc_static_mdelem_table];
return reinterpret_cast<void*>(
grpc_static_mdelem_user_data
[reinterpret_cast<grpc_core::StaticMetadata*>(
GRPC_MDELEM_DATA(md)) -
grpc_static_mdelem_table]);
case GRPC_MDELEM_STORAGE_ALLOCATED: {
auto* am = reinterpret_cast<AllocatedMetadata*>(GRPC_MDELEM_DATA(md));
return get_user_data(am->user_data(), destroy_func);
@ -430,15 +440,18 @@ void* grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void*),
return nullptr;
case GRPC_MDELEM_STORAGE_STATIC:
destroy_func(data);
return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
grpc_static_mdelem_table];
return reinterpret_cast<void*>(
grpc_static_mdelem_user_data
[reinterpret_cast<grpc_core::StaticMetadata*>(
GRPC_MDELEM_DATA(md)) -
grpc_static_mdelem_table]);
case GRPC_MDELEM_STORAGE_ALLOCATED: {
auto* am = reinterpret_cast<AllocatedMetadata*>(GRPC_MDELEM_DATA(md));
return set_user_data(am->user_data(), destroy_func, data);
}
case GRPC_MDELEM_STORAGE_INTERNED: {
auto* im = reinterpret_cast<InternedMetadata*> GRPC_MDELEM_DATA(md);
GPR_ASSERT(!is_mdelem_static(md));
GPR_DEBUG_ASSERT(!is_mdelem_static(md));
return set_user_data(im->user_data(), destroy_func, data);
}
}
@ -482,3 +495,20 @@ void grpc_mdelem_do_unref(grpc_mdelem gmd DEBUG_ARGS) {
}
}
}
void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
uint32_t hash DEBUG_ARGS) {
switch (storage) {
case GRPC_MDELEM_STORAGE_EXTERNAL:
case GRPC_MDELEM_STORAGE_STATIC:
return;
case GRPC_MDELEM_STORAGE_INTERNED: {
note_disposed_interned_metadata(hash);
break;
}
case GRPC_MDELEM_STORAGE_ALLOCATED: {
grpc_core::Delete(reinterpret_cast<AllocatedMetadata*>(ptr));
break;
}
}
}

@ -80,17 +80,22 @@ typedef struct grpc_mdelem_data {
this bit set in their integer value */
#define GRPC_MDELEM_STORAGE_INTERNED_BIT 1
/* External and static storage metadata has no refcount to ref/unref. Allocated
* and interned metadata do have a refcount. Metadata ref and unref methods use
* a switch statement on this enum to determine which behaviour to execute.
* Keeping the no-ref cases together and the ref-cases together leads to
* slightly better code generation (9 inlined instructions rather than 10). */
typedef enum {
/* memory pointed to by grpc_mdelem::payload is owned by an external system */
GRPC_MDELEM_STORAGE_EXTERNAL = 0,
/* memory pointed to by grpc_mdelem::payload is interned by the metadata
system */
GRPC_MDELEM_STORAGE_INTERNED = GRPC_MDELEM_STORAGE_INTERNED_BIT,
/* memory is in the static metadata table */
GRPC_MDELEM_STORAGE_STATIC = GRPC_MDELEM_STORAGE_INTERNED_BIT,
/* memory pointed to by grpc_mdelem::payload is allocated by the metadata
system */
GRPC_MDELEM_STORAGE_ALLOCATED = 2,
/* memory is in the static metadata table */
GRPC_MDELEM_STORAGE_STATIC = 2 | GRPC_MDELEM_STORAGE_INTERNED_BIT,
/* memory pointed to by grpc_mdelem::payload is interned by the metadata
system */
GRPC_MDELEM_STORAGE_INTERNED = 2 | GRPC_MDELEM_STORAGE_INTERNED_BIT,
} grpc_mdelem_data_storage;
struct grpc_mdelem {
@ -141,6 +146,16 @@ inline bool grpc_mdelem_static_value_eq(grpc_mdelem a, grpc_mdelem b_static) {
if (a.payload == b_static.payload) return true;
return grpc_slice_eq_static_interned(GRPC_MDVALUE(a), GRPC_MDVALUE(b_static));
}
#define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL)
inline bool grpc_mdelem_both_interned_eq(grpc_mdelem a_interned,
grpc_mdelem b_interned) {
GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(a_interned) ||
GRPC_MDISNULL(a_interned));
GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(b_interned) ||
GRPC_MDISNULL(b_interned));
return a_interned.payload == b_interned.payload;
}
/* Mutator and accessor for grpc_mdelem user data. The destructor function
is used as a type tag and is checked during user_data fetch. */
@ -169,17 +184,34 @@ struct UserData {
grpc_core::Atomic<void*> data;
};
class InternedMetadata {
class StaticMetadata {
public:
struct BucketLink {
explicit BucketLink(InternedMetadata* md) : next(md) {}
StaticMetadata(const grpc_slice& key, const grpc_slice& value)
: kv_({key, value}), hash_(0) {}
InternedMetadata* next = nullptr;
};
const grpc_mdelem_data& data() const { return kv_; }
InternedMetadata(const grpc_slice& key, const grpc_slice& value,
uint32_t hash, InternedMetadata* next);
~InternedMetadata();
void HashInit();
uint32_t hash() { return hash_; }
private:
grpc_mdelem_data kv_;
/* private only data */
uint32_t hash_;
};
class RefcountedMdBase {
public:
RefcountedMdBase(const grpc_slice& key, const grpc_slice& value)
: key_(key), value_(value), refcnt_(1) {}
RefcountedMdBase(const grpc_slice& key, const grpc_slice& value,
uint32_t hash)
: key_(key), value_(value), refcnt_(1), hash_(hash) {}
const grpc_slice& key() const { return key_; }
const grpc_slice& value() const { return value_; }
uint32_t hash() { return hash_; }
#ifndef NDEBUG
void Ref(const char* file, int line) {
@ -191,92 +223,65 @@ class InternedMetadata {
grpc_mdelem_trace_unref(this, key_, value_, RefValue(), file, line);
return Unref();
}
#else
// We define a naked Ref() in the else-clause to make sure we don't
// inadvertently skip the assert on debug builds.
#endif
void Ref() {
/* we can assume the ref count is >= 1 as the application is calling
this function - meaning that no adjustment to mdtab_free is necessary,
simplifying the logic here to be just an atomic increment */
refcnt_.FetchAdd(1, MemoryOrder::RELAXED);
}
#endif // ifndef NDEBUG
bool Unref() {
const intptr_t prior = refcnt_.FetchSub(1, MemoryOrder::ACQ_REL);
GPR_DEBUG_ASSERT(prior > 0);
return prior == 1;
}
void RefWithShardLocked(mdtab_shard* shard);
const grpc_slice& key() const { return key_; }
const grpc_slice& value() const { return value_; }
UserData* user_data() { return &user_data_; }
uint32_t hash() { return hash_; }
InternedMetadata* bucket_next() { return link_.next; }
void set_bucket_next(InternedMetadata* md) { link_.next = md; }
static size_t CleanupLinkedMetadata(BucketLink* head);
private:
protected:
intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); }
bool AllRefsDropped() { return refcnt_.Load(MemoryOrder::ACQUIRE) == 0; }
bool FirstRef() { return refcnt_.FetchAdd(1, MemoryOrder::RELAXED) == 0; }
intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); }
private:
/* must be byte compatible with grpc_mdelem_data */
grpc_slice key_;
grpc_slice value_;
/* private only data */
grpc_core::Atomic<intptr_t> refcnt_;
uint32_t hash_;
uint32_t hash_ = 0;
};
UserData user_data_;
class InternedMetadata : public RefcountedMdBase {
public:
struct BucketLink {
explicit BucketLink(InternedMetadata* md) : next(md) {}
InternedMetadata* next = nullptr;
};
InternedMetadata(const grpc_slice& key, const grpc_slice& value,
uint32_t hash, InternedMetadata* next);
~InternedMetadata();
void RefWithShardLocked(mdtab_shard* shard);
UserData* user_data() { return &user_data_; }
InternedMetadata* bucket_next() { return link_.next; }
void set_bucket_next(InternedMetadata* md) { link_.next = md; }
static size_t CleanupLinkedMetadata(BucketLink* head);
private:
UserData user_data_;
BucketLink link_;
};
/* Shadow structure for grpc_mdelem_data for allocated elements */
class AllocatedMetadata {
class AllocatedMetadata : public RefcountedMdBase {
public:
AllocatedMetadata(const grpc_slice& key, const grpc_slice& value);
~AllocatedMetadata();
const grpc_slice& key() const { return key_; }
const grpc_slice& value() const { return value_; }
UserData* user_data() { return &user_data_; }
#ifndef NDEBUG
void Ref(const char* file, int line) {
grpc_mdelem_trace_ref(this, key_, value_, RefValue(), file, line);
Ref();
}
bool Unref(const char* file, int line) {
grpc_mdelem_trace_unref(this, key_, value_, RefValue(), file, line);
return Unref();
}
#endif // ifndef NDEBUG
void Ref() {
/* we can assume the ref count is >= 1 as the application is calling
this function - meaning that no adjustment to mdtab_free is necessary,
simplifying the logic here to be just an atomic increment */
refcnt_.FetchAdd(1, MemoryOrder::RELAXED);
}
bool Unref() {
const intptr_t prior = refcnt_.FetchSub(1, MemoryOrder::ACQ_REL);
GPR_DEBUG_ASSERT(prior > 0);
return prior == 1;
}
private:
intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); }
/* must be byte compatible with grpc_mdelem_data */
grpc_slice key_;
grpc_slice value_;
/* private only data */
grpc_core::Atomic<intptr_t> refcnt_;
UserData user_data_;
};
@ -321,30 +326,40 @@ inline grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd) {
#ifndef NDEBUG
#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__)
void grpc_mdelem_do_unref(grpc_mdelem gmd, const char* file, int line);
void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
uint32_t hash, const char* file, int line);
inline void grpc_mdelem_unref(grpc_mdelem gmd, const char* file, int line) {
#else
#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s))
void grpc_mdelem_do_unref(grpc_mdelem gmd);
void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
uint32_t hash);
inline void grpc_mdelem_unref(grpc_mdelem gmd) {
#endif
switch (GRPC_MDELEM_STORAGE(gmd)) {
const grpc_mdelem_data_storage storage = GRPC_MDELEM_STORAGE(gmd);
switch (storage) {
case GRPC_MDELEM_STORAGE_EXTERNAL:
case GRPC_MDELEM_STORAGE_STATIC:
return;
case GRPC_MDELEM_STORAGE_INTERNED:
case GRPC_MDELEM_STORAGE_ALLOCATED:
auto* md =
reinterpret_cast<grpc_core::RefcountedMdBase*> GRPC_MDELEM_DATA(gmd);
/* once the refcount hits zero, some other thread can come along and
free an interned md at any time: it's unsafe from this point on to
access it so we read the hash now. */
uint32_t hash = md->hash();
if (GPR_UNLIKELY(md->Unref())) {
#ifndef NDEBUG
grpc_mdelem_do_unref(gmd, file, line);
grpc_mdelem_on_final_unref(storage, md, hash, file, line);
#else
grpc_mdelem_do_unref(gmd);
grpc_mdelem_on_final_unref(storage, md, hash);
#endif
}
return;
}
}
#define GRPC_MDNULL GRPC_MAKE_MDELEM(NULL, GRPC_MDELEM_STORAGE_EXTERNAL)
#define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL)
/* We add 32 bytes of padding as per RFC-7540 section 6.5.2. */
#define GRPC_MDELEM_LENGTH(e) \

@ -390,184 +390,270 @@ grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b) {
uint32_t h = elems_phash(k);
return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k &&
elem_idxs[h] != 255
? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]],
? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]].data(),
GRPC_MDELEM_STORAGE_STATIC)
: GRPC_MDNULL;
}
grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
{{&grpc_static_metadata_refcounts[3], {{10, g_bytes + 19}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[40], {{3, g_bytes + 612}}}},
{{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[41], {{4, g_bytes + 615}}}},
{{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[42], {{1, g_bytes + 619}}}},
{{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[43], {{11, g_bytes + 620}}}},
{{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[44], {{4, g_bytes + 631}}}},
{{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[45], {{5, g_bytes + 635}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[46], {{3, g_bytes + 640}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[47], {{3, g_bytes + 643}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[48], {{3, g_bytes + 646}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[49], {{3, g_bytes + 649}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[50], {{3, g_bytes + 652}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[51], {{3, g_bytes + 655}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[52], {{3, g_bytes + 658}}}},
{{&grpc_static_metadata_refcounts[53], {{14, g_bytes + 661}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[54], {{13, g_bytes + 675}}}},
{{&grpc_static_metadata_refcounts[55], {{15, g_bytes + 688}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[56], {{13, g_bytes + 703}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[57], {{6, g_bytes + 716}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[58], {{27, g_bytes + 722}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[59], {{3, g_bytes + 749}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[60], {{5, g_bytes + 752}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[61], {{13, g_bytes + 757}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[62], {{13, g_bytes + 770}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[63], {{19, g_bytes + 783}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[64], {{16, g_bytes + 802}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[65], {{14, g_bytes + 818}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[66], {{16, g_bytes + 832}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[67], {{13, g_bytes + 848}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[68], {{6, g_bytes + 861}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[69], {{4, g_bytes + 867}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[70], {{4, g_bytes + 871}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[71], {{6, g_bytes + 875}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[72], {{7, g_bytes + 881}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[73], {{4, g_bytes + 888}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[20], {{4, g_bytes + 278}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[74], {{8, g_bytes + 892}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[75], {{17, g_bytes + 900}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[76], {{13, g_bytes + 917}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[77], {{8, g_bytes + 930}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[78], {{19, g_bytes + 938}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[79], {{13, g_bytes + 957}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[80], {{4, g_bytes + 970}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[81], {{8, g_bytes + 974}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[82], {{12, g_bytes + 982}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[83], {{18, g_bytes + 994}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[84], {{19, g_bytes + 1012}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[85], {{5, g_bytes + 1031}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[86], {{7, g_bytes + 1036}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[87], {{7, g_bytes + 1043}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[88], {{11, g_bytes + 1050}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[89], {{6, g_bytes + 1061}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[90], {{10, g_bytes + 1067}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[91], {{25, g_bytes + 1077}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[92], {{17, g_bytes + 1102}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[19], {{10, g_bytes + 268}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[93], {{4, g_bytes + 1119}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[94], {{3, g_bytes + 1123}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[95], {{16, g_bytes + 1126}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[96], {{1, g_bytes + 1142}}}},
{{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[25], {{1, g_bytes + 350}}}},
{{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[26], {{1, g_bytes + 351}}}},
{{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}},
{{&grpc_static_metadata_refcounts[5], {{2, g_bytes + 36}}},
{&grpc_static_metadata_refcounts[98], {{8, g_bytes + 1151}}}},
{{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[99], {{16, g_bytes + 1159}}}},
{{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[100], {{4, g_bytes + 1175}}}},
{{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[101], {{3, g_bytes + 1179}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[21], {{8, g_bytes + 282}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[102], {{11, g_bytes + 1182}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[103], {{16, g_bytes + 1193}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[105], {{12, g_bytes + 1222}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[106], {{21, g_bytes + 1234}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}},
grpc_core::StaticMetadata grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[3], {{10, g_bytes + 19}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[40], {{3, g_bytes + 612}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[41], {{4, g_bytes + 615}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[42], {{1, g_bytes + 619}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[43], {{11, g_bytes + 620}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[44], {{4, g_bytes + 631}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[45], {{5, g_bytes + 635}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[46], {{3, g_bytes + 640}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[47], {{3, g_bytes + 643}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[48], {{3, g_bytes + 646}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[49], {{3, g_bytes + 649}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[50], {{3, g_bytes + 652}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[51], {{3, g_bytes + 655}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[52], {{3, g_bytes + 658}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[53], {{14, g_bytes + 661}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[54], {{13, g_bytes + 675}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[55], {{15, g_bytes + 688}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[56], {{13, g_bytes + 703}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[57], {{6, g_bytes + 716}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[58], {{27, g_bytes + 722}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[59], {{3, g_bytes + 749}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[60], {{5, g_bytes + 752}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[61], {{13, g_bytes + 757}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[62], {{13, g_bytes + 770}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[63], {{19, g_bytes + 783}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[64], {{16, g_bytes + 802}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[65], {{14, g_bytes + 818}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[66], {{16, g_bytes + 832}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[67], {{13, g_bytes + 848}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[68], {{6, g_bytes + 861}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[69], {{4, g_bytes + 867}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[70], {{4, g_bytes + 871}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[71], {{6, g_bytes + 875}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[72], {{7, g_bytes + 881}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[73], {{4, g_bytes + 888}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[20], {{4, g_bytes + 278}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[74], {{8, g_bytes + 892}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[75], {{17, g_bytes + 900}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[76], {{13, g_bytes + 917}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[77], {{8, g_bytes + 930}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[78], {{19, g_bytes + 938}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[79], {{13, g_bytes + 957}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[80], {{4, g_bytes + 970}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[81], {{8, g_bytes + 974}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[82], {{12, g_bytes + 982}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[83], {{18, g_bytes + 994}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[84], {{19, g_bytes + 1012}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[85], {{5, g_bytes + 1031}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[86], {{7, g_bytes + 1036}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[87], {{7, g_bytes + 1043}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[88], {{11, g_bytes + 1050}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[89], {{6, g_bytes + 1061}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[90], {{10, g_bytes + 1067}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[91], {{25, g_bytes + 1077}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[92], {{17, g_bytes + 1102}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[19], {{10, g_bytes + 268}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[93], {{4, g_bytes + 1119}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[94], {{3, g_bytes + 1123}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[95], {{16, g_bytes + 1126}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[96], {{1, g_bytes + 1142}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[25], {{1, g_bytes + 350}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[26], {{1, g_bytes + 351}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[5], {{2, g_bytes + 36}}},
{&grpc_static_metadata_refcounts[98], {{8, g_bytes + 1151}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[99], {{16, g_bytes + 1159}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[100], {{4, g_bytes + 1175}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[101], {{3, g_bytes + 1179}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[21], {{8, g_bytes + 282}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[102], {{11, g_bytes + 1182}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[103], {{16, g_bytes + 1193}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[105], {{12, g_bytes + 1222}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[106], {{21, g_bytes + 1234}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}),
};
const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78,
79, 80, 81, 82};

@ -269,266 +269,353 @@ extern grpc_slice_refcount
((static_slice).refcount - grpc_static_metadata_refcounts)))
#define GRPC_STATIC_MDELEM_COUNT 86
extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
extern grpc_core::StaticMetadata
grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
/* ":authority": "" */
#define GRPC_MDELEM_AUTHORITY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_AUTHORITY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":method": "GET" */
#define GRPC_MDELEM_METHOD_GET \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_METHOD_GET \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":method": "POST" */
#define GRPC_MDELEM_METHOD_POST \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_METHOD_POST \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":path": "/" */
#define GRPC_MDELEM_PATH_SLASH \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_PATH_SLASH \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":path": "/index.html" */
#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":scheme": "http" */
#define GRPC_MDELEM_SCHEME_HTTP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SCHEME_HTTP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":scheme": "https" */
#define GRPC_MDELEM_SCHEME_HTTPS \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SCHEME_HTTPS \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "200" */
#define GRPC_MDELEM_STATUS_200 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_200 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "204" */
#define GRPC_MDELEM_STATUS_204 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_204 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "206" */
#define GRPC_MDELEM_STATUS_206 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_206 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "304" */
#define GRPC_MDELEM_STATUS_304 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_304 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "400" */
#define GRPC_MDELEM_STATUS_400 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_400 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "404" */
#define GRPC_MDELEM_STATUS_404 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_404 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "500" */
#define GRPC_MDELEM_STATUS_500 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_500 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-charset": "" */
#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "gzip, deflate" */
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-language": "" */
#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-ranges": "" */
#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept": "" */
#define GRPC_MDELEM_ACCEPT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "access-control-allow-origin": "" */
#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "age": "" */
#define GRPC_MDELEM_AGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_AGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "allow": "" */
#define GRPC_MDELEM_ALLOW_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ALLOW_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "authorization": "" */
#define GRPC_MDELEM_AUTHORIZATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_AUTHORIZATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "cache-control": "" */
#define GRPC_MDELEM_CACHE_CONTROL_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CACHE_CONTROL_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-disposition": "" */
#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-encoding": "" */
#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-language": "" */
#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-length": "" */
#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-location": "" */
#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-range": "" */
#define GRPC_MDELEM_CONTENT_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-type": "" */
#define GRPC_MDELEM_CONTENT_TYPE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_TYPE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "cookie": "" */
#define GRPC_MDELEM_COOKIE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_COOKIE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "date": "" */
#define GRPC_MDELEM_DATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_DATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "etag": "" */
#define GRPC_MDELEM_ETAG_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ETAG_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "expect": "" */
#define GRPC_MDELEM_EXPECT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_EXPECT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "expires": "" */
#define GRPC_MDELEM_EXPIRES_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_EXPIRES_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "from": "" */
#define GRPC_MDELEM_FROM_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_FROM_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "host": "" */
#define GRPC_MDELEM_HOST_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_HOST_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-match": "" */
#define GRPC_MDELEM_IF_MATCH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_MATCH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-modified-since": "" */
#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-none-match": "" */
#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-range": "" */
#define GRPC_MDELEM_IF_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-unmodified-since": "" */
#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "last-modified": "" */
#define GRPC_MDELEM_LAST_MODIFIED_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LAST_MODIFIED_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "link": "" */
#define GRPC_MDELEM_LINK_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LINK_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "location": "" */
#define GRPC_MDELEM_LOCATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LOCATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "max-forwards": "" */
#define GRPC_MDELEM_MAX_FORWARDS_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_MAX_FORWARDS_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "proxy-authenticate": "" */
#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "proxy-authorization": "" */
#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "range": "" */
#define GRPC_MDELEM_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "referer": "" */
#define GRPC_MDELEM_REFERER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_REFERER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "refresh": "" */
#define GRPC_MDELEM_REFRESH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_REFRESH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "retry-after": "" */
#define GRPC_MDELEM_RETRY_AFTER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_RETRY_AFTER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "server": "" */
#define GRPC_MDELEM_SERVER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SERVER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "set-cookie": "" */
#define GRPC_MDELEM_SET_COOKIE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SET_COOKIE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "strict-transport-security": "" */
#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "transfer-encoding": "" */
#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "user-agent": "" */
#define GRPC_MDELEM_USER_AGENT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_USER_AGENT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "vary": "" */
#define GRPC_MDELEM_VARY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_VARY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "via": "" */
#define GRPC_MDELEM_VIA_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_VIA_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "www-authenticate": "" */
#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-status": "0" */
#define GRPC_MDELEM_GRPC_STATUS_0 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_STATUS_0 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-status": "1" */
#define GRPC_MDELEM_GRPC_STATUS_1 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_STATUS_1 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-status": "2" */
#define GRPC_MDELEM_GRPC_STATUS_2 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_STATUS_2 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-encoding": "identity" */
#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-encoding": "gzip" */
#define GRPC_MDELEM_GRPC_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-encoding": "deflate" */
#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "te": "trailers" */
#define GRPC_MDELEM_TE_TRAILERS \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_TE_TRAILERS \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-type": "application/grpc" */
#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":scheme": "grpc" */
#define GRPC_MDELEM_SCHEME_GRPC \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SCHEME_GRPC \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":method": "PUT" */
#define GRPC_MDELEM_METHOD_PUT \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_METHOD_PUT \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "" */
#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-encoding": "identity" */
#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-encoding": "gzip" */
#define GRPC_MDELEM_CONTENT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "lb-token": "" */
#define GRPC_MDELEM_LB_TOKEN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LB_TOKEN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "lb-cost-bin": "" */
#define GRPC_MDELEM_LB_COST_BIN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LB_COST_BIN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "identity" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "deflate" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "identity,deflate" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78], GRPC_MDELEM_STORAGE_STATIC))
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "identity,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80], GRPC_MDELEM_STORAGE_STATIC))
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "deflate,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[81], GRPC_MDELEM_STORAGE_STATIC))
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[81].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "identity,deflate,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[82], GRPC_MDELEM_STORAGE_STATIC))
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[82].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "identity" */
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[83], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[83].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "gzip" */
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[84], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[84].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "identity,gzip" */
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[85], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[85].data(), \
GRPC_MDELEM_STORAGE_STATIC))
grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b);
typedef enum {
@ -597,14 +684,16 @@ typedef union {
: GRPC_BATCH_CALLOUTS_COUNT)
extern const uint8_t grpc_static_accept_encoding_metadata[8];
#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
(GRPC_MAKE_MDELEM( \
&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], \
#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
(GRPC_MAKE_MDELEM( \
&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]] \
.data(), \
GRPC_MDELEM_STORAGE_STATIC))
extern const uint8_t grpc_static_accept_stream_encoding_metadata[4];
#define GRPC_MDELEM_ACCEPT_STREAM_ENCODING_FOR_ALGORITHMS(algs) \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table \
[grpc_static_accept_stream_encoding_metadata[(algs)]], \
[grpc_static_accept_stream_encoding_metadata[(algs)]] \
.data(), \
GRPC_MDELEM_STORAGE_STATIC))
#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */

@ -0,0 +1,40 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/grpc.h>
#include <grpcpp/support/validate_service_config.h>
#include "src/core/ext/filters/client_channel/service_config.h"
namespace grpc {
namespace experimental {
grpc::string ValidateServiceConfigJSON(
const grpc::string& service_config_json) {
grpc_init();
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::ServiceConfig::Create(service_config_json.c_str(), &error);
grpc::string return_value;
if (error != GRPC_ERROR_NONE) {
return_value = grpc_error_string(error);
GRPC_ERROR_UNREF(error);
}
grpc_shutdown();
return return_value;
}
} // namespace experimental
} // namespace grpc

@ -56,7 +56,7 @@ class ThreadManager {
// DoWork()
//
// If the return value is SHUTDOWN:,
// - ThreadManager WILL NOT call DoWork() and terminates the thead
// - ThreadManager WILL NOT call DoWork() and terminates the thread
//
// If the return value is TIMEOUT:,
// - ThreadManager WILL NOT call DoWork()
@ -133,7 +133,7 @@ class ThreadManager {
grpc_core::Thread thd_;
};
// The main funtion in ThreadManager
// The main function in ThreadManager
void MainWorkLoop();
void MarkAsCompleted(WorkerThread* thd);

@ -477,6 +477,8 @@ const char *kCFStreamVarName = "grpc_cfstream";
}
- (void)dealloc {
[GRPCConnectivityMonitor unregisterObserver:self];
__block GRPCWrappedCall *wrappedCall = _wrappedCall;
dispatch_async(_callQueue, ^{
wrappedCall = nil;

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -1,6 +1,6 @@
/*
*
* Copyright 2015 gRPC authors.
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +16,19 @@
*
*/
#import <Foundation/Foundation.h>
#ifdef GRPC_COMPILE_WITH_CRONET
@interface Tests : NSObject
@end
#ifdef __cplusplus
extern "C" {
#endif
@implementation Tests
@end
/**
* Enable Cronet for once.
*/
void configureCronet(void);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,39 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef GRPC_COMPILE_WITH_CRONET
#import "ConfigureCronet.h"
#import <Cronet/Cronet.h>
void configureCronet(void) {
static dispatch_once_t configureCronet;
dispatch_once(&configureCronet, ^{
NSLog(@"configureCronet()");
[Cronet setHttp2Enabled:YES];
[Cronet setSslKeyLogFileName:@"Documents/key"];
[Cronet enableTestCertVerifierForTesting];
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSLog(@"Documents directory: %@", url);
[Cronet start];
[Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES];
});
}
#endif

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>gRPC.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -49,6 +49,8 @@
#import <Cronet/Cronet.h>
#include <grpc/grpc_cronet.h>
#import "../ConfigureCronet.h"
typedef struct fullstack_secure_fixture_data {
char *localaddr;
} fullstack_secure_fixture_data;
@ -176,13 +178,7 @@ static char *roots_filename;
grpc_init();
[Cronet setHttp2Enabled:YES];
[Cronet enableTestCertVerifierForTesting];
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSLog(@"Documents directory: %@", url);
[Cronet start];
[Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES];
configureCronet();
}
// The tearDown() function is run after all test cases finish running

@ -20,6 +20,8 @@
#import <netinet/in.h>
#import <sys/socket.h>
#import "../ConfigureCronet.h"
#import <Cronet/Cronet.h>
#import <grpc/grpc.h>
#import <grpc/grpc_cronet.h>
@ -37,6 +39,7 @@
#import "test/core/end2end/data/ssl_test_data.h"
#import "test/core/util/test_config.h"
#define GRPC_SHADOW_BORINGSSL_SYMBOLS
#import "src/core/tsi/grpc_shadow_boringssl.h"
#import <openssl_grpc/ssl.h>
@ -61,16 +64,7 @@ static void drain_cq(grpc_completion_queue *cq) {
grpc_test_init(1, argv);
grpc_init();
[Cronet setHttp2Enabled:YES];
[Cronet setSslKeyLogFileName:@"Documents/key"];
[Cronet enableTestCertVerifierForTesting];
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSLog(@"Documents directory: %@", url);
[Cronet start];
[Cronet startNetLogToFile:@"Documents/cronet_netlog.json" logBytes:YES];
configureCronet();
init_ssl();
}

@ -44,6 +44,10 @@ static int32_t kRemoteInteropServerOverhead = 12;
return kRemoteSSLHost;
}
+ (BOOL)useCronet {
return YES;
}
- (int32_t)encodingOverhead {
return kRemoteInteropServerOverhead; // bytes
}

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -59,4 +59,9 @@
*/
+ (NSString *)hostNameOverride;
/**
* Whether to use Cronet for all the v1 API tests in the test suite.
*/
+ (BOOL)useCronet;
@end

@ -37,6 +37,9 @@
#import <grpc/grpc.h>
#import <grpc/support/log.h>
#import "../ConfigureCronet.h"
#import "InteropTestsBlockCallbacks.h"
#define TEST_TIMEOUT 32
extern const char *kCFStreamVarName;
@ -415,12 +418,16 @@ initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
return nil;
}
+ (BOOL)useCronet {
return NO;
}
+ (void)setUp {
#ifdef GRPC_COMPILE_WITH_CRONET
// Cronet setup
[Cronet setHttp2Enabled:YES];
[Cronet start];
[GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]];
configureCronet();
if ([self useCronet]) {
[GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]];
}
#endif
#ifdef GRPC_CFSTREAM
setenv(kCFStreamVarName, "1", 1);

@ -0,0 +1,33 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <ProtoRPC/ProtoRPC.h>
// Convenience class to use blocks as callbacks
@interface InteropTestsBlockCallbacks : NSObject<GRPCProtoResponseHandler>
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
writeMessageCallback:(void (^)(void))writeMessageCallback;
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
@end

@ -0,0 +1,80 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import "InteropTestsBlockCallbacks.h"
@implementation InteropTestsBlockCallbacks {
void (^_initialMetadataCallback)(NSDictionary *);
void (^_messageCallback)(id);
void (^_closeCallback)(NSDictionary *, NSError *);
void (^_writeMessageCallback)(void);
dispatch_queue_t _dispatchQueue;
}
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
writeMessageCallback:(void (^)(void))writeMessageCallback {
if ((self = [super init])) {
_initialMetadataCallback = initialMetadataCallback;
_messageCallback = messageCallback;
_closeCallback = closeCallback;
_writeMessageCallback = writeMessageCallback;
_dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback {
return [self initWithInitialMetadataCallback:initialMetadataCallback
messageCallback:messageCallback
closeCallback:closeCallback
writeMessageCallback:nil];
}
- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
if (_initialMetadataCallback) {
_initialMetadataCallback(initialMetadata);
}
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
if (_messageCallback) {
_messageCallback(message);
}
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (_closeCallback) {
_closeCallback(trailingMetadata, error);
}
}
- (void)didWriteMessage {
if (_writeMessageCallback) {
_writeMessageCallback();
}
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
@end

@ -0,0 +1,291 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <XCTest/XCTest.h>
#ifdef GRPC_COMPILE_WITH_CRONET
#import <Cronet/Cronet.h>
#endif
#import <RemoteTest/Messages.pbobjc.h>
#import <RemoteTest/Test.pbobjc.h>
#import <RemoteTest/Test.pbrpc.h>
#import <RxLibrary/GRXBufferedPipe.h>
#import "../ConfigureCronet.h"
#import "InteropTestsBlockCallbacks.h"
#define NSStringize_helper(x) #x
#define NSStringize(x) @NSStringize_helper(x)
static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
static NSString *const kLocalSSLHost = NSStringize(HOST_PORT_LOCALSSL);
static NSString *const kLocalCleartextHost = NSStringize(HOST_PORT_LOCAL);
static const NSTimeInterval TEST_TIMEOUT = 8000;
@interface RMTStreamingOutputCallRequest (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
requestedResponseSize:(NSNumber *)responseSize;
@end
@implementation RMTStreamingOutputCallRequest (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
requestedResponseSize:(NSNumber *)responseSize {
RMTStreamingOutputCallRequest *request = [self message];
RMTResponseParameters *parameters = [RMTResponseParameters message];
parameters.size = responseSize.intValue;
[request.responseParametersArray addObject:parameters];
request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
return request;
}
@end
@interface RMTStreamingOutputCallResponse (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize;
@end
@implementation RMTStreamingOutputCallResponse (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize {
RMTStreamingOutputCallResponse *response = [self message];
response.payload.type = RMTPayloadType_Compressable;
response.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
return response;
}
@end
@interface InteropTestsMultipleChannels : XCTestCase
@end
dispatch_once_t initCronet;
@implementation InteropTestsMultipleChannels {
RMTTestService *_remoteService;
RMTTestService *_remoteCronetService;
RMTTestService *_localCleartextService;
RMTTestService *_localSSLService;
}
- (void)setUp {
[super setUp];
self.continueAfterFailure = NO;
_remoteService = [RMTTestService serviceWithHost:kRemoteSSLHost callOptions:nil];
configureCronet();
// Default stack with remote host
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = GRPCTransportTypeCronet;
// Cronet stack with remote host
_remoteCronetService = [RMTTestService serviceWithHost:kRemoteSSLHost callOptions:options];
// Local stack with no SSL
options = [[GRPCMutableCallOptions alloc] init];
options.transportType = GRPCTransportTypeInsecure;
_localCleartextService = [RMTTestService serviceWithHost:kLocalCleartextHost callOptions:options];
// Local stack with SSL
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *certsPath =
[bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"];
NSError *error = nil;
NSString *certs =
[NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error);
options = [[GRPCMutableCallOptions alloc] init];
options.transportType = GRPCTransportTypeChttp2BoringSSL;
options.PEMRootCertificates = certs;
options.hostNameOverride = @"foo.test.google.fr";
_localSSLService = [RMTTestService serviceWithHost:kLocalSSLHost callOptions:options];
}
- (void)testEmptyUnaryRPC {
__weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCronetRemote =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCleartext =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
GPBEmpty *request = [GPBEmpty message];
void (^messageHandler)(id message) = ^(id message) {
id expectedResponse = [GPBEmpty message];
XCTAssertEqualObjects(message, expectedResponse);
};
GRPCUnaryProtoCall *callRemote = [_remoteService
emptyCallWithMessage:request
responseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:messageHandler
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNil(error);
[expectRemote fulfill];
}
writeMessageCallback:nil]
callOptions:nil];
GRPCUnaryProtoCall *callCronet = [_remoteCronetService
emptyCallWithMessage:request
responseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:messageHandler
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNil(error);
[expectCronetRemote fulfill];
}
writeMessageCallback:nil]
callOptions:nil];
GRPCUnaryProtoCall *callCleartext = [_localCleartextService
emptyCallWithMessage:request
responseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:messageHandler
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNil(error);
[expectCleartext fulfill];
}
writeMessageCallback:nil]
callOptions:nil];
GRPCUnaryProtoCall *callSSL = [_localSSLService
emptyCallWithMessage:request
responseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:messageHandler
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNil(error);
[expectSSL fulfill];
}
writeMessageCallback:nil]
callOptions:nil];
[callRemote start];
[callCronet start];
[callCleartext start];
[callSSL start];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testFullDuplexRPC {
__weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCronetRemote =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCleartext =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
NSArray *requestSizes = @[ @100, @101, @102, @103 ];
NSArray *responseSizes = @[ @104, @105, @106, @107 ];
XCTAssertEqual([requestSizes count], [responseSizes count]);
NSUInteger kRounds = [requestSizes count];
NSMutableArray<GRPCStreamingProtoCall *> *calls = [NSMutableArray arrayWithCapacity:4];
NSMutableArray *requests = [NSMutableArray arrayWithCapacity:kRounds];
NSMutableArray *responses = [NSMutableArray arrayWithCapacity:kRounds];
for (int i = 0; i < kRounds; i++) {
requests[i] = [RMTStreamingOutputCallRequest messageWithPayloadSize:requestSizes[i]
requestedResponseSize:responseSizes[i]];
responses[i] = [RMTStreamingOutputCallResponse messageWithPayloadSize:responseSizes[i]];
}
__block NSMutableArray *steps = [NSMutableArray arrayWithCapacity:4];
__block NSMutableArray *requestsBuffers = [NSMutableArray arrayWithCapacity:4];
for (int i = 0; i < 4; i++) {
steps[i] = [NSNumber numberWithUnsignedInteger:0];
requestsBuffers[i] = [[GRXBufferedPipe alloc] init];
[requestsBuffers[i] writeValue:requests[0]];
}
void (^handler)(NSUInteger index, id message) = ^(NSUInteger index, id message) {
NSUInteger step = [steps[index] unsignedIntegerValue];
step++;
steps[index] = [NSNumber numberWithUnsignedInteger:step];
if (step < kRounds) {
[calls[index] writeMessage:requests[step]];
} else {
[calls[index] finish];
}
};
calls[0] = [_remoteService
fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:^(id message) {
handler(0, message);
}
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNil(error);
[expectRemote fulfill];
}
writeMessageCallback:nil]
callOptions:nil];
calls[1] = [_remoteCronetService
fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:^(id message) {
handler(1, message);
}
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNil(error);
[expectCronetRemote fulfill];
}
writeMessageCallback:nil]
callOptions:nil];
calls[2] = [_localCleartextService
fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:^(id message) {
handler(2, message);
}
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNil(error);
[expectCleartext fulfill];
}
writeMessageCallback:nil]
callOptions:nil];
calls[3] = [_localSSLService
fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:^(id message) {
handler(3, message);
}
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNil(error);
[expectSSL fulfill];
}
writeMessageCallback:nil]
callOptions:nil];
for (int i = 0; i < 4; i++) {
[calls[i] start];
[calls[i] writeMessage:requests[0]];
}
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
@end

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -1,116 +0,0 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <XCTest/XCTest.h>
#import <RemoteTest/Messages.pbobjc.h>
#import <RemoteTest/Test.pbobjc.h>
#import <RemoteTest/Test.pbrpc.h>
#import <RxLibrary/GRXBufferedPipe.h>
#import <RxLibrary/GRXWriter+Immediate.h>
#import <grpc/grpc.h>
#define NSStringize_helper(x) #x
#define NSStringize(x) @NSStringize_helper(x)
static NSString *kRemoteHost = NSStringize(HOST_PORT_REMOTE);
const int32_t kRemoteInteropServerOverhead = 12;
static const NSTimeInterval TEST_TIMEOUT = 16000;
@interface InteropTestsCallOptions : XCTestCase
@end
@implementation InteropTestsCallOptions {
RMTTestService *_service;
}
- (void)setUp {
self.continueAfterFailure = NO;
_service = [RMTTestService serviceWithHost:kRemoteHost];
_service.options = [[GRPCCallOptions alloc] init];
}
- (void)test4MBResponsesAreAccepted {
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"MaxResponseSize"];
RMTSimpleRequest *request = [RMTSimpleRequest message];
const int32_t kPayloadSize =
4 * 1024 * 1024 - kRemoteInteropServerOverhead; // 4MB - encoding overhead
request.responseSize = kPayloadSize;
[_service unaryCallWithRequest:request
handler:^(RMTSimpleResponse *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
XCTAssertEqual(response.payload.body.length, kPayloadSize);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testResponsesOverMaxSizeFailWithActionableMessage {
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"ResponseOverMaxSize"];
RMTSimpleRequest *request = [RMTSimpleRequest message];
const int32_t kPayloadSize =
4 * 1024 * 1024 - kRemoteInteropServerOverhead + 1; // 1B over max size
request.responseSize = kPayloadSize;
[_service unaryCallWithRequest:request
handler:^(RMTSimpleResponse *response, NSError *error) {
XCTAssertEqualObjects(
error.localizedDescription,
@"Received message larger than max (4194305 vs. 4194304)");
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testResponsesOver4MBAreAcceptedIfOptedIn {
__weak XCTestExpectation *expectation =
[self expectationWithDescription:@"HigherResponseSizeLimit"];
RMTSimpleRequest *request = [RMTSimpleRequest message];
const size_t kPayloadSize = 5 * 1024 * 1024; // 5MB
request.responseSize = kPayloadSize;
GRPCProtoCall *rpc = [_service
RPCToUnaryCallWithRequest:request
handler:^(RMTSimpleResponse *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
XCTAssertEqual(response.payload.body.length, kPayloadSize);
[expectation fulfill];
}];
GRPCCallOptions *options = rpc.options;
options.responseSizeLimit = 6 * 1024 * 1024;
[rpc start];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
@end

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -1,259 +0,0 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <XCTest/XCTest.h>
#import <Cronet/Cronet.h>
#import <RemoteTest/Messages.pbobjc.h>
#import <RemoteTest/Test.pbobjc.h>
#import <RemoteTest/Test.pbrpc.h>
#import <RxLibrary/GRXBufferedPipe.h>
#define NSStringize_helper(x) #x
#define NSStringize(x) @NSStringize_helper(x)
static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
static NSString *const kLocalSSLHost = NSStringize(HOST_PORT_LOCALSSL);
static NSString *const kLocalCleartextHost = NSStringize(HOST_PORT_LOCAL);
static const NSTimeInterval TEST_TIMEOUT = 8000;
@interface RMTStreamingOutputCallRequest (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
requestedResponseSize:(NSNumber *)responseSize;
@end
@implementation RMTStreamingOutputCallRequest (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
requestedResponseSize:(NSNumber *)responseSize {
RMTStreamingOutputCallRequest *request = [self message];
RMTResponseParameters *parameters = [RMTResponseParameters message];
parameters.size = responseSize.intValue;
[request.responseParametersArray addObject:parameters];
request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
return request;
}
@end
@interface RMTStreamingOutputCallResponse (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize;
@end
@implementation RMTStreamingOutputCallResponse (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize {
RMTStreamingOutputCallResponse *response = [self message];
response.payload.type = RMTPayloadType_Compressable;
response.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
return response;
}
@end
@interface InteropTestsMultipleChannels : XCTestCase
@end
dispatch_once_t initCronet;
@implementation InteropTestsMultipleChannels {
RMTTestService *_remoteService;
RMTTestService *_remoteCronetService;
RMTTestService *_localCleartextService;
RMTTestService *_localSSLService;
}
- (void)setUp {
[super setUp];
self.continueAfterFailure = NO;
// Default stack with remote host
_remoteService = [RMTTestService serviceWithHost:kRemoteSSLHost];
// Cronet stack with remote host
_remoteCronetService = [RMTTestService serviceWithHost:kRemoteSSLHost];
dispatch_once(&initCronet, ^{
[Cronet setHttp2Enabled:YES];
[Cronet start];
});
GRPCCallOptions *options = [[GRPCCallOptions alloc] init];
options.transportType = GRPCTransportTypeCronet;
options.cronetEngine = [Cronet getGlobalEngine];
_remoteCronetService.options = options;
// Local stack with no SSL
_localCleartextService = [RMTTestService serviceWithHost:kLocalCleartextHost];
options = [[GRPCCallOptions alloc] init];
options.transportType = GRPCTransportTypeInsecure;
_localCleartextService.options = options;
// Local stack with SSL
_localSSLService = [RMTTestService serviceWithHost:kLocalSSLHost];
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *certsPath =
[bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"];
NSError *error = nil;
NSString *certs =
[NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error);
options = [[GRPCCallOptions alloc] init];
options.transportType = GRPCTransportTypeChttp2BoringSSL;
options.PEMRootCertificates = certs;
options.hostNameOverride = @"foo.test.google.fr";
_localSSLService.options = options;
}
- (void)testEmptyUnaryRPC {
__weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCronetRemote =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCleartext =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
GPBEmpty *request = [GPBEmpty message];
void (^handler)(GPBEmpty *response, NSError *error) = ^(GPBEmpty *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
id expectedResponse = [GPBEmpty message];
XCTAssertEqualObjects(response, expectedResponse);
};
[_remoteService emptyCallWithRequest:request
handler:^(GPBEmpty *response, NSError *error) {
handler(response, error);
[expectRemote fulfill];
}];
[_remoteCronetService emptyCallWithRequest:request
handler:^(GPBEmpty *response, NSError *error) {
handler(response, error);
[expectCronetRemote fulfill];
}];
[_localCleartextService emptyCallWithRequest:request
handler:^(GPBEmpty *response, NSError *error) {
handler(response, error);
[expectCleartext fulfill];
}];
[_localSSLService emptyCallWithRequest:request
handler:^(GPBEmpty *response, NSError *error) {
handler(response, error);
[expectSSL fulfill];
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testFullDuplexRPC {
__weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCronetRemote =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCleartext =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
NSArray *requestSizes = @[ @100, @101, @102, @103 ];
NSArray *responseSizes = @[ @104, @105, @106, @107 ];
XCTAssertEqual([requestSizes count], [responseSizes count]);
NSUInteger kRounds = [requestSizes count];
NSMutableArray *requests = [NSMutableArray arrayWithCapacity:kRounds];
NSMutableArray *responses = [NSMutableArray arrayWithCapacity:kRounds];
for (int i = 0; i < kRounds; i++) {
requests[i] = [RMTStreamingOutputCallRequest messageWithPayloadSize:requestSizes[i]
requestedResponseSize:responseSizes[i]];
responses[i] = [RMTStreamingOutputCallResponse messageWithPayloadSize:responseSizes[i]];
}
__block NSMutableArray *steps = [NSMutableArray arrayWithCapacity:4];
__block NSMutableArray *requestsBuffers = [NSMutableArray arrayWithCapacity:4];
for (int i = 0; i < 4; i++) {
steps[i] = [NSNumber numberWithUnsignedInteger:0];
requestsBuffers[i] = [[GRXBufferedPipe alloc] init];
[requestsBuffers[i] writeValue:requests[0]];
}
BOOL (^handler)(int, BOOL, RMTStreamingOutputCallResponse *, NSError *) =
^(int index, BOOL done, RMTStreamingOutputCallResponse *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
XCTAssertTrue(done || response, @"Event handler called without an event.");
if (response) {
NSUInteger step = [steps[index] unsignedIntegerValue];
XCTAssertLessThan(step, kRounds, @"More than %lu responses received.",
(unsigned long)kRounds);
XCTAssertEqualObjects(response, responses[step]);
step++;
steps[index] = [NSNumber numberWithUnsignedInteger:step];
GRXBufferedPipe *pipe = requestsBuffers[index];
if (step < kRounds) {
[pipe writeValue:requests[step]];
} else {
[pipe writesFinishedWithError:nil];
}
}
if (done) {
NSUInteger step = [steps[index] unsignedIntegerValue];
XCTAssertEqual(step, kRounds, @"Received %lu responses instead of %lu.", step, kRounds);
return YES;
}
return NO;
};
[_remoteService
fullDuplexCallWithRequestsWriter:requestsBuffers[0]
eventHandler:^(BOOL done,
RMTStreamingOutputCallResponse *_Nullable response,
NSError *_Nullable error) {
if (handler(0, done, response, error)) {
[expectRemote fulfill];
}
}];
[_remoteCronetService
fullDuplexCallWithRequestsWriter:requestsBuffers[1]
eventHandler:^(BOOL done,
RMTStreamingOutputCallResponse *_Nullable response,
NSError *_Nullable error) {
if (handler(1, done, response, error)) {
[expectCronetRemote fulfill];
}
}];
[_localCleartextService
fullDuplexCallWithRequestsWriter:requestsBuffers[2]
eventHandler:^(BOOL done,
RMTStreamingOutputCallResponse *_Nullable response,
NSError *_Nullable error) {
if (handler(2, done, response, error)) {
[expectCleartext fulfill];
}
}];
[_localSSLService
fullDuplexCallWithRequestsWriter:requestsBuffers[3]
eventHandler:^(BOOL done,
RMTStreamingOutputCallResponse *_Nullable response,
NSError *_Nullable error) {
if (handler(3, done, response, error)) {
[expectSSL fulfill];
}
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
@end

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -5,46 +5,24 @@ install! 'cocoapods', :deterministic_uuids => false
# Location of gRPC's repo root relative to this file.
GRPC_LOCAL_SRC = '../../..'
# Install the dependencies in the main target plus all test targets.
%w(
AllTests
RxLibraryUnitTests
InteropTestsRemote
InteropTestsLocalSSL
InteropTestsLocalCleartext
InteropTestsRemoteWithCronet
InteropTestsMultipleChannels
InteropTestsCallOptions
UnitTests
InteropTestsRemoteCFStream
InteropTestsLocalSSLCFStream
InteropTestsLocalCleartextCFStream
APIv2Tests
).each do |target_name|
target target_name do
platform :ios, '8.0'
pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
pod '!ProtoCompiler', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
target 'MacTests' do
platform :osx, '10.13'
pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod '!ProtoCompiler', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'gRPC', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true
pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
if target_name == 'InteropTestsRemoteWithCronet' or target_name == 'InteropTestsMultipleChannels'
pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
end
end
pod 'gRPC', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true
end
target 'MacTests' do
platform :osx, '10.13'
target 'UnitTests' do
platform :ios, '8.0'
pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
pod '!ProtoCompiler', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
@ -60,27 +38,30 @@ target 'MacTests' do
end
%w(
CoreCronetEnd2EndTests
CronetUnitTests
InteropTests
CronetTests
).each do |target_name|
target target_name do
platform :ios, '8.0'
pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Cronet-Interface', :path => GRPC_LOCAL_SRC
pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
pod '!ProtoCompiler', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod 'gRPC', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true
pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC
pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
end
end
target 'ChannelTests' do
platform :ios, '8.0'
pod 'gRPC', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
end
# gRPC-Core.podspec needs to be modified to be successfully used for local development. A Podfile's
# pre_install hook lets us do that. The block passed to it runs after the podspecs are downloaded
# and before they are installed in the user project.

File diff suppressed because it is too large Load Diff

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E3B95A121CAC6C500C0A151"
BuildableName = "APIv2Tests.xctest"
BlueprintName = "APIv2Tests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E3B95A121CAC6C500C0A151"
BuildableName = "APIv2Tests.xctest"
BlueprintName = "APIv2Tests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E3B95A121CAC6C500C0A151"
BuildableName = "APIv2Tests.xctest"
BlueprintName = "APIv2Tests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E3B95A121CAC6C500C0A151"
BuildableName = "APIv2Tests.xctest"
BlueprintName = "APIv2Tests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -1,110 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0630"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63423F431B150A5F006CF63C"
BuildableName = "AllTests.xctest"
BlueprintName = "AllTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63423F431B150A5F006CF63C"
BuildableName = "AllTests.xctest"
BlueprintName = "AllTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
<SkippedTests>
<Test
Identifier = "InteropTests">
</Test>
<Test
Identifier = "LocalClearTextTests">
</Test>
<Test
Identifier = "LocalClearTextTests/testConnectionToLocalServer">
</Test>
</SkippedTests>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63423F431B150A5F006CF63C"
BuildableName = "AllTests.xctest"
BlueprintName = "AllTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63423F431B150A5F006CF63C"
BuildableName = "AllTests.xctest"
BlueprintName = "AllTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63423F431B150A5F006CF63C"
BuildableName = "AllTests.xctest"
BlueprintName = "AllTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Test">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
BuildableName = "ChannelTests.xctest"
BlueprintName = "ChannelTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
BuildableName = "ChannelTests.xctest"
BlueprintName = "ChannelTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
BuildableName = "ChannelTests.xctest"
BlueprintName = "ChannelTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
BuildableName = "ChannelTests.xctest"
BlueprintName = "ChannelTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -1,101 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
BuildableName = "CoreCronetEnd2EndTests.xctest"
BlueprintName = "CoreCronetEnd2EndTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
BuildableName = "CoreCronetEnd2EndTests.xctest"
BlueprintName = "CoreCronetEnd2EndTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
BuildableName = "CoreCronetEnd2EndTests.xctest"
BlueprintName = "CoreCronetEnd2EndTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
BuildableName = "CoreCronetEnd2EndTests.xctest"
BlueprintName = "CoreCronetEnd2EndTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
BuildableName = "CoreCronetEnd2EndTests.xctest"
BlueprintName = "CoreCronetEnd2EndTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -1,60 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableAddressSanitizer = "YES"
enableASanStackUseAfterReturn = "YES"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
BuildableName = "CoreCronetEnd2EndTests.xctest"
BlueprintName = "CoreCronetEnd2EndTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableThreadSanitizer = "YES"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
BuildableName = "CoreCronetEnd2EndTests.xctest"
BlueprintName = "CoreCronetEnd2EndTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -11,19 +11,19 @@
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84331BE15294000708E8"
BuildableName = "InteropTestsLocalSSL.xctest"
BlueprintName = "InteropTestsLocalSSL"
BlueprintIdentifier = "5E7F485822775B15006656AD"
BuildableName = "CronetTests.xctest"
BlueprintName = "CronetTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Test"
buildConfiguration = "Cronet"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
@ -32,9 +32,9 @@
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84331BE15294000708E8"
BuildableName = "InteropTestsLocalSSL.xctest"
BlueprintName = "InteropTestsLocalSSL"
BlueprintIdentifier = "5E7F485822775B15006656AD"
BuildableName = "CronetTests.xctest"
BlueprintName = "CronetTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
<SkippedTests>
@ -44,20 +44,11 @@
</SkippedTests>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84331BE15294000708E8"
BuildableName = "InteropTestsLocalSSL.xctest"
BlueprintName = "InteropTestsLocalSSL"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Test"
buildConfiguration = "Cronet"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
@ -69,9 +60,9 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84331BE15294000708E8"
BuildableName = "InteropTestsLocalSSL.xctest"
BlueprintName = "InteropTestsLocalSSL"
BlueprintIdentifier = "5E7F485822775B15006656AD"
BuildableName = "CronetTests.xctest"
BlueprintName = "CronetTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
@ -79,14 +70,23 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
buildConfiguration = "Cronet"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E7F485822775B15006656AD"
BuildableName = "CronetTests.xctest"
BlueprintName = "CronetTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Test">
buildConfiguration = "Cronet">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EAD6D231E27047400002378"
BuildableName = "CronetUnitTests.xctest"
BlueprintName = "CronetUnitTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -11,19 +11,19 @@
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84221BE15267000708E8"
BuildableName = "InteropTestsRemote.xctest"
BlueprintName = "InteropTestsRemote"
BlueprintIdentifier = "5EA476F32272816A000F72FC"
BuildableName = "InteropTests.xctest"
BlueprintName = "InteropTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Test"
buildConfiguration = "Cronet"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
@ -32,9 +32,9 @@
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84221BE15267000708E8"
BuildableName = "InteropTestsRemote.xctest"
BlueprintName = "InteropTestsRemote"
BlueprintIdentifier = "5EA476F32272816A000F72FC"
BuildableName = "InteropTests.xctest"
BlueprintName = "InteropTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
<SkippedTests>
@ -44,20 +44,11 @@
</SkippedTests>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84221BE15267000708E8"
BuildableName = "InteropTestsRemote.xctest"
BlueprintName = "InteropTestsRemote"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Test"
buildConfiguration = "Cronet"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
@ -69,9 +60,9 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84221BE15267000708E8"
BuildableName = "InteropTestsRemote.xctest"
BlueprintName = "InteropTestsRemote"
BlueprintIdentifier = "5EA476F32272816A000F72FC"
BuildableName = "InteropTests.xctest"
BlueprintName = "InteropTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
@ -84,9 +75,18 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EA476F32272816A000F72FC"
BuildableName = "InteropTests.xctest"
BlueprintName = "InteropTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Test">
buildConfiguration = "Cronet">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E7D71B1210B9EC8001EA6BA"
BuildableName = "InteropTestsCallOptions.xctest"
BlueprintName = "InteropTestsCallOptions"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -1,95 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84421BE152B5000708E8"
BuildableName = "InteropTestsLocalCleartext.xctest"
BlueprintName = "InteropTestsLocalCleartext"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84421BE152B5000708E8"
BuildableName = "InteropTestsLocalCleartext.xctest"
BlueprintName = "InteropTestsLocalCleartext"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
<SkippedTests>
<Test
Identifier = "InteropTests">
</Test>
</SkippedTests>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84421BE152B5000708E8"
BuildableName = "InteropTestsLocalCleartext.xctest"
BlueprintName = "InteropTestsLocalCleartext"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63DC84421BE152B5000708E8"
BuildableName = "InteropTestsLocalCleartext.xctest"
BlueprintName = "InteropTestsLocalCleartext"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Test">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save