Merge branch 'master' into combinernew

reviewable/pr20542/r2
Yash Tibrewal 6 years ago
commit c6da80bcce
  1. 2
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 2
      .github/ISSUE_TEMPLATE/cleanup_request.md
  3. 2
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 2
      .github/pull_request_template.md
  5. 9
      BUILD
  6. 6
      BUILD.gn
  7. 119
      CMakeLists.txt
  8. 72
      Makefile
  9. 19
      build.yaml
  10. 12
      cmake/pkg-config-template.pc.in
  11. 1
      config.m4
  12. 1
      config.w32
  13. 2
      doc/keepalive.md
  14. 4
      examples/cpp/helloworld/Makefile
  15. 5
      gRPC-C++.podspec
  16. 3
      gRPC-Core.podspec
  17. 18
      gRPC.podspec
  18. 2
      grpc.gemspec
  19. 4
      grpc.gyp
  20. 62
      include/grpc/grpc_security.h
  21. 2
      include/grpc/impl/codegen/sync_generic.h
  22. 5
      include/grpcpp/security/credentials.h
  23. 5
      include/grpcpp/security/credentials_impl.h
  24. 6
      include/grpcpp/security/server_credentials.h
  25. 5
      include/grpcpp/security/server_credentials_impl.h
  26. 330
      include/grpcpp/security/tls_credentials_options.h
  27. 2
      package.xml
  28. 116
      src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
  29. 2
      src/core/ext/filters/client_channel/subchannel.h
  30. 126
      src/core/ext/filters/client_channel/xds/xds_api.cc
  31. 9
      src/core/ext/filters/client_channel/xds/xds_api.h
  32. 452
      src/core/ext/filters/client_channel/xds/xds_bootstrap.cc
  33. 99
      src/core/ext/filters/client_channel/xds/xds_bootstrap.h
  34. 5
      src/core/ext/filters/client_channel/xds/xds_channel.cc
  35. 4
      src/core/ext/filters/client_channel/xds/xds_channel.h
  36. 33
      src/core/ext/filters/client_channel/xds/xds_channel_secure.cc
  37. 52
      src/core/ext/filters/client_channel/xds/xds_client.cc
  38. 11
      src/core/ext/filters/client_channel/xds/xds_client.h
  39. 416
      src/core/ext/transport/chttp2/transport/hpack_encoder.cc
  40. 36
      src/core/ext/transport/chttp2/transport/hpack_encoder.h
  41. 5
      src/core/lib/gprpp/inlined_vector.h
  42. 2
      src/core/lib/gprpp/memory.h
  43. 11
      src/core/lib/iomgr/executor.cc
  44. 3
      src/core/lib/iomgr/executor.h
  45. 2
      src/core/lib/json/json.h
  46. 4
      src/core/lib/json/json_string.cc
  47. 64
      src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h
  48. 6
      src/core/lib/security/security_connector/tls/spiffe_security_connector.cc
  49. 1
      src/core/lib/surface/init.cc
  50. 2
      src/core/lib/transport/connectivity_state.h
  51. 7
      src/cpp/client/secure_credentials.cc
  52. 1
      src/cpp/client/secure_credentials.h
  53. 282
      src/cpp/common/tls_credentials_options.cc
  54. 150
      src/cpp/common/tls_credentials_options_util.cc
  55. 58
      src/cpp/common/tls_credentials_options_util.h
  56. 7
      src/cpp/server/secure_server_credentials.cc
  57. 1
      src/cpp/server/secure_server_credentials.h
  58. 10
      src/csharp/Grpc.Core/Calls.cs
  59. 2
      src/csharp/Grpc.IntegrationTesting/Messages.cs
  60. 2
      src/csharp/Grpc.IntegrationTesting/Metrics.cs
  61. 2
      src/objective-c/RxLibrary/GRXWriter.h
  62. 8
      src/objective-c/tests/Podfile
  63. 2
      src/objective-c/tests/TestBase.h
  64. 2
      src/php/ext/grpc/php_grpc.c
  65. 2
      src/php/tests/qps/generated_code/Grpc/Testing/GaugeResponse.php
  66. 2
      src/proto/grpc/testing/messages.proto
  67. 2
      src/proto/grpc/testing/metrics.proto
  68. 2
      src/python/grpcio/grpc/_cython/BUILD.bazel
  69. 20
      src/python/grpcio/grpc/_cython/_cygrpc/aio/call.pyx.pxi
  70. 6
      src/python/grpcio/grpc/_cython/_cygrpc/aio/channel.pyx.pxi
  71. 27
      src/python/grpcio/grpc/_cython/_cygrpc/aio/rpc_error.pxd.pxi
  72. 35
      src/python/grpcio/grpc/_cython/_cygrpc/aio/rpc_error.pyx.pxi
  73. 1
      src/python/grpcio/grpc/_cython/cygrpc.pyx
  74. 26
      src/python/grpcio/grpc/experimental/aio/__init__.py
  75. 28
      src/python/grpcio/grpc/experimental/aio/_channel.py
  76. 1
      src/python/grpcio/grpc_core_dependencies.py
  77. 1
      src/python/grpcio_tests/tests_aio/tests.json
  78. 33
      src/python/grpcio_tests/tests_aio/unit/channel_test.py
  79. 40
      src/python/grpcio_tests/tests_aio/unit/init_test.py
  80. 5
      src/python/grpcio_tests/tests_aio/unit/sync_server.py
  81. 1
      src/ruby/ext/grpc/extconf.rb
  82. 71
      templates/CMakeLists.txt.template
  83. 16
      templates/Makefile.template
  84. 18
      templates/gRPC.podspec.template
  85. 17
      test/core/client_channel/BUILD
  86. 338
      test/core/client_channel/xds_bootstrap_test.cc
  87. 13
      test/core/gprpp/inlined_vector_test.cc
  88. 541
      test/cpp/client/credentials_test.cc
  89. 4
      test/cpp/end2end/BUILD
  90. 22
      test/cpp/end2end/xds_bootstrap.json
  91. 12
      test/cpp/end2end/xds_bootstrap_bad.json
  92. 26
      test/cpp/end2end/xds_end2end_test.cc
  93. 30
      test/cpp/qps/driver.cc
  94. 66
      test/distrib/cpp/run_distrib_test_cmake_pkgconfig.sh
  95. 3
      tools/bazel.rc
  96. 2
      tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
  97. 2
      tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
  98. 9
      tools/dockerfile/grpc_artifact_python_manylinux1_x64/Dockerfile
  99. 11
      tools/dockerfile/grpc_artifact_python_manylinux1_x86/Dockerfile
  100. 10
      tools/dockerfile/grpc_artifact_python_manylinux2010_x64/Dockerfile
  101. Some files were not shown because too many files have changed in this diff Show More

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

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

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

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

