grpc 1.75.0 → 1.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (834) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +24 -5
  3. data/include/grpc/credentials.h +27 -6
  4. data/include/grpc/event_engine/memory_allocator.h +2 -0
  5. data/include/grpc/event_engine/memory_request.h +2 -0
  6. data/include/grpc/impl/channel_arg_names.h +5 -0
  7. data/include/grpc/support/metrics.h +7 -1
  8. data/src/core/call/call_filters.cc +5 -5
  9. data/src/core/call/call_filters.h +211 -37
  10. data/src/core/call/call_spine.cc +1 -1
  11. data/src/core/call/call_spine.h +54 -32
  12. data/src/core/call/channelz_context.h +30 -0
  13. data/src/core/call/client_call.cc +49 -10
  14. data/src/core/call/client_call.h +6 -3
  15. data/src/core/call/filter_fusion.h +9 -9
  16. data/src/core/call/interception_chain.h +7 -6
  17. data/src/core/call/metadata_batch.cc +49 -55
  18. data/src/core/call/metadata_batch.h +10 -9
  19. data/src/core/call/metadata_info.cc +1 -1
  20. data/src/core/call/parsed_metadata.h +2 -2
  21. data/src/core/call/request_buffer.cc +1 -1
  22. data/src/core/call/security_context.cc +2 -2
  23. data/src/core/call/security_context.h +1 -1
  24. data/src/core/call/server_call.cc +5 -5
  25. data/src/core/call/server_call.h +6 -4
  26. data/src/core/call/simple_slice_based_metadata.h +1 -1
  27. data/src/core/call/status_util.cc +1 -1
  28. data/src/core/channelz/channel_trace.cc +1 -1
  29. data/src/core/channelz/channel_trace.h +3 -3
  30. data/src/core/channelz/channelz.cc +25 -29
  31. data/src/core/channelz/channelz.h +73 -22
  32. data/src/core/channelz/channelz_registry.cc +2 -2
  33. data/src/core/channelz/channelz_registry.h +53 -2
  34. data/src/core/channelz/property_list.cc +18 -0
  35. data/src/core/channelz/property_list.h +15 -4
  36. data/src/core/channelz/text_encode.cc +66 -0
  37. data/src/core/channelz/text_encode.h +29 -0
  38. data/src/core/channelz/v2tov1/convert.cc +17 -6
  39. data/src/core/channelz/v2tov1/legacy_api.cc +18 -12
  40. data/src/core/channelz/v2tov1/property_list.cc +2 -1
  41. data/src/core/channelz/ztrace_collector.h +260 -87
  42. data/src/core/client_channel/backup_poller.cc +7 -8
  43. data/src/core/client_channel/buffered_call.cc +140 -0
  44. data/src/core/client_channel/buffered_call.h +104 -0
  45. data/src/core/client_channel/client_channel.cc +144 -84
  46. data/src/core/client_channel/client_channel.h +8 -11
  47. data/src/core/client_channel/client_channel_factory.h +1 -1
  48. data/src/core/client_channel/client_channel_filter.cc +424 -686
  49. data/src/core/client_channel/client_channel_filter.h +57 -150
  50. data/src/core/client_channel/client_channel_internal.h +8 -5
  51. data/src/core/client_channel/client_channel_service_config.cc +43 -3
  52. data/src/core/client_channel/client_channel_service_config.h +12 -1
  53. data/src/core/client_channel/config_selector.h +5 -5
  54. data/src/core/client_channel/connector.h +2 -0
  55. data/src/core/client_channel/dynamic_filters.cc +5 -5
  56. data/src/core/client_channel/global_subchannel_pool.cc +0 -37
  57. data/src/core/client_channel/global_subchannel_pool.h +1 -28
  58. data/src/core/client_channel/lb_metadata.h +1 -1
  59. data/src/core/client_channel/load_balanced_call_destination.cc +10 -12
  60. data/src/core/client_channel/load_balanced_call_destination.h +1 -1
  61. data/src/core/client_channel/local_subchannel_pool.cc +4 -4
  62. data/src/core/client_channel/retry_filter.cc +2 -2
  63. data/src/core/client_channel/retry_filter.h +3 -3
  64. data/src/core/client_channel/retry_filter_legacy_call_data.cc +11 -12
  65. data/src/core/client_channel/retry_filter_legacy_call_data.h +6 -8
  66. data/src/core/client_channel/retry_service_config.cc +3 -3
  67. data/src/core/client_channel/retry_service_config.h +1 -1
  68. data/src/core/client_channel/subchannel.cc +114 -25
  69. data/src/core/client_channel/subchannel.h +24 -8
  70. data/src/core/client_channel/subchannel_pool_interface.cc +2 -2
  71. data/src/core/client_channel/subchannel_pool_interface.h +1 -1
  72. data/src/core/client_channel/subchannel_stream_client.cc +5 -5
  73. data/src/core/client_channel/subchannel_stream_client.h +3 -3
  74. data/src/core/config/config_vars.cc +38 -3
  75. data/src/core/config/config_vars.h +26 -0
  76. data/src/core/config/core_configuration.cc +5 -5
  77. data/src/core/config/core_configuration.h +8 -8
  78. data/src/core/config/load_config.cc +13 -1
  79. data/src/core/config/load_config.h +2 -0
  80. data/src/core/credentials/call/call_credentials.h +4 -4
  81. data/src/core/credentials/call/call_creds_registry.h +1 -1
  82. data/src/core/credentials/call/call_creds_registry_init.cc +2 -2
  83. data/src/core/credentials/call/call_creds_util.cc +7 -6
  84. data/src/core/credentials/call/composite/composite_call_credentials.cc +6 -6
  85. data/src/core/credentials/call/composite/composite_call_credentials.h +1 -1
  86. data/src/core/credentials/call/external/aws_external_account_credentials.cc +9 -9
  87. data/src/core/credentials/call/external/aws_external_account_credentials.h +1 -1
  88. data/src/core/credentials/call/external/external_account_credentials.cc +12 -12
  89. data/src/core/credentials/call/external/external_account_credentials.h +1 -1
  90. data/src/core/credentials/call/external/file_external_account_credentials.cc +3 -3
  91. data/src/core/credentials/call/external/file_external_account_credentials.h +1 -1
  92. data/src/core/credentials/call/external/url_external_account_credentials.cc +7 -7
  93. data/src/core/credentials/call/external/url_external_account_credentials.h +1 -1
  94. data/src/core/credentials/call/gcp_service_account_identity/gcp_service_account_identity_credentials.cc +24 -71
  95. data/src/core/credentials/call/gcp_service_account_identity/gcp_service_account_identity_credentials.h +1 -8
  96. data/src/core/credentials/call/iam/iam_credentials.cc +6 -6
  97. data/src/core/credentials/call/iam/iam_credentials.h +1 -1
  98. data/src/core/credentials/call/json_util.cc +1 -1
  99. data/src/core/credentials/call/jwt/json_token.cc +7 -7
  100. data/src/core/credentials/call/jwt/jwt_credentials.cc +5 -5
  101. data/src/core/credentials/call/jwt/jwt_credentials.h +4 -4
  102. data/src/core/credentials/call/jwt/jwt_verifier.cc +19 -18
  103. data/src/core/credentials/call/jwt_token_file/jwt_token_file_call_credentials.cc +2 -2
  104. data/src/core/credentials/call/jwt_token_file/jwt_token_file_call_credentials.h +3 -3
  105. data/src/core/credentials/call/jwt_util.cc +3 -3
  106. data/src/core/credentials/call/jwt_util.h +1 -1
  107. data/src/core/credentials/call/oauth2/oauth2_credentials.cc +49 -72
  108. data/src/core/credentials/call/oauth2/oauth2_credentials.h +3 -9
  109. data/src/core/credentials/call/plugin/plugin_credentials.cc +6 -6
  110. data/src/core/credentials/call/plugin/plugin_credentials.h +2 -2
  111. data/src/core/credentials/call/token_fetcher/token_fetcher_credentials.cc +46 -0
  112. data/src/core/credentials/call/token_fetcher/token_fetcher_credentials.h +32 -3
  113. data/src/core/credentials/transport/alts/alts_credentials.cc +5 -5
  114. data/src/core/credentials/transport/alts/alts_security_connector.cc +17 -15
  115. data/src/core/credentials/transport/alts/check_gcp_environment_no_op.cc +1 -1
  116. data/src/core/credentials/transport/alts/grpc_alts_credentials_client_options.cc +23 -3
  117. data/src/core/credentials/transport/alts/grpc_alts_credentials_options.cc +10 -1
  118. data/src/core/credentials/transport/alts/grpc_alts_credentials_options.h +31 -0
  119. data/src/core/credentials/transport/alts/grpc_alts_credentials_server_options.cc +8 -3
  120. data/src/core/credentials/transport/channel_creds_registry.h +1 -1
  121. data/src/core/credentials/transport/channel_creds_registry_init.cc +1 -1
  122. data/src/core/credentials/transport/composite/composite_channel_credentials.cc +7 -7
  123. data/src/core/credentials/transport/composite/composite_channel_credentials.h +1 -1
  124. data/src/core/credentials/transport/fake/fake_credentials.cc +1 -1
  125. data/src/core/credentials/transport/fake/fake_credentials.h +1 -1
  126. data/src/core/credentials/transport/fake/fake_security_connector.cc +7 -7
  127. data/src/core/credentials/transport/google_default/credentials_generic.cc +2 -2
  128. data/src/core/credentials/transport/google_default/google_default_credentials.cc +83 -39
  129. data/src/core/credentials/transport/google_default/google_default_credentials.h +0 -2
  130. data/src/core/credentials/transport/insecure/insecure_security_connector.cc +3 -3
  131. data/src/core/credentials/transport/insecure/insecure_security_connector.h +2 -2
  132. data/src/core/credentials/transport/local/local_security_connector.cc +13 -13
  133. data/src/core/credentials/transport/security_connector.cc +6 -6
  134. data/src/core/credentials/transport/security_connector.h +2 -2
  135. data/src/core/credentials/transport/ssl/ssl_credentials.cc +13 -13
  136. data/src/core/credentials/transport/ssl/ssl_credentials.h +2 -2
  137. data/src/core/credentials/transport/ssl/ssl_security_connector.cc +8 -8
  138. data/src/core/credentials/transport/tls/certificate_provider_factory.h +1 -1
  139. data/src/core/credentials/transport/tls/certificate_provider_registry.cc +2 -2
  140. data/src/core/credentials/transport/tls/certificate_provider_registry.h +1 -1
  141. data/src/core/credentials/transport/tls/grpc_tls_certificate_distributor.cc +25 -25
  142. data/src/core/credentials/transport/tls/grpc_tls_certificate_distributor.h +2 -2
  143. data/src/core/credentials/transport/tls/grpc_tls_certificate_match.cc +1 -1
  144. data/src/core/credentials/transport/tls/grpc_tls_certificate_provider.cc +8 -8
  145. data/src/core/credentials/transport/tls/grpc_tls_certificate_provider.h +5 -5
  146. data/src/core/credentials/transport/tls/grpc_tls_certificate_verifier.cc +3 -3
  147. data/src/core/credentials/transport/tls/grpc_tls_certificate_verifier.h +4 -4
  148. data/src/core/credentials/transport/tls/grpc_tls_credentials_options.cc +18 -18
  149. data/src/core/credentials/transport/tls/grpc_tls_crl_provider.cc +5 -5
  150. data/src/core/credentials/transport/tls/grpc_tls_crl_provider.h +3 -3
  151. data/src/core/credentials/transport/tls/load_system_roots_supported.cc +1 -1
  152. data/src/core/credentials/transport/tls/spiffe_utils.cc +10 -8
  153. data/src/core/credentials/transport/tls/spiffe_utils.h +2 -2
  154. data/src/core/credentials/transport/tls/ssl_utils.cc +18 -13
  155. data/src/core/credentials/transport/tls/ssl_utils.h +2 -2
  156. data/src/core/credentials/transport/tls/tls_credentials.cc +3 -3
  157. data/src/core/credentials/transport/tls/tls_security_connector.cc +15 -15
  158. data/src/core/credentials/transport/tls/tls_security_connector.h +3 -3
  159. data/src/core/credentials/transport/transport_credentials.cc +3 -3
  160. data/src/core/credentials/transport/transport_credentials.h +4 -4
  161. data/src/core/credentials/transport/xds/xds_credentials.cc +5 -5
  162. data/src/core/credentials/transport/xds/xds_credentials.h +1 -1
  163. data/src/core/ext/filters/backend_metrics/backend_metric_filter.cc +2 -2
  164. data/src/core/ext/filters/backend_metrics/backend_metric_filter.h +4 -1
  165. data/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc +6 -4
  166. data/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h +2 -2
  167. data/src/core/ext/filters/fault_injection/fault_injection_filter.cc +7 -7
  168. data/src/core/ext/filters/fault_injection/fault_injection_filter.h +6 -3
  169. data/src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h +1 -1
  170. data/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc +2 -2
  171. data/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h +6 -3
  172. data/src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h +1 -1
  173. data/src/core/ext/filters/http/client/http_client_filter.cc +6 -6
  174. data/src/core/ext/filters/http/client/http_client_filter.h +4 -1
  175. data/src/core/ext/filters/http/client_authority_filter.cc +2 -2
  176. data/src/core/ext/filters/http/client_authority_filter.h +4 -1
  177. data/src/core/ext/filters/http/http_filters_plugin.cc +1 -1
  178. data/src/core/ext/filters/http/message_compress/compression_filter.cc +11 -11
  179. data/src/core/ext/filters/http/message_compress/compression_filter.h +24 -5
  180. data/src/core/ext/filters/http/server/http_server_filter.cc +3 -3
  181. data/src/core/ext/filters/http/server/http_server_filter.h +4 -1
  182. data/src/core/ext/filters/message_size/message_size_filter.cc +2 -2
  183. data/src/core/ext/filters/message_size/message_size_filter.h +8 -2
  184. data/src/core/ext/filters/rbac/rbac_filter.cc +1 -1
  185. data/src/core/ext/filters/rbac/rbac_filter.h +4 -1
  186. data/src/core/ext/filters/rbac/rbac_service_config_parser.cc +3 -3
  187. data/src/core/ext/filters/rbac/rbac_service_config_parser.h +1 -1
  188. data/src/core/ext/filters/stateful_session/stateful_session_filter.cc +14 -14
  189. data/src/core/ext/filters/stateful_session/stateful_session_filter.h +13 -2
  190. data/src/core/ext/filters/stateful_session/stateful_session_service_config_parser.h +1 -1
  191. data/src/core/ext/transport/chttp2/alpn/alpn.cc +2 -2
  192. data/src/core/ext/transport/chttp2/client/chttp2_connector.cc +58 -44
  193. data/src/core/ext/transport/chttp2/client/chttp2_connector.h +2 -3
  194. data/src/core/ext/transport/chttp2/server/chttp2_server.cc +25 -24
  195. data/src/core/ext/transport/chttp2/server/chttp2_server.h +1 -2
  196. data/src/core/ext/transport/chttp2/transport/bin_decoder.cc +6 -6
  197. data/src/core/ext/transport/chttp2/transport/bin_encoder.cc +6 -6
  198. data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +306 -148
  199. data/src/core/ext/transport/chttp2/transport/chttp2_transport.h +10 -2
  200. data/src/core/ext/transport/chttp2/transport/flow_control.cc +42 -7
  201. data/src/core/ext/transport/chttp2/transport/flow_control.h +223 -83
  202. data/src/core/ext/transport/chttp2/transport/flow_control_manager.h +105 -0
  203. data/src/core/ext/transport/chttp2/transport/frame.cc +175 -27
  204. data/src/core/ext/transport/chttp2/transport/frame.h +58 -10
  205. data/src/core/ext/transport/chttp2/transport/frame_data.cc +4 -4
  206. data/src/core/ext/transport/chttp2/transport/frame_data.h +1 -1
  207. data/src/core/ext/transport/chttp2/transport/frame_goaway.cc +5 -5
  208. data/src/core/ext/transport/chttp2/transport/frame_ping.cc +6 -6
  209. data/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc +7 -7
  210. data/src/core/ext/transport/chttp2/transport/frame_security.cc +1 -1
  211. data/src/core/ext/transport/chttp2/transport/frame_settings.cc +7 -15
  212. data/src/core/ext/transport/chttp2/transport/frame_window_update.cc +6 -6
  213. data/src/core/ext/transport/chttp2/transport/goaway.cc +129 -0
  214. data/src/core/ext/transport/chttp2/transport/goaway.h +350 -0
  215. data/src/core/ext/transport/chttp2/transport/header_assembler.h +194 -54
  216. data/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +3 -3
  217. data/src/core/ext/transport/chttp2/transport/hpack_encoder.h +8 -6
  218. data/src/core/ext/transport/chttp2/transport/hpack_encoder_table.cc +8 -8
  219. data/src/core/ext/transport/chttp2/transport/hpack_parse_result.cc +3 -3
  220. data/src/core/ext/transport/chttp2/transport/hpack_parse_result.h +5 -5
  221. data/src/core/ext/transport/chttp2/transport/hpack_parser.cc +34 -34
  222. data/src/core/ext/transport/chttp2/transport/hpack_parser.h +6 -7
  223. data/src/core/ext/transport/chttp2/transport/hpack_parser_table.cc +8 -8
  224. data/src/core/ext/transport/chttp2/transport/hpack_parser_table.h +1 -1
  225. data/src/core/ext/transport/chttp2/transport/http2_client_transport.cc +1475 -632
  226. data/src/core/ext/transport/chttp2/transport/http2_client_transport.h +384 -373
  227. data/src/core/ext/transport/chttp2/transport/http2_settings.cc +1 -1
  228. data/src/core/ext/transport/chttp2/transport/http2_settings.h +6 -4
  229. data/src/core/ext/transport/chttp2/transport/http2_settings_manager.cc +4 -3
  230. data/src/core/ext/transport/chttp2/transport/http2_settings_manager.h +6 -5
  231. data/src/core/ext/transport/chttp2/transport/http2_settings_promises.h +417 -0
  232. data/src/core/ext/transport/chttp2/transport/http2_status.h +7 -1
  233. data/src/core/ext/transport/chttp2/transport/http2_transport.cc +337 -30
  234. data/src/core/ext/transport/chttp2/transport/http2_transport.h +196 -21
  235. data/src/core/ext/transport/chttp2/transport/http2_ztrace_collector.h +172 -72
  236. data/src/core/ext/transport/chttp2/transport/incoming_metadata_tracker.h +128 -0
  237. data/src/core/ext/transport/chttp2/transport/internal.h +31 -19
  238. data/src/core/ext/transport/chttp2/transport/keepalive.cc +12 -5
  239. data/src/core/ext/transport/chttp2/transport/keepalive.h +14 -10
  240. data/src/core/ext/transport/chttp2/transport/message_assembler.h +30 -21
  241. data/src/core/ext/transport/chttp2/transport/parsing.cc +25 -23
  242. data/src/core/ext/transport/chttp2/transport/ping_callbacks.cc +2 -2
  243. data/src/core/ext/transport/chttp2/transport/ping_callbacks.h +3 -3
  244. data/src/core/ext/transport/chttp2/transport/ping_promise.cc +70 -28
  245. data/src/core/ext/transport/chttp2/transport/ping_promise.h +63 -23
  246. data/src/core/ext/transport/chttp2/transport/ping_rate_policy.cc +1 -1
  247. data/src/core/ext/transport/chttp2/transport/security_frame.cc +31 -0
  248. data/src/core/ext/transport/chttp2/transport/security_frame.h +32 -0
  249. data/src/core/ext/transport/chttp2/transport/stream.h +287 -0
  250. data/src/core/ext/transport/chttp2/transport/stream_data_queue.h +476 -208
  251. data/src/core/ext/transport/chttp2/transport/stream_lists.cc +8 -8
  252. data/src/core/ext/transport/chttp2/transport/transport_common.cc +17 -1
  253. data/src/core/ext/transport/chttp2/transport/transport_common.h +57 -0
  254. data/src/core/ext/transport/chttp2/transport/varint.h +2 -2
  255. data/src/core/ext/transport/chttp2/transport/writable_streams.h +202 -84
  256. data/src/core/ext/transport/chttp2/transport/write_size_policy.cc +2 -2
  257. data/src/core/ext/transport/chttp2/transport/writing.cc +6 -6
  258. data/src/core/ext/transport/inproc/inproc_transport.cc +9 -3
  259. data/src/core/ext/transport/inproc/legacy_inproc_transport.cc +11 -8
  260. data/src/core/ext/upb-gen/src/proto/grpc/channelz/v2/service.upb.h +740 -0
  261. data/src/core/ext/upb-gen/src/proto/grpc/channelz/v2/service.upb_minitable.c +218 -0
  262. data/src/core/ext/upb-gen/src/proto/grpc/channelz/v2/service.upb_minitable.h +46 -0
  263. data/src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb.h +87 -55
  264. data/src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c +23 -21
  265. data/src/core/ext/upbdefs-gen/src/proto/grpc/channelz/v2/channelz.upbdefs.c +80 -0
  266. data/src/core/ext/upbdefs-gen/src/proto/grpc/channelz/v2/channelz.upbdefs.h +47 -0
  267. data/src/core/ext/upbdefs-gen/src/proto/grpc/channelz/v2/service.upbdefs.c +129 -0
  268. data/src/core/ext/upbdefs-gen/src/proto/grpc/channelz/v2/service.upbdefs.h +72 -0
  269. data/src/core/filter/auth/auth_filters.h +7 -1
  270. data/src/core/filter/auth/client_auth_filter.cc +2 -2
  271. data/src/core/filter/auth/server_auth_filter.cc +5 -5
  272. data/src/core/filter/blackboard.h +2 -2
  273. data/src/core/filter/filter_args.h +40 -2
  274. data/src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc +2 -2
  275. data/src/core/handshaker/handshaker.cc +8 -8
  276. data/src/core/handshaker/handshaker.h +2 -2
  277. data/src/core/handshaker/http_connect/http_connect_handshaker.cc +5 -5
  278. data/src/core/handshaker/http_connect/http_proxy_mapper.cc +12 -12
  279. data/src/core/handshaker/http_connect/http_proxy_mapper.h +1 -1
  280. data/src/core/handshaker/http_connect/xds_http_proxy_mapper.cc +1 -1
  281. data/src/core/handshaker/http_connect/xds_http_proxy_mapper.h +1 -1
  282. data/src/core/handshaker/proxy_mapper.h +1 -1
  283. data/src/core/handshaker/proxy_mapper_registry.h +1 -1
  284. data/src/core/handshaker/security/legacy_secure_endpoint.cc +6 -6
  285. data/src/core/handshaker/security/pipelined_secure_endpoint.cc +38 -15
  286. data/src/core/handshaker/security/secure_endpoint.cc +31 -11
  287. data/src/core/handshaker/security/security_handshaker.cc +11 -8
  288. data/src/core/handshaker/security/security_handshaker.h +1 -1
  289. data/src/core/handshaker/tcp_connect/tcp_connect_handshaker.cc +6 -6
  290. data/src/core/lib/address_utils/parse_address.cc +5 -5
  291. data/src/core/lib/address_utils/parse_address.h +2 -2
  292. data/src/core/lib/address_utils/sockaddr_utils.cc +4 -4
  293. data/src/core/lib/address_utils/sockaddr_utils.h +1 -1
  294. data/src/core/lib/channel/channel_args.cc +1 -1
  295. data/src/core/lib/channel/channel_args.h +2 -2
  296. data/src/core/lib/channel/channel_stack.cc +29 -25
  297. data/src/core/lib/channel/channel_stack.h +8 -3
  298. data/src/core/lib/channel/channel_stack_builder.cc +8 -4
  299. data/src/core/lib/channel/channel_stack_builder.h +10 -9
  300. data/src/core/lib/channel/channel_stack_builder_impl.cc +8 -13
  301. data/src/core/lib/channel/channel_stack_builder_impl.h +1 -1
  302. data/src/core/lib/channel/connected_channel.cc +4 -4
  303. data/src/core/lib/channel/promise_based_filter.cc +132 -72
  304. data/src/core/lib/channel/promise_based_filter.h +39 -23
  305. data/src/core/lib/compression/compression_internal.cc +6 -6
  306. data/src/core/lib/compression/compression_internal.h +1 -1
  307. data/src/core/lib/compression/message_compress.cc +8 -8
  308. data/src/core/lib/debug/trace.cc +2 -5
  309. data/src/core/lib/debug/trace.h +10 -0
  310. data/src/core/lib/debug/trace_flags.cc +2 -2
  311. data/src/core/lib/debug/trace_flags.h +1 -1
  312. data/src/core/lib/event_engine/ares_resolver.cc +30 -28
  313. data/src/core/lib/event_engine/ares_resolver.h +4 -4
  314. data/src/core/lib/event_engine/cf_engine/cf_engine.cc +3 -3
  315. data/src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc +2 -2
  316. data/src/core/lib/event_engine/cf_engine/cfstream_endpoint.h +1 -1
  317. data/src/core/lib/event_engine/cf_engine/dns_service_resolver.cc +4 -4
  318. data/src/core/lib/event_engine/cf_engine/dns_service_resolver.h +3 -3
  319. data/src/core/lib/event_engine/channel_args_endpoint_config.h +1 -1
  320. data/src/core/lib/event_engine/default_event_engine.cc +1 -1
  321. data/src/core/lib/event_engine/event_engine.cc +1 -1
  322. data/src/core/lib/event_engine/extensions/channelz.h +3 -3
  323. data/src/core/lib/event_engine/extensions/chaotic_good_extension.h +1 -1
  324. data/src/core/lib/event_engine/extensions/supports_fd.h +5 -5
  325. data/src/core/lib/event_engine/extensions/tcp_trace.h +8 -1
  326. data/src/core/lib/event_engine/grpc_polled_fd.h +1 -1
  327. data/src/core/lib/event_engine/memory_allocator_factory.h +1 -1
  328. data/src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc +12 -12
  329. data/src/core/lib/event_engine/posix_engine/ev_epoll1_linux.h +5 -5
  330. data/src/core/lib/event_engine/posix_engine/ev_poll_posix.cc +15 -15
  331. data/src/core/lib/event_engine/posix_engine/ev_poll_posix.h +3 -3
  332. data/src/core/lib/event_engine/posix_engine/event_poller.h +2 -2
  333. data/src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc +2 -2
  334. data/src/core/lib/event_engine/posix_engine/file_descriptor_collection.cc +1 -1
  335. data/src/core/lib/event_engine/posix_engine/file_descriptor_collection.h +1 -1
  336. data/src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h +4 -4
  337. data/src/core/lib/event_engine/posix_engine/internal_errqueue.cc +1 -1
  338. data/src/core/lib/event_engine/posix_engine/lockfree_event.cc +3 -3
  339. data/src/core/lib/event_engine/posix_engine/lockfree_event.h +1 -1
  340. data/src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.cc +3 -3
  341. data/src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.h +1 -1
  342. data/src/core/lib/event_engine/posix_engine/posix_endpoint.cc +28 -27
  343. data/src/core/lib/event_engine/posix_engine/posix_endpoint.h +17 -17
  344. data/src/core/lib/event_engine/posix_engine/posix_engine.cc +175 -177
  345. data/src/core/lib/event_engine/posix_engine/posix_engine.h +40 -61
  346. data/src/core/lib/event_engine/posix_engine/posix_engine_listener.cc +11 -7
  347. data/src/core/lib/event_engine/posix_engine/posix_engine_listener.h +4 -4
  348. data/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc +9 -9
  349. data/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.h +1 -1
  350. data/src/core/lib/event_engine/posix_engine/posix_interface.h +2 -2
  351. data/src/core/lib/event_engine/posix_engine/posix_interface_posix.cc +5 -5
  352. data/src/core/lib/event_engine/posix_engine/posix_write_event_sink.h +1 -1
  353. data/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc +1 -1
  354. data/src/core/lib/event_engine/posix_engine/tcp_socket_utils.h +1 -1
  355. data/src/core/lib/event_engine/posix_engine/timer.h +1 -1
  356. data/src/core/lib/event_engine/posix_engine/timer_manager.cc +4 -4
  357. data/src/core/lib/event_engine/posix_engine/timer_manager.h +1 -1
  358. data/src/core/lib/event_engine/posix_engine/traced_buffer_list.cc +2 -2
  359. data/src/core/lib/event_engine/posix_engine/traced_buffer_list.h +2 -2
  360. data/src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.cc +1 -1
  361. data/src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.h +2 -2
  362. data/src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.cc +1 -1
  363. data/src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h +2 -2
  364. data/src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h +1 -1
  365. data/src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc +2 -2
  366. data/src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h +1 -1
  367. data/src/core/lib/event_engine/ref_counted_dns_resolver_interface.h +1 -1
  368. data/src/core/lib/event_engine/resolved_address.cc +3 -3
  369. data/src/core/lib/event_engine/shim.cc +8 -11
  370. data/src/core/lib/event_engine/shim.h +2 -1
  371. data/src/core/lib/event_engine/slice.cc +2 -2
  372. data/src/core/lib/event_engine/tcp_socket_utils.cc +15 -15
  373. data/src/core/lib/event_engine/thread_pool/thread_count.cc +1 -1
  374. data/src/core/lib/event_engine/thread_pool/thread_count.h +1 -1
  375. data/src/core/lib/event_engine/thread_pool/work_stealing_thread_pool.cc +11 -11
  376. data/src/core/lib/event_engine/thread_pool/work_stealing_thread_pool.h +3 -3
  377. data/src/core/lib/event_engine/utils.cc +3 -3
  378. data/src/core/lib/event_engine/utils.h +1 -1
  379. data/src/core/lib/event_engine/windows/grpc_polled_fd_windows.cc +32 -32
  380. data/src/core/lib/event_engine/windows/grpc_polled_fd_windows.h +2 -2
  381. data/src/core/lib/event_engine/windows/iocp.cc +11 -11
  382. data/src/core/lib/event_engine/windows/iocp.h +1 -1
  383. data/src/core/lib/event_engine/windows/native_windows_dns_resolver.cc +5 -2
  384. data/src/core/lib/event_engine/windows/win_socket.cc +7 -7
  385. data/src/core/lib/event_engine/windows/win_socket.h +2 -2
  386. data/src/core/lib/event_engine/windows/windows_endpoint.cc +16 -16
  387. data/src/core/lib/event_engine/windows/windows_engine.cc +20 -18
  388. data/src/core/lib/event_engine/windows/windows_engine.h +3 -3
  389. data/src/core/lib/event_engine/windows/windows_listener.cc +10 -10
  390. data/src/core/lib/event_engine/windows/windows_listener.h +2 -2
  391. data/src/core/lib/event_engine/work_queue/basic_work_queue.h +2 -2
  392. data/src/core/lib/experiments/config.cc +4 -4
  393. data/src/core/lib/experiments/experiments.cc +255 -42
  394. data/src/core/lib/experiments/experiments.h +105 -21
  395. data/src/core/lib/iomgr/buffer_list.cc +1 -1
  396. data/src/core/lib/iomgr/call_combiner.cc +4 -4
  397. data/src/core/lib/iomgr/call_combiner.h +2 -2
  398. data/src/core/lib/iomgr/cfstream_handle.cc +1 -1
  399. data/src/core/lib/iomgr/closure.h +2 -2
  400. data/src/core/lib/iomgr/combiner.cc +2 -2
  401. data/src/core/lib/iomgr/endpoint.h +1 -1
  402. data/src/core/lib/iomgr/endpoint_cfstream.cc +7 -7
  403. data/src/core/lib/iomgr/endpoint_pair_posix.cc +6 -6
  404. data/src/core/lib/iomgr/endpoint_pair_windows.cc +16 -15
  405. data/src/core/lib/iomgr/error.cc +1 -1
  406. data/src/core/lib/iomgr/error.h +2 -2
  407. data/src/core/lib/iomgr/error_cfstream.cc +1 -1
  408. data/src/core/lib/iomgr/ev_apple.cc +1 -1
  409. data/src/core/lib/iomgr/ev_epoll1_linux.cc +19 -19
  410. data/src/core/lib/iomgr/ev_poll_posix.cc +14 -14
  411. data/src/core/lib/iomgr/ev_posix.cc +3 -3
  412. data/src/core/lib/iomgr/event_engine_shims/closure.cc +3 -3
  413. data/src/core/lib/iomgr/event_engine_shims/closure.h +1 -1
  414. data/src/core/lib/iomgr/event_engine_shims/endpoint.cc +10 -9
  415. data/src/core/lib/iomgr/event_engine_shims/endpoint.h +1 -1
  416. data/src/core/lib/iomgr/event_engine_shims/tcp_client.cc +2 -2
  417. data/src/core/lib/iomgr/exec_ctx.cc +3 -3
  418. data/src/core/lib/iomgr/exec_ctx.h +1 -1
  419. data/src/core/lib/iomgr/fork_posix.cc +1 -1
  420. data/src/core/lib/iomgr/internal_errqueue.cc +1 -1
  421. data/src/core/lib/iomgr/iocp_windows.cc +9 -9
  422. data/src/core/lib/iomgr/iomgr.cc +1 -1
  423. data/src/core/lib/iomgr/iomgr_windows.cc +3 -3
  424. data/src/core/lib/iomgr/lockfree_event.cc +3 -3
  425. data/src/core/lib/iomgr/polling_entity.cc +4 -4
  426. data/src/core/lib/iomgr/resolve_address.cc +1 -1
  427. data/src/core/lib/iomgr/resolve_address.h +2 -2
  428. data/src/core/lib/iomgr/resolve_address_posix.cc +4 -4
  429. data/src/core/lib/iomgr/resolve_address_windows.cc +1 -1
  430. data/src/core/lib/iomgr/sockaddr_utils_posix.cc +1 -1
  431. data/src/core/lib/iomgr/socket_utils_common_posix.cc +4 -4
  432. data/src/core/lib/iomgr/socket_windows.cc +6 -6
  433. data/src/core/lib/iomgr/tcp_client_cfstream.cc +1 -1
  434. data/src/core/lib/iomgr/tcp_client_posix.cc +7 -7
  435. data/src/core/lib/iomgr/tcp_client_windows.cc +4 -4
  436. data/src/core/lib/iomgr/tcp_posix.cc +47 -47
  437. data/src/core/lib/iomgr/tcp_server.cc +5 -0
  438. data/src/core/lib/iomgr/tcp_server.h +7 -0
  439. data/src/core/lib/iomgr/tcp_server_posix.cc +62 -31
  440. data/src/core/lib/iomgr/tcp_server_utils_posix.h +4 -1
  441. data/src/core/lib/iomgr/tcp_server_utils_posix_common.cc +7 -7
  442. data/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc +4 -4
  443. data/src/core/lib/iomgr/tcp_server_windows.cc +70 -31
  444. data/src/core/lib/iomgr/tcp_windows.cc +8 -8
  445. data/src/core/lib/iomgr/timer_generic.cc +5 -5
  446. data/src/core/lib/iomgr/timer_manager.cc +3 -3
  447. data/src/core/lib/iomgr/unix_sockets_posix.cc +3 -3
  448. data/src/core/lib/iomgr/unix_sockets_posix.h +1 -1
  449. data/src/core/lib/iomgr/unix_sockets_posix_noop.cc +2 -2
  450. data/src/core/lib/iomgr/vsock.cc +1 -1
  451. data/src/core/lib/iomgr/vsock.h +1 -1
  452. data/src/core/lib/iomgr/wakeup_fd_pipe.cc +1 -1
  453. data/src/core/lib/promise/activity.cc +3 -3
  454. data/src/core/lib/promise/activity.h +11 -10
  455. data/src/core/lib/promise/all_ok.h +3 -3
  456. data/src/core/lib/promise/arena_promise.h +47 -6
  457. data/src/core/lib/promise/context.h +3 -3
  458. data/src/core/lib/promise/detail/join_state.h +10 -10
  459. data/src/core/lib/promise/detail/promise_factory.h +1 -1
  460. data/src/core/lib/promise/detail/promise_like.h +1 -1
  461. data/src/core/lib/promise/detail/seq_state.h +16 -16
  462. data/src/core/lib/promise/detail/status.h +2 -2
  463. data/src/core/lib/promise/exec_ctx_wakeup_scheduler.h +1 -1
  464. data/src/core/lib/promise/for_each.h +8 -8
  465. data/src/core/lib/promise/if.h +1 -1
  466. data/src/core/lib/promise/inter_activity_latch.h +3 -3
  467. data/src/core/lib/promise/inter_activity_mutex.h +1 -1
  468. data/src/core/lib/promise/interceptor_list.h +5 -5
  469. data/src/core/lib/promise/latch.h +9 -9
  470. data/src/core/lib/promise/loop.h +2 -2
  471. data/src/core/lib/promise/map.h +2 -2
  472. data/src/core/lib/promise/mpsc.cc +31 -30
  473. data/src/core/lib/promise/mpsc.h +2 -2
  474. data/src/core/lib/promise/observable.h +6 -6
  475. data/src/core/lib/promise/party.cc +43 -30
  476. data/src/core/lib/promise/party.h +27 -23
  477. data/src/core/lib/promise/pipe.h +31 -17
  478. data/src/core/lib/promise/poll.h +6 -5
  479. data/src/core/lib/promise/promise.h +2 -4
  480. data/src/core/lib/promise/sleep.cc +3 -1
  481. data/src/core/lib/promise/sleep.h +1 -1
  482. data/src/core/lib/promise/status_flag.h +8 -8
  483. data/src/core/lib/promise/try_join.h +5 -5
  484. data/src/core/lib/promise/try_seq.h +5 -5
  485. data/src/core/lib/promise/wait_set.h +2 -2
  486. data/src/core/lib/resource_quota/api.cc +1 -1
  487. data/src/core/lib/resource_quota/arena.cc +1 -1
  488. data/src/core/lib/resource_quota/arena.h +15 -2
  489. data/src/core/lib/resource_quota/connection_quota.cc +9 -7
  490. data/src/core/lib/resource_quota/connection_quota.h +1 -1
  491. data/src/core/lib/resource_quota/memory_quota.cc +48 -27
  492. data/src/core/lib/resource_quota/memory_quota.h +56 -20
  493. data/src/core/lib/resource_quota/periodic_update.h +1 -1
  494. data/src/core/lib/resource_quota/resource_quota.cc +8 -0
  495. data/src/core/lib/resource_quota/resource_quota.h +2 -1
  496. data/src/core/lib/resource_quota/stream_quota.cc +22 -0
  497. data/src/core/lib/resource_quota/stream_quota.h +31 -0
  498. data/src/core/lib/resource_quota/telemetry.h +55 -0
  499. data/src/core/lib/resource_quota/thread_quota.cc +2 -2
  500. data/src/core/lib/resource_quota/thread_quota.h +1 -1
  501. data/src/core/lib/resource_tracker/resource_tracker.cc +33 -0
  502. data/src/core/lib/resource_tracker/resource_tracker.h +46 -0
  503. data/src/core/lib/security/authorization/audit_logging.cc +7 -7
  504. data/src/core/lib/security/authorization/audit_logging.h +1 -1
  505. data/src/core/lib/security/authorization/authorization_policy_provider.h +1 -1
  506. data/src/core/lib/security/authorization/evaluate_args.cc +5 -5
  507. data/src/core/lib/security/authorization/evaluate_args.h +1 -1
  508. data/src/core/lib/security/authorization/grpc_authorization_engine.cc +2 -2
  509. data/src/core/lib/security/authorization/grpc_server_authz_filter.cc +3 -3
  510. data/src/core/lib/security/authorization/grpc_server_authz_filter.h +4 -1
  511. data/src/core/lib/security/authorization/matchers.cc +2 -2
  512. data/src/core/lib/security/authorization/stdout_logger.cc +3 -3
  513. data/src/core/lib/slice/percent_encoding.cc +1 -1
  514. data/src/core/lib/slice/slice.cc +1 -1
  515. data/src/core/lib/slice/slice.h +2 -2
  516. data/src/core/lib/slice/slice_buffer.cc +1 -1
  517. data/src/core/lib/slice/slice_internal.h +1 -1
  518. data/src/core/lib/surface/byte_buffer_reader.cc +2 -2
  519. data/src/core/lib/surface/call.cc +58 -28
  520. data/src/core/lib/surface/call.h +13 -6
  521. data/src/core/lib/surface/call_log_batch.cc +2 -2
  522. data/src/core/lib/surface/call_utils.cc +7 -7
  523. data/src/core/lib/surface/call_utils.h +85 -20
  524. data/src/core/lib/surface/channel.cc +6 -5
  525. data/src/core/lib/surface/channel.h +13 -3
  526. data/src/core/lib/surface/channel_create.cc +12 -8
  527. data/src/core/lib/surface/channel_create.h +1 -1
  528. data/src/core/lib/surface/channel_init.cc +84 -27
  529. data/src/core/lib/surface/channel_init.h +30 -13
  530. data/src/core/lib/surface/completion_queue.cc +21 -20
  531. data/src/core/lib/surface/completion_queue_factory.cc +7 -7
  532. data/src/core/lib/surface/connection_context.h +45 -2
  533. data/src/core/lib/surface/filter_stack_call.cc +25 -31
  534. data/src/core/lib/surface/filter_stack_call.h +6 -7
  535. data/src/core/lib/surface/init.cc +4 -4
  536. data/src/core/lib/surface/lame_client.cc +2 -2
  537. data/src/core/lib/surface/lame_client.h +3 -3
  538. data/src/core/lib/surface/legacy_channel.cc +10 -10
  539. data/src/core/lib/surface/legacy_channel.h +1 -1
  540. data/src/core/lib/surface/validate_metadata.cc +2 -2
  541. data/src/core/lib/surface/validate_metadata.h +3 -3
  542. data/src/core/lib/surface/version.cc +2 -2
  543. data/src/core/lib/transport/bdp_estimator.cc +2 -2
  544. data/src/core/lib/transport/bdp_estimator.h +5 -5
  545. data/src/core/lib/transport/connectivity_state.cc +1 -1
  546. data/src/core/lib/transport/connectivity_state.h +2 -2
  547. data/src/core/lib/transport/error_utils.h +1 -1
  548. data/src/core/lib/transport/promise_endpoint.cc +4 -4
  549. data/src/core/lib/transport/promise_endpoint.h +11 -11
  550. data/src/core/lib/transport/timeout_encoding.cc +4 -4
  551. data/src/core/lib/transport/transport.cc +3 -3
  552. data/src/core/lib/transport/transport.h +62 -4
  553. data/src/core/lib/transport/transport_framing_endpoint_extension.h +1 -1
  554. data/src/core/lib/transport/transport_op_string.cc +2 -2
  555. data/src/core/load_balancing/address_filtering.cc +1 -1
  556. data/src/core/load_balancing/address_filtering.h +2 -2
  557. data/src/core/load_balancing/backend_metric_parser.cc +1 -1
  558. data/src/core/load_balancing/backend_metric_parser.h +1 -1
  559. data/src/core/load_balancing/child_policy_handler.cc +8 -8
  560. data/src/core/load_balancing/child_policy_handler.h +2 -2
  561. data/src/core/load_balancing/delegating_helper.h +2 -2
  562. data/src/core/load_balancing/endpoint_list.cc +6 -6
  563. data/src/core/load_balancing/endpoint_list.h +2 -2
  564. data/src/core/load_balancing/grpclb/client_load_reporting_filter.cc +7 -5
  565. data/src/core/load_balancing/grpclb/client_load_reporting_filter.h +5 -1
  566. data/src/core/load_balancing/grpclb/grpclb.cc +37 -48
  567. data/src/core/load_balancing/grpclb/grpclb_client_stats.h +2 -2
  568. data/src/core/load_balancing/grpclb/load_balancer_api.cc +1 -1
  569. data/src/core/load_balancing/grpclb/load_balancer_api.h +1 -1
  570. data/src/core/load_balancing/health_check_client.cc +13 -9
  571. data/src/core/load_balancing/health_check_client_internal.h +5 -5
  572. data/src/core/load_balancing/lb_policy.h +11 -8
  573. data/src/core/load_balancing/lb_policy_factory.h +2 -2
  574. data/src/core/load_balancing/lb_policy_registry.cc +3 -3
  575. data/src/core/load_balancing/lb_policy_registry.h +2 -2
  576. data/src/core/load_balancing/oob_backend_metric.cc +11 -7
  577. data/src/core/load_balancing/oob_backend_metric_internal.h +4 -4
  578. data/src/core/load_balancing/outlier_detection/outlier_detection.cc +9 -17
  579. data/src/core/load_balancing/pick_first/pick_first.cc +62 -32
  580. data/src/core/load_balancing/priority/priority.cc +29 -30
  581. data/src/core/load_balancing/ring_hash/ring_hash.cc +11 -11
  582. data/src/core/load_balancing/rls/rls.cc +23 -23
  583. data/src/core/load_balancing/round_robin/round_robin.cc +16 -16
  584. data/src/core/load_balancing/subchannel_interface.h +2 -2
  585. data/src/core/load_balancing/weighted_round_robin/static_stride_scheduler.cc +3 -3
  586. data/src/core/load_balancing/weighted_round_robin/weighted_round_robin.cc +42 -41
  587. data/src/core/load_balancing/weighted_target/weighted_target.cc +14 -14
  588. data/src/core/load_balancing/xds/cds.cc +81 -37
  589. data/src/core/load_balancing/xds/xds_cluster_impl.cc +24 -41
  590. data/src/core/load_balancing/xds/xds_cluster_manager.cc +6 -6
  591. data/src/core/load_balancing/xds/xds_override_host.cc +14 -14
  592. data/src/core/load_balancing/xds/xds_override_host.h +1 -1
  593. data/src/core/load_balancing/xds/xds_wrr_locality.cc +5 -5
  594. data/src/core/resolver/dns/c_ares/dns_resolver_ares.cc +8 -8
  595. data/src/core/resolver/dns/c_ares/dns_resolver_ares.h +1 -1
  596. data/src/core/resolver/dns/c_ares/grpc_ares_ev_driver.h +1 -1
  597. data/src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc +4 -4
  598. data/src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc +35 -35
  599. data/src/core/resolver/dns/c_ares/grpc_ares_wrapper.cc +16 -16
  600. data/src/core/resolver/dns/c_ares/grpc_ares_wrapper.h +2 -2
  601. data/src/core/resolver/dns/dns_resolver_plugin.cc +8 -5
  602. data/src/core/resolver/dns/event_engine/event_engine_client_channel_resolver.cc +10 -10
  603. data/src/core/resolver/dns/event_engine/event_engine_client_channel_resolver.h +1 -1
  604. data/src/core/resolver/dns/event_engine/service_config_helper.cc +2 -2
  605. data/src/core/resolver/dns/native/dns_resolver.cc +7 -7
  606. data/src/core/resolver/endpoint_addresses.cc +6 -6
  607. data/src/core/resolver/endpoint_addresses.h +4 -1
  608. data/src/core/resolver/fake/fake_resolver.cc +3 -3
  609. data/src/core/resolver/fake/fake_resolver.h +3 -3
  610. data/src/core/resolver/google_c2p/google_c2p_resolver.cc +46 -59
  611. data/src/core/resolver/polling_resolver.cc +8 -8
  612. data/src/core/resolver/polling_resolver.h +1 -1
  613. data/src/core/resolver/resolver.h +2 -2
  614. data/src/core/resolver/resolver_factory.h +2 -2
  615. data/src/core/resolver/resolver_registry.cc +5 -4
  616. data/src/core/resolver/resolver_registry.h +1 -1
  617. data/src/core/resolver/sockaddr/sockaddr_resolver.cc +4 -4
  618. data/src/core/resolver/xds/xds_config.cc +1 -1
  619. data/src/core/resolver/xds/xds_config.h +3 -3
  620. data/src/core/resolver/xds/xds_dependency_manager.cc +7 -7
  621. data/src/core/resolver/xds/xds_dependency_manager.h +3 -3
  622. data/src/core/resolver/xds/xds_resolver.cc +25 -22
  623. data/src/core/resolver/xds/xds_resolver_attributes.h +1 -1
  624. data/src/core/server/add_port.cc +2 -2
  625. data/src/core/server/server.cc +47 -43
  626. data/src/core/server/server.h +8 -7
  627. data/src/core/server/server_call_tracer_filter.cc +1 -1
  628. data/src/core/server/server_call_tracer_filter.h +9 -5
  629. data/src/core/server/server_config_selector.h +2 -2
  630. data/src/core/server/server_config_selector_filter.cc +5 -5
  631. data/src/core/server/xds_channel_stack_modifier.cc +3 -2
  632. data/src/core/server/xds_channel_stack_modifier.h +1 -1
  633. data/src/core/server/xds_server_config_fetcher.cc +19 -18
  634. data/src/core/service_config/service_config.h +1 -1
  635. data/src/core/service_config/service_config_channel_arg_filter.h +4 -1
  636. data/src/core/service_config/service_config_impl.cc +3 -3
  637. data/src/core/service_config/service_config_impl.h +4 -4
  638. data/src/core/service_config/service_config_parser.h +1 -1
  639. data/src/core/telemetry/call_tracer.cc +39 -49
  640. data/src/core/telemetry/call_tracer.h +201 -24
  641. data/src/core/telemetry/default_tcp_tracer.h +3 -3
  642. data/src/core/telemetry/histogram.h +205 -0
  643. data/src/core/telemetry/instrument.cc +999 -0
  644. data/src/core/telemetry/instrument.h +1105 -0
  645. data/src/core/telemetry/metrics.cc +15 -5
  646. data/src/core/telemetry/metrics.h +36 -5
  647. data/src/core/telemetry/stats.h +2 -2
  648. data/src/core/telemetry/stats_data.cc +1 -20
  649. data/src/core/telemetry/stats_data.h +2 -21
  650. data/src/core/transport/auth_context.cc +3 -3
  651. data/src/core/transport/auth_context.h +2 -1
  652. data/src/core/transport/auth_context_comparator_registry.h +1 -1
  653. data/src/core/tsi/alts/crypt/aes_gcm.cc +1 -1
  654. data/src/core/tsi/alts/frame_protector/alts_frame_protector.cc +2 -2
  655. data/src/core/tsi/alts/frame_protector/frame_handler.cc +1 -1
  656. data/src/core/tsi/alts/handshaker/alts_handshaker_client.cc +81 -48
  657. data/src/core/tsi/alts/handshaker/alts_handshaker_client.h +1 -0
  658. data/src/core/tsi/alts/handshaker/alts_shared_resource.cc +3 -3
  659. data/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc +46 -36
  660. data/src/core/tsi/alts/handshaker/alts_tsi_utils.cc +4 -4
  661. data/src/core/tsi/alts/handshaker/transport_security_common_api.cc +1 -1
  662. data/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc +4 -4
  663. data/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc +11 -3
  664. data/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h +10 -0
  665. data/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc +16 -8
  666. data/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h +3 -0
  667. data/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc +18 -5
  668. data/src/core/tsi/fake_transport_security.cc +6 -5
  669. data/src/core/tsi/local_transport_security.cc +1 -1
  670. data/src/core/tsi/ssl/key_logging/ssl_key_logging.cc +5 -5
  671. data/src/core/tsi/ssl/key_logging/ssl_key_logging.h +1 -1
  672. data/src/core/tsi/ssl/session_cache/ssl_session_cache.cc +10 -10
  673. data/src/core/tsi/ssl/session_cache/ssl_session_openssl.cc +4 -4
  674. data/src/core/tsi/ssl_transport_security.cc +30 -30
  675. data/src/core/tsi/ssl_transport_security.h +1 -1
  676. data/src/core/tsi/ssl_transport_security_utils.cc +10 -10
  677. data/src/core/tsi/ssl_transport_security_utils.h +2 -2
  678. data/src/core/tsi/transport_security_grpc.cc +8 -0
  679. data/src/core/tsi/transport_security_grpc.h +15 -0
  680. data/src/core/util/alloc.cc +1 -1
  681. data/src/core/util/backoff.h +1 -1
  682. data/src/core/util/chunked_vector.h +4 -4
  683. data/src/core/util/crash.h +1 -1
  684. data/src/core/util/dual_ref_counted.h +2 -2
  685. data/src/core/util/event_log.cc +2 -2
  686. data/src/core/util/event_log.h +3 -3
  687. data/src/core/util/gcp_metadata_query.cc +7 -7
  688. data/src/core/util/gcp_metadata_query.h +2 -2
  689. data/src/core/util/glob.cc +2 -0
  690. data/src/core/util/grpc_check.cc +24 -0
  691. data/src/core/util/grpc_check.h +103 -0
  692. data/src/core/util/grpc_if_nametoindex_posix.cc +1 -1
  693. data/src/core/util/grpc_if_nametoindex_unsupported.cc +1 -1
  694. data/src/core/util/http_client/format_request.cc +1 -1
  695. data/src/core/util/http_client/httpcli.cc +6 -6
  696. data/src/core/util/http_client/httpcli.h +4 -4
  697. data/src/core/util/http_client/httpcli_security_connector.cc +4 -4
  698. data/src/core/util/http_client/parser.cc +4 -4
  699. data/src/core/util/json/json_channel_args.h +1 -1
  700. data/src/core/util/json/json_object_loader.h +6 -6
  701. data/src/core/util/json/json_reader.cc +2 -2
  702. data/src/core/util/json/json_reader.h +1 -1
  703. data/src/core/util/json/json_util.h +3 -3
  704. data/src/core/util/json/json_writer.cc +1 -1
  705. data/src/core/util/latent_see.cc +45 -24
  706. data/src/core/util/latent_see.h +199 -28
  707. data/src/core/util/linux/cpu.cc +1 -1
  708. data/src/core/util/load_file.cc +1 -1
  709. data/src/core/util/load_file.h +1 -1
  710. data/src/core/util/log.cc +3 -3
  711. data/src/core/util/lru_cache.h +4 -4
  712. data/src/core/util/matchers.h +1 -1
  713. data/src/core/util/memory_usage.h +17 -1
  714. data/src/core/util/mpscq.h +1 -1
  715. data/src/core/util/notification.h +1 -1
  716. data/src/core/util/posix/cpu.cc +1 -1
  717. data/src/core/util/posix/directory_reader.cc +3 -2
  718. data/src/core/util/posix/stat.cc +2 -2
  719. data/src/core/util/posix/sync.cc +24 -24
  720. data/src/core/util/posix/thd.cc +2 -2
  721. data/src/core/util/posix/tmpfile.cc +2 -2
  722. data/src/core/util/postmortem_emit.cc +52 -0
  723. data/src/core/util/postmortem_emit.h +30 -0
  724. data/src/core/util/ref_counted.h +2 -2
  725. data/src/core/util/ref_counted_ptr.h +6 -1
  726. data/src/core/util/ref_counted_string.h +1 -1
  727. data/src/core/util/single_set_ptr.h +3 -1
  728. data/src/core/util/status_helper.cc +8 -8
  729. data/src/core/util/status_helper.h +1 -1
  730. data/src/core/util/string.cc +2 -2
  731. data/src/core/util/sync_abseil.cc +1 -1
  732. data/src/core/util/table.h +1 -1
  733. data/src/core/util/time.cc +1 -1
  734. data/src/core/util/time_precise.cc +1 -1
  735. data/src/core/util/trie_lookup.h +170 -0
  736. data/src/core/util/unique_ptr_with_bitset.h +5 -5
  737. data/src/core/util/unique_type_name.h +1 -1
  738. data/src/core/util/upb_utils.h +6 -1
  739. data/src/core/util/validation_errors.cc +2 -2
  740. data/src/core/util/validation_errors.h +2 -3
  741. data/src/core/util/wait_for_single_owner.h +2 -2
  742. data/src/core/util/windows/directory_reader.cc +1 -1
  743. data/src/core/util/windows/stat.cc +2 -2
  744. data/src/core/util/windows/thd.cc +2 -2
  745. data/src/core/util/windows/time.cc +1 -1
  746. data/src/core/util/work_serializer.cc +3 -3
  747. data/src/core/util/work_serializer.h +2 -2
  748. data/src/core/xds/grpc/certificate_provider_store.cc +2 -2
  749. data/src/core/xds/grpc/certificate_provider_store.h +2 -2
  750. data/src/core/xds/grpc/file_watcher_certificate_provider_factory.cc +3 -3
  751. data/src/core/xds/grpc/file_watcher_certificate_provider_factory.h +1 -1
  752. data/src/core/xds/grpc/xds_audit_logger_registry.cc +3 -3
  753. data/src/core/xds/grpc/xds_audit_logger_registry.h +1 -1
  754. data/src/core/xds/grpc/xds_bootstrap_grpc.cc +7 -7
  755. data/src/core/xds/grpc/xds_bootstrap_grpc.h +8 -3
  756. data/src/core/xds/grpc/xds_certificate_provider.cc +4 -4
  757. data/src/core/xds/grpc/xds_certificate_provider.h +2 -2
  758. data/src/core/xds/grpc/xds_client_grpc.cc +39 -20
  759. data/src/core/xds/grpc/xds_client_grpc.h +6 -3
  760. data/src/core/xds/grpc/xds_cluster.cc +2 -2
  761. data/src/core/xds/grpc/xds_cluster.h +1 -1
  762. data/src/core/xds/grpc/xds_cluster_parser.cc +7 -7
  763. data/src/core/xds/grpc/xds_cluster_parser.h +1 -1
  764. data/src/core/xds/grpc/xds_cluster_specifier_plugin.cc +4 -4
  765. data/src/core/xds/grpc/xds_cluster_specifier_plugin.h +1 -1
  766. data/src/core/xds/grpc/xds_common_types.cc +1 -1
  767. data/src/core/xds/grpc/xds_common_types.h +1 -1
  768. data/src/core/xds/grpc/xds_common_types_parser.cc +5 -5
  769. data/src/core/xds/grpc/xds_endpoint.h +2 -2
  770. data/src/core/xds/grpc/xds_endpoint_parser.cc +7 -7
  771. data/src/core/xds/grpc/xds_endpoint_parser.h +1 -1
  772. data/src/core/xds/grpc/xds_health_status.cc +1 -1
  773. data/src/core/xds/grpc/xds_health_status.h +1 -1
  774. data/src/core/xds/grpc/xds_http_fault_filter.cc +4 -4
  775. data/src/core/xds/grpc/xds_http_fault_filter.h +2 -2
  776. data/src/core/xds/grpc/xds_http_filter.h +3 -3
  777. data/src/core/xds/grpc/xds_http_filter_registry.cc +4 -3
  778. data/src/core/xds/grpc/xds_http_filter_registry.h +2 -2
  779. data/src/core/xds/grpc/xds_http_gcp_authn_filter.cc +3 -3
  780. data/src/core/xds/grpc/xds_http_gcp_authn_filter.h +2 -2
  781. data/src/core/xds/grpc/xds_http_rbac_filter.cc +4 -4
  782. data/src/core/xds/grpc/xds_http_rbac_filter.h +2 -2
  783. data/src/core/xds/grpc/xds_http_stateful_session_filter.cc +3 -3
  784. data/src/core/xds/grpc/xds_http_stateful_session_filter.h +2 -2
  785. data/src/core/xds/grpc/xds_lb_policy_registry.cc +1 -1
  786. data/src/core/xds/grpc/xds_lb_policy_registry.h +1 -1
  787. data/src/core/xds/grpc/xds_listener.cc +2 -2
  788. data/src/core/xds/grpc/xds_listener_parser.cc +9 -9
  789. data/src/core/xds/grpc/xds_listener_parser.h +1 -1
  790. data/src/core/xds/grpc/xds_matcher.cc +277 -0
  791. data/src/core/xds/grpc/xds_matcher.h +432 -0
  792. data/src/core/xds/grpc/xds_matcher_action.cc +47 -0
  793. data/src/core/xds/grpc/xds_matcher_action.h +48 -0
  794. data/src/core/xds/grpc/xds_matcher_context.cc +29 -0
  795. data/src/core/xds/grpc/xds_matcher_context.h +46 -0
  796. data/src/core/xds/grpc/xds_matcher_input.cc +79 -0
  797. data/src/core/xds/grpc/xds_matcher_input.h +105 -0
  798. data/src/core/xds/grpc/xds_matcher_parse.cc +356 -0
  799. data/src/core/xds/grpc/xds_matcher_parse.h +39 -0
  800. data/src/core/xds/grpc/xds_metadata.cc +4 -3
  801. data/src/core/xds/grpc/xds_metadata.h +3 -3
  802. data/src/core/xds/grpc/xds_metadata_parser.cc +2 -2
  803. data/src/core/xds/grpc/xds_route_config.cc +3 -3
  804. data/src/core/xds/grpc/xds_route_config_parser.cc +14 -14
  805. data/src/core/xds/grpc/xds_route_config_parser.h +1 -1
  806. data/src/core/xds/grpc/xds_routing.cc +6 -6
  807. data/src/core/xds/grpc/xds_routing.h +2 -2
  808. data/src/core/xds/grpc/xds_server_grpc.cc +2 -2
  809. data/src/core/xds/grpc/xds_transport_grpc.cc +11 -11
  810. data/src/core/xds/grpc/xds_transport_grpc.h +2 -2
  811. data/src/core/xds/xds_client/lrs_client.cc +9 -9
  812. data/src/core/xds/xds_client/lrs_client.h +4 -4
  813. data/src/core/xds/xds_client/xds_api.h +1 -1
  814. data/src/core/xds/xds_client/xds_backend_metric_propagation.cc +1 -1
  815. data/src/core/xds/xds_client/xds_backend_metric_propagation.h +1 -1
  816. data/src/core/xds/xds_client/xds_client.cc +17 -17
  817. data/src/core/xds/xds_client/xds_client.h +5 -5
  818. data/src/core/xds/xds_client/xds_locality.h +2 -2
  819. data/src/core/xds/xds_client/xds_resource_type.h +2 -2
  820. data/src/core/xds/xds_client/xds_resource_type_impl.h +1 -1
  821. data/src/core/xds/xds_client/xds_transport.h +2 -2
  822. data/src/ruby/ext/grpc/extconf.rb +14 -12
  823. data/src/ruby/ext/grpc/rb_call.c +0 -1
  824. data/src/ruby/ext/grpc/rb_channel_args.c +0 -1
  825. data/src/ruby/ext/grpc/rb_channel_credentials.c +0 -1
  826. data/src/ruby/ext/grpc/rb_compression_options.c +0 -1
  827. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +2 -2
  828. data/src/ruby/ext/grpc/rb_server_credentials.c +0 -1
  829. data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +0 -1
  830. data/src/ruby/ext/grpc/rb_xds_server_credentials.c +0 -1
  831. data/src/ruby/lib/grpc/version.rb +1 -1
  832. data/third_party/abseil-cpp/absl/container/internal/node_slot_policy.h +95 -0
  833. data/third_party/abseil-cpp/absl/container/node_hash_map.h +687 -0
  834. metadata +51 -6
