Merge branch 'master' into minor-timer-fix

pull/15813/head
Sree Kuchibhotla 7 years ago
commit d69fdefcfa
  1. 6
      .github/CODEOWNERS
  2. 5
      BUILD
  3. 43
      CMakeLists.txt
  4. 54
      Makefile
  5. 16
      build.yaml
  6. 2
      cmake/OWNERS
  7. 2
      config.m4
  8. 2
      config.w32
  9. 4
      doc/environment_variables.md
  10. 2
      doc/server-reflection.md
  11. 36
      doc/ssl-performance.md
  12. 203
      etc/roots.pem
  13. 2
      gRPC-C++.podspec
  14. 7
      gRPC-Core.podspec
  15. 1
      grpc.def
  16. 4
      grpc.gemspec
  17. 2
      grpc.gyp
  18. 4
      include/grpc/grpc.h
  19. 4
      include/grpcpp/impl/codegen/async_generic_service.h
  20. 16
      include/grpcpp/resource_quota.h
  21. 7
      include/grpcpp/server.h
  22. 4
      package.xml
  23. 39
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  24. 12
      src/core/ext/transport/chttp2/transport/flow_control.cc
  25. 13
      src/core/ext/transport/chttp2/transport/internal.h
  26. 17
      src/core/ext/transport/chttp2/transport/stream_lists.cc
  27. 5
      src/core/lib/iomgr/call_combiner.h
  28. 75
      src/core/lib/iomgr/iomgr_posix_cfstream.cc
  29. 5
      src/core/lib/iomgr/port.h
  30. 78
      src/core/lib/iomgr/resource_quota.cc
  31. 16
      src/core/lib/iomgr/resource_quota.h
  32. 2
      src/core/lib/iomgr/tcp_client_cfstream.cc
  33. 29
      src/core/lib/security/security_connector/load_system_roots.h
  34. 32
      src/core/lib/security/security_connector/load_system_roots_fallback.cc
  35. 165
      src/core/lib/security/security_connector/load_system_roots_linux.cc
  36. 44
      src/core/lib/security/security_connector/load_system_roots_linux.h
  37. 18
      src/core/lib/security/security_connector/security_connector.cc
  38. 4
      src/core/lib/security/transport/client_auth_filter.cc
  39. 2
      src/core/lib/security/transport/server_auth_filter.cc
  40. 5
      src/core/lib/surface/call.cc
  41. 4
      src/cpp/common/resource_quota_cc.cc
  42. 2
      src/cpp/server/server_builder.cc
  43. 31
      src/cpp/server/server_cc.cc
  44. 45
      src/cpp/thread_manager/thread_manager.cc
  45. 48
      src/cpp/thread_manager/thread_manager.h
  46. 4
      src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
  47. 6
      src/csharp/Grpc.Core.Tests/SanityTest.cs
  48. 18
      src/csharp/Grpc.Core/Grpc.Core.csproj
  49. 22
      src/csharp/Grpc.Core/GrpcEnvironment.cs
  50. 29
      src/csharp/Grpc.Core/Internal/PlatformApis.cs
  51. 2
      src/csharp/Grpc.Core/Version.csproj.include
  52. 9
      src/csharp/Grpc.Core/build/MonoAndroid10/Grpc.Core.targets
  53. 4
      src/csharp/Grpc.Core/build/Xamarin.iOS10/Grpc.Core.targets
  54. 4
      src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
  55. 4
      src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
  56. 4
      src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
  57. 4
      src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
  58. 38
      src/objective-c/GRPCClient/GRPCCall.m
  59. 5
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
  60. 15
      src/objective-c/GRPCClient/private/GRPCHost.m
  61. 8
      src/objective-c/GRPCClient/private/GRPCWrappedCall.m
  62. 4
      src/objective-c/GRPCClient/private/NSError+GRPC.h
  63. 10
      src/objective-c/GRPCClient/private/NSError+GRPC.m
  64. 14
      src/objective-c/README-CFSTREAM.md
  65. 35
      src/objective-c/tests/GRPCClientTests.m
  66. 5
      src/objective-c/tests/InteropTests.m
  67. 30
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  68. 12
      src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
  69. 2
      src/python/grpcio/grpc_core_dependencies.py
  70. 2
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  71. 3
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  72. 2
      templates/src/csharp/Grpc.Core/Version.csproj.include.template
  73. 97
      test/core/iomgr/resource_quota_test.cc
  74. 21
      test/core/security/BUILD
  75. 22
      test/core/security/etc/BUILD
  76. 2
      test/core/security/etc/README
  77. 63
      test/core/security/etc/bundle.pem
  78. 21
      test/core/security/etc/test_roots/cert1.pem
  79. 21
      test/core/security/etc/test_roots/cert2.pem
  80. 21
      test/core/security/etc/test_roots/cert3.pem
  81. 104
      test/core/security/linux_system_roots_test.cc
  82. 12
      test/core/security/security_connector_test.cc
  83. 1
      test/core/surface/public_headers_must_be_c89.c
  84. 20
      test/cpp/interop/client_helper.cc
  85. 147
      test/cpp/thread_manager/thread_manager_test.cc
  86. 2
      tools/dockerfile/OWNERS
  87. 3
      tools/dockerfile/distribtest/csharp_centos7_x64/Dockerfile
  88. 4
      tools/dockerfile/distribtest/csharp_jessie_x64/Dockerfile
  89. 4
      tools/dockerfile/distribtest/csharp_jessie_x86/Dockerfile
  90. 4
      tools/dockerfile/distribtest/csharp_ubuntu1404_x64/Dockerfile
  91. 4
      tools/dockerfile/distribtest/csharp_ubuntu1604_x64/Dockerfile
  92. 1
      tools/doxygen/Doxyfile.c++
  93. 1
      tools/doxygen/Doxyfile.c++.internal
  94. 1
      tools/doxygen/Doxyfile.core
  95. 5
      tools/doxygen/Doxyfile.core.internal
  96. 11
      tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc
  97. 2
      tools/internal_ci/macos/grpc_interop_toprod.sh
  98. 10
      tools/interop_matrix/client_matrix.py
  99. 11
      tools/run_tests/artifacts/artifact_targets.py
  100. 4
      tools/run_tests/dockerize/build_and_run_docker.sh
  101. Some files were not shown because too many files have changed in this diff Show More