@ -258,6 +258,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/security/credentials_impl.h",
"include/grpcpp/security/server_credentials.h",
"include/grpcpp/security/server_credentials_impl.h",
"include/grpcpp/security/tls_credentials_options.h",
"include/grpcpp/server.h",
"include/grpcpp/server_impl.h",
"include/grpcpp/server_builder.h",
@ -355,12 +356,15 @@ grpc_cc_library(
"src/cpp/common/secure_auth_context.cc",
"src/cpp/common/secure_channel_arguments.cc",
"src/cpp/common/secure_create_auth_context.cc",
"src/cpp/common/tls_credentials_options.cc",
"src/cpp/common/tls_credentials_options_util.cc",
"src/cpp/server/insecure_server_credentials.cc",
"src/cpp/server/secure_server_credentials.cc",
],
hdrs = [
"src/cpp/client/secure_credentials.h",
"src/cpp/common/secure_auth_context.h",
"src/cpp/common/tls_credentials_options_util.h",
"src/cpp/server/secure_server_credentials.h",
],
language = "c++",
@ -369,6 +373,7 @@ grpc_cc_library(
deps = [
"gpr",
"grpc",
"grpc_secure",
"grpc++_base",
"grpc++_codegen_base",
"grpc++_codegen_base_src",
@ -1251,12 +1256,14 @@ grpc_cc_library(
name = "grpc_xds_client",
srcs = [
"src/core/ext/filters/client_channel/xds/xds_api.cc",
"src/core/ext/filters/client_channel/xds/xds_bootstrap.cc",
"src/core/ext/filters/client_channel/xds/xds_client.cc",
"src/core/ext/filters/client_channel/xds/xds_channel.cc",
"src/core/ext/filters/client_channel/xds/xds_client_stats.cc",
],
hdrs = [
"src/core/ext/filters/client_channel/xds/xds_api.h",
"src/core/ext/filters/client_channel/xds/xds_bootstrap.h",
"src/core/ext/filters/client_channel/xds/xds_client.h",
"src/core/ext/filters/client_channel/xds/xds_channel.h",
"src/core/ext/filters/client_channel/xds/xds_channel_args.h",
@ -1274,12 +1281,14 @@ grpc_cc_library(
name = "grpc_xds_client_secure",
srcs = [
"src/core/ext/filters/client_channel/xds/xds_api.cc",
"src/core/ext/filters/client_channel/xds/xds_bootstrap.cc",
"src/core/ext/filters/client_channel/xds/xds_client.cc",
"src/core/ext/filters/client_channel/xds/xds_channel_secure.cc",
"src/core/ext/filters/client_channel/xds/xds_client_stats.cc",
],
hdrs = [
"src/core/ext/filters/client_channel/xds/xds_api.h",
"src/core/ext/filters/client_channel/xds/xds_bootstrap.h",
"src/core/ext/filters/client_channel/xds/xds_client.h",
"src/core/ext/filters/client_channel/xds/xds_channel.h",
"src/core/ext/filters/client_channel/xds/xds_channel_args.h",

@ -298,6 +298,8 @@ config("grpc_config") {
"src/core/ext/filters/client_channel/subchannel_pool_interface.h",
"src/core/ext/filters/client_channel/xds/xds_api.cc",
"src/core/ext/filters/client_channel/xds/xds_api.h",
"src/core/ext/filters/client_channel/xds/xds_bootstrap.cc",
"src/core/ext/filters/client_channel/xds/xds_bootstrap.h",
"src/core/ext/filters/client_channel/xds/xds_channel.h",
"src/core/ext/filters/client_channel/xds/xds_channel_args.h",
"src/core/ext/filters/client_channel/xds/xds_channel_secure.cc",
@ -1164,6 +1166,7 @@ config("grpc_config") {
"include/grpcpp/security/credentials_impl.h",
"include/grpcpp/security/server_credentials.h",
"include/grpcpp/security/server_credentials_impl.h",
"include/grpcpp/security/tls_credentials_options.h",
"include/grpcpp/server.h",
"include/grpcpp/server_builder.h",
"include/grpcpp/server_builder_impl.h",
@ -1401,6 +1404,9 @@ config("grpc_config") {
"src/cpp/common/secure_auth_context.h",
"src/cpp/common/secure_channel_arguments.cc",
"src/cpp/common/secure_create_auth_context.cc",
"src/cpp/common/tls_credentials_options.cc",
"src/cpp/common/tls_credentials_options_util.cc",
"src/cpp/common/tls_credentials_options_util.h",
"src/cpp/common/validate_service_config.cc",
"src/cpp/common/version_cc.cc",
"src/cpp/server/async_generic_service.cc",

@ -25,10 +25,11 @@ cmake_minimum_required(VERSION 3.5.1)
set(PACKAGE_NAME "grpc")
set(PACKAGE_VERSION "1.25.0-dev")
set(gRPC_CORE_VERSION "8.0.0")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
project(${PACKAGE_NAME} C CXX)
project(${PACKAGE_NAME} LANGUAGES C CXX)
set(gRPC_INSTALL_BINDIR "bin" CACHE STRING "Installation directory for executables")
set(gRPC_INSTALL_LIBDIR "lib" CACHE STRING "Installation directory for libraries")
@ -730,6 +731,7 @@ add_dependencies(buildtests_cxx transport_security_common_api_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx writes_per_rpc_test)
endif()
add_dependencies(buildtests_cxx xds_bootstrap_test)
add_dependencies(buildtests_cxx xds_end2end_test)
add_dependencies(buildtests_cxx bad_streaming_id_bad_client_test)
add_dependencies(buildtests_cxx badreq_bad_client_test)
@ -1309,6 +1311,7 @@ add_library(grpc
src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
src/core/ext/filters/client_channel/xds/xds_api.cc
src/core/ext/filters/client_channel/xds/xds_bootstrap.cc
src/core/ext/filters/client_channel/xds/xds_channel_secure.cc
src/core/ext/filters/client_channel/xds/xds_client.cc
src/core/ext/filters/client_channel/xds/xds_client_stats.cc
@ -2826,6 +2829,7 @@ add_library(grpc_unsecure
src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c
src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
src/core/ext/filters/client_channel/xds/xds_api.cc
src/core/ext/filters/client_channel/xds/xds_bootstrap.cc
src/core/ext/filters/client_channel/xds/xds_channel.cc
src/core/ext/filters/client_channel/xds/xds_client.cc
src/core/ext/filters/client_channel/xds/xds_client_stats.cc
@ -3151,6 +3155,8 @@ add_library(grpc++
src/cpp/common/secure_auth_context.cc
src/cpp/common/secure_channel_arguments.cc
src/cpp/common/secure_create_auth_context.cc
src/cpp/common/tls_credentials_options.cc
src/cpp/common/tls_credentials_options_util.cc
src/cpp/server/insecure_server_credentials.cc
src/cpp/server/secure_server_credentials.cc
src/cpp/client/channel_cc.cc
@ -3322,6 +3328,7 @@ foreach(_hdr
include/grpcpp/security/credentials_impl.h
include/grpcpp/security/server_credentials.h
include/grpcpp/security/server_credentials_impl.h
include/grpcpp/security/tls_credentials_options.h
include/grpcpp/server.h
include/grpcpp/server_builder.h
include/grpcpp/server_builder_impl.h
@ -4425,6 +4432,7 @@ foreach(_hdr
include/grpcpp/security/credentials_impl.h
include/grpcpp/security/server_credentials.h
include/grpcpp/security/server_credentials_impl.h
include/grpcpp/security/tls_credentials_options.h
include/grpcpp/server.h
include/grpcpp/server_builder.h
include/grpcpp/server_builder_impl.h
@ -16790,6 +16798,47 @@ endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(xds_bootstrap_test
test/core/client_channel/xds_bootstrap_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(xds_bootstrap_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_UPB_GENERATED_DIR}
PRIVATE ${_gRPC_UPB_GRPC_GENERATED_DIR}
PRIVATE ${_gRPC_UPB_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_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(xds_bootstrap_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc++
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(xds_end2end_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/ads_for_test.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/ads_for_test.grpc.pb.cc
@ -19431,3 +19480,71 @@ endforeach()
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/etc/roots.pem
DESTINATION ${gRPC_INSTALL_SHAREDIR})
# Function to generate pkg-config files.
function(generate_pkgconfig name description version requires
libs libs_private output_filename)
set(PC_NAME "${name}")
set(PC_DESCRIPTION "${description}")
set(PC_VERSION "${version}")
set(PC_REQUIRES "${requires}")
set(PC_LIB "${libs}")
set(PC_LIBS_PRIVATE "${libs_private}")
set(output_filepath "${grpc_BINARY_DIR}/libs/opt/pkgconfig/${output_filename}")
configure_file(
"${grpc_SOURCE_DIR}/cmake/pkg-config-template.pc.in"
"${output_filepath}"
@ONLY)
install(FILES "${output_filepath}"
DESTINATION "lib/pkgconfig/")
endfunction()
# gpr .pc file
generate_pkgconfig(
"gpr"
"gRPC platform support library"
"${gRPC_CORE_VERSION}"
""
"-lgpr"
""
"gpr.pc")
# grpc .pc file
generate_pkgconfig(
"gRPC"
"high performance general RPC framework"
"${gRPC_CORE_VERSION}"
"gpr"
"-lgrpc -laddress_sorting -lcares -lz"
""
"grpc.pc")
# grpc_unsecure .pc file
generate_pkgconfig(
"gRPC unsecure"
"high performance general RPC framework without SSL"
"${gRPC_CORE_VERSION}"
"gpr"
"-lgrpc_unsecure"
""
"grpc_unsecure.pc")
# grpc++ .pc file
generate_pkgconfig(
"gRPC++"
"C++ wrapper for gRPC"
"${PACKAGE_VERSION}"
"grpc"
"-lgrpc++"
""
"grpc++.pc")
# grpc++_unsecure .pc file
generate_pkgconfig(
"gRPC++ unsecure"
"C++ wrapper for gRPC without SSL"
"${PACKAGE_VERSION}"
"grpc_unsecure"
"-lgrpc++_unsecure"
""
"grpc++_unsecure.pc")

@ -498,11 +498,11 @@ ifeq ($(HAS_PKG_CONFIG), true)
CACHE_MK += HAS_PKG_CONFIG = true,
endif
CORE_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CORE_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
CORE_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CORE_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires: $(PC_REQUIRES),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
CPP_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CPP_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
CPP_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CPP_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires: $(PC_REQUIRES),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
CSHARP_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CSHARP_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
CSHARP_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CSHARP_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires: $(PC_REQUIRES),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
ifeq ($(SYSTEM),MINGW32)
EXECUTABLE_SUFFIX = .exe
@ -795,7 +795,7 @@ endif
PC_NAME = gpr
PC_DESCRIPTION = gRPC platform support library
PC_CFLAGS =
PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GPR)
PC_REQUIRES = $(PC_REQUIRES_GPR)
PC_LIBS_PRIVATE = $(PC_LIBS_GPR)
PC_LIB = -lgpr
GPR_PC_FILE := $(CORE_PC_TEMPLATE)
@ -804,7 +804,7 @@ GPR_PC_FILE := $(CORE_PC_TEMPLATE)
PC_NAME = gRPC
PC_DESCRIPTION = high performance general RPC framework
PC_CFLAGS =
PC_REQUIRES_PRIVATE = gpr $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
PC_REQUIRES = 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)
@ -813,7 +813,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 = gpr $(PC_REQUIRES_GRPC)
PC_REQUIRES = gpr $(PC_REQUIRES_GRPC)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
PC_LIB = -lgrpc_unsecure
GRPC_UNSECURE_PC_FILE := $(CORE_PC_TEMPLATE)
@ -875,7 +875,7 @@ endif
PC_NAME = gRPC++
PC_DESCRIPTION = C++ wrapper for gRPC
PC_CFLAGS =
PC_REQUIRES_PRIVATE = grpc $(PC_REQUIRES_GRPCXX)
PC_REQUIRES = grpc $(PC_REQUIRES_GRPCXX)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
PC_LIB = -lgrpc++
GRPCXX_PC_FILE := $(CPP_PC_TEMPLATE)
@ -884,7 +884,7 @@ GRPCXX_PC_FILE := $(CPP_PC_TEMPLATE)
PC_NAME = gRPC++ unsecure
PC_DESCRIPTION = C++ wrapper for gRPC without SSL
PC_CFLAGS =
PC_REQUIRES_PRIVATE = grpc_unsecure $(PC_REQUIRES_GRPCXX)
PC_REQUIRES = grpc_unsecure $(PC_REQUIRES_GRPCXX)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
PC_LIB = -lgrpc++_unsecure
GRPCXX_UNSECURE_PC_FILE := $(CPP_PC_TEMPLATE)
@ -1296,6 +1296,7 @@ transport_connectivity_state_test: $(BINDIR)/$(CONFIG)/transport_connectivity_st
transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
transport_security_common_api_test: $(BINDIR)/$(CONFIG)/transport_security_common_api_test
writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test
xds_bootstrap_test: $(BINDIR)/$(CONFIG)/xds_bootstrap_test
xds_end2end_test: $(BINDIR)/$(CONFIG)/xds_end2end_test
public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89
boringssl_ssl_test: $(BINDIR)/$(CONFIG)/boringssl_ssl_test
@ -1767,6 +1768,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_common_api_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/xds_bootstrap_test \
$(BINDIR)/$(CONFIG)/xds_end2end_test \
$(BINDIR)/$(CONFIG)/boringssl_ssl_test \
$(BINDIR)/$(CONFIG)/boringssl_crypto_test \
@ -1937,6 +1939,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_common_api_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/xds_bootstrap_test \
$(BINDIR)/$(CONFIG)/xds_end2end_test \
$(BINDIR)/$(CONFIG)/bad_streaming_id_bad_client_test \
$(BINDIR)/$(CONFIG)/badreq_bad_client_test \
@ -2483,6 +2486,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/transport_security_common_api_test || ( echo test transport_security_common_api_test failed ; exit 1 )
$(E) "[RUN] Testing writes_per_rpc_test"
$(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 )
$(E) "[RUN] Testing xds_bootstrap_test"
$(Q) $(BINDIR)/$(CONFIG)/xds_bootstrap_test || ( echo test xds_bootstrap_test failed ; exit 1 )
$(E) "[RUN] Testing xds_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/xds_end2end_test || ( echo test xds_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing bad_streaming_id_bad_client_test"
@ -3853,6 +3858,7 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
src/core/ext/filters/client_channel/xds/xds_api.cc \
src/core/ext/filters/client_channel/xds/xds_bootstrap.cc \
src/core/ext/filters/client_channel/xds/xds_channel_secure.cc \
src/core/ext/filters/client_channel/xds/xds_client.cc \
src/core/ext/filters/client_channel/xds/xds_client_stats.cc \
@ -5322,6 +5328,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c \
src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
src/core/ext/filters/client_channel/xds/xds_api.cc \
src/core/ext/filters/client_channel/xds/xds_bootstrap.cc \
src/core/ext/filters/client_channel/xds/xds_channel.cc \
src/core/ext/filters/client_channel/xds/xds_client.cc \
src/core/ext/filters/client_channel/xds/xds_client_stats.cc \
@ -5616,6 +5623,8 @@ LIBGRPC++_SRC = \
src/cpp/common/secure_auth_context.cc \
src/cpp/common/secure_channel_arguments.cc \
src/cpp/common/secure_create_auth_context.cc \
src/cpp/common/tls_credentials_options.cc \
src/cpp/common/tls_credentials_options_util.cc \
src/cpp/server/insecure_server_credentials.cc \
src/cpp/server/secure_server_credentials.cc \
src/cpp/client/channel_cc.cc \
@ -5750,6 +5759,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/security/credentials_impl.h \
include/grpcpp/security/server_credentials.h \
include/grpcpp/security/server_credentials_impl.h \
include/grpcpp/security/tls_credentials_options.h \
include/grpcpp/server.h \
include/grpcpp/server_builder.h \
include/grpcpp/server_builder_impl.h \
@ -6784,6 +6794,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/security/credentials_impl.h \
include/grpcpp/security/server_credentials.h \
include/grpcpp/security/server_credentials_impl.h \
include/grpcpp/security/tls_credentials_options.h \
include/grpcpp/server.h \
include/grpcpp/server_builder.h \
include/grpcpp/server_builder_impl.h \
@ -20019,6 +20030,49 @@ endif
endif
XDS_BOOTSTRAP_TEST_SRC = \
test/core/client_channel/xds_bootstrap_test.cc \
XDS_BOOTSTRAP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(XDS_BOOTSTRAP_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/xds_bootstrap_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)/xds_bootstrap_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/xds_bootstrap_test: $(PROTOBUF_DEP) $(XDS_BOOTSTRAP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(XDS_BOOTSTRAP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/xds_bootstrap_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/client_channel/xds_bootstrap_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_xds_bootstrap_test: $(XDS_BOOTSTRAP_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(XDS_BOOTSTRAP_TEST_OBJS:.o=.dep)
endif
endif
XDS_END2END_TEST_SRC = \
$(GENDIR)/src/proto/grpc/testing/xds/ads_for_test.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/ads_for_test.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/xds/eds_for_test.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/eds_for_test.grpc.pb.cc \
@ -22688,6 +22742,8 @@ src/cpp/common/auth_property_iterator.cc: $(OPENSSL_DEP)
src/cpp/common/secure_auth_context.cc: $(OPENSSL_DEP)
src/cpp/common/secure_channel_arguments.cc: $(OPENSSL_DEP)
src/cpp/common/secure_create_auth_context.cc: $(OPENSSL_DEP)
src/cpp/common/tls_credentials_options.cc: $(OPENSSL_DEP)
src/cpp/common/tls_credentials_options_util.cc: $(OPENSSL_DEP)
src/cpp/ext/proto_server_reflection.cc: $(OPENSSL_DEP)
src/cpp/ext/proto_server_reflection_plugin.cc: $(OPENSSL_DEP)
src/cpp/server/channelz/channelz_service.cc: $(OPENSSL_DEP)

@ -515,6 +515,7 @@ filegroups:
- include/grpcpp/security/credentials_impl.h
- include/grpcpp/security/server_credentials.h
- include/grpcpp/security/server_credentials_impl.h
- include/grpcpp/security/tls_credentials_options.h
- include/grpcpp/server.h
- include/grpcpp/server_builder.h
- include/grpcpp/server_builder_impl.h
@ -1537,12 +1538,14 @@ filegroups:
- name: grpc_xds_client
headers:
- src/core/ext/filters/client_channel/xds/xds_api.h
- src/core/ext/filters/client_channel/xds/xds_bootstrap.h
- src/core/ext/filters/client_channel/xds/xds_channel.h
- src/core/ext/filters/client_channel/xds/xds_channel_args.h
- src/core/ext/filters/client_channel/xds/xds_client.h
- src/core/ext/filters/client_channel/xds/xds_client_stats.h
src:
- src/core/ext/filters/client_channel/xds/xds_api.cc
- src/core/ext/filters/client_channel/xds/xds_bootstrap.cc
- src/core/ext/filters/client_channel/xds/xds_channel.cc
- src/core/ext/filters/client_channel/xds/xds_client.cc
- src/core/ext/filters/client_channel/xds/xds_client_stats.cc
@ -1553,12 +1556,14 @@ filegroups:
- name: grpc_xds_client_secure
headers:
- src/core/ext/filters/client_channel/xds/xds_api.h
- src/core/ext/filters/client_channel/xds/xds_bootstrap.h
- src/core/ext/filters/client_channel/xds/xds_channel.h
- src/core/ext/filters/client_channel/xds/xds_channel_args.h
- src/core/ext/filters/client_channel/xds/xds_client.h
- src/core/ext/filters/client_channel/xds/xds_client_stats.h
src:
- src/core/ext/filters/client_channel/xds/xds_api.cc
- src/core/ext/filters/client_channel/xds/xds_bootstrap.cc
- src/core/ext/filters/client_channel/xds/xds_channel_secure.cc
- src/core/ext/filters/client_channel/xds/xds_client.cc
- src/core/ext/filters/client_channel/xds/xds_client_stats.cc
@ -1816,6 +1821,7 @@ libs:
- include/grpcpp/impl/codegen/core_codegen.h
- src/cpp/client/secure_credentials.h
- src/cpp/common/secure_auth_context.h
- src/cpp/common/tls_credentials_options_util.h
- src/cpp/server/secure_server_credentials.h
src:
- src/cpp/client/insecure_credentials.cc
@ -1824,6 +1830,8 @@ libs:
- src/cpp/common/secure_auth_context.cc
- src/cpp/common/secure_channel_arguments.cc
- src/cpp/common/secure_create_auth_context.cc
- src/cpp/common/tls_credentials_options.cc
- src/cpp/common/tls_credentials_options_util.cc
- src/cpp/server/insecure_server_credentials.cc
- src/cpp/server/secure_server_credentials.cc
deps:
@ -6004,6 +6012,17 @@ targets:
- mac
- linux
- posix
- name: xds_bootstrap_test
gtest: true
build: test
language: c++
src:
- test/core/client_channel/xds_bootstrap_test.cc
deps:
- grpc_test_util
- grpc++
- grpc
- gpr
- name: xds_end2end_test
gtest: true
build: test

@ -0,0 +1,12 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib
Name: @PC_NAME@
Description: @PC_DESCRIPTION@
Version: @PC_VERSION@
Cflags: -I${includedir}
Requires: @PC_REQUIRES@
Libs: -L${libdir} @PC_LIB@
Libs.private: @PC_LIBS_PRIVATE@

@ -418,6 +418,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
src/core/ext/filters/client_channel/xds/xds_api.cc \
src/core/ext/filters/client_channel/xds/xds_bootstrap.cc \
src/core/ext/filters/client_channel/xds/xds_channel_secure.cc \
src/core/ext/filters/client_channel/xds/xds_client.cc \
src/core/ext/filters/client_channel/xds/xds_client_stats.cc \

@ -388,6 +388,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\resolver\\fake\\fake_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds.cc " +
"src\\core\\ext\\filters\\client_channel\\xds\\xds_api.cc " +
"src\\core\\ext\\filters\\client_channel\\xds\\xds_bootstrap.cc " +
"src\\core\\ext\\filters\\client_channel\\xds\\xds_channel_secure.cc " +
"src\\core\\ext\\filters\\client_channel\\xds\\xds_client.cc " +
"src\\core\\ext\\filters\\client_channel\\xds\\xds_client_stats.cc " +

@ -1,4 +1,4 @@
# Keepalive User Guide for gRPC Core (and dependants)
# Keepalive User Guide for gRPC Core (and dependents)
The keepalive ping is a way to check if a channel is currently working by sending HTTP2 pings over the transport. It is sent periodically, and if the ping is not acknowledged by the peer within a certain timeout period, the transport is disconnected.

@ -20,12 +20,12 @@ CXX = g++
CPPFLAGS += `pkg-config --cflags protobuf grpc`
CXXFLAGS += -std=c++11
ifeq ($(SYSTEM),Darwin)
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++`\
-pthread\
-lgrpc++_reflection\
-ldl
else
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++`\
-pthread\
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
-ldl

@ -121,6 +121,7 @@ Pod::Spec.new do |s|
'include/grpcpp/security/credentials_impl.h',
'include/grpcpp/security/server_credentials.h',
'include/grpcpp/security/server_credentials_impl.h',
'include/grpcpp/security/tls_credentials_options.h',
'include/grpcpp/server.h',
'include/grpcpp/server_builder.h',
'include/grpcpp/server_builder_impl.h',
@ -220,6 +221,7 @@ Pod::Spec.new do |s|
ss.source_files = 'include/grpcpp/impl/codegen/core_codegen.h',
'src/cpp/client/secure_credentials.h',
'src/cpp/common/secure_auth_context.h',
'src/cpp/common/tls_credentials_options_util.h',
'src/cpp/server/secure_server_credentials.h',
'src/cpp/client/create_channel_internal.h',
'src/cpp/common/channel_filter.h',
@ -234,6 +236,8 @@ Pod::Spec.new do |s|
'src/cpp/common/secure_auth_context.cc',
'src/cpp/common/secure_channel_arguments.cc',
'src/cpp/common/secure_create_auth_context.cc',
'src/cpp/common/tls_credentials_options.cc',
'src/cpp/common/tls_credentials_options_util.cc',
'src/cpp/server/insecure_server_credentials.cc',
'src/cpp/server/secure_server_credentials.cc',
'src/cpp/client/channel_cc.cc',
@ -277,6 +281,7 @@ Pod::Spec.new do |s|
ss.private_header_files = 'include/grpcpp/impl/codegen/core_codegen.h',
'src/cpp/client/secure_credentials.h',
'src/cpp/common/secure_auth_context.h',
'src/cpp/common/tls_credentials_options_util.h',
'src/cpp/server/secure_server_credentials.h',
'src/cpp/client/create_channel_internal.h',
'src/cpp/common/channel_filter.h',

@ -556,6 +556,7 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.h',
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/xds/xds_api.h',
'src/core/ext/filters/client_channel/xds/xds_bootstrap.h',
'src/core/ext/filters/client_channel/xds/xds_channel.h',
'src/core/ext/filters/client_channel/xds/xds_channel_args.h',
'src/core/ext/filters/client_channel/xds/xds_client.h',
@ -918,6 +919,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
'src/core/ext/filters/client_channel/xds/xds_api.cc',
'src/core/ext/filters/client_channel/xds/xds_bootstrap.cc',
'src/core/ext/filters/client_channel/xds/xds_channel_secure.cc',
'src/core/ext/filters/client_channel/xds/xds_client.cc',
'src/core/ext/filters/client_channel/xds/xds_client_stats.cc',
@ -1294,6 +1296,7 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.h',
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/xds/xds_api.h',
'src/core/ext/filters/client_channel/xds/xds_bootstrap.h',
'src/core/ext/filters/client_channel/xds/xds_channel.h',
'src/core/ext/filters/client_channel/xds/xds_channel_args.h',
'src/core/ext/filters/client_channel/xds/xds_client.h',

@ -117,11 +117,9 @@ Pod::Spec.new do |s|
'src/objective-c/GRPCClient/GRPCCall+Cronet.h',
'src/objective-c/GRPCClient/GRPCCall+OAuth2.h',
'src/objective-c/GRPCClient/GRPCCall+Tests.h',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h',
'src/objective-c/GRPCClient/internal_testing/*.h'
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h'
ss.private_header_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.h'
ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,m}',
'src/objective-c/GRPCClient/private/GRPCCore/*.{h,m}',
ss.source_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.{h,m}',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.m',
'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h',
@ -170,4 +168,16 @@ Pod::Spec.new do |s|
ss.tvos.deployment_target = '10.0'
ss.watchos.deployment_target = '4.0'
end
s.subspec 'InternalTesting' do |ss|
ss.dependency "#{s.name}/GRPCCore", version
ss.public_header_files = 'src/objective-c/GRPCClient/internal_testing/*.h'
ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,m}'
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
ss.ios.deployment_target = '7.0'
ss.osx.deployment_target = '10.9'
ss.tvos.deployment_target = '10.0'
ss.watchos.deployment_target = '4.0'
end
end

@ -486,6 +486,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_api.h )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_bootstrap.h )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_channel.h )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_channel_args.h )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_client.h )
@ -848,6 +849,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds.cc )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_api.cc )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_bootstrap.cc )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_channel_secure.cc )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_client.cc )
s.files += %w( src/core/ext/filters/client_channel/xds/xds_client_stats.cc )

@ -556,6 +556,7 @@
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
'src/core/ext/filters/client_channel/xds/xds_api.cc',
'src/core/ext/filters/client_channel/xds/xds_bootstrap.cc',
'src/core/ext/filters/client_channel/xds/xds_channel_secure.cc',
'src/core/ext/filters/client_channel/xds/xds_client.cc',
'src/core/ext/filters/client_channel/xds/xds_client_stats.cc',
@ -1423,6 +1424,7 @@
'src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
'src/core/ext/filters/client_channel/xds/xds_api.cc',
'src/core/ext/filters/client_channel/xds/xds_bootstrap.cc',
'src/core/ext/filters/client_channel/xds/xds_channel.cc',
'src/core/ext/filters/client_channel/xds/xds_client.cc',
'src/core/ext/filters/client_channel/xds/xds_client_stats.cc',
@ -1524,6 +1526,8 @@
'src/cpp/common/secure_auth_context.cc',
'src/cpp/common/secure_channel_arguments.cc',
'src/cpp/common/secure_create_auth_context.cc',
'src/cpp/common/tls_credentials_options.cc',
'src/cpp/common/tls_credentials_options_util.cc',
'src/cpp/server/insecure_server_credentials.cc',
'src/cpp/server/secure_server_credentials.cc',
'src/cpp/client/channel_cc.cc',

@ -805,20 +805,32 @@ typedef struct grpc_tls_credential_reload_arg grpc_tls_credential_reload_arg;
typedef void (*grpc_tls_on_credential_reload_done_cb)(
grpc_tls_credential_reload_arg* arg);
/** A struct containing all information necessary to schedule/cancel
a credential reload request. cb and cb_user_data represent a gRPC-provided
callback and an argument passed to it. key_materials is an in/output
parameter containing currently used/newly reloaded credentials. If
credential reload does not result in a new credential, key_materials should
not be modified. status and error_details are used to hold information about
errors occurred when a credential reload request is scheduled/cancelled. It
is used for experimental purpose for now and subject to change. */
/** A struct containing all information necessary to schedule/cancel a
credential reload request.
- cb and cb_user_data represent a gRPC-provided
callback and an argument passed to it.
- key_materials_config is an in/output parameter containing currently
used/newly reloaded credentials. If credential reload does not result
in a new credential, key_materials_config should not be modified.
- status and error_details are used to hold information about
errors occurred when a credential reload request is scheduled/cancelled.
- config is a pointer to the unique grpc_tls_credential_reload_config
instance that this argument corresponds to.
- context is a pointer to a wrapped language implementation of this
grpc_tls_credential_reload_arg instance.
- destroy_context is a pointer to a caller-provided method that cleans
up any data associated with the context pointer.
It is used for experimental purposes for now and subject to change.
*/
struct grpc_tls_credential_reload_arg {
grpc_tls_on_credential_reload_done_cb cb;
void* cb_user_data;
grpc_tls_key_materials_config* key_materials_config;
grpc_ssl_certificate_config_reload_status status;
const char* error_details;
grpc_tls_credential_reload_config* config;
void* context;
void (*destroy_context)(void* ctx);
};
/** Create a grpc_tls_credential_reload_config instance.
@ -863,16 +875,27 @@ typedef void (*grpc_tls_on_server_authorization_check_done_cb)(
grpc_tls_server_authorization_check_arg* arg);
/** A struct containing all information necessary to schedule/cancel a server
authorization check request. cb and cb_user_data represent a gRPC-provided
callback and an argument passed to it. success will store the result of
server authorization check. That is, if success returns a non-zero value, it
means the authorization check passes and if returning zero, it means the
check fails. target_name is the name of an endpoint the channel is connecting
to and certificate represents a complete certificate chain including both
signing and leaf certificates. status and error_details contain information
about errors occurred when a server authorization check request is
scheduled/cancelled. It is used for experimental purpose for now and subject
to change.*/
authorization check request.
- cb and cb_user_data represent a gRPC-provided callback and an argument
passed to it.
- success will store the result of server authorization check. That is,
if success returns a non-zero value, it means the authorization check
passes and if returning zero, it means the check fails.
- target_name is the name of an endpoint the channel is connecting to.
- peer_cert represents a complete certificate chain including both
signing and leaf certificates.
- status and error_details contain information
about errors occurred when a server authorization check request is
scheduled/cancelled.
- config is a pointer to the unique
grpc_tls_server_authorization_check_config instance that this argument
corresponds to.
- context is a pointer to a wrapped language implementation of this
grpc_tls_server_authorization_check_arg instance.
- destroy_context is a pointer to a caller-provided method that cleans
up any data associated with the context pointer.
It is used for experimental purpose for now and subject to change.
*/
struct grpc_tls_server_authorization_check_arg {
grpc_tls_on_server_authorization_check_done_cb cb;
void* cb_user_data;
@ -881,6 +904,9 @@ struct grpc_tls_server_authorization_check_arg {
const char* peer_cert;
grpc_status_code status;
const char* error_details;
grpc_tls_server_authorization_check_config* config;
void* context;
void (*destroy_context)(void* ctx);
};
/** Create a grpc_tls_server_authorization_check_config instance.

@ -18,7 +18,7 @@
#ifndef GRPC_IMPL_CODEGEN_SYNC_GENERIC_H
#define GRPC_IMPL_CODEGEN_SYNC_GENERIC_H
/* Generic type defintions for gpr_sync. */
/* Generic type definitions for gpr_sync. */
#include <grpc/impl/codegen/port_platform.h>

@ -132,6 +132,11 @@ static inline std::shared_ptr<grpc_impl::ChannelCredentials> LocalCredentials(
return ::grpc_impl::experimental::LocalCredentials(type);
}
static inline std::shared_ptr<grpc_impl::ChannelCredentials> TlsCredentials(
const ::grpc_impl::experimental::TlsCredentialsOptions& options) {
return ::grpc_impl::experimental::TlsCredentials(options);
}
} // namespace experimental
} // namespace grpc

@ -28,6 +28,7 @@
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/security/auth_context.h>
#include <grpcpp/security/tls_credentials_options.h>
#include <grpcpp/support/channel_arguments_impl.h>
#include <grpcpp/support/status.h>
#include <grpcpp/support/string_ref.h>
@ -336,6 +337,10 @@ std::shared_ptr<ChannelCredentials> AltsCredentials(
std::shared_ptr<ChannelCredentials> LocalCredentials(
grpc_local_connect_type type);
/// Builds TLS Credentials given TLS options.
std::shared_ptr<ChannelCredentials> TlsCredentials(
const TlsCredentialsOptions& options);
} // namespace experimental
} // namespace grpc_impl

@ -79,6 +79,12 @@ static inline std::shared_ptr<ServerCredentials> LocalServerCredentials(
return ::grpc_impl::experimental::LocalServerCredentials(type);
}
/// Builds TLS ServerCredentials given TLS options.
static inline std::shared_ptr<ServerCredentials> TlsServerCredentials(
const ::grpc_impl::experimental::TlsCredentialsOptions& options) {
return ::grpc_impl::experimental::TlsServerCredentials(options);
}
} // namespace experimental
} // namespace grpc

@ -24,6 +24,7 @@
#include <grpc/grpc_security_constants.h>
#include <grpcpp/security/auth_metadata_processor.h>
#include <grpcpp/security/tls_credentials_options.h>
#include <grpcpp/support/config.h>
struct grpc_server;
@ -79,6 +80,10 @@ std::shared_ptr<ServerCredentials> AltsServerCredentials(
std::shared_ptr<ServerCredentials> LocalServerCredentials(
grpc_local_connect_type type);
/// Builds TLS ServerCredentials given TLS options.
std::shared_ptr<ServerCredentials> TlsServerCredentials(
const TlsCredentialsOptions& options);
} // namespace experimental
} // namespace grpc_impl

@ -0,0 +1,330 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SECURITY_TLS_CREDENTIALS_OPTIONS_H
#define GRPCPP_SECURITY_TLS_CREDENTIALS_OPTIONS_H
#include <memory>
#include <vector>
#include <grpc/grpc_security_constants.h>
#include <grpc/status.h>
#include <grpc/support/log.h>
#include <grpcpp/support/config.h>
typedef struct grpc_tls_credential_reload_arg grpc_tls_credential_reload_arg;
typedef struct grpc_tls_credential_reload_config
grpc_tls_credential_reload_config;
typedef struct grpc_tls_server_authorization_check_arg
grpc_tls_server_authorization_check_arg;
typedef struct grpc_tls_server_authorization_check_config
grpc_tls_server_authorization_check_config;
typedef struct grpc_tls_credentials_options grpc_tls_credentials_options;
namespace grpc_impl {
namespace experimental {
/** TLS key materials config, wrapper for grpc_tls_key_materials_config. It is
* used for experimental purposes for now and subject to change. **/
class TlsKeyMaterialsConfig {
public:
struct PemKeyCertPair {
grpc::string private_key;
grpc::string cert_chain;
};
/** Getters for member fields. **/
const grpc::string pem_root_certs() const { return pem_root_certs_; }
const std::vector<PemKeyCertPair>& pem_key_cert_pair_list() const {
return pem_key_cert_pair_list_;
}
int version() const { return version_; }
/** Setter for key materials that will be called by the user. The setter
* transfers ownership of the arguments to the config. **/
void set_pem_root_certs(grpc::string pem_root_certs);
void add_pem_key_cert_pair(const PemKeyCertPair& pem_key_cert_pair);
void set_key_materials(grpc::string pem_root_certs,
std::vector<PemKeyCertPair> pem_key_cert_pair_list);
void set_version(int version) { version_ = version; };
private:
int version_ = 0;
std::vector<PemKeyCertPair> pem_key_cert_pair_list_;
grpc::string pem_root_certs_;
};
/** TLS credential reload arguments, wraps grpc_tls_credential_reload_arg. It is
* used for experimental purposes for now and it is subject to change.
*
* The credential reload arg contains all the info necessary to schedule/cancel
* a credential reload request. The callback function must be called after
* finishing the schedule operation. See the description of the
* grpc_tls_credential_reload_arg struct in grpc_security.h for more details.
* **/
class TlsCredentialReloadArg {
public:
/** TlsCredentialReloadArg does not take ownership of the C arg that is passed
* to the constructor. One must remember to free any memory allocated to the C
* arg after using the setter functions below. **/
TlsCredentialReloadArg(grpc_tls_credential_reload_arg* arg);
~TlsCredentialReloadArg();
/** Getters for member fields. The callback function is not exposed.
* They return the corresponding fields of the underlying C arg. In the case
* of the key materials config, it creates a new instance of the C++ key
* materials config from the underlying C grpc_tls_key_materials_config. **/
void* cb_user_data() const;
bool is_pem_key_cert_pair_list_empty() const;
grpc_ssl_certificate_config_reload_status status() const;
grpc::string error_details() const;
/** Setters for member fields. They modify the fields of the underlying C arg.
* The setters for the key_materials_config and the error_details allocate
* memory when modifying c_arg_, so one must remember to free c_arg_'s
* original key_materials_config or error_details after using the appropriate
* setter function.
* **/
void set_cb_user_data(void* cb_user_data);
void set_pem_root_certs(const grpc::string& pem_root_certs);
void add_pem_key_cert_pair(
TlsKeyMaterialsConfig::PemKeyCertPair pem_key_cert_pair);
void set_key_materials_config(
const std::shared_ptr<TlsKeyMaterialsConfig>& key_materials_config);
void set_status(grpc_ssl_certificate_config_reload_status status);
void set_error_details(const grpc::string& error_details);
/** Calls the C arg's callback function. **/
void OnCredentialReloadDoneCallback();
private:
grpc_tls_credential_reload_arg* c_arg_;
};
/** An interface that the application derives and uses to instantiate a
* TlsCredentialReloadConfig instance. Refer to the definition of the
* grpc_tls_credential_reload_config in grpc_tls_credentials_options.h for more
* details on the expectations of the member functions of the interface. **/
struct TlsCredentialReloadInterface {
virtual ~TlsCredentialReloadInterface() = default;
/** A callback that invokes the credential reload. **/
virtual int Schedule(TlsCredentialReloadArg* arg) = 0;
/** A callback that cancels a credential reload request. **/
virtual void Cancel(TlsCredentialReloadArg* arg) {}
};
/** TLS credential reloag config, wraps grpc_tls_credential_reload_config. It is
* used for experimental purposes for now and it is subject to change. **/
class TlsCredentialReloadConfig {
public:
TlsCredentialReloadConfig(std::shared_ptr<TlsCredentialReloadInterface>
credential_reload_interface);
~TlsCredentialReloadConfig();
int Schedule(TlsCredentialReloadArg* arg) const {
if (credential_reload_interface_ == nullptr) {
gpr_log(GPR_ERROR, "credential reload interface is nullptr");
if (arg != nullptr) {
arg->set_status(GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL);
arg->set_error_details(
"the interface of the credential reload config is nullptr");
}
return 1;
}
return credential_reload_interface_->Schedule(arg);
}
void Cancel(TlsCredentialReloadArg* arg) const {
if (credential_reload_interface_ == nullptr) {
gpr_log(GPR_ERROR, "credential reload interface is nullptr");
if (arg != nullptr) {
arg->set_status(GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL);
arg->set_error_details(
"the interface of the credential reload config is nullptr");
}
return;
}
credential_reload_interface_->Cancel(arg);
}
/** Returns a C struct for the credential reload config. **/
grpc_tls_credential_reload_config* c_config() const { return c_config_; }
private:
grpc_tls_credential_reload_config* c_config_;
std::shared_ptr<TlsCredentialReloadInterface> credential_reload_interface_;
};
/** TLS server authorization check arguments, wraps
* grpc_tls_server_authorization_check_arg. It is used for experimental
* purposes for now and it is subject to change.
*
* The server authorization check arg contains all the info necessary to
* schedule/cancel a server authorization check request. The callback function
* must be called after finishing the schedule operation. See the description
* of the grpc_tls_server_authorization_check_arg struct in grpc_security.h for
* more details. **/
class TlsServerAuthorizationCheckArg {
public:
/** TlsServerAuthorizationCheckArg does not take ownership of the C arg passed
* to the constructor. One must remember to free any memory allocated to the
* C arg after using the setter functions below. **/
TlsServerAuthorizationCheckArg(grpc_tls_server_authorization_check_arg* arg);
~TlsServerAuthorizationCheckArg();
/** Getters for member fields. They return the corresponding fields of the
* underlying C arg.**/
void* cb_user_data() const;
int success() const;
grpc::string target_name() const;
grpc::string peer_cert() const;
grpc_status_code status() const;
grpc::string error_details() const;
/** Setters for member fields. They modify the fields of the underlying C arg.
* The setters for target_name, peer_cert, and error_details allocate memory
* when modifying c_arg_, so one must remember to free c_arg_'s original
* target_name, peer_cert, or error_details after using the appropriate setter
* function.
* **/
void set_cb_user_data(void* cb_user_data);
void set_success(int success);
void set_target_name(const grpc::string& target_name);
void set_peer_cert(const grpc::string& peer_cert);
void set_status(grpc_status_code status);
void set_error_details(const grpc::string& error_details);
/** Calls the C arg's callback function. **/
void OnServerAuthorizationCheckDoneCallback();
private:
grpc_tls_server_authorization_check_arg* c_arg_;
};
/** An interface that the application derives and uses to instantiate a
* TlsServerAuthorizationCheckConfig instance. Refer to the definition of the
* grpc_tls_server_authorization_check_config in grpc_tls_credentials_options.h
* for more details on the expectations of the member functions of the
* interface.
* **/
struct TlsServerAuthorizationCheckInterface {
virtual ~TlsServerAuthorizationCheckInterface() = default;
/** A callback that invokes the server authorization check. **/
virtual int Schedule(TlsServerAuthorizationCheckArg* arg) = 0;
/** A callback that cancels a server authorization check request. **/
virtual void Cancel(TlsServerAuthorizationCheckArg* arg) {}
};
/** TLS server authorization check config, wraps
* grps_tls_server_authorization_check_config. It is used for experimental
* purposes for now and it is subject to change. **/
class TlsServerAuthorizationCheckConfig {
public:
TlsServerAuthorizationCheckConfig(
std::shared_ptr<TlsServerAuthorizationCheckInterface>
server_authorization_check_interface);
~TlsServerAuthorizationCheckConfig();
int Schedule(TlsServerAuthorizationCheckArg* arg) const {
if (server_authorization_check_interface_ == nullptr) {
gpr_log(GPR_ERROR, "server authorization check interface is nullptr");
if (arg != nullptr) {
arg->set_status(GRPC_STATUS_NOT_FOUND);
arg->set_error_details(
"the interface of the server authorization check config is "
"nullptr");
}
return 1;
}
return server_authorization_check_interface_->Schedule(arg);
}
void Cancel(TlsServerAuthorizationCheckArg* arg) const {
if (server_authorization_check_interface_ == nullptr) {
gpr_log(GPR_ERROR, "server authorization check interface is nullptr");
if (arg != nullptr) {
arg->set_status(GRPC_STATUS_NOT_FOUND);
arg->set_error_details(
"the interface of the server authorization check config is "
"nullptr");
}
return;
}
server_authorization_check_interface_->Cancel(arg);
}
/** Returns C struct for the server authorization check config. **/
grpc_tls_server_authorization_check_config* c_config() const {
return c_config_;
}
private:
grpc_tls_server_authorization_check_config* c_config_;
std::shared_ptr<TlsServerAuthorizationCheckInterface>
server_authorization_check_interface_;
};
/** TLS credentials options, wrapper for grpc_tls_credentials_options. It is
* used for experimental purposes for now and it is subject to change. See the
* description of the grpc_tls_credentials_options struct in grpc_security.h for
* more details. **/
class TlsCredentialsOptions {
public:
TlsCredentialsOptions(
grpc_ssl_client_certificate_request_type cert_request_type,
std::shared_ptr<TlsKeyMaterialsConfig> key_materials_config,
std::shared_ptr<TlsCredentialReloadConfig> credential_reload_config,
std::shared_ptr<TlsServerAuthorizationCheckConfig>
server_authorization_check_config);
~TlsCredentialsOptions();
/** Getters for member fields. **/
grpc_ssl_client_certificate_request_type cert_request_type() const {
return cert_request_type_;
}
std::shared_ptr<TlsKeyMaterialsConfig> key_materials_config() const {
return key_materials_config_;
}
std::shared_ptr<TlsCredentialReloadConfig> credential_reload_config() const {
return credential_reload_config_;
}
std::shared_ptr<TlsServerAuthorizationCheckConfig>
server_authorization_check_config() const {
return server_authorization_check_config_;
}
grpc_tls_credentials_options* c_credentials_options() const {
return c_credentials_options_;
}
private:
/** The cert_request_type_ flag is only relevant when the
* TlsCredentialsOptions are used to instantiate server credentials; the flag
* goes unused when creating channel credentials, and the user can set it to
* GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE. **/
grpc_ssl_client_certificate_request_type cert_request_type_;
std::shared_ptr<TlsKeyMaterialsConfig> key_materials_config_;
std::shared_ptr<TlsCredentialReloadConfig> credential_reload_config_;
std::shared_ptr<TlsServerAuthorizationCheckConfig>
server_authorization_check_config_;
grpc_tls_credentials_options* c_credentials_options_;
};
} // namespace experimental
} // namespace grpc_impl
#endif // GRPCPP_SECURITY_TLS_CREDENTIALS_OPTIONS_H

@ -491,6 +491,7 @@
<file baseinstalldir="/" name="src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_bootstrap.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_channel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_channel_args.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_client.h" role="src" />
@ -853,6 +854,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_api.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_bootstrap.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_channel_secure.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_client.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/xds/xds_client_stats.cc" role="src" />

@ -76,17 +76,13 @@ constexpr char kXds[] = "xds_experimental";
class ParsedXdsConfig : public LoadBalancingPolicy::Config {
public:
ParsedXdsConfig(const char* balancer_name,
RefCountedPtr<LoadBalancingPolicy::Config> child_policy,
ParsedXdsConfig(RefCountedPtr<LoadBalancingPolicy::Config> child_policy,
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy)
: balancer_name_(balancer_name),
child_policy_(std::move(child_policy)),
: child_policy_(std::move(child_policy)),
fallback_policy_(std::move(fallback_policy)) {}
const char* name() const override { return kXds; }
const char* balancer_name() const { return balancer_name_; };
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
return child_policy_;
}
@ -96,7 +92,6 @@ class ParsedXdsConfig : public LoadBalancingPolicy::Config {
}
private:
const char* balancer_name_ = nullptr;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy_;
};
@ -373,12 +368,6 @@ class XdsLb : public LoadBalancingPolicy {
void ShutdownLocked() override;
// Parses the xds config given the JSON node of the first child of XdsConfig.
// If parsing succeeds, updates \a balancer_name, and updates \a
// child_policy_config_ and \a fallback_policy_config_ if they are also
// found. Does nothing upon failure.
void ParseLbConfig(const ParsedXdsConfig* xds_config);
// Methods for dealing with fallback state.
void MaybeCancelFallbackAtStartupChecks();
static void OnFallbackTimer(void* arg, grpc_error* error);
@ -391,9 +380,6 @@ class XdsLb : public LoadBalancingPolicy {
// Name of the backend server to connect to.
const char* server_name_ = nullptr;
// Name of the balancer to connect to.
UniquePtr<char> balancer_name_;
// Current channel args from the resolver.
const grpc_channel_args* args_ = nullptr;
@ -715,29 +701,14 @@ void XdsLb::ShutdownLocked() {
}
fallback_policy_.reset();
pending_fallback_policy_.reset();
xds_client_.reset();
// TODO(roth): When we instantiate the XdsClient in the resolver
// instead of here, re-enable the code below. Right now, we need to NOT
// cancel the watches, since the watchers are holding refs to this LB
// policy, and it causes polling-related crashes when this LB policy's
// pollset_set goes away before the one in the XdsClient object. However,
// once the resolver becomes the owner of the XdsClient object, it will be
// using the pollset_set of the resolver, and the resolver will be kept
// alive until after the XdsClient is destroyed via the ServiceConfigWatcher.
// At that point, we will not need to prevent this LB policy from being
// destroyed before the XdsClient, but we WILL need to drop these refs so
// that the LB policy will be destroyed if the XdsClient object is not being
// destroyed at the same time (e.g., if this LB policy is going away
// due to an RDS update that changed the clusters we're using).
#if 0
// Cancel the endpoint watch here instead of in our dtor, because the
// watcher holds a ref to us.
if (xds_client_ != nullptr) {
xds_client_->CancelEndpointDataWatch(StringView(server_name_),
endpoint_watcher_);
xds_client_->RemoveClientStats(StringView(server_name_), &client_stats_);
xds_client_.reset();
}
#endif
}
//
@ -758,24 +729,12 @@ void XdsLb::ResetBackoffLocked() {
}
}
void XdsLb::ParseLbConfig(const ParsedXdsConfig* xds_config) {
if (xds_config == nullptr || xds_config->balancer_name() == nullptr) return;
// TODO(yashykt) : does this need to be a gpr_strdup
// TODO(juanlishen): Read balancer name from bootstrap file.
balancer_name_ = UniquePtr<char>(gpr_strdup(xds_config->balancer_name()));
child_policy_config_ = xds_config->child_policy();
fallback_policy_config_ = xds_config->fallback_policy();
}
void XdsLb::UpdateLocked(UpdateArgs args) {
const bool is_initial_update = xds_client_ == nullptr;
ParseLbConfig(static_cast<const ParsedXdsConfig*>(args.config.get()));
// TODO(roth): This check should go away once we are getting the xds
// server from the bootstrap file.
if (balancer_name_ == nullptr) {
gpr_log(GPR_ERROR, "[xdslb %p] LB config parsing fails.", this);
return;
}
// Update config.
auto* xds_config = static_cast<const ParsedXdsConfig*>(args.config.get());
child_policy_config_ = xds_config->child_policy();
fallback_policy_config_ = xds_config->fallback_policy();
// Update fallback address list.
fallback_backend_addresses_ = std::move(args.addresses);
// Update args.
@ -784,9 +743,17 @@ void XdsLb::UpdateLocked(UpdateArgs args) {
args.args = nullptr;
// Create an xds client if we don't have one yet.
if (xds_client_ == nullptr) {
grpc_error* error = GRPC_ERROR_NONE;
xds_client_ = MakeOrphanable<XdsClient>(
combiner(), interested_parties(), balancer_name_.get(),
StringView(server_name_), nullptr /* service config watcher */, *args_);
combiner(), interested_parties(), StringView(server_name_),
nullptr /* service config watcher */, *args_, &error);
// TODO(roth): When we move instantiation of the XdsClient into the
// xds resolver, add proper error handling there.
GPR_ASSERT(error == GRPC_ERROR_NONE);
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] Created xds client %p", this,
xds_client_.get());
}
endpoint_watcher_ = New<EndpointWatcher>(Ref());
xds_client_->WatchEndpointData(
StringView(server_name_),
@ -815,10 +782,9 @@ void XdsLb::UpdateLocked(UpdateArgs args) {
void XdsLb::MaybeCancelFallbackAtStartupChecks() {
if (!fallback_at_startup_checks_pending_) return;
gpr_log(GPR_INFO,
"[xdslb %p] Cancelling fallback timer and LB channel connectivity "
"watch",
this);
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] Cancelling fallback timer", this);
}
grpc_timer_cancel(&lb_fallback_timer_);
fallback_at_startup_checks_pending_ = false;
}
@ -837,12 +803,10 @@ void XdsLb::OnFallbackTimerLocked(void* arg, grpc_error* error) {
// this callback actually runs, don't fall back.
if (xdslb_policy->fallback_at_startup_checks_pending_ &&
!xdslb_policy->shutting_down_ && error == GRPC_ERROR_NONE) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO,
"[xdslb %p] Child policy not ready after fallback timeout; "
"entering fallback mode",
xdslb_policy);
}
gpr_log(GPR_INFO,
"[xdslb %p] Child policy not ready after fallback timeout; "
"entering fallback mode",
xdslb_policy);
xdslb_policy->fallback_at_startup_checks_pending_ = false;
xdslb_policy->UpdateFallbackPolicyLocked();
}
@ -1476,14 +1440,14 @@ XdsLb::PriorityList::LocalityMap::Locality::CreateChildPolicyLocked(
if (GPR_UNLIKELY(lb_policy == nullptr)) {
gpr_log(GPR_ERROR,
"[xdslb %p] Locality %p %s: failure creating child policy %s",
locality_map_.get(), this, name_->AsHumanReadableString(), name);
xds_policy(), this, name_->AsHumanReadableString(), name);
return nullptr;
}
helper->set_child(lb_policy.get());
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO,
"[xdslb %p] Locality %p %s: Created new child policy %s (%p)",
locality_map_.get(), this, name_->AsHumanReadableString(), name,
xds_policy(), this, name_->AsHumanReadableString(), name,
lb_policy.get());
}
// Add the xDS's interested_parties pollset_set to that of the newly created
@ -1581,7 +1545,7 @@ void XdsLb::PriorityList::LocalityMap::Locality::UpdateLocked(
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO,
"[xdslb %p] Locality %p %s: Creating new %schild policy %s",
locality_map_.get(), this, name_->AsHumanReadableString(),
xds_policy(), this, name_->AsHumanReadableString(),
child_policy_ == nullptr ? "" : "pending ", child_policy_name);
}
auto& lb_policy =
@ -1600,7 +1564,7 @@ void XdsLb::PriorityList::LocalityMap::Locality::UpdateLocked(
// Update the policy.
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] Locality %p %s: Updating %schild policy %p",
locality_map_.get(), this, name_->AsHumanReadableString(),
xds_policy(), this, name_->AsHumanReadableString(),
policy_to_update == pending_child_policy_.get() ? "pending " : "",
policy_to_update);
}
@ -1610,7 +1574,7 @@ void XdsLb::PriorityList::LocalityMap::Locality::UpdateLocked(
void XdsLb::PriorityList::LocalityMap::Locality::ShutdownLocked() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] Locality %p %s: shutting down locality",
locality_map_.get(), this, name_->AsHumanReadableString());
xds_policy(), this, name_->AsHumanReadableString());
}
// Remove the child policy's interested_parties pollset_set from the
// xDS policy.
@ -1769,32 +1733,18 @@ class XdsFactory : public LoadBalancingPolicyFactory {
// xds was mentioned as a policy in the deprecated loadBalancingPolicy
// field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:loadBalancingPolicy error:Xds Parser has required field - "
"balancerName. Please use loadBalancingConfig field of service "
"config instead.");
"field:loadBalancingPolicy error:xds policy requires configuration. "
"Please use loadBalancingConfig field of service config instead.");
return nullptr;
}
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
InlinedVector<grpc_error*, 3> error_list;
const char* balancer_name = nullptr;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy;
for (const grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) continue;
if (strcmp(field->key, "balancerName") == 0) {
if (balancer_name != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:balancerName error:Duplicate entry"));
}
if (field->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:balancerName error:type should be string"));
continue;
}
balancer_name = field->value;
} else if (strcmp(field->key, "childPolicy") == 0) {
if (strcmp(field->key, "childPolicy") == 0) {
if (child_policy != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:childPolicy error:Duplicate entry"));
@ -1822,7 +1772,7 @@ class XdsFactory : public LoadBalancingPolicyFactory {
}
if (error_list.empty()) {
return RefCountedPtr<LoadBalancingPolicy::Config>(New<ParsedXdsConfig>(
balancer_name, std::move(child_policy), std::move(fallback_policy)));
std::move(child_policy), std::move(fallback_policy)));
} else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Xds Parser", &error_list);
return nullptr;

@ -292,7 +292,7 @@ class Subchannel {
bool empty() const { return watchers_.empty(); }
private:
// TODO(roth): Once we can use C++-14 heterogenous lookups, this can
// TODO(roth): Once we can use C++-14 heterogeneous lookups, this can
// be a set instead of a map.
Map<ConnectivityStateWatcherInterface*,
OrphanablePtr<ConnectivityStateWatcherInterface>>

@ -49,7 +49,6 @@ namespace {
constexpr char kEdsTypeUrl[] =
"type.googleapis.com/envoy.api.v2.ClusterLoadAssignment";
constexpr char kEndpointRequired[] = "endpointRequired";
} // namespace
@ -68,8 +67,7 @@ void XdsPriorityListUpdate::Add(
XdsPriorityListUpdate::LocalityMap::Locality locality) {
// Pad the missing priorities in case the localities are not ordered by
// priority.
// TODO(juanlishen): Implement InlinedVector::resize() and use that instead.
while (!Contains(locality.priority)) priorities_.emplace_back();
if (!Contains(locality.priority)) priorities_.resize(locality.priority + 1);
LocalityMap& locality_map = priorities_[locality.priority];
locality_map.localities.emplace(locality.name, std::move(locality));
}
@ -102,22 +100,113 @@ bool XdsDropConfig::ShouldDrop(const UniquePtr<char>** category_name) const {
return false;
}
grpc_slice XdsEdsRequestCreateAndEncode(const char* server_name) {
namespace {
void PopulateMetadataValue(upb_arena* arena, google_protobuf_Value* value_pb,
const XdsBootstrap::MetadataValue& value);
void PopulateListValue(upb_arena* arena, google_protobuf_ListValue* list_value,
const std::vector<XdsBootstrap::MetadataValue>& values) {
for (const auto& value : values) {
auto* value_pb = google_protobuf_ListValue_add_values(list_value, arena);
PopulateMetadataValue(arena, value_pb, value);
}
}
void PopulateMetadata(
upb_arena* arena, google_protobuf_Struct* metadata_pb,
const Map<const char*, XdsBootstrap::MetadataValue, StringLess>& metadata) {
for (const auto& p : metadata) {
google_protobuf_Struct_FieldsEntry* field =
google_protobuf_Struct_add_fields(metadata_pb, arena);
google_protobuf_Struct_FieldsEntry_set_key(field,
upb_strview_makez(p.first));
google_protobuf_Value* value =
google_protobuf_Struct_FieldsEntry_mutable_value(field, arena);
PopulateMetadataValue(arena, value, p.second);
}
}
void PopulateMetadataValue(upb_arena* arena, google_protobuf_Value* value_pb,
const XdsBootstrap::MetadataValue& value) {
switch (value.type) {
case XdsBootstrap::MetadataValue::Type::MD_NULL:
google_protobuf_Value_set_null_value(value_pb, 0);
break;
case XdsBootstrap::MetadataValue::Type::DOUBLE:
google_protobuf_Value_set_number_value(value_pb, value.double_value);
break;
case XdsBootstrap::MetadataValue::Type::STRING:
google_protobuf_Value_set_string_value(
value_pb, upb_strview_makez(value.string_value));
break;
case XdsBootstrap::MetadataValue::Type::BOOL:
google_protobuf_Value_set_bool_value(value_pb, value.bool_value);
break;
case XdsBootstrap::MetadataValue::Type::STRUCT: {
google_protobuf_Struct* struct_value =
google_protobuf_Value_mutable_struct_value(value_pb, arena);
PopulateMetadata(arena, struct_value, value.struct_value);
break;
}
case XdsBootstrap::MetadataValue::Type::LIST: {
google_protobuf_ListValue* list_value =
google_protobuf_Value_mutable_list_value(value_pb, arena);
PopulateListValue(arena, list_value, value.list_value);
break;
}
}
}
void PopulateNode(upb_arena* arena, const XdsBootstrap::Node* node,
const char* build_version, envoy_api_v2_core_Node* node_msg) {
if (node != nullptr) {
if (node->id != nullptr) {
envoy_api_v2_core_Node_set_id(node_msg, upb_strview_makez(node->id));
}
if (node->cluster != nullptr) {
envoy_api_v2_core_Node_set_cluster(node_msg,
upb_strview_makez(node->cluster));
}
if (!node->metadata.empty()) {
google_protobuf_Struct* metadata =
envoy_api_v2_core_Node_mutable_metadata(node_msg, arena);
PopulateMetadata(arena, metadata, node->metadata);
}
if (node->locality_region != nullptr || node->locality_zone != nullptr ||
node->locality_subzone != nullptr) {
envoy_api_v2_core_Locality* locality =
envoy_api_v2_core_Node_mutable_locality(node_msg, arena);
if (node->locality_region != nullptr) {
envoy_api_v2_core_Locality_set_region(
locality, upb_strview_makez(node->locality_region));
}
if (node->locality_zone != nullptr) {
envoy_api_v2_core_Locality_set_zone(
locality, upb_strview_makez(node->locality_zone));
}
if (node->locality_subzone != nullptr) {
envoy_api_v2_core_Locality_set_sub_zone(
locality, upb_strview_makez(node->locality_subzone));
}
}
}
envoy_api_v2_core_Node_set_build_version(node_msg,
upb_strview_makez(build_version));
}
} // namespace
grpc_slice XdsEdsRequestCreateAndEncode(const char* server_name,
const XdsBootstrap::Node* node,
const char* build_version) {
upb::Arena arena;
// Create a request.
envoy_api_v2_DiscoveryRequest* request =
envoy_api_v2_DiscoveryRequest_new(arena.ptr());
envoy_api_v2_core_Node* node =
envoy_api_v2_core_Node* node_msg =
envoy_api_v2_DiscoveryRequest_mutable_node(request, arena.ptr());
google_protobuf_Struct* metadata =
envoy_api_v2_core_Node_mutable_metadata(node, arena.ptr());
google_protobuf_Struct_FieldsEntry* field =
google_protobuf_Struct_add_fields(metadata, arena.ptr());
google_protobuf_Struct_FieldsEntry_set_key(
field, upb_strview_makez(kEndpointRequired));
google_protobuf_Value* value =
google_protobuf_Struct_FieldsEntry_mutable_value(field, arena.ptr());
google_protobuf_Value_set_bool_value(value, true);
PopulateNode(arena.ptr(), node, build_version, node_msg);
envoy_api_v2_DiscoveryRequest_add_resource_names(
request, upb_strview_makez(server_name), arena.ptr());
envoy_api_v2_DiscoveryRequest_set_type_url(request,
@ -327,11 +416,18 @@ grpc_slice LrsRequestEncode(
} // namespace
grpc_slice XdsLrsRequestCreateAndEncode(const char* server_name) {
grpc_slice XdsLrsRequestCreateAndEncode(const char* server_name,
const XdsBootstrap::Node* node,
const char* build_version) {
upb::Arena arena;
// Create a request.
envoy_service_load_stats_v2_LoadStatsRequest* request =
envoy_service_load_stats_v2_LoadStatsRequest_new(arena.ptr());
// Populate node.
envoy_api_v2_core_Node* node_msg =
envoy_service_load_stats_v2_LoadStatsRequest_mutable_node(request,
arena.ptr());
PopulateNode(arena.ptr(), node, build_version, node_msg);
// Add cluster stats. There is only one because we only use one server name in
// one channel.
envoy_api_v2_endpoint_ClusterStats* cluster_stats =

@ -26,6 +26,7 @@
#include <grpc/slice_buffer.h>
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/ext/filters/client_channel/xds/xds_bootstrap.h"
#include "src/core/ext/filters/client_channel/xds/xds_client_stats.h"
namespace grpc_core {
@ -139,7 +140,9 @@ struct EdsUpdate {
struct CdsUpdate {};
// Creates an EDS request querying \a service_name.
grpc_slice XdsEdsRequestCreateAndEncode(const char* server_name);
grpc_slice XdsEdsRequestCreateAndEncode(const char* server_name,
const XdsBootstrap::Node* node,
const char* build_version);
// Parses the EDS response and returns the args to update locality map. If there
// is any error, the output update is invalid.
@ -147,7 +150,9 @@ grpc_error* XdsEdsResponseDecodeAndParse(const grpc_slice& encoded_response,
EdsUpdate* update);
// Creates an LRS request querying \a server_name.
grpc_slice XdsLrsRequestCreateAndEncode(const char* server_name);
grpc_slice XdsLrsRequestCreateAndEncode(const char* server_name,
const XdsBootstrap::Node* node,
const char* build_version);
// Creates an LRS request sending client-side load reports. If all the counters
// in \a client_stats are zero, returns empty slice.

@ -0,0 +1,452 @@
//
// Copyright 2019 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/xds/xds_bootstrap.h"
#include <errno.h>
#include <stdlib.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/slice/slice_internal.h"
namespace grpc_core {
UniquePtr<XdsBootstrap> XdsBootstrap::ReadFromFile(grpc_error** error) {
UniquePtr<char> path(gpr_getenv("GRPC_XDS_BOOTSTRAP"));
if (path == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"GRPC_XDS_BOOTSTRAP env var not set");
return nullptr;
}
grpc_slice contents;
*error = grpc_load_file(path.get(), /*add_null_terminator=*/true, &contents);
if (*error != GRPC_ERROR_NONE) return nullptr;
return MakeUnique<XdsBootstrap>(contents, error);
}
XdsBootstrap::XdsBootstrap(grpc_slice contents, grpc_error** error)
: contents_(contents) {
tree_ = grpc_json_parse_string_with_len(
reinterpret_cast<char*>(GPR_SLICE_START_PTR(contents_)),
GPR_SLICE_LENGTH(contents_));
if (tree_ == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"failed to parse bootstrap file JSON");
return;
}
if (tree_->type != GRPC_JSON_OBJECT || tree_->key != nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"malformed JSON in bootstrap file");
return;
}
InlinedVector<grpc_error*, 1> error_list;
bool seen_xds_server = false;
bool seen_node = false;
for (grpc_json* child = tree_->child; child != nullptr; child = child->next) {
if (child->key == nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null"));
} else if (strcmp(child->key, "xds_server") == 0) {
if (child->type != GRPC_JSON_OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"xds_server\" field is not an object"));
}
if (seen_xds_server) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"duplicate \"xds_server\" field"));
}
seen_xds_server = true;
grpc_error* parse_error = ParseXdsServer(child);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
} else if (strcmp(child->key, "node") == 0) {
if (child->type != GRPC_JSON_OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"node\" field is not an object"));
}
if (seen_node) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"node\" field"));
}
seen_node = true;
grpc_error* parse_error = ParseNode(child);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
}
if (!seen_xds_server) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"xds_server\" field not present"));
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing xds bootstrap file",
&error_list);
}
XdsBootstrap::~XdsBootstrap() {
grpc_json_destroy(tree_);
grpc_slice_unref_internal(contents_);
}
grpc_error* XdsBootstrap::ParseXdsServer(grpc_json* json) {
InlinedVector<grpc_error*, 1> error_list;
server_uri_ = nullptr;
bool seen_channel_creds = false;
for (grpc_json* child = json->child; child != nullptr; child = child->next) {
if (child->key == nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null"));
} else if (strcmp(child->key, "server_uri") == 0) {
if (child->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"server_uri\" field is not a string"));
}
if (server_uri_ != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"duplicate \"server_uri\" field"));
}
server_uri_ = child->value;
} else if (strcmp(child->key, "channel_creds") == 0) {
if (child->type != GRPC_JSON_ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"channel_creds\" field is not a array"));
}
if (seen_channel_creds) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"duplicate \"channel_creds\" field"));
}
seen_channel_creds = true;
grpc_error* parse_error = ParseChannelCredsArray(child);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
}
if (server_uri_ == nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"server_uri\" field not present"));
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"xds_server\" object",
&error_list);
}
grpc_error* XdsBootstrap::ParseChannelCredsArray(grpc_json* json) {
InlinedVector<grpc_error*, 1> error_list;
size_t idx = 0;
for (grpc_json *child = json->child; child != nullptr;
child = child->next, ++idx) {
if (child->key != nullptr) {
char* msg;
gpr_asprintf(&msg, "array element %" PRIuPTR " key is not null", idx);
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
}
if (child->type != GRPC_JSON_OBJECT) {
char* msg;
gpr_asprintf(&msg, "array element %" PRIuPTR " is not an object", idx);
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
} else {
grpc_error* parse_error = ParseChannelCreds(child, idx);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"channel_creds\" array",
&error_list);
}
grpc_error* XdsBootstrap::ParseChannelCreds(grpc_json* json, size_t idx) {
InlinedVector<grpc_error*, 1> error_list;
ChannelCreds channel_creds;
for (grpc_json* child = json->child; child != nullptr; child = child->next) {
if (child->key == nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null"));
} else if (strcmp(child->key, "type") == 0) {
if (child->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"type\" field is not a string"));
}
if (channel_creds.type != nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"type\" field"));
}
channel_creds.type = child->value;
} else if (strcmp(child->key, "config") == 0) {
if (child->type != GRPC_JSON_OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"config\" field is not an object"));
}
if (channel_creds.config != nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"config\" field"));
}
channel_creds.config = child;
}
}
if (channel_creds.type != nullptr) channel_creds_.push_back(channel_creds);
// Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
// string is not static in this case.
if (error_list.empty()) return GRPC_ERROR_NONE;
char* msg;
gpr_asprintf(&msg, "errors parsing index %" PRIuPTR, idx);
grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
for (size_t i = 0; i < error_list.size(); ++i) {
error = grpc_error_add_child(error, error_list[i]);
GRPC_ERROR_UNREF(error_list[i]);
}
return error;
}
grpc_error* XdsBootstrap::ParseNode(grpc_json* json) {
InlinedVector<grpc_error*, 1> error_list;
node_ = MakeUnique<Node>();
bool seen_metadata = false;
bool seen_locality = false;
for (grpc_json* child = json->child; child != nullptr; child = child->next) {
if (child->key == nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null"));
} else if (strcmp(child->key, "id") == 0) {
if (child->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"id\" field is not a string"));
}
if (node_->id != nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"id\" field"));
}
node_->id = child->value;
} else if (strcmp(child->key, "cluster") == 0) {
if (child->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"cluster\" field is not a string"));
}
if (node_->cluster != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"duplicate \"cluster\" field"));
}
node_->cluster = child->value;
} else if (strcmp(child->key, "locality") == 0) {
if (child->type != GRPC_JSON_OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"locality\" field is not an object"));
}
if (seen_locality) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"duplicate \"locality\" field"));
}
seen_locality = true;
grpc_error* parse_error = ParseLocality(child);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
} else if (strcmp(child->key, "metadata") == 0) {
if (child->type != GRPC_JSON_OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"metadata\" field is not an object"));
}
if (seen_metadata) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"duplicate \"metadata\" field"));
}
seen_metadata = true;
InlinedVector<grpc_error*, 1> parse_errors =
ParseMetadataStruct(child, &node_->metadata);
if (!parse_errors.empty()) {
grpc_error* parse_error = GRPC_ERROR_CREATE_FROM_VECTOR(
"errors parsing \"metadata\" object", &parse_errors);
error_list.push_back(parse_error);
}
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"node\" object",
&error_list);
}
grpc_error* XdsBootstrap::ParseLocality(grpc_json* json) {
InlinedVector<grpc_error*, 1> error_list;
node_->locality_region = nullptr;
node_->locality_zone = nullptr;
node_->locality_subzone = nullptr;
for (grpc_json* child = json->child; child != nullptr; child = child->next) {
if (child->key == nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null"));
} else if (strcmp(child->key, "region") == 0) {
if (child->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"region\" field is not a string"));
}
if (node_->locality_region != nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"region\" field"));
}
node_->locality_region = child->value;
} else if (strcmp(child->key, "zone") == 0) {
if (child->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"zone\" field is not a string"));
}
if (node_->locality_zone != nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"zone\" field"));
}
node_->locality_zone = child->value;
} else if (strcmp(child->key, "subzone") == 0) {
if (child->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"subzone\" field is not a string"));
}
if (node_->locality_subzone != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"duplicate \"subzone\" field"));
}
node_->locality_subzone = child->value;
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"locality\" object",
&error_list);
}
InlinedVector<grpc_error*, 1> XdsBootstrap::ParseMetadataStruct(
grpc_json* json,
Map<const char*, XdsBootstrap::MetadataValue, StringLess>* result) {
InlinedVector<grpc_error*, 1> error_list;
for (grpc_json* child = json->child; child != nullptr; child = child->next) {
if (child->key == nullptr) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null"));
continue;
}
if (result->find(child->key) != result->end()) {
char* msg;
gpr_asprintf(&msg, "duplicate metadata key \"%s\"", child->key);
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
gpr_free(msg);
}
MetadataValue& value = (*result)[child->key];
grpc_error* parse_error = ParseMetadataValue(child, 0, &value);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
return error_list;
}
InlinedVector<grpc_error*, 1> XdsBootstrap::ParseMetadataList(
grpc_json* json, std::vector<MetadataValue>* result) {
InlinedVector<grpc_error*, 1> error_list;
size_t idx = 0;
for (grpc_json *child = json->child; child != nullptr;
child = child->next, ++idx) {
if (child->key != nullptr) {
char* msg;
gpr_asprintf(&msg, "JSON key is non-null for index %" PRIuPTR, idx);
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
gpr_free(msg);
}
result->emplace_back();
grpc_error* parse_error = ParseMetadataValue(child, idx, &result->back());
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
return error_list;
}
grpc_error* XdsBootstrap::ParseMetadataValue(grpc_json* json, size_t idx,
MetadataValue* result) {
grpc_error* error = GRPC_ERROR_NONE;
auto context_func = [json, idx]() {
char* context;
if (json->key != nullptr) {
gpr_asprintf(&context, "key \"%s\"", json->key);
} else {
gpr_asprintf(&context, "index %" PRIuPTR, idx);
}
return context;
};
switch (json->type) {
case GRPC_JSON_STRING:
result->type = MetadataValue::Type::STRING;
result->string_value = json->value;
break;
case GRPC_JSON_NUMBER:
result->type = MetadataValue::Type::DOUBLE;
errno = 0; // To distinguish error.
result->double_value = strtod(json->value, nullptr);
if (errno != 0) {
char* context = context_func();
char* msg;
gpr_asprintf(&msg, "error parsing numeric value for %s: \"%s\"",
context, json->value);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(context);
gpr_free(msg);
}
break;
case GRPC_JSON_TRUE:
result->type = MetadataValue::Type::BOOL;
result->bool_value = true;
break;
case GRPC_JSON_FALSE:
result->type = MetadataValue::Type::BOOL;
result->bool_value = false;
break;
case GRPC_JSON_NULL:
result->type = MetadataValue::Type::MD_NULL;
break;
case GRPC_JSON_ARRAY: {
result->type = MetadataValue::Type::LIST;
InlinedVector<grpc_error*, 1> error_list =
ParseMetadataList(json, &result->list_value);
if (!error_list.empty()) {
// Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
// string is not static in this case.
char* context = context_func();
char* msg;
gpr_asprintf(&msg, "errors parsing struct for %s", context);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(context);
gpr_free(msg);
for (size_t i = 0; i < error_list.size(); ++i) {
error = grpc_error_add_child(error, error_list[i]);
GRPC_ERROR_UNREF(error_list[i]);
}
}
break;
}
case GRPC_JSON_OBJECT: {
result->type = MetadataValue::Type::STRUCT;
InlinedVector<grpc_error*, 1> error_list =
ParseMetadataStruct(json, &result->struct_value);
if (!error_list.empty()) {
// Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
// string is not static in this case.
char* context = context_func();
char* msg;
gpr_asprintf(&msg, "errors parsing struct for %s", context);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(context);
gpr_free(msg);
for (size_t i = 0; i < error_list.size(); ++i) {
error = grpc_error_add_child(error, error_list[i]);
GRPC_ERROR_UNREF(error_list[i]);
}
}
break;
}
default:
break;
}
return error;
}
} // namespace grpc_core

