Merge branch 'master' into grpcdotnet_client_compression

pull/20076/head
Jan Tattermusch 6 years ago committed by GitHub
commit 7d0dc91a9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 2
      .github/ISSUE_TEMPLATE/cleanup_request.md
  3. 2
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 2
      .github/pull_request_template.md
  5. 11
      BUILD
  6. 2
      BUILDING.md
  7. 1
      Rakefile
  8. 25
      bazel/grpc_build_system.bzl
  9. 15
      bazel/grpc_deps.bzl
  10. 9
      bazel/grpc_python_deps.bzl
  11. 34
      bazel/python_rules.bzl
  12. 6
      bazel/test/python_test_repo/BUILD
  13. 2
      examples/BUILD
  14. 3
      examples/python/auth/BUILD.bazel
  15. 5
      examples/python/cancellation/BUILD.bazel
  16. 3
      examples/python/compression/BUILD.bazel
  17. 3
      examples/python/debug/BUILD.bazel
  18. 1
      examples/python/errors/BUILD.bazel
  19. 5
      examples/python/multiprocessing/BUILD
  20. 1
      examples/python/wait_for_ready/BUILD.bazel
  21. 30
      gRPC-ProtoRPC.podspec
  22. 17
      gRPC-RxLibrary.podspec
  23. 116
      gRPC.podspec
  24. 9
      include/grpc/impl/codegen/port_platform.h
  25. 97
      src/compiler/objective_c_generator.cc
  26. 14
      src/compiler/objective_c_generator.h
  27. 60
      src/compiler/objective_c_plugin.cc
  28. 19
      src/core/ext/filters/client_channel/client_channel.cc
  29. 4
      src/core/ext/filters/client_channel/client_channel_factory.h
  30. 10
      src/core/ext/filters/client_channel/http_proxy.cc
  31. 2
      src/core/ext/filters/client_channel/lb_policy.cc
  32. 61
      src/core/ext/filters/client_channel/lb_policy.h
  33. 23
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  34. 15
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
  35. 11
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
  36. 52
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
  37. 38
      src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
  38. 14
      src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc
  39. 10
      src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h
  40. 45
      src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc
  41. 8
      src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
  42. 8
      src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
  43. 11
      src/core/ext/filters/client_channel/resolving_lb_policy.cc
  44. 31
      src/core/ext/filters/load_reporting/registered_opencensus_objects.h
  45. 43
      src/core/ext/transport/chttp2/client/insecure/channel_create.cc
  46. 45
      src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
  47. 7
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  48. 2
      src/core/ext/transport/chttp2/transport/hpack_table.cc
  49. 4
      src/core/ext/transport/chttp2/transport/hpack_table.h
  50. 6
      src/core/lib/gpr/log_linux.cc
  51. 4
      src/core/lib/gpr/log_posix.cc
  52. 10
      src/core/lib/gprpp/abstract.h
  53. 16
      src/core/lib/gprpp/map.h
  54. 4
      src/core/lib/iomgr/ev_epollex_linux.cc
  55. 2
      src/core/lib/iomgr/tcp_server_custom.cc
  56. 10
      src/core/lib/security/credentials/credentials.h
  57. 20
      src/core/lib/slice/slice_intern.cc
  58. 2
      src/core/lib/slice/slice_internal.h
  59. 10
      src/core/lib/slice/slice_utils.h
  60. 3
      src/core/lib/surface/init.cc
  61. 8
      src/core/lib/transport/metadata.cc
  62. 1648
      src/core/lib/transport/static_metadata.cc
  63. 454
      src/core/lib/transport/static_metadata.h
  64. 4
      src/cpp/client/create_channel.cc
  65. 2
      src/cpp/client/secure_credentials.cc
  66. 17
      src/cpp/ext/filters/census/grpc_plugin.cc
  67. 9
      src/cpp/ext/filters/census/grpc_plugin.h
  68. 11
      src/cpp/server/load_reporter/load_reporter.cc
  69. 11
      src/cpp/server/load_reporter/load_reporter.h
  70. 2
      src/csharp/experimental/README.md
  71. 243
      src/objective-c/BUILD
  72. 2
      src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
  73. 4
      src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
  74. 2
      src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
  75. 2
      src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m
  76. 13
      src/objective-c/GRPCClient/GRPCCall+Cronet.h
  77. 4
      src/objective-c/GRPCClient/GRPCCall+Cronet.m
  78. 2
      src/objective-c/GRPCClient/GRPCCall+GID.h
  79. 4
      src/objective-c/GRPCClient/GRPCCall+OAuth2.h
  80. 2
      src/objective-c/GRPCClient/GRPCCall+Tests.h
  81. 2
      src/objective-c/GRPCClient/GRPCCall+Tests.m
  82. 240
      src/objective-c/GRPCClient/GRPCCall.h
  83. 867
      src/objective-c/GRPCClient/GRPCCall.m
  84. 136
      src/objective-c/GRPCClient/GRPCCallLegacy.h
  85. 677
      src/objective-c/GRPCClient/GRPCCallLegacy.m
  86. 82
      src/objective-c/GRPCClient/GRPCCallOptions.h
  87. 27
      src/objective-c/GRPCClient/GRPCCallOptions.m
  88. 30
      src/objective-c/GRPCClient/GRPCDispatchable.h
  89. 32
      src/objective-c/GRPCClient/GRPCInterceptor.h
  90. 265
      src/objective-c/GRPCClient/GRPCInterceptor.m
  91. 82
      src/objective-c/GRPCClient/GRPCTransport.h
  92. 142
      src/objective-c/GRPCClient/GRPCTransport.m
  93. 187
      src/objective-c/GRPCClient/GRPCTypes.h
  94. 2
      src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m
  95. 0
      src/objective-c/GRPCClient/private/ChannelArgsUtil.h
  96. 0
      src/objective-c/GRPCClient/private/ChannelArgsUtil.m
  97. 6
      src/objective-c/GRPCClient/private/GRPCCall+V2API.h
  98. 14
      src/objective-c/GRPCClient/private/GRPCCallInternal.h
  99. 140
      src/objective-c/GRPCClient/private/GRPCCallInternal.m
  100. 0
      src/objective-c/GRPCClient/private/GRPCChannel.h
  101. Some files were not shown because too many files have changed in this diff Show More

@ -2,7 +2,7 @@
name: Report a bug
about: Create a report to help us improve
labels: kind/bug, priority/P2
assignees: AspirinSJL
assignees: mhaidrygoog
---

@ -2,7 +2,7 @@
name: Request a cleanup
about: Suggest a cleanup in our repository
labels: kind/internal cleanup
assignees: AspirinSJL
assignees: mhaidrygoog
---

@ -2,7 +2,7 @@
name: Request a feature
about: Suggest an idea for this project
labels: kind/enhancement
assignees: AspirinSJL
assignees: mhaidrygoog
---

@ -8,4 +8,4 @@ If you know who should review your pull request, please remove the mentioning be
-->
@AspirinSJL
@mhaidrygoog

11
BUILD

@ -65,7 +65,7 @@ config_setting(
config_setting(
name = "python3",
values = {"python_path": "python3"},
flag_values = {"@bazel_tools//tools/python:python_version": "PY3"},
)
config_setting(
@ -73,6 +73,11 @@ config_setting(
values = {"cpu": "darwin"},
)
config_setting(
name = "grpc_use_cpp_std_lib",
values = {"define": "GRPC_USE_CPP_STD_LIB=1"},
)
# This should be updated along with build.yaml
g_stands_for = "ganges"
@ -1215,6 +1220,7 @@ grpc_cc_library(
"grpc_client_channel",
"grpc_lb_upb",
"grpc_resolver_fake",
"grpc_transport_chttp2_client_insecure",
],
)
@ -1241,6 +1247,7 @@ grpc_cc_library(
"grpc_lb_upb",
"grpc_resolver_fake",
"grpc_secure",
"grpc_transport_chttp2_client_secure",
],
)
@ -1264,6 +1271,7 @@ grpc_cc_library(
"grpc_base",
"grpc_client_channel",
"grpc_resolver_fake",
"grpc_transport_chttp2_client_insecure",
],
)
@ -1288,6 +1296,7 @@ grpc_cc_library(
"grpc_client_channel",
"grpc_resolver_fake",
"grpc_secure",
"grpc_transport_chttp2_client_secure",
],
)

@ -12,7 +12,7 @@ gRPC C++ - Building from source
If you plan to build from source and run tests, install the following as well:
```sh
$ [sudo] apt-get install libgflags-dev libgtest-dev
$ [sudo] apt-get install clang libc++-dev
$ [sudo] apt-get install clang-5.0 libc++-dev
```
Lastly, see the Protoc section below if you do not yet have the protoc compiler installed.

@ -105,6 +105,7 @@ task 'dlls' do
env_comp = "CC=#{opt[:cross]}-gcc "
env_comp += "CXX=#{opt[:cross]}-g++ "
env_comp += "LD=#{opt[:cross]}-gcc "
env_comp += "LDXX=#{opt[:cross]}-g++ "
docker_for_windows "gem update --system --no-document && #{env} #{env_comp} make -j #{out} && #{opt[:cross]}-strip -x -S #{out} && cp #{out} #{opt[:out]}"
end

@ -24,6 +24,7 @@
#
load("//bazel:cc_grpc_library.bzl", "cc_grpc_library")
load("@build_bazel_rules_apple//apple:resources.bzl", "apple_resource_bundle")
load("@upb//bazel:upb_proto_library.bzl", "upb_proto_library")
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
@ -98,6 +99,9 @@ def grpc_cc_library(
"//:grpc_allow_exceptions": ["GRPC_ALLOW_EXCEPTIONS=1"],
"//:grpc_disallow_exceptions": ["GRPC_ALLOW_EXCEPTIONS=0"],
"//conditions:default": [],
}) + select({
"//:grpc_use_cpp_std_lib": ["GRPC_USE_CPP_STD_LIB=1"],
"//conditions:default": [],
}),
hdrs = hdrs + public_hdrs,
deps = deps + _get_external_deps(external_deps),
@ -235,13 +239,19 @@ def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], da
)
def grpc_generate_one_off_targets():
apple_resource_bundle(
# The choice of name is signicant here, since it determines the bundle name.
name = "gRPCCertificates",
resources = ["etc/roots.pem"],
)
# In open-source, grpc_objc* libraries depend directly on //:grpc
native.alias(
name = "grpc_objc",
actual = "//:grpc",
)
def grpc_generate_objc_one_off_targets():
def grpc_objc_use_cronet_config():
pass
def grpc_sh_test(name, srcs, args = [], data = []):
@ -259,13 +269,22 @@ def grpc_sh_binary(name, srcs, data = []):
data = data,
)
def grpc_py_binary(name, srcs, data = [], deps = [], external_deps = [], testonly = False):
def grpc_py_binary(name,
srcs,
data = [],
deps = [],
external_deps = [],
testonly = False,
python_version = "PY2",
**kwargs):
native.py_binary(
name = name,
srcs = srcs,
testonly = testonly,
data = data,
deps = deps + _get_external_deps(external_deps),
python_version = python_version,
**kwargs
)
def grpc_package(name, visibility = "private", features = []):
@ -286,7 +305,7 @@ def grpc_package(name, visibility = "private", features = []):
def grpc_objc_library(
name,
srcs = [],
srcs,
hdrs = [],
textual_hdrs = [],
data = [],

@ -176,11 +176,11 @@ def grpc_deps():
if "bazel_toolchains" not in native.existing_rules():
http_archive(
name = "bazel_toolchains",
sha256 = "d968b414b32aa99c86977e1171645d31da2b52ac88060de3ac1e49932d5dcbf1",
strip_prefix = "bazel-toolchains-4bd5df80d77aa7f4fb943dfdfad5c9056a62fb47",
sha256 = "872955b658113924eb1a3594b04d43238da47f4f90c17b76e8785709490dc041",
strip_prefix = "bazel-toolchains-1083686fde6032378d52b4c98044922cebde364e",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/4bd5df80d77aa7f4fb943dfdfad5c9056a62fb47.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/4bd5df80d77aa7f4fb943dfdfad5c9056a62fb47.tar.gz",
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/1083686fde6032378d52b4c98044922cebde364e.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/1083686fde6032378d52b4c98044922cebde364e.tar.gz",
],
)
@ -221,10 +221,11 @@ def grpc_deps():
)
if "build_bazel_rules_apple" not in native.existing_rules():
git_repository(
http_archive(
name = "build_bazel_rules_apple",
remote = "https://github.com/bazelbuild/rules_apple.git",
tag = "0.17.2",
url = "https://github.com/bazelbuild/rules_apple/archive/b869b0d3868d78a1d4ffd866ccb304fb68aa12c3.tar.gz",
strip_prefix = "rules_apple-b869b0d3868d78a1d4ffd866ccb304fb68aa12c3",
sha256 = "bdc8e66e70b8a75da23b79f1f8c6207356df07d041d96d2189add7ee0780cf4e",
)
grpc_python_deps()

@ -47,6 +47,15 @@ def grpc_python_deps():
remote = "https://github.com/bazelbuild/rules_python.git",
)
if "rules_python" not in native.existing_rules():
http_archive(
name = "rules_python",
url = "https://github.com/bazelbuild/rules_python/archive/9d68f24659e8ce8b736590ba1e4418af06ec2552.zip",
sha256 = "f7402f11691d657161f871e11968a984e5b48b023321935f5a55d7e56cf4758a",
strip_prefix = "rules_python-9d68f24659e8ce8b736590ba1e4418af06ec2552",
)
python_configure(name = "local_config_python")
native.bind(

@ -61,22 +61,22 @@ _generate_pb2_src = rule(
def py_proto_library(
name,
srcs,
deps,
**kwargs):
"""Generate python code for a protobuf.
Args:
name: The name of the target.
srcs: A list of proto_library dependencies. Must contain a single element.
deps: A list of proto_library dependencies. Must contain a single element.
"""
codegen_target = "_{}_codegen".format(name)
if len(srcs) != 1:
if len(deps) != 1:
fail("Can only compile a single proto at a time.")
_generate_pb2_src(
name = codegen_target,
deps = srcs,
deps = deps,
**kwargs
)
@ -178,3 +178,29 @@ def py_grpc_library(
deps = [Label("//src/python/grpcio/grpc:grpcio")] + deps,
**kwargs
)
def py2and3_test(name,
py_test = native.py_test,
**kwargs):
if "python_version" in kwargs:
fail("Cannot specify 'python_version' in py2and3_test.")
names = [name + suffix for suffix in (".python2", ".python3")]
python_versions = ["PY2", "PY3"]
for case_name, python_version in zip(names, python_versions):
py_test(
name = case_name,
python_version = python_version,
**kwargs
)
suite_kwargs = {}
if "visibility" in kwargs:
suite_kwargs["visibility"] = kwargs["visibility"]
native.test_suite(
name = name,
tests = names,
**suite_kwargs
)

@ -29,7 +29,7 @@ proto_library(
py_proto_library(
name = "helloworld_py_pb2",
srcs = [":helloworld_proto"],
deps = [":helloworld_proto"],
)
py_grpc_library(
@ -40,12 +40,12 @@ py_grpc_library(
py_proto_library(
name = "duration_py_pb2",
srcs = ["@com_google_protobuf//:duration_proto"],
deps = ["@com_google_protobuf//:duration_proto"],
)
py_proto_library(
name = "timestamp_py_pb2",
srcs = ["@com_google_protobuf//:timestamp_proto"],
deps = ["@com_google_protobuf//:timestamp_proto"],
)
py_test(

@ -67,7 +67,7 @@ proto_library(
py_proto_library(
name = "helloworld_py_pb2",
srcs = [":protos/helloworld_proto"],
deps = [":protos/helloworld_proto"],
)
py_grpc_library(

@ -39,6 +39,7 @@ py_binary(
"//examples:helloworld_py_pb2",
"//examples:helloworld_py_pb2_grpc",
],
python_version = "PY3",
)
py_binary(
@ -51,6 +52,7 @@ py_binary(
"//examples:helloworld_py_pb2",
"//examples:helloworld_py_pb2_grpc",
],
python_version = "PY3",
)
py_test(
@ -63,4 +65,5 @@ py_test(
":customized_auth_server",
":_credentials",
],
python_version = "PY3",
)

@ -26,7 +26,7 @@ proto_library(
py_proto_library(
name = "hash_name_py_pb2",
srcs = [":hash_name_proto"],
deps = [":hash_name_proto"],
)
py_grpc_library(
@ -45,6 +45,7 @@ py_binary(
"//external:six"
],
srcs_version = "PY2AND3",
python_version = "PY3",
)
py_library(
@ -68,6 +69,7 @@ py_binary(
"//:python3": [],
}),
srcs_version = "PY2AND3",
python_version = "PY3",
)
py_test(
@ -78,4 +80,5 @@ py_test(
":server"
],
size = "small",
python_version = "PY3",
)

@ -21,6 +21,7 @@ py_binary(
"//examples:helloworld_py_pb2_grpc",
],
srcs_version = "PY2AND3",
python_version = "PY3",
)
py_binary(
@ -32,6 +33,7 @@ py_binary(
"//examples:helloworld_py_pb2_grpc",
],
srcs_version = "PY2AND3",
python_version = "PY3",
)
py_test(
@ -43,4 +45,5 @@ py_test(
":server",
],
size = "small",
python_version = "PY3",
)

@ -35,6 +35,7 @@ py_binary(
"//examples:helloworld_py_pb2",
"//examples:helloworld_py_pb2_grpc",
],
python_version = "PY3",
)
py_binary(
@ -45,6 +46,7 @@ py_binary(
"//src/python/grpcio/grpc:grpcio",
"//src/python/grpcio_channelz/grpc_channelz/v1:grpc_channelz",
],
python_version = "PY3",
)
py_test(
@ -59,4 +61,5 @@ py_test(
":send_message",
":get_stats",
],
python_version = "PY3",
)

@ -55,4 +55,5 @@ py_test(
"../../../src/python/grpcio_status",
"../../../src/python/grpcio_tests",
],
python_version = "PY3",
)

@ -23,7 +23,7 @@ proto_library(
py_proto_library(
name = "prime_proto_pb2",
srcs = [":prime_proto"],
deps = [":prime_proto"],
)
py_grpc_library(
@ -42,6 +42,7 @@ py_binary(
":prime_proto_pb2_grpc",
],
srcs_version = "PY3",
python_version = "PY3",
)
py_binary(
@ -57,6 +58,7 @@ py_binary(
"//:python3": [],
}),
srcs_version = "PY3",
python_version = "PY3",
)
py_test(
@ -67,4 +69,5 @@ py_test(
":server"
],
size = "small",
python_version = "PY3",
)

@ -30,4 +30,5 @@ py_test(
srcs = ["test/_wait_for_ready_example_test.py"],
deps = [":wait_for_ready_example",],
size = "small",
python_version = "PY3",
)

@ -42,40 +42,22 @@ Pod::Spec.new do |s|
s.module_name = name
s.header_dir = name
s.default_subspec = 'Main', 'Legacy', 'Legacy-Header'
src_dir = 'src/objective-c/ProtoRPC'
s.subspec 'Legacy-Header' do |ss|
ss.header_mappings_dir = "src/objective-c/ProtoRPC"
ss.public_header_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.h"
ss.source_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.h"
end
s.default_subspec = 'Main'
s.subspec 'Main' do |ss|
ss.header_mappings_dir = "src/objective-c/ProtoRPC"
ss.dependency "#{s.name}/Legacy-Header", version
ss.dependency 'gRPC/Interface', version
ss.dependency 'Protobuf', '~> 3.0'
ss.source_files = "src/objective-c/ProtoRPC/ProtoMethod.{h,m}",
"src/objective-c/ProtoRPC/ProtoRPC.{h,m}",
"src/objective-c/ProtoRPC/ProtoService.{h,m}"
end
s.subspec 'Legacy' do |ss|
ss.header_mappings_dir = "src/objective-c/ProtoRPC"
ss.dependency "#{s.name}/Main", version
ss.dependency "#{s.name}/Legacy-Header", version
ss.dependency 'gRPC/GRPCCore', version
ss.header_mappings_dir = "#{src_dir}"
ss.dependency 'gRPC', version
ss.dependency 'gRPC-RxLibrary', version
ss.dependency 'Protobuf', '~> 3.0'
ss.source_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.m",
"src/objective-c/ProtoRPC/ProtoServiceLegacy.m"
ss.source_files = "#{src_dir}/*.{h,m}"
end
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream' do |ss|
ss.dependency "#{s.name}/Legacy", version
ss.dependency "#{s.name}/Main", version
end
s.pod_target_xcconfig = {

@ -42,23 +42,6 @@ Pod::Spec.new do |s|
s.module_name = name
s.header_dir = name
s.default_subspec = 'Interface', 'Implementation'
src_dir = 'src/objective-c/RxLibrary'
s.subspec 'Interface' do |ss|
ss.header_mappings_dir = "#{src_dir}"
ss.source_files = "#{src_dir}/*.h"
ss.public_header_files = "#{src_dir}/*.h"
end
s.subspec 'Implementation' do |ss|
ss.header_mappings_dir = "#{src_dir}"
ss.source_files = "#{src_dir}/*.m", "#{src_dir}/**/*.{h,m}"
ss.private_header_files = "#{src_dir}/**/*.h"
ss.dependency "#{s.name}/Interface"
end
src_dir = 'src/objective-c/RxLibrary'
s.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}"
s.private_header_files = "#{src_dir}/private/*.h"

@ -41,7 +41,13 @@ Pod::Spec.new do |s|
s.module_name = name
s.header_dir = name
s.default_subspec = 'Interface', 'GRPCCore', 'Interface-Legacy'
src_dir = 'src/objective-c/GRPCClient'
s.dependency 'gRPC-RxLibrary', version
s.default_subspec = 'Main'
# Certificates, to be able to establish TLS connections:
s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] }
s.pod_target_xcconfig = {
# This is needed by all pods that depend on gRPC-RxLibrary:
@ -49,103 +55,29 @@ Pod::Spec.new do |s|
'CLANG_WARN_STRICT_PROTOTYPES' => 'NO',
}
s.subspec 'Interface-Legacy' do |ss|
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
ss.public_header_files = "GRPCClient/GRPCCall+ChannelArg.h",
"GRPCClient/GRPCCall+ChannelCredentials.h",
"GRPCClient/GRPCCall+Cronet.h",
"GRPCClient/GRPCCall+OAuth2.h",
"GRPCClient/GRPCCall+Tests.h",
"src/objective-c/GRPCClient/GRPCCallLegacy.h",
"src/objective-c/GRPCClient/GRPCTypes.h"
ss.source_files = "GRPCClient/GRPCCall+ChannelArg.h",
"GRPCClient/GRPCCall+ChannelCredentials.h",
"GRPCClient/GRPCCall+Cronet.h",
"GRPCClient/GRPCCall+OAuth2.h",
"GRPCClient/GRPCCall+Tests.h",
"src/objective-c/GRPCClient/GRPCCallLegacy.h",
"src/objective-c/GRPCClient/GRPCTypes.h"
ss.dependency "gRPC-RxLibrary/Interface", version
end
s.subspec 'Main' do |ss|
ss.header_mappings_dir = "#{src_dir}"
s.subspec 'Interface' do |ss|
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
ss.public_header_files = 'src/objective-c/GRPCClient/GRPCCall.h',
'src/objective-c/GRPCClient/GRPCCall+Interceptor.h',
'src/objective-c/GRPCClient/GRPCCallOptions.h',
'src/objective-c/GRPCClient/GRPCInterceptor.h',
'src/objective-c/GRPCClient/GRPCTransport.h',
'src/objective-c/GRPCClient/GRPCDispatchable.h',
'src/objective-c/GRPCClient/version.h'
ss.source_files = 'src/objective-c/GRPCClient/GRPCCall.h',
'src/objective-c/GRPCClient/GRPCCall.m',
'src/objective-c/GRPCClient/GRPCCall+Interceptor.h',
'src/objective-c/GRPCClient/GRPCCall+Interceptor.m',
'src/objective-c/GRPCClient/GRPCCallOptions.h',
'src/objective-c/GRPCClient/GRPCCallOptions.m',
'src/objective-c/GRPCClient/GRPCDispatchable.h',
'src/objective-c/GRPCClient/GRPCInterceptor.h',
'src/objective-c/GRPCClient/GRPCInterceptor.m',
'src/objective-c/GRPCClient/GRPCTransport.h',
'src/objective-c/GRPCClient/GRPCTransport.m',
'src/objective-c/GRPCClient/internal/*.h',
'src/objective-c/GRPCClient/private/GRPCTransport+Private.h',
'src/objective-c/GRPCClient/private/GRPCTransport+Private.m',
'src/objective-c/GRPCClient/version.h'
ss.dependency "#{s.name}/Interface-Legacy", version
end
ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}"
ss.exclude_files = "#{src_dir}/GRPCCall+GID.{h,m}"
ss.private_header_files = "#{src_dir}/private/*.h", "#{src_dir}/internal/*.h"
s.subspec 'GRPCCore' do |ss|
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
ss.public_header_files = 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h',
'src/objective-c/GRPCClient/GRPCCall+Cronet.h',
'src/objective-c/GRPCClient/GRPCCall+OAuth2.h',
'src/objective-c/GRPCClient/GRPCCall+Tests.h',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h',
'src/objective-c/GRPCClient/internal_testing/*.h'
ss.private_header_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.h'
ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,m}',
'src/objective-c/GRPCClient/private/GRPCCore/*.{h,m}',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.m',
'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h',
'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m',
'src/objective-c/GRPCClient/GRPCCall+Cronet.h',
'src/objective-c/GRPCClient/GRPCCall+Cronet.m',
'src/objective-c/GRPCClient/GRPCCall+OAuth2.h',
'src/objective-c/GRPCClient/GRPCCall+OAuth2.m',
'src/objective-c/GRPCClient/GRPCCall+Tests.h',
'src/objective-c/GRPCClient/GRPCCall+Tests.m',
'src/objective-c/GRPCClient/GRPCCallLegacy.m'
# Certificates, to be able to establish TLS connections:
ss.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] }
ss.dependency "#{s.name}/Interface-Legacy", version
ss.dependency "#{s.name}/Interface", version
ss.dependency 'gRPC-Core', version
ss.dependency 'gRPC-RxLibrary', version
end
s.subspec 'GRPCCoreCronet' do |ss|
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
ss.source_files = 'src/objective-c/GRPCClient/GRPCCall+Cronet.h',
'src/objective-c/GRPCClient/GRPCCall+Cronet.m',
'src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/*.{h,m}'
ss.dependency "#{s.name}/GRPCCore", version
ss.dependency 'gRPC-Core/Cronet-Implementation', version
ss.dependency 'CronetFramework'
end
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream' do |ss|
ss.dependency "#{s.name}/GRPCCore", version
ss.dependency "#{s.name}/Main", version
end
s.subspec 'GID' do |ss|
ss.ios.deployment_target = '7.0'
ss.header_mappings_dir = "#{src_dir}"
ss.source_files = "#{src_dir}/GRPCCall+GID.{h,m}"
ss.dependency "#{s.name}/Main", version
ss.dependency 'Google/SignIn'
end
end

@ -27,6 +27,15 @@
* - some syscalls to be made directly
*/
/*
* Defines GRPC_USE_CPP_STD_LIB to use standard C++ library instead of
* in-house library if possible. (e.g. std::map)
*/
#ifndef GRPC_USE_CPP_STD_LIB
/* Default value will be 1 once all tests become green. */
#define GRPC_USE_CPP_STD_LIB 0
#endif
/* Get windows.h included everywhere (we need it) */
#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
#ifndef WIN32_LEAN_AND_MEAN

