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.
@@ -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 &table_; }
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
- class String;
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/str_format.h"
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
- grpc_error_handle HPackTable::SetCurrentTableSize(uint32_t bytes) {
104
- if (current_table_bytes_ == bytes) {
105
- return absl::OkStatus();
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 absl::OkStatus();
124
+ return true;
123
125
  }
124
126
 
125
- grpc_error_handle HPackTable::Add(Memento md) {
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
- // HPACK draft 10 section 4.4 states:
136
- // If the size of the new entry is less than or equal to the maximum
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 absl::OkStatus();
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
- absl::OkStatus()};
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/status/status.h"
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
- grpc_error_handle SetCurrentTableSize(uint32_t bytes);
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
- absl::Status parse_status;
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
- grpc_error_handle Add(Memento md) GRPC_MUST_USE_RESULT;
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
- bool is_eoh = t->expect_continuation_stream_id != 0;
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, std::exchange(err, absl::OkStatus()));
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
- #ifdef GRPC_POSIX_SOCKET_TCP
436
+ #if GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
424
437
  if (poller_manager_ != nullptr) {
425
438
  poller_manager_->TriggerShutdown();
426
439
  }
427
- #endif // GRPC_POSIX_SOCKET_TCP
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
- #ifdef GRPC_POSIX_SOCKET_TCP
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 // GRPC_POSIX_SOCKET_TCP
546
+ #else // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
534
547
  grpc_core::Crash(
535
548
  "EventEngine::CancelConnect is not supported on this platform");
536
- #endif // GRPC_POSIX_SOCKET_TCP
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
- #ifdef GRPC_POSIX_SOCKET_TCP
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 // GRPC_POSIX_SOCKET_TCP
569
+ #else // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
557
570
  grpc_core::Crash("EventEngine::Connect is not supported on this platform");
558
- #endif // GRPC_POSIX_SOCKET_TCP
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
- #ifdef GRPC_POSIX_SOCKET_TCP
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 // GRPC_POSIX_SOCKET_TCP
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 // GRPC_POSIX_SOCKET_TCP
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
- #ifdef GRPC_POSIX_SOCKET_TCP
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 // GRPC_POSIX_SOCKET_TCP
612
+ #else // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
600
613
  grpc_core::Crash(
601
614
  "EventEngine::CreateListener is not supported on this platform");
602
- #endif // GRPC_POSIX_SOCKET_TCP
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
- #ifdef GRPC_POSIX_SOCKET_TCP
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 // GRPC_POSIX_SOCKET_TCP
629
+ #else // GRPC_PLATFORM_SUPPORTS_POSIX_POLLING
617
630
  grpc_core::Crash(
618
631
  "EventEngine::CreateListener is not supported on this platform");
619
- #endif // GRPC_POSIX_SOCKET_TCP
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;