@ -0,0 +1,99 @@
//
// Copyright 2019 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_XDS_XDS_BOOTSTRAP_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_XDS_XDS_BOOTSTRAP_H
#include <grpc/support/port_platform.h>
#include <vector>
#include <grpc/impl/codegen/slice.h>
#include "src/core/lib/gprpp/inlined_vector.h"
#include "src/core/lib/gprpp/map.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h"
namespace grpc_core {
class XdsBootstrap {
public:
struct MetadataValue {
enum class Type { MD_NULL, DOUBLE, STRING, BOOL, STRUCT, LIST };
Type type = Type::MD_NULL;
// TODO(roth): Once we can use C++17, these can be in a std::variant.
double double_value;
const char* string_value;
bool bool_value;
Map<const char*, MetadataValue, StringLess> struct_value;
std::vector<MetadataValue> list_value;
};
struct Node {
const char* id = nullptr;
const char* cluster = nullptr;
const char* locality_region = nullptr;
const char* locality_zone = nullptr;
const char* locality_subzone = nullptr;
Map<const char*, MetadataValue, StringLess> metadata;
};
struct ChannelCreds {
const char* type = nullptr;
grpc_json* config = nullptr;
};
// If *error is not GRPC_ERROR_NONE after returning, then there was an
// error reading the file.
static UniquePtr<XdsBootstrap> ReadFromFile(grpc_error** error);
// Do not instantiate directly -- use ReadFromFile() above instead.
XdsBootstrap(grpc_slice contents, grpc_error** error);
~XdsBootstrap();
const char* server_uri() const { return server_uri_; }
const InlinedVector<ChannelCreds, 1>& channel_creds() const {
return channel_creds_;
}
const Node* node() const { return node_.get(); }
private:
grpc_error* ParseXdsServer(grpc_json* json);
grpc_error* ParseChannelCredsArray(grpc_json* json);
grpc_error* ParseChannelCreds(grpc_json* json, size_t idx);
grpc_error* ParseNode(grpc_json* json);
grpc_error* ParseLocality(grpc_json* json);
InlinedVector<grpc_error*, 1> ParseMetadataStruct(
grpc_json* json, Map<const char*, MetadataValue, StringLess>* result);
InlinedVector<grpc_error*, 1> ParseMetadataList(
grpc_json* json, std::vector<MetadataValue>* result);
grpc_error* ParseMetadataValue(grpc_json* json, size_t idx,
MetadataValue* result);
grpc_slice contents_;
grpc_json* tree_ = nullptr;
const char* server_uri_ = nullptr;
InlinedVector<ChannelCreds, 1> channel_creds_;
UniquePtr<Node> node_;
};
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_XDS_XDS_BOOTSTRAP_H */

@ -28,9 +28,10 @@ grpc_channel_args* ModifyXdsChannelArgs(grpc_channel_args* args) {
return args;
}
grpc_channel* CreateXdsChannel(const char* target_uri,
grpc_channel* CreateXdsChannel(const XdsBootstrap& bootstrap,
const grpc_channel_args& args) {
return grpc_insecure_channel_create(target_uri, &args, nullptr);
if (!bootstrap.channel_creds().empty()) return nullptr;
return grpc_insecure_channel_create(bootstrap.server_uri(), &args, nullptr);
}
} // namespace grpc_core

@ -23,6 +23,8 @@
#include <grpc/impl/codegen/grpc_types.h>
#include "src/core/ext/filters/client_channel/xds/xds_bootstrap.h"
namespace grpc_core {
/// Makes any necessary modifications to \a args for use in the xds
@ -33,7 +35,7 @@ namespace grpc_core {
/// Caller takes ownership of the returned args.
grpc_channel_args* ModifyXdsChannelArgs(grpc_channel_args* args);
grpc_channel* CreateXdsChannel(const char* target_uri,
grpc_channel* CreateXdsChannel(const XdsBootstrap& bootstrap,
const grpc_channel_args& args);
} // namespace grpc_core

@ -32,6 +32,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
#include "src/core/lib/security/transport/target_authority_table.h"
#include "src/core/lib/slice/slice_internal.h"
@ -62,19 +63,35 @@ grpc_channel_args* ModifyXdsChannelArgs(grpc_channel_args* args) {
return result;
}
grpc_channel* CreateXdsChannel(const char* target_uri,
grpc_channel* CreateXdsChannel(const XdsBootstrap& bootstrap,
const grpc_channel_args& args) {
grpc_channel_credentials* creds =
grpc_channel_credentials_find_in_args(&args);
if (creds == nullptr) {
// Built with security but parent channel is insecure.
return grpc_insecure_channel_create(target_uri, &args, nullptr);
grpc_channel_credentials* creds = nullptr;
RefCountedPtr<grpc_channel_credentials> creds_to_unref;
if (!bootstrap.channel_creds().empty()) {
for (size_t i = 0; i < bootstrap.channel_creds().size(); ++i) {
if (strcmp(bootstrap.channel_creds()[i].type, "google_default") == 0) {
creds = grpc_google_default_credentials_create();
break;
} else if (strcmp(bootstrap.channel_creds()[i].type, "fake") == 0) {
creds = grpc_fake_transport_security_credentials_create();
break;
}
}
if (creds == nullptr) return nullptr;
creds_to_unref.reset(creds);
} else {
creds = grpc_channel_credentials_find_in_args(&args);
if (creds == nullptr) {
// Built with security but parent channel is insecure.
return grpc_insecure_channel_create(bootstrap.server_uri(), &args,
nullptr);
}
}
const char* arg_to_remove = GRPC_ARG_CHANNEL_CREDENTIALS;
grpc_channel_args* new_args =
grpc_channel_args_copy_and_remove(&args, &arg_to_remove, 1);
grpc_channel* channel =
grpc_secure_channel_create(creds, target_uri, new_args, nullptr);
grpc_channel* channel = grpc_secure_channel_create(
creds, bootstrap.server_uri(), new_args, nullptr);
grpc_channel_args_destroy(new_args);
return channel;
}

@ -252,7 +252,7 @@ class XdsClient::ChannelState : public InternallyRefCounted<ChannelState> {
OrphanablePtr<Reporter> reporter_;
};
ChannelState(RefCountedPtr<XdsClient> xds_client, const char* balancer_name,
ChannelState(RefCountedPtr<XdsClient> xds_client,
const grpc_channel_args& args);
~ChannelState();
@ -377,12 +377,11 @@ grpc_channel_args* BuildXdsChannelArgs(const grpc_channel_args& args) {
} // namespace
XdsClient::ChannelState::ChannelState(RefCountedPtr<XdsClient> xds_client,
const char* balancer_name,
const grpc_channel_args& args)
: InternallyRefCounted<ChannelState>(&grpc_xds_client_trace),
xds_client_(std::move(xds_client)) {
grpc_channel_args* new_args = BuildXdsChannelArgs(args);
channel_ = CreateXdsChannel(balancer_name, *new_args);
channel_ = CreateXdsChannel(*xds_client_->bootstrap_, *new_args);
grpc_channel_args_destroy(new_args);
GPR_ASSERT(channel_ != nullptr);
StartConnectivityWatchLocked();
@ -560,8 +559,9 @@ XdsClient::ChannelState::AdsCallState::AdsCallState(
nullptr, GRPC_MILLIS_INF_FUTURE, nullptr);
GPR_ASSERT(call_ != nullptr);
// Init the request payload.
grpc_slice request_payload_slice =
XdsEdsRequestCreateAndEncode(xds_client()->server_name_.get());
grpc_slice request_payload_slice = XdsEdsRequestCreateAndEncode(
xds_client()->server_name_.get(), xds_client()->bootstrap_->node(),
xds_client()->build_version_.get());
send_message_payload_ =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_slice_unref_internal(request_payload_slice);
@ -978,8 +978,9 @@ XdsClient::ChannelState::LrsCallState::LrsCallState(
nullptr, GRPC_MILLIS_INF_FUTURE, nullptr);
GPR_ASSERT(call_ != nullptr);
// Init the request payload.
grpc_slice request_payload_slice =
XdsLrsRequestCreateAndEncode(xds_client()->server_name_.get());
grpc_slice request_payload_slice = XdsLrsRequestCreateAndEncode(
xds_client()->server_name_.get(), xds_client()->bootstrap_->node(),
xds_client()->build_version_.get());
send_message_payload_ =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_slice_unref_internal(request_payload_slice);
@ -1261,17 +1262,40 @@ bool XdsClient::ChannelState::LrsCallState::IsCurrentCallOnChannel() const {
// XdsClient
//
namespace {
UniquePtr<char> GenerateBuildVersionString() {
char* build_version_str;
gpr_asprintf(&build_version_str, "gRPC C-core %s %s", grpc_version_string(),
GPR_PLATFORM_STRING);
return UniquePtr<char>(build_version_str);
}
} // namespace
XdsClient::XdsClient(Combiner* combiner, grpc_pollset_set* interested_parties,
const char* balancer_name, StringView server_name,
StringView server_name,
UniquePtr<ServiceConfigWatcherInterface> watcher,
const grpc_channel_args& channel_args)
: combiner_(GRPC_COMBINER_REF(combiner, "xds_client")),
const grpc_channel_args& channel_args, grpc_error** error)
: build_version_(GenerateBuildVersionString()),
combiner_(GRPC_COMBINER_REF(combiner, "xds_client")),
interested_parties_(interested_parties),
bootstrap_(XdsBootstrap::ReadFromFile(error)),
server_name_(server_name.dup()),
service_config_watcher_(std::move(watcher)),
chand_(MakeOrphanable<ChannelState>(
Ref(DEBUG_LOCATION, "XdsClient+ChannelState"), balancer_name,
channel_args)) {
service_config_watcher_(std::move(watcher)) {
if (*error != GRPC_ERROR_NONE) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
gpr_log(GPR_INFO, "[xds_client %p: failed to read bootstrap file: %s",
this, grpc_error_string(*error));
}
return;
}
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
gpr_log(GPR_INFO, "[xds_client %p: creating channel to %s", this,
bootstrap_->server_uri());
}
chand_ = MakeOrphanable<ChannelState>(
Ref(DEBUG_LOCATION, "XdsClient+ChannelState"), channel_args);
// TODO(roth): Start LDS call.
}

@ -21,6 +21,7 @@
#include "src/core/ext/filters/client_channel/service_config.h"
#include "src/core/ext/filters/client_channel/xds/xds_api.h"
#include "src/core/ext/filters/client_channel/xds/xds_bootstrap.h"
#include "src/core/ext/filters/client_channel/xds/xds_client_stats.h"
#include "src/core/lib/gprpp/map.h"
#include "src/core/lib/gprpp/memory.h"
@ -68,10 +69,12 @@ class XdsClient : public InternallyRefCounted<XdsClient> {
virtual void OnError(grpc_error* error) = 0;
};
// If *error is not GRPC_ERROR_NONE after construction, then there was
// an error initializing the client.
XdsClient(Combiner* combiner, grpc_pollset_set* interested_parties,
const char* balancer_name, StringView server_name,
StringView server_name,
UniquePtr<ServiceConfigWatcherInterface> watcher,
const grpc_channel_args& channel_args);
const grpc_channel_args& channel_args, grpc_error** error);
~XdsClient();
void Orphan() override;
@ -131,9 +134,13 @@ class XdsClient : public InternallyRefCounted<XdsClient> {
static const grpc_arg_pointer_vtable kXdsClientVtable;
UniquePtr<char> build_version_;
Combiner* combiner_;
grpc_pollset_set* interested_parties_;
UniquePtr<XdsBootstrap> bootstrap_;
UniquePtr<char> server_name_;
UniquePtr<ServiceConfigWatcherInterface> service_config_watcher_;

@ -42,6 +42,20 @@
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/timeout_encoding.h"
namespace {
/* (Maybe-cuckoo) hpack encoder hash table implementation.
This hashtable implementation is a subset of a proper cuckoo hash; while we
have fallback cells that a value can be hashed to if the first cell is full,
we do not attempt to iteratively rearrange entries into backup cells to get
things to fit. Instead, if both a cell and the backup cell for a value are
occupied, the older existing entry is evicted.
Note that we can disable backup-cell picking by setting
GRPC_HPACK_ENCODER_USE_CUCKOO_HASH to 0. In that case, we simply evict an
existing entry rather than try to use a backup. Hence, "maybe-cuckoo."
TODO(arjunroy): Add unit tests for hashtable implementation. */
#define GRPC_HPACK_ENCODER_USE_CUCKOO_HASH 1
#define HASH_FRAGMENT_MASK (GRPC_CHTTP2_HPACKC_NUM_VALUES - 1)
#define HASH_FRAGMENT_1(x) ((x)&HASH_FRAGMENT_MASK)
#define HASH_FRAGMENT_2(x) \
@ -51,21 +65,200 @@
#define HASH_FRAGMENT_4(x) \
(((x) >> (GRPC_CHTTP2_HPACKC_NUM_VALUES_BITS * 3)) & HASH_FRAGMENT_MASK)
/* don't consider adding anything bigger than this to the hpack table */
constexpr size_t kMaxDecoderSpaceUsage = 512;
constexpr size_t kDataFrameHeaderSize = 9;
constexpr uint8_t kMaxFilterValue = 255;
/* if the probability of this item being seen again is < 1/x then don't add
it to the table */
#define ONE_ON_ADD_PROBABILITY (GRPC_CHTTP2_HPACKC_NUM_VALUES >> 1)
/* don't consider adding anything bigger than this to the hpack table */
#define MAX_DECODER_SPACE_USAGE 512
#define DATA_FRAME_HEADER_SIZE 9
/* The hpack index we encode over the wire. Meaningful to the hpack encoder and
parser on the remote end as well as HTTP2. *Not* the same as
HpackEncoderSlotHash, which is only meaningful to the hpack encoder
implementation (HpackEncoderSlotHash is used for the hashtable implementation
when mapping from metadata to HpackEncoderIndex. */
typedef uint32_t HpackEncoderIndex;
/* Internal-table bookkeeping (*not* the hpack index). */
typedef uint32_t HpackEncoderSlotHash;
struct SliceRefComparator {
typedef grpc_slice_refcount* Type;
static grpc_slice_refcount* Null() { return nullptr; }
static bool IsNull(const grpc_slice_refcount* sref) {
return sref == nullptr;
}
static bool Equals(const grpc_slice_refcount* s1,
const grpc_slice_refcount* s2) {
return s1 == s2;
}
static void Ref(grpc_slice_refcount* sref) {
GPR_DEBUG_ASSERT(sref != nullptr);
sref->Ref();
}
static void Unref(grpc_slice_refcount* sref) {
GPR_DEBUG_ASSERT(sref != nullptr);
sref->Unref();
}
};
static grpc_slice_refcount terminal_slice_refcount(
grpc_slice_refcount::Type::STATIC);
static const grpc_slice terminal_slice = {
&terminal_slice_refcount, /* refcount */
{{0, nullptr}} /* data.refcounted */
struct MetadataComparator {
typedef grpc_mdelem Type;
static const grpc_mdelem Null() { return {0}; }
static bool IsNull(const grpc_mdelem md) { return md.payload == 0; }
static bool Equals(const grpc_mdelem md1, const grpc_mdelem md2) {
return md1.payload == md2.payload;
}
static void Ref(grpc_mdelem md) {
GPR_DEBUG_ASSERT(md.payload != 0);
GRPC_MDELEM_REF(md);
}
static void Unref(grpc_mdelem md) {
GPR_DEBUG_ASSERT(md.payload != 0);
GRPC_MDELEM_UNREF(md);
}
};
/* Index table management */
template <typename Hashtable>
static HpackEncoderIndex HpackIndex(const Hashtable* hashtable,
HpackEncoderSlotHash hash_index) {
return hashtable[hash_index].index;
}
template <typename ValueType, typename Hashtable>
static const ValueType& GetEntry(const Hashtable* hashtable,
HpackEncoderSlotHash hash_index) {
return hashtable[hash_index].value;
}
template <typename Cmp, typename Hashtable>
static bool TableEmptyAt(const Hashtable* hashtable,
HpackEncoderSlotHash hash_index) {
return Cmp::Equals(hashtable[hash_index].value, Cmp::Null());
}
template <typename Cmp, typename Hashtable, typename ValueType>
static bool Matches(const Hashtable* hashtable, const ValueType& value,
HpackEncoderSlotHash hash_index) {
return Cmp::Equals(value, hashtable[hash_index].value);
}
template <typename Hashtable>
static void UpdateIndex(Hashtable* hashtable, HpackEncoderSlotHash hash_index,
HpackEncoderIndex hpack_index) {
hashtable[hash_index].index = hpack_index;
}
template <typename Hashtable, typename ValueType>
static void SetIndex(Hashtable* hashtable, HpackEncoderSlotHash hash_index,
const ValueType& value, HpackEncoderIndex hpack_index) {
hashtable[hash_index].value = value;
UpdateIndex(hashtable, hash_index, hpack_index);
}
template <typename Cmp, typename Hashtable, typename ValueType>
static bool GetMatchingIndex(Hashtable* hashtable, const ValueType& value,
uint32_t value_hash, HpackEncoderIndex* index) {
const HpackEncoderSlotHash cuckoo_first = HASH_FRAGMENT_2(value_hash);
if (Matches<Cmp>(hashtable, value, cuckoo_first)) {
*index = HpackIndex(hashtable, cuckoo_first);
return true;
}
#if GRPC_HPACK_ENCODER_USE_CUCKOO_HASH
const HpackEncoderSlotHash cuckoo_second = HASH_FRAGMENT_3(value_hash);
if (Matches<Cmp>(hashtable, value, cuckoo_second)) {
*index = HpackIndex(hashtable, cuckoo_second);
return true;
}
#endif
return false;
}
template <typename Cmp, typename Hashtable, typename ValueType>
static ValueType ReplaceOlderIndex(Hashtable* hashtable, const ValueType& value,
HpackEncoderSlotHash hash_index_a,
HpackEncoderSlotHash hash_index_b,
HpackEncoderIndex new_index) {
const HpackEncoderIndex hpack_idx_a = hashtable[hash_index_a].index;
const HpackEncoderIndex hpack_idx_b = hashtable[hash_index_b].index;
const HpackEncoderSlotHash id =
hpack_idx_a < hpack_idx_b ? hash_index_a : hash_index_b;
ValueType old = GetEntry<typename Cmp::Type>(hashtable, id);
SetIndex(hashtable, id, value, new_index);
return old;
}
template <typename Cmp, typename Hashtable, typename ValueType>
static void UpdateAddOrEvict(Hashtable hashtable, const ValueType& value,
uint32_t value_hash, HpackEncoderIndex new_index) {
const HpackEncoderSlotHash cuckoo_first = HASH_FRAGMENT_2(value_hash);
if (Matches<Cmp>(hashtable, value, cuckoo_first)) {
UpdateIndex(hashtable, cuckoo_first, new_index);
return;
}
if (TableEmptyAt<Cmp>(hashtable, cuckoo_first)) {
Cmp::Ref(value);
SetIndex(hashtable, cuckoo_first, value, new_index);
return;
}
#if GRPC_HPACK_ENCODER_USE_CUCKOO_HASH
const HpackEncoderSlotHash cuckoo_second = HASH_FRAGMENT_3(value_hash);
if (Matches<Cmp>(hashtable, value, cuckoo_second)) {
UpdateIndex(hashtable, cuckoo_second, new_index);
return;
}
Cmp::Ref(value);
if (TableEmptyAt<Cmp>(hashtable, cuckoo_second)) {
SetIndex(hashtable, cuckoo_second, value, new_index);
return;
}
Cmp::Unref(ReplaceOlderIndex<Cmp>(hashtable, value, cuckoo_first,
cuckoo_second, new_index));
#else
ValueType old = GetEntry<typename Cmp::Type>(hashtable, cuckoo_first);
SetIndex(hashtable, cuckoo_first, value, new_index);
Cmp::Unref(old);
#endif
}
/* halve all counts because an element reached max */
static void HalveFilter(uint8_t idx, uint32_t* sum, uint8_t* elems) {
*sum = 0;
for (int i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
elems[i] /= 2;
(*sum) += elems[i];
}
}
/* increment a filter count, halve all counts if one element reaches max */
static void IncrementFilter(uint8_t idx, uint32_t* sum, uint8_t* elems) {
elems[idx]++;
if (GPR_LIKELY(elems[idx] < kMaxFilterValue)) {
(*sum)++;
} else {
HalveFilter(idx, sum, elems);
}
}
static uint32_t UpdateHashtablePopularity(
grpc_chttp2_hpack_compressor* hpack_compressor, uint32_t elem_hash) {
const uint32_t popularity_hash = HASH_FRAGMENT_1(elem_hash);
IncrementFilter(popularity_hash, &hpack_compressor->filter_elems_sum,
hpack_compressor->filter_elems);
return popularity_hash;
}
static bool CanAddToHashtable(grpc_chttp2_hpack_compressor* hpack_compressor,
uint32_t popularity_hash) {
const bool can_add =
hpack_compressor->filter_elems[popularity_hash] >=
hpack_compressor->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
return can_add;
}
} /* namespace */
typedef struct {
int is_first_frame;
/* number of bytes in 'output' when we started the frame - used to calculate
@ -73,8 +266,10 @@ typedef struct {
size_t output_length_at_start_of_frame;
/* index (in output) of the header for the current frame */
size_t header_idx;
#ifndef NDEBUG
/* have we seen a regular (non-colon-prefixed) header yet? */
uint8_t seen_regular_header;
#endif
/* output stream id */
uint32_t stream_id;
grpc_slice_buffer* output;
@ -84,7 +279,7 @@ typedef struct {
bool use_true_binary_metadata;
} framer_state;
/* fills p (which is expected to be DATA_FRAME_HEADER_SIZE bytes long)
/* fills p (which is expected to be kDataFrameHeaderSize bytes long)
* with a data frame header */
static void fill_header(uint8_t* p, uint8_t type, uint32_t id, size_t len,
uint8_t flags) {
@ -131,7 +326,7 @@ static void finish_frame(framer_state* st, int is_header_boundary,
static_cast<uint8_t>(
(is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
(is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
st->stats->framing_bytes += DATA_FRAME_HEADER_SIZE;
st->stats->framing_bytes += kDataFrameHeaderSize;
st->is_first_frame = 0;
}
@ -140,7 +335,7 @@ static void finish_frame(framer_state* st, int is_header_boundary,
static void begin_frame(framer_state* st) {
grpc_slice reserved;
reserved.refcount = nullptr;
reserved.data.inlined.length = DATA_FRAME_HEADER_SIZE;
reserved.data.inlined.length = kDataFrameHeaderSize;
st->header_idx = grpc_slice_buffer_add_indexed(st->output, reserved);
st->output_length_at_start_of_frame = st->output->length;
}
@ -156,21 +351,6 @@ static void ensure_space(framer_state* st, size_t need_bytes) {
begin_frame(st);
}
/* increment a filter count, halve all counts if one element reaches max */
static void inc_filter(uint8_t idx, uint32_t* sum, uint8_t* elems) {
elems[idx]++;
if (elems[idx] < 255) {
(*sum)++;
} else {
int i;
*sum = 0;
for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
elems[i] /= 2;
(*sum) += elems[i];
}
}
}
static void add_header_data(framer_state* st, grpc_slice slice) {
size_t len = GRPC_SLICE_LENGTH(slice);
size_t remaining;
@ -228,7 +408,6 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
while (c->table_size + elem_size > c->max_table_size) {
evict_entry(c);
}
// TODO(arjunroy): Are we conflating size in bytes vs. membership?
GPR_ASSERT(c->table_elems < c->max_table_size);
c->table_elem_size[new_index % c->cap_table_elems] =
static_cast<uint16_t>(elem_size);
@ -240,97 +419,37 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
// Add a key to the dynamic table. Both key and value will be added to table at
// the decoder.
static void add_key_with_index(grpc_chttp2_hpack_compressor* c,
grpc_mdelem elem, uint32_t new_index,
uint32_t key_hash) {
if (new_index == 0) {
return;
}
/* Store the key into {entries,indices}_keys */
if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem))) {
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
} else if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_3(key_hash)],
GRPC_MDKEY(elem))) {
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
} else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)].refcount ==
&terminal_slice_refcount) {
c->entries_keys[HASH_FRAGMENT_2(key_hash)] =
grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
} else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)].refcount ==
&terminal_slice_refcount) {
c->entries_keys[HASH_FRAGMENT_3(key_hash)] =
grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
} else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] <
c->indices_keys[HASH_FRAGMENT_3(key_hash)]) {
grpc_slice_unref_internal(c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
c->entries_keys[HASH_FRAGMENT_2(key_hash)] =
grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
} else {
grpc_slice_unref_internal(c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
c->entries_keys[HASH_FRAGMENT_3(key_hash)] =
grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
}
static void AddKeyWithIndex(grpc_chttp2_hpack_compressor* c,
grpc_slice_refcount* key_ref, uint32_t new_index,
uint32_t key_hash) {
UpdateAddOrEvict<SliceRefComparator>(c->key_table.entries, key_ref, key_hash,
new_index);
}
/* add an element to the decoder table */
static void add_elem_with_index(grpc_chttp2_hpack_compressor* c,
grpc_mdelem elem, uint32_t new_index,
uint32_t elem_hash, uint32_t key_hash) {
if (new_index == 0) {
return;
}
static void AddElemWithIndex(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
uint32_t new_index, uint32_t elem_hash,
uint32_t key_hash) {
GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
/* Store this element into {entries,indices}_elem */
if (grpc_mdelem_both_interned_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)],
elem)) {
/* already there: update with new index */
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
} else if (grpc_mdelem_both_interned_eq(
c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem)) {
/* already there (cuckoo): update with new index */
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
} else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) {
/* not there, but a free element: add */
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
} else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) {
/* not there (cuckoo), but a free element: add */
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
} else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
/* not there: replace oldest */
GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
} else {
/* not there: replace oldest */
GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
}
add_key_with_index(c, elem, new_index, key_hash);
UpdateAddOrEvict<MetadataComparator>(c->elem_table.entries, elem, elem_hash,
new_index);
AddKeyWithIndex(c, GRPC_MDKEY(elem).refcount, new_index, key_hash);
}
static void add_elem(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
size_t elem_size, uint32_t elem_hash, uint32_t key_hash) {
uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
add_elem_with_index(c, elem, new_index, elem_hash, key_hash);
if (new_index != 0) {
AddElemWithIndex(c, elem, new_index, elem_hash, key_hash);
}
}
static void add_key(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
size_t elem_size, uint32_t key_hash) {
uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
add_key_with_index(c, elem, new_index, key_hash);
if (new_index != 0) {
AddKeyWithIndex(c, GRPC_MDKEY(elem).refcount, new_index, key_hash);
}
}
static void emit_indexed(grpc_chttp2_hpack_compressor* c, uint32_t elem_index,
@ -516,30 +635,19 @@ static EmitIndexedStatus maybe_emit_indexed(grpc_chttp2_hpack_compressor* c,
->hash()
: reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(elem))
->hash();
inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems);
/* Update filter to see if we can perhaps add this elem. */
const uint32_t popularity_hash = UpdateHashtablePopularity(c, elem_hash);
/* is this elem currently in the decoders table? */
if (grpc_mdelem_both_interned_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)],
elem) &&
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (first cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
st);
return EmitIndexedStatus(elem_hash, true, false);
}
if (grpc_mdelem_both_interned_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)],
elem) &&
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (second cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
st);
HpackEncoderIndex indices_key;
if (GetMatchingIndex<MetadataComparator>(c->elem_table.entries, elem,
elem_hash, &indices_key) &&
indices_key > c->tail_remote_index) {
emit_indexed(c, dynidx(c, indices_key), st);
return EmitIndexedStatus(elem_hash, true, false);
}
const bool can_add = c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
return EmitIndexedStatus(elem_hash, false, can_add);
/* Didn't hit either cuckoo index, so no emit. */
return EmitIndexedStatus(elem_hash, false,
CanAddToHashtable(c, popularity_hash));
}
static void emit_maybe_add(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
@ -557,14 +665,15 @@ static void emit_maybe_add(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
/* encode an mdelem */
static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
framer_state* st) {
const grpc_slice& elem_key = GRPC_MDKEY(elem);
/* User-provided key len validated in grpc_validate_header_key_is_legal(). */
GPR_DEBUG_ASSERT(GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)) > 0);
GPR_DEBUG_ASSERT(GRPC_SLICE_LENGTH(elem_key) > 0);
/* Header ordering: all reserved headers (prefixed with ':') must precede
* regular headers. This can be a debug assert, since:
* 1) User cannot give us ':' headers (grpc_validate_header_key_is_legal()).
* 2) grpc filters/core should be checked during debug builds. */
#ifndef NDEBUG
if (GRPC_SLICE_START_PTR(GRPC_MDKEY(elem))[0] != ':') { /* regular header */
if (GRPC_SLICE_START_PTR(elem_key)[0] != ':') { /* regular header */
st->seen_regular_header = 1;
} else {
GPR_DEBUG_ASSERT(
@ -575,11 +684,8 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
hpack_enc_log(elem);
}
const bool elem_interned = GRPC_MDELEM_IS_INTERNED(elem);
const bool key_interned =
elem_interned || grpc_slice_is_interned(GRPC_MDKEY(elem));
const bool key_interned = elem_interned || grpc_slice_is_interned(elem_key);
/* Key is not interned, emit literals. */
if (!key_interned) {
emit_lithdr_v<EmitLitHdrVType::NO_IDX_V>(c, elem, st);
@ -591,38 +697,24 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
if (ret.emitted) {
return;
}
/* should this elem be in the table? */
const size_t decoder_space_usage =
grpc_chttp2_get_size_in_hpack_table(elem, st->use_true_binary_metadata);
const bool decoder_space_available =
decoder_space_usage < MAX_DECODER_SPACE_USAGE;
decoder_space_usage < kMaxDecoderSpaceUsage;
const bool should_add_elem =
elem_interned && decoder_space_available && ret.can_add;
const uint32_t elem_hash = ret.elem_hash;
/* no hits for the elem... maybe there's a key? */
const uint32_t key_hash = GRPC_MDKEY(elem).refcount->Hash(GRPC_MDKEY(elem));
uint32_t indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem)) &&
const uint32_t key_hash = elem_key.refcount->Hash(elem_key);
HpackEncoderIndex indices_key;
if (GetMatchingIndex<SliceRefComparator>(
c->key_table.entries, elem_key.refcount, key_hash, &indices_key) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
emit_maybe_add(c, elem, st, indices_key, should_add_elem,
decoder_space_usage, elem_hash, key_hash);
return;
}
indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_3(key_hash)], GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (second cuckoo hash) */
emit_maybe_add(c, elem, st, indices_key, should_add_elem,
decoder_space_usage, elem_hash, key_hash);
return;
}
/* no elem, key in the table... fall back to literal emission */
const bool should_add_key = !elem_interned && decoder_space_available;
if (should_add_elem || should_add_key) {
@ -660,22 +752,18 @@ void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor* c) {
c->cap_table_elems = elems_for_bytes(c->max_table_size);
c->max_table_elems = c->cap_table_elems;
c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
c->table_elem_size = static_cast<uint16_t*>(
gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems));
memset(c->table_elem_size, 0,
sizeof(*c->table_elem_size) * c->cap_table_elems);
for (size_t i = 0; i < GPR_ARRAY_SIZE(c->entries_keys); i++) {
c->entries_keys[i] = terminal_slice;
}
const size_t alloc_size = sizeof(*c->table_elem_size) * c->cap_table_elems;
c->table_elem_size = static_cast<uint16_t*>(gpr_malloc(alloc_size));
memset(c->table_elem_size, 0, alloc_size);
}
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor* c) {
int i;
for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
if (c->entries_keys[i].refcount != &terminal_slice_refcount) {
grpc_slice_unref_internal(c->entries_keys[i]);
for (int i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
auto* const key = GetEntry<grpc_slice_refcount*>(c->key_table.entries, i);
if (key != nullptr) {
key->Unref();
}
GRPC_MDELEM_UNREF(c->entries_elems[i]);
GRPC_MDELEM_UNREF(GetEntry<grpc_mdelem>(c->elem_table.entries, i));
}
gpr_free(c->table_elem_size);
}
@ -744,7 +832,9 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor* c,
validates that stream_id is not 0. So, this can be a debug assert. */
GPR_DEBUG_ASSERT(options->stream_id != 0);
framer_state st;
#ifndef NDEBUG
st.seen_regular_header = 0;
#endif
st.stream_id = options->stream_id;
st.output = outbuf;
st.is_first_frame = 1;

@ -38,14 +38,10 @@
extern grpc_core::TraceFlag grpc_http_trace;
typedef struct {
uint32_t filter_elems_sum;
struct grpc_chttp2_hpack_compressor {
uint32_t max_table_size;
uint32_t max_table_elems;
uint32_t cap_table_elems;
/** if non-zero, advertise to the decoder that we'll start using a table
of this size */
uint8_t advertise_table_size_change;
/** maximum number of bytes we'll use for the decode table (to guard against
peers ooming us by setting decode table size high) */
uint32_t max_usable_size;
@ -53,23 +49,39 @@ typedef struct {
uint32_t tail_remote_index;
uint32_t table_size;
uint32_t table_elems;
uint16_t* table_elem_size;
/** if non-zero, advertise to the decoder that we'll start using a table
of this size */
uint8_t advertise_table_size_change;
/* filter tables for elems: this tables provides an approximate
popularity count for particular hashes, and are used to determine whether
a new literal should be added to the compression table or not.
They track a single integer that counts how often a particular value has
been seen. When that count reaches max (255), all values are halved. */
uint32_t filter_elems_sum;
uint8_t filter_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
/* entry tables for keys & elems: these tables track values that have been
seen and *may* be in the decompressor table */
grpc_slice entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
grpc_mdelem entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
uint32_t indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
uint32_t indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
uint16_t* table_elem_size;
} grpc_chttp2_hpack_compressor;
struct {
struct {
grpc_mdelem value;
uint32_t index;
} entries[GRPC_CHTTP2_HPACKC_NUM_VALUES];
} elem_table; /* Metadata table management */
struct {
struct {
/* Only store the slice refcount - we do not need the byte buffer or
length of the slice since we only need to store a mapping between the
identity of the slice and the corresponding HPACK index. Since the
slice *must* be static or interned, the refcount is sufficient to
establish identity. */
grpc_slice_refcount* value;
uint32_t index;
} entries[GRPC_CHTTP2_HPACKC_NUM_VALUES];
} key_table; /* Key table management */
};
void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor* c);
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor* c);

