Merge remote-tracking branch 'juanlishen/pf_check_state_before_watch' into pf_keep_unselected_subchannels

reviewable/pr16342/r8
Mark D. Roth 6 years ago
commit e9e92d443c
  1. 6
      .github/CODEOWNERS
  2. 5
      BUILD
  3. 43
      CMakeLists.txt
  4. 77
      Makefile
  5. 17
      build.yaml
  6. 2
      cmake/OWNERS
  7. 4
      cmake/gflags.cmake
  8. 2
      config.m4
  9. 2
      config.w32
  10. 4
      doc/environment_variables.md
  11. 36
      doc/ssl-performance.md
  12. 203
      etc/roots.pem
  13. 2
      gRPC-C++.podspec
  14. 7
      gRPC-Core.podspec
  15. 2
      grpc.def
  16. 4
      grpc.gemspec
  17. 2
      grpc.gyp
  18. 10
      include/grpc/grpc.h
  19. 19
      include/grpc/impl/codegen/grpc_types.h
  20. 4
      include/grpcpp/impl/codegen/async_generic_service.h
  21. 4
      include/grpcpp/impl/codegen/byte_buffer.h
  22. 4
      include/grpcpp/impl/codegen/client_unary_call.h
  23. 11
      include/grpcpp/impl/codegen/completion_queue.h
  24. 17
      include/grpcpp/impl/codegen/method_handler_impl.h
  25. 8
      include/grpcpp/impl/codegen/server_context.h
  26. 12
      include/grpcpp/impl/codegen/sync_stream.h
  27. 16
      include/grpcpp/resource_quota.h
  28. 10
      include/grpcpp/server.h
  29. 4
      package.xml
  30. 2
      src/core/ext/filters/client_channel/client_channel_plugin.cc
  31. 2
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  32. 4
      src/core/ext/filters/deadline/deadline_filter.cc
  33. 12
      src/core/ext/filters/http/client_authority_filter.cc
  34. 27
      src/core/ext/filters/http/http_filters_plugin.cc
  35. 3
      src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
  36. 2
      src/core/ext/filters/max_age/max_age_filter.cc
  37. 6
      src/core/ext/filters/message_size/message_size_filter.cc
  38. 39
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  39. 17
      src/core/ext/transport/chttp2/transport/flow_control.cc
  40. 13
      src/core/ext/transport/chttp2/transport/internal.h
  41. 17
      src/core/ext/transport/chttp2/transport/stream_lists.cc
  42. 4
      src/core/lib/channel/connected_channel.cc
  43. 4
      src/core/lib/channel/connected_channel.h
  44. 54
      src/core/lib/iomgr/ev_posix.cc
  45. 10
      src/core/lib/iomgr/ev_posix.h
  46. 75
      src/core/lib/iomgr/iomgr_posix_cfstream.cc
  47. 5
      src/core/lib/iomgr/port.h
  48. 78
      src/core/lib/iomgr/resource_quota.cc
  49. 16
      src/core/lib/iomgr/resource_quota.h
  50. 2
      src/core/lib/iomgr/tcp_client_cfstream.cc
  51. 29
      src/core/lib/security/security_connector/load_system_roots.h
  52. 32
      src/core/lib/security/security_connector/load_system_roots_fallback.cc
  53. 165
      src/core/lib/security/security_connector/load_system_roots_linux.cc
  54. 44
      src/core/lib/security/security_connector/load_system_roots_linux.h
  55. 18
      src/core/lib/security/security_connector/security_connector.cc
  56. 28
      src/core/lib/surface/channel_init.h
  57. 167
      src/core/lib/surface/completion_queue.cc
  58. 21
      src/core/lib/surface/completion_queue.h
  59. 17
      src/core/lib/surface/completion_queue_factory.cc
  60. 26
      src/core/lib/surface/init.cc
  61. 11
      src/core/lib/surface/init_secure.cc
  62. 9
      src/cpp/common/channel_filter.cc
  63. 7
      src/cpp/common/channel_filter.h
  64. 4
      src/cpp/common/resource_quota_cc.cc
  65. 6
      src/cpp/ext/filters/census/grpc_plugin.cc
  66. 2
      src/cpp/server/server_builder.cc
  67. 57
      src/cpp/server/server_cc.cc
  68. 81
      src/cpp/thread_manager/thread_manager.cc
  69. 54
      src/cpp/thread_manager/thread_manager.h
  70. 4
      src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
  71. 6
      src/csharp/Grpc.Core.Tests/SanityTest.cs
  72. 18
      src/csharp/Grpc.Core/Grpc.Core.csproj
  73. 24
      src/csharp/Grpc.Core/GrpcEnvironment.cs
  74. 29
      src/csharp/Grpc.Core/Internal/PlatformApis.cs
  75. 2
      src/csharp/Grpc.Core/Version.csproj.include
  76. 9
      src/csharp/Grpc.Core/build/MonoAndroid10/Grpc.Core.targets
  77. 4
      src/csharp/Grpc.Core/build/Xamarin.iOS10/Grpc.Core.targets
  78. 4
      src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
  79. 4
      src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
  80. 4
      src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
  81. 4
      src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
  82. 42
      src/objective-c/GRPCClient/GRPCCall.m
  83. 7
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
  84. 19
      src/objective-c/GRPCClient/private/GRPCHost.m
  85. 8
      src/objective-c/GRPCClient/private/GRPCWrappedCall.m
  86. 4
      src/objective-c/GRPCClient/private/NSError+GRPC.h
  87. 10
      src/objective-c/GRPCClient/private/NSError+GRPC.m
  88. 14
      src/objective-c/README-CFSTREAM.md
  89. 35
      src/objective-c/tests/GRPCClientTests.m
  90. 5
      src/objective-c/tests/InteropTests.m
  91. 30
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  92. 5
      src/php/ext/grpc/server.c
  93. 16
      src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
  94. 2
      src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
  95. 2
      src/python/grpcio/grpc_core_dependencies.py
  96. 4
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  97. 6
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  98. 191
      summerofcode/2018/naresh.md
  99. 23
      templates/Makefile.template
  100. 2
      templates/src/csharp/Grpc.Core/Version.csproj.include.template
  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