@ -238,21 +238,19 @@ void PrintV2Implementation(Printer* printer, const MethodDescriptor* method,
}
void PrintMethodImplementations(Printer* printer,
const MethodDescriptor* method,
const Parameters& generator_params) {
const MethodDescriptor* method) {
map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
PrintProtoRpcDeclarationAsPragma(printer, method, vars);
if (!generator_params.no_v1_compatibility) {
// TODO(jcanizales): Print documentation from the method.
PrintSimpleSignature(printer, method, vars);
PrintSimpleImplementation(printer, method, vars);
// TODO(jcanizales): Print documentation from the method.
printer->Print("// Deprecated methods.\n");
PrintSimpleSignature(printer, method, vars);
PrintSimpleImplementation(printer, method, vars);
printer->Print("// Returns a not-yet-started RPC object.\n");
PrintAdvancedSignature(printer, method, vars);
PrintAdvancedImplementation(printer, method, vars);
}
printer->Print("// Returns a not-yet-started RPC object.\n");
PrintAdvancedSignature(printer, method, vars);
PrintAdvancedImplementation(printer, method, vars);
PrintV2Signature(printer, method, vars);
PrintV2Implementation(printer, method, vars);
@ -278,12 +276,9 @@ void PrintMethodImplementations(Printer* printer,
return output;
}
::grpc::string GetProtocol(const ServiceDescriptor* service,
const Parameters& generator_params) {
::grpc::string GetProtocol(const ServiceDescriptor* service) {
::grpc::string output;
if (generator_params.no_v1_compatibility) return output;
// Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
@ -326,8 +321,7 @@ void PrintMethodImplementations(Printer* printer,
return output;
}
::grpc::string GetInterface(const ServiceDescriptor* service,
const Parameters& generator_params) {
::grpc::string GetInterface(const ServiceDescriptor* service) {
::grpc::string output;
// Scope the output stream so it closes and finalizes output to the string.
@ -344,11 +338,7 @@ void PrintMethodImplementations(Printer* printer,
" */\n");
printer.Print(vars,
"@interface $service_class$ :"
" GRPCProtoService<$service_class$2");
if (!generator_params.no_v1_compatibility) {
printer.Print(vars, ", $service_class$");
}
printer.Print(">\n");
" GRPCProtoService<$service_class$, $service_class$2>\n");
printer.Print(
"- (instancetype)initWithHost:(NSString *)host "
"callOptions:(GRPCCallOptions "
@ -357,20 +347,17 @@ void PrintMethodImplementations(Printer* printer,
printer.Print(
"+ (instancetype)serviceWithHost:(NSString *)host "
"callOptions:(GRPCCallOptions *_Nullable)callOptions;\n");
if (!generator_params.no_v1_compatibility) {
printer.Print(
"// The following methods belong to a set of old APIs that have been "
"deprecated.\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host;\n");
printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
}
printer.Print(
"// The following methods belong to a set of old APIs that have been "
"deprecated.\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host;\n");
printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
printer.Print("@end\n");
return output;
}
::grpc::string GetSource(const ServiceDescriptor* service,
const Parameters& generator_params) {
::grpc::string GetSource(const ServiceDescriptor* service) {
::grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@ -394,28 +381,22 @@ void PrintMethodImplementations(Printer* printer,
" packageName:@\"$package$\"\n"
" serviceName:@\"$service_name$\"\n"
" callOptions:callOptions];\n"
"}\n\n");
if (!generator_params.no_v1_compatibility) {
printer.Print(vars,
"- (instancetype)initWithHost:(NSString *)host {\n"
" return [super initWithHost:host\n"
" packageName:@\"$package$\"\n"
" serviceName:@\"$service_name$\"];\n"
"}\n\n");
}
printer.Print("#pragma clang diagnostic pop\n\n");
if (!generator_params.no_v1_compatibility) {
printer.Print(
"// Override superclass initializer to disallow different"
" package and service names.\n"
"- (instancetype)initWithHost:(NSString *)host\n"
" packageName:(NSString *)packageName\n"
" serviceName:(NSString *)serviceName {\n"
" return [self initWithHost:host];\n"
"}\n\n");
}
"}\n\n"
"- (instancetype)initWithHost:(NSString *)host {\n"
" return [super initWithHost:host\n"
" packageName:@\"$package$\"\n"
" serviceName:@\"$service_name$\"];\n"
"}\n\n"
"#pragma clang diagnostic pop\n\n");
printer.Print(
"// Override superclass initializer to disallow different"
" package and service names.\n"
"- (instancetype)initWithHost:(NSString *)host\n"
" packageName:(NSString *)packageName\n"
" serviceName:(NSString *)serviceName {\n"
" return [self initWithHost:host];\n"
"}\n\n"
"- (instancetype)initWithHost:(NSString *)host\n"
" packageName:(NSString *)packageName\n"
" serviceName:(NSString *)serviceName\n"
@ -423,14 +404,11 @@ void PrintMethodImplementations(Printer* printer,
" return [self initWithHost:host callOptions:callOptions];\n"
"}\n\n");
printer.Print("#pragma mark - Class Methods\n\n");
if (!generator_params.no_v1_compatibility) {
printer.Print(
"+ (instancetype)serviceWithHost:(NSString *)host {\n"
" return [[self alloc] initWithHost:host];\n"
"}\n\n");
}
printer.Print(
"#pragma mark - Class Methods\n\n"
"+ (instancetype)serviceWithHost:(NSString *)host {\n"
" return [[self alloc] initWithHost:host];\n"
"}\n\n"
"+ (instancetype)serviceWithHost:(NSString *)host "
"callOptions:(GRPCCallOptions *_Nullable)callOptions {\n"
" return [[self alloc] initWithHost:host callOptions:callOptions];\n"
@ -439,8 +417,7 @@ void PrintMethodImplementations(Printer* printer,
printer.Print("#pragma mark - Method Implementations\n\n");
for (int i = 0; i < service->method_count(); i++) {
PrintMethodImplementations(&printer, service->method(i),
generator_params);
PrintMethodImplementations(&printer, service->method(i));
}
printer.Print("@end\n");

@ -23,11 +23,6 @@
namespace grpc_objective_c_generator {
struct Parameters {
// Do not generate V1 interface and implementation
bool no_v1_compatibility;
};
using ::grpc::protobuf::FileDescriptor;
using ::grpc::protobuf::FileDescriptor;
using ::grpc::protobuf::ServiceDescriptor;
@ -39,8 +34,7 @@ string GetAllMessageClasses(const FileDescriptor* file);
// Returns the content to be included defining the @protocol segment at the
// insertion point of the generated implementation file. This interface is
// legacy and for backwards compatibility.
string GetProtocol(const ServiceDescriptor* service,
const Parameters& generator_params);
string GetProtocol(const ServiceDescriptor* service);
// Returns the content to be included defining the @protocol segment at the
// insertion point of the generated implementation file.
@ -48,13 +42,11 @@ string GetV2Protocol(const ServiceDescriptor* service);
// Returns the content to be included defining the @interface segment at the
// insertion point of the generated implementation file.
string GetInterface(const ServiceDescriptor* service,
const Parameters& generator_params);
string GetInterface(const ServiceDescriptor* service);
// Returns the content to be included in the "global_scope" insertion point of
// the generated implementation file.
string GetSource(const ServiceDescriptor* service,
const Parameters& generator_params);
string GetSource(const ServiceDescriptor* service);
} // namespace grpc_objective_c_generator

@ -111,22 +111,6 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
::grpc::string file_name =
google::protobuf::compiler::objectivec::FilePath(file);
grpc_objective_c_generator::Parameters generator_params;
generator_params.no_v1_compatibility = false;
if (!parameter.empty()) {
std::vector<grpc::string> parameters_list =
grpc_generator::tokenize(parameter, ",");
for (auto parameter_string = parameters_list.begin();
parameter_string != parameters_list.end(); parameter_string++) {
std::vector<grpc::string> param =
grpc_generator::tokenize(*parameter_string, "=");
if (param[0] == "no_v1_compatibility") {
generator_params.no_v1_compatibility = true;
}
}
}
{
// Generate .pbrpc.h
@ -137,25 +121,18 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
imports = FrameworkImport(file_name + ".pbobjc.h", framework);
}
::grpc::string system_imports =
SystemImport("ProtoRPC/ProtoService.h") +
(generator_params.no_v1_compatibility
? SystemImport("ProtoRPC/ProtoRPC.h")
: SystemImport("ProtoRPC/ProtoRPCLegacy.h"));
if (!generator_params.no_v1_compatibility) {
system_imports += SystemImport("RxLibrary/GRXWriteable.h") +
SystemImport("RxLibrary/GRXWriter.h");
}
::grpc::string system_imports = SystemImport("ProtoRPC/ProtoService.h") +
SystemImport("ProtoRPC/ProtoRPC.h") +
SystemImport("RxLibrary/GRXWriteable.h") +
SystemImport("RxLibrary/GRXWriter.h");
::grpc::string forward_declarations =
"@class GRPCProtoCall;\n"
"@class GRPCUnaryProtoCall;\n"
"@class GRPCStreamingProtoCall;\n"
"@class GRPCCallOptions;\n"
"@protocol GRPCProtoResponseHandler;\n";
if (!generator_params.no_v1_compatibility) {
forward_declarations += "@class GRPCProtoCall;\n";
}
forward_declarations += "\n";
"@protocol GRPCProtoResponseHandler;\n"
"\n";
::grpc::string class_declarations =
grpc_objective_c_generator::GetAllMessageClasses(file);
@ -175,15 +152,13 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
::grpc::string protocols;
for (int i = 0; i < file->service_count(); i++) {
const grpc::protobuf::ServiceDescriptor* service = file->service(i);
protocols +=
grpc_objective_c_generator::GetProtocol(service, generator_params);
protocols += grpc_objective_c_generator::GetProtocol(service);
}
::grpc::string interfaces;
for (int i = 0; i < file->service_count(); i++) {
const grpc::protobuf::ServiceDescriptor* service = file->service(i);
interfaces +=
grpc_objective_c_generator::GetInterface(service, generator_params);
interfaces += grpc_objective_c_generator::GetInterface(service);
}
Write(context, file_name + ".pbrpc.h",
@ -203,16 +178,14 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
::grpc::string imports;
if (framework.empty()) {
imports = LocalImport(file_name + ".pbrpc.h") +
LocalImport(file_name + ".pbobjc.h");
LocalImport(file_name + ".pbobjc.h") +
SystemImport("ProtoRPC/ProtoRPC.h") +
SystemImport("RxLibrary/GRXWriter+Immediate.h");
} else {
imports = FrameworkImport(file_name + ".pbrpc.h", framework) +
FrameworkImport(file_name + ".pbobjc.h", framework);
}
imports += (generator_params.no_v1_compatibility
? SystemImport("ProtoRPC/ProtoRPC.h")
: SystemImport("ProtoRPC/ProtoRPCLegacy.h"));
if (!generator_params.no_v1_compatibility) {
imports += SystemImport("RxLibrary/GRXWriter+Immediate.h");
FrameworkImport(file_name + ".pbobjc.h", framework) +
SystemImport("ProtoRPC/ProtoRPC.h") +
SystemImport("RxLibrary/GRXWriter+Immediate.h");
}
::grpc::string class_imports;
@ -223,8 +196,7 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
::grpc::string definitions;
for (int i = 0; i < file->service_count(); i++) {
const grpc::protobuf::ServiceDescriptor* service = file->service(i);
definitions +=
grpc_objective_c_generator::GetSource(service, generator_params);
definitions += grpc_objective_c_generator::GetSource(service);
}
Write(context, file_name + ".pbrpc.m",

@ -1318,11 +1318,6 @@ class ChannelData::ClientChannelControlHelper
chand_, subchannel, std::move(health_check_service_name));
}
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args& args) override {
return chand_->client_channel_factory_->CreateChannel(target, &args);
}
void UpdateState(
grpc_connectivity_state state,
UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker) override {
@ -1345,11 +1340,11 @@ class ChannelData::ClientChannelControlHelper
// No-op -- we should never get this from ResolvingLoadBalancingPolicy.
void RequestReresolution() override {}
void AddTraceEvent(TraceSeverity severity, const char* message) override {
void AddTraceEvent(TraceSeverity severity, StringView message) override {
if (chand_->channelz_node_ != nullptr) {
chand_->channelz_node_->AddTraceEvent(
ConvertSeverityEnum(severity),
grpc_slice_from_copied_string(message));
grpc_slice_from_copied_buffer(message.data(), message.size()));
}
}
@ -3168,8 +3163,8 @@ void CallData::AddRetriableSendInitialMetadataOp(
SubchannelCallRetryState* retry_state,
SubchannelCallBatchData* batch_data) {
// Maps the number of retries to the corresponding metadata value slice.
static const grpc_slice* retry_count_strings[] = {
&GRPC_MDSTR_1, &GRPC_MDSTR_2, &GRPC_MDSTR_3, &GRPC_MDSTR_4};
const grpc_slice* retry_count_strings[] = {&GRPC_MDSTR_1, &GRPC_MDSTR_2,
&GRPC_MDSTR_3, &GRPC_MDSTR_4};
// We need to make a copy of the metadata batch for each attempt, since
// the filters in the subchannel stack may modify this batch, and we don't
// want those modifications to be passed forward to subsequent attempts.
@ -3730,8 +3725,8 @@ const char* PickResultTypeName(
return "COMPLETE";
case LoadBalancingPolicy::PickResult::PICK_QUEUE:
return "QUEUE";
case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE:
return "TRANSIENT_FAILURE";
case LoadBalancingPolicy::PickResult::PICK_FAILED:
return "FAILED";
}
GPR_UNREACHABLE_CODE(return "UNKNOWN");
}
@ -3792,7 +3787,7 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
result.subchannel.get(), grpc_error_string(result.error));
}
switch (result.type) {
case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE: {
case LoadBalancingPolicy::PickResult::PICK_FAILED: {
// If we're shutting down, fail all RPCs.
grpc_error* disconnect_error = chand->disconnect_error();
if (disconnect_error != GRPC_ERROR_NONE) {

@ -36,10 +36,6 @@ class ClientChannelFactory {
virtual Subchannel* CreateSubchannel(const grpc_channel_args* args)
GRPC_ABSTRACT;
// Creates a channel for the specified target with the specified args.
virtual grpc_channel* CreateChannel(
const char* target, const grpc_channel_args* args) GRPC_ABSTRACT;
// Returns a channel arg containing the specified factory.
static grpc_arg CreateChannelArg(ClientChannelFactory* factory);

@ -47,10 +47,12 @@ static char* get_http_proxy_server(char** user_cred) {
char* proxy_name = nullptr;
char** authority_strs = nullptr;
size_t authority_nstrs;
/* Prefer using 'https_proxy'. Fallback on 'http_proxy' if it is not set. The
/* Prefer using 'grpc_proxy'. Fallback on 'http_proxy' if it is not set.
* Also prefer using 'https_proxy' with fallback on 'http_proxy'. The
* fallback behavior can be removed if there's a demand for it.
*/
char* uri_str = gpr_getenv("https_proxy");
char* uri_str = gpr_getenv("grpc_proxy");
if (uri_str == nullptr) uri_str = gpr_getenv("https_proxy");
if (uri_str == nullptr) uri_str = gpr_getenv("http_proxy");
if (uri_str == nullptr) return nullptr;
grpc_uri* uri = grpc_uri_parse(uri_str, false /* suppress_errors */);
@ -122,7 +124,9 @@ static bool proxy_mapper_map_name(grpc_proxy_mapper* mapper,
server_uri);
goto no_use_proxy;
}
no_proxy_str = gpr_getenv("no_proxy");
/* Prefer using 'no_grpc_proxy'. Fallback on 'no_proxy' if it is not set. */
no_proxy_str = gpr_getenv("no_grpc_proxy");
if (no_proxy_str == nullptr) no_proxy_str = gpr_getenv("no_proxy");
if (no_proxy_str != nullptr) {
static const char* NO_PROXY_SEPARATOR = ",";
bool use_proxy = true;

@ -129,7 +129,7 @@ void LoadBalancingPolicy::QueuePicker::CallExitIdle(void* arg,
LoadBalancingPolicy::PickResult
LoadBalancingPolicy::TransientFailurePicker::Pick(PickArgs args) {
PickResult result;
result.type = PickResult::PICK_TRANSIENT_FAILURE;
result.type = PickResult::PICK_FAILED;
result.error = GRPC_ERROR_REF(error_);
return result;
}

@ -42,15 +42,15 @@ extern DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
///
/// Channel: An abstraction that manages connections to backend servers
/// on behalf of a client application. The application creates a channel
/// for a given server name and then sends RPCs on it, and the channel
/// figures out which backend server to send each RPC to. A channel
/// for a given server name and then sends calls (RPCs) on it, and the
/// channel figures out which backend server to send each call to. A channel
/// contains a resolver, a load balancing policy (or a tree of LB policies),
/// and a set of one or more subchannels.
///
/// Subchannel: A subchannel represents a connection to one backend server.
/// The LB policy decides which subchannels to create, manages the
/// connectivity state of those subchannels, and decides which subchannel
/// to send any given RPC to.
/// to send any given call to.
///
/// Resolver: A plugin that takes a gRPC server URI and resolves it to a
/// list of one or more addresses and a service config, as described
@ -59,12 +59,12 @@ extern DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
///
/// Load Balancing (LB) Policy: A plugin that takes a list of addresses
/// from the resolver, maintains and manages a subchannel for each
/// backend address, and decides which subchannel to send each RPC on.
/// backend address, and decides which subchannel to send each call on.
/// An LB policy has two parts:
/// - A LoadBalancingPolicy, which deals with the control plane work of
/// managing subchannels.
/// - A SubchannelPicker, which handles the data plane work of
/// determining which subchannel a given RPC should be sent on.
/// determining which subchannel a given call should be sent on.
/// LoadBalacingPolicy API.
///
@ -78,6 +78,7 @@ extern DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
public:
/// Interface for accessing per-call state.
/// Implemented by the client channel and used by the SubchannelPicker.
class CallState {
public:
CallState() = default;
@ -93,6 +94,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
};
/// Interface for accessing metadata.
/// Implemented by the client channel and used by the SubchannelPicker.
class MetadataInterface {
public:
// Implementations whose iterators fit in intptr_t may internally
@ -123,7 +125,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
GRPC_ABSTRACT_BASE_CLASS
};
/// Arguments used when picking a subchannel for an RPC.
/// Arguments used when picking a subchannel for a call.
struct PickArgs {
/// Initial metadata associated with the picking call.
/// The LB policy may use the existing metadata to influence its routing
@ -135,24 +137,23 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
CallState* call_state;
};
/// The result of picking a subchannel for an RPC.
/// The result of picking a subchannel for a call.
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. If \a subchannel is non-null, the client channel
/// will immediately proceed with the call on that subchannel;
/// otherwise, it will drop the call.
PICK_COMPLETE,
/// Pick cannot be completed until something changes on the control
/// plane. Client channel will queue the pick and try again the
/// plane. The 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,
/// Pick failed. If the call is wait_for_ready, the client channel
/// will wait for the next picker and try again; otherwise, it
/// will immediately fail the call with the status indicated via
/// \a error (although the call may be retried if the client channel
/// is configured to do so).
PICK_FAILED,
};
ResultType type;
@ -160,14 +161,14 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
/// subchannel, or nullptr if the LB policy decides to drop the call.
RefCountedPtr<SubchannelInterface> subchannel;
/// Used only if type is PICK_TRANSIENT_FAILURE.
/// Error to be set when returning a transient failure.
/// Used only if type is PICK_FAILED.
/// Error to be set when returning a failure.
// TODO(roth): Replace this with something similar to grpc::Status,
// so that we don't expose grpc_error to this API.
grpc_error* error = GRPC_ERROR_NONE;
/// Used only if type is PICK_COMPLETE.
/// Callback set by lb policy to be notified of trailing metadata.
/// 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
@ -184,11 +185,12 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
};
/// A subchannel picker is the object used to pick the subchannel to
/// use for a given RPC.
/// use for a given call. This is implemented by the LB policy and
/// used by the client channel to perform picks.
///
/// Pickers are intended to encapsulate all of the state and logic
/// needed on the data plane (i.e., to actually process picks for
/// individual RPCs sent on the channel) while excluding all of the
/// individual calls sent on the channel) while excluding all of the
/// state and logic needed on the control plane (i.e., resolver
/// updates, connectivity state notifications, etc); the latter should
/// live in the LB policy object itself.
@ -206,8 +208,8 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
GRPC_ABSTRACT_BASE_CLASS
};
/// A proxy object used by the LB policy to communicate with the client
/// channel.
/// A proxy object implemented by the client channel and used by the
/// LB policy to communicate with the channel.
// TODO(juanlishen): Consider adding a mid-layer subclass that helps handle
// things like swapping in pending policy when it's ready. Currently, we are
// duplicating the logic in many subclasses.
@ -220,12 +222,6 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
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
/// channel for its own use (e.g., to talk to an external load balancer).
virtual grpc_channel* CreateChannel(
const char* target, const grpc_channel_args& args) GRPC_ABSTRACT;
/// Sets the connectivity state and returns a new picker to be used
/// by the client channel.
virtual void UpdateState(grpc_connectivity_state state,
@ -235,10 +231,9 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
virtual void RequestReresolution() GRPC_ABSTRACT;
/// Adds a trace message associated with the channel.
/// Does NOT take ownership of \a message.
enum TraceSeverity { TRACE_INFO, TRACE_WARNING, TRACE_ERROR };
virtual void AddTraceEvent(TraceSeverity severity,
const char* message) GRPC_ABSTRACT;
StringView message) GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};

@ -293,12 +293,10 @@ class GrpcLb : public LoadBalancingPolicy {
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override;
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args& args) override;
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override;
void RequestReresolution() override;
void AddTraceEvent(TraceSeverity severity, const char* message) override;
void AddTraceEvent(TraceSeverity severity, StringView message) override;
void set_child(LoadBalancingPolicy* child) { child_ = child; }
@ -652,15 +650,6 @@ RefCountedPtr<SubchannelInterface> GrpcLb::Helper::CreateSubchannel(
return parent_->channel_control_helper()->CreateSubchannel(args);
}
grpc_channel* GrpcLb::Helper::CreateChannel(const char* target,
const grpc_channel_args& args) {
if (parent_->shutting_down_ ||
(!CalledByPendingChild() && !CalledByCurrentChild())) {
return nullptr;
}
return parent_->channel_control_helper()->CreateChannel(target, args);
}
void GrpcLb::Helper::UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) {
if (parent_->shutting_down_) return;
@ -756,8 +745,7 @@ void GrpcLb::Helper::RequestReresolution() {
}
}
void GrpcLb::Helper::AddTraceEvent(TraceSeverity severity,
const char* message) {
void GrpcLb::Helper::AddTraceEvent(TraceSeverity severity, StringView message) {
if (parent_->shutting_down_ ||
(!CalledByPendingChild() && !CalledByCurrentChild())) {
return;
@ -1276,7 +1264,7 @@ grpc_channel_args* BuildBalancerChannelArgs(
// the LB channel.
GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
// The LB channel should use the authority indicated by the target
// authority table (see \a grpc_lb_policy_grpclb_modify_lb_channel_args),
// authority table (see \a ModifyGrpclbBalancerChannelArgs),
// as opposed to the authority from the parent channel.
GRPC_ARG_DEFAULT_AUTHORITY,
// Just as for \a GRPC_ARG_DEFAULT_AUTHORITY, the LB channel should be
@ -1312,7 +1300,7 @@ grpc_channel_args* BuildBalancerChannelArgs(
args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add.data(),
args_to_add.size());
// Make any necessary modifications for security.
return grpc_lb_policy_grpclb_modify_lb_channel_args(addresses, new_args);
return ModifyGrpclbBalancerChannelArgs(addresses, new_args);
}
//
@ -1488,8 +1476,7 @@ void GrpcLb::ProcessAddressesAndChannelArgsLocked(
if (lb_channel_ == nullptr) {
char* uri_str;
gpr_asprintf(&uri_str, "fake:///%s", server_name_);
lb_channel_ =
channel_control_helper()->CreateChannel(uri_str, *lb_channel_args);
lb_channel_ = CreateGrpclbBalancerChannel(uri_str, *lb_channel_args);
GPR_ASSERT(lb_channel_ != nullptr);
gpr_free(uri_str);
}

@ -18,9 +18,20 @@
#include <grpc/support/port_platform.h>
#include <grpc/grpc.h>
#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h"
grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
const grpc_core::ServerAddressList& addresses, grpc_channel_args* args) {
namespace grpc_core {
grpc_channel_args* ModifyGrpclbBalancerChannelArgs(
const ServerAddressList& addresses, grpc_channel_args* args) {
return args;
}
grpc_channel* CreateGrpclbBalancerChannel(const char* target_uri,
const grpc_channel_args& args) {
return grpc_insecure_channel_create(target_uri, &args, nullptr);
}
} // namespace grpc_core

@ -25,14 +25,21 @@
#include "src/core/ext/filters/client_channel/server_address.h"
namespace grpc_core {
/// Makes any necessary modifications to \a args for use in the grpclb
/// balancer channel.
///
/// Takes ownership of \a args.
///
/// Caller takes ownership of the returned args.
grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
const grpc_core::ServerAddressList& addresses, grpc_channel_args* args);
grpc_channel_args* ModifyGrpclbBalancerChannelArgs(
const ServerAddressList& addresses, grpc_channel_args* args);
grpc_channel* CreateGrpclbBalancerChannel(const char* target_uri,
const grpc_channel_args& args);
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H \
*/

@ -22,6 +22,7 @@
#include <string.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
@ -35,6 +36,7 @@
#include "src/core/lib/slice/slice_internal.h"
namespace grpc_core {
namespace {
int BalancerNameCmp(const grpc_core::UniquePtr<char>& a,
@ -65,37 +67,53 @@ RefCountedPtr<TargetAuthorityTable> CreateTargetAuthorityTable(
}
} // namespace
} // namespace grpc_core
grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
const grpc_core::ServerAddressList& addresses, grpc_channel_args* args) {
const char* args_to_remove[1];
size_t num_args_to_remove = 0;
grpc_arg args_to_add[2];
size_t num_args_to_add = 0;
grpc_channel_args* ModifyGrpclbBalancerChannelArgs(
const ServerAddressList& addresses, grpc_channel_args* args) {
InlinedVector<const char*, 1> args_to_remove;
InlinedVector<grpc_arg, 2> args_to_add;
// Add arg for targets info table.
grpc_core::RefCountedPtr<grpc_core::TargetAuthorityTable>
target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses);
args_to_add[num_args_to_add++] =
grpc_core::CreateTargetAuthorityTableChannelArg(
target_authority_table.get());
RefCountedPtr<TargetAuthorityTable> target_authority_table =
CreateTargetAuthorityTable(addresses);
args_to_add.emplace_back(
CreateTargetAuthorityTableChannelArg(target_authority_table.get()));
// Substitute the channel credentials with a version without call
// credentials: the load balancer is not necessarily trusted to handle
// bearer token credentials.
grpc_channel_credentials* channel_credentials =
grpc_channel_credentials_find_in_args(args);
grpc_core::RefCountedPtr<grpc_channel_credentials> creds_sans_call_creds;
RefCountedPtr<grpc_channel_credentials> creds_sans_call_creds;
if (channel_credentials != nullptr) {
creds_sans_call_creds =
channel_credentials->duplicate_without_call_credentials();
GPR_ASSERT(creds_sans_call_creds != nullptr);
args_to_remove[num_args_to_remove++] = GRPC_ARG_CHANNEL_CREDENTIALS;
args_to_add[num_args_to_add++] =
grpc_channel_credentials_to_arg(creds_sans_call_creds.get());
args_to_remove.emplace_back(GRPC_ARG_CHANNEL_CREDENTIALS);
args_to_add.emplace_back(
grpc_channel_credentials_to_arg(creds_sans_call_creds.get()));
}
grpc_channel_args* result = grpc_channel_args_copy_and_add_and_remove(
args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add);
args, args_to_remove.data(), args_to_remove.size(), args_to_add.data(),
args_to_add.size());
// Clean up.
grpc_channel_args_destroy(args);
return result;
}
grpc_channel* CreateGrpclbBalancerChannel(const char* target_uri,
const grpc_channel_args& args) {
grpc_channel_credentials* creds =
grpc_channel_credentials_find_in_args(&args);
if (creds == nullptr) {
// Build with security but parent channel is insecure.
return grpc_insecure_channel_create(target_uri, &args, nullptr);
}
const char* arg_to_remove = GRPC_ARG_CHANNEL_CREDENTIALS;
grpc_channel_args* new_args =
grpc_channel_args_copy_and_remove(&args, &arg_to_remove, 1);
grpc_channel* channel =
grpc_secure_channel_create(creds, target_uri, new_args, nullptr);
grpc_channel_args_destroy(new_args);
return channel;
}
} // namespace grpc_core

@ -431,12 +431,10 @@ class XdsLb : public LoadBalancingPolicy {
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override;
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args& args) override;
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override;
void RequestReresolution() override;
void AddTraceEvent(TraceSeverity severity, const char* message) override;
void AddTraceEvent(TraceSeverity severity, StringView message) override;
void set_child(LoadBalancingPolicy* child) { child_ = child; }
@ -482,13 +480,10 @@ class XdsLb : public LoadBalancingPolicy {
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override;
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args& args) override;
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override;
void RequestReresolution() override;
void AddTraceEvent(TraceSeverity severity,
const char* message) override;
void AddTraceEvent(TraceSeverity severity, StringView message) override;
void set_child(LoadBalancingPolicy* child) { child_ = child; }
private:
@ -723,15 +718,6 @@ RefCountedPtr<SubchannelInterface> XdsLb::FallbackHelper::CreateSubchannel(
return parent_->channel_control_helper()->CreateSubchannel(args);
}
grpc_channel* XdsLb::FallbackHelper::CreateChannel(
const char* target, const grpc_channel_args& args) {
if (parent_->shutting_down_ ||
(!CalledByPendingFallback() && !CalledByCurrentFallback())) {
return nullptr;
}
return parent_->channel_control_helper()->CreateChannel(target, args);
}
void XdsLb::FallbackHelper::UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) {
if (parent_->shutting_down_) return;
@ -774,7 +760,7 @@ void XdsLb::FallbackHelper::RequestReresolution() {
}
void XdsLb::FallbackHelper::AddTraceEvent(TraceSeverity severity,
const char* message) {
StringView message) {
if (parent_->shutting_down_ ||
(!CalledByPendingFallback() && !CalledByCurrentFallback())) {
return;
@ -793,8 +779,7 @@ XdsLb::LbChannelState::LbChannelState(RefCountedPtr<XdsLb> xdslb_policy,
xdslb_policy_(std::move(xdslb_policy)) {
GRPC_CLOSURE_INIT(&on_connectivity_changed_, OnConnectivityChangedLocked,
this, grpc_combiner_scheduler(xdslb_policy_->combiner()));
channel_ = xdslb_policy_->channel_control_helper()->CreateChannel(
balancer_name, args);
channel_ = CreateXdsBalancerChannel(balancer_name, args);
GPR_ASSERT(channel_ != nullptr);
eds_calld_.reset(New<RetryableLbCall<EdsCallState>>(
Ref(DEBUG_LOCATION, "LbChannelState+eds")));
@ -1672,7 +1657,7 @@ grpc_channel_args* BuildBalancerChannelArgs(const grpc_channel_args* args) {
// factory will re-add this arg with the right value.
GRPC_ARG_SERVER_URI,
// The LB channel should use the authority indicated by the target
// authority table (see \a grpc_lb_policy_xds_modify_lb_channel_args),
// authority table (see \a ModifyXdsBalancerChannelArgs),
// as opposed to the authority from the parent channel.
GRPC_ARG_DEFAULT_AUTHORITY,
// Just as for \a GRPC_ARG_DEFAULT_AUTHORITY, the LB channel should be
@ -1703,7 +1688,7 @@ grpc_channel_args* BuildBalancerChannelArgs(const grpc_channel_args* args) {
args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add.data(),
args_to_add.size());
// Make any necessary modifications for security.
return grpc_lb_policy_xds_modify_lb_channel_args(new_args);
return ModifyXdsBalancerChannelArgs(new_args);
}
//
@ -2440,15 +2425,6 @@ XdsLb::LocalityMap::LocalityEntry::Helper::CreateSubchannel(
return entry_->parent_->channel_control_helper()->CreateSubchannel(args);
}
grpc_channel* XdsLb::LocalityMap::LocalityEntry::Helper::CreateChannel(
const char* target, const grpc_channel_args& args) {
if (entry_->parent_->shutting_down_ ||
(!CalledByPendingChild() && !CalledByCurrentChild())) {
return nullptr;
}
return entry_->parent_->channel_control_helper()->CreateChannel(target, args);
}
void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState(
grpc_connectivity_state state, UniquePtr<SubchannelPicker> picker) {
if (entry_->parent_->shutting_down_) return;
@ -2510,7 +2486,7 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::RequestReresolution() {
}
void XdsLb::LocalityMap::LocalityEntry::Helper::AddTraceEvent(
TraceSeverity severity, const char* message) {
TraceSeverity severity, StringView message) {
if (entry_->parent_->shutting_down_ ||
(!CalledByPendingChild() && !CalledByCurrentChild())) {
return;

@ -18,9 +18,19 @@
#include <grpc/support/port_platform.h>
#include <grpc/grpc.h>
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h"
grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args(
grpc_channel_args* args) {
namespace grpc_core {
grpc_channel_args* ModifyXdsBalancerChannelArgs(grpc_channel_args* args) {
return args;
}
grpc_channel* CreateXdsBalancerChannel(const char* target_uri,
const grpc_channel_args& args) {
return grpc_insecure_channel_create(target_uri, &args, nullptr);
}
} // namespace grpc_core

@ -23,14 +23,20 @@
#include <grpc/impl/codegen/grpc_types.h>
namespace grpc_core {
/// Makes any necessary modifications to \a args for use in the xds
/// balancer channel.
///
/// Takes ownership of \a args.
///
/// Caller takes ownership of the returned args.
grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args(
grpc_channel_args* args);
grpc_channel_args* ModifyXdsBalancerChannelArgs(grpc_channel_args* args);
grpc_channel* CreateXdsBalancerChannel(const char* target_uri,
const grpc_channel_args& args);
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CHANNEL_H \
*/

@ -20,9 +20,11 @@
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h"
#include <string.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include <string.h>
#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/ext/filters/client_channel/server_address.h"
@ -33,29 +35,48 @@
#include "src/core/lib/security/transport/target_authority_table.h"
#include "src/core/lib/slice/slice_internal.h"
grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args(
grpc_channel_args* args) {
const char* args_to_remove[1];
size_t num_args_to_remove = 0;
grpc_arg args_to_add[2];
size_t num_args_to_add = 0;
namespace grpc_core {
grpc_channel_args* ModifyXdsBalancerChannelArgs(grpc_channel_args* args) {
InlinedVector<const char*, 1> args_to_remove;
InlinedVector<grpc_arg, 2> args_to_add;
// Substitute the channel credentials with a version without call
// credentials: the load balancer is not necessarily trusted to handle
// bearer token credentials.
grpc_channel_credentials* channel_credentials =
grpc_channel_credentials_find_in_args(args);
grpc_core::RefCountedPtr<grpc_channel_credentials> creds_sans_call_creds;
RefCountedPtr<grpc_channel_credentials> creds_sans_call_creds;
if (channel_credentials != nullptr) {
creds_sans_call_creds =
channel_credentials->duplicate_without_call_credentials();
GPR_ASSERT(creds_sans_call_creds != nullptr);
args_to_remove[num_args_to_remove++] = GRPC_ARG_CHANNEL_CREDENTIALS;
args_to_add[num_args_to_add++] =
grpc_channel_credentials_to_arg(creds_sans_call_creds.get());
args_to_remove.emplace_back(GRPC_ARG_CHANNEL_CREDENTIALS);
args_to_add.emplace_back(
grpc_channel_credentials_to_arg(creds_sans_call_creds.get()));
}
grpc_channel_args* result = grpc_channel_args_copy_and_add_and_remove(
args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add);
args, args_to_remove.data(), args_to_remove.size(), args_to_add.data(),
args_to_add.size());
// Clean up.
grpc_channel_args_destroy(args);
return result;
}
grpc_channel* CreateXdsBalancerChannel(const char* target_uri,
const grpc_channel_args& args) {
grpc_channel_credentials* creds =
grpc_channel_credentials_find_in_args(&args);
if (creds == nullptr) {
// Build with security but parent channel is insecure.
return grpc_insecure_channel_create(target_uri, &args, nullptr);
}
const char* arg_to_remove = GRPC_ARG_CHANNEL_CREDENTIALS;
grpc_channel_args* new_args =
grpc_channel_args_copy_and_remove(&args, &arg_to_remove, 1);
grpc_channel* channel =
grpc_secure_channel_create(creds, target_uri, new_args, nullptr);
grpc_channel_args_destroy(new_args);
return channel;
}
} // namespace grpc_core

@ -143,7 +143,15 @@ XdsClientStats::Snapshot XdsClientStats::GetSnapshotAndReset() {
}
{
MutexLock lock(&dropped_requests_mu_);
#if GRPC_USE_CPP_STD_LIB
// This is a workaround for the case where some compilers cannot build
// move-assignment of map with non-copyable but movable key.
// https://stackoverflow.com/questions/36475497
std::swap(snapshot.dropped_requests, dropped_requests_);
dropped_requests_.clear();
#else
snapshot.dropped_requests = std::move(dropped_requests_);
#endif
}
return snapshot;
}

@ -315,7 +315,15 @@ grpc_slice XdsLrsRequestCreateAndEncode(const char* server_name) {
namespace {
void LocalityStatsPopulate(envoy_api_v2_endpoint_UpstreamLocalityStats* output,
#if GRPC_USE_CPP_STD_LIB
// TODO(veblush): Clean up this
// This is to address the difference between
// std::map and Map. #else block will be gone
// once using stdlib is enabled by default.
Pair<const RefCountedPtr<XdsLocalityName>,
#else
Pair<RefCountedPtr<XdsLocalityName>,
#endif
XdsClientStats::LocalityStats::Snapshot>& input,
upb_arena* arena) {
// Set sub_zone.

@ -113,13 +113,6 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
return parent_->channel_control_helper()->CreateSubchannel(args);
}
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args& args) override {
if (parent_->resolver_ == nullptr) return nullptr; // Shutting down.
if (!CalledByCurrentChild() && !CalledByPendingChild()) return nullptr;
return parent_->channel_control_helper()->CreateChannel(target, args);
}
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override {
if (parent_->resolver_ == nullptr) return; // Shutting down.
@ -160,7 +153,7 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
}
}
void AddTraceEvent(TraceSeverity severity, const char* message) override {}
void AddTraceEvent(TraceSeverity severity, StringView message) override {}
void set_child(LoadBalancingPolicy* child) { child_ = child; }
@ -435,7 +428,7 @@ void ResolvingLoadBalancingPolicy::ConcatenateAndAddChannelTraceLocked(
size_t len = 0;
UniquePtr<char> message(gpr_strvec_flatten(&v, &len));
channel_control_helper()->AddTraceEvent(ChannelControlHelper::TRACE_INFO,
message.get());
StringView(message.get()));
gpr_strvec_destroy(&v);
}
}

@ -22,6 +22,7 @@
#include <grpc/support/port_platform.h>
#include "opencensus/stats/stats.h"
#include "opencensus/tags/tag_key.h"
#include "src/cpp/server/load_reporter/constants.h"
@ -80,33 +81,33 @@ inline ::opencensus::stats::MeasureDouble MeasureOtherCallMetric() {
// Tags.
inline ::opencensus::stats::TagKey TagKeyToken() {
static const ::opencensus::stats::TagKey token =
opencensus::stats::TagKey::Register(kTagKeyToken);
inline ::opencensus::tags::TagKey TagKeyToken() {
static const ::opencensus::tags::TagKey token =
opencensus::tags::TagKey::Register(kTagKeyToken);
return token;
}
inline ::opencensus::stats::TagKey TagKeyHost() {
static const ::opencensus::stats::TagKey token =
opencensus::stats::TagKey::Register(kTagKeyHost);
inline ::opencensus::tags::TagKey TagKeyHost() {
static const ::opencensus::tags::TagKey token =
opencensus::tags::TagKey::Register(kTagKeyHost);
return token;
}
inline ::opencensus::stats::TagKey TagKeyUserId() {
static const ::opencensus::stats::TagKey token =
opencensus::stats::TagKey::Register(kTagKeyUserId);
inline ::opencensus::tags::TagKey TagKeyUserId() {
static const ::opencensus::tags::TagKey token =
opencensus::tags::TagKey::Register(kTagKeyUserId);
return token;
}
inline ::opencensus::stats::TagKey TagKeyStatus() {
static const ::opencensus::stats::TagKey token =
opencensus::stats::TagKey::Register(kTagKeyStatus);
inline ::opencensus::tags::TagKey TagKeyStatus() {
static const ::opencensus::tags::TagKey token =
opencensus::tags::TagKey::Register(kTagKeyStatus);
return token;
}
inline ::opencensus::stats::TagKey TagKeyMetricName() {
static const ::opencensus::stats::TagKey token =
opencensus::stats::TagKey::Register(kTagKeyMetricName);
inline ::opencensus::tags::TagKey TagKeyMetricName() {
static const ::opencensus::tags::TagKey token =
opencensus::tags::TagKey::Register(kTagKeyMetricName);
return token;
}

@ -46,27 +46,30 @@ class Chttp2InsecureClientChannelFactory : public ClientChannelFactory {
grpc_channel_args_destroy(new_args);
return s;
}
};
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args* args) override {
if (target == nullptr) {
gpr_log(GPR_ERROR, "cannot create channel with NULL target name");
return nullptr;
}
// Add channel arg containing the server URI.
UniquePtr<char> canonical_target =
ResolverRegistry::AddDefaultPrefixIfNeeded(target);
grpc_arg arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_ARG_SERVER_URI), canonical_target.get());
const char* to_remove[] = {GRPC_ARG_SERVER_URI};
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1);
grpc_channel* channel =
grpc_channel_create(target, new_args, GRPC_CLIENT_CHANNEL, nullptr);
grpc_channel_args_destroy(new_args);
return channel;
namespace {
grpc_channel* CreateChannel(const char* target, const grpc_channel_args* args) {
if (target == nullptr) {
gpr_log(GPR_ERROR, "cannot create channel with NULL target name");
return nullptr;
}
};
// Add channel arg containing the server URI.
UniquePtr<char> canonical_target =
ResolverRegistry::AddDefaultPrefixIfNeeded(target);
grpc_arg arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_ARG_SERVER_URI), canonical_target.get());
const char* to_remove[] = {GRPC_ARG_SERVER_URI};
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1);
grpc_channel* channel =
grpc_channel_create(target, new_args, GRPC_CLIENT_CHANNEL, nullptr);
grpc_channel_args_destroy(new_args);
return channel;
}
} // namespace
} // namespace grpc_core
@ -98,7 +101,7 @@ grpc_channel* grpc_insecure_channel_create(const char* target,
grpc_arg arg = grpc_core::ClientChannelFactory::CreateChannelArg(g_factory);
grpc_channel_args* new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
// Create channel.
grpc_channel* channel = g_factory->CreateChannel(target, new_args);
grpc_channel* channel = grpc_core::CreateChannel(target, new_args);
// Clean up.
grpc_channel_args_destroy(new_args);
return channel != nullptr ? channel

@ -58,26 +58,6 @@ class Chttp2SecureClientChannelFactory : public ClientChannelFactory {
return s;
}
grpc_channel* CreateChannel(const char* target,
const grpc_channel_args* args) override {
if (target == nullptr) {
gpr_log(GPR_ERROR, "cannot create channel with NULL target name");
return nullptr;
}
// Add channel arg containing the server URI.
UniquePtr<char> canonical_target =
ResolverRegistry::AddDefaultPrefixIfNeeded(target);
grpc_arg arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_ARG_SERVER_URI), canonical_target.get());
const char* to_remove[] = {GRPC_ARG_SERVER_URI};
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1);
grpc_channel* channel =
grpc_channel_create(target, new_args, GRPC_CLIENT_CHANNEL, nullptr);
grpc_channel_args_destroy(new_args);
return channel;
}
private:
static grpc_channel_args* GetSecureNamingChannelArgs(
const grpc_channel_args* args) {
@ -170,6 +150,29 @@ class Chttp2SecureClientChannelFactory : public ClientChannelFactory {
}
};
namespace {
grpc_channel* CreateChannel(const char* target, const grpc_channel_args* args) {
if (target == nullptr) {
gpr_log(GPR_ERROR, "cannot create channel with NULL target name");
return nullptr;
}
// Add channel arg containing the server URI.
UniquePtr<char> canonical_target =
ResolverRegistry::AddDefaultPrefixIfNeeded(target);
grpc_arg arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_ARG_SERVER_URI), canonical_target.get());
const char* to_remove[] = {GRPC_ARG_SERVER_URI};
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1);
grpc_channel* channel =
grpc_channel_create(target, new_args, GRPC_CLIENT_CHANNEL, nullptr);
grpc_channel_args_destroy(new_args);
return channel;
}
} // namespace
} // namespace grpc_core
namespace {
@ -209,7 +212,7 @@ grpc_channel* grpc_secure_channel_create(grpc_channel_credentials* creds,
args, args_to_add, GPR_ARRAY_SIZE(args_to_add));
new_args = creds->update_arguments(new_args);
// Create channel.
channel = g_factory->CreateChannel(target, new_args);
channel = grpc_core::CreateChannel(target, new_args);
// Clean up.
grpc_channel_args_destroy(new_args);
}

@ -2465,6 +2465,13 @@ static void cancel_stream_cb(void* user_data, uint32_t key, void* stream) {
}
static void end_all_the_calls(grpc_chttp2_transport* t, grpc_error* error) {
intptr_t http2_error;
// If there is no explicit grpc or HTTP/2 error, set to UNAVAILABLE on server.
if (!t->is_client && !grpc_error_has_clear_grpc_status(error) &&
!grpc_error_get_int(error, GRPC_ERROR_INT_HTTP2_ERROR, &http2_error)) {
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAVAILABLE);
}
cancel_stream_cb_args args = {error, t};
grpc_chttp2_stream_map_for_each(&t->stream_map, cancel_stream_cb, &args);
GRPC_ERROR_UNREF(error);

@ -189,7 +189,7 @@ grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
/* See if the string is in the static table */
for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
grpc_mdelem ent = grpc_static_mdelem_manifested[i];
grpc_mdelem ent = grpc_static_mdelem_manifested()[i];
if (!grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDKEY(ent))) continue;
r.index = i + 1u;
r.has_value = grpc_slice_eq(GRPC_MDVALUE(md), GRPC_MDVALUE(ent));

@ -104,7 +104,7 @@ inline grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl* tbl,
reading the core static metadata table here; at that point we'd need our
own singleton static metadata in the correct order. */
return index <= GRPC_CHTTP2_LAST_STATIC_ENTRY
? grpc_static_mdelem_manifested[index - 1]
? grpc_static_mdelem_manifested()[index - 1]
: grpc_chttp2_hptbl_lookup_dynamic_index(tbl, index);
}
/* add a table entry to the index */
@ -120,7 +120,7 @@ size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
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;
grpc_static_mdelem_table();
if (index < GRPC_CHTTP2_LAST_STATIC_ENTRY) {
return index + 1; // Hpack static metadata element indices start at 1
}

@ -40,9 +40,7 @@
#include <time.h>
#include <unistd.h>
// Not naming it as gettid() to avoid duplicate declarations when complied with
// GCC 9.1.
static long local_gettid(void) { return syscall(__NR_gettid); }
static long sys_gettid(void) { return syscall(__NR_gettid); }
void gpr_log(const char* file, int line, gpr_log_severity severity,
const char* format, ...) {
@ -72,7 +70,7 @@ void gpr_default_log(gpr_log_func_args* args) {
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
struct tm tm;
static __thread long tid = 0;
if (tid == 0) tid = local_gettid();
if (tid == 0) tid = sys_gettid();
timer = static_cast<time_t>(now.tv_sec);
final_slash = strrchr(args->file, '/');

@ -31,7 +31,7 @@
#include <string.h>
#include <time.h>
static intptr_t gettid(void) { return (intptr_t)pthread_self(); }
static intptr_t sys_gettid(void) { return (intptr_t)pthread_self(); }
void gpr_log(const char* file, int line, gpr_log_severity severity,
const char* format, ...) {
@ -86,7 +86,7 @@ void gpr_default_log(gpr_log_func_args* args) {
char* prefix;
gpr_asprintf(&prefix, "%s%s.%09d %7" PRIdPTR " %s:%d]",
gpr_log_severity_string(args->severity), time_buffer,
(int)(now.tv_nsec), gettid(), display_file, args->line);
(int)(now.tv_nsec), sys_gettid(), display_file, args->line);
fprintf(stderr, "%-70s %s\n", prefix, args->message);
gpr_free(prefix);

@ -19,6 +19,14 @@
#ifndef GRPC_CORE_LIB_GPRPP_ABSTRACT_H
#define GRPC_CORE_LIB_GPRPP_ABSTRACT_H
#if GRPC_USE_CPP_STD_LIB
#define GRPC_ABSTRACT_BASE_CLASS
#define GRPC_ABSTRACT = 0
#else
// This is needed to support abstract base classes in the c core. Since gRPC
// doesn't have a c++ runtime, it will hit a linker error on delete unless
// we define a virtual operator delete. See this blog for more info:
@ -34,4 +42,6 @@
GPR_ASSERT(false); \
}
#endif // GRPC_USE_CPP_STD_LIB
#endif /* GRPC_CORE_LIB_GPRPP_ABSTRACT_H */

@ -27,12 +27,17 @@
#include <functional>
#include <iterator>
#if GRPC_USE_CPP_STD_LIB
#include <map>
#endif
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/pair.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
namespace grpc_core {
struct StringLess {
bool operator()(const char* a, const char* b) const {
return strcmp(a, b) < 0;
@ -50,6 +55,13 @@ struct RefCountedPtrLess {
}
};
#if GRPC_USE_CPP_STD_LIB
template <class Key, class T, class Compare = std::less<Key>>
using Map = std::map<Key, T, Compare>;
#else // GRPC_USE_CPP_STD_LIB
namespace testing {
class MapTest;
}
@ -537,5 +549,9 @@ int Map<Key, T, Compare>::CompareKeys(const key_type& lhs,
}
return left_comparison ? -1 : 1;
}
#endif // GRPC_USE_CPP_STD_LIB
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_GPRPP_MAP_H */

@ -1077,7 +1077,7 @@ static void end_worker(grpc_pollset* pollset, grpc_pollset_worker* worker,
}
#ifndef NDEBUG
static long gettid(void) { return syscall(__NR_gettid); }
static long sys_gettid(void) { return syscall(__NR_gettid); }
#endif
/* pollset->mu lock must be held by the caller before calling this.
@ -1097,7 +1097,7 @@ static grpc_error* pollset_work(grpc_pollset* pollset,
#define WORKER_PTR (&worker)
#endif
#ifndef NDEBUG
WORKER_PTR->originator = gettid();
WORKER_PTR->originator = sys_gettid();
#endif
if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
gpr_log(GPR_INFO,

@ -392,7 +392,7 @@ static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
socket->endpoint = nullptr;
socket->listener = nullptr;
socket->connector = nullptr;
grpc_custom_socket_vtable->init(socket, family);
error = grpc_custom_socket_vtable->init(socket, family);
if (error == GRPC_ERROR_NONE) {
error = add_socket_to_server(s, socket, addr, port_index, &sp);

@ -110,11 +110,17 @@ struct grpc_channel_credentials
create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_args** new_args) {
grpc_channel_args** new_args)
#if GRPC_USE_CPP_STD_LIB
= 0;
#else
{
// Tell clang-tidy that call_creds cannot be passed as const-ref.
call_creds.reset();
GRPC_ABSTRACT;
gpr_log(GPR_ERROR, "Function marked GRPC_ABSTRACT was not implemented");
GPR_ASSERT(false);
}
#endif
// Creates a version of the channel credentials without any attached call
// credentials. This can be used in order to open a channel to a non-trusted

@ -138,11 +138,12 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice 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)];
const grpc_core::StaticMetadataSlice* static_slice_table =
grpc_static_slice_table();
if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT &&
grpc_slice_eq_static_interned(slice,
grpc_static_slice_table[ent.idx])) {
grpc_slice_eq_static_interned(slice, static_slice_table[ent.idx])) {
*returned_slice_is_different = true;
return grpc_static_slice_table[ent.idx];
return static_slice_table[ent.idx];
}
}
@ -168,10 +169,11 @@ static const grpc_core::StaticMetadataSlice* MatchStaticSlice(
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)];
const grpc_core::StaticMetadataSlice* static_slice_table =
grpc_static_slice_table();
if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT &&
grpc_static_slice_table[ent.idx].Equals(
std::forward<SliceArgs>(args)...)) {
return &grpc_static_slice_table[ent.idx];
static_slice_table[ent.idx].Equals(std::forward<SliceArgs>(args)...)) {
return &static_slice_table[ent.idx];
}
}
return nullptr;
@ -318,9 +320,11 @@ void grpc_slice_intern_init(void) {
static_metadata_hash[i].idx = GRPC_STATIC_MDSTR_COUNT;
}
max_static_metadata_hash_probe = 0;
const grpc_core::StaticMetadataSlice* static_slice_table =
grpc_static_slice_table();
for (size_t i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
grpc_static_metadata_hash_values[i] =
grpc_slice_default_hash_internal(grpc_static_slice_table[i]);
grpc_slice_default_hash_internal(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);
@ -336,7 +340,7 @@ 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();
grpc_static_mdelem_table()[i].HashInit();
}
}

@ -182,7 +182,7 @@ struct StaticSliceRefcount {
index(index) {}
grpc_slice_refcount base;
uint32_t index;
const uint32_t index;
};
extern grpc_slice_refcount kNoopRefcount;

@ -108,7 +108,7 @@ struct ManagedMemorySlice : public grpc_slice {
return !grpc_slice_differs_refcounted(other, *this);
}
bool Equals(const char* buf, const size_t len) const {
return data.refcounted.length == len &&
return data.refcounted.length == len && buf != nullptr &&
memcmp(buf, data.refcounted.bytes, len) == 0;
}
};
@ -153,10 +153,14 @@ struct ExternallyManagedSlice : public UnmanagedMemorySlice {
};
struct StaticMetadataSlice : public ManagedMemorySlice {
StaticMetadataSlice(grpc_slice_refcount* ref, size_t length, uint8_t* bytes) {
StaticMetadataSlice(grpc_slice_refcount* ref, size_t length,
const uint8_t* bytes) {
refcount = ref;
data.refcounted.length = length;
data.refcounted.bytes = bytes;
// NB: grpc_slice may or may not point to a static slice, but we are
// definitely pointing to static data here. Since we are not changing
// the underlying C-type, we need a const_cast here.
data.refcounted.bytes = const_cast<uint8_t*>(bytes);
}
};

@ -134,6 +134,7 @@ void grpc_init(void) {
grpc_core::Fork::GlobalInit();
grpc_fork_handlers_auto_register();
grpc_stats_init();
grpc_init_static_metadata_ctx();
grpc_slice_intern_init();
grpc_mdctx_global_init();
grpc_channel_init_init();
@ -191,6 +192,8 @@ void grpc_shutdown_internal_locked(void) {
grpc_core::ApplicationCallbackExecCtx::GlobalShutdown();
g_shutting_down = false;
gpr_cv_broadcast(g_shutting_down_cv);
// Absolute last action will be to delete static metadata context.
grpc_destroy_static_metadata_ctx();
}
void grpc_shutdown_internal(void* ignored) {

@ -269,9 +269,9 @@ void grpc_mdctx_global_shutdown() {
#ifndef NDEBUG
static int is_mdelem_static(grpc_mdelem e) {
return reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(e)) >=
&grpc_static_mdelem_table[0] &&
&grpc_static_mdelem_table()[0] &&
reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(e)) <
&grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
&grpc_static_mdelem_table()[GRPC_STATIC_MDELEM_COUNT];
}
#endif
@ -569,7 +569,7 @@ void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*destroy_func)(void*)) {
grpc_static_mdelem_user_data
[reinterpret_cast<grpc_core::StaticMetadata*>(
GRPC_MDELEM_DATA(md)) -
grpc_static_mdelem_table]);
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);
@ -611,7 +611,7 @@ void* grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void*),
grpc_static_mdelem_user_data
[reinterpret_cast<grpc_core::StaticMetadata*>(
GRPC_MDELEM_DATA(md)) -
grpc_static_mdelem_table]);
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);

File diff suppressed because it is too large Load Diff

@ -37,240 +37,262 @@ static_assert(
std::is_trivially_destructible<grpc_core::StaticMetadataSlice>::value,
"grpc_core::StaticMetadataSlice must be trivially destructible.");
#define GRPC_STATIC_MDSTR_COUNT 108
extern const grpc_core::StaticMetadataSlice
grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
void grpc_init_static_metadata_ctx(void);
void grpc_destroy_static_metadata_ctx(void);
namespace grpc_core {
#ifndef NDEBUG
constexpr uint64_t kGrpcStaticMetadataInitCanary = 0xCAFEF00DC0FFEE11L;
uint64_t StaticMetadataInitCanary();
#endif
extern const StaticMetadataSlice* g_static_metadata_slice_table;
}
inline const grpc_core::StaticMetadataSlice* grpc_static_slice_table() {
GPR_DEBUG_ASSERT(grpc_core::StaticMetadataInitCanary() ==
grpc_core::kGrpcStaticMetadataInitCanary);
GPR_DEBUG_ASSERT(grpc_core::g_static_metadata_slice_table != nullptr);
return grpc_core::g_static_metadata_slice_table;
}
/* ":path" */
#define GRPC_MDSTR_PATH (grpc_static_slice_table[0])
#define GRPC_MDSTR_PATH (grpc_static_slice_table()[0])
/* ":method" */
#define GRPC_MDSTR_METHOD (grpc_static_slice_table[1])
#define GRPC_MDSTR_METHOD (grpc_static_slice_table()[1])
/* ":status" */
#define GRPC_MDSTR_STATUS (grpc_static_slice_table[2])
#define GRPC_MDSTR_STATUS (grpc_static_slice_table()[2])
/* ":authority" */
#define GRPC_MDSTR_AUTHORITY (grpc_static_slice_table[3])
#define GRPC_MDSTR_AUTHORITY (grpc_static_slice_table()[3])
/* ":scheme" */
#define GRPC_MDSTR_SCHEME (grpc_static_slice_table[4])
#define GRPC_MDSTR_SCHEME (grpc_static_slice_table()[4])
/* "te" */
#define GRPC_MDSTR_TE (grpc_static_slice_table[5])
#define GRPC_MDSTR_TE (grpc_static_slice_table()[5])
/* "grpc-message" */
#define GRPC_MDSTR_GRPC_MESSAGE (grpc_static_slice_table[6])
#define GRPC_MDSTR_GRPC_MESSAGE (grpc_static_slice_table()[6])
/* "grpc-status" */
#define GRPC_MDSTR_GRPC_STATUS (grpc_static_slice_table[7])
#define GRPC_MDSTR_GRPC_STATUS (grpc_static_slice_table()[7])
/* "grpc-payload-bin" */
#define GRPC_MDSTR_GRPC_PAYLOAD_BIN (grpc_static_slice_table[8])
#define GRPC_MDSTR_GRPC_PAYLOAD_BIN (grpc_static_slice_table()[8])
/* "grpc-encoding" */
#define GRPC_MDSTR_GRPC_ENCODING (grpc_static_slice_table[9])
#define GRPC_MDSTR_GRPC_ENCODING (grpc_static_slice_table()[9])
/* "grpc-accept-encoding" */
#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (grpc_static_slice_table[10])
#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (grpc_static_slice_table()[10])
/* "grpc-server-stats-bin" */
#define GRPC_MDSTR_GRPC_SERVER_STATS_BIN (grpc_static_slice_table[11])
#define GRPC_MDSTR_GRPC_SERVER_STATS_BIN (grpc_static_slice_table()[11])
/* "grpc-tags-bin" */
#define GRPC_MDSTR_GRPC_TAGS_BIN (grpc_static_slice_table[12])
#define GRPC_MDSTR_GRPC_TAGS_BIN (grpc_static_slice_table()[12])
/* "grpc-trace-bin" */
#define GRPC_MDSTR_GRPC_TRACE_BIN (grpc_static_slice_table[13])
#define GRPC_MDSTR_GRPC_TRACE_BIN (grpc_static_slice_table()[13])
/* "content-type" */
#define GRPC_MDSTR_CONTENT_TYPE (grpc_static_slice_table[14])
#define GRPC_MDSTR_CONTENT_TYPE (grpc_static_slice_table()[14])
/* "content-encoding" */
#define GRPC_MDSTR_CONTENT_ENCODING (grpc_static_slice_table[15])
#define GRPC_MDSTR_CONTENT_ENCODING (grpc_static_slice_table()[15])
/* "accept-encoding" */
#define GRPC_MDSTR_ACCEPT_ENCODING (grpc_static_slice_table[16])
#define GRPC_MDSTR_ACCEPT_ENCODING (grpc_static_slice_table()[16])
/* "grpc-internal-encoding-request" */
#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (grpc_static_slice_table[17])
#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST \
(grpc_static_slice_table()[17])
/* "grpc-internal-stream-encoding-request" */
#define GRPC_MDSTR_GRPC_INTERNAL_STREAM_ENCODING_REQUEST \
(grpc_static_slice_table[18])
(grpc_static_slice_table()[18])
/* "user-agent" */
#define GRPC_MDSTR_USER_AGENT (grpc_static_slice_table[19])
#define GRPC_MDSTR_USER_AGENT (grpc_static_slice_table()[19])
/* "host" */
#define GRPC_MDSTR_HOST (grpc_static_slice_table[20])
#define GRPC_MDSTR_HOST (grpc_static_slice_table()[20])
/* "grpc-previous-rpc-attempts" */
#define GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS (grpc_static_slice_table[21])
#define GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS (grpc_static_slice_table()[21])
/* "grpc-retry-pushback-ms" */
#define GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS (grpc_static_slice_table[22])
#define GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS (grpc_static_slice_table()[22])
/* "grpc-timeout" */
#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[23])
#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table()[23])
/* "1" */
#define GRPC_MDSTR_1 (grpc_static_slice_table[24])
#define GRPC_MDSTR_1 (grpc_static_slice_table()[24])
/* "2" */
#define GRPC_MDSTR_2 (grpc_static_slice_table[25])
#define GRPC_MDSTR_2 (grpc_static_slice_table()[25])
/* "3" */
#define GRPC_MDSTR_3 (grpc_static_slice_table[26])
#define GRPC_MDSTR_3 (grpc_static_slice_table()[26])
/* "4" */
#define GRPC_MDSTR_4 (grpc_static_slice_table[27])
#define GRPC_MDSTR_4 (grpc_static_slice_table()[27])
/* "" */
#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[28])
#define GRPC_MDSTR_EMPTY (grpc_static_slice_table()[28])
/* "grpc.wait_for_ready" */
#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[29])
#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table()[29])
/* "grpc.timeout" */
#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[30])
#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table()[30])
/* "grpc.max_request_message_bytes" */
#define GRPC_MDSTR_GRPC_DOT_MAX_REQUEST_MESSAGE_BYTES \
(grpc_static_slice_table[31])
(grpc_static_slice_table()[31])
/* "grpc.max_response_message_bytes" */
#define GRPC_MDSTR_GRPC_DOT_MAX_RESPONSE_MESSAGE_BYTES \
(grpc_static_slice_table[32])
(grpc_static_slice_table()[32])
/* "/grpc.lb.v1.LoadBalancer/BalanceLoad" */
#define GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD \
(grpc_static_slice_table[33])
(grpc_static_slice_table()[33])
/* "/envoy.service.load_stats.v2.LoadReportingService/StreamLoadStats" */
#define GRPC_MDSTR_SLASH_ENVOY_DOT_SERVICE_DOT_LOAD_STATS_DOT_V2_DOT_LOADREPORTINGSERVICE_SLASH_STREAMLOADSTATS \
(grpc_static_slice_table[34])
(grpc_static_slice_table()[34])
/* "/envoy.api.v2.EndpointDiscoveryService/StreamEndpoints" */
#define GRPC_MDSTR_SLASH_ENVOY_DOT_API_DOT_V2_DOT_ENDPOINTDISCOVERYSERVICE_SLASH_STREAMENDPOINTS \
(grpc_static_slice_table[35])
(grpc_static_slice_table()[35])
/* "/grpc.health.v1.Health/Watch" */
#define GRPC_MDSTR_SLASH_GRPC_DOT_HEALTH_DOT_V1_DOT_HEALTH_SLASH_WATCH \
(grpc_static_slice_table[36])
(grpc_static_slice_table()[36])
/* "/envoy.service.discovery.v2.AggregatedDiscoveryService/StreamAggregatedResources"
*/
#define GRPC_MDSTR_SLASH_ENVOY_DOT_SERVICE_DOT_DISCOVERY_DOT_V2_DOT_AGGREGATEDDISCOVERYSERVICE_SLASH_STREAMAGGREGATEDRESOURCES \
(grpc_static_slice_table[37])
(grpc_static_slice_table()[37])
/* "deflate" */
#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[38])
#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table()[38])
/* "gzip" */
#define GRPC_MDSTR_GZIP (grpc_static_slice_table[39])
#define GRPC_MDSTR_GZIP (grpc_static_slice_table()[39])
/* "stream/gzip" */
#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[40])
#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table()[40])
/* "GET" */
#define GRPC_MDSTR_GET (grpc_static_slice_table[41])
#define GRPC_MDSTR_GET (grpc_static_slice_table()[41])
/* "POST" */
#define GRPC_MDSTR_POST (grpc_static_slice_table[42])
#define GRPC_MDSTR_POST (grpc_static_slice_table()[42])
/* "/" */
#define GRPC_MDSTR_SLASH (grpc_static_slice_table[43])
#define GRPC_MDSTR_SLASH (grpc_static_slice_table()[43])
/* "/index.html" */
#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[44])
#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table()[44])
/* "http" */
#define GRPC_MDSTR_HTTP (grpc_static_slice_table[45])
#define GRPC_MDSTR_HTTP (grpc_static_slice_table()[45])
/* "https" */
#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[46])
#define GRPC_MDSTR_HTTPS (grpc_static_slice_table()[46])
/* "200" */
#define GRPC_MDSTR_200 (grpc_static_slice_table[47])
#define GRPC_MDSTR_200 (grpc_static_slice_table()[47])
/* "204" */
#define GRPC_MDSTR_204 (grpc_static_slice_table[48])
#define GRPC_MDSTR_204 (grpc_static_slice_table()[48])
/* "206" */
#define GRPC_MDSTR_206 (grpc_static_slice_table[49])
#define GRPC_MDSTR_206 (grpc_static_slice_table()[49])
/* "304" */
#define GRPC_MDSTR_304 (grpc_static_slice_table[50])
#define GRPC_MDSTR_304 (grpc_static_slice_table()[50])
/* "400" */
#define GRPC_MDSTR_400 (grpc_static_slice_table[51])
#define GRPC_MDSTR_400 (grpc_static_slice_table()[51])
/* "404" */
#define GRPC_MDSTR_404 (grpc_static_slice_table[52])
#define GRPC_MDSTR_404 (grpc_static_slice_table()[52])
/* "500" */
#define GRPC_MDSTR_500 (grpc_static_slice_table[53])
#define GRPC_MDSTR_500 (grpc_static_slice_table()[53])
/* "accept-charset" */
#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[54])
#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table()[54])
/* "gzip, deflate" */
#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[55])
#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table()[55])
/* "accept-language" */
#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[56])
#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table()[56])
/* "accept-ranges" */
#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[57])
#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table()[57])
/* "accept" */
#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[58])
#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table()[58])
/* "access-control-allow-origin" */
#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[59])
#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table()[59])
/* "age" */
#define GRPC_MDSTR_AGE (grpc_static_slice_table[60])
#define GRPC_MDSTR_AGE (grpc_static_slice_table()[60])
/* "allow" */
#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[61])
#define GRPC_MDSTR_ALLOW (grpc_static_slice_table()[61])
/* "authorization" */
#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[62])
#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table()[62])
/* "cache-control" */
#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[63])
#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table()[63])
/* "content-disposition" */
#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[64])
#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table()[64])
/* "content-language" */
#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[65])
#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table()[65])
/* "content-length" */
#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[66])
#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table()[66])
/* "content-location" */
#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[67])
#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table()[67])
/* "content-range" */
#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[68])
#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table()[68])
/* "cookie" */
#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[69])
#define GRPC_MDSTR_COOKIE (grpc_static_slice_table()[69])
/* "date" */
#define GRPC_MDSTR_DATE (grpc_static_slice_table[70])
#define GRPC_MDSTR_DATE (grpc_static_slice_table()[70])
/* "etag" */
#define GRPC_MDSTR_ETAG (grpc_static_slice_table[71])
#define GRPC_MDSTR_ETAG (grpc_static_slice_table()[71])
/* "expect" */
#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[72])
#define GRPC_MDSTR_EXPECT (grpc_static_slice_table()[72])
/* "expires" */
#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[73])
#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table()[73])
/* "from" */
#define GRPC_MDSTR_FROM (grpc_static_slice_table[74])
#define GRPC_MDSTR_FROM (grpc_static_slice_table()[74])
/* "if-match" */
#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[75])
#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table()[75])
/* "if-modified-since" */
#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[76])
#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table()[76])
/* "if-none-match" */
#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[77])
#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table()[77])
/* "if-range" */
#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[78])
#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table()[78])
/* "if-unmodified-since" */
#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[79])
#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table()[79])
/* "last-modified" */
#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[80])
#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table()[80])
/* "link" */
#define GRPC_MDSTR_LINK (grpc_static_slice_table[81])
#define GRPC_MDSTR_LINK (grpc_static_slice_table()[81])
/* "location" */
#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[82])
#define GRPC_MDSTR_LOCATION (grpc_static_slice_table()[82])
/* "max-forwards" */
#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[83])
#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table()[83])
/* "proxy-authenticate" */
#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[84])
#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table()[84])
/* "proxy-authorization" */
#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[85])
#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table()[85])
/* "range" */
#define GRPC_MDSTR_RANGE (grpc_static_slice_table[86])
#define GRPC_MDSTR_RANGE (grpc_static_slice_table()[86])
/* "referer" */
#define GRPC_MDSTR_REFERER (grpc_static_slice_table[87])
#define GRPC_MDSTR_REFERER (grpc_static_slice_table()[87])
/* "refresh" */
#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[88])
#define GRPC_MDSTR_REFRESH (grpc_static_slice_table()[88])
/* "retry-after" */
#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[89])
#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table()[89])
/* "server" */
#define GRPC_MDSTR_SERVER (grpc_static_slice_table[90])
#define GRPC_MDSTR_SERVER (grpc_static_slice_table()[90])
/* "set-cookie" */
#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[91])
#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table()[91])
/* "strict-transport-security" */
#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[92])
#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table()[92])
/* "transfer-encoding" */
#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[93])
#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table()[93])
/* "vary" */
#define GRPC_MDSTR_VARY (grpc_static_slice_table[94])
#define GRPC_MDSTR_VARY (grpc_static_slice_table()[94])
/* "via" */
#define GRPC_MDSTR_VIA (grpc_static_slice_table[95])
#define GRPC_MDSTR_VIA (grpc_static_slice_table()[95])
/* "www-authenticate" */
#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[96])
#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table()[96])
/* "0" */
#define GRPC_MDSTR_0 (grpc_static_slice_table[97])
#define GRPC_MDSTR_0 (grpc_static_slice_table()[97])
/* "identity" */
#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[98])
#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table()[98])
/* "trailers" */
#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[99])
#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table()[99])
/* "application/grpc" */
#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[100])
#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table()[100])
/* "grpc" */
#define GRPC_MDSTR_GRPC (grpc_static_slice_table[101])
#define GRPC_MDSTR_GRPC (grpc_static_slice_table()[101])
/* "PUT" */
#define GRPC_MDSTR_PUT (grpc_static_slice_table[102])
#define GRPC_MDSTR_PUT (grpc_static_slice_table()[102])
/* "lb-cost-bin" */
#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[103])
#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table()[103])
/* "identity,deflate" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[104])
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table()[104])
/* "identity,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[105])
#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table()[105])
/* "deflate,gzip" */
#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[106])
#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table()[106])
/* "identity,deflate,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
(grpc_static_slice_table[107])
(grpc_static_slice_table()[107])
namespace grpc_core {
struct StaticSliceRefcount;
extern StaticSliceRefcount* g_static_metadata_slice_refcounts;
} // namespace grpc_core
inline grpc_core::StaticSliceRefcount* grpc_static_metadata_refcounts() {
GPR_DEBUG_ASSERT(grpc_core::StaticMetadataInitCanary() ==
grpc_core::kGrpcStaticMetadataInitCanary);
GPR_DEBUG_ASSERT(grpc_core::g_static_metadata_slice_refcounts != nullptr);
return grpc_core::g_static_metadata_slice_refcounts;
}
extern grpc_core::StaticSliceRefcount
grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT];
#define GRPC_IS_STATIC_METADATA_STRING(slice) \
((slice).refcount != NULL && \
(slice).refcount->GetType() == grpc_slice_refcount::Type::STATIC)
@ -280,196 +302,216 @@ extern grpc_core::StaticSliceRefcount
->index)
#define GRPC_STATIC_MDELEM_COUNT 85
extern grpc_core::StaticMetadata
grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
namespace grpc_core {
extern StaticMetadata* g_static_mdelem_table;
extern grpc_mdelem* g_static_mdelem_manifested;
} // namespace grpc_core
inline grpc_core::StaticMetadata* grpc_static_mdelem_table() {
GPR_DEBUG_ASSERT(grpc_core::StaticMetadataInitCanary() ==
grpc_core::kGrpcStaticMetadataInitCanary);
GPR_DEBUG_ASSERT(grpc_core::g_static_mdelem_table != nullptr);
return grpc_core::g_static_mdelem_table;
}
inline grpc_mdelem* grpc_static_mdelem_manifested() {
GPR_DEBUG_ASSERT(grpc_core::StaticMetadataInitCanary() ==
grpc_core::kGrpcStaticMetadataInitCanary);
GPR_DEBUG_ASSERT(grpc_core::g_static_mdelem_manifested != nullptr);
return grpc_core::g_static_mdelem_manifested;
}
extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
extern grpc_mdelem grpc_static_mdelem_manifested[GRPC_STATIC_MDELEM_COUNT];
/* ":authority": "" */
#define GRPC_MDELEM_AUTHORITY_EMPTY (grpc_static_mdelem_manifested[0])
#define GRPC_MDELEM_AUTHORITY_EMPTY (grpc_static_mdelem_manifested()[0])
/* ":method": "GET" */
#define GRPC_MDELEM_METHOD_GET (grpc_static_mdelem_manifested[1])
#define GRPC_MDELEM_METHOD_GET (grpc_static_mdelem_manifested()[1])
/* ":method": "POST" */
#define GRPC_MDELEM_METHOD_POST (grpc_static_mdelem_manifested[2])
#define GRPC_MDELEM_METHOD_POST (grpc_static_mdelem_manifested()[2])
/* ":path": "/" */
#define GRPC_MDELEM_PATH_SLASH (grpc_static_mdelem_manifested[3])
#define GRPC_MDELEM_PATH_SLASH (grpc_static_mdelem_manifested()[3])
/* ":path": "/index.html" */
#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (grpc_static_mdelem_manifested[4])
#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \
(grpc_static_mdelem_manifested()[4])
/* ":scheme": "http" */
#define GRPC_MDELEM_SCHEME_HTTP (grpc_static_mdelem_manifested[5])
#define GRPC_MDELEM_SCHEME_HTTP (grpc_static_mdelem_manifested()[5])
/* ":scheme": "https" */
#define GRPC_MDELEM_SCHEME_HTTPS (grpc_static_mdelem_manifested[6])
#define GRPC_MDELEM_SCHEME_HTTPS (grpc_static_mdelem_manifested()[6])
/* ":status": "200" */
#define GRPC_MDELEM_STATUS_200 (grpc_static_mdelem_manifested[7])
#define GRPC_MDELEM_STATUS_200 (grpc_static_mdelem_manifested()[7])
/* ":status": "204" */
#define GRPC_MDELEM_STATUS_204 (grpc_static_mdelem_manifested[8])
#define GRPC_MDELEM_STATUS_204 (grpc_static_mdelem_manifested()[8])
/* ":status": "206" */
#define GRPC_MDELEM_STATUS_206 (grpc_static_mdelem_manifested[9])
#define GRPC_MDELEM_STATUS_206 (grpc_static_mdelem_manifested()[9])
/* ":status": "304" */
#define GRPC_MDELEM_STATUS_304 (grpc_static_mdelem_manifested[10])
#define GRPC_MDELEM_STATUS_304 (grpc_static_mdelem_manifested()[10])
/* ":status": "400" */
#define GRPC_MDELEM_STATUS_400 (grpc_static_mdelem_manifested[11])
#define GRPC_MDELEM_STATUS_400 (grpc_static_mdelem_manifested()[11])
/* ":status": "404" */
#define GRPC_MDELEM_STATUS_404 (grpc_static_mdelem_manifested[12])
#define GRPC_MDELEM_STATUS_404 (grpc_static_mdelem_manifested()[12])
/* ":status": "500" */
#define GRPC_MDELEM_STATUS_500 (grpc_static_mdelem_manifested[13])
#define GRPC_MDELEM_STATUS_500 (grpc_static_mdelem_manifested()[13])
/* "accept-charset": "" */
#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (grpc_static_mdelem_manifested[14])
#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (grpc_static_mdelem_manifested()[14])
/* "accept-encoding": "gzip, deflate" */
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
(grpc_static_mdelem_manifested[15])
(grpc_static_mdelem_manifested()[15])
/* "accept-language": "" */
#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (grpc_static_mdelem_manifested[16])
#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (grpc_static_mdelem_manifested()[16])
/* "accept-ranges": "" */
#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (grpc_static_mdelem_manifested[17])
#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (grpc_static_mdelem_manifested()[17])
/* "accept": "" */
#define GRPC_MDELEM_ACCEPT_EMPTY (grpc_static_mdelem_manifested[18])
#define GRPC_MDELEM_ACCEPT_EMPTY (grpc_static_mdelem_manifested()[18])
/* "access-control-allow-origin": "" */
#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
(grpc_static_mdelem_manifested[19])
(grpc_static_mdelem_manifested()[19])
/* "age": "" */
#define GRPC_MDELEM_AGE_EMPTY (grpc_static_mdelem_manifested[20])
#define GRPC_MDELEM_AGE_EMPTY (grpc_static_mdelem_manifested()[20])
/* "allow": "" */
#define GRPC_MDELEM_ALLOW_EMPTY (grpc_static_mdelem_manifested[21])
#define GRPC_MDELEM_ALLOW_EMPTY (grpc_static_mdelem_manifested()[21])
/* "authorization": "" */
#define GRPC_MDELEM_AUTHORIZATION_EMPTY (grpc_static_mdelem_manifested[22])
#define GRPC_MDELEM_AUTHORIZATION_EMPTY (grpc_static_mdelem_manifested()[22])
/* "cache-control": "" */
#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (grpc_static_mdelem_manifested[23])
#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (grpc_static_mdelem_manifested()[23])
/* "content-disposition": "" */
#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \
(grpc_static_mdelem_manifested[24])
(grpc_static_mdelem_manifested()[24])
/* "content-encoding": "" */
#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (grpc_static_mdelem_manifested[25])
#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (grpc_static_mdelem_manifested()[25])
/* "content-language": "" */
#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (grpc_static_mdelem_manifested[26])
#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (grpc_static_mdelem_manifested()[26])
/* "content-length": "" */
#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (grpc_static_mdelem_manifested[27])
#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (grpc_static_mdelem_manifested()[27])
/* "content-location": "" */
#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (grpc_static_mdelem_manifested[28])
#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (grpc_static_mdelem_manifested()[28])
/* "content-range": "" */
#define GRPC_MDELEM_CONTENT_RANGE_EMPTY (grpc_static_mdelem_manifested[29])
#define GRPC_MDELEM_CONTENT_RANGE_EMPTY (grpc_static_mdelem_manifested()[29])
/* "content-type": "" */
#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (grpc_static_mdelem_manifested[30])
#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (grpc_static_mdelem_manifested()[30])
/* "cookie": "" */
#define GRPC_MDELEM_COOKIE_EMPTY (grpc_static_mdelem_manifested[31])
#define GRPC_MDELEM_COOKIE_EMPTY (grpc_static_mdelem_manifested()[31])
/* "date": "" */
#define GRPC_MDELEM_DATE_EMPTY (grpc_static_mdelem_manifested[32])
#define GRPC_MDELEM_DATE_EMPTY (grpc_static_mdelem_manifested()[32])
/* "etag": "" */
#define GRPC_MDELEM_ETAG_EMPTY (grpc_static_mdelem_manifested[33])
#define GRPC_MDELEM_ETAG_EMPTY (grpc_static_mdelem_manifested()[33])
/* "expect": "" */
#define GRPC_MDELEM_EXPECT_EMPTY (grpc_static_mdelem_manifested[34])
#define GRPC_MDELEM_EXPECT_EMPTY (grpc_static_mdelem_manifested()[34])
/* "expires": "" */
#define GRPC_MDELEM_EXPIRES_EMPTY (grpc_static_mdelem_manifested[35])
#define GRPC_MDELEM_EXPIRES_EMPTY (grpc_static_mdelem_manifested()[35])
/* "from": "" */
#define GRPC_MDELEM_FROM_EMPTY (grpc_static_mdelem_manifested[36])
#define GRPC_MDELEM_FROM_EMPTY (grpc_static_mdelem_manifested()[36])
/* "host": "" */
#define GRPC_MDELEM_HOST_EMPTY (grpc_static_mdelem_manifested[37])
#define GRPC_MDELEM_HOST_EMPTY (grpc_static_mdelem_manifested()[37])
/* "if-match": "" */
#define GRPC_MDELEM_IF_MATCH_EMPTY (grpc_static_mdelem_manifested[38])
#define GRPC_MDELEM_IF_MATCH_EMPTY (grpc_static_mdelem_manifested()[38])
/* "if-modified-since": "" */
#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY (grpc_static_mdelem_manifested[39])
#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \
(grpc_static_mdelem_manifested()[39])
/* "if-none-match": "" */
#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (grpc_static_mdelem_manifested[40])
#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (grpc_static_mdelem_manifested()[40])
/* "if-range": "" */
#define GRPC_MDELEM_IF_RANGE_EMPTY (grpc_static_mdelem_manifested[41])
#define GRPC_MDELEM_IF_RANGE_EMPTY (grpc_static_mdelem_manifested()[41])
/* "if-unmodified-since": "" */
#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \
(grpc_static_mdelem_manifested[42])
(grpc_static_mdelem_manifested()[42])
/* "last-modified": "" */
#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (grpc_static_mdelem_manifested[43])
#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (grpc_static_mdelem_manifested()[43])
/* "link": "" */
#define GRPC_MDELEM_LINK_EMPTY (grpc_static_mdelem_manifested[44])
#define GRPC_MDELEM_LINK_EMPTY (grpc_static_mdelem_manifested()[44])
/* "location": "" */
#define GRPC_MDELEM_LOCATION_EMPTY (grpc_static_mdelem_manifested[45])
#define GRPC_MDELEM_LOCATION_EMPTY (grpc_static_mdelem_manifested()[45])
/* "max-forwards": "" */
#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (grpc_static_mdelem_manifested[46])
#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (grpc_static_mdelem_manifested()[46])
/* "proxy-authenticate": "" */
#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (grpc_static_mdelem_manifested[47])
#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \
(grpc_static_mdelem_manifested()[47])
/* "proxy-authorization": "" */
#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \
(grpc_static_mdelem_manifested[48])
(grpc_static_mdelem_manifested()[48])
/* "range": "" */
#define GRPC_MDELEM_RANGE_EMPTY (grpc_static_mdelem_manifested[49])
#define GRPC_MDELEM_RANGE_EMPTY (grpc_static_mdelem_manifested()[49])
/* "referer": "" */
#define GRPC_MDELEM_REFERER_EMPTY (grpc_static_mdelem_manifested[50])
#define GRPC_MDELEM_REFERER_EMPTY (grpc_static_mdelem_manifested()[50])
/* "refresh": "" */
#define GRPC_MDELEM_REFRESH_EMPTY (grpc_static_mdelem_manifested[51])
#define GRPC_MDELEM_REFRESH_EMPTY (grpc_static_mdelem_manifested()[51])
/* "retry-after": "" */
#define GRPC_MDELEM_RETRY_AFTER_EMPTY (grpc_static_mdelem_manifested[52])
#define GRPC_MDELEM_RETRY_AFTER_EMPTY (grpc_static_mdelem_manifested()[52])
/* "server": "" */
#define GRPC_MDELEM_SERVER_EMPTY (grpc_static_mdelem_manifested[53])
#define GRPC_MDELEM_SERVER_EMPTY (grpc_static_mdelem_manifested()[53])
/* "set-cookie": "" */
#define GRPC_MDELEM_SET_COOKIE_EMPTY (grpc_static_mdelem_manifested[54])
#define GRPC_MDELEM_SET_COOKIE_EMPTY (grpc_static_mdelem_manifested()[54])
/* "strict-transport-security": "" */
#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
(grpc_static_mdelem_manifested[55])
(grpc_static_mdelem_manifested()[55])
/* "transfer-encoding": "" */
#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (grpc_static_mdelem_manifested[56])
#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \
(grpc_static_mdelem_manifested()[56])
/* "user-agent": "" */
#define GRPC_MDELEM_USER_AGENT_EMPTY (grpc_static_mdelem_manifested[57])
#define GRPC_MDELEM_USER_AGENT_EMPTY (grpc_static_mdelem_manifested()[57])
/* "vary": "" */
#define GRPC_MDELEM_VARY_EMPTY (grpc_static_mdelem_manifested[58])
#define GRPC_MDELEM_VARY_EMPTY (grpc_static_mdelem_manifested()[58])
/* "via": "" */
#define GRPC_MDELEM_VIA_EMPTY (grpc_static_mdelem_manifested[59])
#define GRPC_MDELEM_VIA_EMPTY (grpc_static_mdelem_manifested()[59])
/* "www-authenticate": "" */
#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (grpc_static_mdelem_manifested[60])
#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (grpc_static_mdelem_manifested()[60])
/* "grpc-status": "0" */
#define GRPC_MDELEM_GRPC_STATUS_0 (grpc_static_mdelem_manifested[61])
#define GRPC_MDELEM_GRPC_STATUS_0 (grpc_static_mdelem_manifested()[61])
/* "grpc-status": "1" */
#define GRPC_MDELEM_GRPC_STATUS_1 (grpc_static_mdelem_manifested[62])
#define GRPC_MDELEM_GRPC_STATUS_1 (grpc_static_mdelem_manifested()[62])
/* "grpc-status": "2" */
#define GRPC_MDELEM_GRPC_STATUS_2 (grpc_static_mdelem_manifested[63])
#define GRPC_MDELEM_GRPC_STATUS_2 (grpc_static_mdelem_manifested()[63])
/* "grpc-encoding": "identity" */
#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY (grpc_static_mdelem_manifested[64])
#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY (grpc_static_mdelem_manifested()[64])
/* "grpc-encoding": "gzip" */
#define GRPC_MDELEM_GRPC_ENCODING_GZIP (grpc_static_mdelem_manifested[65])
#define GRPC_MDELEM_GRPC_ENCODING_GZIP (grpc_static_mdelem_manifested()[65])
/* "grpc-encoding": "deflate" */
#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE (grpc_static_mdelem_manifested[66])
#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE (grpc_static_mdelem_manifested()[66])
/* "te": "trailers" */
#define GRPC_MDELEM_TE_TRAILERS (grpc_static_mdelem_manifested[67])
#define GRPC_MDELEM_TE_TRAILERS (grpc_static_mdelem_manifested()[67])
/* "content-type": "application/grpc" */
#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
(grpc_static_mdelem_manifested[68])
(grpc_static_mdelem_manifested()[68])
/* ":scheme": "grpc" */
#define GRPC_MDELEM_SCHEME_GRPC (grpc_static_mdelem_manifested[69])
#define GRPC_MDELEM_SCHEME_GRPC (grpc_static_mdelem_manifested()[69])
/* ":method": "PUT" */
#define GRPC_MDELEM_METHOD_PUT (grpc_static_mdelem_manifested[70])
#define GRPC_MDELEM_METHOD_PUT (grpc_static_mdelem_manifested()[70])
/* "accept-encoding": "" */
#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (grpc_static_mdelem_manifested[71])
#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (grpc_static_mdelem_manifested()[71])
/* "content-encoding": "identity" */
#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \
(grpc_static_mdelem_manifested[72])
(grpc_static_mdelem_manifested()[72])
/* "content-encoding": "gzip" */
#define GRPC_MDELEM_CONTENT_ENCODING_GZIP (grpc_static_mdelem_manifested[73])
#define GRPC_MDELEM_CONTENT_ENCODING_GZIP (grpc_static_mdelem_manifested()[73])
/* "lb-cost-bin": "" */
#define GRPC_MDELEM_LB_COST_BIN_EMPTY (grpc_static_mdelem_manifested[74])
#define GRPC_MDELEM_LB_COST_BIN_EMPTY (grpc_static_mdelem_manifested()[74])
/* "grpc-accept-encoding": "identity" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
(grpc_static_mdelem_manifested[75])
(grpc_static_mdelem_manifested()[75])
/* "grpc-accept-encoding": "deflate" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \
(grpc_static_mdelem_manifested[76])
(grpc_static_mdelem_manifested()[76])
/* "grpc-accept-encoding": "identity,deflate" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
(grpc_static_mdelem_manifested[77])
(grpc_static_mdelem_manifested()[77])
/* "grpc-accept-encoding": "gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \
(grpc_static_mdelem_manifested[78])
(grpc_static_mdelem_manifested()[78])
/* "grpc-accept-encoding": "identity,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
(grpc_static_mdelem_manifested[79])
(grpc_static_mdelem_manifested()[79])
/* "grpc-accept-encoding": "deflate,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
(grpc_static_mdelem_manifested[80])
(grpc_static_mdelem_manifested()[80])
/* "grpc-accept-encoding": "identity,deflate,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
(grpc_static_mdelem_manifested[81])
(grpc_static_mdelem_manifested()[81])
/* "accept-encoding": "identity" */
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY (grpc_static_mdelem_manifested[82])
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY \
(grpc_static_mdelem_manifested()[82])
/* "accept-encoding": "gzip" */
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP (grpc_static_mdelem_manifested[83])
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP (grpc_static_mdelem_manifested()[83])
/* "accept-encoding": "identity,gzip" */
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
(grpc_static_mdelem_manifested[84])
(grpc_static_mdelem_manifested()[84])
grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b);
typedef enum {
@ -539,15 +581,15 @@ 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)]] \
.data(), \
GRPC_MDELEM_STORAGE_STATIC))
#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_MAKE_MDELEM(&grpc_static_mdelem_table() \
[grpc_static_accept_stream_encoding_metadata[(algs)]] \
.data(), \
GRPC_MDELEM_STORAGE_STATIC))

@ -38,7 +38,7 @@ std::shared_ptr<grpc::Channel> CreateCustomChannelImpl(
const std::shared_ptr<grpc::ChannelCredentials>& creds,
const grpc::ChannelArguments& args) {
grpc::GrpcLibraryCodegen
init_lib; // We need to call init in case of a bad creds.
init_lib; // We need to call init in case of bad creds.
return creds ? creds->CreateChannelImpl(target, args)
: grpc::CreateChannelInternal(
"",
@ -69,6 +69,8 @@ std::shared_ptr<grpc::Channel> CreateCustomChannelWithInterceptors(
std::vector<
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
grpc::GrpcLibraryCodegen
init_lib; // We need to call init in case of bad creds.
return creds ? creds->CreateChannelWithInterceptors(
target, args, std::move(interceptor_creators))
: grpc::CreateChannelInternal(

@ -407,7 +407,7 @@ int MetadataCredentialsPluginWrapper::GetMetadata(
*num_creds_md = 0;
*status = GRPC_STATUS_OK;
*error_details = nullptr;
return true;
return 1;
}
if (w->plugin_->IsBlocking()) {
// The internals of context may be destroyed if GetMetadata is cancelled.

@ -22,6 +22,7 @@
#include <grpcpp/server_context.h>
#include "opencensus/tags/tag_key.h"
#include "opencensus/trace/span.h"
#include "src/cpp/ext/filters/census/channel_filter.h"
#include "src/cpp/ext/filters/census/client_filter.h"
@ -33,27 +34,27 @@ namespace grpc {
// These measure definitions should be kept in sync across opencensus
// implementations--see
// https://github.com/census-instrumentation/opencensus-java/blob/master/contrib/grpc_metrics/src/main/java/io/opencensus/contrib/grpc/metrics/RpcMeasureConstants.java.
::opencensus::stats::TagKey ClientMethodTagKey() {
::opencensus::tags::TagKey ClientMethodTagKey() {
static const auto method_tag_key =
::opencensus::stats::TagKey::Register("grpc_client_method");
::opencensus::tags::TagKey::Register("grpc_client_method");
return method_tag_key;
}
::opencensus::stats::TagKey ClientStatusTagKey() {
::opencensus::tags::TagKey ClientStatusTagKey() {
static const auto status_tag_key =
::opencensus::stats::TagKey::Register("grpc_client_status");
::opencensus::tags::TagKey::Register("grpc_client_status");
return status_tag_key;
}
::opencensus::stats::TagKey ServerMethodTagKey() {
::opencensus::tags::TagKey ServerMethodTagKey() {
static const auto method_tag_key =
::opencensus::stats::TagKey::Register("grpc_server_method");
::opencensus::tags::TagKey::Register("grpc_server_method");
return method_tag_key;
}
::opencensus::stats::TagKey ServerStatusTagKey() {
::opencensus::tags::TagKey ServerStatusTagKey() {
static const auto status_tag_key =
::opencensus::stats::TagKey::Register("grpc_server_status");
::opencensus::tags::TagKey::Register("grpc_server_status");
return status_tag_key;
}

@ -24,6 +24,7 @@
#include "absl/strings/string_view.h"
#include "include/grpcpp/opencensus.h"
#include "opencensus/stats/stats.h"
#include "opencensus/tags/tag_key.h"
namespace grpc_impl {
class ServerContext;
@ -32,10 +33,10 @@ class ServerContext;
namespace grpc {
// The tag keys set when recording RPC stats.
::opencensus::stats::TagKey ClientMethodTagKey();
::opencensus::stats::TagKey ClientStatusTagKey();
::opencensus::stats::TagKey ServerMethodTagKey();
::opencensus::stats::TagKey ServerStatusTagKey();
::opencensus::tags::TagKey ClientMethodTagKey();
::opencensus::tags::TagKey ClientStatusTagKey();
::opencensus::tags::TagKey ServerMethodTagKey();
::opencensus::tags::TagKey ServerStatusTagKey();
// Names of measures used by the plugin--users can create views on these
// measures but should not record data for them.

@ -29,6 +29,7 @@
#include "src/cpp/server/load_reporter/load_reporter.h"
#include "opencensus/stats/internal/set_aggregation_window.h"
#include "opencensus/tags/tag_key.h"
namespace grpc {
namespace load_reporter {
@ -38,12 +39,12 @@ CpuStatsProvider::CpuStatsSample CpuStatsProviderDefaultImpl::GetCpuStats() {
}
CensusViewProvider::CensusViewProvider()
: tag_key_token_(::opencensus::stats::TagKey::Register(kTagKeyToken)),
tag_key_host_(::opencensus::stats::TagKey::Register(kTagKeyHost)),
tag_key_user_id_(::opencensus::stats::TagKey::Register(kTagKeyUserId)),
tag_key_status_(::opencensus::stats::TagKey::Register(kTagKeyStatus)),
: tag_key_token_(::opencensus::tags::TagKey::Register(kTagKeyToken)),
tag_key_host_(::opencensus::tags::TagKey::Register(kTagKeyHost)),
tag_key_user_id_(::opencensus::tags::TagKey::Register(kTagKeyUserId)),
tag_key_status_(::opencensus::tags::TagKey::Register(kTagKeyStatus)),
tag_key_metric_name_(
::opencensus::stats::TagKey::Register(kTagKeyMetricName)) {
::opencensus::tags::TagKey::Register(kTagKeyMetricName)) {
// One view related to starting a call.
auto vd_start_count =
::opencensus::stats::ViewDescriptor()

@ -34,6 +34,7 @@
#include "src/proto/grpc/lb/v1/load_reporter.grpc.pb.h"
#include "opencensus/stats/stats.h"
#include "opencensus/tags/tag_key.h"
namespace grpc {
namespace load_reporter {
@ -75,11 +76,11 @@ class CensusViewProvider {
private:
ViewDescriptorMap view_descriptor_map_;
// Tag keys.
::opencensus::stats::TagKey tag_key_token_;
::opencensus::stats::TagKey tag_key_host_;
::opencensus::stats::TagKey tag_key_user_id_;
::opencensus::stats::TagKey tag_key_status_;
::opencensus::stats::TagKey tag_key_metric_name_;
::opencensus::tags::TagKey tag_key_token_;
::opencensus::tags::TagKey tag_key_host_;
::opencensus::tags::TagKey tag_key_user_id_;
::opencensus::tags::TagKey tag_key_status_;
::opencensus::tags::TagKey tag_key_metric_name_;
};
// The default implementation fetches the real stats from Census.

@ -23,7 +23,7 @@ Unity and provide feedback!
How to test gRPC in a Unity project
1. Create a Unity project that targets .NET 4.x (Edit -> Project Settings -> Editor -> Scripting Runtime Version). gRPC uses APIs that are only available in .NET4.5+ so this is a requirement.
1. Create a Unity project that targets .NET 4.x Equivalent (Edit -> Project Settings -> Player -> Configuration -> Scripting Runtime Version). gRPC uses APIs that are only available in .NET4.5+ so this is a requirement.
2. Download the latest development build of `grpc_unity_package.VERSION.zip` from
[daily builds](https://packages.grpc.io/)

@ -18,30 +18,24 @@ licenses(["notice"]) # Apache v2
package(default_visibility = ["//visibility:public"])
load("//bazel:grpc_build_system.bzl", "grpc_objc_library", "grpc_generate_objc_one_off_targets")
load("//bazel:grpc_build_system.bzl", "grpc_objc_library", "grpc_objc_use_cronet_config")
exports_files(["LICENSE"])
grpc_generate_objc_one_off_targets()
grpc_objc_library(
name = "rx_library_headers",
hdrs = glob([
"RxLibrary/*.h",
]),
includes = ["."],
)
grpc_objc_use_cronet_config()
grpc_objc_library(
name = "rx_library",
srcs = glob([
"RxLibrary/*.m",
"RxLibrary/transformations/*.m",
]),
hdrs = glob([
"RxLibrary/*.h",
"RxLibrary/transformations/*.h",
]),
includes = ["."],
deps = [
":rx_library_headers",
":rx_library_private",
],
deps = [":rx_library_private"],
)
grpc_objc_library(
@ -56,195 +50,84 @@ grpc_objc_library(
)
grpc_objc_library(
name = "grpc_objc_interface_legacy",
hdrs = [
"GRPCClient/GRPCCall+ChannelArg.h",
"GRPCClient/GRPCCall+ChannelCredentials.h",
"GRPCClient/GRPCCall+Cronet.h",
"GRPCClient/GRPCCall+OAuth2.h",
"GRPCClient/GRPCCall+Tests.h",
"GRPCClient/GRPCCallLegacy.h",
"GRPCClient/GRPCTypes.h",
],
deps = [
"rx_library_headers",
],
)
grpc_objc_library(
name = "grpc_objc_interface",
hdrs = [
"GRPCClient/GRPCCall.h",
"GRPCClient/GRPCCall+Interceptor.h",
"GRPCClient/GRPCCallOptions.h",
"GRPCClient/GRPCInterceptor.h",
"GRPCClient/GRPCTransport.h",
"GRPCClient/GRPCDispatchable.h",
"GRPCClient/internal/GRPCCallOptions+Internal.h",
"GRPCClient/version.h",
],
srcs = [
"GRPCClient/GRPCCall.m",
"GRPCClient/GRPCCall+Interceptor.m",
"GRPCClient/GRPCCallOptions.m",
"GRPCClient/GRPCInterceptor.m",
"GRPCClient/GRPCTransport.m",
"GRPCClient/private/GRPCTransport+Private.m",
],
includes = ["."],
textual_hdrs = [
"GRPCClient/private/GRPCTransport+Private.h",
],
deps = [
":grpc_objc_interface_legacy",
],
)
grpc_objc_library(
name = "grpc_objc_client_core",
hdrs = [
"GRPCClient/GRPCCall+ChannelCredentials.h",
"GRPCClient/GRPCCall+Cronet.h",
"GRPCClient/GRPCCall+OAuth2.h",
"GRPCClient/GRPCCall+Tests.h",
"GRPCClient/GRPCCall+ChannelArg.h",
],
textual_hdrs = glob(["GRPCClient/private/GRPCCore/*.h"]),
srcs = [
"GRPCClient/GRPCCall+ChannelArg.m",
"GRPCClient/GRPCCall+ChannelCredentials.m",
"GRPCClient/GRPCCall+Cronet.m",
"GRPCClient/GRPCCall+OAuth2.m",
"GRPCClient/GRPCCall+Tests.m",
"GRPCClient/GRPCCallLegacy.m",
] + glob(["GRPCClient/private/GRPCCore/*.m"]),
data = [":gRPCCertificates"],
name = "grpc_objc_client",
srcs = glob(
[
"GRPCClient/*.m",
"GRPCClient/private/*.m",
],
exclude = ["GRPCClient/GRPCCall+GID.m"],
),
hdrs = glob(
[
"GRPCClient/*.h",
"GRPCClient/internal/*.h",
],
exclude = ["GRPCClient/GRPCCall+GID.h"],
),
data = ["//:gRPCCertificates"],
includes = ["."],
textual_hdrs = glob([
"GRPCClient/private/*.h",
]),
deps = [
":grpc_objc_interface",
":grpc_objc_interface_legacy",
":rx_library",
"//:grpc_objc",
],
)
alias(
name = "grpc_objc_client",
actual = "grpc_objc_client_core",
)
grpc_objc_library(
name = "proto_objc_rpc_legacy_header",
hdrs = [
"ProtoRPC/ProtoRPCLegacy.h",
],
includes = ["."],
)
grpc_objc_library(
name = "proto_objc_rpc_v2",
srcs = [
"ProtoRPC/ProtoMethod.m",
"ProtoRPC/ProtoRPC.m",
"ProtoRPC/ProtoService.m",
],
hdrs = [
"ProtoRPC/ProtoMethod.h",
"ProtoRPC/ProtoRPC.h",
"ProtoRPC/ProtoService.h",
],
includes = ["."],
defines = ["GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=0"],
deps = [
":grpc_objc_interface",
":proto_objc_rpc_legacy_header",
"@com_google_protobuf//:protobuf_objc",
],
)
grpc_objc_library(
name = "proto_objc_rpc",
srcs = [
"ProtoRPC/ProtoRPCLegacy.m",
"ProtoRPC/ProtoServiceLegacy.m",
],
hdrs = [
"ProtoRPC/ProtoMethod.h",
"ProtoRPC/ProtoRPCLegacy.h",
"ProtoRPC/ProtoService.h",
],
srcs = glob(
["ProtoRPC/*.m"],
),
hdrs = glob(
["ProtoRPC/*.h"],
),
# Different from Cocoapods, do not import as if @com_google_protobuf//:protobuf_objc is a framework,
# use the real paths of @com_google_protobuf//:protobuf_objc instead
defines = ["GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=0"],
deps = [
":grpc_objc_client",
":rx_library",
":proto_objc_rpc_v2",
":proto_objc_rpc_legacy_header",
":grpc_objc_client_core",
"@com_google_protobuf//:protobuf_objc",
],
)
load("@build_bazel_rules_apple//apple:resources.bzl", "apple_resource_bundle")
apple_resource_bundle(
# The choice of name is signicant here, since it determines the bundle name.
name = "gRPCCertificates",
resources = ["//:etc/roots.pem"],
)
# Internal target combining grpc_objc_client_core and proto_objc_rpc for testing
grpc_objc_library(
name = "grpc_objc_client_core_internal_testing",
hdrs = [
"GRPCClient/GRPCCall+ChannelCredentials.h",
"GRPCClient/GRPCCall+Cronet.h",
"GRPCClient/GRPCCall+OAuth2.h",
"GRPCClient/GRPCCall+Tests.h",
"GRPCClient/GRPCCall+ChannelArg.h",
"GRPCClient/internal_testing/GRPCCall+InternalTests.h",
],
textual_hdrs = glob(["GRPCClient/private/GRPCCore/*.h"]),
srcs = [
"GRPCClient/GRPCCall+ChannelArg.m",
"GRPCClient/GRPCCall+ChannelCredentials.m",
"GRPCClient/GRPCCall+Cronet.m",
"GRPCClient/GRPCCall+OAuth2.m",
"GRPCClient/GRPCCall+Tests.m",
"GRPCClient/GRPCCallLegacy.m",
"GRPCClient/internal_testing/GRPCCall+InternalTests.m",
] + glob(["GRPCClient/private/GRPCCore/*.m"]),
data = [":gRPCCertificates"],
name = "grpc_objc_client_internal_testing",
srcs = glob(
[
"GRPCClient/*.m",
"GRPCClient/private/*.m",
"GRPCClient/internal_testing/*.m",
"ProtoRPC/*.m",
],
exclude = ["GRPCClient/GRPCCall+GID.m"],
),
hdrs = glob(
[
"GRPCClient/*.h",
"GRPCClient/internal/*.h",
"GRPCClient/internal_testing/*.h",
"ProtoRPC/*.h",
],
exclude = ["GRPCClient/GRPCCall+GID.h"],
),
includes = ["."],
data = ["//:gRPCCertificates"],
defines = [
"GRPC_TEST_OBJC=1",
"GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=0",
],
textual_hdrs = glob(
[
"GRPCClient/private/*.h",
],
),
deps = [
":grpc_objc_interface",
":grpc_objc_interface_legacy",
":rx_library",
"//:grpc_objc",
],
)
grpc_objc_library(
name = "proto_objc_rpc_internal_testing",
srcs = [
"ProtoRPC/ProtoRPCLegacy.m",
"ProtoRPC/ProtoServiceLegacy.m",
],
hdrs = [
"ProtoRPC/ProtoMethod.h",
"ProtoRPC/ProtoRPCLegacy.h",
"ProtoRPC/ProtoService.h",
],
deps = [
":rx_library",
":proto_objc_rpc_v2",
":proto_objc_rpc_legacy_header",
":grpc_objc_client_core_internal_testing",
"@com_google_protobuf//:protobuf_objc",
],
)
alias(
name = "grpc_objc_client_internal_testing",
actual = "proto_objc_rpc_internal_testing",
)

@ -15,7 +15,7 @@
* limitations under the License.
*
*/
#import "GRPCCallLegacy.h"
#import "GRPCCall.h"
#include <AvailabilityMacros.h>

@ -18,8 +18,8 @@
#import "GRPCCall+ChannelArg.h"
#import "private/GRPCCore/GRPCChannelPool.h"
#import "private/GRPCCore/GRPCHost.h"
#import "private/GRPCChannelPool.h"
#import "private/GRPCHost.h"
#import <grpc/impl/codegen/compression_types.h>

@ -16,7 +16,7 @@
*
*/
#import "GRPCCallLegacy.h"
#import "GRPCCall.h"
// Deprecated interface. Please use GRPCCallOptions instead.
@interface GRPCCall (ChannelCredentials)

@ -18,7 +18,7 @@
#import "GRPCCall+ChannelCredentials.h"
#import "private/GRPCCore/GRPCHost.h"
#import "private/GRPCHost.h"
@implementation GRPCCall (ChannelCredentials)

@ -15,16 +15,12 @@
* limitations under the License.
*
*/
#ifdef GRPC_COMPILE_WITH_CRONET
#import <Cronet/Cronet.h>
#import "GRPCCallLegacy.h"
#import "GRPCTypes.h"
#import "GRPCCall.h"
typedef struct stream_engine stream_engine;
// Transport id for Cronet transport
extern const GRPCTransportId gGRPCCoreCronetId;
// Deprecated class. Please use the gGRPCCoreCronetId with GRPCCallOptions.transport instead.
// Deprecated interface. Please use GRPCCallOptions instead.
@interface GRPCCall (Cronet)
+ (void)useCronetWithEngine:(stream_engine*)engine;
@ -32,3 +28,4 @@ extern const GRPCTransportId gGRPCCoreCronetId;
+ (BOOL)isUsingCronet;
@end
#endif

@ -18,8 +18,7 @@
#import "GRPCCall+Cronet.h"
const GRPCTransportId gGRPCCoreCronetId = "io.grpc.transport.core.cronet";
#ifdef GRPC_COMPILE_WITH_CRONET
static BOOL useCronet = NO;
static stream_engine *globalCronetEngine;
@ -39,3 +38,4 @@ static stream_engine *globalCronetEngine;
}
@end
#endif

@ -17,7 +17,7 @@
*/
#import "GRPCCall+OAuth2.h"
#import "GRPCCallLegacy.h"
#import "GRPCCall.h"
#import <Google/SignIn.h>

@ -16,9 +16,9 @@
*
*/
#import "GRPCCallLegacy.h"
#import "GRPCCall.h"
@protocol GRPCAuthorizationProtocol;
#import "GRPCCallOptions.h"
// Deprecated interface. Please use GRPCCallOptions instead.
@interface GRPCCall (OAuth2)

@ -16,7 +16,7 @@
*
*/
#import "GRPCCallLegacy.h"
#import "GRPCCall.h"
// Deprecated interface. Please use GRPCCallOptions instead.
@interface GRPCCall (Tests)

@ -18,7 +18,7 @@
#import "GRPCCall+Tests.h"
#import "private/GRPCCore/GRPCHost.h"
#import "private/GRPCHost.h"
#import "GRPCCallOptions.h"

@ -33,19 +33,134 @@
*/
#import <Foundation/Foundation.h>
#import <RxLibrary/GRXWriter.h>
#import "GRPCCallOptions.h"
#import "GRPCDispatchable.h"
#import "GRPCTypes.h"
#include <AvailabilityMacros.h>
// The legacy header is included for backwards compatibility. Some V1 API users are still using
// GRPCCall by importing GRPCCall.h header so we need this import.
#import "GRPCCallLegacy.h"
#include "GRPCCallOptions.h"
NS_ASSUME_NONNULL_BEGIN
#pragma mark gRPC errors
/** Domain of NSError objects produced by gRPC. */
extern NSString *const kGRPCErrorDomain;
/**
* gRPC error codes.
* Note that a few of these are never produced by the gRPC libraries, but are of general utility for
* server applications to produce.
*/
typedef NS_ENUM(NSUInteger, GRPCErrorCode) {
/** The operation was cancelled (typically by the caller). */
GRPCErrorCodeCancelled = 1,
/**
* Unknown error. Errors raised by APIs that do not return enough error information may be
* converted to this error.
*/
GRPCErrorCodeUnknown = 2,
/**
* The client specified an invalid argument. Note that this differs from FAILED_PRECONDITION.
* INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the
* server (e.g., a malformed file name).
*/
GRPCErrorCodeInvalidArgument = 3,
/**
* Deadline expired before operation could complete. For operations that change the state of the
* server, this error may be returned even if the operation has completed successfully. For
* example, a successful response from the server could have been delayed long enough for the
* deadline to expire.
*/
GRPCErrorCodeDeadlineExceeded = 4,
/** Some requested entity (e.g., file or directory) was not found. */
GRPCErrorCodeNotFound = 5,
/** Some entity that we attempted to create (e.g., file or directory) already exists. */
GRPCErrorCodeAlreadyExists = 6,
/**
* The caller does not have permission to execute the specified operation. PERMISSION_DENIED isn't
* used for rejections caused by exhausting some resource (RESOURCE_EXHAUSTED is used instead for
* those errors). PERMISSION_DENIED doesn't indicate a failure to identify the caller
* (UNAUTHENTICATED is used instead for those errors).
*/
GRPCErrorCodePermissionDenied = 7,
/**
* The request does not have valid authentication credentials for the operation (e.g. the caller's
* identity can't be verified).
*/
GRPCErrorCodeUnauthenticated = 16,
/** Some resource has been exhausted, perhaps a per-user quota. */
GRPCErrorCodeResourceExhausted = 8,
/**
* The RPC was rejected because the server is not in a state required for the procedure's
* execution. For example, a directory to be deleted may be non-empty, etc.
* The client should not retry until the server state has been explicitly fixed (e.g. by
* performing another RPC). The details depend on the service being called, and should be found in
* the NSError's userInfo.
*/
GRPCErrorCodeFailedPrecondition = 9,
/**
* The RPC was aborted, typically due to a concurrency issue like sequencer check failures,
* transaction aborts, etc. The client should retry at a higher-level (e.g., restarting a read-
* modify-write sequence).
*/
GRPCErrorCodeAborted = 10,
/**
* The RPC was attempted past the valid range. E.g., enumerating past the end of a list.
* Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state
* changes. For example, an RPC to get elements of a list will generate INVALID_ARGUMENT if asked
* to return the element at a negative index, but it will generate OUT_OF_RANGE if asked to return
* the element at an index past the current size of the list.
*/
GRPCErrorCodeOutOfRange = 11,
/** The procedure is not implemented or not supported/enabled in this server. */
GRPCErrorCodeUnimplemented = 12,
/**
* Internal error. Means some invariant expected by the server application or the gRPC library has
* been broken.
*/
GRPCErrorCodeInternal = 13,
/**
* The server is currently unavailable. This is most likely a transient condition and may be
* corrected by retrying with a backoff. Note that it is not always safe to retry
* non-idempotent operations.
*/
GRPCErrorCodeUnavailable = 14,
/** Unrecoverable data loss or corruption. */
GRPCErrorCodeDataLoss = 15,
};
/**
* Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by
* the server.
*/
extern NSString *const kGRPCHeadersKey;
extern NSString *const kGRPCTrailersKey;
/** An object can implement this protocol to receive responses from server from a call. */
@protocol GRPCResponseHandler<NSObject, GRPCDispatchable>
@protocol GRPCResponseHandler<NSObject>
@required
/**
* All the responses must be issued to a user-provided dispatch queue. This property specifies the
* dispatch queue to be used for issuing the notifications.
*/
@property(atomic, readonly) dispatch_queue_t dispatchQueue;
@optional
@ -187,3 +302,114 @@ NS_ASSUME_NONNULL_BEGIN
@end
NS_ASSUME_NONNULL_END
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnullability-completeness"
/**
* This interface is deprecated. Please use \a GRPCcall2.
*
* Represents a single gRPC remote call.
*/
@interface GRPCCall : GRXWriter
- (instancetype)init NS_UNAVAILABLE;
/**
* The container of the request headers of an RPC conforms to this protocol, which is a subset of
* NSMutableDictionary's interface. It will become a NSMutableDictionary later on.
* The keys of this container are the header names, which per the HTTP standard are case-
* insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and
* can only consist of ASCII characters.
* A header value is a NSString object (with only ASCII characters), unless the header name has the
* suffix "-bin", in which case the value has to be a NSData object.
*/
/**
* These HTTP headers will be passed to the server as part of this call. Each HTTP header is a
* name-value pair with string names and either string or binary values.
*
* The passed dictionary has to use NSString keys, corresponding to the header names. The value
* associated to each can be a NSString object or a NSData object. E.g.:
*
* call.requestHeaders = @{@"authorization": @"Bearer ..."};
*
* call.requestHeaders[@"my-header-bin"] = someData;
*
* After the call is started, trying to modify this property is an error.
*
* The property is initialized to an empty NSMutableDictionary.
*/
@property(atomic, readonly) NSMutableDictionary *requestHeaders;
/**
* This dictionary is populated with the HTTP headers received from the server. This happens before
* any response message is received from the server. It has the same structure as the request
* headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a
* NSData value; the others have a NSString value.
*
* The value of this property is nil until all response headers are received, and will change before
* any of -writeValue: or -writesFinishedWithError: are sent to the writeable.
*/
@property(atomic, readonly) NSDictionary *responseHeaders;
/**
* Same as responseHeaders, but populated with the HTTP trailers received from the server before the
* call finishes.
*
* The value of this property is nil until all response trailers are received, and will change
* before -writesFinishedWithError: is sent to the writeable.
*/
@property(atomic, readonly) NSDictionary *responseTrailers;
/**
* The request writer has to write NSData objects into the provided Writeable. The server will
* receive each of those separately and in order as distinct messages.
* A gRPC call might not complete until the request writer finishes. On the other hand, the request
* finishing doesn't necessarily make the call to finish, as the server might continue sending
* messages to the response side of the call indefinitely (depending on the semantics of the
* specific remote method called).
* To finish a call right away, invoke cancel.
* host parameter should not contain the scheme (http:// or https://), only the name or IP addr
* and the port number, for example @"localhost:5050".
*/
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
requestsWriter:(GRXWriter *)requestWriter;
/**
* Finishes the request side of this call, notifies the server that the RPC should be cancelled, and
* finishes the response side of the call with an error of code CANCELED.
*/
- (void)cancel;
/**
* The following methods are deprecated.
*/
+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path;
@property(atomic, copy, readwrite) NSString *serverName;
@property NSTimeInterval timeout;
- (void)setResponseDispatchQueue:(dispatch_queue_t)queue;
@end
#pragma mark Backwards compatibiity
/** This protocol is kept for backwards compatibility with existing code. */
DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.")
@protocol GRPCRequestHeaders<NSObject>
@property(nonatomic, readonly) NSUInteger count;
- (id)objectForKeyedSubscript:(id)key;
- (void)setObject:(id)obj forKeyedSubscript:(id)key;
- (void)removeAllObjects;
- (void)removeObjectForKey:(id)key;
@end
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
/** This is only needed for backwards-compatibility. */
@interface NSMutableDictionary (GRPCRequestHeaders)<GRPCRequestHeaders>
@end
#pragma clang diagnostic pop
#pragma clang diagnostic pop

@ -17,86 +17,56 @@
*/
#import "GRPCCall.h"
#import "GRPCCall+Interceptor.h"
#import "GRPCCall+OAuth2.h"
#import "GRPCCallOptions.h"
#import "GRPCInterceptor.h"
#import "private/GRPCTransport+Private.h"
#import <RxLibrary/GRXBufferedPipe.h>
#import <RxLibrary/GRXConcurrentWriteable.h>
#import <RxLibrary/GRXImmediateSingleWriter.h>
#import <RxLibrary/GRXWriter+Immediate.h>
#include <grpc/grpc.h>
#include <grpc/support/time.h>
#import "private/GRPCCall+V2API.h"
#import "private/GRPCCallInternal.h"
#import "private/GRPCChannelPool.h"
#import "private/GRPCCompletionQueue.h"
#import "private/GRPCHost.h"
#import "private/GRPCRequestHeaders.h"
#import "private/GRPCWrappedCall.h"
#import "private/NSData+GRPC.h"
#import "private/NSDictionary+GRPC.h"
#import "private/NSError+GRPC.h"
// At most 6 ops can be in an op batch for a client: SEND_INITIAL_METADATA,
// SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT, RECV_INITIAL_METADATA, RECV_MESSAGE,
// and RECV_STATUS_ON_CLIENT.
NSInteger kMaxClientBatch = 6;
NSString *const kGRPCHeadersKey = @"io.grpc.HeadersKey";
NSString *const kGRPCTrailersKey = @"io.grpc.TrailersKey";
static NSMutableDictionary *callFlags;
NSString *const kGRPCErrorDomain = @"io.grpc";
/**
* The response dispatcher creates its own serial dispatch queue and target the queue to the
* dispatch queue of a user provided response handler. It removes the requirement of having to use
* serial dispatch queue in the user provided response handler.
*/
@interface GRPCResponseDispatcher : NSObject<GRPCResponseHandler>
- (nullable instancetype)initWithResponseHandler:(id<GRPCResponseHandler>)responseHandler;
@end
static NSString *const kAuthorizationHeader = @"authorization";
static NSString *const kBearerPrefix = @"Bearer ";
@implementation GRPCResponseDispatcher {
id<GRPCResponseHandler> _responseHandler;
dispatch_queue_t _dispatchQueue;
}
const char *kCFStreamVarName = "grpc_cfstream";
- (instancetype)initWithResponseHandler:(id<GRPCResponseHandler>)responseHandler {
if ((self = [super init])) {
_responseHandler = responseHandler;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
if (@available(iOS 8.0, macOS 10.10, *)) {
_dispatchQueue = dispatch_queue_create(
NULL,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0));
} else {
#else
{
#endif
_dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
}
dispatch_set_target_queue(_dispatchQueue, _responseHandler.dispatchQueue);
}
@interface GRPCCall ()<GRXWriteable>
// Make them read-write.
@property(atomic, strong) NSDictionary *responseHeaders;
@property(atomic, strong) NSDictionary *responseTrailers;
return self;
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata {
if ([_responseHandler respondsToSelector:@selector(didReceiveInitialMetadata:)]) {
[_responseHandler didReceiveInitialMetadata:initialMetadata];
}
}
- (void)didReceiveData:(id)data {
// For backwards compatibility with didReceiveRawMessage, if the user provided a response handler
// that handles didReceiveRawMesssage, we issue to that method instead
if ([_responseHandler respondsToSelector:@selector(didReceiveRawMessage:)]) {
[_responseHandler didReceiveRawMessage:data];
} else if ([_responseHandler respondsToSelector:@selector(didReceiveData:)]) {
[_responseHandler didReceiveData:data];
}
}
- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata
error:(nullable NSError *)error {
if ([_responseHandler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
[_responseHandler didCloseWithTrailingMetadata:trailingMetadata error:error];
}
}
- (void)receiveNextMessages:(NSUInteger)numberOfMessages;
- (void)didWriteData {
if ([_responseHandler respondsToSelector:@selector(didWriteData)]) {
[_responseHandler didWriteData];
}
}
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
callSafety:(GRPCCallSafety)safety
requestsWriter:(GRXWriter *)requestsWriter
callOptions:(GRPCCallOptions *)callOptions
writeDone:(void (^)(void))writeDone;
@end
@ -170,39 +140,54 @@ NSString *const kGRPCErrorDomain = @"io.grpc";
}
_responseHandler = responseHandler;
GRPCResponseDispatcher *dispatcher =
[[GRPCResponseDispatcher alloc] initWithResponseHandler:_responseHandler];
NSMutableArray<id<GRPCInterceptorFactory>> *interceptorFactories;
if (_actualCallOptions.interceptorFactories != nil) {
interceptorFactories =
[NSMutableArray arrayWithArray:_actualCallOptions.interceptorFactories];
} else {
interceptorFactories = [NSMutableArray array];
}
// Initialize the interceptor chain
// First initialize the internal call
GRPCCall2Internal *internalCall = [[GRPCCall2Internal alloc] init];
id<GRPCInterceptorInterface> nextInterceptor = internalCall;
GRPCInterceptorManager *nextManager = nil;
// Then initialize the global interceptor, if applicable
id<GRPCInterceptorFactory> globalInterceptorFactory = [GRPCCall2 globalInterceptorFactory];
if (globalInterceptorFactory != nil) {
[interceptorFactories addObject:globalInterceptorFactory];
if (globalInterceptorFactory) {
GRPCInterceptorManager *manager =
[[GRPCInterceptorManager alloc] initWithNextInterceptor:nextInterceptor];
GRPCInterceptor *interceptor =
[globalInterceptorFactory createInterceptorWithManager:manager];
if (interceptor != nil) {
[internalCall setResponseHandler:interceptor];
nextInterceptor = interceptor;
nextManager = manager;
}
}
// continuously create interceptor until one is successfully created
while (_firstInterceptor == nil) {
if (interceptorFactories.count == 0) {
_firstInterceptor = [[GRPCTransportManager alloc] initWithTransportId:_callOptions.transport
previousInterceptor:dispatcher];
break;
// Finally initialize the interceptors in the chain
NSArray *interceptorFactories = _actualCallOptions.interceptorFactories;
for (int i = (int)interceptorFactories.count - 1; i >= 0; i--) {
GRPCInterceptorManager *manager =
[[GRPCInterceptorManager alloc] initWithNextInterceptor:nextInterceptor];
GRPCInterceptor *interceptor = [interceptorFactories[i] createInterceptorWithManager:manager];
NSAssert(interceptor != nil, @"Failed to create interceptor from factory: %@",
interceptorFactories[i]);
if (interceptor == nil) {
NSLog(@"Failed to create interceptor from factory: %@", interceptorFactories[i]);
continue;
}
if (nextManager == nil) {
[internalCall setResponseHandler:interceptor];
} else {
_firstInterceptor =
[[GRPCInterceptorManager alloc] initWithFactories:interceptorFactories
previousInterceptor:dispatcher
transportId:_callOptions.transport];
if (_firstInterceptor == nil) {
[interceptorFactories removeObjectAtIndex:0];
}
[nextManager setPreviousInterceptor:interceptor];
}
nextInterceptor = interceptor;
nextManager = manager;
}
NSAssert(_firstInterceptor != nil, @"Failed to create interceptor or transport.");
if (_firstInterceptor == nil) {
NSLog(@"Failed to create interceptor or transport.");
if (nextManager == nil) {
[internalCall setResponseHandler:_responseHandler];
} else {
[nextManager setPreviousInterceptor:_responseHandler];
}
_firstInterceptor = nextInterceptor;
}
return self;
@ -215,42 +200,696 @@ NSString *const kGRPCErrorDomain = @"io.grpc";
}
- (void)start {
id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor;
GRPCRequestOptions *requestOptions = _requestOptions;
GRPCCallOptions *callOptions = _actualCallOptions;
dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{
[copiedFirstInterceptor startWithRequestOptions:requestOptions callOptions:callOptions];
});
id<GRPCInterceptorInterface> copiedFirstInterceptor;
@synchronized(self) {
copiedFirstInterceptor = _firstInterceptor;
}
GRPCRequestOptions *requestOptions = [_requestOptions copy];
GRPCCallOptions *callOptions = [_actualCallOptions copy];
if ([copiedFirstInterceptor respondsToSelector:@selector(startWithRequestOptions:callOptions:)]) {
dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
[copiedFirstInterceptor startWithRequestOptions:requestOptions callOptions:callOptions];
});
}
}
- (void)cancel {
id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor;
if (copiedFirstInterceptor != nil) {
dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{
id<GRPCInterceptorInterface> copiedFirstInterceptor;
@synchronized(self) {
copiedFirstInterceptor = _firstInterceptor;
}
if ([copiedFirstInterceptor respondsToSelector:@selector(cancel)]) {
dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
[copiedFirstInterceptor cancel];
});
}
}
- (void)writeData:(id)data {
id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor;
dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{
[copiedFirstInterceptor writeData:data];
});
id<GRPCInterceptorInterface> copiedFirstInterceptor;
@synchronized(self) {
copiedFirstInterceptor = _firstInterceptor;
}
if ([copiedFirstInterceptor respondsToSelector:@selector(writeData:)]) {
dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
[copiedFirstInterceptor writeData:data];
});
}
}
- (void)finish {
id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor;
dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{
[copiedFirstInterceptor finish];
id<GRPCInterceptorInterface> copiedFirstInterceptor;
@synchronized(self) {
copiedFirstInterceptor = _firstInterceptor;
}
if ([copiedFirstInterceptor respondsToSelector:@selector(finish)]) {
dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
[copiedFirstInterceptor finish];
});
}
}
- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
id<GRPCInterceptorInterface> copiedFirstInterceptor;
@synchronized(self) {
copiedFirstInterceptor = _firstInterceptor;
}
if ([copiedFirstInterceptor respondsToSelector:@selector(receiveNextMessages:)]) {
dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{
[copiedFirstInterceptor receiveNextMessages:numberOfMessages];
});
}
}
@end
// The following methods of a C gRPC call object aren't reentrant, and thus
// calls to them must be serialized:
// - start_batch
// - destroy
//
// start_batch with a SEND_MESSAGE argument can only be called after the
// OP_COMPLETE event for any previous write is received. This is achieved by
// pausing the requests writer immediately every time it writes a value, and
// resuming it again when OP_COMPLETE is received.
//
// Similarly, start_batch with a RECV_MESSAGE argument can only be called after
// the OP_COMPLETE event for any previous read is received.This is easier to
// enforce, as we're writing the received messages into the writeable:
// start_batch is enqueued once upon receiving the OP_COMPLETE event for the
// RECV_METADATA batch, and then once after receiving each OP_COMPLETE event for
// each RECV_MESSAGE batch.
@implementation GRPCCall {
dispatch_queue_t _callQueue;
NSString *_host;
NSString *_path;
GRPCCallSafety _callSafety;
GRPCCallOptions *_callOptions;
GRPCWrappedCall *_wrappedCall;
// The C gRPC library has less guarantees on the ordering of events than we
// do. Particularly, in the face of errors, there's no ordering guarantee at
// all. This wrapper over our actual writeable ensures thread-safety and
// correct ordering.
GRXConcurrentWriteable *_responseWriteable;
// The network thread wants the requestWriter to resume (when the server is ready for more input),
// or to stop (on errors), concurrently with user threads that want to start it, pause it or stop
// it. Because a writer isn't thread-safe, we'll synchronize those operations on it.
// We don't use a dispatch queue for that purpose, because the writer can call writeValue: or
// writesFinishedWithError: on this GRPCCall as part of those operations. We want to be able to
// pause the writer immediately on writeValue:, so we need our locking to be recursive.
GRXWriter *_requestWriter;
// To create a retain cycle when a call is started, up until it finishes. See
// |startWithWriteable:| and |finishWithError:|. This saves users from having to retain a
// reference to the call object if all they're interested in is the handler being executed when
// the response arrives.
GRPCCall *_retainSelf;
GRPCRequestHeaders *_requestHeaders;
// In the case that the call is a unary call (i.e. the writer to GRPCCall is of type
// GRXImmediateSingleWriter), GRPCCall will delay sending ops (not send them to C core
// immediately) and buffer them into a batch _unaryOpBatch. The batch is sent to C core when
// the SendClose op is added.
BOOL _unaryCall;
NSMutableArray *_unaryOpBatch;
// The dispatch queue to be used for enqueuing responses to user. Defaulted to the main dispatch
// queue
dispatch_queue_t _responseQueue;
// The OAuth2 token fetched from a token provider.
NSString *_fetchedOauth2AccessToken;
// The callback to be called when a write message op is done.
void (^_writeDone)(void);
// Indicate a read request to core is pending.
BOOL _pendingCoreRead;
// Indicate pending read message request from user.
NSUInteger _pendingReceiveNextMessages;
}
@synthesize state = _state;
+ (void)initialize {
// Guarantees the code in {} block is invoked only once. See ref at:
// https://developer.apple.com/documentation/objectivec/nsobject/1418639-initialize?language=objc
if (self == [GRPCCall self]) {
grpc_init();
callFlags = [NSMutableDictionary dictionary];
}
}
+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path {
if (host.length == 0 || path.length == 0) {
return;
}
NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path];
@synchronized(callFlags) {
switch (callSafety) {
case GRPCCallSafetyDefault:
callFlags[hostAndPath] = @0;
break;
case GRPCCallSafetyIdempotentRequest:
callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
break;
case GRPCCallSafetyCacheableRequest:
callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
break;
default:
break;
}
}
}
+ (uint32_t)callFlagsForHost:(NSString *)host path:(NSString *)path {
NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path];
@synchronized(callFlags) {
return [callFlags[hostAndPath] intValue];
}
}
// Designated initializer
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
requestsWriter:(GRXWriter *)requestWriter {
return [self initWithHost:host
path:path
callSafety:GRPCCallSafetyDefault
requestsWriter:requestWriter
callOptions:nil];
}
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
callSafety:(GRPCCallSafety)safety
requestsWriter:(GRXWriter *)requestsWriter
callOptions:(GRPCCallOptions *)callOptions {
return [self initWithHost:host
path:path
callSafety:safety
requestsWriter:requestsWriter
callOptions:callOptions
writeDone:nil];
}
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
callSafety:(GRPCCallSafety)safety
requestsWriter:(GRXWriter *)requestsWriter
callOptions:(GRPCCallOptions *)callOptions
writeDone:(void (^)(void))writeDone {
// Purposely using pointer rather than length (host.length == 0) for backwards compatibility.
NSAssert(host != nil && path != nil, @"Neither host nor path can be nil.");
NSAssert(safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value.");
NSAssert(requestsWriter.state == GRXWriterStateNotStarted,
@"The requests writer can't be already started.");
if (!host || !path) {
return nil;
}
if (safety > GRPCCallSafetyCacheableRequest) {
return nil;
}
if (requestsWriter.state != GRXWriterStateNotStarted) {
return nil;
}
if ((self = [super init])) {
_host = [host copy];
_path = [path copy];
_callSafety = safety;
_callOptions = [callOptions copy];
// Serial queue to invoke the non-reentrant methods of the grpc_call object.
_callQueue = dispatch_queue_create("io.grpc.call", DISPATCH_QUEUE_SERIAL);
_requestWriter = requestsWriter;
_requestHeaders = [[GRPCRequestHeaders alloc] initWithCall:self];
_writeDone = writeDone;
if ([requestsWriter isKindOfClass:[GRXImmediateSingleWriter class]]) {
_unaryCall = YES;
_unaryOpBatch = [NSMutableArray arrayWithCapacity:kMaxClientBatch];
}
_responseQueue = dispatch_get_main_queue();
// do not start a read until initial metadata is received
_pendingReceiveNextMessages = 0;
_pendingCoreRead = YES;
}
return self;
}
- (void)setResponseDispatchQueue:(dispatch_queue_t)queue {
@synchronized(self) {
if (_state != GRXWriterStateNotStarted) {
return;
}
_responseQueue = queue;
}
}
#pragma mark Finish
// This function should support being called within a @synchronized(self) block in another function
// Should not manipulate _requestWriter for deadlock prevention.
- (void)finishWithError:(NSError *)errorOrNil {
@synchronized(self) {
if (_state == GRXWriterStateFinished) {
return;
}
_state = GRXWriterStateFinished;
if (errorOrNil) {
[_responseWriteable cancelWithError:errorOrNil];
} else {
[_responseWriteable enqueueSuccessfulCompletion];
}
// If the call isn't retained anywhere else, it can be deallocated now.
_retainSelf = nil;
}
}
- (void)cancel {
@synchronized(self) {
if (_state == GRXWriterStateFinished) {
return;
}
[self finishWithError:[NSError
errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{NSLocalizedDescriptionKey : @"Canceled by app"}]];
[_wrappedCall cancel];
}
_requestWriter.state = GRXWriterStateFinished;
}
- (void)dealloc {
__block GRPCWrappedCall *wrappedCall = _wrappedCall;
dispatch_async(_callQueue, ^{
wrappedCall = nil;
});
}
#pragma mark Read messages
// Only called from the call queue.
// The handler will be called from the network queue.
- (void)startReadWithHandler:(void (^)(grpc_byte_buffer *))handler {
// TODO(jcanizales): Add error handlers for async failures
[_wrappedCall startBatchWithOperations:@[ [[GRPCOpRecvMessage alloc] initWithHandler:handler] ]];
}
// Called initially from the network queue once response headers are received,
// then "recursively" from the responseWriteable queue after each response from the
// server has been written.
// If the call is currently paused, this is a noop. Restarting the call will invoke this
// method.
// TODO(jcanizales): Rename to readResponseIfNotPaused.
- (void)maybeStartNextRead {
@synchronized(self) {
if (_state != GRXWriterStateStarted) {
return;
}
if (_callOptions.flowControlEnabled && (_pendingCoreRead || _pendingReceiveNextMessages == 0)) {
return;
}
_pendingCoreRead = YES;
_pendingReceiveNextMessages--;
}
dispatch_async(_callQueue, ^{
__weak GRPCCall *weakSelf = self;
[self startReadWithHandler:^(grpc_byte_buffer *message) {
if (message == NULL) {
// No more messages from the server
return;
}
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf == nil) {
grpc_byte_buffer_destroy(message);
return;
}
NSData *data = [NSData grpc_dataWithByteBuffer:message];
grpc_byte_buffer_destroy(message);
if (!data) {
// The app doesn't have enough memory to hold the server response. We
// don't want to throw, because the app shouldn't crash for a behavior
// that's on the hands of any server to have. Instead we finish and ask
// the server to cancel.
@synchronized(strongSelf) {
strongSelf->_pendingCoreRead = NO;
[strongSelf
finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeResourceExhausted
userInfo:@{
NSLocalizedDescriptionKey :
@"Client does not have enough memory to "
@"hold the server response."
}]];
[strongSelf->_wrappedCall cancel];
}
strongSelf->_requestWriter.state = GRXWriterStateFinished;
} else {
@synchronized(strongSelf) {
[strongSelf->_responseWriteable enqueueValue:data
completionHandler:^{
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
@synchronized(strongSelf) {
strongSelf->_pendingCoreRead = NO;
[strongSelf maybeStartNextRead];
}
}
}];
}
}
}];
});
}
#pragma mark Send headers
- (void)sendHeaders {
// TODO (mxyan): Remove after deprecated methods are removed
uint32_t callSafetyFlags = 0;
switch (_callSafety) {
case GRPCCallSafetyDefault:
callSafetyFlags = 0;
break;
case GRPCCallSafetyIdempotentRequest:
callSafetyFlags = GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
break;
case GRPCCallSafetyCacheableRequest:
callSafetyFlags = GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
break;
}
NSMutableDictionary *headers = [_requestHeaders mutableCopy];
NSString *fetchedOauth2AccessToken;
@synchronized(self) {
fetchedOauth2AccessToken = _fetchedOauth2AccessToken;
}
if (fetchedOauth2AccessToken != nil) {
headers[@"authorization"] = [kBearerPrefix stringByAppendingString:fetchedOauth2AccessToken];
} else if (_callOptions.oauth2AccessToken != nil) {
headers[@"authorization"] =
[kBearerPrefix stringByAppendingString:_callOptions.oauth2AccessToken];
}
// TODO(jcanizales): Add error handlers for async failures
GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc]
initWithMetadata:headers
flags:callSafetyFlags
handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA
dispatch_async(_callQueue, ^{
if (!self->_unaryCall) {
[self->_wrappedCall startBatchWithOperations:@[ op ]];
} else {
[self->_unaryOpBatch addObject:op];
}
});
}
- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor;
dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{
[copiedFirstInterceptor receiveNextMessages:numberOfMessages];
if (numberOfMessages == 0) {
return;
}
@synchronized(self) {
_pendingReceiveNextMessages += numberOfMessages;
if (_state != GRXWriterStateStarted || !_callOptions.flowControlEnabled) {
return;
}
[self maybeStartNextRead];
}
}
#pragma mark GRXWriteable implementation
// Only called from the call queue. The error handler will be called from the
// network queue if the write didn't succeed.
// If the call is a unary call, parameter \a errorHandler will be ignored and
// the error handler of GRPCOpSendClose will be executed in case of error.
- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)(void))errorHandler {
__weak GRPCCall *weakSelf = self;
void (^resumingHandler)(void) = ^{
// Resume the request writer.
GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf->_requestWriter.state = GRXWriterStateStarted;
if (strongSelf->_writeDone) {
strongSelf->_writeDone();
}
}
};
GRPCOpSendMessage *op =
[[GRPCOpSendMessage alloc] initWithMessage:message handler:resumingHandler];
if (!_unaryCall) {
[_wrappedCall startBatchWithOperations:@[ op ] errorHandler:errorHandler];
} else {
// Ignored errorHandler since it is the same as the one for GRPCOpSendClose.
// TODO (mxyan): unify the error handlers of all Ops into a single closure.
[_unaryOpBatch addObject:op];
}
}
- (void)writeValue:(id)value {
NSAssert([value isKindOfClass:[NSData class]], @"value must be of type NSData");
@synchronized(self) {
if (_state == GRXWriterStateFinished) {
return;
}
}
// Pause the input and only resume it when the C layer notifies us that writes
// can proceed.
_requestWriter.state = GRXWriterStatePaused;
dispatch_async(_callQueue, ^{
// Write error is not processed here. It is handled by op batch of GRPC_OP_RECV_STATUS_ON_CLIENT
[self writeMessage:value withErrorHandler:nil];
});
}
// Only called from the call queue. The error handler will be called from the
// network queue if the requests stream couldn't be closed successfully.
- (void)finishRequestWithErrorHandler:(void (^)(void))errorHandler {
if (!_unaryCall) {
[_wrappedCall startBatchWithOperations:@[ [[GRPCOpSendClose alloc] init] ]
errorHandler:errorHandler];
} else {
[_unaryOpBatch addObject:[[GRPCOpSendClose alloc] init]];
[_wrappedCall startBatchWithOperations:_unaryOpBatch errorHandler:errorHandler];
}
}
- (void)writesFinishedWithError:(NSError *)errorOrNil {
if (errorOrNil) {
[self cancel];
} else {
dispatch_async(_callQueue, ^{
// EOS error is not processed here. It is handled by op batch of GRPC_OP_RECV_STATUS_ON_CLIENT
[self finishRequestWithErrorHandler:nil];
});
}
}
#pragma mark Invoke
// Both handlers will eventually be called, from the network queue. Writes can start immediately
// after this.
// The first one (headersHandler), when the response headers are received.
// The second one (completionHandler), whenever the RPC finishes for any reason.
- (void)invokeCallWithHeadersHandler:(void (^)(NSDictionary *))headersHandler
completionHandler:(void (^)(NSError *, NSDictionary *))completionHandler {
dispatch_async(_callQueue, ^{
// TODO(jcanizales): Add error handlers for async failures
[self->_wrappedCall
startBatchWithOperations:@[ [[GRPCOpRecvMetadata alloc] initWithHandler:headersHandler] ]];
[self->_wrappedCall
startBatchWithOperations:@[ [[GRPCOpRecvStatus alloc] initWithHandler:completionHandler] ]];
});
}
- (void)invokeCall {
__weak GRPCCall *weakSelf = self;
[self invokeCallWithHeadersHandler:^(NSDictionary *headers) {
// Response headers received.
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
@synchronized(strongSelf) {
// it is ok to set nil because headers are only received once
strongSelf.responseHeaders = nil;
// copy the header so that the GRPCOpRecvMetadata object may be dealloc'ed
NSDictionary *copiedHeaders =
[[NSDictionary alloc] initWithDictionary:headers copyItems:YES];
strongSelf.responseHeaders = copiedHeaders;
strongSelf->_pendingCoreRead = NO;
[strongSelf maybeStartNextRead];
}
}
}
completionHandler:^(NSError *error, NSDictionary *trailers) {
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf.responseTrailers = trailers;
if (error) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
if (error.userInfo) {
[userInfo addEntriesFromDictionary:error.userInfo];
}
userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers;
// Since gRPC core does not guarantee the headers block being called before this block,
// responseHeaders might be nil.
userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders;
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
}
[strongSelf finishWithError:error];
strongSelf->_requestWriter.state = GRXWriterStateFinished;
}
}];
}
#pragma mark GRXWriter implementation
// Lock acquired inside startWithWriteable:
- (void)startCallWithWriteable:(id<GRXWriteable>)writeable {
@synchronized(self) {
if (_state == GRXWriterStateFinished) {
return;
}
_responseWriteable =
[[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue];
GRPCPooledChannel *channel =
[[GRPCChannelPool sharedInstance] channelWithHost:_host callOptions:_callOptions];
_wrappedCall = [channel wrappedCallWithPath:_path
completionQueue:[GRPCCompletionQueue completionQueue]
callOptions:_callOptions];
if (_wrappedCall == nil) {
[self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable
userInfo:@{
NSLocalizedDescriptionKey :
@"Failed to create call or channel."
}]];
return;
}
[self sendHeaders];
[self invokeCall];
}
// Now that the RPC has been initiated, request writes can start.
[_requestWriter startWithWriteable:self];
}
- (void)startWithWriteable:(id<GRXWriteable>)writeable {
id<GRPCAuthorizationProtocol> tokenProvider = nil;
@synchronized(self) {
_state = GRXWriterStateStarted;
// Create a retain cycle so that this instance lives until the RPC finishes (or is cancelled).
// This makes RPCs in which the call isn't externally retained possible (as long as it is
// started before being autoreleased). Care is taken not to retain self strongly in any of the
// blocks used in this implementation, so that the life of the instance is determined by this
// retain cycle.
_retainSelf = self;
if (_callOptions == nil) {
GRPCMutableCallOptions *callOptions = [[GRPCHost callOptionsForHost:_host] mutableCopy];
if (_serverName.length != 0) {
callOptions.serverAuthority = _serverName;
}
if (_timeout > 0) {
callOptions.timeout = _timeout;
}
uint32_t callFlags = [GRPCCall callFlagsForHost:_host path:_path];
if (callFlags != 0) {
if (callFlags == GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
_callSafety = GRPCCallSafetyIdempotentRequest;
} else if (callFlags == GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) {
_callSafety = GRPCCallSafetyCacheableRequest;
}
}
id<GRPCAuthorizationProtocol> tokenProvider = self.tokenProvider;
if (tokenProvider != nil) {
callOptions.authTokenProvider = tokenProvider;
}
_callOptions = callOptions;
}
NSAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil,
@"authTokenProvider and oauth2AccessToken cannot be set at the same time");
tokenProvider = _callOptions.authTokenProvider;
}
if (tokenProvider != nil) {
__weak typeof(self) weakSelf = self;
[tokenProvider getTokenWithHandler:^(NSString *token) {
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
BOOL startCall = NO;
@synchronized(strongSelf) {
if (strongSelf->_state != GRXWriterStateFinished) {
startCall = YES;
if (token) {
strongSelf->_fetchedOauth2AccessToken = [token copy];
}
}
}
if (startCall) {
[strongSelf startCallWithWriteable:writeable];
}
}
}];
} else {
[self startCallWithWriteable:writeable];
}
}
- (void)setState:(GRXWriterState)newState {
@synchronized(self) {
// Manual transitions are only allowed from the started or paused states.
if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) {
return;
}
switch (newState) {
case GRXWriterStateFinished:
_state = newState;
// Per GRXWriter's contract, setting the state to Finished manually
// means one doesn't wish the writeable to be messaged anymore.
[_responseWriteable cancelSilently];
_responseWriteable = nil;
return;
case GRXWriterStatePaused:
_state = newState;
return;
case GRXWriterStateStarted:
if (_state == GRXWriterStatePaused) {
_state = newState;
[self maybeStartNextRead];
}
return;
case GRXWriterStateNotStarted:
return;
}
}
}
@end