@@ -19,49 +19,95 @@
19
19
  #include "src/core/ext/transport/chttp2/transport/http2_client_transport.h"
20
20
 
21
21
  #include <grpc/event_engine/event_engine.h>
22
+ #include <grpc/grpc.h>
22
23
  #include <grpc/support/port_platform.h>
24
+ #include <limits.h>
23
25
 
26
+ #include <algorithm>
27
+ #include <cstddef>
24
28
  #include <cstdint>
29
+ #include <iterator>
25
30
  #include <memory>
26
31
  #include <optional>
32
+ #include <string>
27
33
  #include <utility>
34
+ #include <vector>
28
35
 
29
- #include "absl/log/check.h"
30
- #include "absl/log/log.h"
31
- #include "absl/status/status.h"
32
36
  #include "src/core/call/call_spine.h"
33
37
  #include "src/core/call/message.h"
38
+ #include "src/core/call/metadata.h"
34
39
  #include "src/core/call/metadata_batch.h"
40
+ #include "src/core/call/metadata_info.h"
41
+ #include "src/core/channelz/channelz.h"
42
+ #include "src/core/ext/transport/chttp2/transport/flow_control.h"
43
+ #include "src/core/ext/transport/chttp2/transport/flow_control_manager.h"
35
44
  #include "src/core/ext/transport/chttp2/transport/frame.h"