@ -3,7 +3,7 @@
# repository as the source of truth for module ownership.
/**/OWNERS @markdroth @nicolasnoble @a11r
/bazel/** @nicolasnoble @dgquintas @a11r @vjpai
/cmake/** @jtattermusch @nicolasnoble @matt-kwong
/cmake/** @jtattermusch @nicolasnoble @mehrdada
/src/core/ext/filters/client_channel/** @markdroth @dgquintas @AspirinSJL
/tools/dockerfile/** @jtattermusch @matt-kwong @nicolasnoble
/tools/run_tests/performance/** @ncteisen @matt-kwong @jtattermusch
/tools/dockerfile/** @jtattermusch @mehrdada @nicolasnoble
/tools/run_tests/performance/** @ncteisen @apolcyn @jtattermusch

@ -1010,6 +1010,7 @@ grpc_cc_library(
"src/core/lib/iomgr/cfstream_handle.cc",
"src/core/lib/iomgr/endpoint_cfstream.cc",
"src/core/lib/iomgr/error_cfstream.cc",
"src/core/lib/iomgr/iomgr_posix_cfstream.cc",
"src/core/lib/iomgr/tcp_client_cfstream.cc",
],
hdrs = [
@ -1499,6 +1500,8 @@ grpc_cc_library(
"src/core/lib/security/credentials/plugin/plugin_credentials.cc",
"src/core/lib/security/credentials/ssl/ssl_credentials.cc",
"src/core/lib/security/security_connector/alts_security_connector.cc",
"src/core/lib/security/security_connector/load_system_roots_fallback.cc",
"src/core/lib/security/security_connector/load_system_roots_linux.cc",
"src/core/lib/security/security_connector/local_security_connector.cc",
"src/core/lib/security/security_connector/security_connector.cc",
"src/core/lib/security/transport/client_auth_filter.cc",
@ -1527,6 +1530,8 @@ grpc_cc_library(
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/security_connector/alts_security_connector.h",
"src/core/lib/security/security_connector/load_system_roots.h",
"src/core/lib/security/security_connector/load_system_roots_linux.h",
"src/core/lib/security/security_connector/local_security_connector.h",
"src/core/lib/security/security_connector/security_connector.h",
"src/core/lib/security/transport/auth_filters.h",

@ -581,6 +581,7 @@ add_dependencies(buildtests_cxx generic_end2end_test)
add_dependencies(buildtests_cxx golden_file_test)
add_dependencies(buildtests_cxx grpc_alts_credentials_options_test)
add_dependencies(buildtests_cxx grpc_cli)
add_dependencies(buildtests_cxx grpc_linux_system_roots_test)
add_dependencies(buildtests_cxx grpc_tool_test)
add_dependencies(buildtests_cxx grpclb_api_test)
add_dependencies(buildtests_cxx grpclb_end2end_test)
@ -1129,6 +1130,8 @@ add_library(grpc
src/core/lib/security/credentials/plugin/plugin_credentials.cc
src/core/lib/security/credentials/ssl/ssl_credentials.cc
src/core/lib/security/security_connector/alts_security_connector.cc
src/core/lib/security/security_connector/load_system_roots_fallback.cc
src/core/lib/security/security_connector/load_system_roots_linux.cc
src/core/lib/security/security_connector/local_security_connector.cc
src/core/lib/security/security_connector/security_connector.cc
src/core/lib/security/transport/client_auth_filter.cc
@ -1559,6 +1562,8 @@ add_library(grpc_cronet
src/core/lib/security/credentials/plugin/plugin_credentials.cc
src/core/lib/security/credentials/ssl/ssl_credentials.cc
src/core/lib/security/security_connector/alts_security_connector.cc
src/core/lib/security/security_connector/load_system_roots_fallback.cc
src/core/lib/security/security_connector/load_system_roots_linux.cc
src/core/lib/security/security_connector/local_security_connector.cc
src/core/lib/security/security_connector/security_connector.cc
src/core/lib/security/transport/client_auth_filter.cc
@ -12146,6 +12151,44 @@ if (gRPC_INSTALL)
endif()
endif (gRPC_BUILD_CODEGEN)
if (gRPC_BUILD_TESTS)
add_executable(grpc_linux_system_roots_test
test/core/security/linux_system_roots_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(grpc_linux_system_roots_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(grpc_linux_system_roots_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr_test_util
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_CODEGEN)
add_executable(grpc_node_plugin

@ -1170,6 +1170,7 @@ grpc_alts_credentials_options_test: $(BINDIR)/$(CONFIG)/grpc_alts_credentials_op
grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli
grpc_cpp_plugin: $(BINDIR)/$(CONFIG)/grpc_cpp_plugin
grpc_csharp_plugin: $(BINDIR)/$(CONFIG)/grpc_csharp_plugin
grpc_linux_system_roots_test: $(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test
grpc_node_plugin: $(BINDIR)/$(CONFIG)/grpc_node_plugin
grpc_objective_c_plugin: $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin
grpc_php_plugin: $(BINDIR)/$(CONFIG)/grpc_php_plugin
@ -1670,6 +1671,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/golden_file_test \
$(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \
$(BINDIR)/$(CONFIG)/grpc_cli \
$(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test \
$(BINDIR)/$(CONFIG)/grpc_tool_test \
$(BINDIR)/$(CONFIG)/grpclb_api_test \
$(BINDIR)/$(CONFIG)/grpclb_end2end_test \
@ -1849,6 +1851,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/golden_file_test \
$(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \
$(BINDIR)/$(CONFIG)/grpc_cli \
$(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test \
$(BINDIR)/$(CONFIG)/grpc_tool_test \
$(BINDIR)/$(CONFIG)/grpclb_api_test \
$(BINDIR)/$(CONFIG)/grpclb_end2end_test \
@ -2316,6 +2319,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/golden_file_test || ( echo test golden_file_test failed ; exit 1 )
$(E) "[RUN] Testing grpc_alts_credentials_options_test"
$(Q) $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test || ( echo test grpc_alts_credentials_options_test failed ; exit 1 )
$(E) "[RUN] Testing grpc_linux_system_roots_test"
$(Q) $(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test || ( echo test grpc_linux_system_roots_test failed ; exit 1 )
$(E) "[RUN] Testing grpc_tool_test"
$(Q) $(BINDIR)/$(CONFIG)/grpc_tool_test || ( echo test grpc_tool_test failed ; exit 1 )
$(E) "[RUN] Testing grpclb_api_test"
@ -3608,6 +3613,8 @@ LIBGRPC_SRC = \
src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/security_connector/alts_security_connector.cc \
src/core/lib/security/security_connector/load_system_roots_fallback.cc \
src/core/lib/security/security_connector/load_system_roots_linux.cc \
src/core/lib/security/security_connector/local_security_connector.cc \
src/core/lib/security/security_connector/security_connector.cc \
src/core/lib/security/transport/client_auth_filter.cc \
@ -4037,6 +4044,8 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/security_connector/alts_security_connector.cc \
src/core/lib/security/security_connector/load_system_roots_fallback.cc \
src/core/lib/security/security_connector/load_system_roots_linux.cc \
src/core/lib/security/security_connector/local_security_connector.cc \
src/core/lib/security/security_connector/security_connector.cc \
src/core/lib/security/transport/client_auth_filter.cc \
@ -17907,6 +17916,49 @@ ifneq ($(NO_DEPS),true)
endif
GRPC_LINUX_SYSTEM_ROOTS_TEST_SRC = \
test/core/security/linux_system_roots_test.cc \
GRPC_LINUX_SYSTEM_ROOTS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_LINUX_SYSTEM_ROOTS_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
$(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test: $(PROTOBUF_DEP) $(GRPC_LINUX_SYSTEM_ROOTS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(GRPC_LINUX_SYSTEM_ROOTS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/security/linux_system_roots_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_grpc_linux_system_roots_test: $(GRPC_LINUX_SYSTEM_ROOTS_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GRPC_LINUX_SYSTEM_ROOTS_TEST_OBJS:.o=.dep)
endif
endif
GRPC_NODE_PLUGIN_SRC = \
src/compiler/node_plugin.cc \
@ -24651,6 +24703,8 @@ src/core/lib/security/credentials/oauth2/oauth2_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/plugin/plugin_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/ssl/ssl_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/alts_security_connector.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/load_system_roots_fallback.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/load_system_roots_linux.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/local_security_connector.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/security_connector.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/client_auth_filter.cc: $(OPENSSL_DEP)

@ -548,6 +548,7 @@ filegroups:
- src/core/lib/iomgr/cfstream_handle.cc
- src/core/lib/iomgr/endpoint_cfstream.cc
- src/core/lib/iomgr/error_cfstream.cc
- src/core/lib/iomgr/iomgr_posix_cfstream.cc
- src/core/lib/iomgr/tcp_client_cfstream.cc
uses:
- grpc_base_headers
@ -792,6 +793,8 @@ filegroups:
- src/core/lib/security/credentials/plugin/plugin_credentials.h
- src/core/lib/security/credentials/ssl/ssl_credentials.h
- src/core/lib/security/security_connector/alts_security_connector.h
- src/core/lib/security/security_connector/load_system_roots.h
- src/core/lib/security/security_connector/load_system_roots_linux.h
- src/core/lib/security/security_connector/local_security_connector.h
- src/core/lib/security/security_connector/security_connector.h
- src/core/lib/security/transport/auth_filters.h
@ -819,6 +822,8 @@ filegroups:
- src/core/lib/security/credentials/plugin/plugin_credentials.cc
- src/core/lib/security/credentials/ssl/ssl_credentials.cc
- src/core/lib/security/security_connector/alts_security_connector.cc
- src/core/lib/security/security_connector/load_system_roots_fallback.cc
- src/core/lib/security/security_connector/load_system_roots_linux.cc
- src/core/lib/security/security_connector/local_security_connector.cc
- src/core/lib/security/security_connector/security_connector.cc
- src/core/lib/security/transport/client_auth_filter.cc
@ -4698,6 +4703,17 @@ targets:
secure: false
vs_config_type: Application
vs_project_guid: '{3C813052-A49A-4662-B90A-1ADBEC7EE453}'
- name: grpc_linux_system_roots_test
gtest: true
build: test
language: c++
src:
- test/core/security/linux_system_roots_test.cc
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: grpc_node_plugin
build: protoc
language: c++

@ -1,4 +1,4 @@
set noparent
@jtattermusch
@nicolasnoble
@matt-kwong
@mehrdada

@ -280,6 +280,8 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/security_connector/alts_security_connector.cc \
src/core/lib/security/security_connector/load_system_roots_fallback.cc \
src/core/lib/security/security_connector/load_system_roots_linux.cc \
src/core/lib/security/security_connector/local_security_connector.cc \
src/core/lib/security/security_connector/security_connector.cc \
src/core/lib/security/transport/client_auth_filter.cc \

@ -255,6 +255,8 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\security\\credentials\\plugin\\plugin_credentials.cc " +
"src\\core\\lib\\security\\credentials\\ssl\\ssl_credentials.cc " +
"src\\core\\lib\\security\\security_connector\\alts_security_connector.cc " +
"src\\core\\lib\\security\\security_connector\\load_system_roots_fallback.cc " +
"src\\core\\lib\\security\\security_connector\\load_system_roots_linux.cc " +
"src\\core\\lib\\security\\security_connector\\local_security_connector.cc " +
"src\\core\\lib\\security\\security_connector\\security_connector.cc " +
"src\\core\\lib\\security\\transport\\client_auth_filter.cc " +

@ -135,3 +135,7 @@ some configuration as environment variables that can be set.
if set, flow control will be effectively disabled. Max out all values and
assume the remote peer does the same. Thus we can ignore any flow control
bookkeeping, error checking, and decision making
* grpc_cfstream
set to 1 to turn on CFStream experiment. With this experiment gRPC uses CFStream API to make TCP
connections. The option is only available on iOS platform and when macro GRPC_CFSTREAM is defined.

@ -191,6 +191,6 @@ each language:
- [Go](https://github.com/grpc/grpc-go/blob/master/Documentation/server-reflection-tutorial.md#enable-server-reflection)
- [C++](https://grpc.io/grpc/cpp/md_doc_server_reflection_tutorial.html)
- [C#](https://github.com/grpc/grpc/blob/master/doc/csharp/server_reflection.md)
- Python: (tutorial not yet written)
- [Python](https://github.com/grpc/grpc/blob/master/doc/python/server_reflection.md)
- Ruby: not yet implemented [#2567](https://github.com/grpc/grpc/issues/2567)
- Node: not yet implemented [#2568](https://github.com/grpc/grpc/issues/2568)

@ -0,0 +1,36 @@
# SSL in gRPC and performance
The SSL requirement of gRPC isn't necessarily making it easy to integrate. The HTTP/2 protocol requires ALPN support, which is a fairly new handshake protocol only supported by recent implementations.
As a result, we've tried hard to provide a smooth experience to our users when compiling and distributing gRPC, but this may come at performance costs due to this. More specifically, we will sometime build the SSL library by disabling assembly code
(by setting the `OPENSSL_NO_ASM` option), which can impact performance by an order of magnitude when processing encrypted streams.
## gRPC C++: Building from Source
Build system | Condition | Platform | Uses assembly optimizations
---|---|---|--
Makefile | with OpenSSL 1.0.2 development files | all | :heavy_check_mark:
Makefile | all other cases | all | :x:
Bazel | | Linux | :heavy_check_mark:
Bazel | | MacOS | :heavy_check_mark:
Bazel | | Windows | :x:
CMake | boringssl from submodule (default) | all | :x:
CMake | pre-installed OpenSSL 1.0.2+ (`gRPC_SSL_PROVIDER=package`) | all | :heavy_check_mark:
## Other Languages: Binary/Source Packages
In addition, we are shipping packages for language implementations. These packages are source packages, but also have pre-built binaries being distributed. Building packages from source may give a different result in some cases.
Language | From source | Platform | Uses assembly optimizations
---|---|---|---
C# | n/a | all | :x:
Node.JS | n/a | Linux | :heavy_check_mark:
Node.JS | n/a | MacOS | :heavy_check_mark:
Node.JS | n/a | Windows | :x:
Electron | n/a | all | :heavy_check_mark:
ObjC | Yes | iOS | :x:
PHP | Yes | all | Same as the `Makefile` case from above
PHP | No | all | :x:
Python | n/a | all | :x:
Ruby | No | all | :x:

@ -3734,169 +3734,6 @@ lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof
TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
-----END CERTIFICATE-----
# Issuer: CN=Certplus Root CA G1 O=Certplus
# Subject: CN=Certplus Root CA G1 O=Certplus
# Label: "Certplus Root CA G1"
# Serial: 1491911565779898356709731176965615564637713
# MD5 Fingerprint: 7f:09:9c:f7:d9:b9:5c:69:69:56:d5:37:3e:14:0d:42
# SHA1 Fingerprint: 22:fd:d0:b7:fd:a2:4e:0d:ac:49:2c:a0:ac:a6:7b:6a:1f:e3:f7:66
# SHA256 Fingerprint: 15:2a:40:2b:fc:df:2c:d5:48:05:4d:22:75:b3:9c:7f:ca:3e:c0:97:80:78:b0:f0:ea:76:e5:61:a6:c7:43:3e
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUA
MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy
dHBsdXMgUm9vdCBDQSBHMTAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBa
MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy
dHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
ANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHNr49a
iZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt
6kuJPKNxQv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP
0FG7Yn2ksYyy/yARujVjBYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f
6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTvLRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDE
EW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2z4QTd28n6v+WZxcIbekN
1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc4nBvCGrc
h2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCT
mehd4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV
4EJQeIQEQWGw9CEjjy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPO
WftwenMGE9nTdDckQQoRb5fc5+R+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1Ud
DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSowcCbkahDFXxd
Bie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHYlwuBsTANBgkq
hkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh
66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7
/SMNkPX0XtPGYX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BS
S7CTKtQ+FjPlnsZlFT5kOwQ/2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j
2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F6ALEUz65noe8zDUa3qHpimOHZR4R
Kttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilXCNQ314cnrUlZp5Gr
RHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWetUNy
6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEV
V/xuZDDCVRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5
g4VCXA9DO2pJNdWY9BW/+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl
++O/QmueD6i9a5jc2NvLi6Td11n0bt3+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=
-----END CERTIFICATE-----
# Issuer: CN=Certplus Root CA G2 O=Certplus
# Subject: CN=Certplus Root CA G2 O=Certplus
# Label: "Certplus Root CA G2"
# Serial: 1492087096131536844209563509228951875861589
# MD5 Fingerprint: a7:ee:c4:78:2d:1b:ee:2d:b9:29:ce:d6:a7:96:32:31
# SHA1 Fingerprint: 4f:65:8e:1f:e9:06:d8:28:02:e9:54:47:41:c9:54:25:5d:69:cc:1a
# SHA256 Fingerprint: 6c:c0:50:41:e6:44:5e:74:69:6c:4c:fb:c9:f8:0f:54:3b:7e:ab:bb:44:b4:ce:6f:78:7c:6a:99:71:c4:2f:17
-----BEGIN CERTIFICATE-----
MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4x
CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs
dXMgUm9vdCBDQSBHMjAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4x
CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs
dXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABM0PW1aC3/BFGtat
93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uNAm8x
Ik0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0P
AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwj
FNiPwyCrKGBZMB8GA1UdIwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqG
SM49BAMDA2gAMGUCMHD+sAvZ94OX7PNVHdTcswYO/jOYnYs5kGuUIe22113WTNch
p+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjlvPl5adytRSv3tjFzzAal
U5ORGpOucGpnutee5WEaXw==
-----END CERTIFICATE-----
# Issuer: CN=OpenTrust Root CA G1 O=OpenTrust
# Subject: CN=OpenTrust Root CA G1 O=OpenTrust
# Label: "OpenTrust Root CA G1"
# Serial: 1492036577811947013770400127034825178844775
# MD5 Fingerprint: 76:00:cc:81:29:cd:55:5e:88:6a:7a:2e:f7:4d:39:da
# SHA1 Fingerprint: 79:91:e8:34:f7:e2:ee:dd:08:95:01:52:e9:55:2d:14:e9:58:d5:7e
# SHA256 Fingerprint: 56:c7:71:28:d9:8c:18:d9:1b:4c:fd:ff:bc:25:ee:91:03:d4:75:8e:a2:ab:ad:82:6a:90:f3:45:7d:46:0e:b4
-----BEGIN CERTIFICATE-----
MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUA
MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w
ZW5UcnVzdCBSb290IENBIEcxMB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAw
MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU
T3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7faYp6b
wiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX
/uMftk87ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR0
77F9jAHiOH3BX2pfJLKOYheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGP
uY4zbGneWK2gDqdkVBFpRGZPTBKnjix9xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLx
p2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO9z0M+Yo0FMT7MzUj8czx
Kselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq3ywgsNw2
TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+W
G+Oin6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPw
vFEVVJSmdz7QdFG9URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYY
EQRVzXR7z2FwefR7LFxckvzluFqrTJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUl0YhVyE1
2jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/PxN3DlCPaTKbYw
DQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E
PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kf
gLMtMrpkZ2CvuVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbS
FXJfLkur1J1juONI5f6ELlgKn0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0
V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLhX4SPgPL0DTatdrOjteFkdjpY3H1P
XlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80nR14SohWZ25g/4/I
i+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcmGS3t
TAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L91
09S5zvE/bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/Ky
Pu1svf0OnWZzsD2097+o4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJ
AwSQiumPv+i2tCqjI40cHLI5kqiPAlxAOXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj
1oxx
-----END CERTIFICATE-----
# Issuer: CN=OpenTrust Root CA G2 O=OpenTrust
# Subject: CN=OpenTrust Root CA G2 O=OpenTrust
# Label: "OpenTrust Root CA G2"
# Serial: 1492012448042702096986875987676935573415441
# MD5 Fingerprint: 57:24:b6:59:24:6b:ae:c8:fe:1c:0c:20:f2:c0:4e:eb
# SHA1 Fingerprint: 79:5f:88:60:c5:ab:7c:3d:92:e6:cb:f4:8d:e1:45:cd:11:ef:60:0b
# SHA256 Fingerprint: 27:99:58:29:fe:6a:75:15:c1:bf:e8:48:f9:c4:76:1d:b1:6c:22:59:29:25:7b:f4:0d:08:94:f2:9e:a8:ba:f2
-----BEGIN CERTIFICATE-----
MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUA
MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w
ZW5UcnVzdCBSb290IENBIEcyMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAw
MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU
T3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+Ntmh
/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78e
CbY2albz4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/6
1UWY0jUJ9gNDlP7ZvyCVeYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fE
FY8ElggGQgT4hNYdvJGmQr5J1WqIP7wtUdGejeBSzFfdNTVY27SPJIjki9/ca1TS
gSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz3GIZ38i1MH/1PCZ1Eb3X
G7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj3CzMpSZy
YhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaH
vGOz9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4
t/bQWVyJ98LVtZR00dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/
gh7PU3+06yzbXfZqfUAkBXKJOAGTy3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUajn6QiL3
5okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59M4PLuG53hq8w
DQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz
Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0
nXGEL8pZ0keImUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qT
RmTFAHneIWv2V6CG1wZy7HBGS4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpT
wm+bREx50B1ws9efAvSyB7DH5fitIw6mVskpEndI2S9G/Tvw/HRwkqWOOAgfZDC2
t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ6e18CL13zSdkzJTa
TkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97krgCf2
o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU
3jg9CcCoSmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eA
iN1nE28daCSLT7d0geX0YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14f
WKGVyasvc0rQLW6aWQ9VGHgtPFGml4vmu7JwqkwR3v98KzfUetF3NI/n+UL3PIEM
S1IK
-----END CERTIFICATE-----
# Issuer: CN=OpenTrust Root CA G3 O=OpenTrust
# Subject: CN=OpenTrust Root CA G3 O=OpenTrust
# Label: "OpenTrust Root CA G3"
# Serial: 1492104908271485653071219941864171170455615
# MD5 Fingerprint: 21:37:b4:17:16:92:7b:67:46:70:a9:96:d7:a8:13:24
# SHA1 Fingerprint: 6e:26:64:f3:56:bf:34:55:bf:d1:93:3f:7c:01:de:d8:13:da:8a:a6
# SHA256 Fingerprint: b7:c3:62:31:70:6e:81:07:8c:36:7c:b8:96:19:8f:1e:32:08:dd:92:69:49:dd:8f:57:09:a4:10:f7:5b:62:92
-----BEGIN CERTIFICATE-----
MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAx
CzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5U
cnVzdCBSb290IENBIEczMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFow
QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwUT3Bl
blRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARK7liuTcpm
3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5Bta1d
oYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4G
A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5
DMlv4VBN0BBY3JWIbTAfBgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAK
BggqhkjOPQQDAwNpADBmAjEAj6jcnboMBBf6Fek9LykBl7+BFjNAk2z8+e2AcG+q
j9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta3U1fJAuwACEl74+nBCZx
4nxp5V2a+EEfOzmTk51V6s2N8fvB
-----END CERTIFICATE-----
# Issuer: CN=ISRG Root X1 O=Internet Security Research Group
# Subject: CN=ISRG Root X1 O=Internet Security Research Group
# Label: "ISRG Root X1"
@ -4440,3 +4277,43 @@ MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX
ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg
h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
-----END CERTIFICATE-----
# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6
# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6
# Label: "GlobalSign Root CA - R6"
# Serial: 1417766617973444989252670301619537
# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae
# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1
# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69
-----BEGIN CERTIFICATE-----
MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg
MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh
bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx
MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET
MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI
xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k
ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD
aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw
LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw
1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX
k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2
SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h
bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n
WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY
rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce
MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD
AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu
bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt
Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61
55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj
vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf
cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz
oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp
nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs
pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v
JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R
8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4
5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
-----END CERTIFICATE-----

@ -278,6 +278,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/security_connector/alts_security_connector.h',
'src/core/lib/security/security_connector/load_system_roots.h',
'src/core/lib/security/security_connector/load_system_roots_linux.h',
'src/core/lib/security/security_connector/local_security_connector.h',
'src/core/lib/security/security_connector/security_connector.h',
'src/core/lib/security/transport/auth_filters.h',

@ -289,6 +289,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/security_connector/alts_security_connector.h',
'src/core/lib/security/security_connector/load_system_roots.h',
'src/core/lib/security/security_connector/load_system_roots_linux.h',
'src/core/lib/security/security_connector/local_security_connector.h',
'src/core/lib/security/security_connector/security_connector.h',
'src/core/lib/security/transport/auth_filters.h',
@ -705,6 +707,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
'src/core/lib/security/security_connector/alts_security_connector.cc',
'src/core/lib/security/security_connector/load_system_roots_fallback.cc',
'src/core/lib/security/security_connector/load_system_roots_linux.cc',
'src/core/lib/security/security_connector/local_security_connector.cc',
'src/core/lib/security/security_connector/security_connector.cc',
'src/core/lib/security/transport/client_auth_filter.cc',
@ -882,6 +886,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/security_connector/alts_security_connector.h',
'src/core/lib/security/security_connector/load_system_roots.h',
'src/core/lib/security/security_connector/load_system_roots_linux.h',
'src/core/lib/security/security_connector/local_security_connector.h',
'src/core/lib/security/security_connector/security_connector.h',
'src/core/lib/security/transport/auth_filters.h',
@ -1112,6 +1118,7 @@ Pod::Spec.new do |s|
ss.source_files = 'src/core/lib/iomgr/cfstream_handle.cc',
'src/core/lib/iomgr/endpoint_cfstream.cc',
'src/core/lib/iomgr/error_cfstream.cc',
'src/core/lib/iomgr/iomgr_posix_cfstream.cc',
'src/core/lib/iomgr/tcp_client_cfstream.cc',
'src/core/lib/iomgr/cfstream_handle.h',
'src/core/lib/iomgr/endpoint_cfstream.h',

@ -69,6 +69,7 @@ EXPORTS
grpc_resource_quota_ref
grpc_resource_quota_unref
grpc_resource_quota_resize
grpc_resource_quota_set_max_threads
grpc_resource_quota_arg_vtable
grpc_channelz_get_top_channels
grpc_channelz_get_channel

@ -222,6 +222,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.h )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.h )
s.files += %w( src/core/lib/security/security_connector/alts_security_connector.h )
s.files += %w( src/core/lib/security/security_connector/load_system_roots.h )
s.files += %w( src/core/lib/security/security_connector/load_system_roots_linux.h )
s.files += %w( src/core/lib/security/security_connector/local_security_connector.h )
s.files += %w( src/core/lib/security/security_connector/security_connector.h )
s.files += %w( src/core/lib/security/transport/auth_filters.h )
@ -642,6 +644,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.cc )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.cc )
s.files += %w( src/core/lib/security/security_connector/alts_security_connector.cc )
s.files += %w( src/core/lib/security/security_connector/load_system_roots_fallback.cc )
s.files += %w( src/core/lib/security/security_connector/load_system_roots_linux.cc )
s.files += %w( src/core/lib/security/security_connector/local_security_connector.cc )
s.files += %w( src/core/lib/security/security_connector/security_connector.cc )
s.files += %w( src/core/lib/security/transport/client_auth_filter.cc )

@ -472,6 +472,8 @@
'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
'src/core/lib/security/security_connector/alts_security_connector.cc',
'src/core/lib/security/security_connector/load_system_roots_fallback.cc',
'src/core/lib/security/security_connector/load_system_roots_linux.cc',
'src/core/lib/security/security_connector/local_security_connector.cc',
'src/core/lib/security/security_connector/security_connector.cc',
'src/core/lib/security/transport/client_auth_filter.cc',

@ -460,6 +460,10 @@ GRPCAPI void grpc_resource_quota_unref(grpc_resource_quota* resource_quota);
GRPCAPI void grpc_resource_quota_resize(grpc_resource_quota* resource_quota,
size_t new_size);
/** Update the size of the maximum number of threads allowed */
GRPCAPI void grpc_resource_quota_set_max_threads(
grpc_resource_quota* resource_quota, int new_max_threads);
/** Fetch a vtable for a grpc_channel_arg that points to a grpc_resource_quota
*/
GRPCAPI const grpc_arg_pointer_vtable* grpc_resource_quota_arg_vtable(void);