@ -125,6 +125,11 @@ class InlinedVector {
}
}
void resize(size_t new_size) {
while (new_size > size_) emplace_back();
while (new_size < size_) pop_back();
}
template <typename... Args>
void emplace_back(Args&&... args) {
if (size_ == capacity_) {

@ -37,7 +37,7 @@ inline T* New(Args&&... args) {
return new (p) T(std::forward<Args>(args)...);
}
// Gets the base pointer of any class, in case of multiple inheritence.
// Gets the base pointer of any class, in case of multiple inheritance.
// Used by Delete and friends.
template <typename T, bool isPolymorphic>
struct BasePointerGetter {

@ -164,7 +164,6 @@ void Executor::SetThreading(bool threading) {
GPR_ASSERT(num_threads_ == 0);
gpr_atm_rel_store(&num_threads_, 1);
gpr_tls_init(&g_this_thread_state);
thd_state_ = static_cast<ThreadState*>(
gpr_zalloc(sizeof(ThreadState) * max_threads_));
@ -213,7 +212,6 @@ void Executor::SetThreading(bool threading) {
}
gpr_free(thd_state_);
gpr_tls_destroy(&g_this_thread_state);
// grpc_iomgr_shutdown_background_closure() will close all the registered
// fds in the background poller, and wait for all pending closures to
@ -265,14 +263,7 @@ void Executor::ThreadMain(void* arg) {
subtract_depth = RunClosures(ts->name, closures);
}
// We have an issue with Apple platforms where applying gpr_tls_set here
// leads to an EAGAIN error while performing a gpr_tls_get, so we are
// skipping this cleanup for Apple platforms. See PR #19978
// TODO(mhaidry) : Fix this by switching to using thread_local once we have
// support for it in Xcode (PR #20413)or whatever else it takes
#if !defined(__APPLE__)
gpr_tls_set(&g_this_thread_state, reinterpret_cast<intptr_t>(nullptr));
#endif // !__APPLE__
}
void Executor::Enqueue(grpc_closure* closure, grpc_error* error,
@ -494,4 +485,6 @@ void Executor::SetThreadingDefault(bool enable) {
executors[static_cast<size_t>(ExecutorType::DEFAULT)]->SetThreading(enable);
}
void grpc_executor_global_init() { gpr_tls_init(&g_this_thread_state); }
} // namespace grpc_core

@ -117,6 +117,9 @@ class Executor {
gpr_spinlock adding_thread_lock_;
};
// Global initializer for executor
void grpc_executor_global_init();
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_IOMGR_EXECUTOR_H */

@ -67,7 +67,7 @@ grpc_json* grpc_json_parse_string(char* input);
* If indent is 0, then newlines will be suppressed as well, and the
* output will be condensed at its maximum.
*/
char* grpc_json_dump_to_string(grpc_json* json, int indent);
char* grpc_json_dump_to_string(const grpc_json* json, int indent);
/* Use these to create or delete a grpc_json object.
* Deletion is recursive. We will not attempt to free any of the strings

@ -311,7 +311,7 @@ grpc_json* grpc_json_parse_string(char* input) {
return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH);
}
static void json_dump_recursive(grpc_json_writer* writer, grpc_json* json,
static void json_dump_recursive(grpc_json_writer* writer, const grpc_json* json,
int in_object) {
while (json) {
if (in_object) grpc_json_writer_object_key(writer, json->key);
@ -351,7 +351,7 @@ static grpc_json_writer_vtable writer_vtable = {
json_writer_output_char, json_writer_output_string,
json_writer_output_string_with_len};
char* grpc_json_dump_to_string(grpc_json* json, int indent) {
char* grpc_json_dump_to_string(const grpc_json* json, int indent) {
grpc_json_writer writer;
json_writer_userdata state;

@ -42,6 +42,12 @@ struct grpc_tls_key_materials_config
int version() const { return version_; }
/** Setters for member fields. **/
void set_pem_root_certs(grpc_core::UniquePtr<char> pem_root_certs) {
pem_root_certs_ = std::move(pem_root_certs);
}
void add_pem_key_cert_pair(grpc_core::PemKeyCertPair pem_key_cert_pair) {
pem_key_cert_pair_list_.push_back(pem_key_cert_pair);
}
void set_key_materials(grpc_core::UniquePtr<char> pem_root_certs,
PemKeyCertPairList pem_key_cert_pair_list);
void set_version(int version) { version_ = version; }
@ -65,18 +71,46 @@ struct grpc_tls_credential_reload_config
void (*destruct)(void* config_user_data));
~grpc_tls_credential_reload_config();
void* context() const { return context_; }
void set_context(void* context) { context_ = context; }
int Schedule(grpc_tls_credential_reload_arg* arg) const {
if (schedule_ == nullptr) {
gpr_log(GPR_ERROR, "schedule API is nullptr");
if (arg != nullptr) {
arg->status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL;
arg->error_details =
gpr_strdup("schedule API in credential reload config is nullptr");
}
return 1;
}
if (arg != nullptr) {
arg->config = const_cast<grpc_tls_credential_reload_config*>(this);
}
return schedule_(config_user_data_, arg);
}
void Cancel(grpc_tls_credential_reload_arg* arg) const {
if (cancel_ == nullptr) {
gpr_log(GPR_ERROR, "cancel API is nullptr.");
if (arg != nullptr) {
arg->status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL;
arg->error_details =
gpr_strdup("cancel API in credential reload config is nullptr");
}
return;
}
if (arg != nullptr) {
arg->config = const_cast<grpc_tls_credential_reload_config*>(this);
}
cancel_(config_user_data_, arg);
}
private:
/** This is a pointer to the wrapped language implementation of
* grpc_tls_credential_reload_config. It is necessary to implement the C
* schedule and cancel functions, given the schedule or cancel function in a
* wrapped language. **/
void* context_ = nullptr;
/** config-specific, read-only user data that works for all channels created
with a credential using the config. */
void* config_user_data_;
@ -113,18 +147,48 @@ struct grpc_tls_server_authorization_check_config
void (*destruct)(void* config_user_data));
~grpc_tls_server_authorization_check_config();
void* context() const { return context_; }
void set_context(void* context) { context_ = context; }
int Schedule(grpc_tls_server_authorization_check_arg* arg) const {
if (schedule_ == nullptr) {
gpr_log(GPR_ERROR, "schedule API is nullptr");
if (arg != nullptr) {
arg->status = GRPC_STATUS_NOT_FOUND;
arg->error_details = gpr_strdup(
"schedule API in server authorization check config is nullptr");
}
return 1;
}
if (arg != nullptr && context_ != nullptr) {
arg->config =
const_cast<grpc_tls_server_authorization_check_config*>(this);
}
return schedule_(config_user_data_, arg);
}
void Cancel(grpc_tls_server_authorization_check_arg* arg) const {
if (cancel_ == nullptr) {
gpr_log(GPR_ERROR, "cancel API is nullptr.");
if (arg != nullptr) {
arg->status = GRPC_STATUS_NOT_FOUND;
arg->error_details = gpr_strdup(
"schedule API in server authorization check config is nullptr");
}
return;
}
if (arg != nullptr) {
arg->config =
const_cast<grpc_tls_server_authorization_check_config*>(this);
}
cancel_(config_user_data_, arg);
}
private:
/** This is a pointer to the wrapped language implementation of
* grpc_tls_server_authorization_check_config. It is necessary to implement
* the C schedule and cancel functions, given the schedule or cancel function
* in a wrapped language. **/
void* context_ = nullptr;
/** config-specific, read-only user data that works for all channels created
with a Credential using the config. */
void* config_user_data_;

@ -104,6 +104,9 @@ grpc_status_code TlsFetchKeyMaterials(
}
}
gpr_free((void*)arg->error_details);
if (arg->destroy_context != nullptr) {
arg->destroy_context(arg->context);
}
grpc_core::Delete(arg);
}
return status;
@ -393,6 +396,9 @@ void SpiffeChannelSecurityConnector::ServerAuthorizationCheckArgDestroy(
gpr_free((void*)arg->target_name);
gpr_free((void*)arg->peer_cert);
gpr_free((void*)arg->error_details);
if (arg->destroy_context != nullptr) {
arg->destroy_context(arg->context);
}
grpc_core::Delete(arg);
}