45
+ #include "src/core/ext/transport/chttp2/transport/goaway.h"
36
46
  #include "src/core/ext/transport/chttp2/transport/header_assembler.h"
37
47
  #include "src/core/ext/transport/chttp2/transport/http2_settings.h"
38
- #include "src/core/ext/transport/chttp2/transport/http2_settings_manager.h"
48
+ #include "src/core/ext/transport/chttp2/transport/http2_settings_promises.h"
39
49
  #include "src/core/ext/transport/chttp2/transport/http2_status.h"
40
- #include "src/core/ext/transport/chttp2/transport/internal_channel_arg_names.h"
50
+ #include "src/core/ext/transport/chttp2/transport/http2_transport.h"
51
+ #include "src/core/ext/transport/chttp2/transport/http2_ztrace_collector.h"
52
+ #include "src/core/ext/transport/chttp2/transport/incoming_metadata_tracker.h"
53
+ #include "src/core/ext/transport/chttp2/transport/keepalive.h"
41
54
  #include "src/core/ext/transport/chttp2/transport/message_assembler.h"
55
+ #include "src/core/ext/transport/chttp2/transport/ping_promise.h"
56
+ #include "src/core/ext/transport/chttp2/transport/stream.h"
57
+ #include "src/core/ext/transport/chttp2/transport/stream_data_queue.h"
42
58
  #include "src/core/ext/transport/chttp2/transport/transport_common.h"
43
59
  #include "src/core/lib/channel/channel_args.h"
44
- #include "src/core/lib/debug/trace.h"
60
+ #include "src/core/lib/iomgr/exec_ctx.h"
61
+ #include "src/core/lib/promise/activity.h"
62
+ #include "src/core/lib/promise/context.h"
45
63
  #include "src/core/lib/promise/for_each.h"
64
+ #include "src/core/lib/promise/if.h"
46
65
  #include "src/core/lib/promise/loop.h"
47
66
  #include "src/core/lib/promise/map.h"
48
67
  #include "src/core/lib/promise/match_promise.h"
49
68
  #include "src/core/lib/promise/party.h"
50
69
  #include "src/core/lib/promise/poll.h"
51
70
  #include "src/core/lib/promise/promise.h"
71
+ #include "src/core/lib/promise/race.h"
72
+ #include "src/core/lib/promise/sleep.h"
52
73
  #include "src/core/lib/promise/try_seq.h"
53
74
  #include "src/core/lib/resource_quota/arena.h"
75
+ #include "src/core/lib/resource_quota/resource_quota.h"
54
76
  #include "src/core/lib/slice/slice.h"
55
77
  #include "src/core/lib/slice/slice_buffer.h"
78
+ #include "src/core/lib/transport/connectivity_state.h"
56
79
  #include "src/core/lib/transport/promise_endpoint.h"
57
80
  #include "src/core/lib/transport/transport.h"
81
+ #include "src/core/util/debug_location.h"
82
+ #include "src/core/util/grpc_check.h"
83
+ #include "src/core/util/latent_see.h"
84
+ #include "src/core/util/orphanable.h"
58
85
  #include "src/core/util/ref_counted_ptr.h"
59
86
  #include "src/core/util/sync.h"
87
+ #include "src/core/util/time.h"
88
+ #include "absl/base/thread_annotations.h"
89
+ #include "absl/container/flat_hash_map.h"
90
+ #include "absl/log/log.h"
91
+ #include "absl/status/status.h"
92
+ #include "absl/strings/cord.h"
93
+ #include "absl/strings/str_cat.h"
94
+ #include "absl/strings/string_view.h"
95
+ #include "absl/types/span.h"
60
96
 
