grpc 1.55.0 → 1.55.3
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.
- checksums.yaml +4 -4
- data/Makefile +4 -2
- data/src/core/ext/filters/client_channel/client_channel.cc +4 -6
- data/src/core/ext/filters/client_channel/client_channel.h +2 -0
- data/src/core/ext/transport/chttp2/transport/hpack_parse_result.cc +176 -0
- data/src/core/ext/transport/chttp2/transport/hpack_parse_result.h +325 -0
- data/src/core/ext/transport/chttp2/transport/hpack_parser.cc +567 -543
- data/src/core/ext/transport/chttp2/transport/hpack_parser.h +150 -9
- data/src/core/ext/transport/chttp2/transport/hpack_parser_table.cc +46 -32
- data/src/core/ext/transport/chttp2/transport/hpack_parser_table.h +18 -5
- data/src/core/ext/transport/chttp2/transport/parsing.cc +12 -12
- data/src/core/lib/backoff/random_early_detection.h +5 -0
- data/src/core/lib/event_engine/posix_engine/posix_engine.cc +30 -17
- data/src/core/lib/event_engine/posix_engine/posix_engine.h +1 -0
- data/src/core/lib/event_engine/posix_engine/posix_engine_listener.cc +29 -0
- data/src/core/lib/event_engine/posix_engine/posix_engine_listener.h +3 -0
- data/src/core/lib/iomgr/tcp_server_posix.cc +39 -14
- data/src/core/lib/iomgr/tcp_server_utils_posix.h +12 -0
- data/src/core/lib/iomgr/tcp_server_utils_posix_common.cc +21 -0
- data/src/core/lib/surface/validate_metadata.cc +37 -22
- data/src/core/lib/surface/validate_metadata.h +13 -3
- data/src/ruby/lib/grpc/version.rb +1 -1
- metadata +5 -3
| @@ -21,16 +21,28 @@ | |
| 21 21 |  | 
| 22 22 | 
             
            #include <grpc/support/port_platform.h>
         | 
| 23 23 |  | 
| 24 | 
            +
            #include <stddef.h>
         | 
| 24 25 | 
             
            #include <stdint.h>
         | 
| 25 26 |  | 
| 27 | 
            +
            #include <string>
         | 
| 28 | 
            +
            #include <utility>
         | 
| 26 29 | 
             
            #include <vector>
         | 
| 27 30 |  | 
| 31 | 
            +
            #include "absl/strings/str_cat.h"
         | 
| 32 | 
            +
            #include "absl/strings/string_view.h"
         | 
| 33 | 
            +
            #include "absl/types/optional.h"
         | 
| 34 | 
            +
            #include "absl/types/span.h"
         | 
| 35 | 
            +
            #include "absl/types/variant.h"
         | 
| 36 | 
            +
             | 
| 28 37 | 
             
            #include <grpc/slice.h>
         | 
| 29 38 |  | 
| 30 39 | 
             
            #include "src/core/ext/transport/chttp2/transport/frame.h"
         | 
| 40 | 
            +
            #include "src/core/ext/transport/chttp2/transport/hpack_parse_result.h"
         | 
| 31 41 | 
             
            #include "src/core/ext/transport/chttp2/transport/hpack_parser_table.h"
         | 
| 32 42 | 
             
            #include "src/core/lib/backoff/random_early_detection.h"
         | 
| 33 43 | 
             
            #include "src/core/lib/iomgr/error.h"
         | 
| 44 | 
            +
            #include "src/core/lib/slice/slice.h"
         | 
| 45 | 
            +
            #include "src/core/lib/slice/slice_refcount.h"
         | 
| 34 46 | 
             
            #include "src/core/lib/transport/metadata_batch.h"
         | 
| 35 47 |  | 
| 36 48 | 
             
            // IWYU pragma: no_include <type_traits>
         | 