@ -73,6 +73,7 @@ static void do_basic_init(void) {
g_shutting_down = false;
grpc_register_built_in_plugins();
grpc_cq_global_init();
grpc_core::grpc_executor_global_init();
gpr_time_init();
g_initializations = 0;
}

@ -117,7 +117,7 @@ class ConnectivityStateTracker {
private:
const char* name_;
Atomic<grpc_connectivity_state> state_;
// TODO(roth): Once we can use C++-14 heterogenous lookups, this can
// TODO(roth): Once we can use C++-14 heterogeneous lookups, this can
// be a set instead of a map.
Map<ConnectivityStateWatcherInterface*,
OrphanablePtr<ConnectivityStateWatcherInterface>>

@ -280,6 +280,13 @@ std::shared_ptr<ChannelCredentials> LocalCredentials(
return WrapChannelCredentials(grpc_local_credentials_create(type));
}
// Builds TLS Credentials given TLS options.
std::shared_ptr<ChannelCredentials> TlsCredentials(
const TlsCredentialsOptions& options) {
return WrapChannelCredentials(
grpc_tls_spiffe_credentials_create(options.c_credentials_options()));
}
} // namespace experimental
// Builds credentials for use when running in GCE

@ -23,6 +23,7 @@
#include <grpcpp/security/credentials.h>
#include <grpcpp/security/credentials_impl.h>
#include <grpcpp/security/tls_credentials_options.h>
#include <grpcpp/support/config.h>
#include "src/core/lib/security/credentials/credentials.h"

@ -0,0 +1,282 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpcpp/security/tls_credentials_options.h>
#include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h"
#include <grpc/support/alloc.h>
#include "src/cpp/common/tls_credentials_options_util.h"
namespace grpc_impl {
namespace experimental {
/** TLS key materials config API implementation **/
void TlsKeyMaterialsConfig::set_pem_root_certs(grpc::string pem_root_certs) {
pem_root_certs_ = std::move(pem_root_certs);
}
void TlsKeyMaterialsConfig::add_pem_key_cert_pair(
const PemKeyCertPair& pem_key_cert_pair) {
pem_key_cert_pair_list_.push_back(pem_key_cert_pair);
}
void TlsKeyMaterialsConfig::set_key_materials(
grpc::string pem_root_certs,
std::vector<PemKeyCertPair> pem_key_cert_pair_list) {
pem_key_cert_pair_list_ = std::move(pem_key_cert_pair_list);
pem_root_certs_ = std::move(pem_root_certs);
}
/** TLS credential reload arg API implementation **/
TlsCredentialReloadArg::TlsCredentialReloadArg(
grpc_tls_credential_reload_arg* arg)
: c_arg_(arg) {
if (c_arg_ != nullptr && c_arg_->context != nullptr) {
gpr_log(GPR_ERROR, "c_arg context has already been set");
}
c_arg_->context = static_cast<void*>(this);
c_arg_->destroy_context = &TlsCredentialReloadArgDestroyContext;
}
TlsCredentialReloadArg::~TlsCredentialReloadArg() {}
void* TlsCredentialReloadArg::cb_user_data() const {
return c_arg_->cb_user_data;
}
bool TlsCredentialReloadArg::is_pem_key_cert_pair_list_empty() const {
return c_arg_->key_materials_config->pem_key_cert_pair_list().empty();
}
grpc_ssl_certificate_config_reload_status TlsCredentialReloadArg::status()
const {
return c_arg_->status;
}
grpc::string TlsCredentialReloadArg::error_details() const {
grpc::string cpp_error_details(c_arg_->error_details);
return cpp_error_details;
}
void TlsCredentialReloadArg::set_cb_user_data(void* cb_user_data) {
c_arg_->cb_user_data = cb_user_data;
}
void TlsCredentialReloadArg::set_pem_root_certs(
const grpc::string& pem_root_certs) {
::grpc_core::UniquePtr<char> c_pem_root_certs(
gpr_strdup(pem_root_certs.c_str()));
c_arg_->key_materials_config->set_pem_root_certs(std::move(c_pem_root_certs));
}
void TlsCredentialReloadArg::add_pem_key_cert_pair(
TlsKeyMaterialsConfig::PemKeyCertPair pem_key_cert_pair) {
grpc_ssl_pem_key_cert_pair* ssl_pair =
(grpc_ssl_pem_key_cert_pair*)gpr_malloc(
sizeof(grpc_ssl_pem_key_cert_pair));
ssl_pair->private_key = gpr_strdup(pem_key_cert_pair.private_key.c_str());
ssl_pair->cert_chain = gpr_strdup(pem_key_cert_pair.cert_chain.c_str());
::grpc_core::PemKeyCertPair c_pem_key_cert_pair =
::grpc_core::PemKeyCertPair(ssl_pair);
c_arg_->key_materials_config->add_pem_key_cert_pair(
std::move(c_pem_key_cert_pair));
}
void TlsCredentialReloadArg::set_key_materials_config(
const std::shared_ptr<TlsKeyMaterialsConfig>& key_materials_config) {
if (key_materials_config == nullptr) {
c_arg_->key_materials_config = nullptr;
return;
}
::grpc_core::InlinedVector<::grpc_core::PemKeyCertPair, 1>
c_pem_key_cert_pair_list;
for (auto key_cert_pair =
key_materials_config->pem_key_cert_pair_list().begin();
key_cert_pair != key_materials_config->pem_key_cert_pair_list().end();
key_cert_pair++) {
grpc_ssl_pem_key_cert_pair* ssl_pair =
(grpc_ssl_pem_key_cert_pair*)gpr_malloc(
sizeof(grpc_ssl_pem_key_cert_pair));
ssl_pair->private_key = gpr_strdup(key_cert_pair->private_key.c_str());
ssl_pair->cert_chain = gpr_strdup(key_cert_pair->cert_chain.c_str());
::grpc_core::PemKeyCertPair c_pem_key_cert_pair =
::grpc_core::PemKeyCertPair(ssl_pair);
c_pem_key_cert_pair_list.emplace_back(std::move(c_pem_key_cert_pair));
}
::grpc_core::UniquePtr<char> c_pem_root_certs(
gpr_strdup(key_materials_config->pem_root_certs().c_str()));
if (c_arg_->key_materials_config == nullptr) {
c_arg_->key_materials_config = grpc_tls_key_materials_config_create();
}
c_arg_->key_materials_config->set_key_materials(
std::move(c_pem_root_certs), std::move(c_pem_key_cert_pair_list));
c_arg_->key_materials_config->set_version(key_materials_config->version());
}
void TlsCredentialReloadArg::set_status(
grpc_ssl_certificate_config_reload_status status) {
c_arg_->status = status;
}
void TlsCredentialReloadArg::set_error_details(
const grpc::string& error_details) {
c_arg_->error_details = gpr_strdup(error_details.c_str());
}
void TlsCredentialReloadArg::OnCredentialReloadDoneCallback() {
if (c_arg_->cb == nullptr) {
gpr_log(GPR_ERROR, "credential reload arg callback API is nullptr");
return;
}
c_arg_->cb(c_arg_);
}
/** gRPC TLS credential reload config API implementation **/
TlsCredentialReloadConfig::TlsCredentialReloadConfig(
std::shared_ptr<TlsCredentialReloadInterface> credential_reload_interface)
: credential_reload_interface_(std::move(credential_reload_interface)) {
c_config_ = grpc_tls_credential_reload_config_create(
nullptr, &TlsCredentialReloadConfigCSchedule,
&TlsCredentialReloadConfigCCancel, nullptr);
c_config_->set_context(static_cast<void*>(this));
}
TlsCredentialReloadConfig::~TlsCredentialReloadConfig() {}
/** gRPC TLS server authorization check arg API implementation **/
TlsServerAuthorizationCheckArg::TlsServerAuthorizationCheckArg(
grpc_tls_server_authorization_check_arg* arg)
: c_arg_(arg) {
if (c_arg_ != nullptr && c_arg_->context != nullptr) {
gpr_log(GPR_ERROR, "c_arg context has already been set");
}
c_arg_->context = static_cast<void*>(this);
c_arg_->destroy_context = &TlsServerAuthorizationCheckArgDestroyContext;
}
TlsServerAuthorizationCheckArg::~TlsServerAuthorizationCheckArg() {}
void* TlsServerAuthorizationCheckArg::cb_user_data() const {
return c_arg_->cb_user_data;
}
int TlsServerAuthorizationCheckArg::success() const { return c_arg_->success; }
grpc::string TlsServerAuthorizationCheckArg::target_name() const {
grpc::string cpp_target_name(c_arg_->target_name);
return cpp_target_name;
}
grpc::string TlsServerAuthorizationCheckArg::peer_cert() const {
grpc::string cpp_peer_cert(c_arg_->peer_cert);
return cpp_peer_cert;
}
grpc_status_code TlsServerAuthorizationCheckArg::status() const {
return c_arg_->status;
}
grpc::string TlsServerAuthorizationCheckArg::error_details() const {
grpc::string cpp_error_details(c_arg_->error_details);
return cpp_error_details;
}
void TlsServerAuthorizationCheckArg::set_cb_user_data(void* cb_user_data) {
c_arg_->cb_user_data = cb_user_data;
}
void TlsServerAuthorizationCheckArg::set_success(int success) {
c_arg_->success = success;
}
void TlsServerAuthorizationCheckArg::set_target_name(
const grpc::string& target_name) {
c_arg_->target_name = gpr_strdup(target_name.c_str());
}
void TlsServerAuthorizationCheckArg::set_peer_cert(
const grpc::string& peer_cert) {
c_arg_->peer_cert = gpr_strdup(peer_cert.c_str());
}
void TlsServerAuthorizationCheckArg::set_status(grpc_status_code status) {
c_arg_->status = status;
}
void TlsServerAuthorizationCheckArg::set_error_details(
const grpc::string& error_details) {
c_arg_->error_details = gpr_strdup(error_details.c_str());
}
void TlsServerAuthorizationCheckArg::OnServerAuthorizationCheckDoneCallback() {
if (c_arg_->cb == nullptr) {
gpr_log(GPR_ERROR, "server authorizaton check arg callback API is nullptr");
return;
}
c_arg_->cb(c_arg_);
}
/** gRPC TLS server authorization check config API implementation. **/
TlsServerAuthorizationCheckConfig::TlsServerAuthorizationCheckConfig(
std::shared_ptr<TlsServerAuthorizationCheckInterface>
server_authorization_check_interface)
: server_authorization_check_interface_(
std::move(server_authorization_check_interface)) {
c_config_ = grpc_tls_server_authorization_check_config_create(
nullptr, &TlsServerAuthorizationCheckConfigCSchedule,
&TlsServerAuthorizationCheckConfigCCancel, nullptr);
c_config_->set_context(static_cast<void*>(this));
}
TlsServerAuthorizationCheckConfig::~TlsServerAuthorizationCheckConfig() {}
/** gRPC TLS credential options API implementation **/
TlsCredentialsOptions::TlsCredentialsOptions(
grpc_ssl_client_certificate_request_type cert_request_type,
std::shared_ptr<TlsKeyMaterialsConfig> key_materials_config,
std::shared_ptr<TlsCredentialReloadConfig> credential_reload_config,
std::shared_ptr<TlsServerAuthorizationCheckConfig>
server_authorization_check_config)
: cert_request_type_(cert_request_type),
key_materials_config_(std::move(key_materials_config)),
credential_reload_config_(std::move(credential_reload_config)),
server_authorization_check_config_(
std::move(server_authorization_check_config)) {
c_credentials_options_ = grpc_tls_credentials_options_create();
grpc_tls_credentials_options_set_cert_request_type(c_credentials_options_,
cert_request_type_);
if (key_materials_config_ != nullptr) {
grpc_tls_credentials_options_set_key_materials_config(
c_credentials_options_,
ConvertToCKeyMaterialsConfig(key_materials_config_));
}
if (credential_reload_config_ != nullptr) {
grpc_tls_credentials_options_set_credential_reload_config(
c_credentials_options_, credential_reload_config_->c_config());
}
if (server_authorization_check_config_ != nullptr) {
grpc_tls_credentials_options_set_server_authorization_check_config(
c_credentials_options_, server_authorization_check_config_->c_config());
}
}
TlsCredentialsOptions::~TlsCredentialsOptions() {}
} // namespace experimental
} // namespace grpc_impl