@ -52,12 +52,12 @@ class GenericServerContext final : public ServerContext {
// ServerBuilder builder;
// auto cq = builder.AddCompletionQueue();
// AsyncGenericService generic_service;
// builder.RegisterAsyncGeneicService(&generic_service);
// builder.RegisterAsyncGenericService(&generic_service);
// auto server = builder.BuildAndStart();
//
// // request a new call
// GenericServerContext context;
// GenericAsyncReaderWriter stream;
// GenericServerAsyncReaderWriter stream;
// generic_service.RequestCall(&context, &stream, cq.get(), cq.get(), tag);
//
// When tag is retrieved from cq->Next(), context.method() can be used to look

@ -26,10 +26,10 @@ struct grpc_resource_quota;
namespace grpc {
/// ResourceQuota represents a bound on memory usage by the gRPC library.
/// A ResourceQuota can be attached to a server (via \a ServerBuilder),
/// ResourceQuota represents a bound on memory and thread usage by the gRPC
/// library. A ResourceQuota can be attached to a server (via \a ServerBuilder),
/// or a client channel (via \a ChannelArguments).
/// gRPC will attempt to keep memory used by all attached entities
/// gRPC will attempt to keep memory and threads used by all attached entities
/// below the ResourceQuota bound.
class ResourceQuota final : private GrpcLibraryCodegen {
public:
@ -44,6 +44,16 @@ class ResourceQuota final : private GrpcLibraryCodegen {
/// No time bound is given for this to occur however.
ResourceQuota& Resize(size_t new_size);
/// Set the max number of threads that can be allocated from this
/// ResourceQuota object.
///
/// If the new_max_threads value is smaller than the current value, no new
/// threads are allocated until the number of active threads fall below
/// new_max_threads. There is no time bound on when this may happen i.e none
/// of the current threads are forcefully destroyed and all threads run their
/// normal course.
ResourceQuota& SetMaxThreads(int new_max_threads);
grpc_resource_quota* c_resource_quota() const { return impl_; }
private:

@ -120,6 +120,10 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
int AddListeningPort(const grpc::string& addr,
ServerCredentials* creds) override;
/// NOTE: This is *NOT* a public API. The server constructors are supposed to
/// be used by \a ServerBuilder class only. The constructor will be made
/// 'private' very soon.
///
/// Server constructors. To be used by \a ServerBuilder only.
///
/// \param max_message_size Maximum message length that the channel can
@ -144,7 +148,8 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
Server(int max_message_size, ChannelArguments* args,
std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
sync_server_cqs,
int min_pollers, int max_pollers, int sync_cq_timeout_msec);
int min_pollers, int max_pollers, int sync_cq_timeout_msec,
grpc_resource_quota* server_rq = nullptr);
/// Start the server.
///

@ -227,6 +227,8 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/alts_security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/load_system_roots.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/load_system_roots_linux.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/local_security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/auth_filters.h" role="src" />
@ -647,6 +649,8 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/alts_security_connector.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/load_system_roots_fallback.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/load_system_roots_linux.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/local_security_connector.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/security_connector.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/client_auth_filter.cc" role="src" />

@ -812,12 +812,14 @@ static void set_write_state(grpc_chttp2_transport* t,
write_state_name(t->write_state),
write_state_name(st), reason));
t->write_state = st;
/* If the state is being reset back to idle, it means a write was just
* finished. Make sure all the run_after_write closures are scheduled.
*
* This is also our chance to close the transport if the transport was marked
* to be closed after all writes finish (for example, if we received a go-away
* from peer while we had some pending writes) */
if (st == GRPC_CHTTP2_WRITE_STATE_IDLE) {
grpc_chttp2_stream* s;
while (grpc_chttp2_list_pop_waiting_for_write_stream(t, &s)) {
GRPC_CLOSURE_LIST_SCHED(&s->run_after_write);
GRPC_CHTTP2_STREAM_UNREF(s, "chttp2:write_closure_sched");
}
GRPC_CLOSURE_LIST_SCHED(&t->run_after_write);
if (t->close_transport_on_writes_finished != nullptr) {
grpc_error* err = t->close_transport_on_writes_finished;
t->close_transport_on_writes_finished = nullptr;
@ -903,6 +905,22 @@ void grpc_chttp2_initiate_write(grpc_chttp2_transport* t,
grpc_chttp2_initiate_write_reason_string(reason));
t->is_first_write_in_batch = true;
GRPC_CHTTP2_REF_TRANSPORT(t, "writing");
/* Note that the 'write_action_begin_locked' closure is being scheduled
* on the 'finally_scheduler' of t->combiner. This means that
* 'write_action_begin_locked' is called only *after* all the other
* closures (some of which are potentially initiating more writes on the
* transport) are executed on the t->combiner.
*
* The reason for scheduling on finally_scheduler is to make sure we batch
* as many writes as possible. 'write_action_begin_locked' is the function
* that gathers all the relevant bytes (which are at various places in the
* grpc_chttp2_transport structure) and append them to 'outbuf' field in
* grpc_chttp2_transport thereby batching what would have been potentially
* multiple write operations.
*
* Also, 'write_action_begin_locked' only gathers the bytes into outbuf.
* It does not call the endpoint to write the bytes. That is done by the
* 'write_action' (which is scheduled by 'write_action_begin_locked') */
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_INIT(&t->write_action_begin_locked,
write_action_begin_locked, t,
@ -1014,6 +1032,8 @@ static void write_action(void* gt, grpc_error* error) {
grpc_combiner_scheduler(t->combiner)));
}
/* Callback from the grpc_endpoint after bytes have been written by calling
* sendmsg */
static void write_action_end_locked(void* tp, grpc_error* error) {
GPR_TIMER_SCOPE("terminate_writing_with_lock", 0);
grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
@ -1212,10 +1232,7 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
!(closure->next_data.scratch & CLOSURE_BARRIER_MAY_COVER_WRITE)) {
GRPC_CLOSURE_RUN(closure, closure->error_data.error);
} else {
if (grpc_chttp2_list_add_waiting_for_write_stream(t, s)) {
GRPC_CHTTP2_STREAM_REF(s, "chttp2:pending_write_closure");
}
grpc_closure_list_append(&s->run_after_write, closure,
grpc_closure_list_append(&t->run_after_write, closure,
closure->error_data.error);
}
}
@ -2016,10 +2033,6 @@ static void remove_stream(grpc_chttp2_transport* t, uint32_t id,
void grpc_chttp2_cancel_stream(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
grpc_error* due_to_error) {
GRPC_CLOSURE_LIST_SCHED(&s->run_after_write);
if (grpc_chttp2_list_remove_waiting_for_write_stream(t, s)) {
GRPC_CHTTP2_STREAM_UNREF(s, "chttp2:pending_write_closure");
}
if (!t->is_client && !s->sent_trailing_metadata &&
grpc_error_has_clear_grpc_status(due_to_error)) {
close_from_api(t, s, due_to_error);

@ -55,7 +55,7 @@ static char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) {
static char* fmt_uint32_diff_str(uint32_t old_val, uint32_t new_val) {
char* str;
if (new_val > 0 && old_val != new_val) {
if (old_val != new_val) {
gpr_asprintf(&str, "%" PRIu32 " -> %" PRIu32 "", old_val, new_val);
} else {
gpr_asprintf(&str, "%" PRIu32 "", old_val);
@ -98,10 +98,12 @@ void FlowControlTrace::Finish() {
if (sfc_ != nullptr) {
srw_str = fmt_int64_diff_str(remote_window_delta_ + remote_window,
sfc_->remote_window_delta() + remote_window);
slw_str = fmt_int64_diff_str(local_window_delta_ + acked_local_window,
local_window_delta_ + acked_local_window);
saw_str = fmt_int64_diff_str(announced_window_delta_ + acked_local_window,
announced_window_delta_ + acked_local_window);
slw_str =
fmt_int64_diff_str(local_window_delta_ + acked_local_window,
sfc_->local_window_delta() + acked_local_window);
saw_str =
fmt_int64_diff_str(announced_window_delta_ + acked_local_window,
sfc_->announced_window_delta() + acked_local_window);
} else {
srw_str = gpr_leftpad("", ' ', kTracePadding);
slw_str = gpr_leftpad("", ' ', kTracePadding);

@ -54,8 +54,6 @@ typedef enum {
/** streams that are waiting to start because there are too many concurrent
streams on the connection */
GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY,
/** streams with closures waiting to be run on a write **/
GRPC_CHTTP2_LIST_WAITING_FOR_WRITE,
STREAM_LIST_COUNT /* must be last */
} grpc_chttp2_stream_list_id;
@ -433,6 +431,9 @@ struct grpc_chttp2_transport {
*/
grpc_error* close_transport_on_writes_finished;
/* a list of closures to run after writes are finished */
grpc_closure_list run_after_write;
/* buffer pool state */
/** have we scheduled a benign cleanup? */
bool benign_reclaimer_registered;
@ -583,7 +584,6 @@ struct grpc_chttp2_stream {
grpc_slice_buffer flow_controlled_buffer;
grpc_closure_list run_after_write;
grpc_chttp2_write_cb* on_flow_controlled_cbs;
grpc_chttp2_write_cb* on_write_finished_cbs;
grpc_chttp2_write_cb* finish_after_write;
@ -686,13 +686,6 @@ bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport* t,
bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport* t,
grpc_chttp2_stream* s);
bool grpc_chttp2_list_add_waiting_for_write_stream(grpc_chttp2_transport* t,
grpc_chttp2_stream* s);
bool grpc_chttp2_list_pop_waiting_for_write_stream(grpc_chttp2_transport* t,
grpc_chttp2_stream** s);
bool grpc_chttp2_list_remove_waiting_for_write_stream(grpc_chttp2_transport* t,
grpc_chttp2_stream* s);
/********* Flow Control ***************/
// Takes in a flow control action and performs all the needed operations.

@ -35,8 +35,6 @@ static const char* stream_list_id_string(grpc_chttp2_stream_list_id id) {
return "stalled_by_stream";
case GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY:
return "waiting_for_concurrency";
case GRPC_CHTTP2_LIST_WAITING_FOR_WRITE:
return "waiting_for_write";
case STREAM_LIST_COUNT:
GPR_UNREACHABLE_CODE(return "unknown");
}
@ -216,18 +214,3 @@ bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport* t,
grpc_chttp2_stream* s) {
return stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM);
}
bool grpc_chttp2_list_add_waiting_for_write_stream(grpc_chttp2_transport* t,
grpc_chttp2_stream* s) {
return stream_list_add(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_WRITE);
}
bool grpc_chttp2_list_pop_waiting_for_write_stream(grpc_chttp2_transport* t,
grpc_chttp2_stream** s) {
return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_WRITE);
}
bool grpc_chttp2_list_remove_waiting_for_write_stream(grpc_chttp2_transport* t,
grpc_chttp2_stream* s) {
return stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_WRITE);
}

@ -102,7 +102,10 @@ void grpc_call_combiner_stop(grpc_call_combiner* call_combiner,
/// If \a closure is NULL, then no closure will be invoked on
/// cancellation; this effectively unregisters the previously set closure.
/// However, most filters will not need to explicitly unregister their
/// callbacks, as this is done automatically when the call is destroyed.
/// callbacks, as this is done automatically when the call is destroyed. Filters
/// that schedule the cancellation closure on ExecCtx do not need to take a ref
/// on the call stack to guarantee closure liveness. This is done by explicitly
/// flushing ExecCtx after the unregistration during call destruction.
void grpc_call_combiner_set_notify_on_cancel(grpc_call_combiner* call_combiner,
grpc_closure* closure);

@ -0,0 +1,75 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_CFSTREAM_IOMGR
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/iomgr_posix.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/iomgr/tcp_posix.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/iomgr/timer.h"
static const char* grpc_cfstream_env_var = "grpc_cfstream";
extern grpc_tcp_server_vtable grpc_posix_tcp_server_vtable;
extern grpc_tcp_client_vtable grpc_posix_tcp_client_vtable;
extern grpc_tcp_client_vtable grpc_cfstream_client_vtable;
extern grpc_timer_vtable grpc_generic_timer_vtable;
extern grpc_pollset_vtable grpc_posix_pollset_vtable;
extern grpc_pollset_set_vtable grpc_posix_pollset_set_vtable;
extern grpc_address_resolver_vtable grpc_posix_resolver_vtable;
static void iomgr_platform_init(void) {
grpc_wakeup_fd_global_init();
grpc_event_engine_init();
}
static void iomgr_platform_flush(void) {}
static void iomgr_platform_shutdown(void) {
grpc_event_engine_shutdown();
grpc_wakeup_fd_global_destroy();
}
static grpc_iomgr_platform_vtable vtable = {
iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
void grpc_set_default_iomgr_platform() {
char* enable_cfstream = getenv(grpc_cfstream_env_var);
grpc_tcp_client_vtable* client_vtable = &grpc_posix_tcp_client_vtable;
if (enable_cfstream != nullptr && enable_cfstream[0] == '1') {
client_vtable = &grpc_cfstream_client_vtable;
}
grpc_set_tcp_client_impl(client_vtable);
grpc_set_tcp_server_impl(&grpc_posix_tcp_server_vtable);
grpc_set_timer_impl(&grpc_generic_timer_vtable);
grpc_set_pollset_vtable(&grpc_posix_pollset_vtable);
grpc_set_pollset_set_vtable(&grpc_posix_pollset_set_vtable);
grpc_set_resolver_impl(&grpc_posix_resolver_vtable);
grpc_set_iomgr_platform_vtable(&vtable);
}
#endif /* GRPC_CFSTREAM_IOMGR */

@ -98,9 +98,9 @@
#define GRPC_POSIX_FORK 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#ifdef GRPC_CFSTREAM
#define GRPC_POSIX_SOCKET_IOMGR 1
#define GRPC_CFSTREAM_ENDPOINT 1
#define GRPC_CFSTREAM_IOMGR 1
#define GRPC_CFSTREAM_CLIENT 1
#define GRPC_CFSTREAM_ENDPOINT 1
#define GRPC_POSIX_SOCKET_ARES_EV_DRIVER 1
#define GRPC_POSIX_SOCKET_EV 1
#define GRPC_POSIX_SOCKET_EV_EPOLL1 1
@ -111,6 +111,7 @@
#define GRPC_POSIX_SOCKET_SOCKADDR 1
#define GRPC_POSIX_SOCKET_SOCKET_FACTORY 1
#define GRPC_POSIX_SOCKET_TCP 1
#define GRPC_POSIX_SOCKET_TCP_CLIENT 1
#define GRPC_POSIX_SOCKET_TCP_SERVER 1
#define GRPC_POSIX_SOCKET_TCP_SERVER_UTILS_COMMON 1
#define GRPC_POSIX_SOCKET_UTILS_COMMON 1

@ -96,6 +96,9 @@ struct grpc_resource_user {
list, false otherwise */
bool added_to_free_pool;
/* The number of threads currently allocated to this resource user */
gpr_atm num_threads_allocated;
/* Reclaimers: index 0 is the benign reclaimer, 1 is the destructive reclaimer
*/
grpc_closure* reclaimers[2];
@ -135,12 +138,33 @@ struct grpc_resource_quota {
gpr_atm last_size;
/* Mutex to protect max_threads and num_threads_allocated */
/* Note: We could have used gpr_atm for max_threads and num_threads_allocated
* and avoid having this mutex; but in that case, each invocation of the
* function grpc_resource_user_allocate_threads() would have had to do at
* least two atomic loads (for max_threads and num_threads_allocated) followed
* by a CAS (on num_threads_allocated).
* Moreover, we expect grpc_resource_user_allocate_threads() to be often
* called concurrently thereby increasing the chances of failing the CAS
* operation. This additional complexity is not worth the tiny perf gain we
* may (or may not) have by using atomics */
gpr_mu thread_count_mu;
/* Max number of threads allowed */
int max_threads;
/* Number of threads currently allocated via this resource_quota object */
int num_threads_allocated;
/* Has rq_step been scheduled to occur? */
bool step_scheduled;
/* Are we currently reclaiming memory */
bool reclaiming;
/* Closure around rq_step */
grpc_closure rq_step_closure;
/* Closure around rq_reclamation_done */
grpc_closure rq_reclamation_done_closure;
@ -524,6 +548,11 @@ static void ru_shutdown(void* ru, grpc_error* error) {
static void ru_destroy(void* ru, grpc_error* error) {
grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->refs) == 0);
// Free all the remaining thread quota
grpc_resource_user_free_threads(resource_user,
static_cast<int>(gpr_atm_no_barrier_load(
&resource_user->num_threads_allocated)));
for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
rulist_remove(resource_user, static_cast<grpc_rulist>(i));
}
@ -594,6 +623,9 @@ grpc_resource_quota* grpc_resource_quota_create(const char* name) {
resource_quota->free_pool = INT64_MAX;
resource_quota->size = INT64_MAX;
gpr_atm_no_barrier_store(&resource_quota->last_size, GPR_ATM_MAX);
gpr_mu_init(&resource_quota->thread_count_mu);
resource_quota->max_threads = INT_MAX;
resource_quota->num_threads_allocated = 0;
resource_quota->step_scheduled = false;
resource_quota->reclaiming = false;
gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, 0);
@ -616,6 +648,8 @@ grpc_resource_quota* grpc_resource_quota_create(const char* name) {
void grpc_resource_quota_unref_internal(grpc_resource_quota* resource_quota) {
if (gpr_unref(&resource_quota->refs)) {
// No outstanding thread quota
GPR_ASSERT(resource_quota->num_threads_allocated == 0);
GRPC_COMBINER_UNREF(resource_quota->combiner, "resource_quota");
gpr_free(resource_quota->name);
gpr_free(resource_quota);
@ -646,6 +680,15 @@ double grpc_resource_quota_get_memory_pressure(
(static_cast<double>(MEMORY_USAGE_ESTIMATION_MAX));
}
/* Public API */
void grpc_resource_quota_set_max_threads(grpc_resource_quota* resource_quota,
int new_max_threads) {
GPR_ASSERT(new_max_threads >= 0);
gpr_mu_lock(&resource_quota->thread_count_mu);
resource_quota->max_threads = new_max_threads;
gpr_mu_unlock(&resource_quota->thread_count_mu);
}
/* Public API */
void grpc_resource_quota_resize(grpc_resource_quota* resource_quota,
size_t size) {
@ -731,6 +774,7 @@ grpc_resource_user* grpc_resource_user_create(
grpc_closure_list_init(&resource_user->on_allocated);
resource_user->allocating = false;
resource_user->added_to_free_pool = false;
gpr_atm_no_barrier_store(&resource_user->num_threads_allocated, 0);
resource_user->reclaimers[0] = nullptr;
resource_user->reclaimers[1] = nullptr;
resource_user->new_reclaimers[0] = nullptr;
@ -785,6 +829,40 @@ void grpc_resource_user_shutdown(grpc_resource_user* resource_user) {
}
}
bool grpc_resource_user_allocate_threads(grpc_resource_user* resource_user,
int thread_count) {
GPR_ASSERT(thread_count >= 0);
bool is_success = false;
gpr_mu_lock(&resource_user->resource_quota->thread_count_mu);
grpc_resource_quota* rq = resource_user->resource_quota;
if (rq->num_threads_allocated + thread_count <= rq->max_threads) {
rq->num_threads_allocated += thread_count;
gpr_atm_no_barrier_fetch_add(&resource_user->num_threads_allocated,
thread_count);
is_success = true;
}
gpr_mu_unlock(&resource_user->resource_quota->thread_count_mu);
return is_success;
}
void grpc_resource_user_free_threads(grpc_resource_user* resource_user,
int thread_count) {
GPR_ASSERT(thread_count >= 0);
gpr_mu_lock(&resource_user->resource_quota->thread_count_mu);
grpc_resource_quota* rq = resource_user->resource_quota;
rq->num_threads_allocated -= thread_count;
int old_count = static_cast<int>(gpr_atm_no_barrier_fetch_add(
&resource_user->num_threads_allocated, -thread_count));
if (old_count < thread_count || rq->num_threads_allocated < 0) {
gpr_log(GPR_ERROR,
"Releasing more threads (%d) than currently allocated (rq threads: "
"%d, ru threads: %d)",
thread_count, rq->num_threads_allocated + thread_count, old_count);
abort();
}
gpr_mu_unlock(&resource_user->resource_quota->thread_count_mu);
}
void grpc_resource_user_alloc(grpc_resource_user* resource_user, size_t size,
grpc_closure* optional_on_done) {
gpr_mu_lock(&resource_user->mu);

@ -93,6 +93,22 @@ void grpc_resource_user_ref(grpc_resource_user* resource_user);
void grpc_resource_user_unref(grpc_resource_user* resource_user);
void grpc_resource_user_shutdown(grpc_resource_user* resource_user);
/* Attempts to get quota from the resource_user to create 'thread_count' number
* of threads. Returns true if successful (i.e the caller is now free to create
* 'thread_count' number of threads) or false if quota is not available */
bool grpc_resource_user_allocate_threads(grpc_resource_user* resource_user,
int thread_count);
/* Releases 'thread_count' worth of quota back to the resource user. The quota
* should have been previously obtained successfully by calling
* grpc_resource_user_allocate_threads().
*
* Note: There need not be an exact one-to-one correspondence between
* grpc_resource_user_allocate_threads() and grpc_resource_user_free_threads()
* calls. The only requirement is that the number of threads allocated should
* all be eventually released */
void grpc_resource_user_free_threads(grpc_resource_user* resource_user,
int thread_count);
/* Allocate from the resource user (and its quota).
If optional_on_done is NULL, then allocate immediately. This may push the
quota over-limit, at which point reclamation will kick in.

@ -211,6 +211,6 @@ static void CFStreamClientConnect(grpc_closure* closure, grpc_endpoint** ep,
gpr_mu_unlock(&connect->mu);
}
grpc_tcp_client_vtable grpc_posix_tcp_client_vtable = {CFStreamClientConnect};
grpc_tcp_client_vtable grpc_cfstream_client_vtable = {CFStreamClientConnect};
#endif /* GRPC_CFSTREAM_CLIENT */

@ -0,0 +1,29 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOAD_SYSTEM_ROOTS_H
#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOAD_SYSTEM_ROOTS_H
namespace grpc_core {
// Returns a slice containing roots from the OS trust store
grpc_slice LoadSystemRootCerts();
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOAD_SYSTEM_ROOTS_H */

@ -0,0 +1,32 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include <grpc/slice_buffer.h>
#include "src/core/lib/security/security_connector/load_system_roots.h"
#ifndef GPR_LINUX
namespace grpc_core {
grpc_slice LoadSystemRootCerts() { return grpc_empty_slice(); }
} // namespace grpc_core
#endif /* GPR_LINUX */

@ -0,0 +1,165 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include <grpc/slice_buffer.h>
#include "src/core/lib/security/security_connector/load_system_roots_linux.h"
#ifdef GPR_LINUX
#include "src/core/lib/security/security_connector/load_system_roots.h"
#include <dirent.h>
#include <fcntl.h>
#include <stdbool.h>
#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/inlined_vector.h"
#include "src/core/lib/iomgr/load_file.h"
namespace grpc_core {
namespace {
const char* kLinuxCertFiles[] = {
"/etc/ssl/certs/ca-certificates.crt", "/etc/pki/tls/certs/ca-bundle.crt",
"/etc/ssl/ca-bundle.pem", "/etc/pki/tls/cacert.pem",
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"};
const char* kLinuxCertDirectories[] = {
"/etc/ssl/certs", "/system/etc/security/cacerts", "/usr/local/share/certs",
"/etc/pki/tls/certs", "/etc/openssl/certs"};
grpc_slice GetSystemRootCerts() {
grpc_slice valid_bundle_slice = grpc_empty_slice();
size_t num_cert_files_ = GPR_ARRAY_SIZE(kLinuxCertFiles);
for (size_t i = 0; i < num_cert_files_; i++) {
grpc_error* error =
grpc_load_file(kLinuxCertFiles[i], 1, &valid_bundle_slice);
if (error == GRPC_ERROR_NONE) {
return valid_bundle_slice;
}
}
return grpc_empty_slice();
}
} // namespace
void GetAbsoluteFilePath(const char* valid_file_dir,
const char* file_entry_name, char* path_buffer) {
if (valid_file_dir != nullptr && file_entry_name != nullptr) {
int path_len = snprintf(path_buffer, MAXPATHLEN, "%s/%s", valid_file_dir,
file_entry_name);
if (path_len == 0) {
gpr_log(GPR_ERROR, "failed to get absolute path for file: %s",
file_entry_name);
}
}
}
grpc_slice CreateRootCertsBundle(const char* certs_directory) {
grpc_slice bundle_slice = grpc_empty_slice();
if (certs_directory == nullptr) {
return bundle_slice;
}
DIR* ca_directory = opendir(certs_directory);
if (ca_directory == nullptr) {
return bundle_slice;
}
struct FileData {
char path[MAXPATHLEN];
off_t size;
};
InlinedVector<FileData, 2> roots_filenames;
size_t total_bundle_size = 0;
struct dirent* directory_entry;
while ((directory_entry = readdir(ca_directory)) != nullptr) {
struct stat dir_entry_stat;
const char* file_entry_name = directory_entry->d_name;
FileData file_data;
GetAbsoluteFilePath(certs_directory, file_entry_name, file_data.path);
int stat_return = stat(file_data.path, &dir_entry_stat);
if (stat_return == -1 || !S_ISREG(dir_entry_stat.st_mode)) {
// no subdirectories.
if (stat_return == -1) {
gpr_log(GPR_ERROR, "failed to get status for file: %s", file_data.path);
}
continue;
}
file_data.size = dir_entry_stat.st_size;
total_bundle_size += file_data.size;
roots_filenames.push_back(file_data);
}
closedir(ca_directory);
char* bundle_string = static_cast<char*>(gpr_zalloc(total_bundle_size + 1));
size_t bytes_read = 0;
for (size_t i = 0; i < roots_filenames.size(); i++) {
int file_descriptor = open(roots_filenames[i].path, O_RDONLY);
if (file_descriptor != -1) {
// Read file into bundle.
size_t cert_file_size = roots_filenames[i].size;
int read_ret =
read(file_descriptor, bundle_string + bytes_read, cert_file_size);
if (read_ret != -1) {
bytes_read += read_ret;
} else {
gpr_log(GPR_ERROR, "failed to read file: %s", roots_filenames[i].path);
}
}
}
bundle_slice = grpc_slice_new(bundle_string, bytes_read, gpr_free);
return bundle_slice;
}
grpc_slice LoadSystemRootCerts() {
grpc_slice result = grpc_empty_slice();
// Prioritize user-specified custom directory if flag is set.
char* custom_dir = gpr_getenv("GRPC_SYSTEM_SSL_ROOTS_DIR");
if (custom_dir != nullptr) {
result = CreateRootCertsBundle(custom_dir);
gpr_free(custom_dir);
}
// If the custom directory is empty/invalid/not specified, fallback to
// distribution-specific directory.
if (GRPC_SLICE_IS_EMPTY(result)) {
result = GetSystemRootCerts();
}
if (GRPC_SLICE_IS_EMPTY(result)) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(kLinuxCertDirectories); i++) {
result = CreateRootCertsBundle(kLinuxCertDirectories[i]);
if (!GRPC_SLICE_IS_EMPTY(result)) {
break;
}
}
}
return result;
}
} // namespace grpc_core
#endif /* GPR_LINUX */

@ -0,0 +1,44 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOAD_SYSTEM_ROOTS_LINUX_H
#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOAD_SYSTEM_ROOTS_LINUX_H
#include <grpc/support/port_platform.h>
#ifdef GPR_LINUX
namespace grpc_core {
// Creates a bundle slice containing the contents of all certificate files in
// a directory.
// Returns such slice.
// Exposed for testing purposes only.
grpc_slice CreateRootCertsBundle(const char* certs_directory);
// Gets the absolute file path needed to load a certificate file.
// Populates path_buffer, which must be of size MAXPATHLEN.
// Exposed for testing purposes only.
void GetAbsoluteFilePath(const char* valid_file_dir,
const char* file_entry_name, char* path_buffer);
} // namespace grpc_core
#endif /* GPR_LINUX */
#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOAD_SYSTEM_ROOTS_LINUX_H \
*/

@ -21,7 +21,6 @@
#include "src/core/lib/security/security_connector/security_connector.h"
#include <stdbool.h>
#include <string.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
@ -39,6 +38,7 @@
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
#include "src/core/lib/security/security_connector/load_system_roots.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/security/transport/target_authority_table.h"
@ -57,6 +57,12 @@ static const char* installed_roots_path =
INSTALL_PREFIX "/share/grpc/roots.pem";
#endif
/** Environment variable used as a flag to enable/disable loading system root
certificates from the OS trust store. */
#ifndef GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR
#define GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_USE_SYSTEM_SSL_ROOTS"
#endif
#ifndef TSI_OPENSSL_ALPN_SUPPORT
#define TSI_OPENSSL_ALPN_SUPPORT 1
#endif
@ -1186,6 +1192,10 @@ const char* DefaultSslRootStore::GetPemRootCerts() {
grpc_slice DefaultSslRootStore::ComputePemRootCerts() {
grpc_slice result = grpc_empty_slice();
char* use_system_roots_env_value =
gpr_getenv(GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR);
const bool use_system_roots = gpr_is_true(use_system_roots_env_value);
gpr_free(use_system_roots_env_value);
// First try to load the roots from the environment.
char* default_root_certs_path =
gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
@ -1207,7 +1217,11 @@ grpc_slice DefaultSslRootStore::ComputePemRootCerts() {
}
gpr_free(pem_root_certs);
}
// Fall back to installed certs if needed.
// Try loading roots from OS trust store if flag is enabled.
if (GRPC_SLICE_IS_EMPTY(result) && use_system_roots) {
result = LoadSystemRootCerts();
}
// Fallback to roots manually shipped with gRPC.
if (GRPC_SLICE_IS_EMPTY(result) &&
ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
GRPC_LOG_IF_ERROR("load_file",

@ -167,7 +167,6 @@ static void cancel_get_request_metadata(void* arg, grpc_error* error) {
grpc_call_credentials_cancel_get_request_metadata(
calld->creds, &calld->md_array, GRPC_ERROR_REF(error));
}
GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_get_request_metadata");
}
static void send_security_metadata(grpc_call_element* elem,
@ -222,7 +221,6 @@ static void send_security_metadata(grpc_call_element* elem,
GRPC_ERROR_UNREF(error);
} else {
// Async return; register cancellation closure with call combiner.
GRPC_CALL_STACK_REF(calld->owning_call, "cancel_get_request_metadata");
grpc_call_combiner_set_notify_on_cancel(
calld->call_combiner,
GRPC_CLOSURE_INIT(&calld->get_request_metadata_cancel_closure,
@ -265,7 +263,6 @@ static void cancel_check_call_host(void* arg, grpc_error* error) {
chand->security_connector, &calld->async_result_closure,
GRPC_ERROR_REF(error));
}
GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_check_call_host");
}
static void auth_start_transport_stream_op_batch(
@ -318,7 +315,6 @@ static void auth_start_transport_stream_op_batch(
GRPC_ERROR_UNREF(error);
} else {
// Async return; register cancellation closure with call combiner.
GRPC_CALL_STACK_REF(calld->owning_call, "cancel_check_call_host");
grpc_call_combiner_set_notify_on_cancel(
calld->call_combiner,
GRPC_CLOSURE_INIT(&calld->check_call_host_cancel_closure,

@ -156,7 +156,6 @@ static void cancel_call(void* arg, grpc_error* error) {
on_md_processing_done_inner(elem, nullptr, 0, nullptr, 0,
GRPC_ERROR_REF(error));
}
GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_call");
}
static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
@ -168,7 +167,6 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
if (chand->creds != nullptr && chand->creds->processor.process != nullptr) {
// We're calling out to the application, so we need to make sure
// to drop the call combiner early if we get cancelled.
GRPC_CALL_STACK_REF(calld->owning_call, "cancel_call");
GRPC_CLOSURE_INIT(&calld->cancel_closure, cancel_call, elem,
grpc_schedule_on_exec_ctx);
grpc_call_combiner_set_notify_on_cancel(calld->call_combiner,

@ -613,8 +613,11 @@ void grpc_call_unref(grpc_call* c) {
// Unset the call combiner cancellation closure. This has the
// effect of scheduling the previously set cancellation closure, if
// any, so that it can release any internal references it may be
// holding to the call stack.
// holding to the call stack. Also flush the closures on exec_ctx so that
// filters that schedule cancel notification closures on exec_ctx do not
// need to take a ref of the call stack to guarantee closure liveness.
grpc_call_combiner_set_notify_on_cancel(&c->call_combiner, nullptr);
grpc_core::ExecCtx::Get()->Flush();
}
GRPC_CALL_INTERNAL_UNREF(c, "destroy");
}

@ -33,4 +33,8 @@ ResourceQuota& ResourceQuota::Resize(size_t new_size) {
return *this;
}
ResourceQuota& ResourceQuota::SetMaxThreads(int new_max_threads) {
grpc_resource_quota_set_max_threads(impl_, new_max_threads);
return *this;
}
} // namespace grpc

@ -263,7 +263,7 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
std::unique_ptr<Server> server(new Server(
max_receive_message_size_, &args, sync_server_cqs,
sync_server_settings_.min_pollers, sync_server_settings_.max_pollers,
sync_server_settings_.cq_timeout_msec));
sync_server_settings_.cq_timeout_msec, resource_quota_));
if (has_sync_methods) {
// This is a Sync server

@ -47,6 +47,12 @@
namespace grpc {
namespace {
// The default value for maximum number of threads that can be created in the
// sync server. This value of 500 is empirically chosen. To increase the max
// number of threads in a sync server, pass a custom ResourceQuota object (with
// the desired number of max-threads set) to the server builder
#define DEFAULT_MAX_SYNC_SERVER_THREADS 500
class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
public:
~DefaultGlobalCallbacks() override {}
@ -266,9 +272,9 @@ class Server::SyncRequestThreadManager : public ThreadManager {
public:
SyncRequestThreadManager(Server* server, CompletionQueue* server_cq,
std::shared_ptr<GlobalCallbacks> global_callbacks,
int min_pollers, int max_pollers,
int cq_timeout_msec)
: ThreadManager(min_pollers, max_pollers),
grpc_resource_quota* rq, int min_pollers,
int max_pollers, int cq_timeout_msec)
: ThreadManager("SyncServer", rq, min_pollers, max_pollers),
server_(server),
server_cq_(server_cq),
cq_timeout_msec_(cq_timeout_msec),
@ -376,7 +382,8 @@ Server::Server(
int max_receive_message_size, ChannelArguments* args,
std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
sync_server_cqs,
int min_pollers, int max_pollers, int sync_cq_timeout_msec)
int min_pollers, int max_pollers, int sync_cq_timeout_msec,
grpc_resource_quota* server_rq)
: max_receive_message_size_(max_receive_message_size),
sync_server_cqs_(std::move(sync_server_cqs)),
started_(false),
@ -392,10 +399,22 @@ Server::Server(
global_callbacks_->UpdateArguments(args);
if (sync_server_cqs_ != nullptr) {
bool default_rq_created = false;
if (server_rq == nullptr) {
server_rq = grpc_resource_quota_create("SyncServer-default-rq");
grpc_resource_quota_set_max_threads(server_rq,
DEFAULT_MAX_SYNC_SERVER_THREADS);
default_rq_created = true;
}
for (const auto& it : *sync_server_cqs_) {
sync_req_mgrs_.emplace_back(new SyncRequestThreadManager(
this, it.get(), global_callbacks_, min_pollers, max_pollers,
sync_cq_timeout_msec));
this, it.get(), global_callbacks_, server_rq, min_pollers,
max_pollers, sync_cq_timeout_msec));
}
if (default_rq_created) {
grpc_resource_quota_unref(server_rq);
}
}

@ -22,8 +22,8 @@
#include <mutex>
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/exec_ctx.h"
namespace grpc {
@ -48,12 +48,17 @@ ThreadManager::WorkerThread::~WorkerThread() {
thd_.Join();
}
ThreadManager::ThreadManager(int min_pollers, int max_pollers)
ThreadManager::ThreadManager(const char* name,
grpc_resource_quota* resource_quota,
int min_pollers, int max_pollers)
: shutdown_(false),
num_pollers_(0),
min_pollers_(min_pollers),
max_pollers_(max_pollers == -1 ? INT_MAX : max_pollers),
num_threads_(0) {}
num_threads_(0),
max_active_threads_sofar_(0) {
resource_user_ = grpc_resource_user_create(resource_quota, name);
}
ThreadManager::~ThreadManager() {
{
@ -61,6 +66,8 @@ ThreadManager::~ThreadManager() {
GPR_ASSERT(num_threads_ == 0);
}
grpc_core::ExecCtx exec_ctx; // grpc_resource_user_unref needs an exec_ctx
grpc_resource_user_unref(resource_user_);
CleanupCompletedThreads();
}
@ -81,12 +88,18 @@ bool ThreadManager::IsShutdown() {
return shutdown_;
}
int ThreadManager::GetMaxActiveThreadsSoFar() {
std::lock_guard<std::mutex> list_lock(list_mu_);
return max_active_threads_sofar_;
}
void ThreadManager::MarkAsCompleted(WorkerThread* thd) {
{
std::lock_guard<std::mutex> list_lock(list_mu_);
completed_threads_.push_back(thd);
}
{
std::lock_guard<std::mutex> lock(mu_);
num_threads_--;
if (num_threads_ == 0) {
@ -94,6 +107,10 @@ void ThreadManager::MarkAsCompleted(WorkerThread* thd) {
}
}
// Give a thread back to the resource quota
grpc_resource_user_free_threads(resource_user_, 1);
}
void ThreadManager::CleanupCompletedThreads() {
std::list<WorkerThread*> completed_threads;
{
@ -106,14 +123,22 @@ void ThreadManager::CleanupCompletedThreads() {
}
void ThreadManager::Initialize() {
if (!grpc_resource_user_allocate_threads(resource_user_, min_pollers_)) {
gpr_log(GPR_ERROR,
"No thread quota available to even create the minimum required "
"polling threads (i.e %d). Unable to start the thread manager",
min_pollers_);
abort();
}
{
std::unique_lock<std::mutex> lock(mu_);
num_pollers_ = min_pollers_;
num_threads_ = min_pollers_;
max_active_threads_sofar_ = min_pollers_;
}
for (int i = 0; i < min_pollers_; i++) {
// Create a new thread (which ends up calling the MainWorkLoop() function
new WorkerThread(this);
}
}
@ -139,11 +164,15 @@ void ThreadManager::MainWorkLoop() {
done = true;
break;
case WORK_FOUND:
// If we got work and there are now insufficient pollers, start a new
// one
if (!shutdown_ && num_pollers_ < min_pollers_) {
// If we got work and there are now insufficient pollers and there is
// quota available to create a new thread, start a new poller thread
if (!shutdown_ && num_pollers_ < min_pollers_ &&
grpc_resource_user_allocate_threads(resource_user_, 1)) {
num_pollers_++;
num_threads_++;
if (num_threads_ > max_active_threads_sofar_) {
max_active_threads_sofar_ = num_threads_;
}
// Drop lock before spawning thread to avoid contention
lock.unlock();
new WorkerThread(this);
@ -196,6 +225,8 @@ void ThreadManager::MainWorkLoop() {
}
};
// This thread is exiting. Do some cleanup work i.e delete already completed
// worker threads
CleanupCompletedThreads();
// If we are here, either ThreadManager is shutting down or it already has

@ -27,12 +27,14 @@
#include <grpcpp/support/config.h>
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/resource_quota.h"
namespace grpc {
class ThreadManager {
public:
explicit ThreadManager(int min_pollers, int max_pollers);
explicit ThreadManager(const char* name, grpc_resource_quota* resource_quota,
int min_pollers, int max_pollers);
virtual ~ThreadManager();
// Initializes and Starts the Rpc Manager threads
@ -84,6 +86,11 @@ class ThreadManager {
// all the threads have drained all the outstanding work
virtual void Wait();
// Max number of concurrent threads that were ever active in this thread
// manager so far. This is useful for debugging purposes (and in unit tests)
// to check if resource_quota is properly being enforced.
int GetMaxActiveThreadsSoFar();
private:
// Helper wrapper class around grpc_core::Thread. Takes a ThreadManager object
// and starts a new grpc_core::Thread to calls the Run() function.
@ -91,6 +98,24 @@ class ThreadManager {
// The Run() function calls ThreadManager::MainWorkLoop() function and once
// that completes, it marks the WorkerThread completed by calling
// ThreadManager::MarkAsCompleted()
//
// WHY IS THIS NEEDED?:
// When a thread terminates, some other thread *must* call Join() on that
// thread so that the resources are released. Having a WorkerThread wrapper
// will make this easier. Once Run() completes, each thread calls the
// following two functions:
// ThreadManager::CleanupCompletedThreads()
// ThreadManager::MarkAsCompleted()
//
// - MarkAsCompleted() puts the WorkerThread object in the ThreadManger's
// completed_threads_ list
// - CleanupCompletedThreads() calls "Join()" on the threads that are already
// in the completed_threads_ list (since a thread cannot call Join() on
// itself, it calls CleanupCompletedThreads() *before* calling
// MarkAsCompleted())
//
// TODO(sreek): Consider creating the threads 'detached' so that Join() need
// not be called (and the need for this WorkerThread class is eliminated)
class WorkerThread {
public:
WorkerThread(ThreadManager* thd_mgr);
@ -111,13 +136,21 @@ class ThreadManager {
void MarkAsCompleted(WorkerThread* thd);
void CleanupCompletedThreads();
// Protects shutdown_, num_pollers_ and num_threads_
// TODO: sreek - Change num_pollers and num_threads_ to atomics
// Protects shutdown_, num_pollers_, num_threads_ and
// max_active_threads_sofar_
std::mutex mu_;
bool shutdown_;
std::condition_variable shutdown_cv_;
// The resource user object to use when requesting quota to create threads
//
// Note: The user of this ThreadManager object must create grpc_resource_quota
// object (that contains the actual max thread quota) and a grpc_resource_user
// object through which quota is requested whenver new threads need to be
// created
grpc_resource_user* resource_user_;
// Number of threads doing polling
int num_pollers_;
@ -125,10 +158,15 @@ class ThreadManager {
int min_pollers_;
int max_pollers_;
// The total number of threads (includes threads includes the threads that are
// currently polling i.e num_pollers_)
// The total number of threads currently active (includes threads includes the
// threads that are currently polling i.e num_pollers_)
int num_threads_;
// See GetMaxActiveThreadsSoFar()'s description.
// To be more specific, this variable tracks the max value num_threads_ was
// ever set so far
int max_active_threads_sofar_;
std::mutex list_mu_;
std::list<WorkerThread*> completed_threads_;
};

@ -17,8 +17,8 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="NUnit" Version="3.6.0" />
<PackageReference Include="NUnitLite" Version="3.6.0" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnitLite" Version="3.10.1" />
<PackageReference Include="OpenCover" Version="4.6.519" />
<PackageReference Include="ReportGenerator" Version="2.4.4.0" />
</ItemGroup>

@ -65,13 +65,13 @@ namespace Grpc.Core.Tests
{
foreach (var m in t.GetMethods())
{
var attributes = m.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute), true);
if (attributes.Length > 0)
var testAttributes = m.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute), true);
var testCaseAttributes = m.GetCustomAttributes(typeof(NUnit.Framework.TestCaseAttribute), true);
if (testAttributes.Length > 0 || testCaseAttributes.Length > 0)
{
testClasses.Add(t.FullName);
break;
}
}
}
testClasses.Sort();

@ -47,35 +47,35 @@
<Pack>true</Pack>
</Content>
<Content Include="..\nativelibs\csharp_ext_linux_android_armeabi-v7a\libgrpc_csharp_ext.so">
<PackagePath>runtimes/monoandroid/armeabi-v7a/libgrpc_csharp_ext.so</PackagePath>
<PackagePath>native/android/armeabi-v7a/libgrpc_csharp_ext.so</PackagePath>
<Pack>true</Pack>
</Content>
<Content Include="..\nativelibs\csharp_ext_linux_android_arm64-v8a\libgrpc_csharp_ext.so">
<PackagePath>runtimes/monoandroid/arm64-v8a/libgrpc_csharp_ext.so</PackagePath>
<PackagePath>native/android/arm64-v8a/libgrpc_csharp_ext.so</PackagePath>
<Pack>true</Pack>
</Content>
<Content Include="..\nativelibs\csharp_ext_linux_android_x86\libgrpc_csharp_ext.so">
<PackagePath>runtimes/monoandroid/x86/libgrpc_csharp_ext.so</PackagePath>
<PackagePath>native/android/x86/libgrpc_csharp_ext.so</PackagePath>
<Pack>true</Pack>
</Content>
<Content Include="..\nativelibs\csharp_ext_macos_ios\libgrpc_csharp_ext.a">
<PackagePath>runtimes/ios/native/libgrpc_csharp_ext.a</PackagePath>
<PackagePath>native/ios/universal/libgrpc_csharp_ext.a</PackagePath>
<Pack>true</Pack>
</Content>
<Content Include="..\nativelibs\csharp_ext_macos_ios\libgrpc.a">
<PackagePath>runtimes/ios/native/libgrpc.a</PackagePath>
<PackagePath>native/ios/universal/libgrpc.a</PackagePath>
<Pack>true</Pack>
</Content>
<Content Include="build\net45\Grpc.Core.targets">
<PackagePath>build/net45/</PackagePath>
<Pack>true</Pack>
</Content>
<Content Include="build\MonoAndroid\Grpc.Core.targets">
<PackagePath>build/MonoAndroid/</PackagePath>
<Content Include="build\MonoAndroid10\Grpc.Core.targets">
<PackagePath>build/MonoAndroid10/</PackagePath>
<Pack>true</Pack>
</Content>
<Content Include="build\Xamarin.iOS\Grpc.Core.targets">
<PackagePath>build/Xamarin.iOS/</PackagePath>
<Content Include="build\Xamarin.iOS10\Grpc.Core.targets">
<PackagePath>build/Xamarin.iOS10/</PackagePath>
<Pack>true</Pack>
</Content>
</ItemGroup>

@ -50,6 +50,7 @@ namespace Grpc.Core
static int requestCallContextPoolThreadLocalCapacity = DefaultRequestCallContextPoolThreadLocalCapacity;
static readonly HashSet<Channel> registeredChannels = new HashSet<Channel>();
static readonly HashSet<Server> registeredServers = new HashSet<Server>();
static readonly AtomicCounter nativeInitCounter = new AtomicCounter();
static ILogger logger = new LogLevelFilterLogger(new ConsoleLogger(), LogLevel.Off, true);
@ -360,13 +361,26 @@ namespace Grpc.Core
internal static void GrpcNativeInit()
{
if (!IsNativeShutdownAllowed && nativeInitCounter.Count > 0)
{
// Normally grpc_init and grpc_shutdown calls should come in pairs (C core does reference counting),
// but in case we avoid grpc_shutdown calls altogether, calling grpc_init has no effect
// besides incrementing an internal C core counter that could theoretically overflow.
// To avoid this theoretical possibility we guard repeated calls to grpc_init()
// with a 64-bit atomic counter (that can't realistically overflow).
return;
}
NativeMethods.Get().grpcsharp_init();
nativeInitCounter.Increment();
}
internal static void GrpcNativeShutdown()
{
if (IsNativeShutdownAllowed)
{
NativeMethods.Get().grpcsharp_shutdown();
}
}
/// <summary>
/// Shuts down this environment.
@ -411,6 +425,14 @@ namespace Grpc.Core
return GetThreadPoolSizeOrDefault();
}
// On some platforms (specifically iOS), thread local variables in native code
// require initialization/destruction. By skipping the grpc_shutdown() call,
// we avoid a potential crash where grpc_shutdown() has already destroyed
// the thread local variables, but some C core's *_destroy() methods still
// need to run (e.g. they may be run by finalizer thread which is out of our control)
// For more context, see https://github.com/grpc/grpc/issues/16294
private static bool IsNativeShutdownAllowed => !PlatformApis.IsXamarinIOS && !PlatformApis.IsUnityIOS;
private static class ShutdownHooks
{
static object staticLock = new object();

@ -42,6 +42,7 @@ namespace Grpc.Core.Internal
static readonly bool isMono;
static readonly bool isNetCore;
static readonly bool isUnity;
static readonly bool isUnityIOS;
static readonly bool isXamarin;
static readonly bool isXamarinIOS;
static readonly bool isXamarinAndroid;
@ -63,7 +64,25 @@ namespace Grpc.Core.Internal
isNetCore = false;
#endif
isMono = Type.GetType("Mono.Runtime") != null;
isUnity = Type.GetType(UnityEngineApplicationClassName) != null;
// Unity
var unityApplicationClass = Type.GetType(UnityEngineApplicationClassName);
if (unityApplicationClass != null)
{
isUnity = true;
// Consult value of Application.platform via reflection
// https://docs.unity3d.com/ScriptReference/Application-platform.html
var platformProperty = unityApplicationClass.GetTypeInfo().GetProperty("platform");
var unityRuntimePlatform = platformProperty?.GetValue(null)?.ToString();
isUnityIOS = (unityRuntimePlatform == "IPhonePlayer");
}
else
{
isUnity = false;
isUnityIOS = false;
}
// Xamarin
isXamarinIOS = Type.GetType(XamarinIOSObjectClassName) != null;
isXamarinAndroid = Type.GetType(XamarinAndroidObjectClassName) != null;
isXamarin = isXamarinIOS || isXamarinAndroid;
@ -97,6 +116,14 @@ namespace Grpc.Core.Internal
get { return isUnity; }
}
/// <summary>
/// true if running on Unity iOS, false otherwise.
/// </summary>
public static bool IsUnityIOS
{
get { return isUnityIOS; }
}
/// <summary>
/// true if running on a Xamarin platform (either Xamarin.Android or Xamarin.iOS),
/// false otherwise.

@ -2,6 +2,6 @@
<Project>
<PropertyGroup>
<GrpcCsharpVersion>1.15.0-dev</GrpcCsharpVersion>
<GoogleProtobufVersion>3.6.0</GoogleProtobufVersion>
<GoogleProtobufVersion>3.6.1</GoogleProtobufVersion>
</PropertyGroup>
</Project>

@ -1,25 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_GrpcCoreNugetNativePath Condition="'$(_GrpcCoreNugetNativePath)' == ''">$(MSBuildThisFileDirectory)..\..\</_GrpcCoreNugetNativePath>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'MonoAndroid'">
<AndroidNativeLibrary Include="$(_GrpcCoreNugetNativePath)runtimes\monoandroid\arm64-v8a\libgrpc_csharp_ext.so">
<AndroidNativeLibrary Include="$(MSBuildThisFileDirectory)..\..\native\android\arm64-v8a\libgrpc_csharp_ext.so">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Abi>arm64-v8a</Abi>
</AndroidNativeLibrary>
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'MonoAndroid'">
<AndroidNativeLibrary Include="$(_GrpcCoreNugetNativePath)runtimes\monoandroid\armeabi-v7a\libgrpc_csharp_ext.so">
<AndroidNativeLibrary Include="$(MSBuildThisFileDirectory)..\..\native\android\armeabi-v7a\libgrpc_csharp_ext.so">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Abi>armeabi-v7a</Abi>
</AndroidNativeLibrary>
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'MonoAndroid'">
<AndroidNativeLibrary Include="$(_GrpcCoreNugetNativePath)runtimes\monoandroid\x86\libgrpc_csharp_ext.so">
<AndroidNativeLibrary Include="$(MSBuildThisFileDirectory)..\..\native\android\x86\libgrpc_csharp_ext.so">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Abi>x86</Abi>
</AndroidNativeLibrary>

@ -2,11 +2,11 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<NativeReference Include="$(MSBuildThisFileDirectory)..\..\runtimes\ios\native\libgrpc_csharp_ext.a">
<NativeReference Include="$(MSBuildThisFileDirectory)..\..\native\ios\universal\libgrpc_csharp_ext.a">
<Kind>Static</Kind>
<ForceLoad>True</ForceLoad>
</NativeReference>
<NativeReference Include="$(MSBuildThisFileDirectory)..\..\runtimes\ios\native\libgrpc.a">
<NativeReference Include="$(MSBuildThisFileDirectory)..\..\native\ios\universal\libgrpc.a">
<Kind>Static</Kind>
<ForceLoad>True</ForceLoad>
</NativeReference>

@ -17,8 +17,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="3.6.0" />
<PackageReference Include="NUnitLite" Version="3.6.0" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnitLite" Version="3.10.1" />
<PackageReference Include="Moq" Version="4.8.2" />
</ItemGroup>

@ -16,8 +16,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="3.6.0" />
<PackageReference Include="NUnitLite" Version="3.6.0" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnitLite" Version="3.10.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">

@ -19,8 +19,8 @@
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
<PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
<PackageReference Include="NUnit" Version="3.6.0" />
<PackageReference Include="NUnitLite" Version="3.6.0" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnitLite" Version="3.10.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">

@ -16,8 +16,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="3.6.0" />
<PackageReference Include="NUnitLite" Version="3.6.0" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnitLite" Version="3.10.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">

@ -45,6 +45,8 @@ static NSMutableDictionary *callFlags;
static NSString *const kAuthorizationHeader = @"authorization";
static NSString *const kBearerPrefix = @"Bearer ";
const char *kCFStreamVarName = "grpc_cfstream";
@interface GRPCCall ()<GRXWriteable>
// Make them read-write.
@property(atomic, strong) NSDictionary *responseHeaders;
@ -206,9 +208,12 @@ static NSString *const kBearerPrefix = @"Bearer ";
} else {
[_responseWriteable enqueueSuccessfulCompletion];
}
#ifndef GRPC_CFSTREAM
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream == nil || enableCFStream[0] != '1') {
[GRPCConnectivityMonitor unregisterObserver:self];
#endif
}
// If the call isn't retained anywhere else, it can be deallocated now.
_retainSelf = nil;
@ -220,17 +225,16 @@ static NSString *const kBearerPrefix = @"Bearer ";
}
- (void)cancel {
[self
maybeFinishWithError:[NSError
errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{NSLocalizedDescriptionKey : @"Canceled by app"}]];
if (!self.isWaitingForToken) {
[self cancelCall];
} else {
self.isWaitingForToken = NO;
}
[self
maybeFinishWithError:[NSError
errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{NSLocalizedDescriptionKey : @"Canceled by app"}]];
}
- (void)maybeFinishWithError:(NSError *)errorOrNil {
@ -292,6 +296,7 @@ static NSString *const kBearerPrefix = @"Bearer ";
// 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.
[strongSelf cancelCall];
[strongSelf
maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeResourceExhausted
@ -300,7 +305,6 @@ static NSString *const kBearerPrefix = @"Bearer ";
@"Client does not have enough memory to "
@"hold the server response."
}]];
[strongSelf cancelCall];
return;
}
[strongWriteable enqueueValue:data
@ -463,9 +467,11 @@ static NSString *const kBearerPrefix = @"Bearer ";
[self sendHeaders:_requestHeaders];
[self invokeCall];
#ifndef GRPC_CFSTREAM
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream == nil || enableCFStream[0] != '1') {
[GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)];
#endif
}
}
- (void)startWithWriteable:(id<GRXWriteable>)writeable {
@ -530,13 +536,17 @@ static NSString *const kBearerPrefix = @"Bearer ";
}
- (void)connectivityChanged:(NSNotification *)note {
[self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
// Cancel underlying call upon this notification
__strong GRPCCall *strongSelf = self;
if (strongSelf) {
[self cancelCall];
[self
maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable
userInfo:@{
NSLocalizedDescriptionKey : @"Connectivity lost."
}]];
// Cancel underlying call upon this notification
[self cancelCall];
}
}
@end

@ -20,13 +20,8 @@
#import <grpc/grpc.h>
#ifdef GRPC_CFSTREAM
const grpc_completion_queue_attributes kCompletionQueueAttr = {GRPC_CQ_CURRENT_VERSION,
GRPC_CQ_NEXT, GRPC_CQ_NON_POLLING};
#else
const grpc_completion_queue_attributes kCompletionQueueAttr = {
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING};
#endif
@implementation GRPCCompletionQueue

@ -34,6 +34,8 @@
NS_ASSUME_NONNULL_BEGIN
extern const char *kCFStreamVarName;
static NSMutableDictionary *kHostCache;
@implementation GRPCHost {
@ -49,9 +51,11 @@ static NSMutableDictionary *kHostCache;
if (_channelCreds != nil) {
grpc_channel_credentials_release(_channelCreds);
}
#ifndef GRPC_CFSTREAM
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream == nil || enableCFStream[0] != '1') {
[GRPCConnectivityMonitor unregisterObserver:self];
#endif
}
}
// Default initializer.
@ -87,9 +91,12 @@ static NSMutableDictionary *kHostCache;
_compressAlgorithm = GRPC_COMPRESS_NONE;
_retryEnabled = YES;
}
#ifndef GRPC_CFSTREAM
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream == nil || enableCFStream[0] != '1') {
[GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)];
#endif
}
}
return self;
}

@ -187,6 +187,7 @@
grpc_slice _details;
size_t _detailsCapacity;
grpc_metadata_array _trailers;
const char *_errorString;
}
- (instancetype)init {
@ -200,6 +201,7 @@
_op.data.recv_status_on_client.status_details = &_details;
grpc_metadata_array_init(&_trailers);
_op.data.recv_status_on_client.trailing_metadata = &_trailers;
_op.data.recv_status_on_client.error_string = &_errorString;
if (handler) {
// Prevent reference cycle with _handler
__weak typeof(self) weakSelf = self;
@ -207,8 +209,9 @@
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
char *details = grpc_slice_to_c_string(strongSelf->_details);
NSError *error =
[NSError grpc_errorFromStatusCode:strongSelf->_statusCode details:details];
NSError *error = [NSError grpc_errorFromStatusCode:strongSelf->_statusCode
details:details
errorString:strongSelf->_errorString];
NSDictionary *trailers =
[NSDictionary grpc_dictionaryFromMetadataArray:strongSelf->_trailers];
handler(error, trailers);
@ -223,6 +226,7 @@
- (void)dealloc {
grpc_metadata_array_destroy(&_trailers);
grpc_slice_unref(_details);
gpr_free((void *)_errorString);
}
@end

@ -24,5 +24,7 @@
* Returns nil if the status code is OK. Otherwise, a NSError whose code is one of |GRPCErrorCode|
* and whose domain is |kGRPCErrorDomain|.
*/
+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(char *)details;
+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode
details:(char *)details
errorString:(const char *)errorString;
@end

@ -23,13 +23,19 @@
NSString *const kGRPCErrorDomain = @"io.grpc";
@implementation NSError (GRPC)
+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(char *)details {
+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode
details:(char *)details
errorString:(const char *)errorString {
if (statusCode == GRPC_STATUS_OK) {
return nil;
}
NSString *message = [NSString stringWithCString:details encoding:NSUTF8StringEncoding];
NSString *debugMessage = [NSString stringWithCString:errorString encoding:NSUTF8StringEncoding];
return [NSError errorWithDomain:kGRPCErrorDomain
code:statusCode
userInfo:@{NSLocalizedDescriptionKey : message}];
userInfo:@{
NSLocalizedDescriptionKey : message,
NSDebugDescriptionErrorKey : debugMessage
}];
}
@end

@ -13,17 +13,17 @@ interface that gRPC uses when it is ready for production.
## Usage
If you use gRPC following the instructions in
[README.md](https://github.com/grpc/grpc/blob/master/src/objective-c/README.md):
- Simply replace the
dependency on `gRPC-ProtoRPC` with `gRPC-ProtoRPC/CFStream`. The build system will take care of
everything else and switch networking to CFStream.
- Replace the
dependency on `gRPC-ProtoRPC` with `gRPC-ProtoRPC/CFStream`.
- Enable CFStream with environment variable `grpc_cfstream=1`. This can be done either in Xcode
console or by your code with `setenv()` before gRPC is initialized.
If your project directly depends on podspecs other than `gRPC-ProtoRPC` (e.g. `gRPC` or
`gRPC-Core`):
- Make your projects depend on subspecs corresponding to CFStream in each gRPC podspec. For
`gRPC-Core`, you will need to make sure that the completion queue you create is of type
`GRPC_CQ_NON_POLLING`. This is expected to be fixed soon so that you do not have to modify the
completion queue type.
- Make your projects depend on subspecs corresponding to CFStream in each gRPC podspec.
- Enable CFStream with environment variable `grpc_cfstream=1`. This can be done either in Xcode
console or by your code with `setenv()` before gRPC is initialized.
## Notes

@ -591,4 +591,39 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
[self testTimeoutBackoffWithTimeout:0.3 Backoff:0.7];
}
- (void)testErrorDebugInformation {
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."];
RMTSimpleRequest *request = [RMTSimpleRequest message];
request.fillUsername = YES;
request.fillOauthScope = YES;
GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]];
GRPCCall *call = [[GRPCCall alloc] initWithHost:kRemoteSSLHost
path:kUnaryCallMethod.HTTPPath
requestsWriter:requestsWriter];
call.oauth2AccessToken = @"bogusToken";
id<GRXWriteable> responsesWriteable =
[[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
XCTFail(@"Received unexpected response: %@", value);
}
completionHandler:^(NSError *errorOrNil) {
XCTAssertNotNil(errorOrNil, @"Finished without error!");
NSDictionary *userInfo = errorOrNil.userInfo;
NSString *debugInformation = userInfo[NSDebugDescriptionErrorKey];
XCTAssertNotNil(debugInformation);
XCTAssertNotEqual([debugInformation length], 0);
NSString *challengeHeader = call.oauth2ChallengeHeader;
XCTAssertGreaterThan(challengeHeader.length, 0, @"No challenge in response headers %@",
call.responseHeaders);
[expectation fulfill];
}];
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
@end

@ -36,6 +36,8 @@
#define TEST_TIMEOUT 32
extern const char *kCFStreamVarName;
// Convenience constructors for the generated proto messages:
@interface RMTStreamingOutputCallRequest (Constructors)
@ -97,6 +99,9 @@ BOOL isRemoteInteropTest(NSString *host) {
[Cronet start];
[GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]];
#endif
#ifdef GRPC_CFSTREAM
setenv(kCFStreamVarName, "1", 1);
#endif
}
- (void)setUp {

@ -1982,6 +1982,16 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"COCOAPODS=1",
"$(inherited)",
"GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
"$(inherited)",
"PB_FIELD_32BIT=1",
"PB_NO_PACKED_STRUCTS=1",
"GRPC_CFSTREAM=1",
);
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@ -2100,6 +2110,16 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"COCOAPODS=1",
"$(inherited)",
"GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
"$(inherited)",
"PB_FIELD_32BIT=1",
"PB_NO_PACKED_STRUCTS=1",
"GRPC_CFSTREAM=1",
);
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@ -2218,6 +2238,16 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"COCOAPODS=1",
"$(inherited)",
"GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
"$(inherited)",
"PB_FIELD_32BIT=1",
"PB_NO_PACKED_STRUCTS=1",
"GRPC_CFSTREAM=1",
);
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";

@ -309,13 +309,18 @@ cdef SegregatedCall _segregated_call(
_ChannelState state, int flags, method, host, object deadline,
object metadata, CallCredentials credentials, operationses_and_user_tags):
cdef _CallState call_state = _CallState()
cdef grpc_completion_queue *c_completion_queue = (
grpc_completion_queue_create_for_next(NULL))
cdef SegregatedCall segregated_call
cdef grpc_completion_queue *c_completion_queue
def on_success(started_tags):
state.segregated_call_states.add(call_state)
with state.condition:
if state.open:
c_completion_queue = (grpc_completion_queue_create_for_next(NULL))
else:
raise ValueError('Cannot invoke RPC on closed channel!')
try:
_call(
state, call_state, c_completion_queue, on_success, flags, method, host,
@ -443,8 +448,11 @@ cdef class Channel:
def check_connectivity_state(self, bint try_to_connect):
with self._state.condition:
if self._state.open:
return grpc_channel_check_connectivity_state(
self._state.c_channel, try_to_connect)
else:
raise ValueError('Cannot invoke RPC on closed channel!')
def watch_connectivity_state(
self, grpc_connectivity_state last_observed_state, object deadline):

@ -254,6 +254,8 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
'src/core/lib/security/security_connector/alts_security_connector.cc',
'src/core/lib/security/security_connector/load_system_roots_fallback.cc',
'src/core/lib/security/security_connector/load_system_roots_linux.cc',
'src/core/lib/security/security_connector/local_security_connector.cc',
'src/core/lib/security/security_connector/security_connector.cc',
'src/core/lib/security/transport/client_auth_filter.cc',

@ -92,6 +92,7 @@ grpc_resource_quota_create_type grpc_resource_quota_create_import;
grpc_resource_quota_ref_type grpc_resource_quota_ref_import;
grpc_resource_quota_unref_type grpc_resource_quota_unref_import;
grpc_resource_quota_resize_type grpc_resource_quota_resize_import;
grpc_resource_quota_set_max_threads_type grpc_resource_quota_set_max_threads_import;
grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import;
grpc_channelz_get_top_channels_type grpc_channelz_get_top_channels_import;
grpc_channelz_get_channel_type grpc_channelz_get_channel_import;
@ -343,6 +344,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_resource_quota_ref_import = (grpc_resource_quota_ref_type) GetProcAddress(library, "grpc_resource_quota_ref");
grpc_resource_quota_unref_import = (grpc_resource_quota_unref_type) GetProcAddress(library, "grpc_resource_quota_unref");
grpc_resource_quota_resize_import = (grpc_resource_quota_resize_type) GetProcAddress(library, "grpc_resource_quota_resize");
grpc_resource_quota_set_max_threads_import = (grpc_resource_quota_set_max_threads_type) GetProcAddress(library, "grpc_resource_quota_set_max_threads");
grpc_resource_quota_arg_vtable_import = (grpc_resource_quota_arg_vtable_type) GetProcAddress(library, "grpc_resource_quota_arg_vtable");
grpc_channelz_get_top_channels_import = (grpc_channelz_get_top_channels_type) GetProcAddress(library, "grpc_channelz_get_top_channels");
grpc_channelz_get_channel_import = (grpc_channelz_get_channel_type) GetProcAddress(library, "grpc_channelz_get_channel");

@ -251,6 +251,9 @@ extern grpc_resource_quota_unref_type grpc_resource_quota_unref_import;
typedef void(*grpc_resource_quota_resize_type)(grpc_resource_quota* resource_quota, size_t new_size);
extern grpc_resource_quota_resize_type grpc_resource_quota_resize_import;
#define grpc_resource_quota_resize grpc_resource_quota_resize_import
typedef void(*grpc_resource_quota_set_max_threads_type)(grpc_resource_quota* resource_quota, int new_max_threads);
extern grpc_resource_quota_set_max_threads_type grpc_resource_quota_set_max_threads_import;
#define grpc_resource_quota_set_max_threads grpc_resource_quota_set_max_threads_import
typedef const grpc_arg_pointer_vtable*(*grpc_resource_quota_arg_vtable_type)(void);
extern grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import;
#define grpc_resource_quota_arg_vtable grpc_resource_quota_arg_vtable_import

@ -4,6 +4,6 @@
<Project>
<PropertyGroup>
<GrpcCsharpVersion>${settings.csharp_version}</GrpcCsharpVersion>
<GoogleProtobufVersion>3.6.0</GoogleProtobufVersion>
<GoogleProtobufVersion>3.6.1</GoogleProtobufVersion>
</PropertyGroup>
</Project>

@ -798,6 +798,98 @@ static void test_negative_rq_free_pool(void) {
}
}
// Simple test to check resource quota thread limits
static void test_thread_limit() {
grpc_core::ExecCtx exec_ctx;
grpc_resource_quota* rq = grpc_resource_quota_create("test_thread_limit");
grpc_resource_user* ru1 = grpc_resource_user_create(rq, "ru1");
grpc_resource_user* ru2 = grpc_resource_user_create(rq, "ru2");
// Max threads = 100
grpc_resource_quota_set_max_threads(rq, 100);
// Request quota for 100 threads (50 for ru1, 50 for ru2)
GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 10));
GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 10));
GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 40));
GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 40));
// Threads exhausted. Next request must fail
GPR_ASSERT(!grpc_resource_user_allocate_threads(ru2, 20));
// Free 20 threads from two different users
grpc_resource_user_free_threads(ru1, 10);
grpc_resource_user_free_threads(ru2, 10);
// Next request to 20 threads must succeed
GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 20));
// No more thread quota again
GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 20));
// Free 10 more
grpc_resource_user_free_threads(ru1, 10);
GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 5));
GPR_ASSERT(
!grpc_resource_user_allocate_threads(ru2, 10)); // Only 5 available
GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 5));
// Teardown (ru1 and ru2 release all the quota back to rq)
grpc_resource_user_unref(ru1);
grpc_resource_user_unref(ru2);
grpc_resource_quota_unref(rq);
}
// Change max quota in either direction dynamically
static void test_thread_maxquota_change() {
grpc_core::ExecCtx exec_ctx;
grpc_resource_quota* rq =
grpc_resource_quota_create("test_thread_maxquota_change");
grpc_resource_user* ru1 = grpc_resource_user_create(rq, "ru1");
grpc_resource_user* ru2 = grpc_resource_user_create(rq, "ru2");
// Max threads = 100
grpc_resource_quota_set_max_threads(rq, 100);
// Request quota for 100 threads (50 for ru1, 50 for ru2)
GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 50));
GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 50));
// Threads exhausted. Next request must fail
GPR_ASSERT(!grpc_resource_user_allocate_threads(ru2, 20));
// Increase maxquota and retry
// Max threads = 150;
grpc_resource_quota_set_max_threads(rq, 150);
GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 20)); // ru2=70, ru1=50
// Decrease maxquota (Note: Quota already given to ru1 and ru2 is unaffected)
// Max threads = 10;
grpc_resource_quota_set_max_threads(rq, 10);
// New requests will fail until quota is available
GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 10));
// Make quota available
grpc_resource_user_free_threads(ru1, 50); // ru1 now has 0
GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 10)); // not enough
grpc_resource_user_free_threads(ru2, 70); // ru2 now has 0
// Now we can get quota up-to 10, the current max
GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 10));
// No more thread quota again
GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 10));
// Teardown (ru1 and ru2 release all the quota back to rq)
grpc_resource_user_unref(ru1);
grpc_resource_user_unref(ru2);
grpc_resource_quota_unref(rq);
}
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
grpc_init();
@ -827,6 +919,11 @@ int main(int argc, char** argv) {
test_negative_rq_free_pool();
gpr_mu_destroy(&g_mu);
gpr_cv_destroy(&g_cv);
// Resource quota thread related
test_thread_limit();
test_thread_maxquota_change();
grpc_shutdown();
return 0;
}