| @@ -92,17 +104,150 @@ class HPackParser { | |
| 92 104 | 
             
              void FinishFrame();
         | 
| 93 105 |  | 
| 94 106 | 
             
              // Retrieve the associated hpack table (for tests, debugging)
         | 
| 95 | 
            -
              HPackTable* hpack_table() { return & | 
| 107 | 
            +
              HPackTable* hpack_table() { return &state_.hpack_table; }
         | 
| 96 108 | 
             
              // Is the current frame a boundary of some sort
         | 
| 97 109 | 
             
              bool is_boundary() const { return boundary_ != Boundary::None; }
         | 
| 98 110 | 
             
              // Is the current frame the end of a stream
         | 
| 99 111 | 
             
              bool is_eof() const { return boundary_ == Boundary::EndOfStream; }
         | 
| 100 112 |  | 
| 113 | 
            +
              // How many bytes are buffered (for tests to assert on)
         | 
| 114 | 
            +
              size_t buffered_bytes() const { return unparsed_bytes_.size(); }
         | 
| 115 | 
            +
             | 
| 101 116 | 
             
             private:
         | 
| 102 117 | 
             
              // Helper classes: see implementation
         | 
| 103 118 | 
             
              class Parser;
         | 
| 104 119 | 
             
              class Input;
         | 
| 105 | 
            -
             | 
| 120 | 
            +
             | 
| 121 | 
            +
              // Helper to parse a string and turn it into a slice with appropriate memory
         | 
| 122 | 
            +
              // management characteristics
         | 
| 123 | 
            +
              class String {
         | 
| 124 | 
            +
               public:
         | 
| 125 | 
            +
                // StringResult carries both a HpackParseStatus and the parsed string
         | 
| 126 | 
            +
                struct StringResult;
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                String() : value_(absl::Span<const uint8_t>()) {}
         | 
| 129 | 
            +
                String(const String&) = delete;
         | 
| 130 | 
            +
                String& operator=(const String&) = delete;
         | 
| 131 | 
            +
                String(String&& other) noexcept : value_(std::move(other.value_)) {
         | 
| 132 | 
            +
                  other.value_ = absl::Span<const uint8_t>();
         | 
| 133 | 
            +
                }
         | 
| 134 | 
            +
                String& operator=(String&& other) noexcept {
         | 
| 135 | 
            +
                  value_ = std::move(other.value_);
         | 
| 136 | 
            +
                  other.value_ = absl::Span<const uint8_t>();
         | 
| 137 | 
            +
                  return *this;
         | 
| 138 | 
            +
                }
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                // Take the value and leave this empty
         | 
| 141 | 
            +
                Slice Take();
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                // Return a reference to the value as a string view
         | 
| 144 | 
            +
                absl::string_view string_view() const;
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                // Parse a non-binary string
         | 
| 147 | 
            +
                static StringResult Parse(Input* input, bool is_huff, size_t length);
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                // Parse a binary string
         | 
| 150 | 
            +
                static StringResult ParseBinary(Input* input, bool is_huff, size_t length);
         | 
| 151 | 
            +
             | 
| 152 | 
            +
               private:
         | 
| 153 | 
            +
                void AppendBytes(const uint8_t* data, size_t length);
         | 
| 154 | 
            +
                explicit String(std::vector<uint8_t> v) : value_(std::move(v)) {}
         | 
| 155 | 
            +
                explicit String(absl::Span<const uint8_t> v) : value_(v) {}
         | 
| 156 | 
            +
                String(grpc_slice_refcount* r, const uint8_t* begin, const uint8_t* end)
         | 
| 157 | 
            +
                    : value_(Slice::FromRefcountAndBytes(r, begin, end)) {}
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                // Parse some huffman encoded bytes, using output(uint8_t b) to emit each
         | 
| 160 | 
            +
                // decoded byte.
         | 
| 161 | 
            +
                template <typename Out>
         | 
| 162 | 
            +
                static HpackParseStatus ParseHuff(Input* input, uint32_t length,
         | 
| 163 | 
            +
                                                  Out output);
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                // Parse some uncompressed string bytes.
         | 
| 166 | 
            +
                static StringResult ParseUncompressed(Input* input, uint32_t length,
         | 
| 167 | 
            +
                                                      uint32_t wire_size);
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                // Turn base64 encoded bytes into not base64 encoded bytes.
         | 
| 170 | 
            +
                static StringResult Unbase64(String s);
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                // Main loop for Unbase64
         | 
| 173 | 
            +
                static absl::optional<std::vector<uint8_t>> Unbase64Loop(
         | 
| 174 | 
            +
                    const uint8_t* cur, const uint8_t* end);
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                absl::variant<Slice, absl::Span<const uint8_t>, std::vector<uint8_t>>
         | 
| 177 | 
            +
                    value_;
         | 
| 178 | 
            +
              };
         | 
| 179 | 
            +
             | 
| 180 | 
            +
              // Prefix for a string
         | 
| 181 | 
            +
              struct StringPrefix {
         | 
| 182 | 
            +
                // Number of bytes in input for string
         | 
| 183 | 
            +
                uint32_t length;
         | 
| 184 | 
            +
                // Is it huffman compressed
         | 
| 185 | 
            +
                bool huff;
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                std::string ToString() const {
         | 
| 188 | 
            +
                  return absl::StrCat(length, " bytes ",
         | 
| 189 | 
            +
                                      huff ? "huffman compressed" : "uncompressed");
         | 
| 190 | 
            +
                }
         | 
| 191 | 
            +
              };
         | 
| 192 | 
            +
             | 
| 193 | 
            +
              // Current parse state
         | 
| 194 | 
            +
              // ┌───┐
         | 
| 195 | 
            +
              // │Top│
         | 
| 196 | 
            +
              // └┬─┬┘
         | 
| 197 | 
            +
              //  │┌▽────────────────┐
         | 
| 198 | 
            +
              //  ││ParsingKeyLength │
         | 
| 199 | 
            +
              //  │└┬───────────────┬┘
         | 
| 200 | 
            +
              //  │┌▽─────────────┐┌▽──────────────┐
         | 
| 201 | 
            +
              //  ││ParsingKeyBody││SkippingKeyBody│
         | 
| 202 | 
            +
              //  │└┬─────────────┘└───┬───────────┘
         | 
| 203 | 
            +
              // ┌▽─▽────────────────┐┌▽──────────────────┐
         | 
| 204 | 
            +
              // │ParsingValueLength ││SkippingValueLength│
         | 
| 205 | 
            +
              // └┬─────────────────┬┘└┬──────────────────┘
         | 
| 206 | 
            +
              // ┌▽───────────────┐┌▽──▽─────────────┐
         | 
| 207 | 
            +
              // │ParsingValueBody││SkippingValueBody│
         | 
| 208 | 
            +
              // └────────────────┘└─────────────────┘
         | 
| 209 | 
            +
              enum class ParseState : uint8_t {
         | 
| 210 | 
            +
                // Start of one opcode
         | 
| 211 | 
            +
                kTop,
         | 
| 212 | 
            +
                // Parsing a literal keys length
         | 
| 213 | 
            +
                kParsingKeyLength,
         | 
| 214 | 
            +
                // Parsing a literal key
         | 
| 215 | 
            +
                kParsingKeyBody,
         | 
| 216 | 
            +
                // Skipping a literal key
         | 
| 217 | 
            +
                kSkippingKeyBody,
         | 
| 218 | 
            +
                // Parsing a literal value length
         | 
| 219 | 
            +
                kParsingValueLength,
         | 
| 220 | 
            +
                // Parsing a literal value
         | 
| 221 | 
            +
                kParsingValueBody,
         | 
| 222 | 
            +
                // Reading a literal value length (so we can skip it)
         | 
| 223 | 
            +
                kSkippingValueLength,
         | 
| 224 | 
            +
                // Skipping a literal value
         | 
| 225 | 
            +
                kSkippingValueBody,
         | 
| 226 | 
            +
              };
         | 
| 227 | 
            +
             | 
| 228 | 
            +
              // Shared state for Parser instances between slices.
         | 
| 229 | 
            +
              struct InterSliceState {
         | 
| 230 | 
            +
                HPackTable hpack_table;
         | 
| 231 | 
            +
                // Error so far for this frame (set by class Input)
         | 
| 232 | 
            +
                HpackParseResult frame_error;
         | 
| 233 | 
            +
                // Length of frame so far.
         | 
| 234 | 
            +
                uint32_t frame_length = 0;
         | 
| 235 | 
            +
                // Length of the string being parsed
         | 
| 236 | 
            +
                uint32_t string_length;
         | 
| 237 | 
            +
                // How many more dynamic table updates are allowed
         | 
| 238 | 
            +
                uint8_t dynamic_table_updates_allowed;
         | 
| 239 | 
            +
                // Current parse state
         | 
| 240 | 
            +
                ParseState parse_state = ParseState::kTop;
         | 
| 241 | 
            +
                // RED for overly large metadata sets
         | 
| 242 | 
            +
                RandomEarlyDetection metadata_early_detection;
         | 
| 243 | 
            +
                // Should the current header be added to the hpack table?
         | 
| 244 | 
            +
                bool add_to_table;
         | 
| 245 | 
            +
                // Is the string being parsed huffman compressed?
         | 
| 246 | 
            +
                bool is_string_huff_compressed;
         | 
| 247 | 
            +
                // Is the value being parsed binary?
         | 
| 248 | 
            +
                bool is_binary_header;
         | 
| 249 | 
            +
                absl::variant<const HPackTable::Memento*, Slice> key;
         | 
| 250 | 
            +
              };
         | 
| 106 251 |  | 
| 107 252 | 
             
              grpc_error_handle ParseInput(Input input, bool is_last);
         | 
| 108 253 | 
             
              void ParseInputInner(Input* input);
         | 
| @@ -114,6 +259,8 @@ class HPackParser { | |
| 114 259 |  | 
| 115 260 | 
             
              // Bytes that could not be parsed last parsing round
         | 
| 116 261 | 
             
              std::vector<uint8_t> unparsed_bytes_;
         | 
| 262 | 
            +
              // How many bytes would be needed before progress could be made?
         | 
| 263 | 
            +
              size_t min_progress_size_ = 0;
         | 
| 117 264 | 
             
              // Buffer kind of boundary
         | 
| 118 265 | 
             
              // TODO(ctiller): see if we can move this argument to Parse, and avoid
         | 
| 119 266 | 
             
              // buffering.
         | 
| @@ -122,15 +269,9 @@ class HPackParser { | |
| 122 269 | 
             
              // TODO(ctiller): see if we can move this argument to Parse, and avoid
         | 
| 123 270 | 
             
              // buffering.
         | 
| 124 271 | 
             
              Priority priority_;
         | 
| 125 | 
            -
              uint8_t dynamic_table_updates_allowed_;
         | 
| 126 | 
            -
              // Length of frame so far.
         | 
| 127 | 
            -
              uint32_t frame_length_;
         | 
| 128 | 
            -
              RandomEarlyDetection metadata_early_detection_;
         | 
| 129 272 | 
             
              // Information for logging
         | 
| 130 273 | 
             
              LogInfo log_info_;
         | 
| 131 | 
            -
             | 
| 132 | 
            -
              // hpack table
         | 
| 133 | 
            -
              HPackTable table_;
         | 
| 274 | 
            +
              InterSliceState state_;
         | 
| 134 275 | 
             
            };
         | 
| 135 276 |  | 
| 136 277 | 
             
            }  // namespace grpc_core
         | 
| @@ -25,16 +25,16 @@ | |
| 25 25 | 
             
            #include <algorithm>
         | 
| 26 26 | 
             
            #include <cstddef>
         | 
| 27 27 | 
             
            #include <cstring>
         | 
| 28 | 
            -
            #include <initializer_list>
         | 
| 29 28 | 
             
            #include <utility>
         | 
| 30 29 |  | 
| 31 30 | 
             
            #include "absl/status/status.h"
         | 
| 32 | 
            -
            #include "absl/strings/ | 
| 31 | 
            +
            #include "absl/strings/str_cat.h"
         | 
| 33 32 | 
             
            #include "absl/strings/string_view.h"
         | 
| 34 33 |  | 
| 35 34 | 
             
            #include <grpc/support/log.h>
         | 
| 36 35 |  | 
| 37 36 | 
             
            #include "src/core/ext/transport/chttp2/transport/hpack_constants.h"
         | 
| 37 | 
            +
            #include "src/core/ext/transport/chttp2/transport/hpack_parse_result.h"
         | 
| 38 38 | 
             
            #include "src/core/ext/transport/chttp2/transport/http_trace.h"
         | 
| 39 39 | 
             
            #include "src/core/lib/debug/trace.h"
         | 
| 40 40 | 
             
            #include "src/core/lib/slice/slice.h"
         | 
| @@ -80,6 +80,14 @@ void HPackTable::MementoRingBuffer::Rebuild(uint32_t max_entries) { | |
| 80 80 | 
             
              entries_.swap(entries);
         | 
| 81 81 | 
             
            }
         | 
| 82 82 |  | 
| 83 | 
            +
            void HPackTable::MementoRingBuffer::ForEach(
         | 
| 84 | 
            +
                absl::FunctionRef<void(uint32_t, const Memento&)> f) const {
         | 
| 85 | 
            +
              uint32_t index = 0;
         | 
| 86 | 
            +
              while (auto* m = Lookup(index++)) {
         | 
| 87 | 
            +
                f(index, *m);
         | 
| 88 | 
            +
              }
         | 
| 89 | 
            +
            }
         | 
| 90 | 
            +
             | 
| 83 91 | 
             
            // Evict one element from the table
         | 
| 84 92 | 
             
            void HPackTable::EvictOne() {
         | 
| 85 93 | 
             
              auto first_entry = entries_.PopOne();
         | 
| @@ -100,15 +108,9 @@ void HPackTable::SetMaxBytes(uint32_t max_bytes) { | |
| 100 108 | 
             
              max_bytes_ = max_bytes;
         | 
| 101 109 | 
             
            }
         | 
| 102 110 |  | 
| 103 | 
            -
             | 
| 104 | 
            -
              if (current_table_bytes_ == bytes)  | 
| 105 | 
            -
             | 
| 106 | 
            -
              }
         | 
| 107 | 
            -
              if (bytes > max_bytes_) {
         | 
| 108 | 
            -
                return absl::InternalError(absl::StrFormat(
         | 
| 109 | 
            -
                    "Attempt to make hpack table %d bytes when max is %d bytes", bytes,
         | 
| 110 | 
            -
                    max_bytes_));
         | 
| 111 | 
            -
              }
         | 
| 111 | 
            +
            bool HPackTable::SetCurrentTableSize(uint32_t bytes) {
         | 
| 112 | 
            +
              if (current_table_bytes_ == bytes) return true;
         | 
| 113 | 
            +
              if (bytes > max_bytes_) return false;
         | 
| 112 114 | 
             
              if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
         | 
| 113 115 | 
             
                gpr_log(GPR_INFO, "Update hpack parser table size to %d", bytes);
         | 
| 114 116 | 
             
              }
         | 
| @@ -119,30 +121,16 @@ grpc_error_handle HPackTable::SetCurrentTableSize(uint32_t bytes) { | |
| 119 121 | 
             
              uint32_t new_cap = std::max(hpack_constants::EntriesForBytes(bytes),
         | 
| 120 122 | 
             
                                          hpack_constants::kInitialTableEntries);
         | 
| 121 123 | 
             
              entries_.Rebuild(new_cap);
         | 
| 122 | 
            -
              return  | 
| 124 | 
            +
              return true;
         | 
| 123 125 | 
             
            }
         | 
| 124 126 |  | 
| 125 | 
            -
             | 
| 126 | 
            -
              if (current_table_bytes_ > max_bytes_)  | 
| 127 | 
            -
                return GRPC_ERROR_CREATE(absl::StrFormat(
         | 
| 128 | 
            -
                    "HPACK max table size reduced to %d but not reflected by hpack "
         | 
| 129 | 
            -
                    "stream (still at %d)",
         | 
| 130 | 
            -
                    max_bytes_, current_table_bytes_));
         | 
| 131 | 
            -
              }
         | 
| 127 | 
            +
            bool HPackTable::Add(Memento md) {
         | 
| 128 | 
            +
              if (current_table_bytes_ > max_bytes_) return false;
         | 
| 132 129 |  | 
| 133 130 | 
             
              // we can't add elements bigger than the max table size
         | 
| 134 131 | 
             
              if (md.md.transport_size() > current_table_bytes_) {
         | 
| 135 | 
            -
                 | 
| 136 | 
            -
                 | 
| 137 | 
            -
                // size, that entry is added to the table.  It is not an error to
         | 
| 138 | 
            -
                // attempt to add an entry that is larger than the maximum size; an
         | 
| 139 | 
            -
                // attempt to add an entry larger than the entire table causes
         | 
| 140 | 
            -
                // the table to be emptied of all existing entries, and results in an
         | 
| 141 | 
            -
                // empty table.
         | 
| 142 | 
            -
                while (entries_.num_entries()) {
         | 
| 143 | 
            -
                  EvictOne();
         | 
| 144 | 
            -
                }
         | 
| 145 | 
            -
                return absl::OkStatus();
         | 
| 132 | 
            +
                AddLargerThanCurrentTableSize();
         | 
| 133 | 
            +
                return true;
         | 
| 146 134 | 
             
              }
         | 
| 147 135 |  | 
| 148 136 | 
             
              // evict entries to ensure no overflow
         | 
| @@ -154,7 +142,33 @@ grpc_error_handle HPackTable::Add(Memento md) { | |
| 154 142 | 
             
              // copy the finalized entry in
         | 
| 155 143 | 
             
              mem_used_ += md.md.transport_size();
         | 
| 156 144 | 
             
              entries_.Put(std::move(md));
         | 
| 157 | 
            -
              return  | 
| 145 | 
            +
              return true;
         | 
| 146 | 
            +
            }
         | 
| 147 | 
            +
             | 
| 148 | 
            +
            void HPackTable::AddLargerThanCurrentTableSize() {
         | 
| 149 | 
            +
              // HPACK draft 10 section 4.4 states:
         | 
| 150 | 
            +
              // If the size of the new entry is less than or equal to the maximum
         | 
| 151 | 
            +
              // size, that entry is added to the table.  It is not an error to
         | 
| 152 | 
            +
              // attempt to add an entry that is larger than the maximum size; an
         | 
| 153 | 
            +
              // attempt to add an entry larger than the entire table causes
         | 
| 154 | 
            +
              // the table to be emptied of all existing entries, and results in an
         | 
| 155 | 
            +
              // empty table.
         | 
| 156 | 
            +
              while (entries_.num_entries()) {
         | 
| 157 | 
            +
                EvictOne();
         | 
| 158 | 
            +
              }
         | 
| 159 | 
            +
            }
         | 
| 160 | 
            +
             | 
| 161 | 
            +
            std::string HPackTable::TestOnlyDynamicTableAsString() const {
         | 
| 162 | 
            +
              std::string out;
         | 
| 163 | 
            +
              entries_.ForEach([&out](uint32_t i, const Memento& m) {
         | 
| 164 | 
            +
                if (m.parse_status.ok()) {
         | 
| 165 | 
            +
                  absl::StrAppend(&out, i, ": ", m.md.DebugString(), "\n");
         | 
| 166 | 
            +
                } else {
         | 
| 167 | 
            +
                  absl::StrAppend(&out, i, ": ", m.parse_status.Materialize().ToString(),
         | 
| 168 | 
            +
                                  "\n");
         | 
| 169 | 
            +
                }
         | 
| 170 | 
            +
              });
         | 
| 171 | 
            +
              return out;
         | 
| 158 172 | 
             
            }
         | 
| 159 173 |  | 
| 160 174 | 
             
            namespace {
         | 
| @@ -236,7 +250,7 @@ HPackTable::Memento MakeMemento(size_t i) { | |
| 236 250 | 
             
                      [](absl::string_view, const Slice&) {
         | 
| 237 251 | 
             
                        abort();  // not expecting to see this
         | 
| 238 252 | 
             
                      }),
         | 
| 239 | 
            -
                   | 
| 253 | 
            +
                  HpackParseResult()};
         | 
| 240 254 | 
             
            }
         | 
| 241 255 |  | 
| 242 256 | 
             
            }  // namespace
         | 