@ -767,11 +767,20 @@ else
LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE))
endif
# gpr .pc file
PC_NAME = gpr
PC_DESCRIPTION = gRPC platform support library
PC_CFLAGS =
PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GPR)
PC_LIBS_PRIVATE = $(PC_LIBS_GPR)
PC_LIB = -lgpr
GPR_PC_FILE := $(CORE_PC_TEMPLATE)
# grpc .pc file
PC_NAME = gRPC
PC_DESCRIPTION = high performance general RPC framework
PC_CFLAGS =
PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
PC_REQUIRES_PRIVATE = gpr $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPC) $(PC_LIBS_SECURE)
PC_LIB = -lgrpc
GRPC_PC_FILE := $(CORE_PC_TEMPLATE)
@ -780,7 +789,7 @@ GRPC_PC_FILE := $(CORE_PC_TEMPLATE)
PC_NAME = gRPC unsecure
PC_DESCRIPTION = high performance general RPC framework without SSL
PC_CFLAGS =
PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC)
PC_REQUIRES_PRIVATE = gpr $(PC_REQUIRES_GRPC)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
PC_LIB = -lgrpc
GRPC_UNSECURE_PC_FILE := $(CORE_PC_TEMPLATE)
@ -1170,6 +1179,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
@ -1397,9 +1407,9 @@ plugins: $(PROTOC_PLUGINS)
privatelibs: privatelibs_c privatelibs_cxx
privatelibs_c: $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libcxxabi.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libares.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc
pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
pc_cxx: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc
@ -1670,6 +1680,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 +1860,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 +2328,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"
@ -2514,6 +2528,11 @@ cache.mk::
$(E) "[MAKE] Generating $@"
$(Q) echo "$(CACHE_MK)" | tr , '\n' >$@
$(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc:
$(E) "[MAKE] Generating $@"
$(Q) mkdir -p $(@D)
$(Q) echo "$(GPR_PC_FILE)" | tr , '\n' >$@
$(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc:
$(E) "[MAKE] Generating $@"
$(Q) mkdir -p $(@D)
@ -3124,6 +3143,7 @@ install-grpc-cli: grpc_cli
install-pkg-config_c: pc_c pc_c_unsecure
$(E) "[INSTALL] Installing C pkg-config files"
$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
$(Q) $(INSTALL) -m 0644 $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc $(prefix)/lib/pkgconfig/gpr.pc
$(Q) $(INSTALL) -m 0644 $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(prefix)/lib/pkgconfig/grpc.pc
$(Q) $(INSTALL) -m 0644 $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(prefix)/lib/pkgconfig/grpc_unsecure.pc
@ -3608,6 +3628,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 +4059,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 +17931,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 +24718,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
@ -4106,6 +4111,7 @@ targets:
- mac
- linux
- posix
uses_polling: false
- name: bm_error
build: test
language: c++
@ -4698,6 +4704,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

@ -28,8 +28,8 @@ if("${gRPC_GFLAGS_PROVIDER}" STREQUAL "module")
elseif("${gRPC_GFLAGS_PROVIDER}" STREQUAL "package")
# Use "CONFIG" as there is no built-in cmake module for gflags.
find_package(gflags REQUIRED CONFIG)
if(TARGET gflags::gflags)
set(_gRPC_GFLAGS_LIBRARIES gflags::gflags)
if(TARGET gflags)
set(_gRPC_GFLAGS_LIBRARIES gflags)
set(_gRPC_GFLAGS_INCLUDE_DIR ${GFLAGS_INCLUDE_DIR})
endif()
set(_gRPC_FIND_GFLAGS "if(NOT gflags_FOUND)\n find_package(gflags CONFIG)\nendif()")

@ -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.

@ -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',

@ -20,6 +20,7 @@ EXPORTS
grpc_completion_queue_factory_lookup
grpc_completion_queue_create_for_next
grpc_completion_queue_create_for_pluck
grpc_completion_queue_create_for_callback
grpc_completion_queue_create
grpc_completion_queue_next
grpc_completion_queue_pluck
@ -69,6 +70,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',

@ -101,6 +101,12 @@ GRPCAPI grpc_completion_queue* grpc_completion_queue_create_for_next(
GRPCAPI grpc_completion_queue* grpc_completion_queue_create_for_pluck(
void* reserved);
/** Helper function to create a completion queue with grpc_cq_completion_type
of GRPC_CQ_CALLBACK and grpc_cq_polling_type of GRPC_CQ_DEFAULT_POLLING.
This function is experimental. */
GRPCAPI grpc_completion_queue* grpc_completion_queue_create_for_callback(
void* shutdown_callback, void* reserved);
/** Create a completion queue */
GRPCAPI grpc_completion_queue* grpc_completion_queue_create(
const grpc_completion_queue_factory* factory,
@ -460,6 +466,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);

@ -651,10 +651,16 @@ typedef enum {
GRPC_CQ_NEXT,
/** Events are popped out by calling grpc_completion_queue_pluck() API ONLY*/
GRPC_CQ_PLUCK
GRPC_CQ_PLUCK,
/** EXPERIMENTAL: Events trigger a callback specified as the tag */
GRPC_CQ_CALLBACK
} grpc_cq_completion_type;
#define GRPC_CQ_CURRENT_VERSION 1
/* The upgrade to version 2 is currently experimental. */
#define GRPC_CQ_CURRENT_VERSION 2
#define GRPC_CQ_VERSION_MINIMUM_FOR_CALLBACKABLE 2
typedef struct grpc_completion_queue_attributes {
/** The version number of this structure. More fields might be added to this
structure in future. */
@ -663,6 +669,15 @@ typedef struct grpc_completion_queue_attributes {
grpc_cq_completion_type cq_completion_type;
grpc_cq_polling_type cq_polling_type;
/* END OF VERSION 1 CQ ATTRIBUTES */
/* EXPERIMENTAL: START OF VERSION 2 CQ ATTRIBUTES */
/** When creating a callbackable CQ, pass in a functor to get invoked when
* shutdown is complete */
void* cq_shutdown_cb;
/* END OF VERSION 2 CQ ATTRIBUTES */
} grpc_completion_queue_attributes;
/** The completion queue factory structure is opaque to the callers of grpc */

@ -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

@ -45,6 +45,8 @@ template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
template <class R>
class DeserializeFuncType;
class GrpcByteBufferPeer;
@ -144,6 +146,8 @@ class ByteBuffer final {
friend class internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class internal::ServerStreamingHandler;
template <StatusCode code>
friend class internal::ErrorMethodHandler;
template <class R>
friend class internal::DeserializeFuncType;
friend class ProtoBufferReader;

@ -50,8 +50,8 @@ class BlockingUnaryCallImpl {
ClientContext* context, const InputMessage& request,
OutputMessage* result) {
CompletionQueue cq(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}); // Pluckable completion queue
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}); // Pluckable completion queue
Call call(channel->CreateCall(method, context, &cq));
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,

@ -78,9 +78,10 @@ template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler;
class UnknownMethodHandler;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
} // namespace internal
@ -97,7 +98,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// instance.
CompletionQueue()
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING}) {}
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING,
nullptr}) {}
/// Wrap \a take, taking ownership of the instance.
///
@ -264,7 +266,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
friend class ::grpc::internal::ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
friend class ::grpc::internal::TemplatedBidiStreamingHandler;
friend class ::grpc::internal::UnknownMethodHandler;
template <StatusCode code>
friend class ::grpc::internal::ErrorMethodHandler;
friend class ::grpc::Server;
friend class ::grpc::ServerContext;
friend class ::grpc::ServerInterface;
@ -376,7 +379,7 @@ class ServerCompletionQueue : public CompletionQueue {
/// frequently polled.
ServerCompletionQueue(grpc_cq_polling_type polling_type)
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, polling_type}),
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, polling_type, nullptr}),
polling_type_(polling_type) {}
grpc_cq_polling_type polling_type_;

@ -272,12 +272,14 @@ class SplitServerStreamingHandler
ServerSplitStreamer<RequestType, ResponseType>, false>(func) {}
};
/// Handle unknown method by returning UNIMPLEMENTED error.
class UnknownMethodHandler : public MethodHandler {
/// General method handler class for errors that prevent real method use
/// e.g., handle unknown method by returning UNIMPLEMENTED error.
template <StatusCode code>
class ErrorMethodHandler : public MethodHandler {
public:
template <class T>
static void FillOps(ServerContext* context, T* ops) {
Status status(StatusCode::UNIMPLEMENTED, "");
Status status(code, "");
if (!context->sent_initial_metadata_) {
ops->SendInitialMetadata(context->initial_metadata_,
context->initial_metadata_flags());
@ -294,9 +296,18 @@ class UnknownMethodHandler : public MethodHandler {
FillOps(param.server_context, &ops);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
// We also have to destroy any request payload in the handler parameter
ByteBuffer* payload = param.request.bbuf_ptr();
if (payload != nullptr) {
payload->Clear();
}
}
};
typedef ErrorMethodHandler<StatusCode::UNIMPLEMENTED> UnknownMethodHandler;
typedef ErrorMethodHandler<StatusCode::RESOURCE_EXHAUSTED>
ResourceExhaustedHandler;
} // namespace internal
} // namespace grpc

@ -63,9 +63,10 @@ template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler;
class UnknownMethodHandler;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
class Call;
} // namespace internal
@ -226,6 +227,8 @@ class ServerContext {
/// Async only. Has to be called before the rpc starts.
/// Returns the tag in completion queue when the rpc finishes.
/// IsCancelled() can then be called to check whether the rpc was cancelled.
/// TODO(vjpai): Fix this so that the tag is returned even if the call never
/// starts (https://github.com/grpc/grpc/issues/10136).
void AsyncNotifyWhenDone(void* tag) {
has_notify_when_done_tag_ = true;
async_notify_when_done_tag_ = tag;
@ -262,7 +265,8 @@ class ServerContext {
friend class ::grpc::internal::ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
friend class ::grpc::internal::TemplatedBidiStreamingHandler;
friend class ::grpc::internal::UnknownMethodHandler;
template <StatusCode code>
friend class internal::ErrorMethodHandler;
friend class ::grpc::ClientContext;
/// Prevent copying.

@ -243,8 +243,8 @@ class ClientReader final : public ClientReaderInterface<R> {
ClientContext* context, const W& request)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
@ -377,8 +377,8 @@ class ClientWriter : public ClientWriterInterface<W> {
ClientContext* context, R* response)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
finish_ops_.RecvMessage(response);
finish_ops_.AllowNoMessage();
@ -551,8 +551,8 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
ClientContext* context)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>

@ -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.
///
@ -218,6 +223,9 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
std::unique_ptr<HealthCheckServiceInterface> health_check_service_;
bool health_check_service_disabled_;
// A special handler for resource exhausted in sync case
std::unique_ptr<internal::MethodHandler> resource_exhausted_handler_;
};
} // namespace grpc

@ -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" />

@ -56,7 +56,7 @@ void grpc_client_channel_init(void) {
grpc_register_http_proxy_mapper();
grpc_subchannel_index_init();
grpc_channel_init_register_stage(
GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, append_filter,
GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, append_filter,
(void*)&grpc_client_channel_filter);
grpc_http_connect_register_handshaker_factory();
}

@ -1890,7 +1890,7 @@ void grpc_lb_policy_grpclb_init() {
grpc_core::UniquePtr<grpc_core::LoadBalancingPolicyFactory>(
grpc_core::New<grpc_core::GrpcLbFactory>()));
grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_LOW,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_client_load_reporting_filter,
(void*)&grpc_client_load_reporting_filter);
}