@ -128,6 +128,27 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "linux_system_roots_test",
srcs = ["linux_system_roots_test.cc"],
data = [
"//test/core/security/etc:bundle.pem",
"//test/core/security/etc:test_roots/cert1.pem",
"//test/core/security/etc:test_roots/cert2.pem",
"//test/core/security/etc:test_roots/cert3.pem",
],
language = "C++",
external_deps = [
"gtest",
],
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "ssl_credentials_test",
srcs = ["ssl_credentials_test.cc"],

@ -0,0 +1,22 @@
# Copyright 2018 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
licenses(["notice"]) # Apache v2
exports_files([
"bundle.pem",
"test_roots/cert1.pem",
"test_roots/cert2.pem",
"test_roots/cert3.pem",
])

@ -0,0 +1,2 @@
These files are manual copies of a pem cert from the /etc/ssl/certs/ directory.
They serve only as dummy certificate test files.

@ -0,0 +1,63 @@
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM
FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC
REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp
Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM
VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+
SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ
4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L
cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi
eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV
HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG
A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3
DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j
vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP
DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc
maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D
lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM
FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC
REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp
Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM
VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+
SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ
4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L
cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi
eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV
HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG
A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3
DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j
vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP
DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc
maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D
lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM
FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC
REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp
Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM
VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+
SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ
4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L
cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi
eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV
HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG
A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3
DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j
vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP
DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc
maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D
lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM
FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC
REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp
Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM
VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+
SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ
4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L
cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi
eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV
HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG
A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3
DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j
vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP
DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc
maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D
lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM
FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC
REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp
Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM
VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+
SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ
4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L
cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi
eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV
HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG
A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3
DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j
vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP
DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc
maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D
lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM
FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC
REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp
Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM
VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+
SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ
4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L
cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi
eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV
HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG
A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3
DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j
vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP
DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc
maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D
lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----