| @@ -23,13 +23,14 @@ | |
| 23 23 |  | 
| 24 24 | 
             
            #include <stdint.h>
         | 
| 25 25 |  | 
| 26 | 
            +
            #include <string>
         | 
| 26 27 | 
             
            #include <vector>
         | 
| 27 28 |  | 
| 28 | 
            -
            #include "absl/ | 
| 29 | 
            +
            #include "absl/functional/function_ref.h"
         | 
| 29 30 |  | 
| 30 31 | 
             
            #include "src/core/ext/transport/chttp2/transport/hpack_constants.h"
         | 
| 32 | 
            +
            #include "src/core/ext/transport/chttp2/transport/hpack_parse_result.h"
         | 
| 31 33 | 
             
            #include "src/core/lib/gprpp/no_destruct.h"
         | 
| 32 | 
            -
            #include "src/core/lib/iomgr/error.h"
         | 
| 33 34 | 
             
            #include "src/core/lib/transport/metadata_batch.h"
         | 
| 34 35 | 
             
            #include "src/core/lib/transport/parsed_metadata.h"
         | 
| 35 36 |  | 
| @@ -45,11 +46,12 @@ class HPackTable { | |
| 45 46 | 
             
              HPackTable& operator=(const HPackTable&) = delete;
         | 
| 46 47 |  | 
| 47 48 | 
             
              void SetMaxBytes(uint32_t max_bytes);
         | 
| 48 | 
            -
               | 
| 49 | 
            +
              bool SetCurrentTableSize(uint32_t bytes);
         | 
| 50 | 
            +
              uint32_t current_table_size() { return current_table_bytes_; }
         | 
| 49 51 |  | 
| 50 52 | 
             
              struct Memento {
         | 
| 51 53 | 
             
                ParsedMetadata<grpc_metadata_batch> md;
         | 
| 52 | 
            -
                 | 
| 54 | 
            +
                HpackParseResult parse_status;
         | 
| 53 55 | 
             
              };
         | 
| 54 56 |  | 
| 55 57 | 
             
              // Lookup, but don't ref.
         | 
| @@ -68,7 +70,8 @@ class HPackTable { | |
| 68 70 | 
             
              }
         | 
| 69 71 |  | 
| 70 72 | 
             
              // add a table entry to the index
         | 
| 71 | 
            -
               | 
| 73 | 
            +
              bool Add(Memento md) GRPC_MUST_USE_RESULT;
         | 
| 74 | 
            +
              void AddLargerThanCurrentTableSize();
         | 
| 72 75 |  | 
| 73 76 | 
             
              // Current entry count in the table.
         | 
| 74 77 | 
             
              uint32_t num_entries() const { return entries_.num_entries(); }
         | 
| @@ -76,6 +79,13 @@ class HPackTable { | |
| 76 79 | 
             
              // Current size of the table.
         | 
| 77 80 | 
             
              uint32_t test_only_table_size() const { return mem_used_; }
         | 
| 78 81 |  | 
| 82 | 
            +
              // Maximum allowed size of the table currently
         | 
| 83 | 
            +
              uint32_t max_bytes() const { return max_bytes_; }
         | 
| 84 | 
            +
              uint32_t current_table_bytes() const { return current_table_bytes_; }
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              // Dynamic table entries, stringified
         | 
| 87 | 
            +
              std::string TestOnlyDynamicTableAsString() const;
         | 
| 88 | 
            +
             | 
| 79 89 | 
             
             private:
         | 
| 80 90 | 
             
              struct StaticMementos {
         | 
| 81 91 | 
             
                StaticMementos();
         | 
| @@ -98,6 +108,9 @@ class HPackTable { | |
| 98 108 | 
             
                // Lookup the entry at index, or return nullptr if none exists.
         | 
| 99 109 | 
             
                const Memento* Lookup(uint32_t index) const;
         | 
| 100 110 |  | 
| 111 | 
            +
                void ForEach(absl::FunctionRef<void(uint32_t dynamic_index, const Memento&)>
         | 
| 112 | 
            +
                                 f) const;
         | 
| 113 | 
            +
             | 
| 101 114 | 
             
                uint32_t max_entries() const { return max_entries_; }
         | 
| 102 115 | 
             
                uint32_t num_entries() const { return num_entries_; }
         | 
| 103 116 |  | 
| @@ -23,7 +23,6 @@ | |
| 23 23 |  | 
| 24 24 | 
             
            #include <initializer_list>
         | 
| 25 25 | 
             
            #include <string>
         | 
| 26 | 
            -
            #include <utility>
         | 
| 27 26 |  | 
| 28 27 | 
             
            #include "absl/base/attributes.h"
         | 
| 29 28 | 
             
            #include "absl/status/status.h"
         | 
| @@ -470,8 +469,8 @@ static HPackParser::LogInfo hpack_parser_log_info( | |
| 470 469 | 
             
            }
         | 
| 471 470 |  | 
| 472 471 | 
             
            static grpc_error_handle init_header_skip_frame_parser(
         | 
| 473 | 
            -
                grpc_chttp2_transport* t, HPackParser::Priority priority_type | 
| 474 | 
            -
             | 
| 472 | 
            +
                grpc_chttp2_transport* t, HPackParser::Priority priority_type,
         | 
| 473 | 
            +
                bool is_eoh) {
         | 
| 475 474 | 
             
              t->parser = grpc_chttp2_transport::Parser{
         | 
| 476 475 | 
             
                  "header", grpc_chttp2_header_parser_parse, &t->hpack_parser};
         | 
| 477 476 | 
             
              t->hpack_parser.BeginFrame(
         | 
| @@ -595,7 +594,7 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t, | |
| 595 594 | 
             
                  GRPC_CHTTP2_IF_TRACING(
         | 
| 596 595 | 
             
                      gpr_log(GPR_ERROR,
         | 
| 597 596 | 
             
                              "grpc_chttp2_stream disbanded before CONTINUATION received"));
         | 
| 598 | 
            -
                  return init_header_skip_frame_parser(t, priority_type);
         | 
| 597 | 
            +
                  return init_header_skip_frame_parser(t, priority_type, is_eoh);
         | 
| 599 598 | 
             
                }
         | 
| 600 599 | 
             
                if (t->is_client) {
         | 
| 601 600 | 
             
                  if (GPR_LIKELY((t->incoming_stream_id & 1) &&
         | 
| @@ -605,7 +604,7 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t, | |
| 605 604 | 
             
                    GRPC_CHTTP2_IF_TRACING(gpr_log(
         | 
| 606 605 | 
             
                        GPR_ERROR, "ignoring new grpc_chttp2_stream creation on client"));
         | 
| 607 606 | 
             
                  }
         | 
| 608 | 
            -
                  return init_header_skip_frame_parser(t, priority_type);
         | 
| 607 | 
            +
                  return init_header_skip_frame_parser(t, priority_type, is_eoh);
         | 
| 609 608 | 
             
                } else if (GPR_UNLIKELY(t->last_new_stream_id >= t->incoming_stream_id)) {
         | 
| 610 609 | 
             
                  GRPC_CHTTP2_IF_TRACING(gpr_log(
         | 
| 611 610 | 
             
                      GPR_ERROR,
         | 
| @@ -613,13 +612,13 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t, | |
| 613 612 | 
             
                      "last grpc_chttp2_stream "
         | 
| 614 613 | 
             
                      "id=%d, new grpc_chttp2_stream id=%d",
         | 
| 615 614 | 
             
                      t->last_new_stream_id, t->incoming_stream_id));
         | 
| 616 | 
            -
                  return init_header_skip_frame_parser(t, priority_type);
         | 
| 615 | 
            +
                  return init_header_skip_frame_parser(t, priority_type, is_eoh);
         | 
| 617 616 | 
             
                } else if (GPR_UNLIKELY((t->incoming_stream_id & 1) == 0)) {
         | 
| 618 617 | 
             
                  GRPC_CHTTP2_IF_TRACING(gpr_log(
         | 
| 619 618 | 
             
                      GPR_ERROR,
         | 
| 620 619 | 
             
                      "ignoring grpc_chttp2_stream with non-client generated index %d",
         | 
| 621 620 | 
             
                      t->incoming_stream_id));
         | 
| 622 | 
            -
                  return init_header_skip_frame_parser(t, priority_type);
         | 
| 621 | 
            +
                  return init_header_skip_frame_parser(t, priority_type, is_eoh);
         | 
| 623 622 | 
             
                } else if (GPR_UNLIKELY(
         | 
| 624 623 | 
             
                               grpc_chttp2_stream_map_size(&t->stream_map) >=
         | 
| 625 624 | 
             
                               t->settings[GRPC_ACKED_SETTINGS]
         | 
| @@ -632,7 +631,7 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t, | |
| 632 631 | 
             
                      "grpc_chttp2_stream request id=%d, last grpc_chttp2_stream id=%d",
         | 
| 633 632 | 
             
                      t, std::string(t->peer_string.as_string_view()).c_str(),
         | 
| 634 633 | 
             
                      t->incoming_stream_id, t->last_new_stream_id));
         | 
| 635 | 
            -
                  return init_header_skip_frame_parser(t, priority_type);
         | 
| 634 | 
            +
                  return init_header_skip_frame_parser(t, priority_type, is_eoh);
         | 
| 636 635 | 
             
                }
         | 
| 637 636 | 
             
                t->last_new_stream_id = t->incoming_stream_id;
         | 
| 638 637 | 
             
                s = t->incoming_stream =
         | 
| @@ -640,7 +639,7 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t, | |
| 640 639 | 
             
                if (GPR_UNLIKELY(s == nullptr)) {
         | 
| 641 640 | 
             
                  GRPC_CHTTP2_IF_TRACING(
         | 
| 642 641 | 
             
                      gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted"));
         | 
| 643 | 
            -
                  return init_header_skip_frame_parser(t, priority_type);
         | 
| 642 | 
            +
                  return init_header_skip_frame_parser(t, priority_type, is_eoh);
         | 
| 644 643 | 
             
                }
         | 
| 645 644 | 
             
                if (t->channelz_socket != nullptr) {
         | 
| 646 645 | 
             
                  t->channelz_socket->RecordStreamStartedFromRemote();
         | 
| @@ -654,7 +653,7 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t, | |
| 654 653 | 
             
                GRPC_CHTTP2_IF_TRACING(gpr_log(
         | 
| 655 654 | 
             
                    GPR_ERROR, "skipping already closed grpc_chttp2_stream header"));
         | 
| 656 655 | 
             
                t->incoming_stream = nullptr;
         | 
| 657 | 
            -
                return init_header_skip_frame_parser(t, priority_type);
         | 
| 656 | 
            +
                return init_header_skip_frame_parser(t, priority_type, is_eoh);
         | 
| 658 657 | 
             
              }
         | 
| 659 658 | 
             
              t->parser = grpc_chttp2_transport::Parser{
         | 
| 660 659 | 
             
                  "header", grpc_chttp2_header_parser_parse, &t->hpack_parser};
         | 
| @@ -687,7 +686,7 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t, | |
| 687 686 | 
             
                  break;
         | 
| 688 687 | 
             
                case 2:
         | 
| 689 688 | 
             
                  gpr_log(GPR_ERROR, "too many header frames received");
         | 
| 690 | 
            -
                  return init_header_skip_frame_parser(t, priority_type);
         | 
| 689 | 
            +
                  return init_header_skip_frame_parser(t, priority_type, is_eoh);
         | 
| 691 690 | 
             
              }
         | 
| 692 691 | 
             
              if (frame_type == HPackParser::LogInfo::kTrailers && !t->header_eof) {
         | 
| 693 692 | 
             
                return GRPC_ERROR_CREATE(
         | 
| @@ -815,8 +814,9 @@ static grpc_error_handle parse_frame_slice(grpc_chttp2_transport* t, | |
| 815 814 | 
             
                                     &unused)) {
         | 
| 816 815 | 
             
                grpc_chttp2_parsing_become_skip_parser(t);
         | 
| 817 816 | 
             
                if (s) {
         | 
| 818 | 
            -
                  grpc_chttp2_cancel_stream(t, s,  | 
| 817 | 
            +
                  grpc_chttp2_cancel_stream(t, s, err);
         | 
| 819 818 | 
             
                }
         | 
| 819 | 
            +
                return absl::OkStatus();
         | 
| 820 820 | 
             
              }
         | 
| 821 821 | 
             
              return err;
         | 
| 822 822 | 
             
            }
         | 
| @@ -43,6 +43,11 @@ class RandomEarlyDetection { | |
| 43 43 | 
             
              uint64_t soft_limit() const { return soft_limit_; }
         | 
| 44 44 | 
             
              uint64_t hard_limit() const { return hard_limit_; }
         | 
| 45 45 |  | 
| 46 | 
            +
              void SetLimits(uint64_t soft_limit, uint64_t hard_limit) {
         | 
| 47 | 
            +
                soft_limit_ = soft_limit;
         | 
| 48 | 
            +
                hard_limit_ = hard_limit;
         | 
| 49 | 
            +
              }
         | 
| 50 | 
            +
             | 
| 46 51 | 
             
             private:
         | 
| 47 52 | 
             
              // The soft limit is the size at which we start rejecting items with a
         | 
| 48 53 | 
             
              // probability that increases linearly to 1 as the size approaches the hard
         | 
| @@ -60,6 +60,15 @@ | |
| 60 60 |  | 
| 61 61 | 
             
            // IWYU pragma: no_include <ratio>
         | 
| 62 62 |  | 
| 63 | 
            +
            // TODO(eryu): remove this GRPC_CFSTREAM condition when the CFEngine is ready.
         | 
| 64 | 
            +
            // The posix poller currently crashes iOS.
         | 
| 65 | 
            +
            #if defined(GRPC_POSIX_SOCKET_TCP) && !defined(GRPC_CFSTREAM) && \
         | 
| 66 | 
            +
                !defined(GRPC_DO_NOT_INSTANTIATE_POSIX_POLLER)
         | 
| 67 | 
            +
            #define GRPC_PLATFORM_SUPPORTS_POSIX_POLLING true
         | 
| 68 | 
            +
            #else
         | 
| 69 | 
            +
            #define GRPC_PLATFORM_SUPPORTS_POSIX_POLLING false
         | 
| 70 | 
            +
            #endif
         | 
| 71 | 
            +
             | 
| 63 72 | 
             
            using namespace std::chrono_literals;
         | 
| 64 73 |  | 
| 65 74 | 
             
            namespace grpc_event_engine {
         | 
| @@ -335,13 +344,16 @@ PosixEventEngine::PosixEventEngine(PosixEventPoller* poller) | |
| 335 344 | 
             
                : connection_shards_(std::max(2 * gpr_cpu_num_cores(), 1u)),
         | 
| 336 345 | 
             
                  executor_(std::make_shared<ThreadPool>()),
         | 
| 337 346 | 
             
                  timer_manager_(executor_) {
         | 
| 347 | 
            +
            #if GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 338 348 | 
             
              poller_manager_ = std::make_shared<PosixEnginePollerManager>(poller);
         | 
| 349 | 
            +
            #endif
         | 
| 339 350 | 
             
            }
         | 
| 340 351 |  | 
| 341 352 | 
             
            PosixEventEngine::PosixEventEngine()
         | 
| 342 353 | 
             
                : connection_shards_(std::max(2 * gpr_cpu_num_cores(), 1u)),
         | 
| 343 354 | 
             
                  executor_(std::make_shared<ThreadPool>()),
         | 
| 344 355 | 
             
                  timer_manager_(executor_) {
         | 
| 356 | 
            +
            #if GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 345 357 | 
             
              poller_manager_ = std::make_shared<PosixEnginePollerManager>(executor_);
         | 
| 346 358 | 
             
              // The threadpool must be instantiated after the poller otherwise, the
         | 
| 347 359 | 
             
              // process will deadlock when forking.
         | 
| @@ -350,6 +362,7 @@ PosixEventEngine::PosixEventEngine() | |
| 350 362 | 
             
                  PollerWorkInternal(poller_manager);
         | 
| 351 363 | 
             
                });
         | 
| 352 364 | 
             
              }
         | 
| 365 | 
            +
            #endif  // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 353 366 | 
             
            }
         | 
| 354 367 |  | 
| 355 368 | 
             
            void PosixEventEngine::PollerWorkInternal(
         | 
| @@ -420,11 +433,11 @@ PosixEventEngine::~PosixEventEngine() { | |
| 420 433 | 
             
                GPR_ASSERT(GPR_LIKELY(known_handles_.empty()));
         | 
| 421 434 | 
             
              }
         | 
| 422 435 | 
             
              timer_manager_.Shutdown();
         | 
| 423 | 
            -
            # | 
| 436 | 
            +
            #if GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 424 437 | 
             
              if (poller_manager_ != nullptr) {
         | 
| 425 438 | 
             
                poller_manager_->TriggerShutdown();
         | 
| 426 439 | 
             
              }
         | 
| 427 | 
            -
            #endif  //  | 
| 440 | 
            +
            #endif  // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 428 441 | 
             
              executor_->Quiesce();
         | 
| 429 442 | 
             
            }
         | 
| 430 443 |  | 
| @@ -481,7 +494,7 @@ std::unique_ptr<EventEngine::DNSResolver> PosixEventEngine::GetDNSResolver( | |
| 481 494 | 
             
            bool PosixEventEngine::IsWorkerThread() { grpc_core::Crash("unimplemented"); }
         | 
| 482 495 |  | 
| 483 496 | 
             
            bool PosixEventEngine::CancelConnect(EventEngine::ConnectionHandle handle) {
         | 
| 484 | 
            -
            # | 
| 497 | 
            +
            #if GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 485 498 | 
             
              int connection_handle = handle.keys[0];
         | 
| 486 499 | 
             
              if (connection_handle <= 0) {
         | 
| 487 500 | 
             
                return false;
         | 
| @@ -530,17 +543,17 @@ bool PosixEventEngine::CancelConnect(EventEngine::ConnectionHandle handle) { | |
| 530 543 | 
             
                delete ac;
         | 
| 531 544 | 
             
              }
         | 
| 532 545 | 
             
              return connection_cancel_success;
         | 
| 533 | 
            -
            #else   //  | 
| 546 | 
            +
            #else   // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 534 547 | 
             
              grpc_core::Crash(
         | 
| 535 548 | 
             
                  "EventEngine::CancelConnect is not supported on this platform");
         | 
| 536 | 
            -
            #endif  //  | 
| 549 | 
            +
            #endif  // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 537 550 | 
             
            }
         | 
| 538 551 |  | 
| 539 552 | 
             
            EventEngine::ConnectionHandle PosixEventEngine::Connect(
         | 
| 540 553 | 
             
                OnConnectCallback on_connect, const ResolvedAddress& addr,
         | 
| 541 554 | 
             
                const EndpointConfig& args, MemoryAllocator memory_allocator,
         | 
| 542 555 | 
             
                Duration timeout) {
         | 
| 543 | 
            -
            # | 
| 556 | 
            +
            #if GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 544 557 | 
             
              GPR_ASSERT(poller_manager_ != nullptr);
         | 
| 545 558 | 
             
              PosixTcpOptions options = TcpOptionsFromEndpointConfig(args);
         | 
| 546 559 | 
             
              absl::StatusOr<PosixSocketWrapper::PosixSocketCreateResult> socket =
         | 
| @@ -553,16 +566,16 @@ EventEngine::ConnectionHandle PosixEventEngine::Connect( | |
| 553 566 | 
             
              return ConnectInternal((*socket).sock, std::move(on_connect),
         | 
| 554 567 | 
             
                                     (*socket).mapped_target_addr,
         | 
| 555 568 | 
             
                                     std::move(memory_allocator), options, timeout);
         | 
| 556 | 
            -
            #else   //  | 
| 569 | 
            +
            #else   // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 557 570 | 
             
              grpc_core::Crash("EventEngine::Connect is not supported on this platform");
         | 
| 558 | 
            -
            #endif  //  | 
| 571 | 
            +
            #endif  // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 559 572 | 
             
            }
         | 
| 560 573 |  | 
| 561 574 | 
             
            std::unique_ptr<PosixEndpointWithFdSupport>
         | 
| 562 575 | 
             
            PosixEventEngine::CreatePosixEndpointFromFd(int fd,
         | 
| 563 576 | 
             
                                                        const EndpointConfig& config,
         | 
| 564 577 | 
             
                                                        MemoryAllocator memory_allocator) {
         | 
| 565 | 
            -
            # | 
| 578 | 
            +
            #if GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 566 579 | 
             
              GPR_DEBUG_ASSERT(fd > 0);
         | 
| 567 580 | 
             
              PosixEventPoller* poller = poller_manager_->Poller();
         | 
| 568 581 | 
             
              GPR_DEBUG_ASSERT(poller != nullptr);
         | 
| @@ -571,11 +584,11 @@ PosixEventEngine::CreatePosixEndpointFromFd(int fd, | |
| 571 584 | 
             
              return CreatePosixEndpoint(handle, nullptr, shared_from_this(),
         | 
| 572 585 | 
             
                                         std::move(memory_allocator),
         | 
| 573 586 | 
             
                                         TcpOptionsFromEndpointConfig(config));
         | 
| 574 | 
            -
            #else   //  | 
| 587 | 
            +
            #else   // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 575 588 | 
             
              grpc_core::Crash(
         | 
| 576 589 | 
             
                  "PosixEventEngine::CreatePosixEndpointFromFd is not supported on "
         | 
| 577 590 | 
             
                  "this platform");
         | 
| 578 | 
            -
            #endif  //  | 
| 591 | 
            +
            #endif  // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 579 592 | 
             
            }
         | 
| 580 593 |  | 
| 581 594 | 
             
            absl::StatusOr<std::unique_ptr<EventEngine::Listener>>
         | 
| @@ -584,7 +597,7 @@ PosixEventEngine::CreateListener( | |
| 584 597 | 
             
                absl::AnyInvocable<void(absl::Status)> on_shutdown,
         | 
| 585 598 | 
             
                const EndpointConfig& config,
         | 
| 586 599 | 
             
                std::unique_ptr<MemoryAllocatorFactory> memory_allocator_factory) {
         | 
| 587 | 
            -
            # | 
| 600 | 
            +
            #if GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 588 601 | 
             
              PosixEventEngineWithFdSupport::PosixAcceptCallback posix_on_accept =
         | 
| 589 602 | 
             
                  [on_accept_cb = std::move(on_accept)](
         | 
| 590 603 | 
             
                      int /*listener_fd*/, std::unique_ptr<EventEngine::Endpoint> ep,
         | 
| @@ -596,10 +609,10 @@ PosixEventEngine::CreateListener( | |
| 596 609 | 
             
                  std::move(posix_on_accept), std::move(on_shutdown), config,
         | 
| 597 610 | 
             
                  std::move(memory_allocator_factory), poller_manager_->Poller(),
         | 
| 598 611 | 
             
                  shared_from_this());
         | 
| 599 | 
            -
            #else   //  | 
| 612 | 
            +
            #else   // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 600 613 | 
             
              grpc_core::Crash(
         | 
| 601 614 | 
             
                  "EventEngine::CreateListener is not supported on this platform");
         | 
| 602 | 
            -
            #endif  //  | 
| 615 | 
            +
            #endif  // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 603 616 | 
             
            }
         | 
| 604 617 |  | 
| 605 618 | 
             
            absl::StatusOr<std::unique_ptr<PosixListenerWithFdSupport>>
         | 
| @@ -608,15 +621,15 @@ PosixEventEngine::CreatePosixListener( | |
| 608 621 | 
             
                absl::AnyInvocable<void(absl::Status)> on_shutdown,
         | 
| 609 622 | 
             
                const EndpointConfig& config,
         | 
| 610 623 | 
             
                std::unique_ptr<MemoryAllocatorFactory> memory_allocator_factory) {
         | 
| 611 | 
            -
            # | 
| 624 | 
            +
            #if GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 612 625 | 
             
              return std::make_unique<PosixEngineListener>(
         | 
| 613 626 | 
             
                  std::move(on_accept), std::move(on_shutdown), config,
         | 
| 614 627 | 
             
                  std::move(memory_allocator_factory), poller_manager_->Poller(),
         | 
| 615 628 | 
             
                  shared_from_this());
         | 
| 616 | 
            -
            #else   //  | 
| 629 | 
            +
            #else   // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 617 630 | 
             
              grpc_core::Crash(
         | 
| 618 631 | 
             
                  "EventEngine::CreateListener is not supported on this platform");
         | 
| 619 | 
            -
            #endif  //  | 
| 632 | 
            +
            #endif  // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
         | 
| 620 633 | 
             
            }
         | 
| 621 634 |  | 
| 622 635 | 
             
            }  // namespace experimental
         | 
| @@ -196,6 +196,7 @@ class PosixEventEngine final : public PosixEventEngineWithFdSupport, | |
| 196 196 | 
             
                  const DNSResolver::ResolverOptions& options) override;
         | 
| 197 197 | 
             
              void Run(Closure* closure) override;
         | 
| 198 198 | 
             
              void Run(absl::AnyInvocable<void()> closure) override;
         | 
| 199 | 
            +
              // Caution!! The timer implementation cannot create any fds. See #20418.
         | 
| 199 200 | 
             
              TaskHandle RunAfter(Duration when, Closure* closure) override;
         | 
| 200 201 | 
             
              TaskHandle RunAfter(Duration when,
         | 
| 201 202 | 
             
                                  absl::AnyInvocable<void()> closure) override;
         |