61
97
  namespace grpc_core {
62
98
  namespace http2 {
63
99
 
100
+ // TODO(akshitpatel)(tjagtap) [PH2][P2] : When settings frame increases incoming
101
+ // window size, our transport must make the streams that were blocked on stream
102
+ // flow control as writeable.
103
+
104
+ // As a gRPC server never initiates a stream, the last incoming stream id on
105
+ // the client side will always be 0.
106
+ constexpr uint32_t kLastIncomingStreamIdClient = 0;
107
+
64
108
  using grpc_event_engine::experimental::EventEngine;
109
+ using StreamWritabilityUpdate =
110
+ StreamDataQueue<ClientMetadataHandle>::StreamWritabilityUpdate;
65
111
 
66
112
  // Experimental : This is just the initial skeleton of class
67
113
  // and it is functions. The code will be written iteratively.
@@ -70,6 +116,32 @@ using grpc_event_engine::experimental::EventEngine;
70
116
  // TODO(tjagtap) : [PH2][P3] : Delete this comment when http2
71
117
  // rollout begins
72
118
 
119
+ template <typename Factory>
120
+ void Http2ClientTransport::SpawnInfallible(RefCountedPtr<Party> party,
121
+ absl::string_view name,
122
+ Factory&& factory) {
123
+ party->Spawn(name, std::forward<Factory>(factory), [](Empty) {});
124
+ }
125
+
126
+ template <typename Factory>
127
+ void Http2ClientTransport::SpawnInfallibleTransportParty(absl::string_view name,
128
+ Factory&& factory) {
129
+ SpawnInfallible(general_party_, name, std::forward<Factory>(factory));
130
+ }
131
+
132
+ template <typename Factory>
133
+ void Http2ClientTransport::SpawnGuardedTransportParty(absl::string_view name,
134
+ Factory&& factory) {
135
+ general_party_->Spawn(
136
+ name, std::forward<Factory>(factory),
137
+ [self = RefAsSubclass<Http2ClientTransport>()](absl::Status status) {
138
+ if (!status.ok()) {
139
+ GRPC_UNUSED absl::Status error = self->HandleError(
140
+ /*stream_id=*/std::nullopt, ToHttpOkOrConnError(status));
141
+ }
142
+ });
143
+ }
144
+
73
145
  void Http2ClientTransport::PerformOp(grpc_transport_op* op) {
74
146
  // Notes : Refer : src/core/ext/transport/chaotic_good/client_transport.cc
75
147
  // Functions : StartConnectivityWatch, StopConnectivityWatch, PerformOp
@@ -84,8 +156,9 @@ void Http2ClientTransport::PerformOp(grpc_transport_op* op) {
84
156
  StopConnectivityWatch(op->stop_connectivity_watch);
85
157
  did_stuff = true;
86
158
  }
87
- CHECK(!op->set_accept_stream) << "Set_accept_stream not supported on clients";
88
- DCHECK(did_stuff) << "Unimplemented transport perform op ";
159
+ GRPC_CHECK(!op->set_accept_stream)
160
+ << "Set_accept_stream not supported on clients";
161
+ GRPC_DCHECK(did_stuff) << "Unimplemented transport perform op ";
89
162
 
90
163
  ExecCtx::Run(DEBUG_LOCATION, op->on_consumed, absl::OkStatus());
91
164
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport PerformOp End";
@@ -110,90 +183,145 @@ void Http2ClientTransport::StopConnectivityWatch(
110
183
  state_tracker_.RemoveWatcher(watcher);
111
184
  }
112
185
 
186
+ void Http2ClientTransport::ReportDisconnection(
187
+ const absl::Status& status, StateWatcher::DisconnectInfo disconnect_info,
188
+ const char* reason) {
189
+ MutexLock lock(&transport_mutex_);
190
+ ReportDisconnectionLocked(status, disconnect_info, reason);
191
+ }
192
+
193
+ void Http2ClientTransport::ReportDisconnectionLocked(
194
+ const absl::Status& status, StateWatcher::DisconnectInfo disconnect_info,
195
+ const char* reason) {
196
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ReportDisconnection: status="
197
+ << status.ToString() << "; reason=" << reason;
198
+ state_tracker_.SetState(GRPC_CHANNEL_TRANSIENT_FAILURE, status, reason);
199
+ NotifyStateWatcherOnDisconnectLocked(status, disconnect_info);
200
+ }
201
+
202
+ void Http2ClientTransport::StartWatch(RefCountedPtr<StateWatcher> watcher) {
203
+ MutexLock lock(&transport_mutex_);
204
+ GRPC_CHECK(watcher_ == nullptr);
205
+ watcher_ = std::move(watcher);
206
+ if (is_transport_closed_) {
207
+ // TODO(tjagtap) : [PH2][P2] : Provide better status message and
208
+ // disconnect info here.
209
+ NotifyStateWatcherOnDisconnectLocked(
210
+ absl::UnknownError("transport closed before watcher started"), {});
211
+ } else {
212
+ // TODO(tjagtap) : [PH2][P2] : Notify the state watcher of the current
213
+ // value of the peer's MAX_CONCURRENT_STREAMS setting.
214
+ }
215
+ }
216
+
217
+ void Http2ClientTransport::StopWatch(RefCountedPtr<StateWatcher> watcher) {
218
+ MutexLock lock(&transport_mutex_);
219
+ if (watcher_ == watcher) watcher_.reset();
220
+ }
221
+
222
+ void Http2ClientTransport::NotifyStateWatcherOnDisconnectLocked(
223
+ absl::Status status, StateWatcher::DisconnectInfo disconnect_info) {
224
+ if (watcher_ == nullptr) return;
225
+ event_engine_->Run([watcher = std::move(watcher_), status = std::move(status),
226
+ disconnect_info]() mutable {
227
+ ExecCtx exec_ctx;
228
+ watcher->OnDisconnect(std::move(status), disconnect_info);
229
+ watcher.reset(); // Before ExecCtx goes out of scope.
230
+ });
231
+ }
232
+
113
233
  void Http2ClientTransport::Orphan() {
114
234
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Orphan Begin";
115
235
  // Accessing general_party here is not advisable. It may so happen that
116
236
  // the party is already freed/may free up any time. The only guarantee here
117
237
  // is that the transport is still valid.
118
- MaybeSpawnCloseTransport(Http2Status::AbslConnectionError(
119
- absl::StatusCode::kUnavailable, "Orphaned"));
238
+ SourceDestructing();
239
+ MaybeSpawnCloseTransport(
240
+ ToHttpOkOrConnError(absl::UnavailableError("Orphaned")));
120
241
  Unref();
121
242
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Orphan End";
122
243
  }
123
244
 
124
- void Http2ClientTransport::AbortWithError() {
125
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport AbortWithError Begin";
126
- // TODO(tjagtap) : [PH2][P2] : Implement this function.
127
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport AbortWithError End";
128
- }
129
-
130
245
  ///////////////////////////////////////////////////////////////////////////////
131
246
  // Processing each type of frame
132
247
 
133
248
  Http2Status Http2ClientTransport::ProcessHttp2DataFrame(Http2DataFrame frame) {
134
249
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-data
135
- GRPC_HTTP2_CLIENT_DLOG << "Http2Transport ProcessHttp2DataFrame { stream_id="
136
- << frame.stream_id
137
- << ", end_stream=" << frame.end_stream
138
- << ", payload=" << frame.payload.JoinIntoString()
139
- << "}";
250
+ GRPC_HTTP2_CLIENT_DLOG
251
+ << "Http2ClientTransport ProcessHttp2DataFrame { stream_id="
252
+ << frame.stream_id << ", end_stream=" << frame.end_stream
253
+ << ", payload=" << MaybeTruncatePayload(frame.payload)
254
+ << ", payload length=" << frame.payload.Length() << "}";
140
255
 
141
256
  // TODO(akshitpatel) : [PH2][P3] : Investigate if we should do this even if
142
257
  // the function returns a non-ok status?
143
- ping_manager_.ReceivedDataFrame();
258
+ ping_manager_->ReceivedDataFrame();
144
259
 
145
260
  // Lookup stream
146
- GRPC_HTTP2_CLIENT_DLOG << "Http2Transport ProcessHttp2DataFrame LookupStream";
261
+ GRPC_HTTP2_CLIENT_DLOG
262
+ << "Http2ClientTransport ProcessHttp2DataFrame LookupStream";
147
263
  RefCountedPtr<Stream> stream = LookupStream(frame.stream_id);
264
+
265
+ ValueOrHttp2Status<chttp2::FlowControlAction> flow_control_action =
266
+ ProcessIncomingDataFrameFlowControl(current_frame_header_, flow_control_,
267
+ stream);
268
+ if (!flow_control_action.IsOk()) {
269
+ return ValueOrHttp2Status<chttp2::FlowControlAction>::TakeStatus(
270
+ std::move(flow_control_action));
271
+ }
272
+ ActOnFlowControlAction(flow_control_action.value(), stream);
273
+
148
274
  if (stream == nullptr) {
149
275
  // TODO(tjagtap) : [PH2][P2] : Implement the correct behaviour later.
150
276
  // RFC9113 : If a DATA frame is received whose stream is not in the "open"
151
277
  // or "half-closed (local)" state, the recipient MUST respond with a stream
152
278
  // error (Section 5.4.2) of type STREAM_CLOSED.
153
279
  GRPC_HTTP2_CLIENT_DLOG
154
- << "Http2Transport ProcessHttp2DataFrame { stream_id="
280
+ << "Http2ClientTransport ProcessHttp2DataFrame { stream_id="
155
281
  << frame.stream_id << "} Lookup Failed";
156
282
  return Http2Status::Ok();
157
283
  }
158
284
 
159
- if (stream->GetStreamState() == HttpStreamState::kHalfClosedRemote) {
160
- return Http2Status::Http2StreamError(
161
- Http2ErrorCode::kStreamClosed,
162
- std::string(RFC9113::kHalfClosedRemoteState));
285
+ // TODO(akshitpatel) : [PH2][P3] : We should add a check to reset stream if
286
+ // the stream state is kIdle as well.
287
+
288
+ Http2Status stream_status = stream->CanStreamReceiveDataFrames();
289
+ if (!stream_status.IsOk()) {
290
+ return stream_status;
163
291
  }
164
292
 
165
293
  // Add frame to assembler
166
294
  GRPC_HTTP2_CLIENT_DLOG
167
- << "Http2Transport ProcessHttp2DataFrame AppendNewDataFrame";
295
+ << "Http2ClientTransport ProcessHttp2DataFrame AppendNewDataFrame";
168
296
  GrpcMessageAssembler& assembler = stream->assembler;
169
297
  Http2Status status =
170
298
  assembler.AppendNewDataFrame(frame.payload, frame.end_stream);
171
299
  if (!status.IsOk()) {
172
- GRPC_HTTP2_CLIENT_DLOG
173
- << "Http2Transport ProcessHttp2DataFrame AppendNewDataFrame Failed";
300
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessHttp2DataFrame "
301
+ "AppendNewDataFrame Failed";
174
302
  return status;
175
303
  }
176
304
 
177
305
  // Pass the messages up the stack if it is ready.
178
306
  while (true) {
179
307
  GRPC_HTTP2_CLIENT_DLOG
180
- << "Http2Transport ProcessHttp2DataFrame ExtractMessage";
308
+ << "Http2ClientTransport ProcessHttp2DataFrame ExtractMessage";
181
309
  ValueOrHttp2Status<MessageHandle> result = assembler.ExtractMessage();
182
310
  if (!result.IsOk()) {
183
311
  GRPC_HTTP2_CLIENT_DLOG
184
- << "Http2Transport ProcessHttp2DataFrame ExtractMessage Failed";
312
+ << "Http2ClientTransport ProcessHttp2DataFrame ExtractMessage Failed";
185
313
  return ValueOrHttp2Status<MessageHandle>::TakeStatus(std::move(result));
186
314
  }
187
315
  MessageHandle message = TakeValue(std::move(result));
188
316
  if (message != nullptr) {
189
317
  GRPC_HTTP2_CLIENT_DLOG
190
- << "Http2Transport ProcessHttp2DataFrame SpawnPushMessage "
318
+ << "Http2ClientTransport ProcessHttp2DataFrame SpawnPushMessage "
191
319
  << message->DebugString();
192
320
  stream->call.SpawnPushMessage(std::move(message));
193
321
  continue;
194
322
  }
195
323
  GRPC_HTTP2_CLIENT_DLOG
196
- << "Http2Transport ProcessHttp2DataFrame While Break";
324
+ << "Http2ClientTransport ProcessHttp2DataFrame While Break";
197
325
  break;
198
326
  }
199
327
 
@@ -213,14 +341,16 @@ Http2Status Http2ClientTransport::ProcessHttp2HeaderFrame(
213
341
  Http2HeaderFrame frame) {
214
342
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-headers
215
343
  GRPC_HTTP2_CLIENT_DLOG
216
- << "Http2Transport ProcessHttp2HeaderFrame Promise { stream_id="
344
+ << "Http2ClientTransport ProcessHttp2HeaderFrame Promise { stream_id="
217
345
  << frame.stream_id << ", end_headers=" << frame.end_headers
218
346
  << ", end_stream=" << frame.end_stream
219
- << ", payload=" << frame.payload.JoinIntoString() << " }";
220
- ping_manager_.ReceivedDataFrame();
347
+ << ", payload=" << MaybeTruncatePayload(frame.payload) << " }";
348
+ // State update MUST happen before processing the frame.
349
+ incoming_headers_.OnHeaderReceived(frame);
350
+
351
+ ping_manager_->ReceivedDataFrame();
221
352
 
222
- RefCountedPtr<Http2ClientTransport::Stream> stream =
223
- LookupStream(frame.stream_id);
353
+ RefCountedPtr<Stream> stream = LookupStream(frame.stream_id);
224
354
  if (stream == nullptr) {
225
355
  // TODO(tjagtap) : [PH2][P3] : Implement this.
226
356
  // RFC9113 : The identifier of a newly established stream MUST be
@@ -230,76 +360,82 @@ Http2Status Http2ClientTransport::ProcessHttp2HeaderFrame(
230
360
  // receives an unexpected stream identifier MUST respond with a connection
231
361
  // error (Section 5.4.1) of type PROTOCOL_ERROR.
232
362
  GRPC_HTTP2_CLIENT_DLOG
233
- << "Http2Transport ProcessHttp2HeaderFrame Promise { stream_id="
363
+ << "Http2ClientTransport ProcessHttp2HeaderFrame Promise { stream_id="
234
364
  << frame.stream_id << "} Lookup Failed";
235
- return Http2Status::Ok();
365
+ return ParseAndDiscardHeaders(std::move(frame.payload), frame.end_headers,
366
+ /*stream=*/nullptr, Http2Status::Ok());
236
367
  }
237
- if (stream->GetStreamState() == HttpStreamState::kHalfClosedRemote) {
238
- return Http2Status::Http2StreamError(
239
- Http2ErrorCode::kStreamClosed,
240
- std::string(RFC9113::kHalfClosedRemoteState));
368
+
369
+ if (stream->IsStreamHalfClosedRemote()) {
370
+ return ParseAndDiscardHeaders(
371
+ std::move(frame.payload), frame.end_headers, stream,
372
+ Http2Status::Http2StreamError(
373
+ Http2ErrorCode::kStreamClosed,
374
+ std::string(RFC9113::kHalfClosedRemoteState)));
241
375
  }
242
376
 
243
- incoming_header_in_progress_ = !frame.end_headers;
244
- incoming_header_stream_id_ = frame.stream_id;
245
- incoming_header_end_stream_ = frame.end_stream;
246
- if ((incoming_header_end_stream_ && stream->did_push_trailing_metadata) ||
247
- (!incoming_header_end_stream_ && stream->did_push_initial_metadata)) {
248
- return Http2Status::Http2StreamError(
249
- Http2ErrorCode::kInternalError,
250
- "gRPC Error : A gRPC server can send upto 1 initial metadata followed "
251
- "by upto 1 trailing metadata");
377
+ if (incoming_headers_.ClientReceivedDuplicateMetadata(
378
+ stream->did_receive_initial_metadata,
379
+ stream->did_receive_trailing_metadata)) {
380
+ return ParseAndDiscardHeaders(
381
+ std::move(frame.payload), frame.end_headers, stream,
382
+ Http2Status::Http2StreamError(
383
+ Http2ErrorCode::kInternalError,
384
+ std::string(GrpcErrors::kTooManyMetadata)));
252
385
  }
253
386
 
254
- HeaderAssembler& assembler = stream->header_assembler;
255
- Http2Status append_result = assembler.AppendHeaderFrame(std::move(frame));
256
- if (append_result.IsOk()) {
257
- return ProcessMetadata(stream->stream_id, assembler, stream->call,
258
- stream->did_push_initial_metadata,
259
- stream->did_push_trailing_metadata);
387
+ Http2Status append_result = stream->header_assembler.AppendHeaderFrame(frame);
388
+ if (!append_result.IsOk()) {
389
+ // Frame payload is not consumed if AppendHeaderFrame returns a non-OK
390
+ // status. We need to process it to keep our in consistent state.
391
+ return ParseAndDiscardHeaders(std::move(frame.payload), frame.end_headers,
392
+ stream, std::move(append_result));
393
+ }
394
+
395
+ Http2Status status = ProcessMetadata(stream);
396
+ if (!status.IsOk()) {
397
+ // Frame payload has been moved to the HeaderAssembler. So calling
398
+ // ParseAndDiscardHeaders with an empty buffer.
399
+ return ParseAndDiscardHeaders(SliceBuffer(), frame.end_headers, stream,
400
+ std::move(status));
260
401
  }
261
- return append_result;
402
+
403
+ // Frame payload has either been processed or moved to the HeaderAssembler.
404
+ return Http2Status::Ok();
262
405
  }
263
406
 
264
407
  Http2Status Http2ClientTransport::ProcessMetadata(
265
- uint32_t stream_id, HeaderAssembler& assembler, CallHandler& call,
266
- bool& did_push_initial_metadata, bool& did_push_trailing_metadata) {
267
- GRPC_HTTP2_CLIENT_DLOG << "Http2Transport ProcessMetadata";
408
+ RefCountedPtr<Stream> stream) {
409
+ HeaderAssembler& assembler = stream->header_assembler;
410
+ CallHandler call = stream->call;
411
+
412
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessMetadata";
268
413
  if (assembler.IsReady()) {
269
- ValueOrHttp2Status<Arena::PoolPtr<grpc_metadata_batch>> read_result =
270
- assembler.ReadMetadata(parser_, !incoming_header_end_stream_,
414
+ ValueOrHttp2Status<ServerMetadataHandle> read_result =
415
+ assembler.ReadMetadata(parser_, !incoming_headers_.HeaderHasEndStream(),
271
416
  /*is_client=*/true,
272
417
  /*max_header_list_size_soft_limit=*/
273
- max_header_list_size_soft_limit_,
418
+ incoming_headers_.soft_limit(),
274
419
  /*max_header_list_size_hard_limit=*/
275
- settings_.acked().max_header_list_size());
420
+ settings_->acked().max_header_list_size());
276
421
  if (read_result.IsOk()) {
277
- Arena::PoolPtr<grpc_metadata_batch> metadata =
278
- TakeValue(std::move(read_result));
279
- if (incoming_header_end_stream_) {
422
+ ServerMetadataHandle metadata = TakeValue(std::move(read_result));
423
+ if (incoming_headers_.HeaderHasEndStream()) {
280
424
  // TODO(tjagtap) : [PH2][P1] : Is this the right way to differentiate
281
425
  // between initial and trailing metadata?
282
- GRPC_HTTP2_CLIENT_DLOG
283
- << "Http2Transport ProcessMetadata SpawnPushServerTrailingMetadata";
284
- did_push_trailing_metadata = true;
285
- call.SpawnPushServerTrailingMetadata(std::move(metadata));
286
- CloseStream(stream_id, absl::OkStatus(),
287
- CloseStreamArgs{
288
- /*close_reads=*/true,
289
- /*close_writes=*/true,
290
- /*send_rst_stream=*/false,
291
- /*should_not_push_trailers=*/true,
292
- });
293
-
426
+ stream->MarkHalfClosedRemote();
427
+ stream->did_receive_trailing_metadata = true;
428
+ BeginCloseStream(stream, /*reset_stream_error_code=*/std::nullopt,
429
+ std::move(metadata));
294
430
  } else {
295
- GRPC_HTTP2_CLIENT_DLOG
296
- << "Http2Transport ProcessMetadata SpawnPushServerInitialMetadata";
297
- did_push_initial_metadata = true;
431
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessMetadata "
432
+ "SpawnPushServerInitialMetadata";
433
+ stream->did_receive_initial_metadata = true;
298
434
  call.SpawnPushServerInitialMetadata(std::move(metadata));
299
435
  }
300
436
  return Http2Status::Ok();
301
437
  }
302
- GRPC_HTTP2_CLIENT_DLOG << "Http2Transport ProcessMetadata Failed";
438
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessMetadata Failed";
303
439
  return ValueOrHttp2Status<Arena::PoolPtr<grpc_metadata_batch>>::TakeStatus(
304
440
  std::move(read_result));
305
441
  }
@@ -310,19 +446,19 @@ Http2Status Http2ClientTransport::ProcessHttp2RstStreamFrame(
310
446
  Http2RstStreamFrame frame) {
311
447
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-rst_stream
312
448
  GRPC_HTTP2_CLIENT_DLOG
313
- << "Http2Transport ProcessHttp2RstStreamFrame { stream_id="
449
+ << "Http2ClientTransport ProcessHttp2RstStreamFrame { stream_id="
314
450
  << frame.stream_id << ", error_code=" << frame.error_code << " }";
315
- Http2ErrorCode error_code =
316
- Http2ErrorCodeFromRstFrameErrorCode(frame.error_code);
317
- CloseStream(frame.stream_id,
318
- absl::Status((ErrorCodeToAbslStatusCode(error_code)),
319
- "Reset stream frame received."),
320
- CloseStreamArgs{
321
- /*close_reads=*/true,
322
- /*close_writes=*/true,
323
- /*send_rst_stream=*/false,
324
- /*push_trailing_metadata=*/true,
325
- });
451
+
452
+ Http2ErrorCode error_code = FrameErrorCodeToHttp2ErrorCode(frame.error_code);
453
+ absl::Status status = absl::Status(ErrorCodeToAbslStatusCode(error_code),
454
+ "Reset stream frame received.");
455
+ RefCountedPtr<Stream> stream = LookupStream(frame.stream_id);
456
+ if (stream != nullptr) {
457
+ stream->MarkHalfClosedRemote();
458
+ BeginCloseStream(stream, /*reset_stream_error_code=*/std::nullopt,
459
+ CancelledServerMetadataFromStatus(status));
460
+ }
461
+
326
462
  // In case of stream error, we do not want the Read Loop to be broken. Hence
327
463
  // returning an ok status.
328
464
  return Http2Status::Ok();
@@ -332,30 +468,34 @@ Http2Status Http2ClientTransport::ProcessHttp2SettingsFrame(
332
468
  Http2SettingsFrame frame) {
333
469
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-settings
334
470
 
335
- GRPC_HTTP2_CLIENT_DLOG << "Http2Transport ProcessHttp2SettingsFrame { ack="
336
- << frame.ack
337
- << ", settings length=" << frame.settings.size()
338
- << "}";
339
-
340
- // The connector code needs us to run this
341
- if (on_receive_settings_ != nullptr) {
342
- ExecCtx::Run(DEBUG_LOCATION, on_receive_settings_, absl::OkStatus());
343
- on_receive_settings_ = nullptr;
344
- }
471
+ GRPC_HTTP2_CLIENT_DLOG
472
+ << "Http2ClientTransport ProcessHttp2SettingsFrame { ack=" << frame.ack
473
+ << ", settings length=" << frame.settings.size() << "}";
345
474
 
346
475
  if (!frame.ack) {
347
- // Check if the received settings have legal values
348
476
  Http2Status status = ValidateSettingsValues(frame.settings);
349
477
  if (!status.IsOk()) {
350
478
  return status;
351
479
  }
352
- // TODO(tjagtap) : [PH2][P1]
353
- // Apply the new settings
354
- // Quickly send the ACK to the peer once the settings are applied
480
+ settings_->BufferPeerSettings(std::move(frame.settings));
481
+ SpawnGuardedTransportParty("SettingsAck", TriggerWriteCycle());
482
+ if (GPR_UNLIKELY(!settings_->IsFirstPeerSettingsApplied())) {
483
+ // Apply the first settings before we read any other frames.
484
+ reader_state_.SetPauseReadLoop();
485
+ }
355
486
  } else {
356
- // TODO(tjagtap) : [PH2][P1]
357
- // Stop the setting timeout promise
358
- // Update the ACKed setting data structure
487
+ if (settings_->OnSettingsAckReceived()) {
488
+ parser_.hpack_table()->SetMaxBytes(
489
+ settings_->acked().header_table_size());
490
+ ActOnFlowControlAction(flow_control_.SetAckedInitialWindow(
491
+ settings_->acked().initial_window_size()),
492
+ /*stream=*/nullptr);
493
+ } else {
494
+ // TODO(tjagtap) [PH2][P4] : The RFC does not say anything about what
495
+ // should happen if we receive an unsolicited SETTINGS ACK. Decide if we
496
+ // want to respond with any error or just proceed.
497
+ LOG(ERROR) << "Settings ack received without sending settings";
498
+ }
359
499
  }
360
500
 
361
501
  return Http2Status::Ok();
@@ -363,7 +503,7 @@ Http2Status Http2ClientTransport::ProcessHttp2SettingsFrame(
363
503
 
364
504
  auto Http2ClientTransport::ProcessHttp2PingFrame(Http2PingFrame frame) {
365
505
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-ping
366
- GRPC_HTTP2_CLIENT_DLOG << "Http2Transport ProcessHttp2PingFrame { ack="
506
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessHttp2PingFrame { ack="
367
507
  << frame.ack << ", opaque=" << frame.opaque << " }";
368
508
  return AssertResultType<Http2Status>(If(
369
509
  frame.ack,
@@ -372,37 +512,114 @@ auto Http2ClientTransport::ProcessHttp2PingFrame(Http2PingFrame frame) {
372
512
  return self->AckPing(opaque);
373
513
  },
374
514
  [self = RefAsSubclass<Http2ClientTransport>(), opaque = frame.opaque]() {
375
- // TODO(akshitpatel) : [PH2][P2] : Have a counter to track number of
376
- // pending induced frames (Ping/Settings Ack). This is to ensure that
377
- // if write is taking a long time, we can stop reads and prioritize
378
- // writes.
379
- // RFC9113: PING responses SHOULD be given higher priority than any
380
- // other frame.
381
- self->pending_ping_acks_.push_back(opaque);
382
- // TODO(akshitpatel) : [PH2][P2] : This is done assuming that the other
383
- // ProcessFrame promises may return stream or connection failures. If
384
- // this does not turn out to be true, consider returning absl::Status
385
- // here.
386
- return Map(self->TriggerWriteCycle(), [](absl::Status status) {
387
- return (status.ok())
388
- ? Http2Status::Ok()
389
- : Http2Status::AbslConnectionError(
390
- status.code(), std::string(status.message()));
391
- });
515
+ return If(
516
+ self->test_only_ack_pings_,
517
+ [self, opaque]() {
518
+ // TODO(akshitpatel) : [PH2][P2] : Have a counter to track number
519
+ // of pending induced frames (Ping/Settings Ack). This is to
520
+ // ensure that if write is taking a long time, we can stop reads
521
+ // and prioritize writes. RFC9113: PING responses SHOULD be given
522
+ // higher priority than any other frame.
523
+ self->ping_manager_->AddPendingPingAck(opaque);
524
+ // TODO(akshitpatel) : [PH2][P2] : This is done assuming that the
525
+ // other ProcessFrame promises may return stream or connection
526
+ // failures. If this does not turn out to be true, consider
527
+ // returning absl::Status here.
528
+ return Map(self->TriggerWriteCycle(), [](absl::Status status) {
529
+ return ToHttpOkOrConnError(status);
530
+ });
531
+ },
532
+ []() {
533
+ GRPC_HTTP2_CLIENT_DLOG
534
+ << "Http2ClientTransport ProcessHttp2PingFrame "
535
+ "test_only_ack_pings_ is false. Ignoring the ping "
536
+ "request.";
537
+ return Immediate(Http2Status::Ok());
538
+ });
392
539
  }));
393
540
  }
394
541
 
395
542
  Http2Status Http2ClientTransport::ProcessHttp2GoawayFrame(
396
543
  Http2GoawayFrame frame) {
397
544
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-goaway
398
- GRPC_HTTP2_CLIENT_DLOG << "Http2Transport ProcessHttp2GoawayFrame Factory";
399
- // TODO(tjagtap) : [PH2][P2] : Implement this.
400
- GRPC_HTTP2_CLIENT_DLOG << "Http2Transport ProcessHttp2GoawayFrame Promise { "
401
- "last_stream_id="
402
- << frame.last_stream_id
403
- << ", error_code=" << frame.error_code
404
- << ", debug_data=" << frame.debug_data.as_string_view()
405
- << "}";
545
+ GRPC_HTTP2_CLIENT_DLOG
546
+ << "Http2ClientTransport ProcessHttp2GoawayFrame Promise { "
547
+ "last_stream_id="
548
+ << frame.last_stream_id << ", error_code=" << frame.error_code
549
+ << ", debug_data=" << frame.debug_data.as_string_view() << "}";
550
+ LOG_IF(ERROR,
551
+ frame.error_code != static_cast<uint32_t>(Http2ErrorCode::kNoError))
552
+ << "Received GOAWAY frame with error code: " << frame.error_code
553
+ << " and debug data: " << frame.debug_data.as_string_view();
554
+
555
+ uint32_t last_stream_id = 0;
556
+ absl::Status status(ErrorCodeToAbslStatusCode(
557
+ FrameErrorCodeToHttp2ErrorCode(frame.error_code)),
558
+ frame.debug_data.as_string_view());
559
+ if (frame.error_code == static_cast<uint32_t>(Http2ErrorCode::kNoError) &&
560
+ frame.last_stream_id == RFC9113::kMaxStreamId31Bit) {
561
+ const uint32_t next_stream_id = PeekNextStreamId();
562
+ last_stream_id = (next_stream_id > 1) ? next_stream_id - 2 : 0;
563
+ } else {
564
+ last_stream_id = frame.last_stream_id;
565
+ }
566
+ SetMaxAllowedStreamId(last_stream_id);
567
+
568
+ bool close_transport = false;
569
+ {
570
+ MutexLock lock(&transport_mutex_);
571
+ if (CanCloseTransportLocked()) {
572
+ close_transport = true;
573
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessHttp2GoawayFrame "
574
+ "stream_list_ is empty";
575
+ }
576
+ }
577
+
578
+ StateWatcher::DisconnectInfo disconnect_info;
579
+ disconnect_info.reason = Transport::StateWatcher::kGoaway;
580
+ disconnect_info.http2_error_code =
581
+ static_cast<Http2ErrorCode>(frame.error_code);
582
+
583
+ // Throttle keepalive time if the server sends a GOAWAY with error code
584
+ // ENHANCE_YOUR_CALM and debug data equal to "too_many_pings". This will
585
+ // apply to any new transport created on by any subchannel of this channel.
586
+ if (GPR_UNLIKELY(frame.error_code == static_cast<uint32_t>(
587
+ Http2ErrorCode::kEnhanceYourCalm) &&
588
+ frame.debug_data == "too_many_pings")) {
589
+ LOG(ERROR) << ": Received a GOAWAY with error code ENHANCE_YOUR_CALM and "
590
+ "debug data equal to \"too_many_pings\". Current keepalive "
591
+ "time (before throttling): "
592
+ << keepalive_time_.ToString();
593
+ constexpr int max_keepalive_time_millis =
594
+ INT_MAX / KEEPALIVE_TIME_BACKOFF_MULTIPLIER;
595
+ uint64_t throttled_keepalive_time =
596
+ keepalive_time_.millis() > max_keepalive_time_millis
597
+ ? INT_MAX
598
+ : keepalive_time_.millis() * KEEPALIVE_TIME_BACKOFF_MULTIPLIER;
599
+ if (!IsTransportStateWatcherEnabled()) {
600
+ status.SetPayload(kKeepaliveThrottlingKey,
601
+ absl::Cord(std::to_string(throttled_keepalive_time)));
602
+ }
603
+ disconnect_info.keepalive_time =
604
+ Duration::Milliseconds(throttled_keepalive_time);
605
+ }
606
+
607
+ if (close_transport) {
608
+ // TODO(akshitpatel) : [PH2][P3] : Ideally the error here should be
609
+ // kNoError. However, Http2Status does not support kNoError. We should
610
+ // revisit this and update the error code.
611
+ MaybeSpawnCloseTransport(Http2Status::Http2ConnectionError(
612
+ FrameErrorCodeToHttp2ErrorCode((
613
+ frame.error_code ==
614
+ Http2ErrorCodeToFrameErrorCode(Http2ErrorCode::kNoError)
615
+ ? Http2ErrorCodeToFrameErrorCode(Http2ErrorCode::kInternalError)
616
+ : frame.error_code)),
617
+ std::string(frame.debug_data.as_string_view())));
618
+ }
619
+
620
+ // lie: use transient failure from the transport to indicate goaway has been
621
+ // received.
622
+ ReportDisconnection(status, disconnect_info, "got_goaway");
406
623
  return Http2Status::Ok();
407
624
  }
408
625
 
@@ -410,12 +627,31 @@ Http2Status Http2ClientTransport::ProcessHttp2WindowUpdateFrame(
410
627
  Http2WindowUpdateFrame frame) {
411
628
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-window_update
412
629
  GRPC_HTTP2_CLIENT_DLOG
413
- << "Http2Transport ProcessHttp2WindowUpdateFrame Factory";
414
- // TODO(tjagtap) : [PH2][P2] : Implement this.
415
- GRPC_HTTP2_CLIENT_DLOG
416
- << "Http2Transport ProcessHttp2WindowUpdateFrame Promise { "
630
+ << "Http2ClientTransport ProcessHttp2WindowUpdateFrame Promise { "
417
631
  " stream_id="
418
632
  << frame.stream_id << ", increment=" << frame.increment << "}";
633
+
634
+ RefCountedPtr<Stream> stream = nullptr;
635
+ if (frame.stream_id != 0) {
636
+ stream = LookupStream(frame.stream_id);
637
+ }
638
+ if (stream != nullptr) {
639
+ StreamWritabilityUpdate update =
640
+ stream->ReceivedFlowControlWindowUpdate(frame.increment);
641
+ if (update.became_writable) {
642
+ absl::Status status = writable_stream_list_.EnqueueWrapper(
643
+ stream, update.priority, AreTransportFlowControlTokensAvailable());
644
+ if (!status.ok()) {
645
+ return ToHttpOkOrConnError(status);
646
+ }
647
+ }
648
+ }
649
+
650
+ const bool should_trigger_write =
651
+ ProcessIncomingWindowUpdateFrameFlowControl(frame, flow_control_, stream);
652
+ if (should_trigger_write) {
653
+ SpawnGuardedTransportParty("TransportTokensAvailable", TriggerWriteCycle());
654
+ }
419
655
  return Http2Status::Ok();
420
656
  }
421
657
 
@@ -423,11 +659,14 @@ Http2Status Http2ClientTransport::ProcessHttp2ContinuationFrame(
423
659
  Http2ContinuationFrame frame) {
424
660
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-continuation
425
661
  GRPC_HTTP2_CLIENT_DLOG
426
- << "Http2Transport ProcessHttp2ContinuationFrame Promise { "
662
+ << "Http2ClientTransport ProcessHttp2ContinuationFrame Promise { "
427
663
  "stream_id="
428
664
  << frame.stream_id << ", end_headers=" << frame.end_headers
429
- << ", payload=" << frame.payload.JoinIntoString() << " }";
430
- incoming_header_in_progress_ = !frame.end_headers;
665
+ << ", payload=" << MaybeTruncatePayload(frame.payload) << " }";
666
+
667
+ // State update MUST happen before processing the frame.
668
+ incoming_headers_.OnContinuationReceived(frame);
669
+
431
670
  RefCountedPtr<Stream> stream = LookupStream(frame.stream_id);
432
671
  if (stream == nullptr) {
433
672
  // TODO(tjagtap) : [PH2][P3] : Implement this.
@@ -437,34 +676,45 @@ Http2Status Http2ClientTransport::ProcessHttp2ContinuationFrame(
437
676
  // frame and streams that are reserved using PUSH_PROMISE. An endpoint that
438
677
  // receives an unexpected stream identifier MUST respond with a connection
439
678
  // error (Section 5.4.1) of type PROTOCOL_ERROR.
440
- return Http2Status::Ok();
679
+ return ParseAndDiscardHeaders(std::move(frame.payload), frame.end_headers,
680
+ nullptr, Http2Status::Ok());
441
681
  }
442
- if (stream->GetStreamState() == HttpStreamState::kHalfClosedRemote) {
443
- return Http2Status::Http2StreamError(
444
- Http2ErrorCode::kStreamClosed,
445
- std::string(RFC9113::kHalfClosedRemoteState));
682
+
683
+ if (stream->IsStreamHalfClosedRemote()) {
684
+ return ParseAndDiscardHeaders(
685
+ std::move(frame.payload), frame.end_headers, stream,
686
+ Http2Status::Http2StreamError(
687
+ Http2ErrorCode::kStreamClosed,
688
+ std::string(RFC9113::kHalfClosedRemoteState)));
446
689
  }
447
690
 
448
- HeaderAssembler& assember = stream->header_assembler;
449
- Http2Status result = assember.AppendContinuationFrame(std::move(frame));
450
- if (result.IsOk()) {
451
- return ProcessMetadata(stream->stream_id, assember, stream->call,
452
- stream->did_push_initial_metadata,
453
- stream->did_push_trailing_metadata);
691
+ Http2Status append_result =
692
+ stream->header_assembler.AppendContinuationFrame(frame);
693
+ if (!append_result.IsOk()) {
694
+ // Frame payload is not consumed if AppendContinuationFrame returns a
695
+ // non-OK status. We need to process it to keep our in consistent state.
696
+ return ParseAndDiscardHeaders(std::move(frame.payload), frame.end_headers,
697
+ stream, std::move(append_result));
698
+ }
699
+
700
+ Http2Status status = ProcessMetadata(stream);
701
+ if (!status.IsOk()) {
702
+ // Frame payload is consumed by HeaderAssembler. So passing an empty
703
+ // SliceBuffer to ParseAndDiscardHeaders.
704
+ return ParseAndDiscardHeaders(SliceBuffer(), frame.end_headers, stream,
705
+ std::move(status));
454
706
  }
455
- return result;
707
+
708
+ // Frame payload has either been processed or moved to the HeaderAssembler.
709
+ return Http2Status::Ok();
456
710
  }
457
711
 
458
712
  Http2Status Http2ClientTransport::ProcessHttp2SecurityFrame(
459
713
  Http2SecurityFrame frame) {
460
- GRPC_HTTP2_CLIENT_DLOG << "Http2Transport ProcessHttp2SecurityFrame "
461
- "ProcessHttp2SecurityFrame { payload="
462
- << frame.payload.JoinIntoString() << " }";
463
- if ((settings_.acked().allow_security_frame() ||
464
- settings_.local().allow_security_frame()) &&
465
- settings_.peer().allow_security_frame()) {
466
- // TODO(tjagtap) : [PH2][P4] : Evaluate when to accept the frame and when to
467
- // reject it. Compare it with the requirement and with CHTTP2.
714
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessHttp2SecurityFrame "
715
+ "{ payload.Length="
716
+ << frame.payload.Length() << " }";
717
+ if (settings_->IsSecurityFrameExpected()) {
468
718
  // TODO(tjagtap) : [PH2][P3] : Add handling of Security frame
469
719
  // Just the frame.payload needs to be passed to the endpoint_ object.
470
720
  // Refer usage of TransportFramingEndpointExtension.
@@ -508,7 +758,7 @@ auto Http2ClientTransport::ProcessOneFrame(Http2Frame frame) {
508
758
  return self->ProcessHttp2SecurityFrame(std::move(frame));
509
759
  },
510
760
  [](GRPC_UNUSED Http2UnknownFrame frame) {
511
- // As per HTTP2 RFC, implementations MUST ignore and discard frames of
761
+ // RFC9113: Implementations MUST ignore and discard frames of
512
762
  // unknown types.
513
763
  return Http2Status::Ok();
514
764
  },
@@ -519,8 +769,64 @@ auto Http2ClientTransport::ProcessOneFrame(Http2Frame frame) {
519
769
  }));
520
770
  }
521
771
 
772
+ Http2Status Http2ClientTransport::ParseAndDiscardHeaders(
773
+ SliceBuffer&& buffer, const bool is_end_headers,
774
+ const RefCountedPtr<Stream> stream, Http2Status&& original_status,
775
+ DebugLocation whence) {
776
+ const bool is_initial_metadata = !incoming_headers_.HeaderHasEndStream();
777
+ const uint32_t incoming_stream_id = incoming_headers_.GetStreamId();
778
+ GRPC_HTTP2_CLIENT_DLOG
779
+ << "Http2ClientTransport ParseAndDiscardHeaders buffer "
780
+ "size: "
781
+ << buffer.Length() << " is_initial_metadata: " << is_initial_metadata
782
+ << " is_end_headers: " << is_end_headers
783
+ << " incoming_stream_id: " << incoming_stream_id
784
+ << " stream_id: " << (stream == nullptr ? 0 : stream->GetStreamId())
785
+ << " original_status: " << original_status.DebugString()
786
+ << " whence: " << whence.file() << ":" << whence.line();
787
+
788
+ return http2::ParseAndDiscardHeaders(
789
+ parser_, std::move(buffer),
790
+ HeaderAssembler::ParseHeaderArgs{
791
+ /*is_initial_metadata=*/is_initial_metadata,
792
+ /*is_end_headers=*/is_end_headers,
793
+ /*is_client=*/true,
794
+ /*max_header_list_size_soft_limit=*/
795
+ incoming_headers_.soft_limit(),
796
+ /*max_header_list_size_hard_limit=*/
797
+ settings_->acked().max_header_list_size(),
798
+ /*stream_id=*/incoming_stream_id,
799
+ },
800
+ stream, std::move(original_status));
801
+ }
802
+
522
803
  ///////////////////////////////////////////////////////////////////////////////
523
804
  // Read Related Promises and Promise Factories
805
+ auto Http2ClientTransport::EndpointReadSlice(const size_t num_bytes) {
806
+ return Map(
807
+ endpoint_.ReadSlice(num_bytes),
808
+ [self = RefAsSubclass<Http2ClientTransport>(),
809
+ num_bytes](absl::StatusOr<Slice> status) {
810
+ if (status.ok()) {
811
+ self->keepalive_manager_->GotData();
812
+ self->ztrace_collector_->Append(PromiseEndpointReadTrace{num_bytes});
813
+ }
814
+ return status;
815
+ });
816
+ }
817
+
818
+ auto Http2ClientTransport::EndpointRead(const size_t num_bytes) {
819
+ return Map(
820
+ endpoint_.Read(num_bytes),
821
+ [self = RefAsSubclass<Http2ClientTransport>(),
822
+ num_bytes](absl::StatusOr<SliceBuffer> status) {
823
+ if (status.ok()) {
824
+ self->keepalive_manager_->GotData();
825
+ self->ztrace_collector_->Append(PromiseEndpointReadTrace{num_bytes});
826
+ }
827
+ return status;
828
+ });
829
+ }
524
830
 
525
831
  auto Http2ClientTransport::ReadAndProcessOneFrame() {
526
832
  GRPC_HTTP2_CLIENT_DLOG
@@ -539,13 +845,21 @@ auto Http2ClientTransport::ReadAndProcessOneFrame() {
539
845
  // Validate the incoming frame as per the current state of the transport
540
846
  [self = RefAsSubclass<Http2ClientTransport>()](Http2FrameHeader header) {
541
847
  Http2Status status = ValidateFrameHeader(
542
- /*max_frame_size_setting*/ self->settings_.acked().max_frame_size(),
543
- /*incoming_header_in_progress*/ self->incoming_header_in_progress_,
544
- /*incoming_header_stream_id*/ self->incoming_header_stream_id_,
545
- /*current_frame_header*/ header);
546
-
547
- if (!status.IsOk()) {
548
- return self->HandleError(std::move(status));
848
+ /*max_frame_size_setting*/ self->settings_->acked()
849
+ .max_frame_size(),
850
+ /*incoming_header_in_progress*/
851
+ self->incoming_headers_.IsWaitingForContinuationFrame(),
852
+ /*incoming_header_stream_id*/
853
+ self->incoming_headers_.GetStreamId(),
854
+ /*current_frame_header*/ header,
855
+ /*last_stream_id=*/self->GetLastStreamId(),
856
+ /*is_client=*/true, /*is_first_settings_processed=*/
857
+ self->settings_->IsFirstPeerSettingsApplied());
858
+
859
+ if (GPR_UNLIKELY(!status.IsOk())) {
860
+ GRPC_DCHECK(status.GetType() ==
861
+ Http2Status::Http2ErrorType::kConnectionError);
862
+ return self->HandleError(std::nullopt, std::move(status));
549
863
  }
550
864
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ReadAndProcessOneFrame "
551
865
  "Validated Frame Header:"
@@ -565,11 +879,12 @@ auto Http2ClientTransport::ReadAndProcessOneFrame() {
565
879
  SliceBuffer payload) -> absl::StatusOr<Http2Frame> {
566
880
  GRPC_HTTP2_CLIENT_DLOG
567
881
  << "Http2ClientTransport ReadAndProcessOneFrame ParseFramePayload "
568
- << payload.JoinIntoString();
882
+ << MaybeTruncatePayload(payload);
569
883
  ValueOrHttp2Status<Http2Frame> frame =
570
884
  ParseFramePayload(self->current_frame_header_, std::move(payload));
571
885
  if (!frame.IsOk()) {
572
886
  return self->HandleError(
887
+ self->current_frame_header_.stream_id,
573
888
  ValueOrHttp2Status<Http2Frame>::TakeStatus(std::move(frame)));
574
889
  }
575
890
  return TakeValue(std::move(frame));
@@ -578,14 +893,18 @@ auto Http2ClientTransport::ReadAndProcessOneFrame() {
578
893
  GRPC_UNUSED Http2Frame frame) {
579
894
  GRPC_HTTP2_CLIENT_DLOG
580
895
  << "Http2ClientTransport ReadAndProcessOneFrame ProcessOneFrame";
581
- return AssertResultType<absl::Status>(
582
- Map(self->ProcessOneFrame(std::move(frame)),
583
- [self](Http2Status status) {
584
- if (!status.IsOk()) {
585
- return self->HandleError(std::move(status));
586
- }
587
- return absl::OkStatus();
588
- }));
896
+ return AssertResultType<absl::Status>(Map(
897
+ self->ProcessOneFrame(std::move(frame)),
898
+ [self](Http2Status status) {
899
+ if (!status.IsOk()) {
900
+ return self->HandleError(self->current_frame_header_.stream_id,
901
+ std::move(status));
902
+ }
903
+ return absl::OkStatus();
904
+ }));
905
+ },
906
+ [self = RefAsSubclass<Http2ClientTransport>()]() -> Poll<absl::Status> {
907
+ return self->reader_state_.MaybePauseReadLoop();
589
908
  }));
590
909
  }
591
910
 
@@ -602,355 +921,778 @@ auto Http2ClientTransport::ReadLoop() {
602
921
  }));
603
922
  }
604
923
 
605
- auto Http2ClientTransport::OnReadLoopEnded() {
606
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport OnReadLoopEnded Factory";
607
- return
608
- [self = RefAsSubclass<Http2ClientTransport>()](absl::Status status) {
609
- GRPC_HTTP2_CLIENT_DLOG
610
- << "Http2ClientTransport OnReadLoopEnded Promise Status=" << status;
611
- GRPC_UNUSED absl::Status error =
612
- self->HandleError(Http2Status::AbslConnectionError(
613
- status.code(), std::string(status.message())));
614
- };
615
- }
616
-
617
924
  ///////////////////////////////////////////////////////////////////////////////
618
- // Write Related Promises and Promise Factories
619
-
620
- auto Http2ClientTransport::WriteFromQueue() {
621
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport WriteFromQueue Factory";
622
- return TrySeq(
623
- outgoing_frames_.NextBatch(128),
624
- [self = RefAsSubclass<Http2ClientTransport>()](
625
- std::vector<Http2Frame> frames) {
626
- SliceBuffer output_buf;
627
- if (self->is_first_write_) {
628
- GRPC_HTTP2_CLIENT_DLOG
629
- << "Http2ClientTransport Write GRPC_CHTTP2_CLIENT_CONNECT_STRING";
630
- output_buf.Append(Slice(grpc_slice_from_copied_string(
631
- GRPC_CHTTP2_CLIENT_CONNECT_STRING)));
632
- self->is_first_write_ = false;
633
- }
634
- Serialize(absl::Span<Http2Frame>(frames), output_buf);
635
- uint64_t buffer_length = output_buf.Length();
636
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport WriteFromQueue Promise";
637
- return If(
638
- buffer_length > 0,
639
- [self, output_buffer = std::move(output_buf)]() mutable {
640
- self->bytes_sent_in_last_write_ = true;
641
- return self->endpoint_.Write(std::move(output_buffer),
642
- PromiseEndpoint::WriteArgs{});
643
- },
644
- [] { return absl::OkStatus(); });
645
- });
646
- }
925
+ // Flow Control for the Transport
647
926
 
648
- auto Http2ClientTransport::WriteLoop() {
649
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport WriteLoop Factory";
927
+ auto Http2ClientTransport::FlowControlPeriodicUpdateLoop() {
928
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport PeriodicUpdateLoop Factory";
650
929
  return AssertResultType<absl::Status>(
651
930
  Loop([self = RefAsSubclass<Http2ClientTransport>()]() {
652
- // TODO(akshitpatel) : [PH2][P1] : Once a common SliceBuffer is used, we
653
- // can move bytes_sent_in_last_write_ to be a local variable.
654
- self->bytes_sent_in_last_write_ = false;
931
+ GRPC_HTTP2_CLIENT_DLOG
932
+ << "Http2ClientTransport FlowControlPeriodicUpdateLoop Loop";
655
933
  return TrySeq(
656
- // TODO(akshitpatel) : [PH2][P1] : WriteFromQueue may write settings
657
- // acks as well. This will break the call to ResetPingClock as it
658
- // only needs to be called on writing Data/Header/WindowUpdate
659
- // frames. Possible fixes: Either WriteFromQueue iterates over all
660
- // the frames and figures out the types of frames needed (this may
661
- // anyways be needed to check that we do not send frames for closed
662
- // streams) or we have flags to indicate the types of frame that are
663
- // enqueued.
664
- self->WriteFromQueue(), [self] { return self->MaybeSendPing(); },
665
- [self] { return self->MaybeSendPingAcks(); },
666
- [self]() -> LoopCtl<absl::Status> {
667
- // If any Header/Data/WindowUpdate frame was sent in the last
668
- // write, reset the ping clock.
669
- if (self->bytes_sent_in_last_write_) {
670
- self->ping_manager_.ResetPingClock(/*is_client=*/true);
671
- }
934
+ // TODO(tjagtap) [PH2][P2][BDP] Remove this static sleep when the
935
+ // BDP code is done.
936
+ Sleep(chttp2::kFlowControlPeriodicUpdateTimer),
937
+ [self]() -> Poll<absl::Status> {
672
938
  GRPC_HTTP2_CLIENT_DLOG
673
- << "Http2ClientTransport WriteLoop Continue";
674
- return Continue();
675
- });
939
+ << "Http2ClientTransport FlowControl PeriodicUpdate()";
940
+ chttp2::FlowControlAction action =
941
+ self->flow_control_.PeriodicUpdate();
942
+ bool is_action_empty = action == chttp2::FlowControlAction();
943
+ // This may trigger a write cycle
944
+ self->ActOnFlowControlAction(action, nullptr);
945
+ if (is_action_empty) {
946
+ // TODO(tjagtap) [PH2][P2][BDP] Remove this when the BDP code is
947
+ // done. We must continue to do PeriodicUpdate once BDP is in
948
+ // place.
949
+ MutexLock lock(&self->transport_mutex_);
950
+ if (self->GetActiveStreamCountLocked() == 0) {
951
+ self->AddPeriodicUpdatePromiseWaker();
952
+ return Pending{};
953
+ }
954
+ }
955
+ return absl::OkStatus();
956
+ },
957
+ [self]() -> LoopCtl<absl::Status> { return Continue{}; });
676
958
  }));
677
959
  }
678
960
 
679
- auto Http2ClientTransport::OnWriteLoopEnded() {
680
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport OnWriteLoopEnded Factory";
681
- return
682
- [self = RefAsSubclass<Http2ClientTransport>()](absl::Status status) {
961
+ // Equivalent to grpc_chttp2_act_on_flowctl_action in chttp2_transport.cc
962
+ void Http2ClientTransport::ActOnFlowControlAction(
963
+ const chttp2::FlowControlAction& action, RefCountedPtr<Stream> stream) {
964
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::ActOnFlowControlAction"
965
+ << action.DebugString();
966
+ if (action.send_stream_update() != kNoActionNeeded) {
967
+ if (GPR_LIKELY(stream != nullptr)) {
968
+ GRPC_DCHECK_GT(stream->GetStreamId(), 0u);
969
+ if (stream->CanSendWindowUpdateFrames()) {
970
+ window_update_list_.insert(stream->GetStreamId());
683
971
  GRPC_HTTP2_CLIENT_DLOG
684
- << "Http2ClientTransport OnWriteLoopEnded Promise Status="
685
- << status;
686
- GRPC_UNUSED absl::Status error =
687
- self->HandleError(Http2Status::AbslConnectionError(
688
- status.code(), std::string(status.message())));
689
- };
972
+ << "Http2ClientTransport::ActOnFlowControlAction "
973
+ "added stream "
974
+ << stream->GetStreamId() << " to window_update_list_";
975
+ }
976
+ } else {
977
+ GRPC_HTTP2_CLIENT_DLOG
978
+ << "Http2ClientTransport::ActOnFlowControlAction stream is null";
979
+ }
980
+ }
981
+
982
+ ActOnFlowControlActionSettings(
983
+ action, settings_->mutable_local(),
984
+ enable_preferred_rx_crypto_frame_advertisement_);
985
+
986
+ if (action.AnyUpdateImmediately()) {
987
+ // Prioritize sending flow control updates over reading data. If we
988
+ // continue reading while urgent flow control updates are pending, we might
989
+ // exhaust the flow control window. This prevents us from sending window
990
+ // updates to the peer, causing the peer to block unnecessarily while
991
+ // waiting for flow control tokens.
992
+ reader_state_.SetPauseReadLoop();
993
+ SpawnGuardedTransportParty("SendControlFrames", TriggerWriteCycle());
994
+ GRPC_HTTP2_CLIENT_DLOG << "Update Immediately : "
995
+ << action.ImmediateUpdateReasons();
996
+ }
690
997
  }
691
998
 
692
- auto Http2ClientTransport::StreamMultiplexerLoop() {
693
- GRPC_HTTP2_CLIENT_DLOG
694
- << "Http2ClientTransport StreamMultiplexerLoop Factory";
695
- // This loop iterates over all the writable streams and drains them. If
696
- // there are no writable streams, StreamMultiplexerLoop blocks until there
697
- // is a writable stream.
698
- return Loop([self = RefAsSubclass<Http2ClientTransport>()]() mutable {
699
- // Overview:
700
- // 1. Get the next writable stream.
701
- // 2. Dequeue frames from the stream queue based on available transport
702
- // tokens.
703
- // 3. If the stream is still writable, enqueue the stream back to the
704
- // writable stream list.
705
- // 4. Enqueue the dequeued frames to the MPSC queue.
999
+ ///////////////////////////////////////////////////////////////////////////////
1000
+ // Write Related Promises and Promise Factories
1001
+
1002
+ auto Http2ClientTransport::ProcessAndWriteControlFrames() {
1003
+ SliceBuffer output_buf;
1004
+ if (is_first_write_) {
1005
+ // RFC9113: That is, the connection preface starts with the string
1006
+ // "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
1007
+ // This sequence MUST be followed by a SETTINGS frame, which MAY be empty.
1008
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport WriteControlFrames "
1009
+ "GRPC_CHTTP2_CLIENT_CONNECT_STRING";
1010
+ output_buf.Append(
1011
+ Slice::FromCopiedString(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
1012
+ settings_->MaybeGetSettingsAndSettingsAckFrames(flow_control_, output_buf);
1013
+ // TODO(tjagtap) [PH2][P2][Server] : This will be opposite for server. We
1014
+ // must read before we write for the server. So the ReadLoop will be Spawned
1015
+ // just after the constructor, and the write loop should be spawned only
1016
+ // after the first SETTINGS frame is completely received.
1017
+ //
1018
+ // Because the client is expected to write before it reads, we spawn the
1019
+ // ReadLoop of the client only after the first write is queued.
1020
+ SpawnGuardedTransportParty("ReadLoop", UntilTransportClosed(ReadLoop()));
1021
+ is_first_write_ = false;
1022
+ }
1023
+
1024
+ // Order of Control Frames is important.
1025
+ // 1. GOAWAY - This is first because if this is the final GoAway, then we may
1026
+ // not need to send anything else to the peer.
1027
+ // 2. SETTINGS and SETTINGS ACK
1028
+ // 3. PING and PING acks.
1029
+ // 4. WINDOW_UPDATE
1030
+ // 5. Custom gRPC security frame
1031
+
1032
+ goaway_manager_.MaybeGetSerializedGoawayFrame(output_buf);
1033
+ http2::Http2ErrorCode apply_status =
1034
+ settings_->MaybeReportAndApplyBufferedPeerSettings(event_engine_.get());
1035
+ if (!goaway_manager_.IsImmediateGoAway() &&
1036
+ apply_status == http2::Http2ErrorCode::kNoError) {
1037
+ EnforceLatestIncomingSettings();
1038
+ settings_->MaybeGetSettingsAndSettingsAckFrames(flow_control_, output_buf);
1039
+ ping_manager_->MaybeGetSerializedPingFrames(output_buf,
1040
+ NextAllowedPingInterval());
1041
+ MaybeGetWindowUpdateFrames(output_buf);
1042
+ }
1043
+ const uint64_t buffer_length = output_buf.Length();
1044
+ ztrace_collector_->Append(PromiseEndpointWriteTrace{buffer_length});
1045
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport WriteControlFrames Size : "
1046
+ << buffer_length;
1047
+ return AssertResultType<absl::Status>(
1048
+ If((buffer_length > 0 && apply_status == http2::Http2ErrorCode::kNoError),
1049
+ [self = RefAsSubclass<Http2ClientTransport>(),
1050
+ output_buf = std::move(output_buf)]() mutable {
1051
+ return self->endpoint_.Write(std::move(output_buf),
1052
+ GetWriteArgs(self->settings_->peer()));
1053
+ },
1054
+ [self = RefAsSubclass<Http2ClientTransport>(), apply_status]() {
1055
+ if (apply_status != http2::Http2ErrorCode::kNoError) {
1056
+ return self->HandleError(
1057
+ std::nullopt,
1058
+ Http2Status::Http2ConnectionError(
1059
+ apply_status, "Failed to apply incoming settings"));
1060
+ }
1061
+ return absl::OkStatus();
1062
+ }));
1063
+ }
1064
+
1065
+ void Http2ClientTransport::NotifyControlFramesWriteDone() {
1066
+ // Notify Control modules that we have sent the frames.
1067
+ // All notifications are expected to be synchronous.
1068
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport NotifyControlFramesWriteDone";
1069
+ reader_state_.ResumeReadLoopIfPaused();
1070
+ ping_manager_->NotifyPingSent();
1071
+ goaway_manager_.NotifyGoawaySent();
1072
+ MaybeSpawnWaitForSettingsTimeout();
1073
+ }
1074
+
1075
+ auto Http2ClientTransport::SerializeAndWrite(std::vector<Http2Frame>&& frames) {
1076
+ SliceBuffer output_buf;
1077
+ should_reset_ping_clock_ =
1078
+ Serialize(absl::Span<Http2Frame>(frames), output_buf)
1079
+ .should_reset_ping_clock;
1080
+ size_t output_buf_length = output_buf.Length();
1081
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport SerializeAndWrite Write "
1082
+ "output_buf.length() = "
1083
+ << output_buf_length;
1084
+ return AssertResultType<absl::Status>(If(
1085
+ output_buf_length > 0,
1086
+ [self = RefAsSubclass<Http2ClientTransport>(),
1087
+ output_buf = std::move(output_buf)]() mutable {
1088
+ return self->endpoint_.Write(std::move(output_buf),
1089
+ GetWriteArgs(self->settings_->peer()));
1090
+ },
1091
+ []() { return absl::OkStatus(); }));
1092
+ }
1093
+
1094
+ absl::StatusOr<std::vector<Http2Frame>>
1095
+ Http2ClientTransport::DequeueStreamFrames(RefCountedPtr<Stream> stream) {
1096
+ // write_bytes_remaining_ is passed as an upper bound on the max
1097
+ // number of tokens that can be dequeued to prevent dequeuing huge
1098
+ // data frames when write_bytes_remaining_ is very low. As the
1099
+ // available transport tokens can only range from 0 to 2^31 - 1,
1100
+ // we are clamping the write_bytes_remaining_ to that range.
1101
+ const uint32_t tokens =
1102
+ GetMaxPermittedDequeue(flow_control_, stream->flow_control,
1103
+ write_bytes_remaining_, settings_->peer());
1104
+ const uint32_t stream_flow_control_tokens = static_cast<uint32_t>(
1105
+ GetStreamFlowControlTokens(stream->flow_control, settings_->peer()));
1106
+ stream->flow_control.ReportIfStalled(
1107
+ /*is_client=*/true, stream->GetStreamId(), settings_->peer());
1108
+ StreamDataQueue<ClientMetadataHandle>::DequeueResult result =
1109
+ stream->DequeueFrames(tokens, stream_flow_control_tokens,
1110
+ settings_->peer().max_frame_size(), encoder_);
1111
+ ProcessOutgoingDataFrameFlowControl(stream->flow_control,
1112
+ result.flow_control_tokens_consumed);
1113
+ if (result.is_writable) {
1114
+ // Stream is still writable. Enqueue it back to the writable
1115
+ // stream list.
1116
+ absl::Status status = writable_stream_list_.EnqueueWrapper(
1117
+ stream, result.priority, AreTransportFlowControlTokensAvailable());
1118
+
1119
+ if (GPR_UNLIKELY(!status.ok())) {
1120
+ GRPC_HTTP2_CLIENT_DLOG
1121
+ << "Http2ClientTransport DequeueStreamFrames Failed to "
1122
+ "enqueue stream "
1123
+ << stream->GetStreamId() << " with status: " << status;
1124
+ // Close transport if we fail to enqueue stream.
1125
+ return HandleError(std::nullopt, ToHttpOkOrConnError(status));
1126
+ }
1127
+ }
1128
+
1129
+ // If the stream is aborted before initial metadata is dequeued, we will
1130
+ // not dequeue any frames from the stream data queue (including RST_STREAM).
1131
+ // Because of this, we will add the stream to the stream_list only when
1132
+ // we are guaranteed to send initial metadata on the wire. If the above
1133
+ // mentioned scenario occurs, the stream ref will be dropped by the
1134
+ // multiplexer loop as the stream will never be writable again. Additionally,
1135
+ // the other two stream refs, CallHandler OnDone and OutboundLoop will be
1136
+ // dropped by Callv3 triggering cleaning up the stream object.
1137
+ if (result.InitialMetadataDequeued()) {
1138
+ GRPC_HTTP2_CLIENT_DLOG
1139
+ << "Http2ClientTransport DequeueStreamFrames InitialMetadataDequeued "
1140
+ "stream_id = "
1141
+ << stream->GetStreamId();
1142
+ stream->SentInitialMetadata();
1143
+ // After this point, initial metadata is guaranteed to be sent out.
1144
+ AddToStreamList(stream);
1145
+ }
1146
+
1147
+ if (result.HalfCloseDequeued()) {
1148
+ GRPC_HTTP2_CLIENT_DLOG
1149
+ << "Http2ClientTransport DequeueStreamFrames HalfCloseDequeued "
1150
+ "stream_id = "
1151
+ << stream->GetStreamId();
1152
+ stream->MarkHalfClosedLocal();
1153
+ CloseStream(
1154
+ stream,
1155
+ CloseStreamArgs{/*close_reads=*/stream->did_receive_trailing_metadata,
1156
+ /*close_writes=*/true});
1157
+ }
1158
+ if (result.ResetStreamDequeued()) {
1159
+ GRPC_HTTP2_CLIENT_DLOG
1160
+ << "Http2ClientTransport DequeueStreamFrames ResetStreamDequeued "
1161
+ "stream_id = "
1162
+ << stream->GetStreamId();
1163
+ stream->MarkHalfClosedLocal();
1164
+ CloseStream(stream, CloseStreamArgs{/*close_reads=*/true,
1165
+ /*close_writes=*/true});
1166
+ }
1167
+
1168
+ // Update the write_bytes_remaining_ based on the bytes consumed
1169
+ // in the current dequeue.
1170
+ write_bytes_remaining_ =
1171
+ (write_bytes_remaining_ >= result.total_bytes_consumed)
1172
+ ? (write_bytes_remaining_ - result.total_bytes_consumed)
1173
+ : 0;
1174
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport DequeueStreamFrames "
1175
+ "write_bytes_remaining_ after dequeue = "
1176
+ << write_bytes_remaining_ << " total_bytes_consumed = "
1177
+ << result.total_bytes_consumed
1178
+ << " stream_id = " << stream->GetStreamId()
1179
+ << " is_writable = " << result.is_writable
1180
+ << " stream_priority = "
1181
+ << static_cast<uint8_t>(result.priority)
1182
+ << " number of frames = " << result.frames.size();
1183
+ return std::move(result.frames);
1184
+ }
1185
+
1186
+ // This MultiplexerLoop promise is responsible for Multiplexing multiple gRPC
1187
+ // Requests (HTTP2 Streams) and writing them into one common endpoint.
1188
+ auto Http2ClientTransport::MultiplexerLoop() {
1189
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport MultiplexerLoop Factory";
1190
+ return AssertResultType<
1191
+ absl::Status>(Loop([self = RefAsSubclass<Http2ClientTransport>()]() {
1192
+ self->write_bytes_remaining_ = self->GetMaxWriteSize();
1193
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport MultiplexerLoop "
1194
+ << " max_write_size_=" << self->GetMaxWriteSize();
706
1195
  return TrySeq(
707
- self->writable_stream_list_.Next(/*transport_tokens_available*/ true),
708
- [self](const uint32_t stream_id) mutable
709
- -> absl::StatusOr<std::vector<Http2Frame>> {
710
- RefCountedPtr<Stream> stream = self->LookupStream(stream_id);
711
- if (GPR_UNLIKELY(stream == nullptr)) {
712
- // Stream was closed before we could dequeue.
713
- // TODO(akshitpatel) : [PH2][P2] : Race condition. Determine should
714
- // we have a DCHECK here based on how ResetStream/Aborts are
715
- // handled.
716
- return std::vector<Http2Frame>();
717
- }
1196
+ self->writable_stream_list_.WaitForReady(
1197
+ self->AreTransportFlowControlTokensAvailable()),
1198
+ [self]() {
1199
+ // TODO(akshitpatel) : [PH2][P2] : Return an `important` tag from
1200
+ // WriteControlFrames() to indicate if we should do a separate write
1201
+ // for the queued control frames or send the queued frames with the
1202
+ // data frames(if any).
1203
+ return Map(
1204
+ self->ProcessAndWriteControlFrames(),
1205
+ [self](absl::Status status) {
1206
+ if (GPR_UNLIKELY(!status.ok())) {
1207
+ GRPC_HTTP2_CLIENT_DLOG
1208
+ << "Http2ClientTransport MultiplexerLoop Failed to "
1209
+ "write control frames with status: "
1210
+ << status;
1211
+ return status;
1212
+ }
1213
+ self->NotifyControlFramesWriteDone();
1214
+ return absl::OkStatus();
1215
+ });
1216
+ },
1217
+ [self]() -> absl::StatusOr<std::vector<Http2Frame>> {
1218
+ std::vector<Http2Frame> frames;
1219
+ // Drain all the writable streams till we have written
1220
+ // max_write_size_ bytes of data or there is no more data to send. In
1221
+ // some cases, we may write more than max_write_size_ bytes(like
1222
+ // writing metadata).
1223
+ while (self->write_bytes_remaining_ > 0) {
1224
+ std::optional<RefCountedPtr<Stream>> optional_stream =
1225
+ self->writable_stream_list_.ImmediateNext(
1226
+ self->AreTransportFlowControlTokensAvailable());
1227
+ if (!optional_stream.has_value()) {
1228
+ GRPC_HTTP2_CLIENT_DLOG
1229
+ << "Http2ClientTransport MultiplexerLoop "
1230
+ "No writable streams available, write_bytes_remaining_ = "
1231
+ << self->write_bytes_remaining_;
1232
+ break;
1233
+ }
1234
+ RefCountedPtr<Stream> stream = std::move(optional_stream.value());
1235
+ GRPC_HTTP2_CLIENT_DLOG
1236
+ << "Http2ClientTransport MultiplexerLoop "
1237
+ "Next writable stream id = "
1238
+ << stream->GetStreamId()
1239
+ << " is_closed_for_writes = " << stream->IsClosedForWrites();
1240
+
1241
+ if (stream->GetStreamId() == kInvalidStreamId) {
1242
+ GRPC_DCHECK(stream->IsStreamIdle());
1243
+ // TODO(akshitpatel) : [PH2][P5] : We will waste a stream id in
1244
+ // the rare scenario where the stream is aborted before it can be
1245
+ // written to. This is a possible area to optimize in future.
1246
+ absl::Status status = self->InitializeStream(stream);
1247
+ if (!status.ok()) {
1248
+ GRPC_HTTP2_CLIENT_DLOG
1249
+ << "Http2ClientTransport MultiplexerLoop "
1250
+ "Failed to assign stream id and add to stream list for "
1251
+ "stream: "
1252
+ << stream.get() << " closing this stream.";
1253
+ self->BeginCloseStream(
1254
+ stream, /*reset_stream_error_code=*/std::nullopt,
1255
+ CancelledServerMetadataFromStatus(status));
1256
+ continue;
1257
+ }
1258
+ }
1259
+
1260
+ if (GPR_LIKELY(!stream->IsClosedForWrites())) {
1261
+ absl::StatusOr<std::vector<Http2Frame>> stream_frames =
1262
+ self->DequeueStreamFrames(stream);
1263
+ if (GPR_UNLIKELY(!stream_frames.ok())) {
1264
+ GRPC_HTTP2_CLIENT_DLOG
1265
+ << "Http2ClientTransport MultiplexerLoop "
1266
+ "Failed to dequeue stream frames with status: "
1267
+ << stream_frames.status();
1268
+ return stream_frames.status();
1269
+ }
718
1270
 
719
- // TODO(akshitpatel) : [PH2][P3] : Plug transport_tokens when
720
- // transport flow control is implemented.
721
- absl::StatusOr<StreamDataQueue<ClientMetadataHandle>::DequeueResult>
722
- result = stream->DequeueFrames(
723
- /*transport_tokens*/ std::numeric_limits<uint32_t>::max(),
724
- self->settings_.peer().max_frame_size(), self->encoder_);
725
- if (result.ok() && result->is_writable) {
726
- // Stream is still writable. Enqueue it back to the writable stream
727
- // list.
728
- // TODO(akshitpatel) : [PH2][P3] : Plug transport_tokens when
729
- // transport flow control is implemented.
730
- absl::Status status = self->writable_stream_list_.Enqueue(
731
- stream_id, WritableStreams::StreamPriority::kDefault);
732
-
733
- if (GPR_UNLIKELY(!status.ok())) {
734
- LOG(ERROR) << "Failed to enqueue stream " << stream_id
735
- << " with status: " << status;
736
- // Close transport if we fail to enqueue stream.
737
- return absl::InternalError("Failed to enqueue stream");
1271
+ frames.reserve(frames.size() + stream_frames.value().size());
1272
+ frames.insert(
1273
+ frames.end(),
1274
+ std::make_move_iterator(stream_frames.value().begin()),
1275
+ std::make_move_iterator(stream_frames.value().end()));
738
1276
  }
739
- } else if (GPR_UNLIKELY(!result.ok())) {
740
- // Close the corresponding stream if we fail to dequeue frames from
741
- // the stream queue.
742
- LOG(ERROR) << "Failed to dequeue frames for stream " << stream_id
743
- << " with status: " << result.status();
744
- absl::Status status =
745
- self->HandleError(Http2Status::AbslStreamError(
746
- absl::StatusCode::kInternal, "Failed to dequeue frames"));
747
- return std::vector<Http2Frame>();
748
1277
  }
1278
+
749
1279
  GRPC_HTTP2_CLIENT_DLOG
750
- << "Http2ClientTransport StreamMultiplexerLoop. Dequeued "
751
- << result->frames.size()
752
- << " frames for "
753
- "stream: "
754
- << stream_id;
755
- return std::move(result->frames);
1280
+ << "Http2ClientTransport MultiplexerLoop "
1281
+ "write_bytes_remaining_ after draining all writable streams = "
1282
+ << self->write_bytes_remaining_;
1283
+
1284
+ return std::move(frames);
756
1285
  },
757
1286
  [self](std::vector<Http2Frame> frames) {
758
- // Enqueue the frames to the MPSC queue.
759
- return Loop([self, frames = std::move(frames), idx = 0u]() mutable {
760
- return If(
761
- idx < frames.size(),
762
- [self, &frames, &idx]() {
763
- return Map(
764
- // Enqueue to the MPSC queue could return pending. This
765
- // induces backpressure for the sender. Only after writing
766
- // to the MPSC queue we will loop back to read more
767
- // streams.
768
- self->EnqueueOutgoingFrame(std::move(frames[idx++])),
769
- [](absl::Status status) -> LoopCtl<absl::Status> {
770
- if (GPR_UNLIKELY(!status.ok())) {
771
- return status;
772
- }
773
- return Continue{};
774
- });
775
- },
776
- []() -> LoopCtl<absl::Status> { return absl::OkStatus(); });
777
- });
1287
+ return self->SerializeAndWrite(std::move(frames));
778
1288
  },
779
- []() -> LoopCtl<absl::Status> { return Continue{}; });
780
- });
1289
+ [self]() -> LoopCtl<absl::Status> {
1290
+ if (self->should_reset_ping_clock_) {
1291
+ GRPC_HTTP2_CLIENT_DLOG
1292
+ << "Http2ClientTransport MultiplexerLoop ResetPingClock";
1293
+ self->ping_manager_->ResetPingClock(/*is_client=*/true);
1294
+ self->should_reset_ping_clock_ = false;
1295
+ }
1296
+ return Continue();
1297
+ });
1298
+ }));
781
1299
  }
782
1300
 
783
- auto Http2ClientTransport::OnStreamMultiplexerLoopEnded() {
784
- GRPC_HTTP2_CLIENT_DLOG
785
- << "Http2ClientTransport OnStreamMultiplexerLoopEnded Factory";
786
- return [self = RefAsSubclass<Http2ClientTransport>()](absl::Status status) {
1301
+ absl::Status Http2ClientTransport::InitializeStream(
1302
+ RefCountedPtr<Stream> stream) {
1303
+ absl::StatusOr<uint32_t> next_stream_id = NextStreamId();
1304
+ if (!next_stream_id.ok()) {
1305
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport InitializeStream "
1306
+ "Failed to get next stream id for stream: "
1307
+ << stream.get();
1308
+ return std::move(next_stream_id).status();
1309
+ }
1310
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport InitializeStream "
1311
+ "Assigned stream id: "
1312
+ << next_stream_id.value()
1313
+ << " to stream: " << stream.get()
1314
+ << ", allow_true_binary_metadata:"
1315
+ << settings_->peer().allow_true_binary_metadata();
1316
+ stream->InitializeStream(next_stream_id.value(),
1317
+ settings_->peer().allow_true_binary_metadata(),
1318
+ settings_->acked().allow_true_binary_metadata());
1319
+ return absl::OkStatus();
1320
+ }
1321
+
1322
+ void Http2ClientTransport::AddToStreamList(RefCountedPtr<Stream> stream) {
1323
+ bool should_wake_periodic_updates = false;
1324
+ {
1325
+ MutexLock lock(&transport_mutex_);
1326
+ GRPC_DCHECK(stream != nullptr) << "stream is null";
1327
+ GRPC_DCHECK_GT(stream->GetStreamId(), 0u) << "stream id is invalid";
787
1328
  GRPC_HTTP2_CLIENT_DLOG
788
- << "Http2ClientTransport OnStreamMultiplexerLoopEnded Promise Status="
789
- << status;
790
- GRPC_UNUSED absl::Status error =
791
- self->HandleError(Http2Status::AbslConnectionError(
792
- status.code(), std::string(status.message())));
1329
+ << "Http2ClientTransport AddToStreamList for stream id: "
1330
+ << stream->GetStreamId();
1331
+ stream_list_.emplace(stream->GetStreamId(), stream);
1332
+ // TODO(tjagtap) [PH2][P2][BDP] Remove this when the BDP code is done.
1333
+ if (GetActiveStreamCountLocked() == 1) {
1334
+ should_wake_periodic_updates = true;
1335
+ }
1336
+ }
1337
+ // TODO(tjagtap) [PH2][P2][BDP] Remove this when the BDP code is done.
1338
+ if (should_wake_periodic_updates) {
1339
+ // Release the lock before you wake up another promise on the party.
1340
+ WakeupPeriodicUpdatePromise();
1341
+ }
1342
+ }
1343
+
1344
+ ///////////////////////////////////////////////////////////////////////////////
1345
+ // Settings and Window Update Management
1346
+
1347
+ void Http2ClientTransport::EnforceLatestIncomingSettings() {
1348
+ encoder_.SetMaxTableSize(settings_->peer().header_table_size());
1349
+ }
1350
+
1351
+ auto Http2ClientTransport::WaitForSettingsTimeoutOnDone() {
1352
+ return [self = RefAsSubclass<Http2ClientTransport>()](absl::Status status) {
1353
+ if (!status.ok()) {
1354
+ GRPC_UNUSED absl::Status result = self->HandleError(
1355
+ std::nullopt, Http2Status::Http2ConnectionError(
1356
+ Http2ErrorCode::kProtocolError,
1357
+ std::string(RFC9113::kSettingsTimeout)));
1358
+ }
793
1359
  };
794
1360
  }
795
1361
 
1362
+ void Http2ClientTransport::MaybeSpawnWaitForSettingsTimeout() {
1363
+ if (settings_->ShouldSpawnWaitForSettingsTimeout()) {
1364
+ GRPC_HTTP2_CLIENT_DLOG
1365
+ << "Http2ClientTransport::MaybeSpawnWaitForSettingsTimeout Spawning";
1366
+ general_party_->Spawn("WaitForSettingsTimeout",
1367
+ settings_->WaitForSettingsTimeout(),
1368
+ WaitForSettingsTimeoutOnDone());
1369
+ }
1370
+ }
1371
+
1372
+ void Http2ClientTransport::MaybeGetWindowUpdateFrames(SliceBuffer& output_buf) {
1373
+ std::vector<Http2Frame> frames;
1374
+ frames.reserve(window_update_list_.size() + 1);
1375
+ uint32_t window_size =
1376
+ flow_control_.DesiredAnnounceSize(/*writing_anyway=*/true);
1377
+ if (window_size > 0) {
1378
+ GRPC_HTTP2_CLIENT_DLOG
1379
+ << "Http2ClientTransport::MaybeGetWindowUpdateFrames Transport Window "
1380
+ "Update : "
1381
+ << window_size;
1382
+ frames.emplace_back(Http2WindowUpdateFrame{/*stream_id=*/0, window_size});
1383
+ flow_control_.SentUpdate(window_size);
1384
+ }
1385
+ for (const uint32_t stream_id : window_update_list_) {
1386
+ RefCountedPtr<Stream> stream = LookupStream(stream_id);
1387
+ MaybeAddStreamWindowUpdateFrame(stream, frames);
1388
+ }
1389
+ window_update_list_.clear();
1390
+ if (!frames.empty()) {
1391
+ GRPC_HTTP2_CLIENT_DLOG
1392
+ << "Http2ClientTransport::MaybeGetWindowUpdateFrames Total Window "
1393
+ "Update Frames : "
1394
+ << frames.size();
1395
+ Serialize(absl::Span<Http2Frame>(frames), output_buf);
1396
+ }
1397
+ }
1398
+
796
1399
  ///////////////////////////////////////////////////////////////////////////////
797
1400
  // Constructor Destructor
798
1401
 
799
1402
  Http2ClientTransport::Http2ClientTransport(
800
1403
  PromiseEndpoint endpoint, GRPC_UNUSED const ChannelArgs& channel_args,
801
1404
  std::shared_ptr<EventEngine> event_engine,
802
- grpc_closure* on_receive_settings)
803
- : endpoint_(std::move(endpoint)),
804
- outgoing_frames_(kMpscSize),
805
- stream_id_mutex_(/*Initial Stream Id*/ 1),
806
- bytes_sent_in_last_write_(false),
807
- incoming_header_in_progress_(false),
808
- incoming_header_end_stream_(false),
1405
+ absl::AnyInvocable<void(absl::StatusOr<uint32_t>)> on_receive_settings)
1406
+ : channelz::DataSource(http2::CreateChannelzSocketNode(
1407
+ endpoint.GetEventEngineEndpoint(), channel_args)),
1408
+ event_engine_(std::move(event_engine)),
1409
+ endpoint_(std::move(endpoint)),
1410
+ settings_(MakeRefCounted<SettingsPromiseManager>(
1411
+ std::move(on_receive_settings))),
1412
+ next_stream_id_(/*Initial Stream ID*/ 1),
1413
+ should_reset_ping_clock_(false),
809
1414
  is_first_write_(true),
810
- incoming_header_stream_id_(0),
811
- on_receive_settings_(on_receive_settings),
812
- max_header_list_size_soft_limit_(
813
- GetSoftLimitFromChannelArgs(channel_args)),
814
- keepalive_time_(std::max(
815
- Duration::Seconds(10),
816
- channel_args.GetDurationFromIntMillis(GRPC_ARG_KEEPALIVE_TIME_MS)
817
- .value_or(Duration::Infinity()))),
818
- // Keepalive timeout is only passed to the keepalive manager if it is less
819
- // than the ping timeout. As keepalives use pings for health checks, if
820
- // keepalive timeout is greater than ping timeout, we would always hit the
821
- // ping timeout first.
822
- keepalive_timeout_(std::max(
823
- Duration::Zero(),
824
- channel_args.GetDurationFromIntMillis(GRPC_ARG_KEEPALIVE_TIMEOUT_MS)
825
- .value_or(keepalive_time_ == Duration::Infinity()
826
- ? Duration::Infinity()
827
- : (Duration::Seconds(20))))),
828
- ping_timeout_(std::max(
829
- Duration::Zero(),
830
- channel_args.GetDurationFromIntMillis(GRPC_ARG_PING_TIMEOUT_MS)
831
- .value_or(keepalive_time_ == Duration::Infinity()
832
- ? Duration::Infinity()
833
- : Duration::Minutes(1)))),
834
- ping_manager_(channel_args, PingSystemInterfaceImpl::Make(this),
835
- event_engine),
836
- keepalive_manager_(
837
- KeepAliveInterfaceImpl::Make(this),
838
- ((keepalive_timeout_ < ping_timeout_) ? keepalive_timeout_
839
- : Duration::Infinity()),
840
- keepalive_time_),
841
- keepalive_permit_without_calls_(false) {
1415
+ max_write_size_(kMaxWriteSize),
1416
+ ping_manager_(std::nullopt),
1417
+ keepalive_manager_(std::nullopt),
1418
+ goaway_manager_(GoawayInterfaceImpl::Make(this)),
1419
+ memory_owner_(channel_args.GetObject<ResourceQuota>()
1420
+ ->memory_quota()
1421
+ ->CreateMemoryOwner()),
1422
+ flow_control_(
1423
+ "PH2_Client",
1424
+ channel_args.GetBool(GRPC_ARG_HTTP2_BDP_PROBE).value_or(true),
1425
+ &memory_owner_),
1426
+ ztrace_collector_(std::make_shared<PromiseHttp2ZTraceCollector>()) {
842
1427
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Constructor Begin";
843
-
844
- InitLocalSettings(settings_.mutable_local(), /*is_client=*/true);
845
- ReadSettingsFromChannelArgs(channel_args, settings_.mutable_local(),
846
- /*is_client=*/true);
847
-
848
1428
  // Initialize the general party and write party.
849
- auto general_party_arena = SimpleArenaAllocator(0)->MakeArena();
850
- general_party_arena->SetContext<EventEngine>(event_engine.get());
851
- general_party_ = Party::Make(std::move(general_party_arena));
1429
+ RefCountedPtr<Arena> party_arena = SimpleArenaAllocator(0)->MakeArena();
1430
+ party_arena->SetContext<EventEngine>(event_engine_.get());
1431
+ general_party_ = Party::Make(std::move(party_arena));
852
1432
 
853
- general_party_->Spawn("ReadLoop", ReadLoop(), OnReadLoopEnded());
854
- // TODO(tjagtap) : [PH2][P2] Fix when needed.
855
- general_party_->Spawn("WriteLoop", WriteLoop(), OnWriteLoopEnded());
856
- general_party_->Spawn("StreamMultiplexerLoop", StreamMultiplexerLoop(),
857
- OnStreamMultiplexerLoopEnded());
1433
+ InitLocalSettings(settings_->mutable_local(), /*is_client=*/true);
1434
+ TransportChannelArgs args;
1435
+ ReadChannelArgs(channel_args, args);
858
1436
 
859
- // The keepalive loop is only spawned if the keepalive time is not infinity.
860
- keepalive_manager_.Spawn(general_party_.get());
861
-
862
- // TODO(tjagtap) : [PH2][P2] Delete this hack once flow control is done.
863
- // We are increasing the flow control window so that we can avoid sending
864
- // WINDOW_UPDATE frames while flow control is under development. Once it is
865
- // ready we should remove these lines.
866
- // <DeleteAfterFlowControl>
867
- Http2ErrorCode code = settings_.mutable_local().Apply(
868
- Http2Settings::kInitialWindowSizeWireId,
869
- (Http2Settings::max_initial_window_size() - 1));
870
- DCHECK(code == Http2ErrorCode::kNoError);
871
- // </DeleteAfterFlowControl>
872
-
873
- const int max_hpack_table_size =
874
- channel_args.GetInt(GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER).value_or(-1);
875
- if (max_hpack_table_size >= 0) {
876
- encoder_.SetMaxUsableSize(max_hpack_table_size);
877
- }
1437
+ ping_manager_.emplace(channel_args, args.ping_timeout,
1438
+ PingSystemInterfaceImpl::Make(this), event_engine_);
878
1439
 
879
- settings_timeout_ =
880
- channel_args.GetDurationFromIntMillis(GRPC_ARG_SETTINGS_TIMEOUT)
881
- .value_or(std::max(keepalive_timeout_ * 2, Duration::Minutes(1)));
1440
+ // The keepalive loop is only spawned if the keepalive time is not infinity.
1441
+ keepalive_manager_.emplace(
1442
+ KeepAliveInterfaceImpl::Make(this),
1443
+ ((args.keepalive_timeout < args.ping_timeout) ? args.keepalive_timeout
1444
+ : Duration::Infinity()),
1445
+ args.keepalive_time, general_party_.get());
882
1446
 
883
- std::optional<Http2SettingsFrame> settings_frame =
884
- settings_.MaybeSendUpdate();
885
- if (settings_frame.has_value()) {
886
- GRPC_HTTP2_CLIENT_DLOG
887
- << "Http2ClientTransport Constructor Spawn SendFirstSettingsFrame";
888
- general_party_->Spawn(
889
- "SendFirstSettingsFrame",
890
- [self = RefAsSubclass<Http2ClientTransport>(),
891
- frame = std::move(*settings_frame)]() mutable {
892
- return self->EnqueueOutgoingFrame(std::move(frame));
893
- },
894
- [](GRPC_UNUSED absl::Status status) {});
895
- }
896
- if (settings_.local().allow_security_frame()) {
1447
+ if (settings_->local().allow_security_frame()) {
897
1448
  // TODO(tjagtap) : [PH2][P3] : Setup the plumbing to pass the security frame
898
1449
  // to the endpoing via TransportFramingEndpointExtension.
899
1450
  // Also decide if this plumbing is done here, or when the peer sends
900
1451
  // allow_security_frame too.
901
1452
  }
1453
+
1454
+ GRPC_DCHECK(ping_manager_.has_value());
1455
+ GRPC_DCHECK(keepalive_manager_.has_value());
1456
+ SourceConstructed();
902
1457
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Constructor End";
903
1458
  }
904
1459
 
905
- // This function MUST be idempotent.
906
- void Http2ClientTransport::CloseStream(uint32_t stream_id, absl::Status status,
1460
+ void Http2ClientTransport::SpawnTransportLoops() {
1461
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::SpawnTransportLoops Begin";
1462
+ SpawnGuardedTransportParty(
1463
+ "FlowControlPeriodicUpdateLoop",
1464
+ UntilTransportClosed(FlowControlPeriodicUpdateLoop()));
1465
+
1466
+ SpawnGuardedTransportParty("FlushInitialFrames", TriggerWriteCycle());
1467
+ SpawnGuardedTransportParty("MultiplexerLoop",
1468
+ UntilTransportClosed(MultiplexerLoop()));
1469
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::SpawnTransportLoops End";
1470
+ }
1471
+
1472
+ void Http2ClientTransport::ReadChannelArgs(const ChannelArgs& channel_args,
1473
+ TransportChannelArgs& args) {
1474
+ http2::ReadChannelArgs(channel_args, args, settings_->mutable_local(),
1475
+ flow_control_,
1476
+ /*is_client=*/true);
1477
+
1478
+ // Assign the channel args to the member variables.
1479
+ keepalive_time_ = args.keepalive_time;
1480
+ incoming_headers_.set_soft_limit(args.max_header_list_size_soft_limit);
1481
+ keepalive_permit_without_calls_ = args.keepalive_permit_without_calls;
1482
+ enable_preferred_rx_crypto_frame_advertisement_ =
1483
+ args.enable_preferred_rx_crypto_frame_advertisement;
1484
+ test_only_ack_pings_ = args.test_only_ack_pings;
1485
+
1486
+ if (args.initial_sequence_number > 0) {
1487
+ next_stream_id_ = args.initial_sequence_number;
1488
+ }
1489
+
1490
+ settings_->SetSettingsTimeout(args.settings_timeout);
1491
+ if (args.max_usable_hpack_table_size >= 0) {
1492
+ encoder_.SetMaxUsableSize(args.max_usable_hpack_table_size);
1493
+ }
1494
+ }
1495
+
1496
+ // This function MUST be idempotent. This function MUST be called from the
1497
+ // transport party.
1498
+ void Http2ClientTransport::CloseStream(RefCountedPtr<Stream> stream,
907
1499
  CloseStreamArgs args,
908
1500
  DebugLocation whence) {
909
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::CloseStream for stream id: "
910
- << stream_id << " status=" << status
911
- << " location=" << whence.file() << ":"
912
- << whence.line();
1501
+ std::optional<Http2Status> close_transport_error;
913
1502
 
914
- // TODO(akshitpatel) : [PH2][P3] : Measure the impact of holding mutex
915
- // throughout this function.
916
- MutexLock lock(&transport_mutex_);
917
- auto pair = stream_list_.find(stream_id);
918
- if (pair == stream_list_.end()) {
1503
+ {
1504
+ // TODO(akshitpatel) : [PH2][P3] : Measure the impact of holding mutex
1505
+ // throughout this function.
1506
+ MutexLock lock(&transport_mutex_);
1507
+ GRPC_DCHECK(stream != nullptr) << "stream is null";
919
1508
  GRPC_HTTP2_CLIENT_DLOG
920
- << "Http2ClientTransport::CloseStream for stream id: " << stream_id
921
- << " stream not found";
922
- return;
1509
+ << "Http2ClientTransport::CloseStream for stream id: "
1510
+ << stream->GetStreamId() << " close_reads=" << args.close_reads
1511
+ << " close_writes=" << args.close_writes
1512
+ << " incoming_headers_=" << incoming_headers_.DebugString()
1513
+ << " location=" << whence.file() << ":" << whence.line();
1514
+
1515
+ if (args.close_writes) {
1516
+ stream->SetWriteClosed();
1517
+ }
1518
+
1519
+ if (args.close_reads) {
1520
+ GRPC_HTTP2_CLIENT_DLOG
1521
+ << "Http2ClientTransport::CloseStream for stream id: "
1522
+ << stream->GetStreamId() << " closing stream for reads.";
1523
+ // If the stream is closed while reading HEADER/CONTINUATION frames, we
1524
+ // should still parse the enqueued buffer to maintain HPACK state between
1525
+ // peers.
1526
+ if (incoming_headers_.IsWaitingForContinuationFrame()) {
1527
+ Http2Status result = http2::ParseAndDiscardHeaders(
1528
+ parser_, SliceBuffer(),
1529
+ HeaderAssembler::ParseHeaderArgs{
1530
+ /*is_initial_metadata=*/!incoming_headers_.HeaderHasEndStream(),
1531
+ /*is_end_headers=*/false,
1532
+ /*is_client=*/true,
1533
+ /*max_header_list_size_soft_limit=*/
1534
+ incoming_headers_.soft_limit(),
1535
+ /*max_header_list_size_hard_limit=*/
1536
+ settings_->acked().max_header_list_size(),
1537
+ /*stream_id=*/incoming_headers_.GetStreamId(),
1538
+ },
1539
+ stream, /*original_status=*/Http2Status::Ok());
1540
+ if (result.GetType() == Http2Status::Http2ErrorType::kConnectionError) {
1541
+ GRPC_HTTP2_CLIENT_DLOG
1542
+ << "Http2ClientTransport::CloseStream for stream id: "
1543
+ << stream->GetStreamId()
1544
+ << " failed to partially process header: "
1545
+ << result.DebugString();
1546
+ close_transport_error.emplace(std::move(result));
1547
+ }
1548
+ }
1549
+
1550
+ stream_list_.erase(stream->GetStreamId());
1551
+ if (!close_transport_error.has_value() && CanCloseTransportLocked()) {
1552
+ // TODO(akshitpatel) : [PH2][P3] : Is kInternalError the right error
1553
+ // code to use here? IMO it should be kNoError.
1554
+ close_transport_error.emplace(Http2Status::Http2ConnectionError(
1555
+ Http2ErrorCode::kInternalError,
1556
+ std::string(RFC9113::kLastStreamClosed)));
1557
+ }
1558
+ }
923
1559
  }
924
- auto& stream = pair->second;
925
1560
 
926
- if (args.close_reads) {
927
- stream->MarkHalfClosedRemote();
1561
+ if (close_transport_error.has_value()) {
1562
+ GRPC_UNUSED absl::Status status = HandleError(
1563
+ /*stream_id=*/std::nullopt, std::move(*close_transport_error));
928
1564
  }
929
- if (args.close_writes) {
930
- stream->MarkHalfClosedLocal();
1565
+ }
1566
+
1567
+ // This function is idempotent and MUST be called from the transport party.
1568
+ // All the scenarios that can lead to this function being called are:
1569
+ // 1. Reading a RST stream frame: In this case, the stream is immediately
1570
+ // closed for reads and writes and removed from the stream_list_.
1571
+ // 2. Reading a Trailing Metadata frame: There are two possible scenarios:
1572
+ // a. The stream is closed for writes: Close the stream for reads and writes
1573
+ // and remove the stream from the stream_list_.
1574
+ // b. The stream is NOT closed for writes: Stream is kept open for reads and
1575
+ // writes. CallHandler OnDone will trigger sending a half close frame. If
1576
+ // before the multiplexer loop triggers sending a half close a RST stream
1577
+ // is read, the stream is closed for reads and writes immediately and the
1578
+ // half close is discarded. If no RST stream is read, the stream is closed
1579
+ // for reads and writes upon sending the half close frame from the
1580
+ // multiplexer loop.
1581
+ // 3. Hitting error condition in the transport: In this case, RST stream is
1582
+ // enqueued and the stream is closed for reads immediately. This implies we
1583
+ // reduce the number of active streams inline. When multiplexer loop
1584
+ // processes the RST stream frame, the stream ref will dropped. The other
1585
+ // stream ref will be dropped when CallHandler's OnDone is executed causing
1586
+ // the stream to be destroyed. CallHandlers OnDone also tries to enqueue a
1587
+ // RST stream frame. This is a no-op at this point.
1588
+ // 4. Application abort: In this case, CallHandler OnDone will enqueue RST
1589
+ // stream frame to the stream data queue. The multiplexer loop will send the
1590
+ // reset stream frame and close the stream from reads and writes.
1591
+ // 5. Transport close: This takes up the same path as case 3.
1592
+ // In all the above cases, trailing metadata is pushed to the call spine.
1593
+ // Note: The stream ref is held in atmost 3 places:
1594
+ // 1. stream_list_ : This is released when the stream is closed for reads.
1595
+ // 2. CallHandler OnDone : This is released when Trailing Metadata is pushed to
1596
+ // the call spine.
1597
+ // 3. List of writable streams : This is released after the final frame is
1598
+ // dequeued from the StreamDataQueue.
1599
+ void Http2ClientTransport::BeginCloseStream(
1600
+ RefCountedPtr<Stream> stream,
1601
+ std::optional<uint32_t> reset_stream_error_code,
1602
+ ServerMetadataHandle&& metadata, DebugLocation whence) {
1603
+ if (stream == nullptr) {
1604
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::BeginCloseStream stream "
1605
+ "is null reset_stream_error_code="
1606
+ << (reset_stream_error_code.has_value()
1607
+ ? absl::StrCat(*reset_stream_error_code)
1608
+ : "nullopt")
1609
+ << " metadata=" << metadata->DebugString();
1610
+ return;
931
1611
  }
932
1612
 
933
- if (stream->IsClosed()) {
934
- GRPC_HTTP2_CLIENT_DLOG
935
- << "Http2ClientTransport::CloseStream for stream id: " << stream_id
936
- << " closing stream.";
937
- if (args.send_rst_stream) {
938
- // TODO(akshitpatel) : [PH2][P2] : Send RST_STREAM frame.
1613
+ GRPC_HTTP2_CLIENT_DLOG
1614
+ << "Http2ClientTransport::BeginCloseStream for stream id: "
1615
+ << stream->GetStreamId() << " error_code="
1616
+ << (reset_stream_error_code.has_value()
1617
+ ? absl::StrCat(*reset_stream_error_code)
1618
+ : "nullopt")
1619
+ << " ServerMetadata=" << metadata->DebugString()
1620
+ << " location=" << whence.file() << ":" << whence.line();
1621
+
1622
+ bool close_reads = false;
1623
+ bool close_writes = false;
1624
+ if (metadata->get(GrpcCallWasCancelled())) {
1625
+ if (!reset_stream_error_code) {
1626
+ // Callers taking this path:
1627
+ // 1. Reading a RST stream frame (will not send any frame out).
1628
+ // 2. Closing a stream before initial metadata is sent.
1629
+ close_reads = true;
1630
+ close_writes = true;
1631
+ GRPC_HTTP2_CLIENT_DLOG
1632
+ << "Http2ClientTransport::BeginCloseStream for stream id: "
1633
+ << stream->GetStreamId() << " close_reads= " << close_reads
1634
+ << " close_writes= " << close_writes;
1635
+ } else {
1636
+ // Callers taking this path:
1637
+ // 1. Processing Error in transport (will send reset stream from here).
1638
+ absl::StatusOr<StreamWritabilityUpdate> enqueue_result =
1639
+ stream->EnqueueResetStream(reset_stream_error_code.value());
1640
+ GRPC_HTTP2_CLIENT_DLOG << "Enqueued ResetStream with error code="
1641
+ << reset_stream_error_code.value()
1642
+ << " status=" << enqueue_result.status();
1643
+ if (enqueue_result.ok()) {
1644
+ GRPC_UNUSED absl::Status status =
1645
+ MaybeAddStreamToWritableStreamList(stream, enqueue_result.value());
1646
+ }
1647
+ close_reads = true;
1648
+ GRPC_HTTP2_CLIENT_DLOG
1649
+ << "Http2ClientTransport::BeginCloseStream for stream id: "
1650
+ << stream->GetStreamId() << " close_reads= " << close_reads
1651
+ << " close_writes= " << close_writes;
939
1652
  }
940
-
941
- if (args.push_trailing_metadata) {
942
- stream->call.SpawnPushServerTrailingMetadata(
943
- ServerMetadataFromStatus(status));
1653
+ } else {
1654
+ // Callers taking this path:
1655
+ // 1. Reading Trailing Metadata (MAY send half close from OnDone).
1656
+ if (stream->IsClosedForWrites()) {
1657
+ close_reads = true;
1658
+ close_writes = true;
1659
+ GRPC_HTTP2_CLIENT_DLOG
1660
+ << "Http2ClientTransport::BeginCloseStream for stream id: "
1661
+ << stream->GetStreamId() << " close_reads= " << close_reads
1662
+ << " close_writes= " << close_writes;
944
1663
  }
945
- stream_list_.erase(stream_id);
946
1664
  }
1665
+
1666
+ if (close_reads || close_writes) {
1667
+ CloseStream(stream, CloseStreamArgs{close_reads, close_writes}, whence);
1668
+ }
1669
+
1670
+ // If the call was cancelled, the stream MUST be closed for reads.
1671
+ GRPC_DCHECK(metadata->get(GrpcCallWasCancelled()) ? close_reads : true);
1672
+
1673
+ // This maybe called multiple times while closing a stream. In CallV3, the
1674
+ // flow for pushing server trailing metadata is idempotent. However, there is
1675
+ // a subtle difference. When we push server trailing metadata with a cancelled
1676
+ // status PushServerTrailingMetadata is spawned inline on the Call party
1677
+ // whereas for the non-cancelled status, PushServerTrailingMetadata is
1678
+ // spawned in the server_to_client spawn serializer. Because of this, in
1679
+ // case when the server pushes trailing metadata (non-cancelled) followed by a
1680
+ // RST stream with cancelled status, it is possible that the cancelled
1681
+ // trailing metadata (for RST stream) is processed before. This would result
1682
+ // in losing the actual status/message pushed by the server.
1683
+ // To address this, we push the server trailing metadata to the stream only
1684
+ // if it is not pushed already.
1685
+ stream->MaybePushServerTrailingMetadata(std::move(metadata));
947
1686
  }
948
1687
 
949
1688
  void Http2ClientTransport::CloseTransport() {
950
1689
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::CloseTransport";
951
1690
 
952
- // This is the only place where the general_party_ is
953
- // reset.
1691
+ transport_closed_latch_.Set();
1692
+ settings_->HandleTransportShutdown(event_engine_.get());
1693
+
1694
+ MutexLock lock(&transport_mutex_);
1695
+ // This is the only place where the general_party_ is reset.
954
1696
  general_party_.reset();
955
1697
  }
956
1698
 
@@ -976,16 +1718,15 @@ void Http2ClientTransport::MaybeSpawnCloseTransport(Http2Status http2_status,
976
1718
  absl::flat_hash_map<uint32_t, RefCountedPtr<Stream>> stream_list =
977
1719
  std::move(stream_list_);
978
1720
  stream_list_.clear();
979
- state_tracker_.SetState(GRPC_CHANNEL_SHUTDOWN,
980
- http2_status.GetAbslConnectionError(),
981
- "transport closed");
1721
+ ReportDisconnectionLocked(
1722
+ http2_status.GetAbslConnectionError(), {},
1723
+ absl::StrCat("Transport closed: ", http2_status.DebugString()).c_str());
982
1724
  lock.Release();
983
1725
 
984
- general_party_->Spawn(
985
- "CloseTransport",
986
- [self = RefAsSubclass<Http2ClientTransport>(),
987
- stream_list = std::move(stream_list),
988
- http2_status = std::move(http2_status)]() mutable {
1726
+ SpawnInfallibleTransportParty(
1727
+ "CloseTransport", [self = RefAsSubclass<Http2ClientTransport>(),
1728
+ stream_list = std::move(stream_list),
1729
+ http2_status = std::move(http2_status)]() mutable {
989
1730
  GRPC_HTTP2_CLIENT_DLOG
990
1731
  << "Http2ClientTransport::CloseTransport Cleaning up call stacks";
991
1732
  // Clean up the call stacks for all active streams.
@@ -995,37 +1736,132 @@ void Http2ClientTransport::MaybeSpawnCloseTransport(Http2Status http2_status,
995
1736
  // fail. Also, as this is running on the transport
996
1737
  // party, there would not be concurrent access to the stream.
997
1738
  auto& stream = pair.second;
998
- stream->call.SpawnPushServerTrailingMetadata(
999
- ServerMetadataFromStatus(http2_status.GetAbslConnectionError()));
1739
+ self->BeginCloseStream(stream,
1740
+ Http2ErrorCodeToFrameErrorCode(
1741
+ http2_status.GetConnectionErrorCode()),
1742
+ CancelledServerMetadataFromStatus(
1743
+ http2_status.GetAbslConnectionError()));
1000
1744
  }
1001
1745
 
1002
1746
  // RFC9113 : A GOAWAY frame might not immediately precede closing of
1003
1747
  // the connection; a receiver of a GOAWAY that has no more use for the
1004
1748
  // connection SHOULD still send a GOAWAY frame before terminating the
1005
1749
  // connection.
1006
- // TODO(akshitpatel) : [PH2][P2] : There would a timer for sending
1007
- // goaway here. Once goaway is sent or timer is expired, close the
1008
- // transport.
1009
- return Map(Immediate(absl::OkStatus()),
1010
- [self](GRPC_UNUSED absl::Status) mutable {
1011
- self->CloseTransport();
1012
- return Empty{};
1013
- });
1014
- },
1015
- [](Empty) {});
1750
+ return Map(
1751
+ // TODO(akshitpatel) : [PH2][P4] : This is creating a copy of
1752
+ // the debug data. Verify if this is causing a performance
1753
+ // issue.
1754
+ Race(AssertResultType<absl::Status>(
1755
+ self->goaway_manager_.RequestGoaway(
1756
+ http2_status.GetConnectionErrorCode(),
1757
+ /*debug_data=*/
1758
+ Slice::FromCopiedString(
1759
+ http2_status.GetAbslConnectionError().message()),
1760
+ kLastIncomingStreamIdClient, /*immediate=*/true)),
1761
+ // Failsafe to close the transport if goaway is not
1762
+ // sent within kGoawaySendTimeoutSeconds seconds.
1763
+ Sleep(Duration::Seconds(kGoawaySendTimeoutSeconds))),
1764
+ [self](auto) mutable {
1765
+ self->CloseTransport();
1766
+ return Empty{};
1767
+ });
1768
+ ;
1769
+ });
1770
+ }
1771
+
1772
+ bool Http2ClientTransport::CanCloseTransportLocked() const {
1773
+ // If there are no more streams and next stream id is greater than the
1774
+ // max allowed stream id, then no more streams can be created and it is
1775
+ // safe to close the transport.
1776
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::CanCloseTransportLocked "
1777
+ "GetActiveStreamCountLocked="
1778
+ << GetActiveStreamCountLocked()
1779
+ << " PeekNextStreamId=" << PeekNextStreamId()
1780
+ << " GetMaxAllowedStreamId="
1781
+ << GetMaxAllowedStreamId();
1782
+ return GetActiveStreamCountLocked() == 0 &&
1783
+ PeekNextStreamId() > GetMaxAllowedStreamId();
1016
1784
  }
1017
1785
 
1018
1786
  Http2ClientTransport::~Http2ClientTransport() {
1019
1787
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Destructor Begin";
1020
- DCHECK(stream_list_.empty());
1788
+ GRPC_DCHECK(stream_list_.empty());
1789
+ GRPC_DCHECK(general_party_ == nullptr);
1790
+ memory_owner_.Reset();
1021
1791
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Destructor End";
1022
1792
  }
1023
1793
 
1794
+ void Http2ClientTransport::SpawnAddChannelzData(RefCountedPtr<Party> party,
1795
+ channelz::DataSink sink) {
1796
+ SpawnInfallible(
1797
+ std::move(party), "AddData",
1798
+ [self = RefAsSubclass<Http2ClientTransport>(),
1799
+ sink = std::move(sink)]() mutable {
1800
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::AddData Promise";
1801
+ sink.AddData(
1802
+ "Http2ClientTransport",
1803
+ channelz::PropertyList()
1804
+ .Set("keepalive_time", self->keepalive_time_)
1805
+ .Set("keepalive_permit_without_calls",
1806
+ self->keepalive_permit_without_calls_)
1807
+ .Set("settings", self->settings_->ChannelzProperties())
1808
+ .Set("flow_control",
1809
+ self->flow_control_.stats().ChannelzProperties()));
1810
+ self->general_party_->ExportToChannelz("Http2ClientTransport Party",
1811
+ sink);
1812
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::AddData End";
1813
+ return Empty{};
1814
+ });
1815
+ }
1816
+
1817
+ void Http2ClientTransport::AddData(channelz::DataSink sink) {
1818
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::AddData Begin";
1819
+
1820
+ event_engine_->Run([self = RefAsSubclass<Http2ClientTransport>(),
1821
+ sink = std::move(sink)]() mutable {
1822
+ bool is_party_null = false;
1823
+ {
1824
+ // Apart from CloseTransport, this is the only place where a lock is taken
1825
+ // to access general_party_. All other access to general_party_ happens
1826
+ // on the general party itself and hence do not race with CloseTransport.
1827
+ // TODO(akshitpatel) : [PH2][P4] : Check if a new mutex is needed to
1828
+ // protect general_party_. Curently transport_mutex_ can is used in
1829
+ // these places:
1830
+ // 1. In promises running on the transport party
1831
+ // 2. In AddData promise
1832
+ // 3. In Orphan function.
1833
+ // 4. Stream creation (this will be removed soon).
1834
+ // Given that #1 is already serialized (guaranteed by party), #2 is on
1835
+ // demand and #3 happens once for the lifetime of the transport while
1836
+ // closing the transport, the contention should be minimal.
1837
+ MutexLock lock(&self->transport_mutex_);
1838
+ // TODO(akshitpatel) : [PH2][P2] : There is still a potential for a race
1839
+ // here where the general_party_ is reset between the lock being
1840
+ // released and the spawn. We cannot just do a spawn inside the mutex as
1841
+ // that may result in deadlock.
1842
+ // Potential fix to hold a ref to the party inside the mutex and do a
1843
+ // spawn outside the mutex. The only side effect is that this introduces
1844
+ // an additional ref to the party other the transport's copy.
1845
+ if (GPR_UNLIKELY(self->general_party_ == nullptr)) {
1846
+ is_party_null = true;
1847
+ GRPC_HTTP2_CLIENT_DLOG
1848
+ << "Http2ClientTransport::AddData general_party_ is "
1849
+ "null. Transport is closed.";
1850
+ }
1851
+ }
1852
+
1853
+ ExecCtx exec_ctx;
1854
+ if (!is_party_null) {
1855
+ self->SpawnAddChannelzData(self->general_party_, std::move(sink));
1856
+ }
1857
+ self.reset(); // Cleanup with exec_ctx in scope
1858
+ });
1859
+ }
1860
+
1024
1861
  ///////////////////////////////////////////////////////////////////////////////
1025
1862
  // Stream Related Operations
1026
1863
 
1027
- RefCountedPtr<Http2ClientTransport::Stream> Http2ClientTransport::LookupStream(
1028
- uint32_t stream_id) {
1864
+ RefCountedPtr<Stream> Http2ClientTransport::LookupStream(uint32_t stream_id) {
1029
1865
  MutexLock lock(&transport_mutex_);
1030
1866
  auto it = stream_list_.find(stream_id);
1031
1867
  if (it == stream_list_.end()) {
@@ -1037,134 +1873,146 @@ RefCountedPtr<Http2ClientTransport::Stream> Http2ClientTransport::LookupStream(
1037
1873
  return it->second;
1038
1874
  }
1039
1875
 
1040
- bool Http2ClientTransport::MakeStream(CallHandler call_handler,
1041
- const uint32_t stream_id) {
1042
- // https://datatracker.ietf.org/doc/html/rfc9113#name-stream-identifiers
1043
- // TODO(tjagtap) : [PH2][P2] Validate implementation.
1044
-
1045
- // TODO(akshitpatel) : [PH2][P1] : Probably do not need this lock. This
1046
- // function is always called under the stream_id_mutex_. The issue is the
1047
- // OnDone needs to be synchronous and hence InterActivityMutex might not be
1048
- // an option to protect the stream_list_.
1049
- MutexLock lock(&transport_mutex_);
1050
- const bool on_done_added =
1051
- call_handler.OnDone([self = RefAsSubclass<Http2ClientTransport>(),
1052
- stream_id](bool cancelled) {
1876
+ bool Http2ClientTransport::SetOnDone(CallHandler call_handler,
1877
+ RefCountedPtr<Stream> stream) {
1878
+ return call_handler.OnDone(
1879
+ [self = RefAsSubclass<Http2ClientTransport>(), stream,
1880
+ stream_id = stream->GetStreamId()](bool cancelled) {
1053
1881
  GRPC_HTTP2_CLIENT_DLOG << "PH2: Client call " << self.get()
1054
1882
  << " id=" << stream_id
1055
1883
  << " done: cancelled=" << cancelled;
1884
+ absl::StatusOr<StreamWritabilityUpdate> enqueue_result;
1885
+ GRPC_HTTP2_CLIENT_DLOG
1886
+ << "PH2: Client call " << self.get() << " id=" << stream_id
1887
+ << " done: stream=" << stream.get() << " cancelled=" << cancelled;
1056
1888
  if (cancelled) {
1057
- // TODO(akshitpatel) : [PH2][P2] : There are two ways to handle
1058
- // cancellation.
1059
- // 1. Call CloseStream from the on_done callback as done here. This
1060
- // will be invoked when PullServerTrailingMetadata resolves.
1061
- // 2. Call CloseStream from the OutboundLoop. When the call is
1062
- // cancelled, for_each() should return with an error. The
1063
- // WasCancelled() function can be used to determinie if the call
1064
- // was cancelled.
1065
- // At this point, both the above mentioned approaches seem to be more
1066
- // or less the same as both are running on the call party.
1067
- self->CloseStream(stream_id, absl::CancelledError(),
1068
- CloseStreamArgs{
1069
- /*close_reads=*/true,
1070
- /*close_writes=*/true,
1071
- /*send_rst_stream=*/true,
1072
- /*push_trailing_metadata=*/false,
1073
- });
1889
+ // In most of the cases, EnqueueResetStream would be a no-op as
1890
+ // BeginCloseStream would have already enqueued the reset stream.
1891
+ // Currently only Aborts from application will actually enqueue
1892
+ // the reset stream here.
1893
+ enqueue_result = stream->EnqueueResetStream(
1894
+ static_cast<uint32_t>(Http2ErrorCode::kCancel));
1895
+ GRPC_HTTP2_CLIENT_DLOG
1896
+ << "Enqueued ResetStream with error code="
1897
+ << static_cast<uint32_t>(Http2ErrorCode::kCancel)
1898
+ << " status=" << enqueue_result.status();
1899
+ } else {
1900
+ enqueue_result = stream->EnqueueHalfClosed();
1901
+ GRPC_HTTP2_CLIENT_DLOG << "Enqueued HalfClosed with result="
1902
+ << enqueue_result.status();
1903
+ }
1904
+
1905
+ if (enqueue_result.ok()) {
1906
+ GRPC_HTTP2_CLIENT_DLOG
1907
+ << "Http2ClientTransport::SetOnDone "
1908
+ "MaybeAddStreamToWritableStreamList for stream= "
1909
+ << stream->GetStreamId() << " enqueue_result={became_writable="
1910
+ << enqueue_result.value().became_writable << ", priority="
1911
+ << static_cast<uint8_t>(enqueue_result.value().priority) << "}";
1912
+ GRPC_UNUSED absl::Status status =
1913
+ self->MaybeAddStreamToWritableStreamList(stream,
1914
+ enqueue_result.value());
1074
1915
  }
1075
1916
  });
1076
- if (!on_done_added) return false;
1077
- stream_list_.emplace(
1078
- stream_id, MakeRefCounted<Stream>(std::move(call_handler), stream_id));
1079
- return true;
1917
+ }
1918
+
1919
+ std::optional<RefCountedPtr<Stream>> Http2ClientTransport::MakeStream(
1920
+ CallHandler call_handler) {
1921
+ // https://datatracker.ietf.org/doc/html/rfc9113#name-stream-identifiers
1922
+ RefCountedPtr<Stream> stream;
1923
+ {
1924
+ // TODO(akshitpatel) : [PH2][P3] : Remove this mutex once settings is in
1925
+ // place.
1926
+ MutexLock lock(&transport_mutex_);
1927
+ stream = MakeRefCounted<Stream>(call_handler, flow_control_);
1928
+ }
1929
+ const bool on_done_added = SetOnDone(call_handler, stream);
1930
+ if (!on_done_added) return std::nullopt;
1931
+ return stream;
1932
+ }
1933
+
1934
+ uint32_t Http2ClientTransport::GetMaxAllowedStreamId() const {
1935
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport GetMaxAllowedStreamId "
1936
+ << max_allowed_stream_id_;
1937
+ return max_allowed_stream_id_;
1938
+ }
1939
+
1940
+ void Http2ClientTransport::SetMaxAllowedStreamId(
1941
+ const uint32_t max_allowed_stream_id) {
1942
+ const uint32_t old_max_allowed_stream_id = GetMaxAllowedStreamId();
1943
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport SetMaxAllowedStreamId "
1944
+ << " max_allowed_stream_id: " << max_allowed_stream_id
1945
+ << " old_allowed_max_stream_id: "
1946
+ << old_max_allowed_stream_id;
1947
+ // RFC9113 : Endpoints MUST NOT increase the value they send in the last
1948
+ // stream identifier, since the peers might already have retried unprocessed
1949
+ // requests on another connection.
1950
+ if (GPR_LIKELY(max_allowed_stream_id <= old_max_allowed_stream_id)) {
1951
+ max_allowed_stream_id_ = max_allowed_stream_id;
1952
+ } else {
1953
+ LOG_IF(ERROR, max_allowed_stream_id > old_max_allowed_stream_id)
1954
+ << "Endpoints MUST NOT increase the value they send in the last "
1955
+ "stream "
1956
+ "identifier";
1957
+ GRPC_DCHECK_LE(max_allowed_stream_id, old_max_allowed_stream_id)
1958
+ << "Endpoints MUST NOT increase the value they send in the last "
1959
+ "stream "
1960
+ "identifier";
1961
+ }
1080
1962
  }
1081
1963
 
1082
1964
  ///////////////////////////////////////////////////////////////////////////////
1083
1965
  // Call Spine related operations
1084
1966
 
1085
- auto Http2ClientTransport::CallOutboundLoop(
1086
- CallHandler call_handler, const uint32_t stream_id,
1087
- InterActivityMutex<uint32_t>::Lock lock /* Locked stream_id_mutex */,
1088
- ClientMetadataHandle metadata) {
1967
+ auto Http2ClientTransport::CallOutboundLoop(CallHandler call_handler,
1968
+ RefCountedPtr<Stream> stream,
1969
+ ClientMetadataHandle metadata) {
1089
1970
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport CallOutboundLoop";
1971
+ GRPC_DCHECK(stream != nullptr);
1090
1972
 
1091
1973
  auto send_message = [self = RefAsSubclass<Http2ClientTransport>(),
1092
- stream_id](MessageHandle&& message) mutable {
1093
- RefCountedPtr<Stream> stream = self->LookupStream(stream_id);
1094
- return If(
1095
- stream != nullptr,
1096
- [self, stream, message = std::move(message), stream_id]() mutable {
1097
- return TrySeq(stream->EnqueueMessage(std::move(message)),
1098
- [self, stream_id](bool became_writable) {
1099
- GRPC_HTTP2_CLIENT_DLOG
1100
- << "Http2ClientTransport CallOutboundLoop "
1101
- "Enqueued Message";
1102
- return self->MaybeAddStreamToWritableStreamList(
1103
- stream_id, became_writable);
1104
- });
1105
- },
1106
- []() {
1107
- // This will trigger Call stack cleanup.
1108
- return absl::InternalError("Stream not found while sending message");
1109
- });
1974
+ stream](MessageHandle&& message) mutable {
1975
+ return TrySeq(stream->EnqueueMessage(std::move(message)),
1976
+ [self, stream](const StreamWritabilityUpdate result) mutable {
1977
+ GRPC_HTTP2_CLIENT_DLOG
1978
+ << "Http2ClientTransport CallOutboundLoop "
1979
+ "Enqueued Message";
1980
+ return self->MaybeAddStreamToWritableStreamList(
1981
+ std::move(stream), result);
1982
+ });
1110
1983
  };
1111
1984
 
1112
1985
  auto send_initial_metadata = [self = RefAsSubclass<Http2ClientTransport>(),
1113
- stream_id,
1986
+ stream,
1114
1987
  metadata = std::move(metadata)]() mutable {
1115
- RefCountedPtr<Stream> stream = self->LookupStream(stream_id);
1116
- return If(
1117
- stream != nullptr,
1118
- [self, stream, metadata = std::move(metadata), stream_id]() mutable {
1119
- return TrySeq(
1120
- stream->EnqueueInitialMetadata(std::move(metadata)),
1121
- [self, stream_id](bool became_writable) {
1122
- GRPC_HTTP2_CLIENT_DLOG
1123
- << "Http2ClientTransport CallOutboundLoop "
1124
- "Enqueued Initial Metadata";
1125
- return self->MaybeAddStreamToWritableStreamList(
1126
- stream_id, became_writable);
1127
- },
1128
- [stream] {
1129
- // TODO(akshitpatel) : [PH2][P2] : Think how to handle stream
1130
- // states.
1131
- stream->SentInitialMetadata();
1132
- return absl::OkStatus();
1133
- });
1988
+ return TrySeq(
1989
+ [stream, metadata = std::move(metadata)]() mutable {
1990
+ return stream->EnqueueInitialMetadata(std::move(metadata));
1134
1991
  },
1135
- []() {
1136
- // This will trigger Call stack cleanup.
1137
- return absl::InternalError(
1138
- "Stream not found while sending initial metadata");
1992
+ [self, stream](const StreamWritabilityUpdate result) mutable {
1993
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport CallOutboundLoop "
1994
+ "Enqueued Initial Metadata";
1995
+ return self->MaybeAddStreamToWritableStreamList(std::move(stream),
1996
+ result);
1139
1997
  });
1140
1998
  };
1141
1999
 
1142
2000
  auto send_half_closed = [self = RefAsSubclass<Http2ClientTransport>(),
1143
- stream_id]() mutable {
1144
- RefCountedPtr<Stream> stream = self->LookupStream(stream_id);
1145
- return If(
1146
- stream != nullptr,
1147
- [self, stream, stream_id]() mutable {
1148
- return TrySeq(stream->EnqueueHalfClosed(),
1149
- [self, stream_id](bool became_writable) {
1150
- GRPC_HTTP2_CLIENT_DLOG
1151
- << "Http2ClientTransport CallOutboundLoop "
1152
- "Enqueued Half Closed";
1153
- return self->MaybeAddStreamToWritableStreamList(
1154
- stream_id, became_writable);
1155
- });
1156
- },
1157
- []() {
1158
- // This will trigger Call stack cleanup.
1159
- return absl::InternalError(
1160
- "Stream not found while sending half closed");
1161
- });
2001
+ stream]() mutable {
2002
+ return TrySeq([stream]() { return stream->EnqueueHalfClosed(); },
2003
+ [self, stream](const StreamWritabilityUpdate result) mutable {
2004
+ GRPC_HTTP2_CLIENT_DLOG
2005
+ << "Http2ClientTransport CallOutboundLoop "
2006
+ "Enqueued Half Closed";
2007
+ return self->MaybeAddStreamToWritableStreamList(
2008
+ std::move(stream), result);
2009
+ });
1162
2010
  };
1163
2011
  return GRPC_LATENT_SEE_PROMISE(
1164
2012
  "Ph2CallOutboundLoop",
1165
2013
  TrySeq(
1166
2014
  send_initial_metadata(),
1167
- [call_handler, send_message, lock = std::move(lock)]() {
2015
+ [call_handler, send_message]() {
1168
2016
  // The lock will be released once the promise is constructed from
1169
2017
  // this factory. ForEach will be polled after the lock is
1170
2018
  // released.
@@ -1189,43 +2037,38 @@ void Http2ClientTransport::StartCall(CallHandler call_handler) {
1189
2037
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport StartCall Begin";
1190
2038
  call_handler.SpawnGuarded(
1191
2039
  "OutboundLoop",
1192
- TrySeq(
1193
- call_handler.PullClientInitialMetadata(),
1194
- [self = RefAsSubclass<Http2ClientTransport>()](
1195
- ClientMetadataHandle metadata) {
1196
- // Lock the stream_id_mutex_
1197
- return Staple(self->stream_id_mutex_.Acquire(),
1198
- std::move(metadata));
1199
- },
1200
- [self = RefAsSubclass<Http2ClientTransport>(),
1201
- call_handler](auto args /* Locked stream_id_mutex */) mutable {
1202
- // For a gRPC Client, we only need to check the
1203
- // MAX_CONCURRENT_STREAMS setting compliance at the time of
1204
- // sending (that is write path). A gRPC Client will never
1205
- // receive a stream initiated by a server, so we dont have to
1206
- // check MAX_CONCURRENT_STREAMS compliance on the Read-Path.
1207
- //
1208
- // TODO(tjagtap) : [PH2][P1] Check for MAX_CONCURRENT_STREAMS
1209
- // sent by peer before making a stream. Decide behaviour if we are
1210
- // crossing this threshold.
1211
- //
1212
- // TODO(tjagtap) : [PH2][P1] : For a server we will have to do
1213
- // this for incoming streams only. If a server receives more streams
1214
- // from a client than is allowed by the clients settings, whether or
1215
- // not we should fail is debatable.
1216
- const uint32_t stream_id = self->NextStreamId(std::get<0>(args));
1217
- return If(
1218
- self->MakeStream(call_handler, stream_id),
1219
- [self, call_handler, stream_id,
1220
- args = std::move(args)]() mutable {
1221
- return Map(
1222
- self->CallOutboundLoop(call_handler, stream_id,
1223
- std::move(std::get<0>(args)),
1224
- std::move(std::get<1>(args))),
1225
- [](absl::Status status) { return status; });
1226
- },
1227
- []() { return absl::InternalError("Failed to make stream"); });
1228
- }));
2040
+ TrySeq(call_handler.PullClientInitialMetadata(),
2041
+ [self = RefAsSubclass<Http2ClientTransport>(),
2042
+ call_handler](ClientMetadataHandle metadata) mutable {
2043
+ // For a gRPC Client, we only need to check the
2044
+ // MAX_CONCURRENT_STREAMS setting compliance at the time of
2045
+ // sending (that is write path). A gRPC Client will never
2046
+ // receive a stream initiated by a server, so we dont have to
2047
+ // check MAX_CONCURRENT_STREAMS compliance on the Read-Path.
2048
+ //
2049
+ // TODO(tjagtap) : [PH2][P1] Check for MAX_CONCURRENT_STREAMS
2050
+ // sent by peer before making a stream. Decide behaviour if we
2051
+ // are crossing this threshold.
2052
+ //
2053
+ // TODO(tjagtap) : [PH2][P1] : For a server we will have to do
2054
+ // this for incoming streams only. If a server receives more
2055
+ // streams from a client than is allowed by the clients settings,
2056
+ // whether or not we should fail is debatable.
2057
+ std::optional<RefCountedPtr<Stream>> stream =
2058
+ self->MakeStream(call_handler);
2059
+ return If(
2060
+ stream.has_value(),
2061
+ [self, call_handler, stream,
2062
+ initial_metadata = std::move(metadata)]() mutable {
2063
+ return Map(
2064
+ self->CallOutboundLoop(call_handler, stream.value(),
2065
+ std::move(initial_metadata)),
2066
+ [](absl::Status status) { return status; });
2067
+ },
2068
+ []() {
2069
+ return absl::InternalError("Failed to make stream");
2070
+ });
2071
+ }));
1229
2072
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport StartCall End";
1230
2073
  }
1231
2074