@ -0,0 +1,104 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include <stdio.h>
#ifdef GPR_LINUX
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <string.h>
#include <sys/param.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/tmpfile.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/security_connector/load_system_roots.h"
#include "src/core/lib/security/security_connector/load_system_roots_linux.h"
#include "src/core/lib/security/security_connector/security_connector.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security.h"
#include "test/core/util/test_config.h"
#include "gtest/gtest.h"
#ifndef GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR
#define GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_USE_SYSTEM_SSL_ROOTS"
#endif
namespace grpc {
namespace {
TEST(AbsoluteFilePathTest, ConcatenatesCorrectly) {
const char* directory = "nonexistent/test/directory";
const char* filename = "doesnotexist.txt";
char result_path[MAXPATHLEN];
grpc_core::GetAbsoluteFilePath(directory, filename, result_path);
EXPECT_STREQ(result_path, "nonexistent/test/directory/doesnotexist.txt");
}
TEST(CreateRootCertsBundleTest, ReturnsEmpty) {
// Test that CreateRootCertsBundle returns an empty slice for null or
// nonexistent cert directories.
grpc_slice result_slice = grpc_core::CreateRootCertsBundle(nullptr);
EXPECT_TRUE(GRPC_SLICE_IS_EMPTY(result_slice));
grpc_slice_unref(result_slice);
result_slice = grpc_core::CreateRootCertsBundle("does/not/exist");
EXPECT_TRUE(GRPC_SLICE_IS_EMPTY(result_slice));
grpc_slice_unref(result_slice);
}
TEST(CreateRootCertsBundleTest, BundlesCorrectly) {
gpr_setenv(GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR, "true");
// Test that CreateRootCertsBundle returns a correct slice.
grpc_slice roots_bundle = grpc_empty_slice();
GRPC_LOG_IF_ERROR(
"load_file",
grpc_load_file("test/core/security/etc/bundle.pem", 1, &roots_bundle));
// result_slice should have the same content as roots_bundle.
grpc_slice result_slice =
grpc_core::CreateRootCertsBundle("test/core/security/etc/test_roots");
char* result_str = grpc_slice_to_c_string(result_slice);
char* bundle_str = grpc_slice_to_c_string(roots_bundle);
EXPECT_STREQ(result_str, bundle_str);
// Clean up.
unsetenv(GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR);
gpr_free(result_str);
gpr_free(bundle_str);
grpc_slice_unref(roots_bundle);
grpc_slice_unref(result_slice);
}
} // namespace
} // namespace grpc
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#else
int main() {
printf("*** WARNING: this test is only supported on Linux systems ***\n");
return 0;
}
#endif // GPR_LINUX