@ -1,136 +0,0 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/**
* This is the legacy interface of this gRPC library. This API is deprecated and users should use
* the API in GRPCCall.h. This API exists solely for the purpose of backwards compatibility.
*/
#import <RxLibrary/GRXWriter.h>
#import "GRPCTypes.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnullability-completeness"
/**
* This interface is deprecated. Please use \a GRPCCall2.
*
* Represents a single gRPC remote call.
*/
@interface GRPCCall : GRXWriter
- (instancetype)init NS_UNAVAILABLE;
/**
* The container of the request headers of an RPC conforms to this protocol, which is a subset of
* NSMutableDictionary's interface. It will become a NSMutableDictionary later on.
* The keys of this container are the header names, which per the HTTP standard are case-
* insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and
* can only consist of ASCII characters.
* A header value is a NSString object (with only ASCII characters), unless the header name has the
* suffix "-bin", in which case the value has to be a NSData object.
*/
/**
* These HTTP headers will be passed to the server as part of this call. Each HTTP header is a
* name-value pair with string names and either string or binary values.
*
* The passed dictionary has to use NSString keys, corresponding to the header names. The value
* associated to each can be a NSString object or a NSData object. E.g.:
*
* call.requestHeaders = @{@"authorization": @"Bearer ..."};
*
* call.requestHeaders[@"my-header-bin"] = someData;
*
* After the call is started, trying to modify this property is an error.
*
* The property is initialized to an empty NSMutableDictionary.
*/
@property(atomic, readonly) NSMutableDictionary *requestHeaders;
/**
* This dictionary is populated with the HTTP headers received from the server. This happens before
* any response message is received from the server. It has the same structure as the request
* headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a
* NSData value; the others have a NSString value.
*
* The value of this property is nil until all response headers are received, and will change before
* any of -writeValue: or -writesFinishedWithError: are sent to the writeable.
*/
@property(atomic, readonly) NSDictionary *responseHeaders;
/**
* Same as responseHeaders, but populated with the HTTP trailers received from the server before the
* call finishes.
*
* The value of this property is nil until all response trailers are received, and will change
* before -writesFinishedWithError: is sent to the writeable.
*/
@property(atomic, readonly) NSDictionary *responseTrailers;
/**
* The request writer has to write NSData objects into the provided Writeable. The server will
* receive each of those separately and in order as distinct messages.
* A gRPC call might not complete until the request writer finishes. On the other hand, the request
* finishing doesn't necessarily make the call to finish, as the server might continue sending
* messages to the response side of the call indefinitely (depending on the semantics of the
* specific remote method called).
* To finish a call right away, invoke cancel.
* host parameter should not contain the scheme (http:// or https://), only the name or IP addr
* and the port number, for example @"localhost:5050".
*/
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
requestsWriter:(GRXWriter *)requestWriter;
/**
* Finishes the request side of this call, notifies the server that the RPC should be cancelled, and
* finishes the response side of the call with an error of code CANCELED.
*/
- (void)cancel;
/**
* The following methods are deprecated.
*/
+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path;
@property(atomic, copy, readwrite) NSString *serverName;
@property NSTimeInterval timeout;
- (void)setResponseDispatchQueue:(dispatch_queue_t)queue;
@end
#pragma mark Backwards compatibiity
/** This protocol is kept for backwards compatibility with existing code. */
DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.")
@protocol GRPCRequestHeaders<NSObject>
@property(nonatomic, readonly) NSUInteger count;
- (id)objectForKeyedSubscript:(id)key;
- (void)setObject:(id)obj forKeyedSubscript:(id)key;
- (void)removeAllObjects;
- (void)removeObjectForKey:(id)key;
@end
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
/** This is only needed for backwards-compatibility. */
@interface NSMutableDictionary (GRPCRequestHeaders)<GRPCRequestHeaders>
@end
#pragma clang diagnostic pop
#pragma clang diagnostic pop

