[chaotic-good] Connection setup & test suites (#35650)

Closes #35650

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35650 from ctiller:shush-tsan fd55ea1be3
PiperOrigin-RevId: 601221780
pull/35630/head^2
Craig Tiller 1 year ago committed by Copybara-Service
parent 7d5b53e2a7
commit 870a66d9a0
  1. 189
      CMakeLists.txt
  2. 143
      build_autogenerated.yaml
  3. 131
      src/core/BUILD
  4. 328
      src/core/ext/transport/chaotic_good/client/chaotic_good_connector.cc
  5. 114
      src/core/ext/transport/chaotic_good/client/chaotic_good_connector.h
  6. 24
      src/core/ext/transport/chaotic_good/frame.cc
  7. 1
      src/core/ext/transport/chaotic_good/frame.h
  8. 410
      src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc
  9. 202
      src/core/ext/transport/chaotic_good/server/chaotic_good_server.h
  10. 13
      src/core/ext/transport/chaotic_good/server_transport.cc
  11. 81
      src/core/ext/transport/chaotic_good/settings_metadata.cc
  12. 46
      src/core/ext/transport/chaotic_good/settings_metadata.h
  13. 59
      src/core/lib/promise/inter_activity_latch.h
  14. 2
      src/core/lib/resource_quota/memory_quota.cc
  15. 4
      src/core/lib/transport/metadata_batch.h
  16. 40
      test/core/end2end/fuzzers/BUILD
  17. 1
      test/core/end2end/fuzzers/network_input.cc
  18. 39
      test/core/end2end/fuzzers/server_fuzzer.cc
  19. 34
      test/core/end2end/fuzzers/server_fuzzer.h
  20. 36
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good.cc
  21. 5
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/0d935c3f36dacec03424c94df1abb0c620eb43fc
  22. 4
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/112d7775db5f5a752656a0a6247aadbef3419946
  23. 6
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/2e47637f02f17049d62d8ab39ccc76c357361751
  24. 6
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/2e7f50a50c066bad5205820ca70b5e06edbd6251
  25. 2
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/63183371a4703b1d50738759d24b6e4e9bc4a8a5
  26. 4
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/78def83352dae155ccfb6911755df930ec448d34
  27. 2
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/7dcd04438cf570ee85613752fa82fde0f6e27d48
  28. 2
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/8058271eb5ffed8fff7a50befc56b425518e42b5
  29. 6
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/832a708b602494e209027f25e45dc2ab9946b1c1
  30. 6
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/b184a899e1be9f324b0f2c2ec87e9719745ff2c0
  31. 5
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/bf15b8e03b2fdf07739ac5a02f20fe7763f6652e
  32. 3
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/cb4d4bb3651d49274363e32c0fd49893598efc2e
  33. 25
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-30518a29ab7cbc598c50d9aba0802f3f5d051507
  34. 5
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-37ee262ad3d3c94d4984ceab893527b62a76b8a0
  35. 20
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-389fb72510e4ae5efc13b96633da23db10831deb
  36. 17
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-3a2038d846f69d4be1bd5cbf0ec7864b7aa3e3db
  37. 12
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-411add0df93f4fb59fbd16d1157552910d7534ac
  38. 10
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-4708c969d581643a3dce5e90db59a214fa387e7b
  39. 14
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-490c27d5994e4a9f12780652d21052489add16ef
  40. 22
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-619070feb030f2f634343590f251552c8ae72278
  41. 40
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-67c0832c302f2b427006e0c37535972ee19a13ca
  42. 17
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-6b3d50b5d9e0dce2c250933b7d124e75558480e4
  43. 13
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-8f2a8efbd591bddcf19a1daa5c0231fdc8ad31ce
  44. 8
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-9503132635a1b666a17e1a5cc460d02d44ba1722
  45. 5
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-96da1815a45dffe533b9c49ce0802caba7990cb6
  46. 13
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-97c27b69d3f53f442778d6f8b54c3d6eeeedfe5b
  47. 7
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-adec385a8091220a7ad6f29b06af1abf4adf8222
  48. 16
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-bcaa4c143d75f0d13ccc39848ce3e0b7763574b6
  49. 34
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-c0240769ff7f73f4be4765f56cb5a6525e2bee23
  50. 5
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-c7ee9adac4e4e59269e6156d33b773c70bb999ff
  51. 10
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-d45aa4d5864d2b0fb477c62e8934863225c689cc
  52. 8
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-d6e88b7c2c76062614175fcf5ed49a8707521c73
  53. 14
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-dd2b30811e8fbb98317592cb776128651d21df37
  54. 7
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-dfb6d257affc96916aacff29d0903d90c28600fa
  55. 11
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-f3dc83113ea4f43e64f727a37329710d24de13d1
  56. 14
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-f58f6bd63c48cab9a9ac01a27002fa0b57d8c6fd
  57. 11
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/crash-feadabfcfa2ff0e25487ed1734492ba09d5443e4
  58. 2
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/d1e68bd6df3dbd06b1601548d3010a9588b446f5
  59. 4
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/e8e95ee5b19d31634258383e91e156f6d121c0ae
  60. 1
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/empty
  61. 6
      test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus/fa1183de2ea3019dafe50f468197a27403c74d56
  62. 28
      test/core/end2end/fuzzers/server_fuzzer_chttp2.cc
  63. 0
      test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus/5098656614121472
  64. 0
      test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus/5250991764078592
  65. 0
      test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus/5367317597847552
  66. 0
      test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus/cancel-request.bin
  67. 0
      test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus/cancel-timeout-request.bin
  68. 0
      test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus/timeout-request.bin
  69. 31
      test/core/transport/chaotic_good/BUILD
  70. 149
      test/core/transport/chaotic_good/chaotic_good_server_test.cc
  71. 54
      tools/run_tests/generated/tests.json

189
CMakeLists.txt generated

@ -823,6 +823,12 @@ protobuf_generate_grpc_cpp_with_import_path_correction(
protobuf_generate_grpc_cpp_with_import_path_correction(
src/proto/grpc/testing/xds/v3/wrr_locality.proto src/proto/grpc/testing/xds/v3/wrr_locality.proto
)
protobuf_generate_grpc_cpp_with_import_path_correction(
test/core/end2end/fuzzers/api_fuzzer.proto test/core/end2end/fuzzers/api_fuzzer.proto
)
protobuf_generate_grpc_cpp_with_import_path_correction(
test/core/end2end/fuzzers/fuzzer_input.proto test/core/end2end/fuzzers/fuzzer_input.proto
)
protobuf_generate_grpc_cpp_with_import_path_correction(
test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto
)
@ -835,6 +841,9 @@ protobuf_generate_grpc_cpp_with_import_path_correction(
protobuf_generate_grpc_cpp_with_import_path_correction(
test/core/util/fuzz_config_vars.proto test/core/util/fuzz_config_vars.proto
)
protobuf_generate_grpc_cpp_with_import_path_correction(
test/core/util/fuzzing_channel_args.proto test/core/util/fuzzing_channel_args.proto
)
if(gRPC_BUILD_TESTS)
add_custom_target(buildtests_c)
@ -1335,6 +1344,12 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx server_context_test_spouse_test)
add_dependencies(buildtests_cxx server_early_return_test)
add_dependencies(buildtests_cxx server_finishes_request_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx server_fuzzer_chaotic_good)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx server_fuzzer_chttp2)
endif()
add_dependencies(buildtests_cxx server_interceptors_end2end_test)
add_dependencies(buildtests_cxx server_registered_method_bad_client_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -26046,6 +26061,180 @@ target_link_libraries(server_finishes_request_test
)
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(server_fuzzer_chaotic_good
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/api_fuzzer.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/api_fuzzer.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/api_fuzzer.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/api_fuzzer.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/fuzzer_input.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/fuzzer_input.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/fuzzer_input.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/fuzzer_input.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzz_config_vars.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzz_config_vars.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzz_config_vars.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzz_config_vars.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzzing_channel_args.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzzing_channel_args.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzzing_channel_args.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzzing_channel_args.grpc.pb.h
src/core/ext/transport/chaotic_good/frame.cc
src/core/ext/transport/chaotic_good/frame_header.cc
src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc
src/core/ext/transport/chaotic_good/settings_metadata.cc
src/core/lib/transport/promise_endpoint.cc
test/core/end2end/fuzzers/fuzzing_common.cc
test/core/end2end/fuzzers/network_input.cc
test/core/end2end/fuzzers/server_fuzzer.cc
test/core/end2end/fuzzers/server_fuzzer_chaotic_good.cc
test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc
test/core/util/cmdline.cc
test/core/util/fuzz_config_vars.cc
test/core/util/fuzz_config_vars_helpers.cc
test/core/util/fuzzer_corpus_test.cc
test/core/util/fuzzer_util.cc
test/core/util/fuzzing_channel_args.cc
test/core/util/grpc_profiler.cc
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(server_fuzzer_chaotic_good
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(server_fuzzer_chaotic_good PUBLIC cxx_std_14)
target_include_directories(server_fuzzer_chaotic_good
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(server_fuzzer_chaotic_good
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
${_gRPC_PROTOBUF_LIBRARIES}
grpc_test_util
grpc++_test_config
)
endif()
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(server_fuzzer_chttp2
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/api_fuzzer.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/api_fuzzer.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/api_fuzzer.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/api_fuzzer.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/fuzzer_input.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/fuzzer_input.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/fuzzer_input.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/end2end/fuzzers/fuzzer_input.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzz_config_vars.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzz_config_vars.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzz_config_vars.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzz_config_vars.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzzing_channel_args.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzzing_channel_args.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzzing_channel_args.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/util/fuzzing_channel_args.grpc.pb.h
src/core/ext/transport/chaotic_good/frame_header.cc
test/core/end2end/fuzzers/fuzzing_common.cc
test/core/end2end/fuzzers/network_input.cc
test/core/end2end/fuzzers/server_fuzzer.cc
test/core/end2end/fuzzers/server_fuzzer_chttp2.cc
test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc
test/core/util/cmdline.cc
test/core/util/fuzz_config_vars.cc
test/core/util/fuzz_config_vars_helpers.cc
test/core/util/fuzzer_corpus_test.cc
test/core/util/fuzzer_util.cc
test/core/util/fuzzing_channel_args.cc
test/core/util/grpc_profiler.cc
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(server_fuzzer_chttp2
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(server_fuzzer_chttp2 PUBLIC cxx_std_14)
target_include_directories(server_fuzzer_chttp2
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(server_fuzzer_chttp2
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
${_gRPC_PROTOBUF_LIBRARIES}
grpc_test_util
grpc++_test_config
)
endif()
endif()
if(gRPC_BUILD_TESTS)

@ -15358,6 +15358,149 @@ targets:
- grpc_authorization_provider
- grpc_unsecure
- grpc_test_util
- name: server_fuzzer_chaotic_good
gtest: true
build: test
language: c++
headers:
- src/core/ext/transport/chaotic_good/frame.h
- src/core/ext/transport/chaotic_good/frame_header.h
- src/core/ext/transport/chaotic_good/server/chaotic_good_server.h
- src/core/ext/transport/chaotic_good/settings_metadata.h
- src/core/lib/promise/event_engine_wakeup_scheduler.h
- src/core/lib/promise/inter_activity_latch.h
- src/core/lib/promise/wait_set.h
- src/core/lib/transport/promise_endpoint.h
- test/core/end2end/fuzzers/fuzzing_common.h
- test/core/end2end/fuzzers/network_input.h
- test/core/end2end/fuzzers/server_fuzzer.h
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h
- test/core/util/cmdline.h
- test/core/util/evaluate_args_test_util.h
- test/core/util/fuzz_config_vars.h
- test/core/util/fuzz_config_vars_helpers.h
- test/core/util/fuzzer_util.h
- test/core/util/fuzzing_channel_args.h
- test/core/util/grpc_profiler.h
- test/core/util/histogram.h
- test/core/util/mock_authorization_endpoint.h
- test/core/util/mock_endpoint.h
- test/core/util/parse_hexstring.h
- test/core/util/passthru_endpoint.h
- test/core/util/resolve_localhost_ip46.h
- test/core/util/slice_splitter.h
- test/core/util/tracer_util.h
src:
- test/core/end2end/fuzzers/api_fuzzer.proto
- test/core/end2end/fuzzers/fuzzer_input.proto
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto
- test/core/util/fuzz_config_vars.proto
- test/core/util/fuzzing_channel_args.proto
- src/core/ext/transport/chaotic_good/frame.cc
- src/core/ext/transport/chaotic_good/frame_header.cc
- src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc
- src/core/ext/transport/chaotic_good/settings_metadata.cc
- src/core/lib/transport/promise_endpoint.cc
- test/core/end2end/fuzzers/fuzzing_common.cc
- test/core/end2end/fuzzers/network_input.cc
- test/core/end2end/fuzzers/server_fuzzer.cc
- test/core/end2end/fuzzers/server_fuzzer_chaotic_good.cc
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc
- test/core/util/cmdline.cc
- test/core/util/fuzz_config_vars.cc
- test/core/util/fuzz_config_vars_helpers.cc
- test/core/util/fuzzer_corpus_test.cc
- test/core/util/fuzzer_util.cc
- test/core/util/fuzzing_channel_args.cc
- test/core/util/grpc_profiler.cc
- test/core/util/histogram.cc
- test/core/util/mock_endpoint.cc
- test/core/util/parse_hexstring.cc
- test/core/util/passthru_endpoint.cc
- test/core/util/resolve_localhost_ip46.cc
- test/core/util/slice_splitter.cc
- test/core/util/tracer_util.cc
deps:
- gtest
- protobuf
- grpc_test_util
- grpc++_test_config
args:
- test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus
- -runs=20000
- -max_total_time=300
- --directory=test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus
platforms:
- linux
- posix
- mac
uses_polling: false
- name: server_fuzzer_chttp2
gtest: true
build: test
language: c++
headers:
- src/core/ext/transport/chaotic_good/frame_header.h
- test/core/end2end/fuzzers/fuzzing_common.h
- test/core/end2end/fuzzers/network_input.h
- test/core/end2end/fuzzers/server_fuzzer.h
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h
- test/core/util/cmdline.h
- test/core/util/evaluate_args_test_util.h
- test/core/util/fuzz_config_vars.h
- test/core/util/fuzz_config_vars_helpers.h
- test/core/util/fuzzer_util.h
- test/core/util/fuzzing_channel_args.h
- test/core/util/grpc_profiler.h
- test/core/util/histogram.h
- test/core/util/mock_authorization_endpoint.h
- test/core/util/mock_endpoint.h
- test/core/util/parse_hexstring.h
- test/core/util/passthru_endpoint.h
- test/core/util/resolve_localhost_ip46.h
- test/core/util/slice_splitter.h
- test/core/util/tracer_util.h
src:
- test/core/end2end/fuzzers/api_fuzzer.proto
- test/core/end2end/fuzzers/fuzzer_input.proto
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto
- test/core/util/fuzz_config_vars.proto
- test/core/util/fuzzing_channel_args.proto
- src/core/ext/transport/chaotic_good/frame_header.cc
- test/core/end2end/fuzzers/fuzzing_common.cc
- test/core/end2end/fuzzers/network_input.cc
- test/core/end2end/fuzzers/server_fuzzer.cc
- test/core/end2end/fuzzers/server_fuzzer_chttp2.cc
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc
- test/core/util/cmdline.cc
- test/core/util/fuzz_config_vars.cc
- test/core/util/fuzz_config_vars_helpers.cc
- test/core/util/fuzzer_corpus_test.cc
- test/core/util/fuzzer_util.cc
- test/core/util/fuzzing_channel_args.cc
- test/core/util/grpc_profiler.cc
- test/core/util/histogram.cc
- test/core/util/mock_endpoint.cc
- test/core/util/parse_hexstring.cc
- test/core/util/passthru_endpoint.cc
- test/core/util/resolve_localhost_ip46.cc
- test/core/util/slice_splitter.cc
- test/core/util/tracer_util.cc
deps:
- gtest
- protobuf
- grpc_test_util
- grpc++_test_config
args:
- test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus
- -runs=20000
- -max_total_time=300
- --directory=test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus
platforms:
- linux
- posix
- mac
uses_polling: false
- name: server_interceptors_end2end_test
gtest: true
build: test

@ -6371,6 +6371,25 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "chaotic_good_settings_metadata",
srcs = [
"ext/transport/chaotic_good/settings_metadata.cc",
],
hdrs = [
"ext/transport/chaotic_good/settings_metadata.h",
],
external_deps = [
"absl/status",
"absl/types:optional",
],
deps = [
"arena",
"metadata_batch",
"//:gpr",
],
)
grpc_cc_library(
name = "chaotic_good_frame_header",
srcs = [
@ -6627,6 +6646,7 @@ grpc_cc_library(
"chaotic_good_transport",
"context",
"default_event_engine",
"error_utils",
"event_engine_wakeup_scheduler",
"for_each",
"grpc_promise_endpoint",
@ -6825,6 +6845,117 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "chaotic_good_server",
srcs = [
"ext/transport/chaotic_good/server/chaotic_good_server.cc",
],
hdrs = [
"ext/transport/chaotic_good/server/chaotic_good_server.h",
],
external_deps = [
"absl/container:flat_hash_map",
"absl/random",
"absl/random:bit_gen_ref",
"absl/status",
"absl/status:statusor",
],
language = "c++",
deps = [
"activity",
"arena",
"channel_args",
"channel_args_endpoint_config",
"chaotic_good_frame",
"chaotic_good_frame_header",
"chaotic_good_settings_metadata",
"closure",
"context",
"default_event_engine",
"error",
"event_engine_tcp_socket_utils",
"event_engine_wakeup_scheduler",
"grpc_promise_endpoint",
"if",
"inter_activity_latch",
"iomgr_fwd",
"latch",
"memory_quota",
"metadata",
"metadata_batch",
"race",
"resource_quota",
"sleep",
"slice",
"slice_buffer",
"status_helper",
"time",
"try_seq",
"//:gpr",
"//:gpr_platform",
"//:grpc_base",
"//:handshaker",
"//:hpack_encoder",
"//:hpack_parser",
"//:orphanable",
"//:ref_counted_ptr",
],
)
grpc_cc_library(
name = "chaotic_good_connector",
srcs = [
"ext/transport/chaotic_good/client/chaotic_good_connector.cc",
],
hdrs = [
"ext/transport/chaotic_good/client/chaotic_good_connector.h",
],
external_deps = [
"absl/random",
"absl/random:bit_gen_ref",
"absl/status",
"absl/status:statusor",
],
language = "c++",
deps = [
"activity",
"arena",
"channel_args",
"channel_args_endpoint_config",
"chaotic_good_frame",
"chaotic_good_frame_header",
"chaotic_good_settings_metadata",
"closure",
"context",
"default_event_engine",
"error",
"event_engine_wakeup_scheduler",
"grpc_promise_endpoint",
"latch",
"memory_quota",
"metadata_batch",
"notification",
"race",
"resource_quota",
"sleep",
"slice",
"slice_buffer",
"time",
"try_seq",
"wait_for_callback",
"//:debug_location",
"//:exec_ctx",
"//:gpr",
"//:gpr_platform",
"//:grpc_base",
"//:grpc_client_channel",
"//:handshaker",
"//:hpack_encoder",
"//:hpack_parser",
"//:ref_counted_ptr",
],
)
### UPB Targets
grpc_upb_proto_library(

@ -0,0 +1,328 @@
// Copyright 2024 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/transport/chaotic_good/client/chaotic_good_connector.h"
#include <cstdint>
#include <memory>
#include <utility>
#include "absl/random/bit_gen_ref.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include <grpc/event_engine/event_engine.h>
#include "src/core/ext/transport/chaotic_good/frame.h"
#include "src/core/ext/transport/chaotic_good/frame_header.h"
#include "src/core/ext/transport/chaotic_good/settings_metadata.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/event_engine/channel_args_endpoint_config.h"
#include "src/core/lib/event_engine/default_event_engine.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/event_engine_shims/endpoint.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/event_engine_wakeup_scheduler.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/race.h"
#include "src/core/lib/promise/sleep.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/promise/wait_for_callback.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/resource_quota/resource_quota.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/transport/handshaker.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/promise_endpoint.h"
namespace grpc_core {
namespace chaotic_good {
using grpc_event_engine::experimental::EventEngine;
namespace {
void MaybeNotify(const DebugLocation& location, grpc_closure*& notify,
grpc_error_handle error) {
if (notify != nullptr) {
ExecCtx exec_ctx;
ExecCtx::Run(location, std::exchange(notify, nullptr), error);
}
}
const int32_t kDataAlignmentBytes = 64;
const int32_t kTimeoutSecs = 5;
} // namespace
ChaoticGoodConnector::ChaoticGoodConnector(
std::shared_ptr<grpc_event_engine::experimental::EventEngine> event_engine)
: event_engine_(std::move(event_engine)),
handshake_mgr_(std::make_shared<HandshakeManager>()),
data_endpoint_latch_(
std::make_shared<Latch<std::shared_ptr<PromiseEndpoint>>>()),
wait_for_data_endpoint_callback_(std::make_shared<WaitForCallback>()) {
channel_args_ = channel_args_.SetObject(event_engine_);
channel_args_ =
channel_args_.Set(GRPC_ARG_RESOURCE_QUOTA, ResourceQuota::Default());
}
ChaoticGoodConnector::~ChaoticGoodConnector() {
if (connect_activity_ != nullptr) {
connect_activity_.reset();
}
}
auto ChaoticGoodConnector::DataEndpointReadSettingsFrame(
RefCountedPtr<ChaoticGoodConnector> self) {
GPR_ASSERT(self->data_endpoint_ != nullptr);
return TrySeq(
self->data_endpoint_->ReadSlice(FrameHeader::kFrameHeaderSize),
[self](Slice slice) mutable {
// Read setting frame;
// Parse frame header
GPR_ASSERT(self->data_endpoint_ != nullptr);
auto frame_header_ =
FrameHeader::Parse(reinterpret_cast<const uint8_t*>(
GRPC_SLICE_START_PTR(slice.c_slice())));
return If(
frame_header_.ok(),
[frame_header_ = *frame_header_, self]() {
auto frame_header_length = frame_header_.GetFrameLength();
return TrySeq(self->data_endpoint_->Read(frame_header_length),
[]() { return absl::OkStatus(); });
},
[status = frame_header_.status()]() { return status; });
});
}
auto ChaoticGoodConnector::DataEndpointWriteSettingsFrame(
RefCountedPtr<ChaoticGoodConnector> self) {
GPR_ASSERT(self->data_endpoint_ != nullptr);
return [self]() {
// Serialize setting frame.
SettingsFrame frame;
// frame.header set connectiion_type: control
frame.headers = SettingsMetadata{SettingsMetadata::ConnectionType::kData,
self->connection_id_, kDataAlignmentBytes}
.ToMetadataBatch(GetContext<Arena>());
auto write_buffer = frame.Serialize(&self->hpack_compressor_);
return self->data_endpoint_->Write(std::move(write_buffer.control));
};
}
auto ChaoticGoodConnector::WaitForDataEndpointSetup(
RefCountedPtr<ChaoticGoodConnector> self) {
// Data endpoint on_connect callback.
grpc_event_engine::experimental::EventEngine::OnConnectCallback
on_data_endpoint_connect =
[self](absl::StatusOr<std::unique_ptr<EventEngine::Endpoint>>
endpoint) mutable {
if (!endpoint.ok() || self->handshake_mgr_ == nullptr) {
auto error = GRPC_ERROR_CREATE("connect endpoint failed");
MaybeNotify(DEBUG_LOCATION, self->notify_, error);
return;
}
self->data_endpoint_latch_->Set(std::make_shared<PromiseEndpoint>(
std::move(endpoint.value()), SliceBuffer()));
auto cb = self->wait_for_data_endpoint_callback_->MakeCallback();
// Wake up wait_for_data_endpoint_callback_.
cb();
};
self->event_engine_->Connect(
std::move(on_data_endpoint_connect), *self->resolved_addr_,
grpc_event_engine::experimental::ChannelArgsEndpointConfig(
self->channel_args_),
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"data_endpoint_connection"),
EventEngine::Duration(kTimeoutSecs));
return TrySeq(
self->wait_for_data_endpoint_callback_->MakeWaitPromise(),
Race(TrySeq(
self->data_endpoint_latch_->Wait(),
[self](std::shared_ptr<PromiseEndpoint> data_endpoint) mutable {
self->data_endpoint_.swap(data_endpoint);
return TrySeq(
DataEndpointWriteSettingsFrame(self),
DataEndpointReadSettingsFrame(self),
[]() -> absl::Status { return absl::OkStatus(); });
}),
TrySeq(Sleep(Timestamp::Now() + Duration::Seconds(kTimeoutSecs)),
[]() -> absl::Status {
return absl::DeadlineExceededError(
"Data endpoint connect deadline exceeded.");
})));
}
auto ChaoticGoodConnector::ControlEndpointReadSettingsFrame(
RefCountedPtr<ChaoticGoodConnector> self) {
GPR_ASSERT(self->control_endpoint_ != nullptr);
return TrySeq(
self->control_endpoint_->ReadSlice(FrameHeader::kFrameHeaderSize),
[self](Slice slice) {
// Parse frame header
auto frame_header = FrameHeader::Parse(reinterpret_cast<const uint8_t*>(
GRPC_SLICE_START_PTR(slice.c_slice())));
return If(
frame_header.ok(),
TrySeq(
self->control_endpoint_->Read(frame_header->GetFrameLength()),
[frame_header = *frame_header, self](SliceBuffer buffer) {
// Deserialize setting frame.
SettingsFrame frame;
BufferPair buffer_pair{std::move(buffer), SliceBuffer()};
auto status = frame.Deserialize(
&self->hpack_parser_, frame_header,
absl::BitGenRef(self->bitgen_), GetContext<Arena>(),
std::move(buffer_pair), FrameLimits{});
if (!status.ok()) return status;
if (frame.headers == nullptr) {
return absl::UnavailableError("no settings headers");
}
auto settings_metadata =
SettingsMetadata::FromMetadataBatch(*frame.headers);
if (!settings_metadata.ok()) {
return settings_metadata.status();
}
if (!settings_metadata->connection_id.has_value()) {
return absl::UnavailableError(
"no connection id in settings frame");
}
self->connection_id_ = *settings_metadata->connection_id;
return absl::OkStatus();
},
WaitForDataEndpointSetup(self)),
[status = frame_header.status()]() { return status; });
});
}
auto ChaoticGoodConnector::ControlEndpointWriteSettingsFrame(
RefCountedPtr<ChaoticGoodConnector> self) {
return [self]() {
GPR_ASSERT(self->control_endpoint_ != nullptr);
// Serialize setting frame.
SettingsFrame frame;
// frame.header set connectiion_type: control
frame.headers = SettingsMetadata{SettingsMetadata::ConnectionType::kControl,
absl::nullopt, absl::nullopt}
.ToMetadataBatch(GetContext<Arena>());
auto write_buffer = frame.Serialize(&self->hpack_compressor_);
return self->control_endpoint_->Write(std::move(write_buffer.control));
};
}
void ChaoticGoodConnector::Connect(const Args& args, Result* result,
grpc_closure* notify) {
{
MutexLock lock(&mu_);
result_ = result;
if (is_shutdown_) {
auto error = GRPC_ERROR_CREATE("connector shutdown");
MaybeNotify(DEBUG_LOCATION, notify, error);
return;
}
}
args_ = args;
notify_ = notify;
resolved_addr_ = EventEngine::ResolvedAddress(
reinterpret_cast<const sockaddr*>(args_.address->addr),
args_.address->len);
GPR_ASSERT(resolved_addr_.value().address() != nullptr);
grpc_event_engine::experimental::EventEngine::OnConnectCallback on_connect =
[self = RefAsSubclass<ChaoticGoodConnector>()](
absl::StatusOr<std::unique_ptr<EventEngine::Endpoint>>
endpoint) mutable {
if (!endpoint.ok() || self->handshake_mgr_ == nullptr) {
auto error = GRPC_ERROR_CREATE("connect endpoint failed");
MaybeNotify(DEBUG_LOCATION, self->notify_, error);
return;
}
ExecCtx exec_ctx;
auto* p = self.release();
p->handshake_mgr_->DoHandshake(
grpc_event_engine_endpoint_create(std::move(endpoint.value())),
p->channel_args_, p->args_.deadline, nullptr /* acceptor */,
OnHandshakeDone, p);
};
event_engine_->Connect(
std::move(on_connect), *resolved_addr_,
grpc_event_engine::experimental::ChannelArgsEndpointConfig(channel_args_),
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"data_endpoint_connection"),
EventEngine::Duration(kTimeoutSecs));
}
void ChaoticGoodConnector::OnHandshakeDone(void* arg, grpc_error_handle error) {
auto* args = static_cast<HandshakerArgs*>(arg);
RefCountedPtr<ChaoticGoodConnector> self(
static_cast<ChaoticGoodConnector*>(args->user_data));
gpr_log(GPR_ERROR, "SubchannelConnector::OnHandshakeDone:%p",
static_cast<SubchannelConnector*>(self.get()));
grpc_slice_buffer_destroy(args->read_buffer);
gpr_free(args->read_buffer);
// Start receiving setting frames;
{
MutexLock lock(&self->mu_);
if (!error.ok() || self->is_shutdown_) {
if (error.ok()) {
error = GRPC_ERROR_CREATE("connector shutdown");
// We were shut down after handshaking completed successfully, so
// destroy the endpoint here.
if (args->endpoint != nullptr) {
grpc_endpoint_shutdown(args->endpoint, error);
grpc_endpoint_destroy(args->endpoint);
}
}
self->result_->Reset();
MaybeNotify(DEBUG_LOCATION, self->notify_, error);
return;
}
}
if (args->endpoint != nullptr) {
GPR_ASSERT(grpc_event_engine::experimental::grpc_is_event_engine_endpoint(
args->endpoint));
self->control_endpoint_ = std::make_shared<PromiseEndpoint>(
grpc_event_engine::experimental::
grpc_take_wrapped_event_engine_endpoint(args->endpoint),
SliceBuffer());
auto activity = MakeActivity(
[self] {
return TrySeq(ControlEndpointWriteSettingsFrame(self),
ControlEndpointReadSettingsFrame(self),
[]() { return absl::OkStatus(); });
},
EventEngineWakeupScheduler(self->event_engine_),
[self](absl::Status status) {
MaybeNotify(DEBUG_LOCATION, self->notify_, status);
},
self->arena_.get(), self->event_engine_.get());
MutexLock lock(&self->mu_);
if (!self->is_shutdown_) {
self->connect_activity_ = std::move(activity);
}
} else {
// Handshaking succeeded but there is no endpoint.
MutexLock lock(&self->mu_);
self->result_->Reset();
auto error = GRPC_ERROR_CREATE("handshake complete with empty endpoint.");
MaybeNotify(DEBUG_LOCATION, self->notify_, error);
}
}
} // namespace chaotic_good
} // namespace grpc_core

@ -0,0 +1,114 @@
// Copyright 2024 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_SRC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_CLIENT_CHAOTIC_GOOD_CONNECTOR_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_CLIENT_CHAOTIC_GOOD_CONNECTOR_H
#include <grpc/support/port_platform.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include "absl/random/random.h"
#include "absl/status/statusor.h"
#include <grpc/event_engine/event_engine.h>
#include "src/core/ext/filters/client_channel/connector.h"
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/event_engine/channel_args_endpoint_config.h"
#include "src/core/lib/gprpp/notification.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/wait_for_callback.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/resource_quota/memory_quota.h"
#include "src/core/lib/resource_quota/resource_quota.h"
#include "src/core/lib/transport/handshaker.h"
#include "src/core/lib/transport/promise_endpoint.h"
namespace grpc_core {
namespace chaotic_good {
class ChaoticGoodConnector : public SubchannelConnector {
public:
explicit ChaoticGoodConnector(
std::shared_ptr<grpc_event_engine::experimental::EventEngine>
event_engine);
~ChaoticGoodConnector() override;
void Connect(const Args& args, Result* result, grpc_closure* notify) override;
void Shutdown(grpc_error_handle error) override {
gpr_log(GPR_ERROR, "SubchannelConnector::Shutdown: %s; mgr=%p",
error.ToString().c_str(), handshake_mgr_.get());
ActivityPtr connect_activity;
MutexLock lock(&mu_);
if (is_shutdown_) return;
is_shutdown_ = true;
if (handshake_mgr_ != nullptr) {
handshake_mgr_->Shutdown(error);
}
connect_activity = std::move(connect_activity_);
};
private:
static auto DataEndpointReadSettingsFrame(
RefCountedPtr<ChaoticGoodConnector> self);
static auto DataEndpointWriteSettingsFrame(
RefCountedPtr<ChaoticGoodConnector> self);
static auto ControlEndpointReadSettingsFrame(
RefCountedPtr<ChaoticGoodConnector> self);
static auto ControlEndpointWriteSettingsFrame(
RefCountedPtr<ChaoticGoodConnector> self);
static auto WaitForDataEndpointSetup(
RefCountedPtr<ChaoticGoodConnector> self);
static void OnHandshakeDone(void* arg, grpc_error_handle error);
grpc_event_engine::experimental::MemoryAllocator memory_allocator_ =
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"connect_activity");
ScopedArenaPtr arena_ = MakeScopedArena(1024, &memory_allocator_);
Mutex mu_;
Args args_;
Result* result_ ABSL_GUARDED_BY(mu_);
grpc_closure* notify_;
bool is_shutdown_ ABSL_GUARDED_BY(mu_) = false;
ChannelArgs channel_args_;
absl::StatusOr<grpc_event_engine::experimental::EventEngine::ResolvedAddress>
resolved_addr_;
std::shared_ptr<PromiseEndpoint> control_endpoint_;
std::shared_ptr<PromiseEndpoint> data_endpoint_;
ActivityPtr connect_activity_ ABSL_GUARDED_BY(mu_);
const std::shared_ptr<grpc_event_engine::experimental::EventEngine>
event_engine_;
std::shared_ptr<HandshakeManager> handshake_mgr_;
HPackCompressor hpack_compressor_;
HPackParser hpack_parser_;
absl::BitGen bitgen_;
std::shared_ptr<Latch<std::shared_ptr<PromiseEndpoint>>> data_endpoint_latch_;
std::shared_ptr<WaitForCallback> wait_for_data_endpoint_callback_;
std::string connection_id_;
};
} // namespace chaotic_good
} // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_CLIENT_CHAOTIC_GOOD_CONNECTOR_H

@ -189,24 +189,40 @@ absl::Status FrameLimits::ValidateMessage(const FrameHeader& header) {
return absl::OkStatus();
}
absl::Status SettingsFrame::Deserialize(HPackParser*, const FrameHeader& header,
absl::BitGenRef, Arena*,
absl::Status SettingsFrame::Deserialize(HPackParser* parser,
const FrameHeader& header,
absl::BitGenRef bitsrc, Arena* arena,
BufferPair buffers, FrameLimits) {
if (header.type != FrameType::kSettings) {
return absl::InvalidArgumentError("Expected settings frame");
}
if (header.flags.any()) {
if (header.flags.is_set(1) || header.flags.is_set(2)) {
return absl::InvalidArgumentError("Unexpected flags");
}
if (buffers.data.Length() != 0) {
return absl::InvalidArgumentError("Unexpected data");
}
FrameDeserializer deserializer(header, buffers);
if (header.flags.is_set(0)) {
auto r = ReadMetadata<ClientMetadata>(parser, deserializer.ReceiveHeaders(),
header.stream_id, true, true, bitsrc,
arena);
if (!r.ok()) return r.status();
if (r.value() != nullptr) {
headers = std::move(r.value());
}
} else if (header.header_length != 0) {
return absl::InvalidArgumentError(absl::StrCat(
"Unexpected non-zero header length", header.header_length));
}
return deserializer.Finish();
}
BufferPair SettingsFrame::Serialize(HPackCompressor*) const {
BufferPair SettingsFrame::Serialize(HPackCompressor* encoder) const {
FrameSerializer serializer(FrameType::kSettings, 0);
if (headers.get() != nullptr) {
encoder->EncodeRawHeaders(*headers.get(), serializer.AddHeaders());
}
return serializer.Finish();
}

@ -77,6 +77,7 @@ struct SettingsFrame final : public FrameInterface {
absl::BitGenRef bitsrc, Arena* arena,
BufferPair buffers, FrameLimits limits) override;
BufferPair Serialize(HPackCompressor* encoder) const override;
ClientMetadataHandle headers;
std::string ToString() const override;
bool operator==(const SettingsFrame&) const { return true; }

@ -0,0 +1,410 @@
// Copyright 2024 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/transport/chaotic_good/server/chaotic_good_server.h"
#include <cstdint>
#include <memory>
#include <random>
#include <string>
#include <utility>
#include <vector>
#include "absl/random/bit_gen_ref.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include <grpc/event_engine/event_engine.h>
#include <grpc/grpc.h>
#include <grpc/slice.h>
#include <grpc/support/log.h>
#include "src/core/ext/transport/chaotic_good/frame.h"
#include "src/core/ext/transport/chaotic_good/frame_header.h"
#include "src/core/ext/transport/chaotic_good/settings_metadata.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/event_engine/channel_args_endpoint_config.h"
#include "src/core/lib/event_engine/default_event_engine.h"
#include "src/core/lib/event_engine/tcp_socket_utils.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/status_helper.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/event_engine_shims/endpoint.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/event_engine_wakeup_scheduler.h"
#include "src/core/lib/promise/if.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/race.h"
#include "src/core/lib/promise/sleep.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/handshaker.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/promise_endpoint.h"
namespace grpc_core {
namespace chaotic_good {
namespace {
const Duration kConnectionDeadline = Duration::Seconds(5);
} // namespace
using grpc_event_engine::experimental::EventEngine;
ChaoticGoodServerListener::ChaoticGoodServerListener(
Server* server, const ChannelArgs& args,
absl::AnyInvocable<std::string()> connection_id_generator)
: server_(server),
args_(args),
event_engine_(grpc_event_engine::experimental::GetDefaultEventEngine()),
connection_id_generator_(std::move(connection_id_generator)) {}
ChaoticGoodServerListener::~ChaoticGoodServerListener() {
event_engine_->Run([on_destroy_done = on_destroy_done_]() {
ExecCtx exec_ctx;
if (on_destroy_done != nullptr) {
ExecCtx::Run(DEBUG_LOCATION, on_destroy_done, absl::OkStatus());
ExecCtx::Get()->Flush();
}
});
}
absl::StatusOr<int> ChaoticGoodServerListener::Bind(const char* addr) {
EventEngine::Listener::AcceptCallback accept_cb =
[self = Ref()](std::unique_ptr<EventEngine::Endpoint> ep,
MemoryAllocator) {
ExecCtx exec_ctx;
MutexLock lock(&self->mu_);
self->connection_list_.emplace(
MakeOrphanable<ActiveConnection>(self, std::move(ep)));
};
auto shutdown_cb = [](absl::Status status) {
if (!status.ok()) {
gpr_log(GPR_ERROR, "Server accept connection failed: %s",
StatusToString(status).c_str());
}
};
GPR_ASSERT(event_engine_ != nullptr);
auto ee_listener = event_engine_->CreateListener(
std::move(accept_cb), std::move(shutdown_cb),
grpc_event_engine::experimental::ChannelArgsEndpointConfig(args_),
std::make_unique<MemoryQuota>("chaotic_good_server_listener"));
if (!ee_listener.ok()) {
return ee_listener.status();
}
ee_listener_ = std::move(ee_listener.value());
auto resolved_addr =
grpc_event_engine::experimental::URIToResolvedAddress(addr);
GPR_ASSERT(resolved_addr.ok());
if (!resolved_addr.ok()) {
return resolved_addr.status();
}
auto port_num = ee_listener_->Bind(resolved_addr.value());
if (!port_num.ok()) {
return port_num.status();
}
server_->AddListener(OrphanablePtr<Server::ListenerInterface>(this));
return port_num;
}
absl::Status ChaoticGoodServerListener::StartListening() {
GPR_ASSERT(ee_listener_ != nullptr);
auto status = ee_listener_->Start();
return status;
}
ChaoticGoodServerListener::ActiveConnection::ActiveConnection(
RefCountedPtr<ChaoticGoodServerListener> listener,
std::unique_ptr<EventEngine::Endpoint> endpoint)
: InternallyRefCounted("ActiveConnection"),
memory_allocator_(listener->memory_allocator_),
listener_(listener) {
handshaking_state_ = MakeRefCounted<HandshakingState>(Ref());
handshaking_state_->Start(std::move(endpoint));
}
ChaoticGoodServerListener::ActiveConnection::~ActiveConnection() {
if (receive_settings_activity_ != nullptr) receive_settings_activity_.reset();
}
void ChaoticGoodServerListener::ActiveConnection::NewConnectionID() {
bool has_new_id = false;
MutexLock lock(&listener_->mu_);
while (!has_new_id) {
connection_id_ = listener_->connection_id_generator_();
if (!listener_->connectivity_map_.contains(connection_id_)) {
has_new_id = true;
}
}
listener_->connectivity_map_.emplace(
connection_id_,
std::make_shared<InterActivityLatch<std::shared_ptr<PromiseEndpoint>>>());
}
void ChaoticGoodServerListener::ActiveConnection::Fail(
absl::string_view error) {
gpr_log(GPR_ERROR, "ActiveConnection::Fail:%p %s", this,
std::string(error).c_str());
// Can easily be holding various locks here: bounce through EE to ensure no
// deadlocks.
listener_->event_engine_->Run([self = Ref()]() {
ExecCtx exec_ctx;
OrphanablePtr<ActiveConnection> con;
MutexLock lock(&self->listener_->mu_);
auto v = self->listener_->connection_list_.extract(self.get());
if (!v.empty()) con = std::move(v.value());
});
}
ChaoticGoodServerListener::ActiveConnection::HandshakingState::HandshakingState(
RefCountedPtr<ActiveConnection> connection)
: memory_allocator_(connection->memory_allocator_),
connection_(std::move(connection)),
handshake_mgr_(MakeRefCounted<HandshakeManager>()) {}
void ChaoticGoodServerListener::ActiveConnection::HandshakingState::Start(
std::unique_ptr<EventEngine::Endpoint> endpoint) {
handshake_mgr_->DoHandshake(
grpc_event_engine_endpoint_create(std::move(endpoint)),
connection_->args(), GetConnectionDeadline(), nullptr, OnHandshakeDone,
Ref().release());
}
auto ChaoticGoodServerListener::ActiveConnection::HandshakingState::
EndpointReadSettingsFrame(RefCountedPtr<HandshakingState> self) {
return TrySeq(
self->connection_->endpoint_->ReadSlice(FrameHeader::kFrameHeaderSize),
[self](Slice slice) {
// Parse frame header
auto frame_header = FrameHeader::Parse(reinterpret_cast<const uint8_t*>(
GRPC_SLICE_START_PTR(slice.c_slice())));
return If(
frame_header.ok(),
[self, &frame_header]() {
return TrySeq(
self->connection_->endpoint_->Read(
frame_header->GetFrameLength()),
[frame_header = *frame_header,
self](SliceBuffer buffer) -> absl::StatusOr<bool> {
// Read Setting frame.
SettingsFrame frame;
// Deserialize frame from read buffer.
BufferPair buffer_pair{std::move(buffer), SliceBuffer()};
auto status = frame.Deserialize(
&self->connection_->hpack_parser_, frame_header,
absl::BitGenRef(self->connection_->bitgen_),
GetContext<Arena>(), std::move(buffer_pair),
FrameLimits{});
if (!status.ok()) return status;
if (frame.headers == nullptr) {
return absl::UnavailableError("no settings headers");
}
auto settings_metadata =
SettingsMetadata::FromMetadataBatch(*frame.headers);
if (!settings_metadata.ok()) {
return settings_metadata.status();
}
const bool is_control_endpoint =
settings_metadata->connection_type ==
SettingsMetadata::ConnectionType::kControl;
if (!is_control_endpoint) {
if (!settings_metadata->connection_id.has_value()) {
return absl::UnavailableError(
"no connection id in data endpoint settings frame");
}
if (!settings_metadata->alignment.has_value()) {
return absl::UnavailableError(
"no alignment in data endpoint settings frame");
}
// Get connection-id and data-alignment for data endpoint.
self->connection_->connection_id_ =
*settings_metadata->connection_id;
self->connection_->data_alignment_ =
*settings_metadata->alignment;
}
return is_control_endpoint;
});
},
[&frame_header]() {
return [r = frame_header.status()]() -> absl::StatusOr<bool> {
return r;
};
});
});
}
auto ChaoticGoodServerListener::ActiveConnection::HandshakingState::
WaitForDataEndpointSetup(RefCountedPtr<HandshakingState> self) {
return Race(TrySeq(
[]() {
// TODO(ladynana): find a way to resolve SeqState to actual
// value.
return absl::OkStatus();
},
[self]() {
MutexLock lock(&self->connection_->listener_->mu_);
auto latch = self->connection_->listener_->connectivity_map_
.find(self->connection_->connection_id_)
->second;
return latch->Wait();
},
[](std::shared_ptr<PromiseEndpoint> ret) -> absl::Status {
if (ret == nullptr) {
return absl::UnavailableError("no data endpoint");
}
// TODO(ladynana): initialize server transport.
return absl::OkStatus();
}),
// Set timeout for waiting data endpoint connect.
TrySeq(
// []() {
Sleep(Timestamp::Now() + kConnectionDeadline),
[self]() mutable -> absl::Status {
MutexLock lock(&self->connection_->listener_->mu_);
// Delete connection id from map when timeout;
self->connection_->listener_->connectivity_map_.erase(
self->connection_->connection_id_);
return absl::DeadlineExceededError("Deadline exceeded.");
}));
}
auto ChaoticGoodServerListener::ActiveConnection::HandshakingState::
ControlEndpointWriteSettingsFrame(RefCountedPtr<HandshakingState> self) {
return TrySeq(
[self]() {
self->connection_->NewConnectionID();
SettingsFrame frame;
frame.headers =
SettingsMetadata{absl::nullopt, self->connection_->connection_id_,
absl::nullopt}
.ToMetadataBatch(GetContext<Arena>());
auto write_buffer =
frame.Serialize(&self->connection_->hpack_compressor_);
return self->connection_->endpoint_->Write(
std::move(write_buffer.control));
},
WaitForDataEndpointSetup(self));
}
auto ChaoticGoodServerListener::ActiveConnection::HandshakingState::
DataEndpointWriteSettingsFrame(RefCountedPtr<HandshakingState> self) {
return TrySeq(
[self]() {
// Send data endpoint setting frame
SettingsFrame frame;
frame.headers =
SettingsMetadata{absl::nullopt, self->connection_->connection_id_,
self->connection_->data_alignment_}
.ToMetadataBatch(GetContext<Arena>());
auto write_buffer =
frame.Serialize(&self->connection_->hpack_compressor_);
return self->connection_->endpoint_->Write(
std::move(write_buffer.control));
},
[self]() mutable {
MutexLock lock(&self->connection_->listener_->mu_);
// Set endpoint to latch
auto it = self->connection_->listener_->connectivity_map_.find(
self->connection_->connection_id_);
if (it == self->connection_->listener_->connectivity_map_.end()) {
return absl::InternalError(
absl::StrCat("Connection not in map: ",
absl::CEscape(self->connection_->connection_id_)));
}
it->second->Set(std::move(self->connection_->endpoint_));
return absl::OkStatus();
});
}
auto ChaoticGoodServerListener::ActiveConnection::HandshakingState::
EndpointWriteSettingsFrame(RefCountedPtr<HandshakingState> self,
bool is_control_endpoint) {
return If(is_control_endpoint, ControlEndpointWriteSettingsFrame(self),
DataEndpointWriteSettingsFrame(self));
}
void ChaoticGoodServerListener::ActiveConnection::HandshakingState::
OnHandshakeDone(void* arg, grpc_error_handle error) {
auto* args = static_cast<HandshakerArgs*>(arg);
GPR_ASSERT(args != nullptr);
RefCountedPtr<HandshakingState> self(
static_cast<HandshakingState*>(args->user_data));
grpc_slice_buffer_destroy(args->read_buffer);
gpr_free(args->read_buffer);
if (!error.ok()) {
self->connection_->Fail(
absl::StrCat("Handshake failed: ", StatusToString(error)));
return;
}
if (args->endpoint == nullptr) {
self->connection_->Fail("Server handshake done but has empty endpoint.");
return;
}
GPR_ASSERT(grpc_event_engine::experimental::grpc_is_event_engine_endpoint(
args->endpoint));
self->connection_->endpoint_ = std::make_shared<PromiseEndpoint>(
grpc_event_engine::experimental::grpc_take_wrapped_event_engine_endpoint(
args->endpoint),
SliceBuffer());
auto activity = MakeActivity(
[self]() {
return TrySeq(Race(EndpointReadSettingsFrame(self),
TrySeq(Sleep(Timestamp::Now() + kConnectionDeadline),
[]() -> absl::StatusOr<bool> {
return absl::DeadlineExceededError(
"Waiting for initial settings frame");
})),
[self](bool is_control_endpoint) {
return EndpointWriteSettingsFrame(self,
is_control_endpoint);
});
},
EventEngineWakeupScheduler(
grpc_event_engine::experimental::GetDefaultEventEngine()),
[self](absl::Status status) {
if (!status.ok()) {
self->connection_->Fail(
absl::StrCat("Server setting frame handling failed: ",
StatusToString(status)));
}
},
self->connection_->arena_.get(),
grpc_event_engine::experimental::GetDefaultEventEngine().get());
MutexLock lock(&self->connection_->mu_);
if (self->connection_->orphaned_) return;
self->connection_->receive_settings_activity_ = std::move(activity);
}
Timestamp ChaoticGoodServerListener::ActiveConnection::HandshakingState::
GetConnectionDeadline() {
if (connection_->args().Contains(GRPC_ARG_SERVER_HANDSHAKE_TIMEOUT_MS)) {
return Timestamp::Now() +
connection_->args()
.GetDurationFromIntMillis(GRPC_ARG_SERVER_HANDSHAKE_TIMEOUT_MS)
.value();
}
return Timestamp::Now() + kConnectionDeadline;
}
} // namespace chaotic_good
} // namespace grpc_core

@ -0,0 +1,202 @@
// Copyright 2022 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_SRC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_SERVER_CHAOTIC_GOOD_SERVER_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_SERVER_CHAOTIC_GOOD_SERVER_H
#include <grpc/support/port_platform.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/random/random.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include <grpc/event_engine/event_engine.h>
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/iomgr_fwd.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/inter_activity_latch.h"
#include "src/core/lib/resource_quota/memory_quota.h"
#include "src/core/lib/resource_quota/resource_quota.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/handshaker.h"
#include "src/core/lib/transport/promise_endpoint.h"
namespace grpc_core {
namespace chaotic_good {
class ChaoticGoodServerListener final
: public Server::ListenerInterface,
public RefCounted<ChaoticGoodServerListener> {
public:
static absl::AnyInvocable<std::string()> DefaultConnectionIDGenerator() {
return [bitgen = absl::BitGen()]() mutable {
return absl::StrCat(absl::Hex(absl::Uniform<uint64_t>(bitgen)));
};
}
ChaoticGoodServerListener(
Server* server, const ChannelArgs& args,
absl::AnyInvocable<std::string()> connection_id_generator =
DefaultConnectionIDGenerator());
~ChaoticGoodServerListener() override;
// Bind address to EventEngine listener.
absl::StatusOr<int> Bind(const char* addr);
absl::Status StartListening();
const ChannelArgs& args() const { return args_; }
void Orphan() override {
gpr_log(GPR_INFO, "ORPHAN");
{
absl::flat_hash_set<OrphanablePtr<ActiveConnection>> connection_list;
MutexLock lock(&mu_);
connection_list = std::move(connection_list_);
}
ee_listener_.reset();
Unref();
gpr_log(GPR_INFO, "~ORPHAN");
};
class ActiveConnection : public InternallyRefCounted<ActiveConnection> {
public:
ActiveConnection(
RefCountedPtr<ChaoticGoodServerListener> listener,
std::unique_ptr<grpc_event_engine::experimental::EventEngine::Endpoint>
endpoint);
~ActiveConnection() override;
const ChannelArgs& args() const { return listener_->args(); }
void Orphan() override {
gpr_log(GPR_INFO, "ORPHAN ActiveConnection:%p", this);
if (handshaking_state_ != nullptr) {
handshaking_state_->Shutdown();
handshaking_state_.reset();
}
ActivityPtr activity;
{
MutexLock lock(&mu_);
orphaned_ = true;
activity = std::move(receive_settings_activity_);
}
activity.reset();
Unref();
gpr_log(GPR_INFO, "~ORPHAN ActiveConnection");
}
class HandshakingState : public RefCounted<HandshakingState> {
public:
explicit HandshakingState(RefCountedPtr<ActiveConnection> connection);
~HandshakingState() override{};
void Start(std::unique_ptr<
grpc_event_engine::experimental::EventEngine::Endpoint>
endpoint);
void Shutdown() {
gpr_log(GPR_INFO, "Shutdown:%p", this);
handshake_mgr_->Shutdown(absl::CancelledError("Shutdown"));
}
private:
static auto EndpointReadSettingsFrame(
RefCountedPtr<HandshakingState> self);
static auto EndpointWriteSettingsFrame(
RefCountedPtr<HandshakingState> self, bool is_control_endpoint);
static auto WaitForDataEndpointSetup(
RefCountedPtr<HandshakingState> self);
static auto ControlEndpointWriteSettingsFrame(
RefCountedPtr<HandshakingState> self);
static auto DataEndpointWriteSettingsFrame(
RefCountedPtr<HandshakingState> self);
static void OnHandshakeDone(void* arg, grpc_error_handle error);
Timestamp GetConnectionDeadline();
const std::shared_ptr<grpc_event_engine::experimental::MemoryAllocator>
memory_allocator_;
const RefCountedPtr<ActiveConnection> connection_;
const RefCountedPtr<HandshakeManager> handshake_mgr_;
};
private:
void Fail(absl::string_view error);
void NewConnectionID();
const std::shared_ptr<grpc_event_engine::experimental::MemoryAllocator>
memory_allocator_;
ScopedArenaPtr arena_ = MakeScopedArena(1024, memory_allocator_.get());
const RefCountedPtr<ChaoticGoodServerListener> listener_;
RefCountedPtr<HandshakingState> handshaking_state_;
Mutex mu_;
ActivityPtr receive_settings_activity_ ABSL_GUARDED_BY(mu_);
bool orphaned_ ABSL_GUARDED_BY(mu_) = false;
std::shared_ptr<PromiseEndpoint> endpoint_;
HPackCompressor hpack_compressor_;
HPackParser hpack_parser_;
absl::BitGen bitgen_;
std::string connection_id_;
int32_t data_alignment_;
};
void Start(Server*, const std::vector<grpc_pollset*>*) override {
StartListening().IgnoreError();
};
channelz::ListenSocketNode* channelz_listen_socket_node() const override {
return nullptr;
}
void SetOnDestroyDone(grpc_closure* closure) override {
MutexLock lock(&mu_);
on_destroy_done_ = closure;
};
private:
Server* server_;
ChannelArgs args_;
std::shared_ptr<grpc_event_engine::experimental::EventEngine> event_engine_;
std::unique_ptr<grpc_event_engine::experimental::EventEngine::Listener>
ee_listener_;
Mutex mu_;
// Map of connection id to endpoints connectivity.
absl::flat_hash_map<
std::string,
std::shared_ptr<InterActivityLatch<std::shared_ptr<PromiseEndpoint>>>>
connectivity_map_ ABSL_GUARDED_BY(mu_);
absl::flat_hash_set<OrphanablePtr<ActiveConnection>> connection_list_
ABSL_GUARDED_BY(mu_);
absl::AnyInvocable<std::string()> connection_id_generator_
ABSL_GUARDED_BY(mu_);
grpc_closure* on_destroy_done_ ABSL_GUARDED_BY(mu_) = nullptr;
std::shared_ptr<grpc_event_engine::experimental::MemoryAllocator>
memory_allocator_ =
std::make_shared<grpc_event_engine::experimental::MemoryAllocator>(
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"server_connection"));
};
} // namespace chaotic_good
} // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_SERVER_CHAOTIC_GOOD_SERVER_H

@ -118,8 +118,10 @@ auto ChaoticGoodServerTransport::MaybePushFragmentIntoCall(
auto ChaoticGoodServerTransport::SendFragment(
ServerFragmentFrame frame, MpscSender<ServerFrame> outgoing_frames) {
gpr_log(GPR_INFO, "CHAOTIC_GOOD: SendFragment: frame=%s",
frame.ToString().c_str());
if (grpc_chaotic_good_trace.enabled()) {
gpr_log(GPR_INFO, "CHAOTIC_GOOD: SendFragment: frame=%s",
frame.ToString().c_str());
}
return Map(outgoing_frames.Send(std::move(frame)),
[](bool success) -> absl::Status {
if (!success) {
@ -163,8 +165,11 @@ auto ChaoticGoodServerTransport::SendCallInitialMetadataAndBody(
call_initiator.PullServerInitialMetadata(),
[stream_id, outgoing_frames, call_initiator,
this](absl::optional<ServerMetadataHandle> md) mutable {
gpr_log(GPR_INFO, "CHAOTIC_GOOD: SendCallInitialMetadataAndBody: md=%s",
md.has_value() ? (*md)->DebugString().c_str() : "null");
if (grpc_chaotic_good_trace.enabled()) {
gpr_log(GPR_INFO,
"CHAOTIC_GOOD: SendCallInitialMetadataAndBody: md=%s",
md.has_value() ? (*md)->DebugString().c_str() : "null");
}
return If(
md.has_value(),
[&md, stream_id, &outgoing_frames, &call_initiator, this]() {

@ -0,0 +1,81 @@
// Copyright 2024 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/transport/chaotic_good/settings_metadata.h"
#include "absl/status/status.h"
#include "src/core/lib/gprpp/crash.h"
namespace grpc_core {
namespace chaotic_good {
Arena::PoolPtr<grpc_metadata_batch> SettingsMetadata::ToMetadataBatch(
Arena* arena) {
auto md = Arena::MakePooled<grpc_metadata_batch>(arena);
auto add = [&md](absl::string_view key, std::string value) {
md->Append(key, Slice::FromCopiedString(value),
[key, value](absl::string_view error, const Slice&) {
Crash(absl::StrCat("Failed to add metadata '", key, "' = '",
value, "': ", error));
});
};
if (connection_type.has_value()) {
add("chaotic-good-connection-type",
connection_type.value() == ConnectionType::kControl ? "control"
: "data");
}
if (connection_id.has_value()) {
add("chaotic-good-connection-id", connection_id.value());
}
if (alignment.has_value()) {
add("chaotic-good-alignment", absl::StrCat(alignment.value()));
}
return md;
}
absl::StatusOr<SettingsMetadata> SettingsMetadata::FromMetadataBatch(
const grpc_metadata_batch& batch) {
SettingsMetadata md;
std::string buffer;
auto v = batch.GetStringValue("chaotic-good-connection-type", &buffer);
if (v.has_value()) {
if (*v == "control") {
md.connection_type = ConnectionType::kControl;
} else if (*v == "data") {
md.connection_type = ConnectionType::kData;
} else {
return absl::UnavailableError(
absl::StrCat("Invalid connection type: ", *v));
}
}
v = batch.GetStringValue("chaotic-good-connection-id", &buffer);
if (v.has_value()) {
md.connection_id = std::string(*v);
}
v = batch.GetStringValue("chaotic-good-alignment", &buffer);
if (v.has_value()) {
uint32_t alignment;
if (!absl::SimpleAtoi(*v, &alignment)) {
return absl::UnavailableError(absl::StrCat("Invalid alignment: ", *v));
}
md.alignment = alignment;
}
return md;
}
} // namespace chaotic_good
} // namespace grpc_core

@ -0,0 +1,46 @@
// Copyright 2024 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_SRC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_SETTINGS_METADATA_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_SETTINGS_METADATA_H
#include <grpc/support/port_platform.h>
#include "absl/types/optional.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/transport/metadata_batch.h"
namespace grpc_core {
namespace chaotic_good {
// Captures metadata sent in a chaotic good settings frame.
struct SettingsMetadata {
enum class ConnectionType {
kControl,
kData,
};
absl::optional<ConnectionType> connection_type;
absl::optional<std::string> connection_id;
absl::optional<uint32_t> alignment;
Arena::PoolPtr<grpc_metadata_batch> ToMetadataBatch(Arena* arena);
static absl::StatusOr<SettingsMetadata> FromMetadataBatch(
const grpc_metadata_batch& batch);
};
} // namespace chaotic_good
} // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_SETTINGS_METADATA_H

@ -36,7 +36,62 @@ namespace grpc_core {
// A latch providing true cross activity wakeups
template <typename T>
class InterActivityLatch;
class InterActivityLatch {
public:
InterActivityLatch() = default;
InterActivityLatch(const InterActivityLatch&) = delete;
InterActivityLatch& operator=(const InterActivityLatch&) = delete;
// Produce a promise to wait for this latch.
auto Wait() {
return [this]() -> Poll<T> {
MutexLock lock(&mu_);
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%sPollWait %s", DebugTag().c_str(),
StateString().c_str());
}
if (is_set_) {
return std::move(value_);
} else {
return waiters_.AddPending(
GetContext<Activity>()->MakeNonOwningWaker());
}
};
}
// Set the latch.
void Set(T value) {
MutexLock lock(&mu_);
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%sSet %s", DebugTag().c_str(), StateString().c_str());
}
is_set_ = true;
value_ = std::move(value);
waiters_.WakeupAsync();
}
bool IsSet() const ABSL_LOCKS_EXCLUDED(mu_) {
MutexLock lock(&mu_);
return is_set_;
}
private:
std::string DebugTag() {
return absl::StrCat(GetContext<Activity>()->DebugTag(),
" INTER_ACTIVITY_LATCH[0x",
reinterpret_cast<uintptr_t>(this), "]: ");
}
std::string StateString() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
return absl::StrCat("is_set:", is_set_);
}
mutable Mutex mu_;
// True if we have a value set, false otherwise.
bool is_set_ ABSL_GUARDED_BY(mu_) = false;
WaitSet waiters_ ABSL_GUARDED_BY(mu_);
T value_ ABSL_GUARDED_BY(mu_);
};
template <>
class InterActivityLatch<void> {
@ -90,7 +145,7 @@ class InterActivityLatch<void> {
mutable Mutex mu_;
// True if we have a value set, false otherwise.
bool is_set_ = false;
bool is_set_ ABSL_GUARDED_BY(mu_) = false;
WaitSet waiters_ ABSL_GUARDED_BY(mu_);
};

@ -256,7 +256,7 @@ GrpcMemoryAllocatorImpl::~GrpcMemoryAllocatorImpl() {
GPR_ASSERT(free_bytes_.load(std::memory_order_acquire) +
sizeof(GrpcMemoryAllocatorImpl) ==
taken_bytes_.load(std::memory_order_relaxed));
memory_quota_->Return(taken_bytes_);
memory_quota_->Return(taken_bytes_.load(std::memory_order_relaxed));
}
void GrpcMemoryAllocatorImpl::Shutdown() {

@ -1050,7 +1050,7 @@ class UnknownMap {
public:
explicit UnknownMap(Arena* arena) : unknown_(arena) {}
using BackingType = ChunkedVector<std::pair<Slice, Slice>, 10>;
using BackingType = ChunkedVector<std::pair<Slice, Slice>, 5>;
void Append(absl::string_view key, Slice value);
void Remove(absl::string_view key);
@ -1067,7 +1067,7 @@ class UnknownMap {
private:
// Backing store for added metadata.
ChunkedVector<std::pair<Slice, Slice>, 10> unknown_;
BackingType unknown_;
};
// Given a factory template Factory, construct a type that derives from

@ -121,15 +121,10 @@ grpc_proto_fuzzer(
],
)
grpc_proto_fuzzer(
grpc_cc_library(
name = "server_fuzzer",
srcs = ["server_fuzzer.cc"],
corpus = "server_fuzzer_corpus",
language = "C++",
proto = None,
tags = ["no_windows"],
uses_event_engine = False,
uses_polling = False,
hdrs = ["server_fuzzer.h"],
deps = [
"fuzzer_input_proto",
"fuzzing_common",
@ -137,8 +132,39 @@ grpc_proto_fuzzer(
"//:gpr",
"//:grpc",
"//src/core:channel_args",
"//test/core/event_engine/fuzzing_event_engine",
"//test/core/util:fuzz_config_vars",
"//test/core/util:grpc_test_util",
"//test/core/util:grpc_test_util_base",
],
)
grpc_proto_fuzzer(
name = "server_fuzzer_chttp2",
srcs = ["server_fuzzer_chttp2.cc"],
corpus = "server_fuzzer_chttp2_corpus",
language = "C++",
proto = None,
tags = ["no_windows"],
uses_event_engine = False,
uses_polling = False,
deps = [
":server_fuzzer",
"//:grpc",
],
)
grpc_proto_fuzzer(
name = "server_fuzzer_chaotic_good",
srcs = ["server_fuzzer_chaotic_good.cc"],
corpus = "server_fuzzer_chaotic_good_corpus",
language = "C++",
proto = None,
tags = ["no_windows"],
uses_event_engine = False,
uses_polling = False,
deps = [
":server_fuzzer",
"//src/core:chaotic_good_server",
],
)

@ -513,6 +513,7 @@ Duration ScheduleConnection(
[event_engine, channel_args,
connect_timeout_ms = network_input.connect_timeout_ms(),
schedule = std::move(schedule), port]() mutable {
ExecCtx exec_ctx;
event_engine->Connect(
[event_engine, schedule = std::move(schedule)](
absl::StatusOr<std::unique_ptr<EventEngine::Endpoint>>

@ -21,10 +21,10 @@
#include <grpc/slice.h>
#include <grpc/support/log.h>
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/experiments/config.h"
#include "src/core/lib/gprpp/env.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/libfuzzer/libfuzzer_macro.h"
#include "test/core/end2end/fuzzers/api_fuzzer.pb.h"
#include "test/core/end2end/fuzzers/fuzzer_input.pb.h"
#include "test/core/end2end/fuzzers/fuzzing_common.h"
@ -41,15 +41,24 @@ namespace testing {
class ServerFuzzer final : public BasicFuzzer {
public:
explicit ServerFuzzer(const fuzzer_input::Msg& msg)
explicit ServerFuzzer(
const fuzzer_input::Msg& msg,
absl::FunctionRef<void(grpc_server*, int, const ChannelArgs&)>
server_setup)
: BasicFuzzer(msg.event_engine_actions()) {
ExecCtx exec_ctx;
grpc_server_register_completion_queue(server_, cq(), nullptr);
// TODO(ctiller): add more registered methods (one for POST, one for PUT)
grpc_server_register_method(server_, "/reg", nullptr, {}, 0);
auto* creds = grpc_insecure_server_credentials_create();
grpc_server_add_http2_port(server_, "0.0.0.0:1234", creds);
grpc_server_credentials_release(creds);
server_setup(
server_, 1234,
CoreConfiguration::Get()
.channel_args_preconditioning()
.PreconditionChannelArgs(
CreateChannelArgsFromFuzzingConfiguration(
msg.channel_args(), FuzzingEnvironment{resource_quota()})
.ToC()
.get()));
grpc_server_start(server_);
for (const auto& input : msg.network_input()) {
UpdateMinimumRunTime(ScheduleConnection(
@ -81,19 +90,23 @@ class ServerFuzzer final : public BasicFuzzer {
};
} // namespace testing
} // namespace grpc_core
DEFINE_PROTO_FUZZER(const fuzzer_input::Msg& msg) {
if (squelch && !grpc_core::GetEnv("GRPC_TRACE_FUZZER").has_value()) {
void RunServerFuzzer(
const fuzzer_input::Msg& msg,
absl::FunctionRef<void(grpc_server*, int, const ChannelArgs&)>
server_setup) {
if (squelch && !GetEnv("GRPC_TRACE_FUZZER").has_value()) {
gpr_set_log_function(dont_log);
}
static const int once = []() {
grpc_core::ForceEnableExperiment("event_engine_client", true);
grpc_core::ForceEnableExperiment("event_engine_listener", true);
ForceEnableExperiment("event_engine_client", true);
ForceEnableExperiment("event_engine_listener", true);
return 42;
}();
GPR_ASSERT(once == 42); // avoid unused variable warning
grpc_core::ApplyFuzzConfigVars(msg.config_vars());
grpc_core::TestOnlyReloadExperimentsFromConfigVariables();
grpc_core::testing::ServerFuzzer(msg).Run(msg.api_actions());
ApplyFuzzConfigVars(msg.config_vars());
TestOnlyReloadExperimentsFromConfigVariables();
testing::ServerFuzzer(msg, server_setup).Run(msg.api_actions());
}
} // namespace grpc_core

@ -0,0 +1,34 @@
// Copyright 2024 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_TEST_CORE_END2END_FUZZERS_SERVER_FUZZER_H
#define GRPC_TEST_CORE_END2END_FUZZERS_SERVER_FUZZER_H
#include "absl/functional/function_ref.h"
#include <grpc/grpc.h>
#include "src/core/lib/channel/channel_args.h"
#include "test/core/end2end/fuzzers/fuzzer_input.pb.h"
namespace grpc_core {
void RunServerFuzzer(
const fuzzer_input::Msg& msg,
absl::FunctionRef<void(grpc_server*, int, const ChannelArgs&)>
server_setup);
} // namespace grpc_core
#endif // GRPC_TEST_CORE_END2END_FUZZERS_SERVER_FUZZER_H

@ -0,0 +1,36 @@
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <grpc/grpc_security.h>
#include "src/core/ext/transport/chaotic_good/server/chaotic_good_server.h"
#include "src/libfuzzer/libfuzzer_macro.h"
#include "test/core/end2end/fuzzers/server_fuzzer.h"
DEFINE_PROTO_FUZZER(const fuzzer_input::Msg& msg) {
grpc_core::RunServerFuzzer(
msg, [](grpc_server* server, int port_num,
const grpc_core::ChannelArgs& channel_args) {
grpc_core::ExecCtx exec_ctx;
auto* listener = new grpc_core::chaotic_good::ChaoticGoodServerListener(
grpc_core::Server::FromC(server), channel_args,
[next = uint64_t(0)]() mutable {
return absl::StrCat(absl::Hex(next++));
});
auto port =
listener->Bind(absl::StrCat("ipv4:0.0.0.0:", port_num).c_str());
GPR_ASSERT(port.ok());
GPR_ASSERT(port.value() == port_num);
});
}

@ -0,0 +1,25 @@
network_input {
single_read_bytes: "\005\000"
connect_delay_ms: 4352
endpoint_config {
args {
resource_quota {
}
}
}
}
api_actions {
resize_resource_quota: 0
}
api_actions {
create_call {
host {
value: "\001\000\000\024"
}
}
}
config_vars {
verbosity: ""
}
channel_args {
}

@ -0,0 +1,5 @@
network_input {
single_read_bytes: "\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357"
}
channel_args {
}

@ -0,0 +1,20 @@
network_input {
input_segments {
segments {
header {
simple_header {
chaotic_good_alignment: "X"
}
}
}
}
}
config_vars {
stacktrace_minloglevel: ""
trace: ""
}
channel_args {
args {
i: 8
}
}

@ -0,0 +1,17 @@
network_input {
input_segments {
segments {
header {
raw_bytes: "\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305\305"
}
}
}
}
api_actions {
close_channel {
}
}
api_actions {
}
channel_args {
}

@ -0,0 +1,12 @@
network_input {
input_segments {
segments {
client_prefix {
}
}
}
}
api_actions {
}
channel_args {
}

@ -0,0 +1,10 @@
network_input {
single_read_bytes: "\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213\213"
connect_delay_ms: 96
}
api_actions {
}
event_engine_actions {
}
channel_args {
}

@ -0,0 +1,14 @@
network_input {
input_segments {
segments {
goaway {
debug_data: "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
}
}
}
}
config_vars {
verbosity: ""
}
channel_args {
}

@ -0,0 +1,22 @@
network_input {
input_segments {
segments {
chaotic_good {
headers_simple_header {
}
}
}
}
endpoint_config {
args {
i: 64
}
}
}
api_actions {
}
config_vars {
dns_resolver: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
}
channel_args {
}

@ -0,0 +1,40 @@
network_input {
single_read_bytes: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
endpoint_config {
args {
key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
}
}
}
network_input {
connect_timeout_ms: 11776
}
network_input {
connect_timeout_ms: -6
}
network_input {
input_segments {
segments {
chaotic_good {
headers_simple_header {
x_envoy_peer_metadata: "+"
path: "\000\000"
grpc_retry_pushback_ms: "7"
chaotic_good_connection_id: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
chaotic_good_alignment: "7"
}
}
}
}
connect_timeout_ms: 768
endpoint_config {
args {
i: 64
}
}
}
config_vars {
experiments: 0
}
channel_args {
}

@ -0,0 +1,17 @@
network_input {
input_segments {
segments {
chaotic_good {
headers_raw_bytes: ""
trailers_none {
}
}
}
}
}
config_vars {
stacktrace_minloglevel: ""
experiments: 0
}
channel_args {
}

@ -0,0 +1,13 @@
network_input {
single_read_bytes: ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"
}
api_actions {
request_call {
}
}
api_actions {
cancel_all_calls_if_shutdown {
}
}
channel_args {
}

@ -0,0 +1,8 @@
network_input {
single_read_bytes: "\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177"
}
config_vars {
experiments: 0
}
channel_args {
}

@ -0,0 +1,5 @@
network_input {
single_read_bytes: "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
}
channel_args {
}

@ -0,0 +1,13 @@
network_input {
input_segments {
segments {
client_prefix {
}
}
}
}
config_vars {
experiments: 0
}
channel_args {
}

@ -0,0 +1,7 @@
network_input {
single_read_bytes: "GGGGGGGGGGGGGGGGGGGGGGGGGGG"
}
api_actions {
}
config_vars {
}

@ -0,0 +1,16 @@
network_input {
input_segments {
segments {
rst_stream {
error_code: 1694498816
}
}
segments {
rst_stream {
error_code: 1694498816
}
}
}
}
channel_args {
}

@ -0,0 +1,34 @@
network_input {
input_segments {
segments {
chaotic_good {
headers_simple_header {
headers {
}
user_agent: ""
chaotic_good_connection_id: "\001\000\000\001"
chaotic_good_alignment: "0"
}
}
}
}
endpoint_config {
args {
key: "\'"
i: 64
}
}
}
api_actions {
}
api_actions {
sleep_ms: 4096
}
config_vars {
dns_resolver: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
}
channel_args {
args {
key: "\000\000\000\000\000\017B@"
}
}

@ -0,0 +1,5 @@
network_input {
single_read_bytes: "\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207\207"
}
channel_args {
}

@ -0,0 +1,10 @@
network_input {
single_read_bytes: "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
}
network_input {
}
config_vars {
experiments: 0
}
channel_args {
}

@ -0,0 +1,8 @@
network_input {
}
api_actions {
}
event_engine_actions {
}
channel_args {
}

@ -0,0 +1,14 @@
network_input {
input_segments {
segments {
client_prefix {
}
}
}
}
event_engine_actions {
}
config_vars {
stacktrace_minloglevel: "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"
trace: ""
}

@ -0,0 +1,7 @@
network_input {
}
network_input {
single_read_bytes: "\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035"
}
channel_args {
}

@ -0,0 +1,11 @@
network_input {
input_segments {
segments {
client_prefix {
}
}
}
}
network_input {
connect_delay_ms: 32000
}

@ -0,0 +1,14 @@
network_input {
input_segments {
segments {
client_prefix {
}
}
}
}
api_actions {
}
api_actions {
}
channel_args {
}

@ -0,0 +1,11 @@
network_input {
single_read_bytes: "222222222222222222222222222222222222222222222222222222222222222222222"
}
api_actions {
create_server {
channel_args {
}
}
}
channel_args {
}

@ -0,0 +1,28 @@
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <grpc/grpc_security.h>
#include "src/libfuzzer/libfuzzer_macro.h"
#include "test/core/end2end/fuzzers/server_fuzzer.h"
DEFINE_PROTO_FUZZER(const fuzzer_input::Msg& msg) {
grpc_core::RunServerFuzzer(msg, [](grpc_server* server, int port_num,
const grpc_core::ChannelArgs&) {
auto* creds = grpc_insecure_server_credentials_create();
grpc_server_add_http2_port(
server, absl::StrCat("0.0.0.0:", port_num).c_str(), creds);
grpc_server_credentials_release(creds);
});
}

@ -210,3 +210,34 @@ grpc_cc_test(
"//test/core/event_engine/fuzzing_event_engine:fuzzing_event_engine_proto",
],
)
grpc_cc_test(
name = "chaotic_good_server_test",
srcs = ["chaotic_good_server_test.cc"],
external_deps = [
"absl/strings",
"absl/time",
"gtest",
],
language = "C++",
tags = [
"no_windows",
],
uses_event_engine = True,
uses_polling = False,
deps = [
"//:grpc",
"//:grpc++",
"//:grpc_public_hdrs",
"//:parse_address",
"//:uri_parser",
"//src/core:channel_args",
"//src/core:chaotic_good_connector",
"//src/core:chaotic_good_server",
"//src/core:notification",
"//src/core:resource_quota",
"//src/core:time",
"//test/core/event_engine:event_engine_test_utils",
"//test/core/util:grpc_test_util",
],
)

@ -0,0 +1,149 @@
// Copyright 2024 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/core/ext/transport/chaotic_good/server/chaotic_good_server.h"
#include <memory>
#include <string>
#include <utility>
#include "absl/strings/str_cat.h"
#include "absl/time/time.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <grpc/event_engine/event_engine.h>
#include <grpc/grpc.h>
#include <grpc/status.h>
#include <grpcpp/server.h>
#include "src/core/ext/transport/chaotic_good/client/chaotic_good_connector.h"
#include "src/core/lib/address_utils/parse_address.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/notification.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/resource_quota/resource_quota.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/uri/uri_parser.h"
#include "test/core/event_engine/event_engine_test_utils.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
namespace grpc_core {
namespace chaotic_good {
namespace testing {
using grpc_event_engine::experimental::EventEngine;
class ChaoticGoodServerTest : public ::testing::Test {
public:
ChaoticGoodServerTest() {
event_engine_ = std::shared_ptr<EventEngine>(
grpc_event_engine::experimental::CreateEventEngine());
StartServer();
ConstructConnector();
}
~ChaoticGoodServerTest() override {
args_.channel_args = ChannelArgs();
if (connector_ != nullptr) connector_->Shutdown(absl::CancelledError());
connector_.reset();
auto* shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
grpc_server_shutdown_and_notify(server_, shutdown_cq, nullptr);
auto ev = grpc_completion_queue_pluck(
shutdown_cq, nullptr, grpc_timeout_milliseconds_to_deadline(15000),
nullptr);
GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
GPR_ASSERT(ev.tag == nullptr);
grpc_completion_queue_destroy(shutdown_cq);
grpc_server_destroy(server_);
grpc_event_engine::experimental::WaitForSingleOwner(
std::move(event_engine_));
}
void StartServer() {
port_ = grpc_pick_unused_port_or_die();
addr_ = absl::StrCat("ipv6:[::1]:", port_);
server_ = grpc_server_create(nullptr, nullptr);
core_server_ = Server::FromC(server_);
auto* listener =
new ChaoticGoodServerListener(core_server_, channel_args());
auto port = listener->Bind(addr_.c_str());
EXPECT_TRUE(port.ok());
EXPECT_EQ(port.value(), port_);
grpc_server_start(server_);
}
void ConstructConnector() {
auto uri = URI::Parse(addr_);
GPR_ASSERT(uri.ok());
GPR_ASSERT(grpc_parse_uri(*uri, &resolved_addr_));
args_.address = &resolved_addr_;
args_.deadline = Timestamp::Now() + Duration::Seconds(5);
args_.channel_args = channel_args();
connector_ = MakeRefCounted<ChaoticGoodConnector>(event_engine_);
}
protected:
static void OnConnectingFinished(void* arg, grpc_error_handle error) {
gpr_log(GPR_ERROR, "OnConnectingFinished: %p %s", arg,
error.ToString().c_str());
Notification* connect_finished_ = static_cast<Notification*>(arg);
connect_finished_->Notify();
}
ChannelArgs channel_args() {
return ChannelArgs()
.SetObject(event_engine_)
.Set(GRPC_ARG_RESOURCE_QUOTA, ResourceQuota::Default());
}
grpc_server* server_;
Server* core_server_;
ChaoticGoodConnector::Args args_;
ChaoticGoodConnector::Result connecting_result_;
grpc_closure on_connecting_finished_;
int port_;
std::string addr_;
grpc_resolved_address resolved_addr_;
RefCountedPtr<ChaoticGoodConnector> connector_;
std::shared_ptr<EventEngine> event_engine_;
};
TEST_F(ChaoticGoodServerTest, Connect) {
Notification connect_finished;
GRPC_CLOSURE_INIT(&on_connecting_finished_, OnConnectingFinished,
&connect_finished, grpc_schedule_on_exec_ctx);
connector_->Connect(args_, &connecting_result_, &on_connecting_finished_);
connect_finished.WaitForNotification();
}
TEST_F(ChaoticGoodServerTest, ConnectAndShutdown) {
Notification connect_finished;
GRPC_CLOSURE_INIT(&on_connecting_finished_, OnConnectingFinished,
&connect_finished, grpc_schedule_on_exec_ctx);
connector_->Connect(args_, &connecting_result_, &on_connecting_finished_);
connector_->Shutdown(absl::InternalError("shutdown"));
connect_finished.WaitForNotification();
}
} // namespace testing
} // namespace chaotic_good
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
// Must call to create default EventEngine.
grpc_init();
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

@ -9043,6 +9043,60 @@
],
"uses_polling": true
},
{
"args": [
"test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus",
"-runs=20000",
"-max_total_time=300",
"--directory=test/core/end2end/fuzzers/server_fuzzer_chaotic_good_corpus"
],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "server_fuzzer_chaotic_good",
"platforms": [
"linux",
"mac",
"posix"
],
"uses_polling": false
},
{
"args": [
"test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus",
"-runs=20000",
"-max_total_time=300",
"--directory=test/core/end2end/fuzzers/server_fuzzer_chttp2_corpus"
],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "server_fuzzer_chttp2",
"platforms": [
"linux",
"mac",
"posix"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save