@ -379,10 +379,10 @@ static bool maybe_add_deadline_filter(grpc_channel_stack_builder* builder,
void grpc_deadline_filter_init(void) {
grpc_channel_init_register_stage(
GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH,
GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_deadline_filter, (void*)&grpc_client_deadline_filter);
grpc_channel_init_register_stage(
GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH,
GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_deadline_filter, (void*)&grpc_server_deadline_filter);
}

@ -146,12 +146,12 @@ static bool add_client_authority_filter(grpc_channel_stack_builder* builder,
}
void grpc_client_authority_filter_init(void) {
grpc_channel_init_register_stage(
GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH,
add_client_authority_filter, (void*)&grpc_client_authority_filter);
grpc_channel_init_register_stage(
GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH,
add_client_authority_filter, (void*)&grpc_client_authority_filter);
grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX,
add_client_authority_filter,
(void*)&grpc_client_authority_filter);
grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX,
add_client_authority_filter,
(void*)&grpc_client_authority_filter);
}
void grpc_client_authority_filter_shutdown(void) {}

@ -18,7 +18,6 @@
#include <grpc/support/port_platform.h>
#include <limits.h>
#include <string.h>
#include "src/core/ext/filters/http/client/http_client_filter.h"
@ -52,15 +51,15 @@ static bool maybe_add_optional_filter(grpc_channel_stack_builder* builder,
bool enable = grpc_channel_arg_get_bool(
grpc_channel_args_find(channel_args, filtarg->control_channel_arg),
!grpc_channel_args_want_minimal_stack(channel_args));
return enable ? grpc_channel_stack_builder_append_filter(
return enable ? grpc_channel_stack_builder_prepend_filter(
builder, filtarg->filter, nullptr, nullptr)
: true;
}
static bool maybe_append_required_filter(grpc_channel_stack_builder* builder,
void* arg) {
static bool maybe_add_required_filter(grpc_channel_stack_builder* builder,
void* arg) {
return is_building_http_like_transport(builder)
? grpc_channel_stack_builder_append_filter(
? grpc_channel_stack_builder_prepend_filter(
builder, static_cast<const grpc_channel_filter*>(arg),
nullptr, nullptr)
: true;
@ -68,23 +67,23 @@ static bool maybe_append_required_filter(grpc_channel_stack_builder* builder,
void grpc_http_filters_init(void) {
grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_HIGH,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_optional_filter, &compress_filter);
grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_HIGH,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_optional_filter, &compress_filter);
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_HIGH,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_optional_filter, &compress_filter);
grpc_channel_init_register_stage(
GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH,
maybe_append_required_filter, (void*)&grpc_http_client_filter);
GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_required_filter, (void*)&grpc_http_client_filter);
grpc_channel_init_register_stage(
GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH,
maybe_append_required_filter, (void*)&grpc_http_client_filter);
GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_required_filter, (void*)&grpc_http_client_filter);
grpc_channel_init_register_stage(
GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH,
maybe_append_required_filter, (void*)&grpc_http_server_filter);
GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_required_filter, (void*)&grpc_http_server_filter);
}
void grpc_http_filters_shutdown(void) {}

@ -345,8 +345,7 @@ struct ServerLoadReportingFilterStaticRegistrar {
if (registered) return;
RegisterChannelFilter<ServerLoadReportingChannelData,
ServerLoadReportingCallData>(
"server_load_reporting", GRPC_SERVER_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_LOW, true,
"server_load_reporting", GRPC_SERVER_CHANNEL, INT_MAX,
MaybeAddServerLoadReportingFilter);
// Access measures to ensure they are initialized. Otherwise, we can't
// create any valid view before the first RPC.

@ -536,7 +536,7 @@ static bool maybe_add_max_age_filter(grpc_channel_stack_builder* builder,
void grpc_max_age_filter_init(void) {
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_LOW,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_max_age_filter, nullptr);
}

@ -311,13 +311,13 @@ static bool maybe_add_message_size_filter(grpc_channel_stack_builder* builder,
void grpc_message_size_filter_init(void) {
grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_LOW,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_message_size_filter, nullptr);
grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_LOW,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_message_size_filter, nullptr);
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_LOW,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_message_size_filter, nullptr);
}

@ -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);

@ -40,6 +40,7 @@ namespace chttp2 {
namespace {
static constexpr const int kTracePadding = 30;
static constexpr const uint32_t kMaxWindowUpdateSize = (1u << 31) - 1;
static char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) {
char* str;
@ -55,7 +56,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 +99,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);
@ -191,7 +194,7 @@ uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) {
if ((writing_anyway || announced_window_ <= target_announced_window / 2) &&
announced_window_ != target_announced_window) {
const uint32_t announce = static_cast<uint32_t> GPR_CLAMP(
target_announced_window - announced_window_, 0, UINT32_MAX);
target_announced_window - announced_window_, 0, kMaxWindowUpdateSize);
announced_window_ += announce;
return announce;
}
@ -265,7 +268,7 @@ uint32_t StreamFlowControl::MaybeSendUpdate() {
FlowControlTrace trace("s updt sent", tfc_, this);
if (local_window_delta_ > announced_window_delta_) {
uint32_t announce = static_cast<uint32_t> GPR_CLAMP(
local_window_delta_ - announced_window_delta_, 0, UINT32_MAX);
local_window_delta_ - announced_window_delta_, 0, kMaxWindowUpdateSize);
UpdateAnnouncedWindowDelta(tfc_, announce);
return announce;
}

@ -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);
}