@ -363,7 +363,7 @@ static void test_ipv6_address_san(void) {
namespace grpc_core {
namespace {
class TestDefafaultSllRootStore : public DefaultSslRootStore {
class TestDefaultSslRootStore : public DefaultSslRootStore {
public:
static grpc_slice ComputePemRootCertsForTesting() {
return ComputePemRootCerts();
@ -389,7 +389,7 @@ static void test_default_ssl_roots(void) {
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
grpc_set_ssl_roots_override_callback(override_roots_success);
grpc_slice roots =
grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
char* roots_contents = grpc_slice_to_c_string(roots);
grpc_slice_unref(roots);
GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
@ -398,7 +398,7 @@ static void test_default_ssl_roots(void) {
/* Now let's set the env var: We should get the contents pointed value
instead. */
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path);
roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
roots_contents = grpc_slice_to_c_string(roots);
grpc_slice_unref(roots);
GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0);
@ -407,7 +407,7 @@ static void test_default_ssl_roots(void) {
/* Now reset the env var. We should fall back to the value overridden using
the api. */
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
roots_contents = grpc_slice_to_c_string(roots);
grpc_slice_unref(roots);
GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
@ -416,10 +416,10 @@ static void test_default_ssl_roots(void) {
/* Now setup a permanent failure for the overridden roots and we should get
an empty slice. */
grpc_set_ssl_roots_override_callback(override_roots_permanent_failure);
roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots));
const tsi_ssl_root_certs_store* root_store =
grpc_core::TestDefafaultSllRootStore::GetRootStore();
grpc_core::TestDefaultSslRootStore::GetRootStore();
GPR_ASSERT(root_store == nullptr);
/* Cleanup. */

@ -131,6 +131,7 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_resource_quota_ref);
printf("%lx", (unsigned long) grpc_resource_quota_unref);
printf("%lx", (unsigned long) grpc_resource_quota_resize);
printf("%lx", (unsigned long) grpc_resource_quota_set_max_threads);
printf("%lx", (unsigned long) grpc_resource_quota_arg_vtable);
printf("%lx", (unsigned long) grpc_channelz_get_top_channels);
printf("%lx", (unsigned long) grpc_channelz_get_channel);

@ -88,20 +88,20 @@ std::shared_ptr<Channel> CreateChannelForTestCase(
std::shared_ptr<CallCredentials> creds;
if (test_case == "compute_engine_creds") {
GPR_ASSERT(FLAGS_use_tls);
creds = GoogleComputeEngineCredentials();
GPR_ASSERT(creds);
creds = FLAGS_custom_credentials_type == "google_default_credentials"
? nullptr
: GoogleComputeEngineCredentials();
} else if (test_case == "jwt_token_creds") {
GPR_ASSERT(FLAGS_use_tls);
grpc::string json_key = GetServiceAccountJsonKey();
std::chrono::seconds token_lifetime = std::chrono::hours(1);
creds =
ServiceAccountJWTAccessCredentials(json_key, token_lifetime.count());
GPR_ASSERT(creds);
creds = FLAGS_custom_credentials_type == "google_default_credentials"
? nullptr
: ServiceAccountJWTAccessCredentials(json_key,
token_lifetime.count());
} else if (test_case == "oauth2_auth_token") {
grpc::string raw_token = GetOauth2AccessToken();
creds = AccessTokenCredentials(raw_token);
GPR_ASSERT(creds);
creds = FLAGS_custom_credentials_type == "google_default_credentials"
? nullptr
: AccessTokenCredentials(GetOauth2AccessToken());
}
if (FLAGS_custom_credentials_type.empty()) {
transport_security security_type =

@ -30,30 +30,44 @@
#include "test/cpp/util/test_config.h"
namespace grpc {
struct ThreadManagerTestSettings {
// The min number of pollers that SHOULD be active in ThreadManager
int min_pollers;
// The max number of pollers that could be active in ThreadManager
int max_pollers;
// The sleep duration in PollForWork() function to simulate "polling"
int poll_duration_ms;
// The sleep duration in DoWork() function to simulate "work"
int work_duration_ms;
// Max number of times PollForWork() is called before shutting down
int max_poll_calls;
};
class ThreadManagerTest final : public grpc::ThreadManager {
public:
ThreadManagerTest()
: ThreadManager(kMinPollers, kMaxPollers),
ThreadManagerTest(const char* name, grpc_resource_quota* rq,
const ThreadManagerTestSettings& settings)
: ThreadManager(name, rq, settings.min_pollers, settings.max_pollers),
settings_(settings),
num_do_work_(0),
num_poll_for_work_(0),
num_work_found_(0) {}
grpc::ThreadManager::WorkStatus PollForWork(void** tag, bool* ok) override;
void DoWork(void* tag, bool ok) override;
void PerformTest();
// Get number of times PollForWork() returned WORK_FOUND
int GetNumWorkFound();
// Get number of times DoWork() was called
int GetNumDoWork();
private:
void SleepForMs(int sleep_time_ms);
static const int kMinPollers = 2;
static const int kMaxPollers = 10;
static const int kPollingTimeoutMsec = 10;
static const int kDoWorkDurationMsec = 1;
// PollForWork will return SHUTDOWN after these many number of invocations
static const int kMaxNumPollForWork = 50;
ThreadManagerTestSettings settings_;
// Counters
gpr_atm num_do_work_; // Number of calls to DoWork
gpr_atm num_poll_for_work_; // Number of calls to PollForWork
gpr_atm num_work_found_; // Number of times WORK_FOUND was returned
@ -69,54 +83,117 @@ void ThreadManagerTest::SleepForMs(int duration_ms) {
grpc::ThreadManager::WorkStatus ThreadManagerTest::PollForWork(void** tag,
bool* ok) {
int call_num = gpr_atm_no_barrier_fetch_add(&num_poll_for_work_, 1);
if (call_num >= kMaxNumPollForWork) {
if (call_num >= settings_.max_poll_calls) {
Shutdown();
return SHUTDOWN;
}
// Simulate "polling for work" by sleeping for sometime
SleepForMs(kPollingTimeoutMsec);
SleepForMs(settings_.poll_duration_ms); // Simulate "polling" duration
*tag = nullptr;
*ok = true;
// Return timeout roughly 1 out of every 3 calls
// Return timeout roughly 1 out of every 3 calls just to make the test a bit
// more interesting
if (call_num % 3 == 0) {
return TIMEOUT;
} else {
}
gpr_atm_no_barrier_fetch_add(&num_work_found_, 1);
return WORK_FOUND;
}
}
void ThreadManagerTest::DoWork(void* tag, bool ok) {
gpr_atm_no_barrier_fetch_add(&num_do_work_, 1);
SleepForMs(kDoWorkDurationMsec); // Simulate doing work by sleeping
SleepForMs(settings_.work_duration_ms); // Simulate work by sleeping
}
void ThreadManagerTest::PerformTest() {
// Initialize() starts the ThreadManager
Initialize();
// Wait for all the threads to gracefully terminate
Wait();
int ThreadManagerTest::GetNumWorkFound() {
return static_cast<int>(gpr_atm_no_barrier_load(&num_work_found_));
}
// The number of times DoWork() was called is equal to the number of times
// WORK_FOUND was returned
gpr_log(GPR_DEBUG, "DoWork() called %" PRIdPTR " times",
gpr_atm_no_barrier_load(&num_do_work_));
GPR_ASSERT(gpr_atm_no_barrier_load(&num_do_work_) ==
gpr_atm_no_barrier_load(&num_work_found_));
int ThreadManagerTest::GetNumDoWork() {
return static_cast<int>(gpr_atm_no_barrier_load(&num_do_work_));
}
} // namespace grpc
// Test that the number of times DoWork() is called is equal to the number of
// times PollForWork() returned WORK_FOUND
static void TestPollAndWork() {
grpc_resource_quota* rq = grpc_resource_quota_create("Test-poll-and-work");
grpc::ThreadManagerTestSettings settings = {
2 /* min_pollers */, 10 /* max_pollers */, 10 /* poll_duration_ms */,
1 /* work_duration_ms */, 50 /* max_poll_calls */};
grpc::ThreadManagerTest test_thread_mgr("TestThreadManager", rq, settings);
grpc_resource_quota_unref(rq);
test_thread_mgr.Initialize(); // Start the thread manager
test_thread_mgr.Wait(); // Wait for all threads to finish
// Verify that The number of times DoWork() was called is equal to the number
// of times WORK_FOUND was returned
gpr_log(GPR_DEBUG, "DoWork() called %d times",
test_thread_mgr.GetNumDoWork());
GPR_ASSERT(test_thread_mgr.GetNumDoWork() ==
test_thread_mgr.GetNumWorkFound());
}
static void TestThreadQuota() {
const int kMaxNumThreads = 3;
grpc_resource_quota* rq = grpc_resource_quota_create("Test-thread-quota");
grpc_resource_quota_set_max_threads(rq, kMaxNumThreads);
// Set work_duration_ms to be much greater than poll_duration_ms. This way,
// the thread manager will be forced to create more 'polling' threads to
// honor the min_pollers guarantee
grpc::ThreadManagerTestSettings settings = {
1 /* min_pollers */, 1 /* max_pollers */, 1 /* poll_duration_ms */,
10 /* work_duration_ms */, 50 /* max_poll_calls */};
// Create two thread managers (but with same resource quota). This means
// that the max number of active threads across BOTH the thread managers
// cannot be greater than kMaxNumthreads
grpc::ThreadManagerTest test_thread_mgr_1("TestThreadManager-1", rq,
settings);
grpc::ThreadManagerTest test_thread_mgr_2("TestThreadManager-2", rq,
settings);
// It is ok to unref resource quota before starting thread managers.
grpc_resource_quota_unref(rq);
// Start both thread managers
test_thread_mgr_1.Initialize();
test_thread_mgr_2.Initialize();
// Wait for both to finish
test_thread_mgr_1.Wait();
test_thread_mgr_2.Wait();
// Now verify that the total number of active threads in either thread manager
// never exceeds kMaxNumThreads
//
// NOTE: Actually the total active threads across *both* thread managers at
// any point of time never exceeds kMaxNumThreads but unfortunately there is
// no easy way to verify it (i.e we can't just do (max1 + max2 <= k))
// Its okay to not test this case here. The resource quota c-core tests
// provide enough coverage to resource quota object with multiple resource
// users
int max1 = test_thread_mgr_1.GetMaxActiveThreadsSoFar();
int max2 = test_thread_mgr_2.GetMaxActiveThreadsSoFar();
gpr_log(
GPR_DEBUG,
"MaxActiveThreads in TestThreadManager_1: %d, TestThreadManager_2: %d",
max1, max2);
GPR_ASSERT(max1 <= kMaxNumThreads && max2 <= kMaxNumThreads);
}
int main(int argc, char** argv) {
std::srand(std::time(nullptr));
grpc::testing::InitTest(&argc, &argv, true);
grpc::ThreadManagerTest test_rpc_manager;
test_rpc_manager.PerformTest();
grpc_init();
TestPollAndWork();
TestThreadQuota();
grpc_shutdown();
return 0;
}

@ -7,5 +7,5 @@ set noparent
# for kokoro to be able to access the pre-built images.
@jtattermusch
@matt-kwong
@mehrdada
@nicolasnoble

@ -22,3 +22,6 @@ RUN yum install -y mono-devel
RUN yum install -y nuget
RUN yum install -y unzip
# Make sure the mono certificate store is up-to-date to prevent issues with nuget restore
RUN curl https://curl.haxx.se/ca/cacert.pem > ~/cacert.pem && cert-sync ~/cacert.pem && rm -f ~/cacert.pem

@ -25,3 +25,7 @@ RUN apt-get update && apt-get install -y \
&& apt-get clean
RUN apt-get update && apt-get install -y unzip && apt-get clean
# Make sure the mono certificate store is up-to-date to prevent issues with nuget restore
RUN apt-get update && apt-get install -y curl && apt-get clean
RUN curl https://curl.haxx.se/ca/cacert.pem > ~/cacert.pem && cert-sync ~/cacert.pem && rm -f ~/cacert.pem

@ -25,3 +25,7 @@ RUN apt-get update && apt-get install -y \
&& apt-get clean
RUN apt-get update && apt-get install -y unzip && apt-get clean
# Make sure the mono certificate store is up-to-date to prevent issues with nuget restore
RUN apt-get update && apt-get install -y curl && apt-get clean
RUN curl https://curl.haxx.se/ca/cacert.pem > ~/cacert.pem && cert-sync ~/cacert.pem && rm -f ~/cacert.pem

@ -38,3 +38,7 @@ RUN mkdir warmup \
&& dotnet new \
&& cd .. \
&& rm -rf warmup
# Make sure the mono certificate store is up-to-date to prevent issues with nuget restore
RUN apt-get update && apt-get install -y curl && apt-get clean
RUN curl https://curl.haxx.se/ca/cacert.pem > ~/cacert.pem && cert-sync ~/cacert.pem && rm -f ~/cacert.pem

@ -25,3 +25,7 @@ RUN apt-get update && apt-get install -y \
&& apt-get clean
RUN apt-get update && apt-get install -y unzip && apt-get clean
# Make sure the mono certificate store is up-to-date to prevent issues with nuget restore
RUN apt-get update && apt-get install -y curl && apt-get clean
RUN curl https://curl.haxx.se/ca/cacert.pem > ~/cacert.pem && cert-sync ~/cacert.pem && rm -f ~/cacert.pem

@ -791,6 +791,7 @@ doc/server-reflection.md \
doc/server_reflection_tutorial.md \
doc/server_side_auth.md \
doc/service_config.md \
doc/ssl-performance.md \
doc/status_ordering.md \
doc/statuscodes.md \
doc/unit_testing.md \

@ -791,6 +791,7 @@ doc/server-reflection.md \
doc/server_reflection_tutorial.md \
doc/server_side_auth.md \
doc/service_config.md \
doc/ssl-performance.md \
doc/status_ordering.md \
doc/statuscodes.md \
doc/unit_testing.md \

@ -793,6 +793,7 @@ doc/server-reflection.md \
doc/server_reflection_tutorial.md \
doc/server_side_auth.md \
doc/service_config.md \
doc/ssl-performance.md \
doc/status_ordering.md \
doc/statuscodes.md \
doc/unit_testing.md \

@ -793,6 +793,7 @@ doc/server-reflection.md \
doc/server_reflection_tutorial.md \
doc/server_side_auth.md \
doc/service_config.md \
doc/ssl-performance.md \
doc/status_ordering.md \
doc/statuscodes.md \
doc/unit_testing.md \
@ -1355,6 +1356,10 @@ src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.h \
src/core/lib/security/security_connector/alts_security_connector.cc \
src/core/lib/security/security_connector/alts_security_connector.h \
src/core/lib/security/security_connector/load_system_roots.h \
src/core/lib/security/security_connector/load_system_roots_fallback.cc \
src/core/lib/security/security_connector/load_system_roots_linux.cc \
src/core/lib/security/security_connector/load_system_roots_linux.h \
src/core/lib/security/security_connector/local_security_connector.cc \
src/core/lib/security/security_connector/local_security_connector.h \
src/core/lib/security/security_connector/security_connector.cc \

@ -17,17 +17,6 @@
# builds. This rc script must be used in the root directory of gRPC
# and is expected to be used before prepare_build_macos_rc
export CONFIG=opt
# Move gRPC repo to directory that Docker for Mac has drive access to
mkdir /Users/kbuilder/workspace
cp -R ./ /Users/kbuilder/workspace/grpc
cd /Users/kbuilder/workspace/grpc
# Needed for identifying Docker image sha1
brew update
brew install md5sha1sum
# Set up gRPC-Go and gRPC-Java to test
git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go
git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java

@ -18,8 +18,8 @@ set -ex
# change to grpc repo root
cd $(dirname $0)/../../..
source tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc
source tools/internal_ci/helper_scripts/prepare_build_macos_rc
source tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc
# using run_interop_tests.py without --use_docker, so we need to build first
tools/run_tests/run_tests.py -l c++ -c opt --build_only

@ -97,7 +97,7 @@ LANG_RELEASE_MATRIX = {
'v1.13.0': None
},
{
'v1.14.0': None
'v1.14.1': None
},
],
'go': [
@ -226,7 +226,7 @@ LANG_RELEASE_MATRIX = {
'v1.13.0': None
},
{
'v1.14.0': None
'v1.14.1': None
},
],
'node': [
@ -314,7 +314,7 @@ LANG_RELEASE_MATRIX = {
'v1.13.0': None
},
{
'v1.14.0': None
'v1.14.1': None
},
],
'php': [
@ -358,7 +358,7 @@ LANG_RELEASE_MATRIX = {
'v1.13.0': None
},
{
'v1.14.0': None
'v1.14.1': None
},
],
'csharp': [
@ -407,7 +407,7 @@ LANG_RELEASE_MATRIX = {
'v1.13.0': None
},
{
'v1.14.0': None
'v1.14.1': None
},
],
}

@ -290,15 +290,9 @@ class PHPArtifact:
return []
def build_jobspec(self):
if self.platform == 'linux':
return create_docker_jobspec(
self.name, 'tools/dockerfile/grpc_artifact_linux_{}'.format(
self.arch),
'tools/run_tests/artifacts/build_artifact_php.sh')
else:
return create_jobspec(
self.name, ['tools/run_tests/artifacts/build_artifact_php.sh'],
use_workspace=True)
self.arch), 'tools/run_tests/artifacts/build_artifact_php.sh')
class ProtocArtifact:
@ -400,6 +394,5 @@ def targets():
PythonArtifact('windows', 'x64', 'Python37'),
RubyArtifact('linux', 'x64'),
RubyArtifact('macos', 'x64'),
PHPArtifact('linux', 'x64'),
PHPArtifact('macos', 'x64')
PHPArtifact('linux', 'x64')
])

@ -73,6 +73,10 @@ docker run \
# Copy output artifacts
if [ "$OUTPUT_DIR" != "" ]
then
# Create the artifact directory in advance to avoid a race in "docker cp" if tasks
# that were running in parallel finish at the same time.
# see https://github.com/grpc/grpc/issues/16155
mkdir -p "$git_root/$OUTPUT_DIR"
docker cp "$CONTAINER_NAME:/var/local/git/grpc/$OUTPUT_DIR" "$git_root" || FAILED="true"
fi

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

Loading…
Cancel
Save