@ -0,0 +1,150 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "src/cpp/common/tls_credentials_options_util.h"
#include <grpcpp/security/tls_credentials_options.h>
namespace grpc_impl {
namespace experimental {
/** Converts the Cpp key materials to C key materials; this allocates memory for
* the C key materials. Note that the user must free
* the underlying pointer to private key and cert chain duplicates; they are not
* freed when the UniquePtr<char> member variables of PemKeyCertPair are unused.
* Similarly, the user must free the underlying pointer to c_pem_root_certs. **/
grpc_tls_key_materials_config* ConvertToCKeyMaterialsConfig(
const std::shared_ptr<TlsKeyMaterialsConfig>& config) {
if (config == nullptr) {
return nullptr;
}
grpc_tls_key_materials_config* c_config =
grpc_tls_key_materials_config_create();
::grpc_core::InlinedVector<::grpc_core::PemKeyCertPair, 1>
c_pem_key_cert_pair_list;
for (auto key_cert_pair = config->pem_key_cert_pair_list().begin();
key_cert_pair != config->pem_key_cert_pair_list().end();
key_cert_pair++) {
grpc_ssl_pem_key_cert_pair* ssl_pair =
(grpc_ssl_pem_key_cert_pair*)gpr_malloc(
sizeof(grpc_ssl_pem_key_cert_pair));
ssl_pair->private_key = gpr_strdup(key_cert_pair->private_key.c_str());
ssl_pair->cert_chain = gpr_strdup(key_cert_pair->cert_chain.c_str());
::grpc_core::PemKeyCertPair c_pem_key_cert_pair =
::grpc_core::PemKeyCertPair(ssl_pair);
c_pem_key_cert_pair_list.push_back(::std::move(c_pem_key_cert_pair));
}
::grpc_core::UniquePtr<char> c_pem_root_certs(
gpr_strdup(config->pem_root_certs().c_str()));
c_config->set_key_materials(std::move(c_pem_root_certs),
std::move(c_pem_key_cert_pair_list));
c_config->set_version(config->version());
return c_config;
}
/** The C schedule and cancel functions for the credential reload config.
* They populate a C credential reload arg with the result of a C++ credential
* reload schedule/cancel API. **/
int TlsCredentialReloadConfigCSchedule(void* config_user_data,
grpc_tls_credential_reload_arg* arg) {
if (arg == nullptr || arg->config == nullptr ||
arg->config->context() == nullptr) {
gpr_log(GPR_ERROR, "credential reload arg was not properly initialized");
return 1;
}
TlsCredentialReloadConfig* cpp_config =
static_cast<TlsCredentialReloadConfig*>(arg->config->context());
TlsCredentialReloadArg* cpp_arg = new TlsCredentialReloadArg(arg);
int schedule_result = cpp_config->Schedule(cpp_arg);
return schedule_result;
}
void TlsCredentialReloadConfigCCancel(void* config_user_data,
grpc_tls_credential_reload_arg* arg) {
if (arg == nullptr || arg->config == nullptr ||
arg->config->context() == nullptr) {
gpr_log(GPR_ERROR, "credential reload arg was not properly initialized");
return;
}
if (arg->context == nullptr) {
gpr_log(GPR_ERROR, "credential reload arg schedule has already completed");
return;
}
TlsCredentialReloadConfig* cpp_config =
static_cast<TlsCredentialReloadConfig*>(arg->config->context());
TlsCredentialReloadArg* cpp_arg =
static_cast<TlsCredentialReloadArg*>(arg->context);
cpp_config->Cancel(cpp_arg);
}
void TlsCredentialReloadArgDestroyContext(void* context) {
if (context != nullptr) {
TlsCredentialReloadArg* cpp_arg =
static_cast<TlsCredentialReloadArg*>(context);
delete cpp_arg;
}
}
/** The C schedule and cancel functions for the server authorization check
* config. They populate a C server authorization check arg with the result
* of a C++ server authorization check schedule/cancel API. **/
int TlsServerAuthorizationCheckConfigCSchedule(
void* config_user_data, grpc_tls_server_authorization_check_arg* arg) {
if (arg == nullptr || arg->config == nullptr ||
arg->config->context() == nullptr) {
gpr_log(GPR_ERROR,
"server authorization check arg was not properly initialized");
return 1;
}
TlsServerAuthorizationCheckConfig* cpp_config =
static_cast<TlsServerAuthorizationCheckConfig*>(arg->config->context());
TlsServerAuthorizationCheckArg* cpp_arg =
new TlsServerAuthorizationCheckArg(arg);
int schedule_result = cpp_config->Schedule(cpp_arg);
return schedule_result;
}
void TlsServerAuthorizationCheckConfigCCancel(
void* config_user_data, grpc_tls_server_authorization_check_arg* arg) {
if (arg == nullptr || arg->config == nullptr ||
arg->config->context() == nullptr) {
gpr_log(GPR_ERROR,
"server authorization check arg was not properly initialized");
return;
}
if (arg->context == nullptr) {
gpr_log(GPR_ERROR,
"server authorization check arg schedule has already completed");
return;
}
TlsServerAuthorizationCheckConfig* cpp_config =
static_cast<TlsServerAuthorizationCheckConfig*>(arg->config->context());
TlsServerAuthorizationCheckArg* cpp_arg =
static_cast<TlsServerAuthorizationCheckArg*>(arg->context);
cpp_config->Cancel(cpp_arg);
}
void TlsServerAuthorizationCheckArgDestroyContext(void* context) {
if (context != nullptr) {
TlsServerAuthorizationCheckArg* cpp_arg =
static_cast<TlsServerAuthorizationCheckArg*>(context);
delete cpp_arg;
}
}
} // namespace experimental
} // namespace grpc_impl

@ -0,0 +1,58 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_INTERNAL_CPP_COMMON_TLS_CREDENTIALS_OPTIONS_UTIL_H
#define GRPC_INTERNAL_CPP_COMMON_TLS_CREDENTIALS_OPTIONS_UTIL_H
#include <grpc/grpc_security.h>
#include <grpcpp/security/tls_credentials_options.h>
#include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h"
namespace grpc_impl {
namespace experimental {
/** The following function is exposed for testing purposes. **/
grpc_tls_key_materials_config* ConvertToCKeyMaterialsConfig(
const std::shared_ptr<TlsKeyMaterialsConfig>& config);
/** The following 4 functions convert the user-provided schedule or cancel
* functions into C style schedule or cancel functions. These are internal
* functions, not meant to be accessed by the user. **/
int TlsCredentialReloadConfigCSchedule(void* config_user_data,
grpc_tls_credential_reload_arg* arg);
void TlsCredentialReloadConfigCCancel(void* config_user_data,
grpc_tls_credential_reload_arg* arg);
int TlsServerAuthorizationCheckConfigCSchedule(
void* config_user_data, grpc_tls_server_authorization_check_arg* arg);
void TlsServerAuthorizationCheckConfigCCancel(
void* config_user_data, grpc_tls_server_authorization_check_arg* arg);
/** The following 2 functions cleanup data created in the above C schedule
* functions. **/
void TlsCredentialReloadArgDestroyContext(void* context);
void TlsServerAuthorizationCheckArgDestroyContext(void* context);
} // namespace experimental
} // namespace grpc_impl
#endif // GRPC_INTERNAL_CPP_COMMON_TLS_CREDENTIALS_OPTIONS_UTIL_H

@ -150,5 +150,12 @@ std::shared_ptr<ServerCredentials> LocalServerCredentials(
new SecureServerCredentials(grpc_local_server_credentials_create(type)));
}
std::shared_ptr<ServerCredentials> TlsServerCredentials(
const TlsCredentialsOptions& options) {
return std::shared_ptr<ServerCredentials>(
new SecureServerCredentials(grpc_tls_spiffe_server_credentials_create(
options.c_credentials_options())));
}
} // namespace experimental
} // namespace grpc_impl

@ -22,6 +22,7 @@
#include <memory>
#include <grpcpp/security/server_credentials.h>
#include <grpcpp/security/tls_credentials_options.h>
#include <grpc/grpc_security.h>

@ -33,7 +33,7 @@ namespace Grpc.Core
/// Invokes a simple remote call in a blocking fashion.
/// </summary>
/// <returns>The response.</returns>
/// <param name="call">The call defintion.</param>
/// <param name="call">The call definition.</param>
/// <param name="req">Request message.</param>
/// <typeparam name="TRequest">Type of request message.</typeparam>
/// <typeparam name="TResponse">The of response message.</typeparam>
@ -49,7 +49,7 @@ namespace Grpc.Core
/// Invokes a simple remote call asynchronously.
/// </summary>
/// <returns>An awaitable call object providing access to the response.</returns>
/// <param name="call">The call defintion.</param>
/// <param name="call">The call definition.</param>
/// <param name="req">Request message.</param>
/// <typeparam name="TRequest">Type of request message.</typeparam>
/// <typeparam name="TResponse">The of response message.</typeparam>
@ -67,7 +67,7 @@ namespace Grpc.Core
/// In server streaming scenario, client sends on request and server responds with a stream of responses.
/// </summary>
/// <returns>A call object providing access to the asynchronous response stream.</returns>
/// <param name="call">The call defintion.</param>
/// <param name="call">The call definition.</param>
/// <param name="req">Request message.</param>
/// <typeparam name="TRequest">Type of request message.</typeparam>
/// <typeparam name="TResponse">The of response messages.</typeparam>
@ -85,7 +85,7 @@ namespace Grpc.Core
/// Invokes a client streaming call asynchronously.
/// In client streaming scenario, client sends a stream of requests and server responds with a single response.
/// </summary>
/// <param name="call">The call defintion.</param>
/// <param name="call">The call definition.</param>
/// <returns>An awaitable call object providing access to the response.</returns>
/// <typeparam name="TRequest">Type of request messages.</typeparam>
/// <typeparam name="TResponse">The of response message.</typeparam>
@ -107,7 +107,7 @@ namespace Grpc.Core
/// <returns>A call object providing access to the asynchronous request and response streams.</returns>
/// <param name="call">The call definition.</param>
/// <typeparam name="TRequest">Type of request messages.</typeparam>
/// <typeparam name="TResponse">Type of reponse messages.</typeparam>
/// <typeparam name="TResponse">Type of responsemessages.</typeparam>
public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call)
where TRequest : class
where TResponse : class