@ -1,677 +0,0 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import "GRPCCallLegacy.h"
#import "GRPCCall+OAuth2.h"
#import "GRPCCallOptions.h"
#import "GRPCTypes.h"
#import "private/GRPCCore/GRPCChannelPool.h"
#import "private/GRPCCore/GRPCCompletionQueue.h"
#import "private/GRPCCore/GRPCHost.h"
#import "private/GRPCCore/GRPCWrappedCall.h"
#import "private/GRPCCore/NSData+GRPC.h"
#import <RxLibrary/GRXBufferedPipe.h>
#import <RxLibrary/GRXConcurrentWriteable.h>
#import <RxLibrary/GRXImmediateSingleWriter.h>
#import <RxLibrary/GRXWriter+Immediate.h>
#include <grpc/grpc.h>
const char *kCFStreamVarName = "grpc_cfstream";
static NSMutableDictionary *callFlags;
// At most 6 ops can be in an op batch for a client: SEND_INITIAL_METADATA,
// SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT, RECV_INITIAL_METADATA, RECV_MESSAGE,
// and RECV_STATUS_ON_CLIENT.
NSInteger kMaxClientBatch = 6;
static NSString *const kAuthorizationHeader = @"authorization";
static NSString *const kBearerPrefix = @"Bearer ";
@interface GRPCCall ()<GRXWriteable>
// Make them read-write.
@property(atomic, strong) NSDictionary *responseHeaders;
@property(atomic, strong) NSDictionary *responseTrailers;
- (void)receiveNextMessages:(NSUInteger)numberOfMessages;
@end
// The following methods of a C gRPC call object aren't reentrant, and thus
// calls to them must be serialized:
// - start_batch
// - destroy
//
// start_batch with a SEND_MESSAGE argument can only be called after the
// OP_COMPLETE event for any previous write is received. This is achieved by
// pausing the requests writer immediately every time it writes a value, and
// resuming it again when OP_COMPLETE is received.
//
// Similarly, start_batch with a RECV_MESSAGE argument can only be called after
// the OP_COMPLETE event for any previous read is received.This is easier to
// enforce, as we're writing the received messages into the writeable:
// start_batch is enqueued once upon receiving the OP_COMPLETE event for the
// RECV_METADATA batch, and then once after receiving each OP_COMPLETE event for
// each RECV_MESSAGE batch.
@implementation GRPCCall {
dispatch_queue_t _callQueue;
NSString *_host;
NSString *_path;
GRPCCallSafety _callSafety;
GRPCCallOptions *_callOptions;
GRPCWrappedCall *_wrappedCall;
// The C gRPC library has less guarantees on the ordering of events than we
// do. Particularly, in the face of errors, there's no ordering guarantee at
// all. This wrapper over our actual writeable ensures thread-safety and
// correct ordering.
GRXConcurrentWriteable *_responseWriteable;
// The network thread wants the requestWriter to resume (when the server is ready for more input),
// or to stop (on errors), concurrently with user threads that want to start it, pause it or stop
// it. Because a writer isn't thread-safe, we'll synchronize those operations on it.
// We don't use a dispatch queue for that purpose, because the writer can call writeValue: or
// writesFinishedWithError: on this GRPCCall as part of those operations. We want to be able to
// pause the writer immediately on writeValue:, so we need our locking to be recursive.
GRXWriter *_requestWriter;
// To create a retain cycle when a call is started, up until it finishes. See
// |startWithWriteable:| and |finishWithError:|. This saves users from having to retain a
// reference to the call object if all they're interested in is the handler being executed when
// the response arrives.
GRPCCall *_retainSelf;
GRPCRequestHeaders *_requestHeaders;
// In the case that the call is a unary call (i.e. the writer to GRPCCall is of type
// GRXImmediateSingleWriter), GRPCCall will delay sending ops (not send them to C core
// immediately) and buffer them into a batch _unaryOpBatch. The batch is sent to C core when
// the SendClose op is added.
BOOL _unaryCall;
NSMutableArray *_unaryOpBatch;
// The dispatch queue to be used for enqueuing responses to user. Defaulted to the main dispatch
// queue
dispatch_queue_t _responseQueue;
// The OAuth2 token fetched from a token provider.
NSString *_fetchedOauth2AccessToken;
// The callback to be called when a write message op is done.
void (^_writeDone)(void);
// Indicate a read request to core is pending.
BOOL _pendingCoreRead;
// Indicate pending read message request from user.
NSUInteger _pendingReceiveNextMessages;
}
@synthesize state = _state;
+ (void)initialize {
// Guarantees the code in {} block is invoked only once. See ref at:
// https://developer.apple.com/documentation/objectivec/nsobject/1418639-initialize?language=objc
if (self == [GRPCCall self]) {
grpc_init();
callFlags = [NSMutableDictionary dictionary];
}
}
+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path {
if (host.length == 0 || path.length == 0) {
return;
}
NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path];
@synchronized(callFlags) {
switch (callSafety) {
case GRPCCallSafetyDefault:
callFlags[hostAndPath] = @0;
break;
case GRPCCallSafetyIdempotentRequest:
callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
break;
case GRPCCallSafetyCacheableRequest:
callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
break;
default:
break;
}
}
}
+ (uint32_t)callFlagsForHost:(NSString *)host path:(NSString *)path {
NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path];
@synchronized(callFlags) {
return [callFlags[hostAndPath] intValue];
}
}
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
requestsWriter:(GRXWriter *)requestWriter {
return [self initWithHost:host
path:path
callSafety:GRPCCallSafetyDefault
requestsWriter:requestWriter
callOptions:nil
writeDone:nil];
}
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
callSafety:(GRPCCallSafety)safety
requestsWriter:(GRXWriter *)requestsWriter
callOptions:(GRPCCallOptions *)callOptions
writeDone:(void (^)(void))writeDone {
// Purposely using pointer rather than length (host.length == 0) for backwards compatibility.
NSAssert(host != nil && path != nil, @"Neither host nor path can be nil.");
NSAssert(safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value.");
NSAssert(requestsWriter.state == GRXWriterStateNotStarted,
@"The requests writer can't be already started.");
if (!host || !path) {
return nil;
}
if (safety > GRPCCallSafetyCacheableRequest) {
return nil;
}
if (requestsWriter.state != GRXWriterStateNotStarted) {
return nil;
}
if ((self = [super init])) {
_host = [host copy];
_path = [path copy];
_callSafety = safety;
_callOptions = [callOptions copy];
// Serial queue to invoke the non-reentrant methods of the grpc_call object.
_callQueue = dispatch_queue_create("io.grpc.call", DISPATCH_QUEUE_SERIAL);
_requestWriter = requestsWriter;
_requestHeaders = [[GRPCRequestHeaders alloc] initWithCall:self];
_writeDone = writeDone;
if ([requestsWriter isKindOfClass:[GRXImmediateSingleWriter class]]) {
_unaryCall = YES;
_unaryOpBatch = [NSMutableArray arrayWithCapacity:kMaxClientBatch];
}
_responseQueue = dispatch_get_main_queue();
// do not start a read until initial metadata is received
_pendingReceiveNextMessages = 0;
_pendingCoreRead = YES;
}
return self;
}
- (void)setResponseDispatchQueue:(dispatch_queue_t)queue {
@synchronized(self) {
if (_state != GRXWriterStateNotStarted) {
return;
}
_responseQueue = queue;
}
}
#pragma mark Finish
// This function should support being called within a @synchronized(self) block in another function
// Should not manipulate _requestWriter for deadlock prevention.
- (void)finishWithError:(NSError *)errorOrNil {
@synchronized(self) {
if (_state == GRXWriterStateFinished) {
return;
}
_state = GRXWriterStateFinished;
if (errorOrNil) {
[_responseWriteable cancelWithError:errorOrNil];
} else {
[_responseWriteable enqueueSuccessfulCompletion];
}
// If the call isn't retained anywhere else, it can be deallocated now.
_retainSelf = nil;
}
}
- (void)cancel {
@synchronized(self) {
if (_state == GRXWriterStateFinished) {
return;
}
[self finishWithError:[NSError
errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{NSLocalizedDescriptionKey : @"Canceled by app"}]];
[_wrappedCall cancel];
}
_requestWriter.state = GRXWriterStateFinished;
}
- (void)dealloc {
__block GRPCWrappedCall *wrappedCall = _wrappedCall;
dispatch_async(_callQueue, ^{
wrappedCall = nil;
});
}
#pragma mark Read messages
// Only called from the call queue.
// The handler will be called from the network queue.
- (void)startReadWithHandler:(void (^)(grpc_byte_buffer *))handler {
// TODO(jcanizales): Add error handlers for async failures
[_wrappedCall startBatchWithOperations:@[ [[GRPCOpRecvMessage alloc] initWithHandler:handler] ]];
}
// Called initially from the network queue once response headers are received,
// then "recursively" from the responseWriteable queue after each response from the
// server has been written.
// If the call is currently paused, this is a noop. Restarting the call will invoke this
// method.
// TODO(jcanizales): Rename to readResponseIfNotPaused.
- (void)maybeStartNextRead {
@synchronized(self) {
if (_state != GRXWriterStateStarted) {
return;
}
if (_callOptions.flowControlEnabled && (_pendingCoreRead || _pendingReceiveNextMessages == 0)) {
return;
}
_pendingCoreRead = YES;
_pendingReceiveNextMessages--;
}
dispatch_async(_callQueue, ^{
__weak GRPCCall *weakSelf = self;
[self startReadWithHandler:^(grpc_byte_buffer *message) {
if (message == NULL) {
// No more messages from the server
return;
}
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf == nil) {
grpc_byte_buffer_destroy(message);
return;
}
NSData *data = [NSData grpc_dataWithByteBuffer:message];
grpc_byte_buffer_destroy(message);
if (!data) {
// The app doesn't have enough memory to hold the server response. We
// don't want to throw, because the app shouldn't crash for a behavior
// that's on the hands of any server to have. Instead we finish and ask
// the server to cancel.
@synchronized(strongSelf) {
strongSelf->_pendingCoreRead = NO;
[strongSelf
finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeResourceExhausted
userInfo:@{
NSLocalizedDescriptionKey :
@"Client does not have enough memory to "
@"hold the server response."
}]];
[strongSelf->_wrappedCall cancel];
}
strongSelf->_requestWriter.state = GRXWriterStateFinished;
} else {
@synchronized(strongSelf) {
[strongSelf->_responseWriteable enqueueValue:data
completionHandler:^{
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
@synchronized(strongSelf) {
strongSelf->_pendingCoreRead = NO;
[strongSelf maybeStartNextRead];
}
}
}];
}
}
}];
});
}
#pragma mark Send headers
- (void)sendHeaders {
// TODO (mxyan): Remove after deprecated methods are removed
uint32_t callSafetyFlags = 0;
switch (_callSafety) {
case GRPCCallSafetyDefault:
callSafetyFlags = 0;
break;
case GRPCCallSafetyIdempotentRequest:
callSafetyFlags = GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
break;
case GRPCCallSafetyCacheableRequest:
callSafetyFlags = GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
break;
}
NSMutableDictionary *headers = [_requestHeaders mutableCopy];
NSString *fetchedOauth2AccessToken;
@synchronized(self) {
fetchedOauth2AccessToken = _fetchedOauth2AccessToken;
}
if (fetchedOauth2AccessToken != nil) {
headers[@"authorization"] = [kBearerPrefix stringByAppendingString:fetchedOauth2AccessToken];
} else if (_callOptions.oauth2AccessToken != nil) {
headers[@"authorization"] =
[kBearerPrefix stringByAppendingString:_callOptions.oauth2AccessToken];
}
// TODO(jcanizales): Add error handlers for async failures
GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc]
initWithMetadata:headers
flags:callSafetyFlags
handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA
dispatch_async(_callQueue, ^{
if (!self->_unaryCall) {
[self->_wrappedCall startBatchWithOperations:@[ op ]];
} else {
[self->_unaryOpBatch addObject:op];
}
});
}
- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
if (numberOfMessages == 0) {
return;
}
@synchronized(self) {
_pendingReceiveNextMessages += numberOfMessages;
if (_state != GRXWriterStateStarted || !_callOptions.flowControlEnabled) {
return;
}
[self maybeStartNextRead];
}
}
#pragma mark GRXWriteable implementation
// Only called from the call queue. The error handler will be called from the
// network queue if the write didn't succeed.
// If the call is a unary call, parameter \a errorHandler will be ignored and
// the error handler of GRPCOpSendClose will be executed in case of error.
- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)(void))errorHandler {
__weak GRPCCall *weakSelf = self;
void (^resumingHandler)(void) = ^{
// Resume the request writer.
GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf->_requestWriter.state = GRXWriterStateStarted;
if (strongSelf->_writeDone) {
strongSelf->_writeDone();
}
}
};
GRPCOpSendMessage *op =
[[GRPCOpSendMessage alloc] initWithMessage:message handler:resumingHandler];
if (!_unaryCall) {
[_wrappedCall startBatchWithOperations:@[ op ] errorHandler:errorHandler];
} else {
// Ignored errorHandler since it is the same as the one for GRPCOpSendClose.
// TODO (mxyan): unify the error handlers of all Ops into a single closure.
[_unaryOpBatch addObject:op];
}
}
- (void)writeValue:(id)value {
NSAssert([value isKindOfClass:[NSData class]], @"value must be of type NSData");
@synchronized(self) {
if (_state == GRXWriterStateFinished) {
return;
}
}
// Pause the input and only resume it when the C layer notifies us that writes
// can proceed.
_requestWriter.state = GRXWriterStatePaused;
dispatch_async(_callQueue, ^{
// Write error is not processed here. It is handled by op batch of GRPC_OP_RECV_STATUS_ON_CLIENT
[self writeMessage:value withErrorHandler:nil];
});
}
// Only called from the call queue. The error handler will be called from the
// network queue if the requests stream couldn't be closed successfully.
- (void)finishRequestWithErrorHandler:(void (^)(void))errorHandler {
if (!_unaryCall) {
[_wrappedCall startBatchWithOperations:@[ [[GRPCOpSendClose alloc] init] ]
errorHandler:errorHandler];
} else {
[_unaryOpBatch addObject:[[GRPCOpSendClose alloc] init]];
[_wrappedCall startBatchWithOperations:_unaryOpBatch errorHandler:errorHandler];
}
}
- (void)writesFinishedWithError:(NSError *)errorOrNil {
if (errorOrNil) {
[self cancel];
} else {
dispatch_async(_callQueue, ^{
// EOS error is not processed here. It is handled by op batch of GRPC_OP_RECV_STATUS_ON_CLIENT
[self finishRequestWithErrorHandler:nil];
});
}
}
#pragma mark Invoke
// Both handlers will eventually be called, from the network queue. Writes can start immediately
// after this.
// The first one (headersHandler), when the response headers are received.
// The second one (completionHandler), whenever the RPC finishes for any reason.
- (void)invokeCallWithHeadersHandler:(void (^)(NSDictionary *))headersHandler
completionHandler:(void (^)(NSError *, NSDictionary *))completionHandler {
dispatch_async(_callQueue, ^{
// TODO(jcanizales): Add error handlers for async failures
[self->_wrappedCall
startBatchWithOperations:@[ [[GRPCOpRecvMetadata alloc] initWithHandler:headersHandler] ]];
[self->_wrappedCall
startBatchWithOperations:@[ [[GRPCOpRecvStatus alloc] initWithHandler:completionHandler] ]];
});
}
- (void)invokeCall {
__weak GRPCCall *weakSelf = self;
[self invokeCallWithHeadersHandler:^(NSDictionary *headers) {
// Response headers received.
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
@synchronized(strongSelf) {
// it is ok to set nil because headers are only received once
strongSelf.responseHeaders = nil;
// copy the header so that the GRPCOpRecvMetadata object may be dealloc'ed
NSDictionary *copiedHeaders =
[[NSDictionary alloc] initWithDictionary:headers copyItems:YES];
strongSelf.responseHeaders = copiedHeaders;
strongSelf->_pendingCoreRead = NO;
[strongSelf maybeStartNextRead];
}
}
}
completionHandler:^(NSError *error, NSDictionary *trailers) {
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf.responseTrailers = trailers;
if (error) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
if (error.userInfo) {
[userInfo addEntriesFromDictionary:error.userInfo];
}
userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers;
// Since gRPC core does not guarantee the headers block being called before this block,
// responseHeaders might be nil.
userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders;
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
}
[strongSelf finishWithError:error];
strongSelf->_requestWriter.state = GRXWriterStateFinished;
}
}];
}
#pragma mark GRXWriter implementation
// Lock acquired inside startWithWriteable:
- (void)startCallWithWriteable:(id<GRXWriteable>)writeable {
@synchronized(self) {
if (_state == GRXWriterStateFinished) {
return;
}
_responseWriteable =
[[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue];
GRPCPooledChannel *channel =
[[GRPCChannelPool sharedInstance] channelWithHost:_host callOptions:_callOptions];
_wrappedCall = [channel wrappedCallWithPath:_path
completionQueue:[GRPCCompletionQueue completionQueue]
callOptions:_callOptions];
if (_wrappedCall == nil) {
[self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable
userInfo:@{
NSLocalizedDescriptionKey :
@"Failed to create call or channel."
}]];
return;
}
[self sendHeaders];
[self invokeCall];
}
// Now that the RPC has been initiated, request writes can start.
[_requestWriter startWithWriteable:self];
}
- (void)startWithWriteable:(id<GRXWriteable>)writeable {
id<GRPCAuthorizationProtocol> tokenProvider = nil;
@synchronized(self) {
_state = GRXWriterStateStarted;
// Create a retain cycle so that this instance lives until the RPC finishes (or is cancelled).
// This makes RPCs in which the call isn't externally retained possible (as long as it is
// started before being autoreleased). Care is taken not to retain self strongly in any of the
// blocks used in this implementation, so that the life of the instance is determined by this
// retain cycle.
_retainSelf = self;
// If _callOptions is nil, people must be using the deprecated v1 interface. In this case,
// generate the call options from the corresponding GRPCHost configs and apply other options
// that are not covered by GRPCHost.
if (_callOptions == nil) {
GRPCMutableCallOptions *callOptions = [[GRPCHost callOptionsForHost:_host] mutableCopy];
if (_serverName.length != 0) {
callOptions.serverAuthority = _serverName;
}
if (_timeout > 0) {
callOptions.timeout = _timeout;
}
uint32_t callFlags = [GRPCCall callFlagsForHost:_host path:_path];
if (callFlags != 0) {
if (callFlags == GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
_callSafety = GRPCCallSafetyIdempotentRequest;
} else if (callFlags == GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) {
_callSafety = GRPCCallSafetyCacheableRequest;
}
}
id<GRPCAuthorizationProtocol> tokenProvider = self.tokenProvider;
if (tokenProvider != nil) {
callOptions.authTokenProvider = tokenProvider;
}
_callOptions = callOptions;
}
NSAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil,
@"authTokenProvider and oauth2AccessToken cannot be set at the same time");
tokenProvider = _callOptions.authTokenProvider;
}
if (tokenProvider != nil) {
__weak typeof(self) weakSelf = self;
[tokenProvider getTokenWithHandler:^(NSString *token) {
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
BOOL startCall = NO;
@synchronized(strongSelf) {
if (strongSelf->_state != GRXWriterStateFinished) {
startCall = YES;
if (token) {
strongSelf->_fetchedOauth2AccessToken = [token copy];
}
}
}
if (startCall) {
[strongSelf startCallWithWriteable:writeable];
}
}
}];
} else {
[self startCallWithWriteable:writeable];
}
}
- (void)setState:(GRXWriterState)newState {
@synchronized(self) {
// Manual transitions are only allowed from the started or paused states.
if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) {
return;
}
switch (newState) {
case GRXWriterStateFinished:
_state = newState;
// Per GRXWriter's contract, setting the state to Finished manually
// means one doesn't wish the writeable to be messaged anymore.
[_responseWriteable cancelSilently];
_responseWriteable = nil;
return;
case GRXWriterStatePaused:
_state = newState;
return;
case GRXWriterStateStarted:
if (_state == GRXWriterStatePaused) {
_state = newState;
[self maybeStartNextRead];
}
return;
case GRXWriterStateNotStarted:
return;
}
}
}
@end