@ -228,8 +228,8 @@ static void bind_transport(grpc_channel_stack* channel_stack,
grpc_transport_stream_size(static_cast<grpc_transport*>(t));
}
bool grpc_append_connected_filter(grpc_channel_stack_builder* builder,
void* arg_must_be_null) {
bool grpc_add_connected_filter(grpc_channel_stack_builder* builder,
void* arg_must_be_null) {
GPR_ASSERT(arg_must_be_null == nullptr);
grpc_transport* t = grpc_channel_stack_builder_get_transport(builder);
GPR_ASSERT(t != nullptr);

@ -25,8 +25,8 @@
extern const grpc_channel_filter grpc_connected_filter;
bool grpc_append_connected_filter(grpc_channel_stack_builder* builder,
void* arg_must_be_null);
bool grpc_add_connected_filter(grpc_channel_stack_builder* builder,
void* arg_must_be_null);
/* Debug helper to dig the transport stream out of a call element */
grpc_stream* grpc_connected_channel_get_stream(grpc_call_element* elem);

@ -101,10 +101,28 @@ const grpc_event_engine_vtable* init_non_polling(bool explicit_request) {
}
} // namespace
static const event_engine_factory g_factories[] = {
#define ENGINE_HEAD_CUSTOM "head_custom"
#define ENGINE_TAIL_CUSTOM "tail_custom"
// The global array of event-engine factories. Each entry is a pair with a name
// and an event-engine generator function (nullptr if there is no generator
// registered for this name). The middle entries are the engines predefined by
// open-source gRPC. The head entries represent an opportunity for specific
// high-priority custom pollers to be added by the initializer plugins of
// custom-built gRPC libraries. The tail entries represent the same, but for
// low-priority custom pollers. The actual poller selected is either the first
// available one in the list if no specific poller is requested, or the first
// specific poller that is requested by name in the GRPC_POLL_STRATEGY
// environment variable if that variable is set (which should be a
// comma-separated list of one or more event engine names)
static event_engine_factory g_factories[] = {
{ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
{ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
{"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
{"epollsig", grpc_init_epollsig_linux}, {"poll", grpc_init_poll_posix},
{"poll-cv", grpc_init_poll_cv_posix}, {"none", init_non_polling},
{ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
{ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
};
static void add(const char* beg, const char* end, char*** ss, size_t* ns) {
@ -138,7 +156,7 @@ static bool is(const char* want, const char* have) {
static void try_engine(const char* engine) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(g_factories); i++) {
if (is(engine, g_factories[i].name)) {
if (g_factories[i].factory != nullptr && is(engine, g_factories[i].name)) {
if ((g_event_engine = g_factories[i].factory(
0 == strcmp(engine, g_factories[i].name)))) {
g_poll_strategy_name = g_factories[i].name;
@ -149,14 +167,32 @@ static void try_engine(const char* engine) {
}
}
/* This should be used for testing purposes ONLY */
void grpc_set_event_engine_test_only(
const grpc_event_engine_vtable* ev_engine) {
g_event_engine = ev_engine;
}
/* Call this before calling grpc_event_engine_init() */
void grpc_register_event_engine_factory(const char* name,
event_engine_factory_fn factory,
bool add_at_head) {
const char* custom_match =
add_at_head ? ENGINE_HEAD_CUSTOM : ENGINE_TAIL_CUSTOM;
// Overwrite an existing registration if already registered
for (size_t i = 0; i < GPR_ARRAY_SIZE(g_factories); i++) {
if (0 == strcmp(name, g_factories[i].name)) {
g_factories[i].factory = factory;
return;
}
}
// Otherwise fill in an available custom slot
for (size_t i = 0; i < GPR_ARRAY_SIZE(g_factories); i++) {
if (0 == strcmp(g_factories[i].name, custom_match)) {
g_factories[i].name = name;
g_factories[i].factory = factory;
return;
}
}
const grpc_event_engine_vtable* grpc_get_event_engine_test_only() {
return g_event_engine;
// Otherwise fail
GPR_ASSERT(false);
}
/* Call this only after calling grpc_event_engine_init() */

@ -82,6 +82,11 @@ typedef struct grpc_event_engine_vtable {
void (*shutdown_engine)(void);
} grpc_event_engine_vtable;
/* register a new event engine factory */
void grpc_register_event_engine_factory(
const char* name, const grpc_event_engine_vtable* (*factory)(bool),
bool add_at_head);
void grpc_event_engine_init(void);
void grpc_event_engine_shutdown(void);
@ -173,9 +178,4 @@ void grpc_pollset_set_del_fd(grpc_pollset_set* pollset_set, grpc_fd* fd);
typedef int (*grpc_poll_function_type)(struct pollfd*, nfds_t, int);
extern grpc_poll_function_type grpc_poll_function;
/* WARNING: The following two functions should be used for testing purposes
* ONLY */
void grpc_set_event_engine_test_only(const grpc_event_engine_vtable*);
const grpc_event_engine_vtable* grpc_get_event_engine_test_only();
#endif /* GRPC_CORE_LIB_IOMGR_EV_POSIX_H */

@ -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",

@ -21,37 +21,11 @@
#include <grpc/support/port_platform.h>
#include <limits.h>
#include "src/core/lib/channel/channel_stack_builder.h"
#include "src/core/lib/surface/channel_stack_type.h"
#include "src/core/lib/transport/transport.h"
// Priority for channel registration functions to be used in
// grpc_channel_init_register_stage(). The priority dictates the
// order in which the registration functions run.
//
// When used to register a filter, the filter can either be appended or
// prepended, thus dictating whether the filter goes at the top or bottom of
// the stack. Higher priority functions can get closer to the top or bottom
// of the stack than lower priority functions.
enum {
// Default level. Most of filters should use this level if their location in
// the stack does not matter.
GRPC_CHANNEL_INIT_PRIORITY_LOW = 0,
// For filters that should be added after the group of filters with default
// priority, such as auth filters.
GRPC_CHANNEL_INIT_PRIORITY_MED = 10000,
// For filters that need to be close to top or bottom, such as protocol-level
// filters (client_authority, http-client, http-server).
GRPC_CHANNEL_INIT_PRIORITY_HIGH = 20000,
// For filters that need to be very close to the wire or surface, such as
// stats filters (census).
GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH = 30000,
// For things that have to happen last, such as connected channel filter or
// surface server filter. Consider as reserved for gRPC internals.
GRPC_CHANNEL_INIT_PRIORITY_MAX = INT_MAX
};
#define GRPC_CHANNEL_INIT_BUILTIN_PRIORITY 10000
/// This module provides a way for plugins (and the grpc core library itself)
/// to register mutators for channel stacks.

@ -184,7 +184,7 @@ static const cq_poller_vtable g_poller_vtable_by_poller_type[] = {
typedef struct cq_vtable {
grpc_cq_completion_type cq_completion_type;
size_t data_size;
void (*init)(void* data);
void (*init)(void* data, grpc_core::CQCallbackInterface* shutdown_callback);
void (*shutdown)(grpc_completion_queue* cq);
void (*destroy)(void* data);
bool (*begin_op)(grpc_completion_queue* cq, void* tag);
@ -253,6 +253,23 @@ typedef struct cq_pluck_data {
plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
} cq_pluck_data;
typedef struct cq_callback_data {
/** No actual completed events queue, unlike other types */
/** Number of pending events (+1 if we're not shutdown) */
gpr_atm pending_events;
/** Counter of how many things have ever been queued on this completion queue
useful for avoiding locks to check the queue */
gpr_atm things_queued_ever;
/** 0 initially. 1 once we initiated shutdown */
bool shutdown_called;
/** A callback that gets invoked when the CQ completes shutdown */
grpc_core::CQCallbackInterface* shutdown_callback;
} cq_callback_data;
/* Completion queue structure */
struct grpc_completion_queue {
/** Once owning_refs drops to zero, we will destroy the cq */
@ -276,12 +293,21 @@ struct grpc_completion_queue {
/* Forward declarations */
static void cq_finish_shutdown_next(grpc_completion_queue* cq);
static void cq_finish_shutdown_pluck(grpc_completion_queue* cq);
static void cq_finish_shutdown_callback(grpc_completion_queue* cq);
static void cq_shutdown_next(grpc_completion_queue* cq);
static void cq_shutdown_pluck(grpc_completion_queue* cq);
static void cq_shutdown_callback(grpc_completion_queue* cq);
static bool cq_begin_op_for_next(grpc_completion_queue* cq, void* tag);
static bool cq_begin_op_for_pluck(grpc_completion_queue* cq, void* tag);
static bool cq_begin_op_for_callback(grpc_completion_queue* cq, void* tag);
// A cq_end_op function is called when an operation on a given CQ with
// a given tag has completed. The storage argument is a reference to the
// space reserved for this completion as it is placed into the corresponding
// queue. The done argument is a callback that will be invoked when it is
// safe to free up that storage. The storage MUST NOT be freed until the
// done callback is invoked.
static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
@ -294,16 +320,28 @@ static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
static void cq_end_op_for_callback(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline,
void* reserved);
static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag,
gpr_timespec deadline, void* reserved);
static void cq_init_next(void* data);
static void cq_init_pluck(void* data);
// Note that cq_init_next and cq_init_pluck do not use the shutdown_callback
static void cq_init_next(void* data,
grpc_core::CQCallbackInterface* shutdown_callback);
static void cq_init_pluck(void* data,
grpc_core::CQCallbackInterface* shutdown_callback);
static void cq_init_callback(void* data,
grpc_core::CQCallbackInterface* shutdown_callback);
static void cq_destroy_next(void* data);
static void cq_destroy_pluck(void* data);
static void cq_destroy_callback(void* data);
/* Completion queue vtables based on the completion-type */
static const cq_vtable g_cq_vtable[] = {
@ -315,6 +353,10 @@ static const cq_vtable g_cq_vtable[] = {
{GRPC_CQ_PLUCK, sizeof(cq_pluck_data), cq_init_pluck, cq_shutdown_pluck,
cq_destroy_pluck, cq_begin_op_for_pluck, cq_end_op_for_pluck, nullptr,
cq_pluck},
/* GRPC_CQ_CALLBACK */
{GRPC_CQ_CALLBACK, sizeof(cq_callback_data), cq_init_callback,
cq_shutdown_callback, cq_destroy_callback, cq_begin_op_for_callback,
cq_end_op_for_callback, nullptr, nullptr},
};
#define DATA_FROM_CQ(cq) ((void*)(cq + 1))
@ -419,8 +461,8 @@ static long cq_event_queue_num_items(grpc_cq_event_queue* q) {
}
grpc_completion_queue* grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type,
grpc_cq_polling_type polling_type) {
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type,
grpc_core::CQCallbackInterface* shutdown_callback) {
GPR_TIMER_SCOPE("grpc_completion_queue_create_internal", 0);
grpc_completion_queue* cq;
@ -448,15 +490,16 @@ grpc_completion_queue* grpc_completion_queue_create_internal(
gpr_ref_init(&cq->owning_refs, 2);
poller_vtable->init(POLLSET_FROM_CQ(cq), &cq->mu);
vtable->init(DATA_FROM_CQ(cq));
vtable->init(DATA_FROM_CQ(cq), shutdown_callback);
GRPC_CLOSURE_INIT(&cq->pollset_shutdown_done, on_pollset_shutdown_done, cq,
grpc_schedule_on_exec_ctx);
return cq;
}
static void cq_init_next(void* ptr) {
cq_next_data* cqd = static_cast<cq_next_data*>(ptr);
static void cq_init_next(void* data,
grpc_core::CQCallbackInterface* shutdown_callback) {
cq_next_data* cqd = static_cast<cq_next_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
cqd->shutdown_called = false;
@ -464,14 +507,15 @@ static void cq_init_next(void* ptr) {
cq_event_queue_init(&cqd->queue);
}
static void cq_destroy_next(void* ptr) {
cq_next_data* cqd = static_cast<cq_next_data*>(ptr);
static void cq_destroy_next(void* data) {
cq_next_data* cqd = static_cast<cq_next_data*>(data);
GPR_ASSERT(cq_event_queue_num_items(&cqd->queue) == 0);
cq_event_queue_destroy(&cqd->queue);
}
static void cq_init_pluck(void* ptr) {
cq_pluck_data* cqd = static_cast<cq_pluck_data*>(ptr);
static void cq_init_pluck(void* data,
grpc_core::CQCallbackInterface* shutdown_callback) {
cq_pluck_data* cqd = static_cast<cq_pluck_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
cqd->completed_tail = &cqd->completed_head;
@ -482,11 +526,23 @@ static void cq_init_pluck(void* ptr) {
gpr_atm_no_barrier_store(&cqd->things_queued_ever, 0);
}
static void cq_destroy_pluck(void* ptr) {
cq_pluck_data* cqd = static_cast<cq_pluck_data*>(ptr);
static void cq_destroy_pluck(void* data) {
cq_pluck_data* cqd = static_cast<cq_pluck_data*>(data);
GPR_ASSERT(cqd->completed_head.next == (uintptr_t)&cqd->completed_head);
}
static void cq_init_callback(
void* data, grpc_core::CQCallbackInterface* shutdown_callback) {
cq_callback_data* cqd = static_cast<cq_callback_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
cqd->shutdown_called = false;
gpr_atm_no_barrier_store(&cqd->things_queued_ever, 0);
cqd->shutdown_callback = shutdown_callback;
}
static void cq_destroy_callback(void* data) {}
grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue* cq) {
return cq->vtable->cq_completion_type;
}
@ -596,6 +652,11 @@ static bool cq_begin_op_for_pluck(grpc_completion_queue* cq, void* tag) {
return atm_inc_if_nonzero(&cqd->pending_events);
}
static bool cq_begin_op_for_callback(grpc_completion_queue* cq, void* tag) {
cq_callback_data* cqd = static_cast<cq_callback_data*> DATA_FROM_CQ(cq);
return atm_inc_if_nonzero(&cqd->pending_events);
}
bool grpc_cq_begin_op(grpc_completion_queue* cq, void* tag) {
#ifndef NDEBUG
gpr_mu_lock(cq->mu);
@ -759,6 +820,48 @@ static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
GRPC_ERROR_UNREF(error);
}
/* Complete an event on a completion queue of type GRPC_CQ_CALLBACK */
static void cq_end_op_for_callback(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage) {
GPR_TIMER_SCOPE("cq_end_op_for_callback", 0);
cq_callback_data* cqd = static_cast<cq_callback_data*> DATA_FROM_CQ(cq);
bool is_success = (error == GRPC_ERROR_NONE);
if (grpc_api_trace.enabled() ||
(grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE)) {
const char* errmsg = grpc_error_string(error);
GRPC_API_TRACE(
"cq_end_op_for_callback(cq=%p, tag=%p, error=%s, "
"done=%p, done_arg=%p, storage=%p)",
6, (cq, tag, errmsg, done, done_arg, storage));
if (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
}
}
// The callback-based CQ isn't really a queue at all and thus has no need
// for reserved storage. Invoke the done callback right away to release it.
done(done_arg, storage);
gpr_mu_lock(cq->mu);
cq_check_tag(cq, tag, false); /* Used in debug builds only */
gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1);
if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
cq_finish_shutdown_callback(cq);
gpr_mu_unlock(cq->mu);
} else {
gpr_mu_unlock(cq->mu);
}
GRPC_ERROR_UNREF(error);
(static_cast<grpc_core::CQCallbackInterface*>(tag))->Run(is_success);
}
void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage) {
@ -1233,6 +1336,40 @@ static void cq_shutdown_pluck(grpc_completion_queue* cq) {
GRPC_CQ_INTERNAL_UNREF(cq, "shutting_down (pluck cq)");
}
static void cq_finish_shutdown_callback(grpc_completion_queue* cq) {
cq_callback_data* cqd = static_cast<cq_callback_data*> DATA_FROM_CQ(cq);
auto* callback = cqd->shutdown_callback;
GPR_ASSERT(cqd->shutdown_called);
cq->poller_vtable->shutdown(POLLSET_FROM_CQ(cq), &cq->pollset_shutdown_done);
callback->Run(true);
}
static void cq_shutdown_callback(grpc_completion_queue* cq) {
cq_callback_data* cqd = static_cast<cq_callback_data*> DATA_FROM_CQ(cq);
/* Need an extra ref for cq here because:
* We call cq_finish_shutdown_callback() below, which calls pollset shutdown.
* Pollset shutdown decrements the cq ref count which can potentially destroy
* the cq (if that happens to be the last ref).
* Creating an extra ref here prevents the cq from getting destroyed while
* this function is still active */
GRPC_CQ_INTERNAL_REF(cq, "shutting_down (callback cq)");
gpr_mu_lock(cq->mu);
if (cqd->shutdown_called) {
gpr_mu_unlock(cq->mu);
GRPC_CQ_INTERNAL_UNREF(cq, "shutting_down (callback cq)");
return;
}
cqd->shutdown_called = true;
if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
cq_finish_shutdown_callback(cq);
}
gpr_mu_unlock(cq->mu);
GRPC_CQ_INTERNAL_UNREF(cq, "shutting_down (callback cq)");
}
/* Shutdown simply drops a ref that we reserved at creation time; if we drop
to zero here, then enter shutdown mode and wake up any waiters */
void grpc_completion_queue_shutdown(grpc_completion_queue* cq) {

@ -25,6 +25,7 @@
#include <grpc/grpc.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/abstract.h"
#include "src/core/lib/iomgr/pollset.h"
/* These trace flags default to 1. The corresponding lines are only traced
@ -47,6 +48,23 @@ typedef struct grpc_cq_completion {
uintptr_t next;
} grpc_cq_completion;
/// For callback CQs, the tag that is passed in for an operation must
/// actually be a pointer to an implementation of the following class.
/// When the operation completes, the tag will be typecasted from void*
/// to grpc_core::CQCallbackInterface* and then the Run method will be
/// invoked on it. In practice, the language binding (e.g., C++ API
/// implementation) is responsible for providing and using an implementation
/// of this abstract base class.
namespace grpc_core {
class CQCallbackInterface {
public:
virtual ~CQCallbackInterface() {}
virtual void Run(bool) GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
} // namespace grpc_core
#ifndef NDEBUG
void grpc_cq_internal_ref(grpc_completion_queue* cc, const char* reason,
const char* file, int line);
@ -87,6 +105,7 @@ grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue* cc);
int grpc_get_cq_poll_num(grpc_completion_queue* cc);
grpc_completion_queue* grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type);
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type,
grpc_core::CQCallbackInterface* shutdown_callback);
#endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */

@ -30,8 +30,9 @@
static grpc_completion_queue* default_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attr) {
return grpc_completion_queue_create_internal(attr->cq_completion_type,
attr->cq_polling_type);
return grpc_completion_queue_create_internal(
attr->cq_completion_type, attr->cq_polling_type,
static_cast<grpc_core::CQCallbackInterface*>(attr->cq_shutdown_cb));
}
static grpc_completion_queue_factory_vtable default_vtable = {default_create};
@ -60,14 +61,22 @@ const grpc_completion_queue_factory* grpc_completion_queue_factory_lookup(
grpc_completion_queue* grpc_completion_queue_create_for_next(void* reserved) {
GPR_ASSERT(!reserved);
grpc_completion_queue_attributes attr = {1, GRPC_CQ_NEXT,
GRPC_CQ_DEFAULT_POLLING};
GRPC_CQ_DEFAULT_POLLING, nullptr};
return g_default_cq_factory.vtable->create(&g_default_cq_factory, &attr);
}
grpc_completion_queue* grpc_completion_queue_create_for_pluck(void* reserved) {
GPR_ASSERT(!reserved);
grpc_completion_queue_attributes attr = {1, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING};
GRPC_CQ_DEFAULT_POLLING, nullptr};
return g_default_cq_factory.vtable->create(&g_default_cq_factory, &attr);
}
grpc_completion_queue* grpc_completion_queue_create_for_callback(
void* shutdown_callback, void* reserved) {
GPR_ASSERT(!reserved);
grpc_completion_queue_attributes attr = {
2, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, shutdown_callback};
return g_default_cq_factory.vtable->create(&g_default_cq_factory, &attr);
}

@ -70,6 +70,11 @@ static void do_basic_init(void) {
g_initializations = 0;
}
static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
return grpc_channel_stack_builder_append_filter(
builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
}
static bool prepend_filter(grpc_channel_stack_builder* builder, void* arg) {
return grpc_channel_stack_builder_prepend_filter(
builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
@ -77,20 +82,19 @@ static bool prepend_filter(grpc_channel_stack_builder* builder, void* arg) {
static void register_builtin_channel_init() {
grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_MAX,
grpc_append_connected_filter, nullptr);
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
grpc_add_connected_filter, nullptr);
grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_MAX,
grpc_append_connected_filter, nullptr);
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
grpc_add_connected_filter, nullptr);
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_MAX,
grpc_append_connected_filter, nullptr);
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
grpc_add_connected_filter, nullptr);
grpc_channel_init_register_stage(GRPC_CLIENT_LAME_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_MAX,
prepend_filter, (void*)&grpc_lame_filter);
grpc_channel_init_register_stage(
GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, prepend_filter,
(void*)&grpc_server_top_filter);
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
append_filter, (void*)&grpc_lame_filter);
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter,
(void*)&grpc_server_top_filter);
}
typedef struct grpc_plugin {

@ -67,17 +67,14 @@ static bool maybe_prepend_server_auth_filter(
}
void grpc_register_security_filters(void) {
// Register the auth client with a medium priority to allow the authority
// Register the auth client with a priority < INT_MAX to allow the authority
// filter -on which the auth filter depends- to be higher on the channel
// stack.
grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_MED,
grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX - 1,
maybe_prepend_client_auth_filter, nullptr);
grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_MED,
grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX - 1,
maybe_prepend_client_auth_filter, nullptr);
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_MED,
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
maybe_prepend_server_auth_filter, nullptr);
}

@ -78,13 +78,8 @@ bool MaybeAddFilter(grpc_channel_stack_builder* builder, void* arg) {
grpc_channel_stack_builder_get_channel_arguments(builder);
if (!filter.include_filter(*args)) return true;
}
if (filter.prepend) {
return grpc_channel_stack_builder_prepend_filter(builder, &filter.filter,
nullptr, nullptr);
} else {
return grpc_channel_stack_builder_append_filter(builder, &filter.filter,
nullptr, nullptr);
}
return grpc_channel_stack_builder_prepend_filter(builder, &filter.filter,
nullptr, nullptr);
}
} // namespace

@ -36,8 +36,7 @@
/// \c ChannelData. Then register the filter using something like this:
/// \code{.cpp}
/// RegisterChannelFilter<MyChannelDataSubclass, MyCallDataSubclass>(
/// "name-of-filter", GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_LOW,
/// true, nullptr);
/// "name-of-filter", GRPC_SERVER_CHANNEL, INT_MAX, nullptr);
/// \endcode
namespace grpc {
@ -352,7 +351,6 @@ class ChannelFilter final {
struct FilterRecord {
grpc_channel_stack_type stack_type;
int priority;
bool prepend;
std::function<bool(const grpc_channel_args&)> include_filter;
grpc_channel_filter filter;
};
@ -365,14 +363,12 @@ void ChannelFilterPluginShutdown();
/// Registers a new filter.
/// Must be called by only one thread at a time.
/// The \a prepend argument decides whether to prepend or append the filter.
/// The \a include_filter argument specifies a function that will be called
/// to determine at run-time whether or not to add the filter. If the
/// value is nullptr, the filter will be added unconditionally.
template <typename ChannelDataType, typename CallDataType>
void RegisterChannelFilter(
const char* name, grpc_channel_stack_type stack_type, int priority,
bool prepend,
std::function<bool(const grpc_channel_args&)> include_filter) {
// If we haven't been called before, initialize channel_filters and
// call grpc_register_plugin().
@ -387,7 +383,6 @@ void RegisterChannelFilter(
internal::FilterRecord filter_record = {
stack_type,
priority,
prepend,
include_filter,
{FilterType::StartTransportStreamOpBatch, FilterType::StartTransportOp,
FilterType::call_data_size, FilterType::InitCallElement,

@ -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

@ -32,12 +32,10 @@ namespace grpc {
void RegisterOpenCensusPlugin() {
RegisterChannelFilter<CensusChannelData, CensusClientCallData>(
"opencensus_client", GRPC_CLIENT_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH, true /* prepend */,
"opencensus_client", GRPC_CLIENT_CHANNEL, INT_MAX /* priority */,
nullptr /* condition function */);
RegisterChannelFilter<CensusChannelData, CensusServerCallData>(
"opencensus_server", GRPC_SERVER_CHANNEL,
GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH, true /* prepend */,
"opencensus_server", GRPC_SERVER_CHANNEL, INT_MAX /* priority */,
nullptr /* condition function */);
// Access measures to ensure they are initialized. Otherwise, creating a view

@ -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,13 @@
namespace grpc {
namespace {
// The default value for maximum number of threads that can be created in the
// sync server. This value of INT_MAX is chosen to match the default behavior if
// no ResourceQuota is set. To modify 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 INT_MAX
class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
public:
~DefaultGlobalCallbacks() override {}
@ -204,8 +211,10 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
call_(mrd->call_, server, &cq_, server->max_receive_message_size()),
ctx_(mrd->deadline_, &mrd->request_metadata_),
has_request_payload_(mrd->has_request_payload_),
request_payload_(mrd->request_payload_),
method_(mrd->method_) {
request_payload_(has_request_payload_ ? mrd->request_payload_
: nullptr),
method_(mrd->method_),
server_(server) {
ctx_.set_call(mrd->call_);
ctx_.cq_ = &cq_;
GPR_ASSERT(mrd->in_flight_);
@ -219,10 +228,13 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
}
}
void Run(const std::shared_ptr<GlobalCallbacks>& global_callbacks) {
void Run(const std::shared_ptr<GlobalCallbacks>& global_callbacks,
bool resources) {
ctx_.BeginCompletionOp(&call_);
global_callbacks->PreSynchronousRequest(&ctx_);
method_->handler()->RunHandler(internal::MethodHandler::HandlerParameter(
auto* handler = resources ? method_->handler()
: server_->resource_exhausted_handler_.get();
handler->RunHandler(internal::MethodHandler::HandlerParameter(
&call_, &ctx_, request_payload_));
global_callbacks->PostSynchronousRequest(&ctx_);
request_payload_ = nullptr;
@ -244,6 +256,7 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
const bool has_request_payload_;
grpc_byte_buffer* request_payload_;
internal::RpcServiceMethod* const method_;
Server* server_;
};
private:
@ -266,9 +279,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),
@ -294,7 +307,7 @@ class Server::SyncRequestThreadManager : public ThreadManager {
GPR_UNREACHABLE_CODE(return TIMEOUT);
}
void DoWork(void* tag, bool ok) override {
void DoWork(void* tag, bool ok, bool resources) override {
SyncRequest* sync_req = static_cast<SyncRequest*>(tag);
if (!sync_req) {
@ -314,7 +327,7 @@ class Server::SyncRequestThreadManager : public ThreadManager {
}
GPR_TIMER_SCOPE("cd.Run()", 0);
cd.Run(global_callbacks_);
cd.Run(global_callbacks_, resources);
}
// TODO (sreek) If ok is false here (which it isn't in case of
// grpc_request_registered_call), we should still re-queue the request
@ -376,7 +389,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 +406,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);
}
}
@ -559,6 +585,13 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
}
}
// If this server has any support for synchronous methods (has any sync
// server CQs), make sure that we have a ResourceExhausted handler
// to deal with the case of thread exhaustion
if (!sync_server_cqs_->empty()) {
resource_exhausted_handler_.reset(new internal::ResourceExhaustedHandler);
}
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
(*it)->Start();
}

@ -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,17 +88,27 @@ 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) {
shutdown_cv_.notify_one();
{
std::lock_guard<std::mutex> lock(mu_);
num_threads_--;
if (num_threads_ == 0) {
shutdown_cv_.notify_one();
}
}
// Give a thread back to the resource quota
grpc_resource_user_free_threads(resource_user_, 1);
}
void ThreadManager::CleanupCompletedThreads() {
@ -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,20 +164,40 @@ void ThreadManager::MainWorkLoop() {
done = true;
break;
case WORK_FOUND:
// If we got work and there are now insufficient pollers, start a new
// one
// 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
bool resource_exhausted = false;
if (!shutdown_ && num_pollers_ < min_pollers_) {
num_pollers_++;
num_threads_++;
// Drop lock before spawning thread to avoid contention
lock.unlock();
new WorkerThread(this);
if (grpc_resource_user_allocate_threads(resource_user_, 1)) {
// We can allocate a new poller thread
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);
} else if (num_pollers_ > 0) {
// There is still at least some thread polling, so we can go on
// even though we are below the number of pollers that we would
// like to have (min_pollers_)
lock.unlock();
} else {
// There are no pollers to spare and we couldn't allocate
// a new thread, so resources are exhausted!
lock.unlock();
resource_exhausted = true;
}
} else {
// Drop lock for consistency with above branch
// There are a sufficient number of pollers available so we can do
// the work and continue polling with our existing poller threads
lock.unlock();
}
// Lock is always released at this point - do the application work
DoWork(tag, ok);
// or return resource exhausted if there is new work but we couldn't
// get a thread in which to do it.
DoWork(tag, ok, !resource_exhausted);
// Take the lock again to check post conditions
lock.lock();
// If we're shutdown, we should finish at this point.
@ -196,6 +241,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
@ -65,12 +67,14 @@ class ThreadManager {
// The implementation of DoWork() is supposed to perform the work found by
// PollForWork(). The tag and ok parameters are the same as returned by
// PollForWork()
// PollForWork(). The resources parameter indicates that the call actually
// has the resources available for performing the RPC's work. If it doesn't,
// the implementation should fail it appropriately.
//
// The implementation of DoWork() should also do any setup needed to ensure
// that the next call to PollForWork() (not necessarily by the current thread)
// actually finds some work
virtual void DoWork(void* tag, bool ok) = 0;
virtual void DoWork(void* tag, bool ok, bool resources) = 0;
// Mark the ThreadManager as shutdown and begin draining the work. This is a
// non-blocking call and the caller should call Wait(), a blocking call which
@ -84,6 +88,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 +100,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 +138,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 +160,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,12 +361,25 @@ 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()
{
NativeMethods.Get().grpcsharp_shutdown();
if (IsNativeShutdownAllowed)
{
NativeMethods.Get().grpcsharp_shutdown();
}
}
/// <summary>
@ -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
[GRPCConnectivityMonitor unregisterObserver:self];
#endif
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream == nil || enableCFStream[0] != '1') {
[GRPCConnectivityMonitor unregisterObserver:self];
}
// 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
[GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)];
#endif
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream == nil || enableCFStream[0] != '1') {
[GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)];
}
}
- (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
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING, NULL};
@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
[GRPCConnectivityMonitor unregisterObserver:self];
#endif
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream == nil || enableCFStream[0] != '1') {
[GRPCConnectivityMonitor unregisterObserver:self];
}
}
// Default initializer.
@ -87,9 +91,12 @@ static NSMutableDictionary *kHostCache;
_compressAlgorithm = GRPC_COMPRESS_NONE;
_retryEnabled = YES;
}
#ifndef GRPC_CFSTREAM
[GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)];
#endif
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream == nil || enableCFStream[0] != '1') {
[GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)];
}
}
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";

@ -75,7 +75,10 @@ PHP_METHOD(Server, __construct) {
if (args_array == NULL) {
server->wrapped = grpc_server_create(NULL, NULL);
} else {
php_grpc_read_args_array(args_array, &args TSRMLS_CC);
if (php_grpc_read_args_array(args_array, &args TSRMLS_CC) == FAILURE) {
efree(args.args);
return;
}
server->wrapped = grpc_server_create(&args, NULL);
efree(args.args);
}

@ -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:
return grpc_channel_check_connectivity_state(
self._state.c_channel, try_to_connect)
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):

@ -48,7 +48,7 @@ cdef int _get_metadata(
cdef size_t metadata_count
cdef grpc_metadata *c_metadata
def callback(metadata, grpc_status_code status, bytes error_details):
if status is StatusCode.ok:
if status == StatusCode.ok:
_store_c_metadata(metadata, &c_metadata, &metadata_count)
cb(user_data, c_metadata, metadata_count, status, NULL)
_release_c_metadata(c_metadata, metadata_count)

@ -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',

@ -43,6 +43,7 @@ grpc_g_stands_for_type grpc_g_stands_for_import;
grpc_completion_queue_factory_lookup_type grpc_completion_queue_factory_lookup_import;
grpc_completion_queue_create_for_next_type grpc_completion_queue_create_for_next_import;
grpc_completion_queue_create_for_pluck_type grpc_completion_queue_create_for_pluck_import;
grpc_completion_queue_create_for_callback_type grpc_completion_queue_create_for_callback_import;
grpc_completion_queue_create_type grpc_completion_queue_create_import;
grpc_completion_queue_next_type grpc_completion_queue_next_import;
grpc_completion_queue_pluck_type grpc_completion_queue_pluck_import;
@ -92,6 +93,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;
@ -294,6 +296,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_completion_queue_factory_lookup_import = (grpc_completion_queue_factory_lookup_type) GetProcAddress(library, "grpc_completion_queue_factory_lookup");
grpc_completion_queue_create_for_next_import = (grpc_completion_queue_create_for_next_type) GetProcAddress(library, "grpc_completion_queue_create_for_next");
grpc_completion_queue_create_for_pluck_import = (grpc_completion_queue_create_for_pluck_type) GetProcAddress(library, "grpc_completion_queue_create_for_pluck");
grpc_completion_queue_create_for_callback_import = (grpc_completion_queue_create_for_callback_type) GetProcAddress(library, "grpc_completion_queue_create_for_callback");
grpc_completion_queue_create_import = (grpc_completion_queue_create_type) GetProcAddress(library, "grpc_completion_queue_create");
grpc_completion_queue_next_import = (grpc_completion_queue_next_type) GetProcAddress(library, "grpc_completion_queue_next");
grpc_completion_queue_pluck_import = (grpc_completion_queue_pluck_type) GetProcAddress(library, "grpc_completion_queue_pluck");
@ -343,6 +346,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");

@ -104,6 +104,9 @@ extern grpc_completion_queue_create_for_next_type grpc_completion_queue_create_f
typedef grpc_completion_queue*(*grpc_completion_queue_create_for_pluck_type)(void* reserved);
extern grpc_completion_queue_create_for_pluck_type grpc_completion_queue_create_for_pluck_import;
#define grpc_completion_queue_create_for_pluck grpc_completion_queue_create_for_pluck_import
typedef grpc_completion_queue*(*grpc_completion_queue_create_for_callback_type)(void* shutdown_callback, void* reserved);
extern grpc_completion_queue_create_for_callback_type grpc_completion_queue_create_for_callback_import;
#define grpc_completion_queue_create_for_callback grpc_completion_queue_create_for_callback_import
typedef grpc_completion_queue*(*grpc_completion_queue_create_type)(const grpc_completion_queue_factory* factory, const grpc_completion_queue_attributes* attributes, void* reserved);
extern grpc_completion_queue_create_type grpc_completion_queue_create_import;
#define grpc_completion_queue_create grpc_completion_queue_create_import
@ -251,6 +254,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

@ -0,0 +1,191 @@
# Project overview
## Title
Enable Building of gRPC Python with Bazel
## Overview
gRPC Python currently has a constellation of scripts written to build the
project, but it has a lot of limitations in terms of speed and maintainability.
[Bazel](https://bazel.build/) is the open-sourced variant of Google's internal
system, Blaze, which is an ideal replacement for building such projects in a
fast and declarative fashion. But Bazel in itself is still in active
development, especially in terms of Python (amongst a few other languages).
The project aimed to fill this gap and build gRPC Python with Bazel.
[Project page](https://summerofcode.withgoogle.com/projects/#6482576244473856)
[Link to proposal](https://storage.googleapis.com/summerofcode-prod.appspot.com/gsoc/core_project/doc/5316764725411840_1522049732_Naresh_Ramesh_-_GSoC_proposal.pdf)
## Thoughts and challenges
### State of Bazel for Python
Although previously speculated, the project didn't require any contributions
directly to [bazelbuild/bazel](https://github.com/bazelbuild/bazel). The Bazel
rules for Python are currently being separated out into their own repo at
[bazelbuild/rules_python](https://github.com/bazelbuild/rules_python/).
Bazel is [still very much in active development for
Python](https://groups.google.com/forum/#!topic/bazel-sig-python/iQjV9sfSufw)
though. There's still challenges when it comes to building for Python 2 vs 3.
Using pip packages is still in experimental. Bazel Python support is currently
distributed across these two repositories and is yet to begin migration to one
place (which will be
[bazelbuild/rules_python](https://github.com/bazelbuild/rules_python/)).
Bazel's roadmap for Python is publicly available [here as a Google
doc](https://docs.google.com/document/d/1A6J3j3y1SQ0HliS86_mZBnB5UeBe7vExWL2Ryd_EONI/edit).
### Cross collaboration between projects
Cross contribution surprisingly came up because of building protobuf sources
for Python, which is still not natively supported by Bazel. An existing
repository, [pubref/rules_protobuf](https://github.com/pubref/rules_protobuf),
which was maintained by an independent maintainer (i.e. not a part of Bazel)
helped solve this problem, but had [one major blocking
issue](https://github.com/pubref/rules_protobuf/issues/233) and could not be
resolved at the source. But [a solution to the
issue](https://github.com/pubref/rules_protobuf/pull/196) was proposed by user
dududko, which was not merged because of failing golang tests but worked well
for Python. Hence, a fork of this repo was made and is to be used with gRPC
until the solution can be merged back at the source.
### Building Cython code
Building Cython code is still not supported by Bazel, but the team at
[cython/cython](https://github.com/cython/cython) have added support for Bazel
on their side. The way it works is by including Cython as a third-party Bazel
dependency and using custom Bazel rules for building our Cython code using the
binary within the dependency.
### Packaging Python code using Bazel
pip and PyPI still remain the de-facto standard for distributing Python
packages. Although Bazel is pretty versatile and is amazing for it's
reproducible and incremental build capabilities, these can only be still used
by the contributors and developers for building and testing the gRPC code. But
there's no way yet to build Python packages for distribution.
### Building gRPC Python with Bazel on Kokoro (internal CI)
Integration with the internal CI was one of the areas that highlighted how
simple Bazel can be to use. gRPC was already using a dockerized Bazel setup to
build some of it's core code (but not as the primary build setup). Adding a new
job on the internal CI ended up being as simple as creating a new shell script
to install the required dependencies (which were python-dev and Bazel) and a
new configuration file which pointed to the subdirectiory (src/python) under
which to look for targets and run the tests accordingly.
### Handling imports in Python code
When writing Python packages, imports in nested modules are typically made
relative to the package root. But because of the way Bazel works, these paths
wouldn't make sense from the Workspace root. So, the folks at Bazel have added
a nifty `imports` parameter to all the Python rules which lets us specify for
each target, which path to consider as the root. This parameter allows for
relative paths like `imports = ["../",]`.
### Fetching Python headers for Cython code to use
Cython code makes use of `Python.h`, which pulls in the Python API for C
extension modules to use, but it's location depending on the Python version and
operating system the code is building on. To make this easier, the folks at
Tensorflow wrote [repository rules for Python
autoconfiguration](https://github.com/tensorflow/tensorflow/tree/e447ae4759317156d31a9421290716f0ffbffcd8/third_party/py).
This has been [adapted with some some
modifications](https://github.com/grpc/grpc/pull/15992) for use in gRPC Python
as well.
## How to use
All the Bazel tests for gRPC Python can be run using a single command:
```bash
bazel test --spawn_strategy=standalone --genrule_strategy=standalone //src/python/...
```
If any specific test is to be run, like say `LoggingPoolTest` (which is present
in
`src/python/grpcio_tests/tests/unit/framework/foundation/_logging_pool_test.py`),
the command to run would be:
```bash
bazel test --spawn_strategy=standalone --genrule_strategy=standalone //src/python/grpcio_tests/tests/unit/framework/foundation:logging_pool_test
```
where, `logging_pool_test` is the name of the Bazel target for this test.
Similarly, to run a particular method, use:
```bash
bazel test --spawn_strategy=standalone --genrule_strategy=standalone //src/python/grpcio_tests/tests/unit/_rpc_test --test_arg=RPCTest.testUnrecognizedMethod
```
## Useful Bazel flags
- Use `bazel build` with a `-s` flag to see the logs being printed out to
standard output while building.
- Similarly, use `bazel test` with a `--test_output=streamed` to see the the
test logs while testing. Something to know while using this flag is that all
tests will be run locally, without sharding, one at a time.
## Contributions
### Related to the project
- [435c6f8](https://github.com/grpc/grpc/commit/435c6f8d1e53783ec049b3482445813afd8bc514)
Update grpc_gevent cython files to include .pxi
- [74426fd](https://github.com/grpc/grpc/commit/74426fd2164c51d6754732ebe372133c19ba718c)
Add gevent_util.h to grpc_base_c Bazel target
- [b6518af](https://github.com/grpc/grpc/commit/b6518afdd610f0115b42aee1ffc71520c6b0d6b1)
Upgrade Bazel to 0.15.0
- [ebcf04d](https://github.com/grpc/grpc/commit/ebcf04d075333c42979536c5dd2091d363f67e5a)
Kokoro setup for building gRPC Python with Bazel
- [3af1aaa](https://github.com/grpc/grpc/commit/3af1aaadabf49bc6274711a11f81627c0f351a9a)
Basic setup to build gRPC Python with Bazel
- [11f199e](https://github.com/grpc/grpc/commit/11f199e34dc416a2bd8b56391b242a867bedade4)
Workspace changes to build gRPC Python with Bazel
- [848fd9d](https://github.com/grpc/grpc/commit/848fd9d75f6df10f00e8328ff052c0237b3002ab)
Minimal Bazel BUILD files for grpcio Python
### Other contibutions
- [89ce16b](https://github.com/grpc/grpc/commit/89ce16b6daaad4caeb1c9ba670c6c4b62ea1a93c)
Update Dockerfiles for python artifacts to use latest git version
- [32f7c48](https://github.com/grpc/grpc/commit/32f7c48dad71cac7af652bf994ab1dde3ddb0607)
Revert removals from python artifact dockerfiles
- [712eb9f](https://github.com/grpc/grpc/commit/712eb9ff91cde66af94e8381ec01ad512ed6d03c)
Make logging after success in jobset more apparent
- [c6e4372](https://github.com/grpc/grpc/commit/c6e4372f8a93bb0eb996b5f202465785422290f2)
Create README for gRPC Python reflection package
- [2e113ca](https://github.com/grpc/grpc/commit/2e113ca6b2cc31aa8a9687d40ee1bd759381654f)
Update logging in Python to use module-level logger
### Pending PRs
- BUILD files for all tests in
[tests.json](https://github.com/ghostwriternr/grpc/blob/70c8a58b2918a5369905e5a203d7ce7897b6207e/src/python/grpcio_tests/tests/tests.json).
- BUILD files for gRPC testing, gRPC health checking, gRPC reflection.
- (Yet to complete) BUILD files for grpcio_tools. One test depends on this.
## Known issues
- [grpc/grpc #16336](https://github.com/grpc/grpc/issues/16336) RuntimeError
for `_reconnect_test` Python unit test with Bazel
- Some tests in Bazel pass despite throwing an exception. Example:
`testAbortedStreamStream` in
`src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py`.
- [#14557](https://github.com/grpc/grpc/pull/14557) introduced a minor bug
where the module level loggers don't initialize a default logging handler.
- Sanity test doesn't make sense in the context of Bazel, and thus fails.
- There are some issues with Python2 vs Python3. Specifically,
- On some machines, “cygrpc.so: undefined symbol: _Py_FalseStruct” error
shows up. This is because of incorrect Python version being used to build
Cython.
- Some external packages like enum34 throw errors when used with Python 3 and
some extra packages are currently installed as Python version in current
build scripts. For now, the extra packages are added to a
`requirements.bazel.txt` file in the repository root.

@ -668,11 +668,20 @@
LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE))
endif
# gpr .pc file
PC_NAME = gpr
PC_DESCRIPTION = gRPC platform support library
PC_CFLAGS =
PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GPR)
PC_LIBS_PRIVATE = $(PC_LIBS_GPR)
PC_LIB = -lgpr
GPR_PC_FILE := $(CORE_PC_TEMPLATE)
# grpc .pc file
PC_NAME = gRPC
PC_DESCRIPTION = high performance general RPC framework
PC_CFLAGS =
PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
PC_REQUIRES_PRIVATE = gpr $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPC) $(PC_LIBS_SECURE)
PC_LIB = -lgrpc
GRPC_PC_FILE := $(CORE_PC_TEMPLATE)
@ -681,7 +690,7 @@
PC_NAME = gRPC unsecure
PC_DESCRIPTION = high performance general RPC framework without SSL
PC_CFLAGS =
PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC)
PC_REQUIRES_PRIVATE = gpr $(PC_REQUIRES_GRPC)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
PC_LIB = -lgrpc
GRPC_UNSECURE_PC_FILE := $(CORE_PC_TEMPLATE)
@ -976,9 +985,9 @@
% endif
% endfor
pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc
pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
pc_cxx: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc
@ -1199,6 +1208,11 @@
$(E) "[MAKE] Generating $@"
$(Q) echo "$(CACHE_MK)" | tr , '\n' >$@
$(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc:
$(E) "[MAKE] Generating $@"
$(Q) mkdir -p $(@D)
$(Q) echo "$(GPR_PC_FILE)" | tr , '\n' >$@
$(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc:
$(E) "[MAKE] Generating $@"
$(Q) mkdir -p $(@D)
@ -1397,6 +1411,7 @@
install-pkg-config_c: pc_c pc_c_unsecure
$(E) "[INSTALL] Installing C pkg-config files"
$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
$(Q) $(INSTALL) -m 0644 $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc $(prefix)/lib/pkgconfig/gpr.pc
$(Q) $(INSTALL) -m 0644 $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(prefix)/lib/pkgconfig/grpc.pc
$(Q) $(INSTALL) -m 0644 $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(prefix)/lib/pkgconfig/grpc_unsecure.pc

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

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

Loading…
Cancel
Save