@ -97,7 +97,7 @@ namespace Grpc.Testing {
/// the server via the "gRPCLB fallback" path, and "backend" if it detects
/// that the RPC reached the server via "gRPCLB backend" path (i.e. if it got
/// the address of this server from the gRPCLB server BalanceLoad RPC). Exactly
/// how this detection is done is context and server dependant.
/// how this detection is done is context and server dependent.
/// </summary>
public enum GrpclbRouteType {
/// <summary>

@ -46,7 +46,7 @@ namespace Grpc.Testing {
}
#region Messages
/// <summary>
/// Reponse message containing the gauge name and value
/// Response message containing the gauge name and value
/// </summary>
public sealed partial class GaugeResponse : pb::IMessage<GaugeResponse> {
private static readonly pb::MessageParser<GaugeResponse> _parser = new pb::MessageParser<GaugeResponse>(() => new GaugeResponse());

@ -44,7 +44,7 @@ typedef NS_ENUM(NSInteger, GRXWriterState) {
/**
* The writer has released its writeable and won't interact with it anymore.
*
* One seldomly wants to set a writer's state to this value, as its writeable isn't notified with
* One seldom wants to set a writer's state to this value, as its writeable isn't notified with
* a writesFinishedWithError: message. Instead, sending finishWithError: to the writer will make
* it notify the writeable and then transition to this state.
*/

@ -13,10 +13,10 @@ def grpc_deps
pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod 'gRPC', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
pod 'gRPC/InternalTesting', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true
end

@ -38,7 +38,7 @@
+ (NSString *)host;
/**
* Bytes of overhead of test proto responses due to encoding. This is used to excercise the behavior
* Bytes of overhead of test proto responses due to encoding. This is used to exercise the behavior
* when responses are just above or below the max response size. For some reason, the local and
* remote servers enconde responses with different overhead (?), so this is defined per-subclass.
*/

@ -173,7 +173,7 @@ void prefork() {
void postfork_child() {
TSRMLS_FETCH();
// loop through persistant list and destroy all underlying grpc_channel objs
// loop through persistent list and destroy all underlying grpc_channel objs
destroy_grpc_channels();
// clear completion queue

@ -9,7 +9,7 @@ use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Reponse message containing the gauge name and value
* Response message containing the gauge name and value
*
* Generated from protobuf message <code>grpc.testing.GaugeResponse</code>
*/

@ -53,7 +53,7 @@ message EchoStatus {
// the server via the "gRPCLB fallback" path, and "backend" if it detects
// that the RPC reached the server via "gRPCLB backend" path (i.e. if it got
// the address of this server from the gRPCLB server BalanceLoad RPC). Exactly
// how this detection is done is context and server dependant.
// how this detection is done is context and server dependent.
enum GrpclbRouteType {
// Server didn't detect the route that a client took to reach it.
GRPCLB_ROUTE_TYPE_UNKNOWN = 0;

@ -22,7 +22,7 @@ syntax = "proto3";
package grpc.testing;
// Reponse message containing the gauge name and value
// Response message containing the gauge name and value
message GaugeResponse {
string name = 1;
oneof value {

@ -10,6 +10,8 @@ pyx_library(
"_cygrpc/_hooks.pyx.pxi",
"_cygrpc/aio/call.pxd.pxi",
"_cygrpc/aio/call.pyx.pxi",
"_cygrpc/aio/rpc_error.pxd.pxi",
"_cygrpc/aio/rpc_error.pyx.pxi",
"_cygrpc/aio/callbackcontext.pxd.pxi",
"_cygrpc/aio/channel.pxd.pxi",
"_cygrpc/aio/channel.pyx.pxi",

@ -13,15 +13,15 @@
# limitations under the License.
cimport cpython
import grpc
_EMPTY_FLAGS = 0
_EMPTY_METADATA = ()
_EMPTY_METADATA = None
_OP_ARRAY_LENGTH = 6
cdef class _AioCall:
def __cinit__(self, AioChannel channel):
self._channel = channel
self._functor.functor_run = _AioCall.functor_run
@ -59,7 +59,7 @@ cdef class _AioCall:
else:
call._waiter_call.set_result(None)
async def unary_unary(self, method, request):
async def unary_unary(self, method, request, timeout):
cdef grpc_call * call
cdef grpc_slice method_slice
cdef grpc_op * ops
@ -72,7 +72,7 @@ cdef class _AioCall:
cdef Operation receive_status_on_client_operation
cdef grpc_call_error call_status
cdef gpr_timespec deadline = _timespec_from_time(timeout)
method_slice = grpc_slice_from_copied_buffer(
<const char *> method,
@ -86,7 +86,7 @@ cdef class _AioCall:
self._cq,
method_slice,
NULL,
_timespec_from_time(None),
deadline,
NULL
)
@ -146,4 +146,12 @@ cdef class _AioCall:
grpc_call_unref(call)
gpr_free(ops)
return receive_message_operation.message()
if receive_status_on_client_operation.code() == grpc._cygrpc.StatusCode.ok:
return receive_message_operation.message()
raise grpc.experimental.aio.AioRpcError(
receive_initial_metadata_operation.initial_metadata(),
receive_status_on_client_operation.code(),
receive_status_on_client_operation.details(),
receive_status_on_client_operation.trailing_metadata(),
)

@ -18,13 +18,13 @@ cdef class AioChannel:
self._target = target
def __repr__(self):
class_name = self.__class__.__name__
class_name = self.__class__.__name__
id_ = id(self)
return f"<{class_name} {id_}>"
def close(self):
grpc_channel_destroy(self.channel)
async def unary_unary(self, method, request):
async def unary_unary(self, method, request, timeout):
call = _AioCall(self)
return await call.unary_unary(method, request)
return await call.unary_unary(method, request, timeout)

@ -0,0 +1,27 @@
# Copyright 2019 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Exceptions for the aio version of the RPC calls."""
cdef class _AioRpcError(Exception):
cdef readonly:
tuple _initial_metadata
int _code
str _details
tuple _trailing_metadata
cpdef tuple initial_metadata(self)
cpdef int code(self)
cpdef str details(self)
cpdef tuple trailing_metadata(self)

@ -0,0 +1,35 @@
# Copyright 2019 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Exceptions for the aio version of the RPC calls."""
cdef class _AioRpcError(Exception):
def __cinit__(self, tuple initial_metadata, int code, str details, tuple trailing_metadata):
self._initial_metadata = initial_metadata
self._code = code
self._details = details
self._trailing_metadata = trailing_metadata
cpdef tuple initial_metadata(self):
return self._initial_metadata
cpdef int code(self):
return self._code
cpdef str details(self):
return self._details
cpdef tuple trailing_metadata(self):
return self._trailing_metadata

@ -63,6 +63,7 @@ include "_cygrpc/aio/iomgr/resolver.pyx.pxi"
include "_cygrpc/aio/grpc_aio.pyx.pxi"
include "_cygrpc/aio/call.pyx.pxi"
include "_cygrpc/aio/channel.pyx.pxi"
include "_cygrpc/aio/rpc_error.pyx.pxi"
#

@ -14,8 +14,11 @@
"""gRPC's Asynchronous Python API."""
import abc
import types
import six
import grpc
from grpc._cython import cygrpc
from grpc._cython.cygrpc import init_grpc_aio
@ -74,6 +77,7 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
async def __call__(self,
request,
*,
timeout=None,
metadata=None,
credentials=None,
@ -121,3 +125,25 @@ def insecure_channel(target, options=None, compression=None):
from grpc.experimental.aio import _channel # pylint: disable=cyclic-import
return _channel.Channel(target, ()
if options is None else options, None, compression)
class _AioRpcError:
"""Private implementation of AioRpcError"""
class AioRpcError:
"""An RpcError to be used by the asynchronous API.
Parent classes: (cygrpc._AioRpcError, RpcError)
"""
# Dynamically registered as subclass of _AioRpcError and RpcError, because the former one is
# only available after the cython code has been compiled.
_class_built = _AioRpcError
def __new__(cls, *args, **kwargs):
if cls._class_built is _AioRpcError:
cls._class_built = types.new_class(
"AioRpcError", (cygrpc._AioRpcError, grpc.RpcError))
cls._class_built.__doc__ = cls.__doc__
return cls._class_built(*args, **kwargs)

@ -12,32 +12,42 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Invocation-side implementation of gRPC Asyncio Python."""
import asyncio
from typing import Callable, Optional
from grpc import _common
from grpc._cython import cygrpc
from grpc.experimental import aio
SerializingFunction = Callable[[str], bytes]
DeserializingFunction = Callable[[bytes], str]
class UnaryUnaryMultiCallable(aio.UnaryUnaryMultiCallable):
def __init__(self, channel, method, request_serializer,
response_deserializer):
def __init__(self, channel: cygrpc.AioChannel, method: bytes,
request_serializer: SerializingFunction,
response_deserializer: DeserializingFunction) -> None:
self._channel = channel
self._method = method
self._request_serializer = request_serializer
self._response_deserializer = response_deserializer
self._loop = asyncio.get_event_loop()
def _timeout_to_deadline(self, timeout: int) -> Optional[int]:
if timeout is None:
return None
return self._loop.time() + timeout
async def __call__(self,
request,
*,
timeout=None,
metadata=None,
credentials=None,
wait_for_ready=None,
compression=None):
if timeout:
raise NotImplementedError("TODO: timeout not implemented yet")
if metadata:
raise NotImplementedError("TODO: metadata not implemented yet")
@ -51,9 +61,11 @@ class UnaryUnaryMultiCallable(aio.UnaryUnaryMultiCallable):
if compression:
raise NotImplementedError("TODO: compression not implemented yet")
response = await self._channel.unary_unary(
self._method, _common.serialize(request, self._request_serializer))
serialized_request = _common.serialize(request,
self._request_serializer)
timeout = self._timeout_to_deadline(timeout)
response = await self._channel.unary_unary(self._method,
serialized_request, timeout)
return _common.deserialize(response, self._response_deserializer)

@ -387,6 +387,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
'src/core/ext/filters/client_channel/xds/xds_api.cc',
'src/core/ext/filters/client_channel/xds/xds_bootstrap.cc',
'src/core/ext/filters/client_channel/xds/xds_channel_secure.cc',
'src/core/ext/filters/client_channel/xds/xds_client.cc',
'src/core/ext/filters/client_channel/xds/xds_client_stats.cc',

@ -1,5 +1,6 @@
[
"_sanity._sanity_test.AioSanityTest",
"unit.channel_test.TestChannel",
"unit.init_test.TestAioRpcError",
"unit.init_test.TestInsecureChannel"
]

@ -15,9 +15,12 @@
import logging
import unittest
import grpc
from grpc.experimental import aio
from tests_aio.unit import test_base
from src.proto.grpc.testing import messages_pb2
from tests.unit.framework.common import test_constants
class TestChannel(test_base.AioTestBase):
@ -52,6 +55,36 @@ class TestChannel(test_base.AioTestBase):
self.loop.run_until_complete(coro())
def test_unary_call_times_out(self):
async def coro():
async with aio.insecure_channel(self.server_target) as channel:
empty_call_with_sleep = channel.unary_unary(
"/grpc.testing.TestService/EmptyCall",
request_serializer=messages_pb2.SimpleRequest.
SerializeToString,
response_deserializer=messages_pb2.SimpleResponse.
FromString,
)
timeout = test_constants.SHORT_TIMEOUT / 2
# TODO: Update once the async server is ready, change the synchronization mechanism by removing the
# sleep(<timeout>) as both components (client & server) will be on the same process.
with self.assertRaises(grpc.RpcError) as exception_context:
await empty_call_with_sleep(
messages_pb2.SimpleRequest(), timeout=timeout)
status_code, details = grpc.StatusCode.DEADLINE_EXCEEDED.value
self.assertEqual(exception_context.exception.code(),
status_code)
self.assertEqual(exception_context.exception.details(),
details.title())
self.assertIsNotNone(
exception_context.exception.initial_metadata())
self.assertIsNotNone(
exception_context.exception.trailing_metadata())
self.loop.run_until_complete(coro())
if __name__ == '__main__':
logging.basicConfig()

@ -15,10 +15,50 @@
import logging
import unittest
import grpc
from grpc.experimental import aio
from tests_aio.unit import test_base
class TestAioRpcError(unittest.TestCase):
_TEST_INITIAL_METADATA = ("initial metadata",)
_TEST_TRAILING_METADATA = ("trailing metadata",)
def test_attributes(self):
aio_rpc_error = aio.AioRpcError(self._TEST_INITIAL_METADATA, 0,
"details", self._TEST_TRAILING_METADATA)
self.assertEqual(aio_rpc_error.initial_metadata(),
self._TEST_INITIAL_METADATA)
self.assertEqual(aio_rpc_error.code(), 0)
self.assertEqual(aio_rpc_error.details(), "details")
self.assertEqual(aio_rpc_error.trailing_metadata(),
self._TEST_TRAILING_METADATA)
def test_class_hierarchy(self):
aio_rpc_error = aio.AioRpcError(self._TEST_INITIAL_METADATA, 0,
"details", self._TEST_TRAILING_METADATA)
self.assertIsInstance(aio_rpc_error, grpc.RpcError)
def test_class_attributes(self):
aio_rpc_error = aio.AioRpcError(self._TEST_INITIAL_METADATA, 0,
"details", self._TEST_TRAILING_METADATA)
self.assertEqual(aio_rpc_error.__class__.__name__, "AioRpcError")
self.assertEqual(aio_rpc_error.__class__.__doc__,
aio.AioRpcError.__doc__)
def test_class_singleton(self):
first_aio_rpc_error = aio.AioRpcError(self._TEST_INITIAL_METADATA, 0,
"details",
self._TEST_TRAILING_METADATA)
second_aio_rpc_error = aio.AioRpcError(self._TEST_INITIAL_METADATA, 0,
"details",
self._TEST_TRAILING_METADATA)
self.assertIs(first_aio_rpc_error.__class__,
second_aio_rpc_error.__class__)
class TestInsecureChannel(test_base.AioTestBase):
def test_insecure_channel(self):

@ -20,6 +20,7 @@ from time import sleep
import grpc
from src.proto.grpc.testing import messages_pb2
from src.proto.grpc.testing import test_pb2_grpc
from tests.unit.framework.common import test_constants
# TODO (https://github.com/grpc/grpc/issues/19762)
@ -29,6 +30,10 @@ class TestServiceServicer(test_pb2_grpc.TestServiceServicer):
def UnaryCall(self, request, context):
return messages_pb2.SimpleResponse()
def EmptyCall(self, request, context):
while True:
sleep(test_constants.LONG_TIMEOUT)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Synchronous gRPC server.')

@ -76,6 +76,7 @@ if grpc_config == 'dbg'
end
$LDFLAGS << ' -Wl,-wrap,memcpy' if RUBY_PLATFORM =~ /linux/
$LDFLAGS << ' -static-libgcc -static-libstdc++' if RUBY_PLATFORM =~ /linux/
$LDFLAGS << ' -static' if windows
$CFLAGS << ' -std=c99 '

@ -73,10 +73,11 @@
set(PACKAGE_NAME "grpc")
set(PACKAGE_VERSION "${settings.cpp_version}")
set(gRPC_CORE_VERSION "${settings.core_version}")
set(PACKAGE_STRING "<%text>${PACKAGE_NAME} ${PACKAGE_VERSION}</%text>")
set(PACKAGE_TARNAME "<%text>${PACKAGE_NAME}-${PACKAGE_VERSION}</%text>")
set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
project(<%text>${PACKAGE_NAME}</%text> C CXX)
project(<%text>${PACKAGE_NAME}</%text> LANGUAGES C CXX)
set(gRPC_INSTALL_BINDIR "bin" CACHE STRING "Installation directory for executables")
set(gRPC_INSTALL_LIBDIR "lib" CACHE STRING "Installation directory for libraries")
@ -569,3 +570,71 @@
install(FILES <%text>${CMAKE_CURRENT_SOURCE_DIR}/etc/roots.pem</%text>
DESTINATION <%text>${gRPC_INSTALL_SHAREDIR}</%text>)
# Function to generate pkg-config files.
function(generate_pkgconfig name description version requires
libs libs_private output_filename)
set(PC_NAME "<%text>${name}</%text>")
set(PC_DESCRIPTION "<%text>${description}</%text>")
set(PC_VERSION "<%text>${version}</%text>")
set(PC_REQUIRES "<%text>${requires}</%text>")
set(PC_LIB "<%text>${libs}</%text>")
set(PC_LIBS_PRIVATE "<%text>${libs_private}</%text>")
set(output_filepath "<%text>${grpc_BINARY_DIR}/libs/opt/pkgconfig/${output_filename}</%text>")
configure_file(
"<%text>${grpc_SOURCE_DIR}/cmake/pkg-config-template.pc.in</%text>"
"<%text>${output_filepath}</%text>"
@ONLY)
install(FILES "<%text>${output_filepath}</%text>"
DESTINATION "lib/pkgconfig/")
endfunction()
# gpr .pc file
generate_pkgconfig(
"gpr"
"gRPC platform support library"
"<%text>${gRPC_CORE_VERSION}</%text>"
""
"-lgpr"
""
"gpr.pc")
# grpc .pc file
generate_pkgconfig(
"gRPC"
"high performance general RPC framework"
"<%text>${gRPC_CORE_VERSION}</%text>"
"gpr"
"-lgrpc -laddress_sorting -lcares -lz"
""
"grpc.pc")
# grpc_unsecure .pc file
generate_pkgconfig(
"gRPC unsecure"
"high performance general RPC framework without SSL"
"<%text>${gRPC_CORE_VERSION}</%text>"
"gpr"
"-lgrpc_unsecure"
""
"grpc_unsecure.pc")
# grpc++ .pc file
generate_pkgconfig(
"gRPC++"
"C++ wrapper for gRPC"
"<%text>${PACKAGE_VERSION}</%text>"
"grpc"
"-lgrpc++"
""
"grpc++.pc")
# grpc++_unsecure .pc file
generate_pkgconfig(
"gRPC++ unsecure"
"C++ wrapper for gRPC without SSL"
"<%text>${PACKAGE_VERSION}</%text>"
"grpc_unsecure"
"-lgrpc++_unsecure"
""
"grpc++_unsecure.pc")

@ -374,7 +374,7 @@
Description: $(PC_DESCRIPTION),\
Version: $(CORE_VERSION),\
Cflags: -I${'\$${includedir}'} $(PC_CFLAGS),\
Requires.private: $(PC_REQUIRES_PRIVATE),\
Requires: $(PC_REQUIRES),\
Libs: -L${'\$${libdir}'} $(PC_LIB),\
Libs.private: $(PC_LIBS_PRIVATE)
@ -387,7 +387,7 @@
Description: $(PC_DESCRIPTION),\
Version: $(CPP_VERSION),\
Cflags: -I${'\$${includedir}'} $(PC_CFLAGS),\
Requires.private: $(PC_REQUIRES_PRIVATE),\
Requires: $(PC_REQUIRES),\
Libs: -L${'\$${libdir}'} $(PC_LIB),\
Libs.private: $(PC_LIBS_PRIVATE)
@ -400,7 +400,7 @@
Description: $(PC_DESCRIPTION),\
Version: $(CSHARP_VERSION),\
Cflags: -I${'\$${includedir}'} $(PC_CFLAGS),\
Requires.private: $(PC_REQUIRES_PRIVATE),\
Requires: $(PC_REQUIRES),\
Libs: -L${'\$${libdir}'} $(PC_LIB),\
Libs.private: $(PC_LIBS_PRIVATE)
@ -695,7 +695,7 @@
PC_NAME = gpr
PC_DESCRIPTION = gRPC platform support library
PC_CFLAGS =
PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GPR)
PC_REQUIRES = $(PC_REQUIRES_GPR)
PC_LIBS_PRIVATE = $(PC_LIBS_GPR)
PC_LIB = -lgpr
GPR_PC_FILE := $(CORE_PC_TEMPLATE)
@ -704,7 +704,7 @@
PC_NAME = gRPC
PC_DESCRIPTION = high performance general RPC framework
PC_CFLAGS =
PC_REQUIRES_PRIVATE = gpr $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
PC_REQUIRES = 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)
@ -713,7 +713,7 @@
PC_NAME = gRPC unsecure
PC_DESCRIPTION = high performance general RPC framework without SSL
PC_CFLAGS =
PC_REQUIRES_PRIVATE = gpr $(PC_REQUIRES_GRPC)
PC_REQUIRES = gpr $(PC_REQUIRES_GRPC)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
PC_LIB = -lgrpc_unsecure
GRPC_UNSECURE_PC_FILE := $(CORE_PC_TEMPLATE)
@ -781,7 +781,7 @@
PC_NAME = gRPC++
PC_DESCRIPTION = C++ wrapper for gRPC
PC_CFLAGS =
PC_REQUIRES_PRIVATE = grpc $(PC_REQUIRES_GRPCXX)
PC_REQUIRES = grpc $(PC_REQUIRES_GRPCXX)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
PC_LIB = -lgrpc++
GRPCXX_PC_FILE := $(CPP_PC_TEMPLATE)
@ -790,7 +790,7 @@
PC_NAME = gRPC++ unsecure
PC_DESCRIPTION = C++ wrapper for gRPC without SSL
PC_CFLAGS =
PC_REQUIRES_PRIVATE = grpc_unsecure $(PC_REQUIRES_GRPCXX)
PC_REQUIRES = grpc_unsecure $(PC_REQUIRES_GRPCXX)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
PC_LIB = -lgrpc++_unsecure
GRPCXX_UNSECURE_PC_FILE := $(CPP_PC_TEMPLATE)

@ -119,11 +119,9 @@
'src/objective-c/GRPCClient/GRPCCall+Cronet.h',
'src/objective-c/GRPCClient/GRPCCall+OAuth2.h',
'src/objective-c/GRPCClient/GRPCCall+Tests.h',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h',
'src/objective-c/GRPCClient/internal_testing/*.h'
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h'
ss.private_header_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.h'
ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,m}',
'src/objective-c/GRPCClient/private/GRPCCore/*.{h,m}',
ss.source_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.{h,m}',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.m',
'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h',
@ -172,4 +170,16 @@
ss.tvos.deployment_target = '10.0'
ss.watchos.deployment_target = '4.0'
end
s.subspec 'InternalTesting' do |ss|
ss.dependency "#{s.name}/GRPCCore", version
ss.public_header_files = 'src/objective-c/GRPCClient/internal_testing/*.h'
ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,m}'
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
ss.ios.deployment_target = '7.0'
ss.osx.deployment_target = '10.9'
ss.tvos.deployment_target = '10.0'
ss.watchos.deployment_target = '4.0'
end
end

@ -96,3 +96,20 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "xds_bootstrap_test",
srcs = ["xds_bootstrap_test.cc"],
external_deps = [
"gtest",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
# TODO(nnoble): Remove this once https://github.com/grpc/grpc/issues/20541
# is resolved.
tags = ["no_windows"],
)

@ -0,0 +1,338 @@
//
// Copyright 2019 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <regex>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <grpc/grpc.h>
#include <grpc/slice.h>
#include "src/core/ext/filters/client_channel/xds/xds_bootstrap.h"
#include "test/core/util/test_config.h"
namespace grpc_core {
namespace testing {
void VerifyRegexMatch(grpc_error* error, const std::regex& e) {
std::smatch match;
std::string s(grpc_error_string(error));
EXPECT_TRUE(std::regex_search(s, match, e));
GRPC_ERROR_UNREF(error);
}
TEST(XdsBootstrapTest, Basic) {
const char* json =
"{"
" \"xds_server\": {"
" \"server_uri\": \"fake:///lb\","
" \"channel_creds\": ["
" {"
" \"type\": \"fake\","
" \"ignore\": 0"
" }"
" ],"
" \"ignore\": 0"
" },"
" \"node\": {"
" \"id\": \"foo\","
" \"cluster\": \"bar\","
" \"locality\": {"
" \"region\": \"milky_way\","
" \"zone\": \"sol_system\","
" \"subzone\": \"earth\","
" \"ignore\": {}"
" },"
" \"metadata\": {"
" \"null\": null,"
" \"string\": \"quux\","
" \"double\": 123.4,"
" \"bool\": true,"
" \"struct\": {"
" \"whee\": 0"
" },"
" \"list\": [1, 2, 3]"
" },"
" \"ignore\": \"whee\""
" },"
" \"ignore\": {}"
"}";
grpc_slice slice = grpc_slice_from_copied_string(json);
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::XdsBootstrap bootstrap(slice, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_STREQ(bootstrap.server_uri(), "fake:///lb");
ASSERT_EQ(bootstrap.channel_creds().size(), 1);
EXPECT_STREQ(bootstrap.channel_creds()[0].type, "fake");
EXPECT_EQ(bootstrap.channel_creds()[0].config, nullptr);
ASSERT_NE(bootstrap.node(), nullptr);
EXPECT_STREQ(bootstrap.node()->id, "foo");
EXPECT_STREQ(bootstrap.node()->cluster, "bar");
EXPECT_STREQ(bootstrap.node()->locality_region, "milky_way");
EXPECT_STREQ(bootstrap.node()->locality_zone, "sol_system");
EXPECT_STREQ(bootstrap.node()->locality_subzone, "earth");
EXPECT_THAT(
bootstrap.node()->metadata,
::testing::ElementsAre(
::testing::Pair(::testing::StrEq("null"),
::testing::AllOf(::testing::Field(
&XdsBootstrap::MetadataValue::type,
XdsBootstrap::MetadataValue::Type::MD_NULL))),
::testing::Pair(
::testing::StrEq("string"),
::testing::AllOf(
::testing::Field(&XdsBootstrap::MetadataValue::type,
XdsBootstrap::MetadataValue::Type::STRING),
::testing::Field(&XdsBootstrap::MetadataValue::string_value,
::testing::StrEq("quux")))),
::testing::Pair(
::testing::StrEq("double"),
::testing::AllOf(
::testing::Field(&XdsBootstrap::MetadataValue::type,
XdsBootstrap::MetadataValue::Type::DOUBLE),
::testing::Field(&XdsBootstrap::MetadataValue::double_value,
123.4))),
::testing::Pair(
::testing::StrEq("bool"),
::testing::AllOf(
::testing::Field(&XdsBootstrap::MetadataValue::type,
XdsBootstrap::MetadataValue::Type::BOOL),
::testing::Field(&XdsBootstrap::MetadataValue::bool_value,
true))),
::testing::Pair(
::testing::StrEq("struct"),
::testing::AllOf(
::testing::Field(&XdsBootstrap::MetadataValue::type,
XdsBootstrap::MetadataValue::Type::STRUCT),
::testing::Field(
&XdsBootstrap::MetadataValue::struct_value,
::testing::ElementsAre(::testing::Pair(
::testing::StrEq("whee"),
::testing::AllOf(
::testing::Field(
&XdsBootstrap::MetadataValue::type,
XdsBootstrap::MetadataValue::Type::DOUBLE),
::testing::Field(
&XdsBootstrap::MetadataValue::double_value,
0))))))),
::testing::Pair(
::testing::StrEq("list"),
::testing::Field(&XdsBootstrap::MetadataValue::type,
XdsBootstrap::MetadataValue::Type::LIST))));
// TODO(roth): Once our InlinedVector<> implementation supports
// iteration, replace this by using ElementsAre() in the statement above.
auto it = bootstrap.node()->metadata.find("list");
ASSERT_TRUE(it != bootstrap.node()->metadata.end());
ASSERT_EQ(it->second.list_value.size(), 3);
EXPECT_EQ(it->second.list_value[0].type,
XdsBootstrap::MetadataValue::Type::DOUBLE);
EXPECT_EQ(it->second.list_value[0].double_value, 1);
EXPECT_EQ(it->second.list_value[1].type,
XdsBootstrap::MetadataValue::Type::DOUBLE);
EXPECT_EQ(it->second.list_value[1].double_value, 2);
EXPECT_EQ(it->second.list_value[2].type,
XdsBootstrap::MetadataValue::Type::DOUBLE);
EXPECT_EQ(it->second.list_value[2].double_value, 3);
}
TEST(XdsBootstrapTest, ValidWithoutChannelCredsAndNode) {
const char* json =
"{"
" \"xds_server\": {"
" \"server_uri\": \"fake:///lb\""
" }"
"}";
grpc_slice slice = grpc_slice_from_copied_string(json);
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::XdsBootstrap bootstrap(slice, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_STREQ(bootstrap.server_uri(), "fake:///lb");
EXPECT_EQ(bootstrap.channel_creds().size(), 0);
EXPECT_EQ(bootstrap.node(), nullptr);
}
TEST(XdsBootstrapTest, InvalidJson) {
grpc_slice slice = grpc_slice_from_copied_string("");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::XdsBootstrap bootstrap(slice, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(std::string("failed to parse bootstrap file JSON"));
VerifyRegexMatch(error, e);
}
TEST(XdsBootstrapTest, MalformedJson) {
grpc_slice slice = grpc_slice_from_copied_string("\"foo\"");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::XdsBootstrap bootstrap(slice, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(std::string("malformed JSON in bootstrap file"));
VerifyRegexMatch(error, e);
}
TEST(XdsBootstrapTest, MissingXdsServer) {
grpc_slice slice = grpc_slice_from_copied_string("{}");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::XdsBootstrap bootstrap(slice, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(std::string("\"xds_server\" field not present"));
VerifyRegexMatch(error, e);
}
TEST(XdsBootstrapTest, BadXdsServer) {
grpc_slice slice = grpc_slice_from_copied_string(
"{"
" \"xds_server\":1,"
" \"xds_server\":{}"
"}");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::XdsBootstrap bootstrap(slice, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("\"xds_server\" field is not an object(.*)"
"duplicate \"xds_server\" field(.*)"
"errors parsing \"xds_server\" object(.*)"
"\"server_uri\" field not present"));
VerifyRegexMatch(error, e);
}
TEST(XdsBootstrapTest, BadXdsServerContents) {
grpc_slice slice = grpc_slice_from_copied_string(
"{"
" \"xds_server\":{"
" \"server_uri\":1,"
" \"server_uri\":\"foo\","
" \"channel_creds\":1,"
" \"channel_creds\":{}"
" }"
"}");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::XdsBootstrap bootstrap(slice, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("errors parsing \"xds_server\" object(.*)"
"\"server_uri\" field is not a string(.*)"
"duplicate \"server_uri\" field(.*)"
"\"channel_creds\" field is not an array(.*)"
"duplicate \"channel_creds\" field(.*)"
"\"channel_creds\" field is not an array"));
VerifyRegexMatch(error, e);
}
TEST(XdsBootstrapTest, BadChannelCredsContents) {
grpc_slice slice = grpc_slice_from_copied_string(
"{"
" \"xds_server\":{"
" \"server_uri\":\"foo\","
" \"channel_creds\":["
" {"
" \"type\":0,"
" \"type\":\"fake\","
" \"config\":1,"
" \"config\":{}"
" }"
" ]"
" }"
"}");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::XdsBootstrap bootstrap(slice, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("errors parsing \"xds_server\" object(.*)"
"errors parsing \"channel_creds\" object(.*)"
"\"type\" field is not a string(.*)"
"duplicate \"type\" field(.*)"
"\"config\" field is not an object(.*)"
"duplicate \"config\" field"));
VerifyRegexMatch(error, e);
}
TEST(XdsBootstrapTest, BadNode) {
grpc_slice slice = grpc_slice_from_copied_string(
"{"
" \"node\":1,"
" \"node\":{"
" \"id\":0,"
" \"id\":\"foo\","
" \"cluster\":0,"
" \"cluster\":\"foo\","
" \"locality\":0,"
" \"locality\":{"
" \"region\":0,"
" \"region\":\"foo\","
" \"zone\":0,"
" \"zone\":\"foo\","
" \"subzone\":0,"
" \"subzone\":\"foo\""
" },"
" \"metadata\":0,"
" \"metadata\":{"
" \"foo\":0,"
" \"foo\":\"whee\","
" \"foo\":\"whee2\""
" }"
" }"
"}");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::XdsBootstrap bootstrap(slice, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("\"node\" field is not an object(.*)"
"duplicate \"node\" field(.*)"
"errors parsing \"node\" object(.*)"
"\"id\" field is not a string(.*)"
"duplicate \"id\" field(.*)"
"\"cluster\" field is not a string(.*)"
"duplicate \"cluster\" field(.*)"
"\"locality\" field is not an object(.*)"
"duplicate \"locality\" field(.*)"
"errors parsing \"locality\" object(.*)"
"\"region\" field is not a string(.*)"
"duplicate \"region\" field(.*)"
"\"zone\" field is not a string(.*)"
"duplicate \"zone\" field(.*)"
"\"subzone\" field is not a string(.*)"
"duplicate \"subzone\" field(.*)"
"\"metadata\" field is not an object(.*)"
"duplicate \"metadata\" field(.*)"
"errors parsing \"metadata\" object(.*)"
"duplicate metadata key \"foo\""));
VerifyRegexMatch(error, e);
}
} // namespace testing
} // namespace grpc_core
int main(int argc, char** argv) {
// Regexes don't work in gcc4.8 and below, so just skip testing in those cases
#if defined(__GNUC__) && \
((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__) <= 8))
return 0;
#endif
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

@ -486,6 +486,19 @@ TEST(InlinedVectorTest, PopBackAllocated) {
EXPECT_EQ(sz - 1, v.size());
}
TEST(InlinedVectorTest, Resize) {
const int kInlinedSize = 2;
InlinedVector<UniquePtr<int>, kInlinedSize> v;
// Size up.
v.resize(5);
EXPECT_EQ(5UL, v.size());
EXPECT_EQ(nullptr, v[4]);
// Size down.
v[4] = MakeUnique<int>(5);
v.resize(1);
EXPECT_EQ(1UL, v.size());
}
} // namespace testing
} // namespace grpc_core

@ -17,6 +17,7 @@
*/
#include <grpcpp/security/credentials.h>
#include <grpcpp/security/tls_credentials_options.h>
#include <memory>
@ -26,7 +27,81 @@
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/tmpfile.h"
#include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h"
#include "src/cpp/client/secure_credentials.h"
#include "src/cpp/common/tls_credentials_options_util.h"
namespace {
typedef class ::grpc_impl::experimental::TlsKeyMaterialsConfig
TlsKeyMaterialsConfig;
typedef class ::grpc_impl::experimental::TlsCredentialReloadArg
TlsCredentialReloadArg;
typedef struct ::grpc_impl::experimental::TlsCredentialReloadInterface
TlsCredentialReloadInterface;
typedef class ::grpc_impl::experimental::TlsServerAuthorizationCheckArg
TlsServerAuthorizationCheckArg;
typedef struct ::grpc_impl::experimental::TlsServerAuthorizationCheckInterface
TlsServerAuthorizationCheckInterface;
static void tls_credential_reload_callback(
grpc_tls_credential_reload_arg* arg) {
GPR_ASSERT(arg != nullptr);
arg->status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED;
}
class TestTlsCredentialReload : public TlsCredentialReloadInterface {
int Schedule(TlsCredentialReloadArg* arg) override {
GPR_ASSERT(arg != nullptr);
struct TlsKeyMaterialsConfig::PemKeyCertPair pair3 = {"private_key3",
"cert_chain3"};
arg->set_pem_root_certs("new_pem_root_certs");
arg->add_pem_key_cert_pair(pair3);
arg->set_status(GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW);
return 0;
}
void Cancel(TlsCredentialReloadArg* arg) override {
GPR_ASSERT(arg != nullptr);
arg->set_status(GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL);
arg->set_error_details("cancelled");
}
};
static void tls_server_authorization_check_callback(
grpc_tls_server_authorization_check_arg* arg) {
GPR_ASSERT(arg != nullptr);
grpc::string cb_user_data = "cb_user_data";
arg->cb_user_data = static_cast<void*>(gpr_strdup(cb_user_data.c_str()));
arg->success = 1;
arg->target_name = gpr_strdup("callback_target_name");
arg->peer_cert = gpr_strdup("callback_peer_cert");
arg->status = GRPC_STATUS_OK;
arg->error_details = gpr_strdup("callback_error_details");
}
class TestTlsServerAuthorizationCheck
: public TlsServerAuthorizationCheckInterface {
int Schedule(TlsServerAuthorizationCheckArg* arg) override {
GPR_ASSERT(arg != nullptr);
grpc::string cb_user_data = "cb_user_data";
arg->set_cb_user_data(static_cast<void*>(gpr_strdup(cb_user_data.c_str())));
arg->set_success(1);
arg->set_target_name("sync_target_name");
arg->set_peer_cert("sync_peer_cert");
arg->set_status(GRPC_STATUS_OK);
arg->set_error_details("sync_error_details");
return 1;
}
void Cancel(TlsServerAuthorizationCheckArg* arg) override {
GPR_ASSERT(arg != nullptr);
arg->set_status(GRPC_STATUS_PERMISSION_DENIED);
arg->set_error_details("cancelled");
}
};
} // namespace
namespace grpc {
namespace testing {
@ -196,6 +271,472 @@ TEST_F(CredentialsTest, StsCredentialsOptionsFromEnv) {
gpr_unsetenv("STS_CREDENTIALS");
}
typedef class ::grpc_impl::experimental::TlsKeyMaterialsConfig
TlsKeyMaterialsConfig;
TEST_F(CredentialsTest, TlsKeyMaterialsConfigCppToC) {
std::shared_ptr<TlsKeyMaterialsConfig> config(new TlsKeyMaterialsConfig());
struct TlsKeyMaterialsConfig::PemKeyCertPair pair = {"private_key",
"cert_chain"};
std::vector<TlsKeyMaterialsConfig::PemKeyCertPair> pair_list = {pair};
config->set_key_materials("pem_root_certs", pair_list);
grpc_tls_key_materials_config* c_config =
ConvertToCKeyMaterialsConfig(config);
EXPECT_STREQ("pem_root_certs", c_config->pem_root_certs());
EXPECT_EQ(1, static_cast<int>(c_config->pem_key_cert_pair_list().size()));
EXPECT_STREQ(pair.private_key.c_str(),
c_config->pem_key_cert_pair_list()[0].private_key());
EXPECT_STREQ(pair.cert_chain.c_str(),
c_config->pem_key_cert_pair_list()[0].cert_chain());
gpr_free(c_config->pem_key_cert_pair_list()[0].private_key());
gpr_free(c_config->pem_key_cert_pair_list()[0].cert_chain());
gpr_free(const_cast<char*>(c_config->pem_root_certs()));
gpr_free(c_config);
}
TEST_F(CredentialsTest, TlsKeyMaterialsModifiers) {
std::shared_ptr<TlsKeyMaterialsConfig> config(new TlsKeyMaterialsConfig());
struct TlsKeyMaterialsConfig::PemKeyCertPair pair = {"private_key",
"cert_chain"};
config->add_pem_key_cert_pair(pair);
config->set_pem_root_certs("pem_root_certs");
EXPECT_STREQ(config->pem_root_certs().c_str(), "pem_root_certs");
std::vector<TlsKeyMaterialsConfig::PemKeyCertPair> list =
config->pem_key_cert_pair_list();
EXPECT_EQ(static_cast<int>(list.size()), 1);
EXPECT_STREQ(list[0].private_key.c_str(), "private_key");
EXPECT_STREQ(list[0].cert_chain.c_str(), "cert_chain");
}
typedef class ::grpc_impl::experimental::TlsCredentialReloadArg
TlsCredentialReloadArg;
typedef class ::grpc_impl::experimental::TlsCredentialReloadConfig
TlsCredentialReloadConfig;
TEST_F(CredentialsTest, TlsCredentialReloadArgCallback) {
grpc_tls_credential_reload_arg* c_arg = new grpc_tls_credential_reload_arg;
c_arg->cb = tls_credential_reload_callback;
c_arg->context = nullptr;
TlsCredentialReloadArg* arg = new TlsCredentialReloadArg(c_arg);
arg->set_status(GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW);
arg->OnCredentialReloadDoneCallback();
EXPECT_EQ(arg->status(), GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED);
// Cleanup.
delete arg;
delete c_arg;
}
TEST_F(CredentialsTest, TlsCredentialReloadConfigSchedule) {
std::shared_ptr<TestTlsCredentialReload> test_credential_reload(
new TestTlsCredentialReload());
std::shared_ptr<TlsCredentialReloadConfig> config(
new TlsCredentialReloadConfig(test_credential_reload));
grpc_tls_credential_reload_arg* c_arg =
grpc_core::New<grpc_tls_credential_reload_arg>();
c_arg->context = nullptr;
TlsCredentialReloadArg* arg = new TlsCredentialReloadArg(c_arg);
std::shared_ptr<TlsKeyMaterialsConfig> key_materials_config(
new TlsKeyMaterialsConfig());
struct TlsKeyMaterialsConfig::PemKeyCertPair pair1 = {"private_key1",
"cert_chain1"};
struct TlsKeyMaterialsConfig::PemKeyCertPair pair2 = {"private_key2",
"cert_chain2"};
std::vector<TlsKeyMaterialsConfig::PemKeyCertPair> pair_list = {pair1, pair2};
key_materials_config->set_key_materials("pem_root_certs", pair_list);
arg->set_key_materials_config(key_materials_config);
arg->set_status(GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW);
arg->set_error_details("error_details");
const char* error_details_before_schedule = c_arg->error_details;
int schedule_output = config->Schedule(arg);
EXPECT_EQ(schedule_output, 0);
EXPECT_STREQ(c_arg->key_materials_config->pem_root_certs(),
"new_pem_root_certs");
grpc_tls_key_materials_config::PemKeyCertPairList c_pair_list =
c_arg->key_materials_config->pem_key_cert_pair_list();
EXPECT_TRUE(!arg->is_pem_key_cert_pair_list_empty());
EXPECT_EQ(static_cast<int>(c_pair_list.size()), 3);
EXPECT_STREQ(c_pair_list[0].private_key(), "private_key1");
EXPECT_STREQ(c_pair_list[0].cert_chain(), "cert_chain1");
EXPECT_STREQ(c_pair_list[1].private_key(), "private_key2");
EXPECT_STREQ(c_pair_list[1].cert_chain(), "cert_chain2");
EXPECT_STREQ(c_pair_list[2].private_key(), "private_key3");
EXPECT_STREQ(c_pair_list[2].cert_chain(), "cert_chain3");
EXPECT_EQ(arg->status(), GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW);
EXPECT_STREQ(arg->error_details().c_str(), "error_details");
// Cleanup.
gpr_free(const_cast<char*>(error_details_before_schedule));
grpc_core::Delete(c_arg->key_materials_config);
if (c_arg->destroy_context != nullptr) {
c_arg->destroy_context(c_arg->context);
}
gpr_free(c_arg);
gpr_free(config->c_config());
}
TEST_F(CredentialsTest, TlsCredentialReloadConfigCppToC) {
std::shared_ptr<TestTlsCredentialReload> test_credential_reload(
new TestTlsCredentialReload());
TlsCredentialReloadConfig config(test_credential_reload);
grpc_tls_credential_reload_arg c_arg;
c_arg.context = nullptr;
c_arg.cb_user_data = static_cast<void*>(nullptr);
grpc_tls_key_materials_config c_key_materials;
grpc::string test_private_key = "private_key";
grpc::string test_cert_chain = "cert_chain";
grpc_ssl_pem_key_cert_pair* ssl_pair =
(grpc_ssl_pem_key_cert_pair*)gpr_malloc(
sizeof(grpc_ssl_pem_key_cert_pair));
ssl_pair->private_key = gpr_strdup(test_private_key.c_str());
ssl_pair->cert_chain = gpr_strdup(test_cert_chain.c_str());
::grpc_core::PemKeyCertPair pem_key_cert_pair =
::grpc_core::PemKeyCertPair(ssl_pair);
::grpc_core::InlinedVector<::grpc_core::PemKeyCertPair, 1>
pem_key_cert_pair_list;
pem_key_cert_pair_list.push_back(pem_key_cert_pair);
grpc::string test_pem_root_certs = "pem_root_certs";
c_key_materials.set_key_materials(
::grpc_core::UniquePtr<char>(gpr_strdup(test_pem_root_certs.c_str())),
pem_key_cert_pair_list);
c_arg.key_materials_config = &c_key_materials;
c_arg.status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED;
grpc::string test_error_details = "error_details";
c_arg.error_details = test_error_details.c_str();
grpc_tls_credential_reload_config* c_config = config.c_config();
c_arg.config = c_config;
int c_schedule_output = c_config->Schedule(&c_arg);
EXPECT_EQ(c_schedule_output, 0);
EXPECT_EQ(c_arg.cb_user_data, nullptr);
EXPECT_STREQ(c_arg.key_materials_config->pem_root_certs(),
"new_pem_root_certs");
::grpc_core::InlinedVector<::grpc_core::PemKeyCertPair, 1> pair_list =
c_arg.key_materials_config->pem_key_cert_pair_list();
EXPECT_EQ(static_cast<int>(pair_list.size()), 2);
EXPECT_STREQ(pair_list[0].private_key(), "private_key");
EXPECT_STREQ(pair_list[0].cert_chain(), "cert_chain");
EXPECT_STREQ(pair_list[1].private_key(), "private_key3");
EXPECT_STREQ(pair_list[1].cert_chain(), "cert_chain3");
EXPECT_EQ(c_arg.status, GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW);
EXPECT_STREQ(c_arg.error_details, test_error_details.c_str());
// Cleanup.
c_arg.destroy_context(c_arg.context);
::grpc_core::Delete(config.c_config());
}
typedef class ::grpc_impl::experimental::TlsServerAuthorizationCheckArg
TlsServerAuthorizationCheckArg;
typedef class ::grpc_impl::experimental::TlsServerAuthorizationCheckConfig
TlsServerAuthorizationCheckConfig;
TEST_F(CredentialsTest, TlsServerAuthorizationCheckArgCallback) {
grpc_tls_server_authorization_check_arg* c_arg =
new grpc_tls_server_authorization_check_arg;
c_arg->cb = tls_server_authorization_check_callback;
c_arg->context = nullptr;
TlsServerAuthorizationCheckArg* arg =
new TlsServerAuthorizationCheckArg(c_arg);
arg->set_cb_user_data(nullptr);
arg->set_success(0);
arg->set_target_name("target_name");
arg->set_peer_cert("peer_cert");
arg->set_status(GRPC_STATUS_UNAUTHENTICATED);
arg->set_error_details("error_details");
const char* target_name_before_callback = c_arg->target_name;
const char* peer_cert_before_callback = c_arg->peer_cert;
const char* error_details_before_callback = c_arg->error_details;
arg->OnServerAuthorizationCheckDoneCallback();
EXPECT_STREQ(static_cast<char*>(arg->cb_user_data()), "cb_user_data");
gpr_free(arg->cb_user_data());
EXPECT_EQ(arg->success(), 1);
EXPECT_STREQ(arg->target_name().c_str(), "callback_target_name");
EXPECT_STREQ(arg->peer_cert().c_str(), "callback_peer_cert");
EXPECT_EQ(arg->status(), GRPC_STATUS_OK);
EXPECT_STREQ(arg->error_details().c_str(), "callback_error_details");
// Cleanup.
gpr_free(const_cast<char*>(target_name_before_callback));
gpr_free(const_cast<char*>(peer_cert_before_callback));
gpr_free(const_cast<char*>(error_details_before_callback));
gpr_free(const_cast<char*>(c_arg->target_name));
gpr_free(const_cast<char*>(c_arg->peer_cert));
gpr_free(const_cast<char*>(c_arg->error_details));
delete arg;
delete c_arg;
}
TEST_F(CredentialsTest, TlsServerAuthorizationCheckConfigSchedule) {
std::shared_ptr<TestTlsServerAuthorizationCheck>
test_server_authorization_check(new TestTlsServerAuthorizationCheck());
TlsServerAuthorizationCheckConfig config(test_server_authorization_check);
grpc_tls_server_authorization_check_arg* c_arg =
grpc_core::New<grpc_tls_server_authorization_check_arg>();
c_arg->context = nullptr;
TlsServerAuthorizationCheckArg* arg =
new TlsServerAuthorizationCheckArg(c_arg);
arg->set_cb_user_data(nullptr);
arg->set_success(0);
arg->set_target_name("target_name");
arg->set_peer_cert("peer_cert");
arg->set_status(GRPC_STATUS_PERMISSION_DENIED);
arg->set_error_details("error_details");
const char* target_name_before_schedule = c_arg->target_name;
const char* peer_cert_before_schedule = c_arg->peer_cert;
const char* error_details_before_schedule = c_arg->error_details;
int schedule_output = config.Schedule(arg);
EXPECT_EQ(schedule_output, 1);
EXPECT_STREQ(static_cast<char*>(arg->cb_user_data()), "cb_user_data");
EXPECT_EQ(arg->success(), 1);
EXPECT_STREQ(arg->target_name().c_str(), "sync_target_name");
EXPECT_STREQ(arg->peer_cert().c_str(), "sync_peer_cert");
EXPECT_EQ(arg->status(), GRPC_STATUS_OK);
EXPECT_STREQ(arg->error_details().c_str(), "sync_error_details");
// Cleanup.
gpr_free(arg->cb_user_data());
gpr_free(const_cast<char*>(target_name_before_schedule));
gpr_free(const_cast<char*>(peer_cert_before_schedule));
gpr_free(const_cast<char*>(error_details_before_schedule));
gpr_free(const_cast<char*>(c_arg->target_name));
gpr_free(const_cast<char*>(c_arg->peer_cert));
gpr_free(const_cast<char*>(c_arg->error_details));
if (c_arg->destroy_context != nullptr) {
c_arg->destroy_context(c_arg->context);
}
gpr_free(c_arg);
gpr_free(config.c_config());
}
TEST_F(CredentialsTest, TlsServerAuthorizationCheckConfigCppToC) {
std::shared_ptr<TestTlsServerAuthorizationCheck>
test_server_authorization_check(new TestTlsServerAuthorizationCheck());
TlsServerAuthorizationCheckConfig config(test_server_authorization_check);
grpc_tls_server_authorization_check_arg c_arg;
c_arg.cb = tls_server_authorization_check_callback;
c_arg.cb_user_data = nullptr;
c_arg.success = 0;
c_arg.target_name = "target_name";
c_arg.peer_cert = "peer_cert";
c_arg.status = GRPC_STATUS_UNAUTHENTICATED;
c_arg.error_details = "error_details";
c_arg.config = config.c_config();
c_arg.context = nullptr;
int c_schedule_output = (c_arg.config)->Schedule(&c_arg);
EXPECT_EQ(c_schedule_output, 1);
EXPECT_STREQ(static_cast<char*>(c_arg.cb_user_data), "cb_user_data");
EXPECT_EQ(c_arg.success, 1);
EXPECT_STREQ(c_arg.target_name, "sync_target_name");
EXPECT_STREQ(c_arg.peer_cert, "sync_peer_cert");
EXPECT_EQ(c_arg.status, GRPC_STATUS_OK);
EXPECT_STREQ(c_arg.error_details, "sync_error_details");
// Cleanup.
gpr_free(c_arg.cb_user_data);
c_arg.destroy_context(c_arg.context);
gpr_free(const_cast<char*>(c_arg.error_details));
gpr_free(const_cast<char*>(c_arg.target_name));
gpr_free(const_cast<char*>(c_arg.peer_cert));
gpr_free(config.c_config());
}
typedef class ::grpc_impl::experimental::TlsCredentialsOptions
TlsCredentialsOptions;
TEST_F(CredentialsTest, TlsCredentialsOptionsCppToC) {
std::shared_ptr<TlsKeyMaterialsConfig> key_materials_config(
new TlsKeyMaterialsConfig());
struct TlsKeyMaterialsConfig::PemKeyCertPair pair = {"private_key",
"cert_chain"};
std::vector<TlsKeyMaterialsConfig::PemKeyCertPair> pair_list = {pair};
key_materials_config->set_key_materials("pem_root_certs", pair_list);
std::shared_ptr<TestTlsCredentialReload> test_credential_reload(
new TestTlsCredentialReload());
std::shared_ptr<TlsCredentialReloadConfig> credential_reload_config(
new TlsCredentialReloadConfig(test_credential_reload));
std::shared_ptr<TestTlsServerAuthorizationCheck>
test_server_authorization_check(new TestTlsServerAuthorizationCheck());
std::shared_ptr<TlsServerAuthorizationCheckConfig>
server_authorization_check_config(new TlsServerAuthorizationCheckConfig(
test_server_authorization_check));
TlsCredentialsOptions options = TlsCredentialsOptions(
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY, key_materials_config,
credential_reload_config, server_authorization_check_config);
grpc_tls_credentials_options* c_options = options.c_credentials_options();
EXPECT_EQ(c_options->cert_request_type(),
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY);
grpc_tls_key_materials_config* c_key_materials_config =
c_options->key_materials_config();
grpc_tls_credential_reload_config* c_credential_reload_config =
c_options->credential_reload_config();
grpc_tls_credential_reload_arg c_credential_reload_arg;
c_credential_reload_arg.cb_user_data = nullptr;
c_credential_reload_arg.key_materials_config =
c_options->key_materials_config();
c_credential_reload_arg.status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED;
grpc::string test_error_details = "error_details";
c_credential_reload_arg.error_details = test_error_details.c_str();
c_credential_reload_arg.context = nullptr;
grpc_tls_server_authorization_check_config*
c_server_authorization_check_config =
c_options->server_authorization_check_config();
grpc_tls_server_authorization_check_arg c_server_authorization_check_arg;
c_server_authorization_check_arg.cb = tls_server_authorization_check_callback;
c_server_authorization_check_arg.cb_user_data = nullptr;
c_server_authorization_check_arg.success = 0;
c_server_authorization_check_arg.target_name = "target_name";
c_server_authorization_check_arg.peer_cert = "peer_cert";
c_server_authorization_check_arg.status = GRPC_STATUS_UNAUTHENTICATED;
c_server_authorization_check_arg.error_details = "error_details";
c_server_authorization_check_arg.context = nullptr;
EXPECT_STREQ(c_key_materials_config->pem_root_certs(), "pem_root_certs");
EXPECT_EQ(
static_cast<int>(c_key_materials_config->pem_key_cert_pair_list().size()),
1);
EXPECT_STREQ(
c_key_materials_config->pem_key_cert_pair_list()[0].private_key(),
"private_key");
EXPECT_STREQ(c_key_materials_config->pem_key_cert_pair_list()[0].cert_chain(),
"cert_chain");
GPR_ASSERT(c_credential_reload_config != nullptr);
int c_credential_reload_schedule_output =
c_credential_reload_config->Schedule(&c_credential_reload_arg);
EXPECT_EQ(c_credential_reload_schedule_output, 0);
EXPECT_EQ(c_credential_reload_arg.cb_user_data, nullptr);
EXPECT_STREQ(c_credential_reload_arg.key_materials_config->pem_root_certs(),
"new_pem_root_certs");
::grpc_core::InlinedVector<::grpc_core::PemKeyCertPair, 1> c_pair_list =
c_credential_reload_arg.key_materials_config->pem_key_cert_pair_list();
EXPECT_EQ(static_cast<int>(c_pair_list.size()), 2);
EXPECT_STREQ(c_pair_list[0].private_key(), "private_key");
EXPECT_STREQ(c_pair_list[0].cert_chain(), "cert_chain");
EXPECT_STREQ(c_pair_list[1].private_key(), "private_key3");
EXPECT_STREQ(c_pair_list[1].cert_chain(), "cert_chain3");
EXPECT_EQ(c_credential_reload_arg.status,
GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW);
EXPECT_STREQ(c_credential_reload_arg.error_details,
test_error_details.c_str());
int c_server_authorization_check_schedule_output =
c_server_authorization_check_config->Schedule(
&c_server_authorization_check_arg);
EXPECT_EQ(c_server_authorization_check_schedule_output, 1);
EXPECT_STREQ(
static_cast<char*>(c_server_authorization_check_arg.cb_user_data),
"cb_user_data");
EXPECT_EQ(c_server_authorization_check_arg.success, 1);
EXPECT_STREQ(c_server_authorization_check_arg.target_name,
"sync_target_name");
EXPECT_STREQ(c_server_authorization_check_arg.peer_cert, "sync_peer_cert");
EXPECT_EQ(c_server_authorization_check_arg.status, GRPC_STATUS_OK);
EXPECT_STREQ(c_server_authorization_check_arg.error_details,
"sync_error_details");
// Cleanup.
::grpc_core::Delete(c_credential_reload_arg.key_materials_config);
c_credential_reload_arg.destroy_context(c_credential_reload_arg.context);
c_server_authorization_check_arg.destroy_context(
c_server_authorization_check_arg.context);
gpr_free(c_server_authorization_check_arg.cb_user_data);
gpr_free(const_cast<char*>(c_server_authorization_check_arg.target_name));
gpr_free(const_cast<char*>(c_server_authorization_check_arg.peer_cert));
gpr_free(const_cast<char*>(c_server_authorization_check_arg.error_details));
::grpc_core::Delete(c_credential_reload_config);
::grpc_core::Delete(c_server_authorization_check_config);
gpr_free(c_options);
}
// This test demonstrates how the SPIFFE credentials will be used.
TEST_F(CredentialsTest, LoadSpiffeChannelCredentials) {
std::shared_ptr<TestTlsCredentialReload> test_credential_reload(
new TestTlsCredentialReload());
std::shared_ptr<TlsCredentialReloadConfig> credential_reload_config(
new TlsCredentialReloadConfig(test_credential_reload));
std::shared_ptr<TestTlsServerAuthorizationCheck>
test_server_authorization_check(new TestTlsServerAuthorizationCheck());
std::shared_ptr<TlsServerAuthorizationCheckConfig>
server_authorization_check_config(new TlsServerAuthorizationCheckConfig(
test_server_authorization_check));
TlsCredentialsOptions options = TlsCredentialsOptions(
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY, nullptr,
credential_reload_config, server_authorization_check_config);
std::shared_ptr<grpc_impl::ChannelCredentials> channel_credentials =
grpc::experimental::TlsCredentials(options);
GPR_ASSERT(channel_credentials != nullptr);
}
TEST_F(CredentialsTest, TlsCredentialReloadConfigErrorMessages) {
std::shared_ptr<TlsCredentialReloadConfig> config(
new TlsCredentialReloadConfig(nullptr));
grpc_tls_credential_reload_arg* c_arg = new grpc_tls_credential_reload_arg;
c_arg->context = nullptr;
TlsCredentialReloadArg* arg = new TlsCredentialReloadArg(c_arg);
int schedule_output = config->Schedule(arg);
EXPECT_EQ(schedule_output, 1);
EXPECT_EQ(arg->status(), GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL);
EXPECT_STREQ(arg->error_details().c_str(),
"the interface of the credential reload config is nullptr");
gpr_free(const_cast<char*>(c_arg->error_details));
arg->set_status(GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED);
config->Cancel(arg);
EXPECT_EQ(arg->status(), GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL);
EXPECT_STREQ(arg->error_details().c_str(),
"the interface of the credential reload config is nullptr");
// Cleanup.
gpr_free(const_cast<char*>(c_arg->error_details));
if (c_arg->destroy_context != nullptr) {
c_arg->destroy_context(c_arg->context);
}
delete c_arg;
gpr_free(config->c_config());
}
TEST_F(CredentialsTest, TlsServerAuthorizationCheckConfigErrorMessages) {
std::shared_ptr<TlsServerAuthorizationCheckConfig> config(
new TlsServerAuthorizationCheckConfig(nullptr));
grpc_tls_server_authorization_check_arg* c_arg =
new grpc_tls_server_authorization_check_arg;
c_arg->context = nullptr;
TlsServerAuthorizationCheckArg* arg =
new TlsServerAuthorizationCheckArg(c_arg);
int schedule_output = config->Schedule(arg);
EXPECT_EQ(schedule_output, 1);
EXPECT_EQ(arg->status(), GRPC_STATUS_NOT_FOUND);
EXPECT_STREQ(
arg->error_details().c_str(),
"the interface of the server authorization check config is nullptr");
gpr_free(const_cast<char*>(c_arg->error_details));
arg->set_status(GRPC_STATUS_OK);
config->Cancel(arg);
EXPECT_EQ(arg->status(), GRPC_STATUS_NOT_FOUND);
EXPECT_STREQ(
arg->error_details().c_str(),
"the interface of the server authorization check config is nullptr");
// Cleanup.
gpr_free(const_cast<char*>(c_arg->error_details));
if (c_arg->destroy_context != nullptr) {
c_arg->destroy_context(c_arg->context);
}
delete c_arg;
gpr_free(config->c_config());
}
} // namespace testing
} // namespace grpc

@ -508,6 +508,10 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
"//test/cpp/util:test_util",
],
data = [
"xds_bootstrap.json",
"xds_bootstrap_bad.json",
],
tags = ["no_windows"], # TODO(jtattermusch): fix test on windows
)

@ -0,0 +1,22 @@
{
"xds_server": {
"server_uri": "fake:///lb",
"channel_creds": [
{
"type": "fake"
}
]
},
"node": {
"id": "xds_end2end_test",
"cluster": "test",
"metadata": {
"foo": "bar"
},
"locality": {
"region": "corp",
"zone": "svl",
"subzone": "mp3"
}
}
}

@ -0,0 +1,12 @@
{
"xds_server": {
"server_uri": "fake:///wrong_lb",
"channel_creds": [
{
"type": "fake"
}
]
},
"node": {
}
}

@ -536,6 +536,7 @@ class XdsEnd2endTest : public ::testing::Test {
static void TearDownTestCase() { grpc_shutdown(); }
void SetUp() override {
gpr_setenv("GRPC_XDS_BOOTSTRAP", "test/cpp/end2end/xds_bootstrap.json");
response_generator_ =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
lb_channel_response_generator_ =
@ -664,7 +665,7 @@ class XdsEnd2endTest : public ::testing::Test {
gpr_log(GPR_INFO, "========= BACKEND %lu READY ==========", backend_idx);
}
grpc_core::ServerAddressList CreateLbAddressesFromPortList(
grpc_core::ServerAddressList CreateAddressListFromPortList(
const std::vector<int>& ports) {
grpc_core::ServerAddressList addresses;
for (int port : ports) {
@ -674,10 +675,7 @@ class XdsEnd2endTest : public ::testing::Test {
GPR_ASSERT(lb_uri != nullptr);
grpc_resolved_address address;
GPR_ASSERT(grpc_parse_uri(lb_uri, &address));
std::vector<grpc_arg> args_to_add;
grpc_channel_args* args = grpc_channel_args_copy_and_add(
nullptr, args_to_add.data(), args_to_add.size());
addresses.emplace_back(address.addr, address.len, args);
addresses.emplace_back(address.addr, address.len, nullptr);
grpc_uri_destroy(lb_uri);
gpr_free(lb_uri_str);
}
@ -690,7 +688,7 @@ class XdsEnd2endTest : public ::testing::Test {
lb_channel_response_generator = nullptr) {
grpc_core::ExecCtx exec_ctx;
grpc_core::Resolver::Result result;
result.addresses = CreateLbAddressesFromPortList(ports);
result.addresses = CreateAddressListFromPortList(ports);
if (service_config_json != nullptr) {
grpc_error* error = GRPC_ERROR_NONE;
result.service_config =
@ -723,7 +721,7 @@ class XdsEnd2endTest : public ::testing::Test {
nullptr) {
grpc_core::ExecCtx exec_ctx;
grpc_core::Resolver::Result result;
result.addresses = CreateLbAddressesFromPortList(ports);
result.addresses = CreateAddressListFromPortList(ports);
if (service_config_json != nullptr) {
grpc_error* error = GRPC_ERROR_NONE;
result.service_config =
@ -739,7 +737,7 @@ class XdsEnd2endTest : public ::testing::Test {
void SetNextReresolutionResponse(const std::vector<int>& ports) {
grpc_core::ExecCtx exec_ctx;
grpc_core::Resolver::Result result;
result.addresses = CreateLbAddressesFromPortList(ports);
result.addresses = CreateAddressListFromPortList(ports);
response_generator_->SetReresolutionResponse(std::move(result));
}
@ -916,7 +914,7 @@ class XdsEnd2endTest : public ::testing::Test {
"{\n"
" \"loadBalancingConfig\":[\n"
" { \"does_not_exist\":{} },\n"
" { \"xds_experimental\":{ \"balancerName\": \"fake:///lb\" } }\n"
" { \"xds_experimental\":{} }\n"
" ]\n"
"}";
};
@ -1101,20 +1099,14 @@ TEST_F(SecureNamingTest, TargetNameIsExpected) {
// Tests that secure naming check fails if target name is unexpected.
TEST_F(SecureNamingTest, TargetNameIsUnexpected) {
gpr_setenv("GRPC_XDS_BOOTSTRAP", "test/cpp/end2end/xds_bootstrap_bad.json");
::testing::FLAGS_gtest_death_test_style = "threadsafe";
// Make sure that we blow up (via abort() from the security connector) when
// the name from the balancer doesn't match expectations.
ASSERT_DEATH_IF_SUPPORTED(
{
ResetStub(0, 0, kApplicationTargetName_ + ";lb");
SetNextResolution({},
"{\n"
" \"loadBalancingConfig\":[\n"
" { \"does_not_exist\":{} },\n"
" { \"xds_experimental\":{ \"balancerName\": "
"\"fake:///wrong_lb\" } }\n"
" ]\n"
"}");
SetNextResolution({}, kDefaultServiceConfig_.c_str());
SetNextResolutionForLbChannel({balancers_[0]->port()});
channel_->WaitForConnected(grpc_timeout_seconds_to_deadline(1));
},

@ -118,6 +118,20 @@ static double ServerIdleCpuTime(const ServerStats& s) {
}
static int Cores(int n) { return n; }
static bool IsSuccess(const Status& s) {
if (s.ok()) return true;
// Since we shutdown servers and clients at the same time, they both can
// observe cancellation. Thus, we consider CANCELLED as good status.
if (static_cast<StatusCode>(s.error_code()) == StatusCode::CANCELLED) {
return true;
}
// Since we shutdown servers and clients at the same time, server can close
// the socket before the client attempts to do that, and vice versa. Thus
// receiving a "Socket closed" error is fine.
if (s.error_message() == "Socket closed") return true;
return false;
}
// Postprocess ScenarioResult and populate result summary.
static void postprocess_scenario_result(ScenarioResult* result) {
Histogram histogram;
@ -495,8 +509,12 @@ std::unique_ptr<ScenarioResult> RunScenario(
for (size_t i = 0; i < num_clients; i++) {
auto client = &clients[i];
Status s = client->stream->Finish();
result->add_client_success(s.ok());
if (!s.ok()) {
// Since we shutdown servers and clients at the same time, clients can
// observe cancellation. Thus, we consider both OK and CANCELLED as good
// status.
const bool success = IsSuccess(s);
result->add_client_success(success);
if (!success) {
gpr_log(GPR_ERROR, "Client %zu had an error %s", i,
s.error_message().c_str());
}
@ -526,8 +544,12 @@ std::unique_ptr<ScenarioResult> RunScenario(
for (size_t i = 0; i < num_servers; i++) {
auto server = &servers[i];
Status s = server->stream->Finish();
result->add_server_success(s.ok());
if (!s.ok()) {
// Since we shutdown servers and clients at the same time, servers can
// observe cancellation. Thus, we consider both OK and CANCELLED as good
// status.
const bool success = IsSuccess(s);
result->add_server_success(success);
if (!success) {
gpr_log(GPR_ERROR, "Server %zu had an error %s", i,
s.error_message().c_str());
}

@ -0,0 +1,66 @@
#!/bin/bash
# Copyright 2017 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -ex
cd "$(dirname "$0")/../../.."
echo "deb http://archive.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf
sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list
apt-get update
apt-get install -t jessie-backports -y libssl-dev pkg-config
# Install c-ares
cd third_party/cares/cares
git fetch origin
git checkout cares-1_15_0
mkdir -p cmake/build
cd cmake/build
cmake -DCMAKE_BUILD_TYPE=Release ../..
make -j4 install
cd ../../../../..
rm -rf third_party/cares/cares # wipe out to prevent influencing the grpc build
# Install zlib
cd third_party/zlib
mkdir -p cmake/build
cd cmake/build
cmake -DCMAKE_BUILD_TYPE=Release ../..
make -j4 install
cd ../../../..
rm -rf third_party/zlib # wipe out to prevent influencing the grpc build
# Install protobuf
cd third_party/protobuf
mkdir -p cmake/build
cd cmake/build
cmake -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release ..
make -j4 install
cd ../../../..
rm -rf third_party/protobuf # wipe out to prevent influencing the grpc build
# Install gRPC
mkdir -p cmake/build
cd cmake/build
cmake -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DgRPC_PROTOBUF_PROVIDER=package -DgRPC_ZLIB_PROVIDER=package -DgRPC_CARES_PROVIDER=package -DgRPC_SSL_PROVIDER=package -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/grpc ../..
make -j4 install
cd ../..
# Build helloworld example using Makefiles and pkg-config
cd examples/cpp/helloworld
export PKG_CONFIG_PATH=/usr/local/grpc/lib/pkgconfig
export PATH=$PATH:/usr/local/grpc/bin
make

@ -12,6 +12,9 @@ build:opt --copt=-Wframe-larger-than=16384
build:dbg --compilation_mode=dbg
build:windows_opt --compilation_mode=opt
build:windows_dbg --compilation_mode=dbg
build:asan --strip=never
build:asan --copt=-fsanitize=address
build:asan --copt=-O0

@ -84,7 +84,7 @@ RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get cl
# Python AuditWheel dependencies (needed to check manylinux1 compatibility)
RUN apt-get install -y python3 python3-pip
RUN pip3 install auditwheel==1.10.0
RUN pip3 install auditwheel==2.1.1
RUN mkdir /var/local/jenkins

@ -77,7 +77,7 @@ RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get cl
# Python AuditWheel dependencies (needed to check manylinux1 compatibility)
RUN apt-get install -y python3 python3-pip
RUN pip3 install auditwheel==1.10.0
RUN pip3 install auditwheel==2.1.1
RUN mkdir /var/local/jenkins

@ -28,11 +28,4 @@ RUN /opt/python/cp34-cp34m/bin/pip install cython
RUN /opt/python/cp35-cp35m/bin/pip install cython
RUN /opt/python/cp36-cp36m/bin/pip install cython
RUN /opt/python/cp37-cp37m/bin/pip install cython
####################################################
# Install auditwheel with fix for namespace packages
RUN git clone https://github.com/pypa/auditwheel /usr/local/src/auditwheel
RUN cd /usr/local/src/auditwheel && git checkout 2.1
RUN /opt/python/cp36-cp36m/bin/pip install /usr/local/src/auditwheel
RUN rm /usr/local/bin/auditwheel
RUN cd /usr/local/bin && ln -s /opt/python/cp36-cp36m/bin/auditwheel
RUN /opt/python/cp38-cp38/bin/pip install cython

@ -28,12 +28,5 @@ RUN /opt/python/cp34-cp34m/bin/pip install cython
RUN /opt/python/cp35-cp35m/bin/pip install cython
RUN /opt/python/cp36-cp36m/bin/pip install cython
RUN /opt/python/cp37-cp37m/bin/pip install cython
####################################################
# Install auditwheel with fix for namespace packages
RUN git clone https://github.com/pypa/auditwheel /usr/local/src/auditwheel
RUN cd /usr/local/src/auditwheel && git checkout 2.1
RUN /opt/python/cp36-cp36m/bin/pip install /usr/local/src/auditwheel
RUN rm /usr/local/bin/auditwheel
RUN cd /usr/local/bin && ln -s /opt/python/cp36-cp36m/bin/auditwheel
RUN /opt/python/cp37-cp37m/bin/pip install cython
RUN /opt/python/cp38-cp38/bin/pip install cython

@ -28,11 +28,5 @@ RUN /opt/python/cp34-cp34m/bin/pip install cython
RUN /opt/python/cp35-cp35m/bin/pip install cython
RUN /opt/python/cp36-cp36m/bin/pip install cython
RUN /opt/python/cp37-cp37m/bin/pip install cython
####################################################
# Install auditwheel with fix for namespace packages
RUN git clone https://github.com/pypa/auditwheel /usr/local/src/auditwheel
RUN cd /usr/local/src/auditwheel && git checkout 2.1
RUN /opt/python/cp36-cp36m/bin/pip install /usr/local/src/auditwheel
RUN rm /usr/local/bin/auditwheel
RUN cd /usr/local/bin && ln -s /opt/python/cp36-cp36m/bin/auditwheel
RUN /opt/python/cp37-cp37m/bin/pip install cython
RUN /opt/python/cp38-cp38/bin/pip install cython

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

Loading…
Cancel
Save