@ -18,11 +18,57 @@
#import <Foundation/Foundation.h>
#import "GRPCTypes.h"
NS_ASSUME_NONNULL_BEGIN
@protocol GRPCInterceptorFactory;
/**
* Safety remark of a gRPC method as defined in RFC 2616 Section 9.1
*/
typedef NS_ENUM(NSUInteger, GRPCCallSafety) {
/** Signal that there is no guarantees on how the call affects the server state. */
GRPCCallSafetyDefault = 0,
/** Signal that the call is idempotent. gRPC is free to use PUT verb. */
GRPCCallSafetyIdempotentRequest = 1,
/**
* Signal that the call is cacheable and will not affect server state. gRPC is free to use GET
* verb.
*/
GRPCCallSafetyCacheableRequest = 2,
};
// Compression algorithm to be used by a gRPC call
typedef NS_ENUM(NSUInteger, GRPCCompressionAlgorithm) {
GRPCCompressNone = 0,
GRPCCompressDeflate,
GRPCCompressGzip,
GRPCStreamCompressGzip,
};
// GRPCCompressAlgorithm is deprecated; use GRPCCompressionAlgorithm
typedef GRPCCompressionAlgorithm GRPCCompressAlgorithm;
/** The transport to be used by a gRPC call */
typedef NS_ENUM(NSUInteger, GRPCTransportType) {
GRPCTransportTypeDefault = 0,
/** gRPC internal HTTP/2 stack with BoringSSL */
GRPCTransportTypeChttp2BoringSSL = 0,
/** Cronet stack */
GRPCTransportTypeCronet,
/** Insecure channel. FOR TEST ONLY! */
GRPCTransportTypeInsecure,
};
/**
* Implement this protocol to provide a token to gRPC when a call is initiated.
*/
@protocol GRPCAuthorizationProtocol
/**
* This method is called when gRPC is about to start the call. When OAuth token is acquired,
* \a handler is expected to be called with \a token being the new token to be used for this call.
*/
- (void)getTokenWithHandler:(void (^)(NSString *_Nullable token))handler;
@end
@interface GRPCCallOptions : NSObject<NSCopying, NSMutableCopying>
@ -58,7 +104,7 @@ NS_ASSUME_NONNULL_BEGIN
* this array. This parameter should not be modified by any interceptor and will
* not take effect if done so.
*/
@property(copy, readonly) NSArray<id<GRPCInterceptorFactory>> *interceptorFactories;
@property(copy, readonly) NSArray *interceptorFactories;
// OAuth2 parameters. Users of gRPC may specify one of the following two parameters.
@ -146,23 +192,10 @@ NS_ASSUME_NONNULL_BEGIN
@property(copy, readonly, nullable) NSString *PEMCertificateChain;
/**
* Deprecated: this option is deprecated. Please use the property \a transport
* instead.
*
* Select the transport type to be used for this call.
*/
@property(readonly) GRPCTransportType transportType;
/**
* The transport to be used for this call. Users may choose a native transport
* identifier defined in \a GRPCTransport or provided by a non-native transport
* implementation. If the option is left to be NULL, gRPC will use its default
* transport.
*
* This is currently an experimental option.
*/
@property(readonly) GRPCTransportId transport;
/**
* Override the hostname during the TLS hostname validation process.
*/
@ -234,7 +267,7 @@ NS_ASSUME_NONNULL_BEGIN
* this array. This parameter should not be modified by any interceptor and will
* not take effect if done so.
*/
@property(copy, readwrite) NSArray<id<GRPCInterceptorFactory>> *interceptorFactories;
@property(copy, readwrite) NSArray *interceptorFactories;
// OAuth2 parameters. Users of gRPC may specify one of the following two parameters.
@ -324,23 +357,10 @@ NS_ASSUME_NONNULL_BEGIN
@property(copy, readwrite, nullable) NSString *PEMCertificateChain;
/**
* Deprecated: this option is deprecated. Please use the property \a transport
* instead.
*
* Select the transport type to be used for this call.
*/
@property(readwrite) GRPCTransportType transportType;
/**
* The transport to be used for this call. Users may choose a native transport
* identifier defined in \a GRPCTransport or provided by a non-native ttransport
* implementation. If the option is left to be NULL, gRPC will use its default
* transport.
*
* An interceptor must not change the value of this option.
*/
@property(readwrite) GRPCTransportId transport;
/**
* Override the hostname during the TLS hostname validation process.
*/

@ -17,14 +17,13 @@
*/
#import "GRPCCallOptions.h"
#import "GRPCTransport.h"
#import "internal/GRPCCallOptions+Internal.h"
// The default values for the call options.
static NSString *const kDefaultServerAuthority = nil;
static const NSTimeInterval kDefaultTimeout = 0;
static const BOOL kDefaultFlowControlEnabled = NO;
static NSArray<id<GRPCInterceptorFactory>> *const kDefaultInterceptorFactories = nil;
static NSArray *const kDefaultInterceptorFactories = nil;
static NSDictionary *const kDefaultInitialMetadata = nil;
static NSString *const kDefaultUserAgentPrefix = nil;
static const NSUInteger kDefaultResponseSizeLimit = 0;
@ -42,7 +41,6 @@ static NSString *const kDefaultPEMCertificateChain = nil;
static NSString *const kDefaultOauth2AccessToken = nil;
static const id<GRPCAuthorizationProtocol> kDefaultAuthTokenProvider = nil;
static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeChttp2BoringSSL;
static const GRPCTransportId kDefaultTransport = NULL;
static NSString *const kDefaultHostNameOverride = nil;
static const id kDefaultLogContext = nil;
static NSString *const kDefaultChannelPoolDomain = nil;
@ -64,7 +62,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
NSString *_serverAuthority;
NSTimeInterval _timeout;
BOOL _flowControlEnabled;
NSArray<id<GRPCInterceptorFactory>> *_interceptorFactories;
NSArray *_interceptorFactories;
NSString *_oauth2AccessToken;
id<GRPCAuthorizationProtocol> _authTokenProvider;
NSDictionary *_initialMetadata;
@ -82,7 +80,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
NSString *_PEMPrivateKey;
NSString *_PEMCertificateChain;
GRPCTransportType _transportType;
GRPCTransportId _transport;
NSString *_hostNameOverride;
id<NSObject> _logContext;
NSString *_channelPoolDomain;
@ -110,7 +107,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
@synthesize PEMPrivateKey = _PEMPrivateKey;
@synthesize PEMCertificateChain = _PEMCertificateChain;
@synthesize transportType = _transportType;
@synthesize transport = _transport;
@synthesize hostNameOverride = _hostNameOverride;
@synthesize logContext = _logContext;
@synthesize channelPoolDomain = _channelPoolDomain;
@ -138,7 +134,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
PEMPrivateKey:kDefaultPEMPrivateKey
PEMCertificateChain:kDefaultPEMCertificateChain
transportType:kDefaultTransportType
transport:kDefaultTransport
hostNameOverride:kDefaultHostNameOverride
logContext:kDefaultLogContext
channelPoolDomain:kDefaultChannelPoolDomain
@ -148,7 +143,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
- (instancetype)initWithServerAuthority:(NSString *)serverAuthority
timeout:(NSTimeInterval)timeout
flowControlEnabled:(BOOL)flowControlEnabled
interceptorFactories:(NSArray<id<GRPCInterceptorFactory>> *)interceptorFactories
interceptorFactories:(NSArray *)interceptorFactories
oauth2AccessToken:(NSString *)oauth2AccessToken
authTokenProvider:(id<GRPCAuthorizationProtocol>)authTokenProvider
initialMetadata:(NSDictionary *)initialMetadata
@ -166,7 +161,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
PEMPrivateKey:(NSString *)PEMPrivateKey
PEMCertificateChain:(NSString *)PEMCertificateChain
transportType:(GRPCTransportType)transportType
transport:(GRPCTransportId)transport
hostNameOverride:(NSString *)hostNameOverride
logContext:(id)logContext
channelPoolDomain:(NSString *)channelPoolDomain
@ -199,7 +193,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
_PEMPrivateKey = [PEMPrivateKey copy];
_PEMCertificateChain = [PEMCertificateChain copy];
_transportType = transportType;
_transport = transport;
_hostNameOverride = [hostNameOverride copy];
_logContext = logContext;
_channelPoolDomain = [channelPoolDomain copy];
@ -231,7 +224,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
PEMPrivateKey:_PEMPrivateKey
PEMCertificateChain:_PEMCertificateChain
transportType:_transportType
transport:_transport
hostNameOverride:_hostNameOverride
logContext:_logContext
channelPoolDomain:_channelPoolDomain
@ -264,7 +256,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
PEMPrivateKey:[_PEMPrivateKey copy]
PEMCertificateChain:[_PEMCertificateChain copy]
transportType:_transportType
transport:_transport
hostNameOverride:[_hostNameOverride copy]
logContext:_logContext
channelPoolDomain:[_channelPoolDomain copy]
@ -289,7 +280,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
if (!areObjectsEqual(callOptions.PEMCertificateChain, _PEMCertificateChain)) return NO;
if (!areObjectsEqual(callOptions.hostNameOverride, _hostNameOverride)) return NO;
if (!(callOptions.transportType == _transportType)) return NO;
if (!(TransportIdIsEqual(callOptions.transport, _transport))) return NO;
if (!areObjectsEqual(callOptions.logContext, _logContext)) return NO;
if (!areObjectsEqual(callOptions.channelPoolDomain, _channelPoolDomain)) return NO;
if (!(callOptions.channelID == _channelID)) return NO;
@ -314,7 +304,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
result ^= _PEMCertificateChain.hash;
result ^= _hostNameOverride.hash;
result ^= _transportType;
result ^= TransportIdHash(_transport);
result ^= _logContext.hash;
result ^= _channelPoolDomain.hash;
result ^= _channelID;
@ -347,7 +336,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
@dynamic PEMPrivateKey;
@dynamic PEMCertificateChain;
@dynamic transportType;
@dynamic transport;
@dynamic hostNameOverride;
@dynamic logContext;
@dynamic channelPoolDomain;
@ -375,7 +363,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
PEMPrivateKey:kDefaultPEMPrivateKey
PEMCertificateChain:kDefaultPEMCertificateChain
transportType:kDefaultTransportType
transport:kDefaultTransport
hostNameOverride:kDefaultHostNameOverride
logContext:kDefaultLogContext
channelPoolDomain:kDefaultChannelPoolDomain
@ -405,7 +392,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
PEMPrivateKey:_PEMPrivateKey
PEMCertificateChain:_PEMCertificateChain
transportType:_transportType
transport:_transport
hostNameOverride:_hostNameOverride
logContext:_logContext
channelPoolDomain:_channelPoolDomain
@ -436,7 +422,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
PEMPrivateKey:_PEMPrivateKey
PEMCertificateChain:_PEMCertificateChain
transportType:_transportType
transport:_transport
hostNameOverride:_hostNameOverride
logContext:_logContext
channelPoolDomain:_channelPoolDomain
@ -460,7 +445,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
_flowControlEnabled = flowControlEnabled;
}
- (void)setInterceptorFactories:(NSArray<id<GRPCInterceptorFactory>> *)interceptorFactories {
- (void)setInterceptorFactories:(NSArray *)interceptorFactories {
_interceptorFactories = interceptorFactories;
}
@ -553,10 +538,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) {
_transportType = transportType;
}
- (void)setTransport:(GRPCTransportId)transport {
_transport = transport;
}
- (void)setHostNameOverride:(NSString *)hostNameOverride {
_hostNameOverride = [hostNameOverride copy];
}

@ -1,30 +0,0 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/**
* An object that processes its methods with a dispatch queue.
*/
@protocol GRPCDispatchable
/**
* The dispatch queue where the object's methods should be run on.
*/
@property(atomic, readonly) dispatch_queue_t dispatchQueue;
@end

@ -106,20 +106,22 @@
*/
#import "GRPCCall.h"
#import "GRPCDispatchable.h"
NS_ASSUME_NONNULL_BEGIN
@class GRPCInterceptorManager;
@class GRPCInterceptor;
@class GRPCRequestOptions;
@class GRPCCallOptions;
@protocol GRPCResponseHandler;
/**
* The GRPCInterceptorInterface defines the request events that can occur to an interceptr.
*/
@protocol GRPCInterceptorInterface<NSObject, GRPCDispatchable>
@protocol GRPCInterceptorInterface<NSObject>
/**
* The queue on which all methods of this interceptor should be dispatched on. The queue must be a
* serial queue.
*/
@property(readonly) dispatch_queue_t requestDispatchQueue;
/**
* To start the call. This method will only be called once for each instance.
@ -169,20 +171,19 @@ NS_ASSUME_NONNULL_BEGIN
* invoke shutDown method of its corresponding manager so that references to other interceptors can
* be released.
*/
@interface GRPCInterceptorManager : NSObject<GRPCInterceptorInterface, GRPCResponseHandler>
@interface GRPCInterceptorManager : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype) new NS_UNAVAILABLE;
- (nullable instancetype)initWithFactories:(nullable NSArray<id<GRPCInterceptorFactory>> *)factories
previousInterceptor:(nullable id<GRPCResponseHandler>)previousInterceptor
transportId:(GRPCTransportId)transportId;
- (nullable instancetype)initWithNextInterceptor:(id<GRPCInterceptorInterface>)nextInterceptor
NS_DESIGNATED_INITIALIZER;
/**
* Notify the manager that the interceptor has shut down and the manager should release references
* to other interceptors and stop forwarding requests/responses.
*/
/** Set the previous interceptor in the chain. Can only be set once. */
- (void)setPreviousInterceptor:(id<GRPCResponseHandler>)previousInterceptor;
/** Indicate shutdown of the interceptor; release the reference to other interceptors */
- (void)shutDown;
// Methods to forward GRPCInterceptorInterface calls to the next interceptor
@ -234,6 +235,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface GRPCInterceptor : NSObject<GRPCInterceptorInterface, GRPCResponseHandler>
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype) new NS_UNAVAILABLE;
/**
@ -241,7 +243,9 @@ NS_ASSUME_NONNULL_BEGIN
* that this interceptor's methods are dispatched onto.
*/
- (nullable instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
dispatchQueue:(dispatch_queue_t)dispatchQueue;
requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue
responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue
NS_DESIGNATED_INITIALIZER;
// Default implementation of GRPCInterceptorInterface

@ -19,253 +19,117 @@
#import <Foundation/Foundation.h>
#import "GRPCInterceptor.h"
#import "private/GRPCTransport+Private.h"
@interface GRPCInterceptorManager ()<GRPCInterceptorInterface, GRPCResponseHandler>
@end
@implementation GRPCInterceptorManager {
id<GRPCInterceptorInterface> _nextInterceptor;
id<GRPCResponseHandler> _previousInterceptor;
GRPCInterceptor *_thisInterceptor;
dispatch_queue_t _dispatchQueue;
NSArray<id<GRPCInterceptorFactory>> *_factories;
GRPCTransportId _transportId;
BOOL _shutDown;
}
- (instancetype)initWithFactories:(NSArray<id<GRPCInterceptorFactory>> *)factories
previousInterceptor:(id<GRPCResponseHandler>)previousInterceptor
transportId:(nonnull GRPCTransportId)transportId {
- (instancetype)initWithNextInterceptor:(id<GRPCInterceptorInterface>)nextInterceptor {
if ((self = [super init])) {
if (factories.count == 0) {
[NSException raise:NSInternalInconsistencyException
format:@"Interceptor manager must have factories"];
}
_thisInterceptor = [factories[0] createInterceptorWithManager:self];
if (_thisInterceptor == nil) {
return nil;
}
_previousInterceptor = previousInterceptor;
_factories = factories;
// Generate interceptor
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
if (@available(iOS 8.0, macOS 10.10, *)) {
_dispatchQueue = dispatch_queue_create(
NULL,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0));
} else {
#else
{
#endif
_dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
}
dispatch_set_target_queue(_dispatchQueue, _thisInterceptor.dispatchQueue);
_transportId = transportId;
_nextInterceptor = nextInterceptor;
}
return self;
}
- (void)shutDown {
dispatch_async(_dispatchQueue, ^{
self->_nextInterceptor = nil;
self->_previousInterceptor = nil;
self->_thisInterceptor = nil;
self->_shutDown = YES;
});
- (void)setPreviousInterceptor:(id<GRPCResponseHandler>)previousInterceptor {
_previousInterceptor = previousInterceptor;
}
- (void)createNextInterceptor {
NSAssert(_nextInterceptor == nil, @"Starting the next interceptor more than once");
NSAssert(_factories.count > 0, @"Interceptor manager of transport cannot start next interceptor");
if (_nextInterceptor != nil) {
NSLog(@"Starting the next interceptor more than once");
return;
}
NSMutableArray<id<GRPCInterceptorFactory>> *interceptorFactories = [NSMutableArray
arrayWithArray:[_factories subarrayWithRange:NSMakeRange(1, _factories.count - 1)]];
while (_nextInterceptor == nil) {
if (interceptorFactories.count == 0) {
_nextInterceptor =
[[GRPCTransportManager alloc] initWithTransportId:_transportId previousInterceptor:self];
break;
} else {
_nextInterceptor = [[GRPCInterceptorManager alloc] initWithFactories:interceptorFactories
previousInterceptor:self
transportId:_transportId];
if (_nextInterceptor == nil) {
[interceptorFactories removeObjectAtIndex:0];
}
}
}
NSAssert(_nextInterceptor != nil, @"Failed to create interceptor or transport.");
if (_nextInterceptor == nil) {
NSLog(@"Failed to create interceptor or transport.");
}
- (void)shutDown {
_nextInterceptor = nil;
_previousInterceptor = nil;
}
- (void)startNextInterceptorWithRequest:(GRPCRequestOptions *)requestOptions
callOptions:(GRPCCallOptions *)callOptions {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
if (_nextInterceptor != nil) {
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
[copiedNextInterceptor startWithRequestOptions:requestOptions callOptions:callOptions];
});
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor startWithRequestOptions:requestOptions callOptions:callOptions];
});
}
- (void)writeNextInterceptorWithData:(id)data {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
if (_nextInterceptor != nil) {
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
[copiedNextInterceptor writeData:data];
});
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor writeData:data];
});
}
- (void)finishNextInterceptor {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
if (_nextInterceptor != nil) {
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
[copiedNextInterceptor finish];
});
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor finish];
});
}
- (void)cancelNextInterceptor {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
if (_nextInterceptor != nil) {
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
[copiedNextInterceptor cancel];
});
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor cancel];
});
}
/** Notify the next interceptor in the chain to receive more messages */
- (void)receiveNextInterceptorMessages:(NSUInteger)numberOfMessages {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
if (_nextInterceptor != nil) {
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{
[copiedNextInterceptor receiveNextMessages:numberOfMessages];
});
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor receiveNextMessages:numberOfMessages];
});
}
// Methods to forward GRPCResponseHandler callbacks to the previous object
/** Forward initial metadata to the previous interceptor in the chain */
- (void)forwardPreviousInterceptorWithInitialMetadata:(NSDictionary *)initialMetadata {
if (_previousInterceptor == nil) {
return;
- (void)forwardPreviousInterceptorWithInitialMetadata:(nullable NSDictionary *)initialMetadata {
if ([_previousInterceptor respondsToSelector:@selector(didReceiveInitialMetadata:)]) {
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didReceiveInitialMetadata:initialMetadata];
});
}
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didReceiveInitialMetadata:initialMetadata];
});
}
/** Forward a received message to the previous interceptor in the chain */
- (void)forwardPreviousInterceptorWithData:(id)data {
if (_previousInterceptor == nil) {
return;
if ([_previousInterceptor respondsToSelector:@selector(didReceiveData:)]) {
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didReceiveData:data];
});
}
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didReceiveData:data];
});
}
/** Forward call close and trailing metadata to the previous interceptor in the chain */
- (void)forwardPreviousInterceptorCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata
error:(NSError *)error {
if (_previousInterceptor == nil) {
return;
- (void)forwardPreviousInterceptorCloseWithTrailingMetadata:
(nullable NSDictionary *)trailingMetadata
error:(nullable NSError *)error {
if ([_previousInterceptor respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error];
});
}
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error];
});
}
/** Forward write completion to the previous interceptor in the chain */
- (void)forwardPreviousInterceptorDidWriteData {
if (_previousInterceptor == nil) {
return;
}
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didWriteData];
});
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
callOptions:(GRPCCallOptions *)callOptions {
[_thisInterceptor startWithRequestOptions:requestOptions callOptions:callOptions];
}
- (void)writeData:(id)data {
[_thisInterceptor writeData:data];
}
- (void)finish {
[_thisInterceptor finish];
}
- (void)cancel {
[_thisInterceptor cancel];
}
- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
[_thisInterceptor receiveNextMessages:numberOfMessages];
}
- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata {
if ([_thisInterceptor respondsToSelector:@selector(didReceiveInitialMetadata:)]) {
[_thisInterceptor didReceiveInitialMetadata:initialMetadata];
}
}
- (void)didReceiveData:(id)data {
if ([_thisInterceptor respondsToSelector:@selector(didReceiveData:)]) {
[_thisInterceptor didReceiveData:data];
}
}
- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata
error:(nullable NSError *)error {
if ([_thisInterceptor respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
[_thisInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error];
}
}
- (void)didWriteData {
if ([_thisInterceptor respondsToSelector:@selector(didWriteData)]) {
[_thisInterceptor didWriteData];
if ([_previousInterceptor respondsToSelector:@selector(didWriteData)]) {
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didWriteData];
});
}
}
@ -273,21 +137,28 @@
@implementation GRPCInterceptor {
GRPCInterceptorManager *_manager;
dispatch_queue_t _dispatchQueue;
dispatch_queue_t _requestDispatchQueue;
dispatch_queue_t _responseDispatchQueue;
}
- (instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
dispatchQueue:(dispatch_queue_t)dispatchQueue {
requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue
responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue {
if ((self = [super init])) {
_manager = interceptorManager;
_dispatchQueue = dispatchQueue;
_requestDispatchQueue = requestDispatchQueue;
_responseDispatchQueue = responseDispatchQueue;
}
return self;
}
- (dispatch_queue_t)requestDispatchQueue {
return _requestDispatchQueue;
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
return _responseDispatchQueue;
}
- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions

@ -1,82 +0,0 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// The interface for a transport implementation
#import "GRPCInterceptor.h"
NS_ASSUME_NONNULL_BEGIN
#pragma mark Transport ID
/**
* The default transport implementations available in gRPC. These implementations will be provided
* by gRPC by default unless explicitly excluded.
*/
extern const struct GRPCDefaultTransportImplList {
const GRPCTransportId core_secure;
const GRPCTransportId core_insecure;
} GRPCDefaultTransportImplList;
/** Returns whether two transport id's are identical. */
BOOL TransportIdIsEqual(GRPCTransportId lhs, GRPCTransportId rhs);
/** Returns the hash value of a transport id. */
NSUInteger TransportIdHash(GRPCTransportId);
#pragma mark Transport and factory
@protocol GRPCInterceptorInterface;
@protocol GRPCResponseHandler;
@class GRPCTransportManager;
@class GRPCRequestOptions;
@class GRPCCallOptions;
@class GRPCTransport;
/** The factory method to create a transport. */
@protocol GRPCTransportFactory<NSObject>
- (GRPCTransport *)createTransportWithManager:(GRPCTransportManager *)transportManager;
@end
/** The registry of transport implementations. */
@interface GRPCTransportRegistry : NSObject
+ (instancetype)sharedInstance;
/**
* Register a transport implementation with the registry. All transport implementations to be used
* in a process must register with the registry on process start-up in its +load: class method.
* Parameter \a transportId is the identifier of the implementation, and \a factory is the factory
* object to create the corresponding transport instance.
*/
- (void)registerTransportWithId:(GRPCTransportId)transportId
factory:(id<GRPCTransportFactory>)factory;
@end
/**
* Base class for transport implementations. All transport implementation should inherit from this
* class.
*/
@interface GRPCTransport : NSObject<GRPCInterceptorInterface>
@end
NS_ASSUME_NONNULL_END

@ -1,142 +0,0 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import "GRPCTransport.h"
static const GRPCTransportId gGRPCCoreSecureId = "io.grpc.transport.core.secure";
static const GRPCTransportId gGRPCCoreInsecureId = "io.grpc.transport.core.insecure";
const struct GRPCDefaultTransportImplList GRPCDefaultTransportImplList = {
.core_secure = gGRPCCoreSecureId, .core_insecure = gGRPCCoreInsecureId};
static const GRPCTransportId gDefaultTransportId = gGRPCCoreSecureId;
static GRPCTransportRegistry *gTransportRegistry = nil;
static dispatch_once_t initTransportRegistry;
BOOL TransportIdIsEqual(GRPCTransportId lhs, GRPCTransportId rhs) {
// Directly comparing pointers works because we require users to use the id provided by each
// implementation, not coming up with their own string.
return lhs == rhs;
}
NSUInteger TransportIdHash(GRPCTransportId transportId) {
if (transportId == NULL) {
transportId = gDefaultTransportId;
}
return [NSString stringWithCString:transportId encoding:NSUTF8StringEncoding].hash;
}
@implementation GRPCTransportRegistry {
NSMutableDictionary<NSString *, id<GRPCTransportFactory>> *_registry;
id<GRPCTransportFactory> _defaultFactory;
}
+ (instancetype)sharedInstance {
dispatch_once(&initTransportRegistry, ^{
gTransportRegistry = [[GRPCTransportRegistry alloc] init];
NSAssert(gTransportRegistry != nil, @"Unable to initialize transport registry.");
if (gTransportRegistry == nil) {
NSLog(@"Unable to initialize transport registry.");
[NSException raise:NSGenericException format:@"Unable to initialize transport registry."];
}
});
return gTransportRegistry;
}
- (instancetype)init {
if ((self = [super init])) {
_registry = [NSMutableDictionary dictionary];
}
return self;
}
- (void)registerTransportWithId:(GRPCTransportId)transportId
factory:(id<GRPCTransportFactory>)factory {
NSString *nsTransportId = [NSString stringWithCString:transportId encoding:NSUTF8StringEncoding];
NSAssert(_registry[nsTransportId] == nil, @"The transport %@ has already been registered.",
nsTransportId);
if (_registry[nsTransportId] != nil) {
NSLog(@"The transport %@ has already been registered.", nsTransportId);
return;
}
_registry[nsTransportId] = factory;
// if the default transport is registered, mark it.
if (0 == strcmp(transportId, gDefaultTransportId)) {
_defaultFactory = factory;
}
}
- (id<GRPCTransportFactory>)getTransportFactoryWithId:(GRPCTransportId)transportId {
if (transportId == NULL) {
if (_defaultFactory == nil) {
[NSException raise:NSInvalidArgumentException
format:@"Unable to get default transport factory"];
return nil;
}
return _defaultFactory;
}
NSString *nsTransportId = [NSString stringWithCString:transportId encoding:NSUTF8StringEncoding];
id<GRPCTransportFactory> transportFactory = _registry[nsTransportId];
if (transportFactory == nil) {
// User named a transport id that was not registered with the registry.
[NSException raise:NSInvalidArgumentException
format:@"Unable to get transport factory with id %s", transportId];
return nil;
}
return transportFactory;
}
@end
@implementation GRPCTransport
- (dispatch_queue_t)dispatchQueue {
[NSException raise:NSGenericException
format:@"Implementations should override the dispatch queue"];
return nil;
}
- (void)startWithRequestOptions:(nonnull GRPCRequestOptions *)requestOptions
callOptions:(nonnull GRPCCallOptions *)callOptions {
[NSException raise:NSGenericException
format:@"Implementations should override the methods of GRPCTransport"];
}
- (void)writeData:(nonnull id)data {
[NSException raise:NSGenericException
format:@"Implementations should override the methods of GRPCTransport"];
}
- (void)cancel {
[NSException raise:NSGenericException
format:@"Implementations should override the methods of GRPCTransport"];
}
- (void)finish {
[NSException raise:NSGenericException
format:@"Implementations should override the methods of GRPCTransport"];
}
- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
[NSException raise:NSGenericException
format:@"Implementations should override the methods of GRPCTransport"];
}
@end

@ -1,187 +0,0 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/**
* gRPC error codes.
* Note that a few of these are never produced by the gRPC libraries, but are of
* general utility for server applications to produce.
*/
typedef NS_ENUM(NSUInteger, GRPCErrorCode) {
/** The operation was cancelled (typically by the caller). */
GRPCErrorCodeCancelled = 1,
/**
* Unknown error. Errors raised by APIs that do not return enough error
* information may be converted to this error.
*/
GRPCErrorCodeUnknown = 2,
/**
* The client specified an invalid argument. Note that this differs from
* FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
* problematic regardless of the state of the server (e.g., a malformed file
* name).
*/
GRPCErrorCodeInvalidArgument = 3,
/**
* Deadline expired before operation could complete. For operations that
* change the state of the server, this error may be returned even if the
* operation has completed successfully. For example, a successful response
* from the server could have been delayed long enough for the deadline to
* expire.
*/
GRPCErrorCodeDeadlineExceeded = 4,
/** Some requested entity (e.g., file or directory) was not found. */
GRPCErrorCodeNotFound = 5,
/** Some entity that we attempted to create (e.g., file or directory) already
exists. */
GRPCErrorCodeAlreadyExists = 6,
/**
* The caller does not have permission to execute the specified operation.
* PERMISSION_DENIED isn't used for rejections caused by exhausting some
* resource (RESOURCE_EXHAUSTED is used instead for those errors).
* PERMISSION_DENIED doesn't indicate a failure to identify the caller
* (UNAUTHENTICATED is used instead for those errors).
*/
GRPCErrorCodePermissionDenied = 7,
/**
* The request does not have valid authentication credentials for the
* operation (e.g. the caller's identity can't be verified).
*/
GRPCErrorCodeUnauthenticated = 16,
/** Some resource has been exhausted, perhaps a per-user quota. */
GRPCErrorCodeResourceExhausted = 8,
/**
* The RPC was rejected because the server is not in a state required for the
* procedure's execution. For example, a directory to be deleted may be
* non-empty, etc. The client should not retry until the server state has been
* explicitly fixed (e.g. by performing another RPC). The details depend on
* the service being called, and should be found in the NSError's userInfo.
*/
GRPCErrorCodeFailedPrecondition = 9,
/**
* The RPC was aborted, typically due to a concurrency issue like sequencer
* check failures, transaction aborts, etc. The client should retry at a
* higher-level (e.g., restarting a read- modify-write sequence).
*/
GRPCErrorCodeAborted = 10,
/**
* The RPC was attempted past the valid range. E.g., enumerating past the end
* of a list. Unlike INVALID_ARGUMENT, this error indicates a problem that may
* be fixed if the system state changes. For example, an RPC to get elements
* of a list will generate INVALID_ARGUMENT if asked to return the element at
* a negative index, but it will generate OUT_OF_RANGE if asked to return the
* element at an index past the current size of the list.
*/
GRPCErrorCodeOutOfRange = 11,
/** The procedure is not implemented or not supported/enabled in this server.
*/
GRPCErrorCodeUnimplemented = 12,
/**
* Internal error. Means some invariant expected by the server application or
* the gRPC library has been broken.
*/
GRPCErrorCodeInternal = 13,
/**
* The server is currently unavailable. This is most likely a transient
* condition and may be corrected by retrying with a backoff. Note that it is
* not always safe to retry non-idempotent operations.
*/
GRPCErrorCodeUnavailable = 14,
/** Unrecoverable data loss or corruption. */
GRPCErrorCodeDataLoss = 15,
};
/**
* Safety remark of a gRPC method as defined in RFC 2616 Section 9.1
*/
typedef NS_ENUM(NSUInteger, GRPCCallSafety) {
/**
* Signal that there is no guarantees on how the call affects the server
* state.
*/
GRPCCallSafetyDefault = 0,
/** Signal that the call is idempotent. gRPC is free to use PUT verb. */
GRPCCallSafetyIdempotentRequest = 1,
/**
* Signal that the call is cacheable and will not affect server state. gRPC is
* free to use GET verb.
*/
GRPCCallSafetyCacheableRequest = 2,
};
// Compression algorithm to be used by a gRPC call
typedef NS_ENUM(NSUInteger, GRPCCompressionAlgorithm) {
GRPCCompressNone = 0,
GRPCCompressDeflate,
GRPCCompressGzip,
GRPCStreamCompressGzip,
};
// GRPCCompressAlgorithm is deprecated; use GRPCCompressionAlgorithm
typedef GRPCCompressionAlgorithm GRPCCompressAlgorithm;
/** The transport to be used by a gRPC call */
typedef NS_ENUM(NSUInteger, GRPCTransportType) {
GRPCTransportTypeDefault = 0,
/** gRPC internal HTTP/2 stack with BoringSSL */
GRPCTransportTypeChttp2BoringSSL = 0,
/** Cronet stack */
GRPCTransportTypeCronet,
/** Insecure channel. FOR TEST ONLY! */
GRPCTransportTypeInsecure,
};
/** Domain of NSError objects produced by gRPC. */
extern NSString* _Nonnull const kGRPCErrorDomain;
/**
* Keys used in |NSError|'s |userInfo| dictionary to store the response headers
* and trailers sent by the server.
*/
extern NSString* _Nonnull const kGRPCHeadersKey;
extern NSString* _Nonnull const kGRPCTrailersKey;
/** The id of a transport implementation. */
typedef char* _Nonnull GRPCTransportId;
/**
* Implement this protocol to provide a token to gRPC when a call is initiated.
*/
@protocol GRPCAuthorizationProtocol
/**
* This method is called when gRPC is about to start the call. When OAuth token is acquired,
* \a handler is expected to be called with \a token being the new token to be used for this call.
*/
- (void)getTokenWithHandler:(void (^_Nonnull)(NSString* _Nullable token))handler;
@end

@ -20,7 +20,7 @@
#import "GRPCCall+InternalTests.h"
#import "../private/GRPCCore/GRPCOpBatchLog.h"
#import "../private/GRPCOpBatchLog.h"
@implementation GRPCCall (InternalTests)

@ -18,6 +18,12 @@
@interface GRPCCall (V2API)
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
callSafety:(GRPCCallSafety)safety
requestsWriter:(GRXWriter *)requestsWriter
callOptions:(GRPCCallOptions *)callOptions;
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
callSafety:(GRPCCallSafety)safety

@ -16,22 +16,20 @@
*
*/
#import <GRPCClient/GRPCTransport.h>
#import <GRPCClient/GRPCInterceptor.h>
NS_ASSUME_NONNULL_BEGIN
@protocol GRPCResponseHandler;
@class GRPCCallOptions;
@protocol GRPCChannelFactory;
@interface GRPCCall2Internal : NSObject<GRPCInterceptorInterface>
@interface GRPCCall2Internal : GRPCTransport
- (instancetype)init;
- (instancetype)initWithTransportManager:(GRPCTransportManager *)transportManager;
- (void)setResponseHandler:(id<GRPCResponseHandler>)responseHandler;
- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
callOptions:(GRPCCallOptions *)callOptions;
callOptions:(nullable GRPCCallOptions *)callOptions;
- (void)writeData:(id)data;
- (void)writeData:(NSData *)data;
- (void)finish;

@ -19,10 +19,8 @@
#import "GRPCCallInternal.h"
#import <GRPCClient/GRPCCall.h>
#import <GRPCClient/GRPCInterceptor.h>
#import <RxLibrary/GRXBufferedPipe.h>
#import "../GRPCTransport+Private.h"
#import "GRPCCall+V2API.h"
@implementation GRPCCall2Internal {
@ -30,8 +28,8 @@
GRPCRequestOptions *_requestOptions;
/** Options for the call. */
GRPCCallOptions *_callOptions;
/** The interceptor manager to process responses. */
GRPCTransportManager *_transportManager;
/** The handler of responses. */
id<GRPCResponseHandler> _handler;
/**
* Make use of legacy GRPCCall to make calls. Nullified when call is finished.
@ -53,28 +51,40 @@
NSUInteger _pendingReceiveNextMessages;
}
- (instancetype)initWithTransportManager:(GRPCTransportManager *)transportManager {
dispatch_queue_t dispatchQueue;
- (instancetype)init {
if ((self = [super init])) {
// Set queue QoS only when iOS version is 8.0 or above and Xcode version is 9.0 or above
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
if (@available(iOS 8.0, macOS 10.10, *)) {
dispatchQueue = dispatch_queue_create(
NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0));
} else {
if (@available(iOS 8.0, macOS 10.10, *)) {
_dispatchQueue = dispatch_queue_create(
NULL,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0));
} else {
#else
{
{
#endif
dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
}
if ((self = [super init])) {
_dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
}
_pipe = [GRXBufferedPipe pipe];
_transportManager = transportManager;
_dispatchQueue = dispatchQueue;
}
return self;
}
- (dispatch_queue_t)dispatchQueue {
- (void)setResponseHandler:(id<GRPCResponseHandler>)responseHandler {
@synchronized(self) {
NSAssert(!_started, @"Call already started.");
if (_started) {
return;
}
_handler = responseHandler;
_initialMetadataPublished = NO;
_started = NO;
_canceled = NO;
_finished = NO;
}
}
- (dispatch_queue_t)requestDispatchQueue {
return _dispatchQueue;
}
@ -92,15 +102,26 @@
return;
}
GRPCCall *copiedCall = nil;
@synchronized(self) {
NSAssert(_handler != nil, @"Response handler required.");
if (_handler == nil) {
NSLog(@"Invalid response handler.");
return;
}
_requestOptions = requestOptions;
if (callOptions == nil) {
_callOptions = [[GRPCCallOptions alloc] init];
} else {
_callOptions = [callOptions copy];
}
}
[self start];
}
- (void)start {
GRPCCall *copiedCall = nil;
@synchronized(self) {
NSAssert(!_started, @"Call already started.");
NSAssert(!_canceled, @"Call already canceled.");
if (_started) {
@ -119,7 +140,7 @@
callOptions:_callOptions
writeDone:^{
@synchronized(self) {
if (self->_transportManager) {
if (self->_handler) {
[self issueDidWriteData];
}
}
@ -137,7 +158,7 @@
void (^valueHandler)(id value) = ^(id value) {
@synchronized(self) {
if (self->_transportManager) {
if (self->_handler) {
if (!self->_initialMetadataPublished) {
self->_initialMetadataPublished = YES;
[self issueInitialMetadata:self->_call.responseHeaders];
@ -150,7 +171,7 @@
};
void (^completionHandler)(NSError *errorOrNil) = ^(NSError *errorOrNil) {
@synchronized(self) {
if (self->_transportManager) {
if (self->_handler) {
if (!self->_initialMetadataPublished) {
self->_initialMetadataPublished = YES;
[self issueInitialMetadata:self->_call.responseHeaders];
@ -186,19 +207,20 @@
_call = nil;
_pipe = nil;
if (_transportManager != nil) {
[_transportManager
forwardPreviousInterceptorCloseWithTrailingMetadata:nil
error:
[NSError
errorWithDomain:kGRPCErrorDomain
code:
GRPCErrorCodeCancelled
userInfo:@{
NSLocalizedDescriptionKey :
@"Canceled by app"
}]];
[_transportManager shutDown];
if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
id<GRPCResponseHandler> copiedHandler = _handler;
_handler = nil;
dispatch_async(copiedHandler.dispatchQueue, ^{
[copiedHandler didCloseWithTrailingMetadata:nil
error:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{
NSLocalizedDescriptionKey :
@"Canceled by app"
}]];
});
} else {
_handler = nil;
}
}
[copiedCall cancel];
@ -249,25 +271,59 @@
}
- (void)issueInitialMetadata:(NSDictionary *)initialMetadata {
if (initialMetadata != nil) {
[_transportManager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
@synchronized(self) {
if (initialMetadata != nil &&
[_handler respondsToSelector:@selector(didReceiveInitialMetadata:)]) {
id<GRPCResponseHandler> copiedHandler = _handler;
dispatch_async(_handler.dispatchQueue, ^{
[copiedHandler didReceiveInitialMetadata:initialMetadata];
});
}
}
}
- (void)issueMessage:(id)message {
if (message != nil) {
[_transportManager forwardPreviousInterceptorWithData:message];
@synchronized(self) {
if (message != nil) {
if ([_handler respondsToSelector:@selector(didReceiveData:)]) {
id<GRPCResponseHandler> copiedHandler = _handler;
dispatch_async(_handler.dispatchQueue, ^{
[copiedHandler didReceiveData:message];
});
} else if ([_handler respondsToSelector:@selector(didReceiveRawMessage:)]) {
id<GRPCResponseHandler> copiedHandler = _handler;
dispatch_async(_handler.dispatchQueue, ^{
[copiedHandler didReceiveRawMessage:message];
});
}
}
}
}
- (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
[_transportManager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata
error:error];
[_transportManager shutDown];
@synchronized(self) {
if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
id<GRPCResponseHandler> copiedHandler = _handler;
// Clean up _handler so that no more responses are reported to the handler.
_handler = nil;
dispatch_async(copiedHandler.dispatchQueue, ^{
[copiedHandler didCloseWithTrailingMetadata:trailingMetadata error:error];
});
} else {
_handler = nil;
}
}
}
- (void)issueDidWriteData {
[_transportManager forwardPreviousInterceptorDidWriteData];
@synchronized(self) {
if (_callOptions.flowControlEnabled && [_handler respondsToSelector:@selector(didWriteData)]) {
id<GRPCResponseHandler> copiedHandler = _handler;
dispatch_async(copiedHandler.dispatchQueue, ^{
[copiedHandler didWriteData];
});
}
}
}
- (void)receiveNextMessages:(NSUInteger)numberOfMessages {

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

Loading…
Cancel
Save