grpc 1.53.0 → 1.53.2
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/include/grpc/impl/grpc_types.h +11 -2
- data/src/core/ext/filters/client_channel/http_proxy.cc +1 -1
- data/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc +1 -1
- data/src/core/ext/transport/chttp2/transport/bin_encoder.cc +12 -8
- data/src/core/ext/transport/chttp2/transport/bin_encoder.h +5 -1
- data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +33 -2
- data/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +118 -222
- data/src/core/ext/transport/chttp2/transport/hpack_encoder.h +295 -113
- data/src/core/ext/transport/chttp2/transport/hpack_encoder_table.cc +2 -0
- data/src/core/ext/transport/chttp2/transport/hpack_encoder_table.h +2 -0
- data/src/core/ext/transport/chttp2/transport/hpack_parser.cc +466 -273
- data/src/core/ext/transport/chttp2/transport/hpack_parser.h +7 -3
- data/src/core/ext/transport/chttp2/transport/hpack_parser_table.cc +14 -12
- data/src/core/ext/transport/chttp2/transport/hpack_parser_table.h +9 -1
- data/src/core/ext/transport/chttp2/transport/internal.h +2 -0
- data/src/core/ext/transport/chttp2/transport/parsing.cc +6 -0
- data/src/core/lib/backoff/random_early_detection.cc +31 -0
- data/src/core/lib/backoff/random_early_detection.h +59 -0
- 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/endpoint_pair.h +2 -2
- data/src/core/lib/iomgr/endpoint_pair_posix.cc +2 -2
- data/src/core/lib/iomgr/endpoint_pair_windows.cc +1 -1
- 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 +43 -42
- data/src/core/lib/surface/validate_metadata.h +9 -0
- data/src/core/lib/transport/metadata_batch.cc +4 -4
- data/src/core/lib/transport/metadata_batch.h +153 -15
- data/src/core/lib/transport/parsed_metadata.h +19 -9
- data/src/ruby/lib/grpc/version.rb +1 -1
- metadata +5 -3
@@ -29,6 +29,7 @@
|
|
29
29
|
|
30
30
|
#include "src/core/ext/transport/chttp2/transport/frame.h"
|
31
31
|
#include "src/core/ext/transport/chttp2/transport/hpack_parser_table.h"
|
32
|
+
#include "src/core/lib/backoff/random_early_detection.h"
|
32
33
|
#include "src/core/lib/iomgr/error.h"
|
33
34
|
#include "src/core/lib/transport/metadata_batch.h"
|
34
35
|
|
@@ -80,7 +81,8 @@ class HPackParser {
|
|
80
81
|
// Begin parsing a new frame
|
81
82
|
// Sink receives each parsed header,
|
82
83
|
void BeginFrame(grpc_metadata_batch* metadata_buffer,
|
83
|
-
uint32_t
|
84
|
+
uint32_t metadata_size_soft_limit,
|
85
|
+
uint32_t metadata_size_hard_limit, Boundary boundary,
|
84
86
|
Priority priority, LogInfo log_info);
|
85
87
|
// Start throwing away any received headers after parsing them.
|
86
88
|
void StopBufferingFrame() { metadata_buffer_ = nullptr; }
|
@@ -103,7 +105,9 @@ class HPackParser {
|
|
103
105
|
class String;
|
104
106
|
|
105
107
|
grpc_error_handle ParseInput(Input input, bool is_last);
|
106
|
-
|
108
|
+
void ParseInputInner(Input* input);
|
109
|
+
GPR_ATTRIBUTE_NOINLINE
|
110
|
+
void HandleMetadataSoftSizeLimitExceeded(Input* input);
|
107
111
|
|
108
112
|
// Target metadata buffer
|
109
113
|
grpc_metadata_batch* metadata_buffer_ = nullptr;
|
@@ -121,7 +125,7 @@ class HPackParser {
|
|
121
125
|
uint8_t dynamic_table_updates_allowed_;
|
122
126
|
// Length of frame so far.
|
123
127
|
uint32_t frame_length_;
|
124
|
-
|
128
|
+
RandomEarlyDetection metadata_early_detection_;
|
125
129
|
// Information for logging
|
126
130
|
LogInfo log_info_;
|
127
131
|
|
@@ -82,8 +82,8 @@ void HPackTable::MementoRingBuffer::Rebuild(uint32_t max_entries) {
|
|
82
82
|
// Evict one element from the table
|
83
83
|
void HPackTable::EvictOne() {
|
84
84
|
auto first_entry = entries_.PopOne();
|
85
|
-
GPR_ASSERT(first_entry.transport_size() <= mem_used_);
|
86
|
-
mem_used_ -= first_entry.transport_size();
|
85
|
+
GPR_ASSERT(first_entry.md.transport_size() <= mem_used_);
|
86
|
+
mem_used_ -= first_entry.md.transport_size();
|
87
87
|
}
|
88
88
|
|
89
89
|
void HPackTable::SetMaxBytes(uint32_t max_bytes) {
|
@@ -104,7 +104,7 @@ grpc_error_handle HPackTable::SetCurrentTableSize(uint32_t bytes) {
|
|
104
104
|
return absl::OkStatus();
|
105
105
|
}
|
106
106
|
if (bytes > max_bytes_) {
|
107
|
-
return
|
107
|
+
return absl::InternalError(absl::StrFormat(
|
108
108
|
"Attempt to make hpack table %d bytes when max is %d bytes", bytes,
|
109
109
|
max_bytes_));
|
110
110
|
}
|
@@ -130,7 +130,7 @@ grpc_error_handle HPackTable::Add(Memento md) {
|
|
130
130
|
}
|
131
131
|
|
132
132
|
// we can't add elements bigger than the max table size
|
133
|
-
if (md.transport_size() > current_table_bytes_) {
|
133
|
+
if (md.md.transport_size() > current_table_bytes_) {
|
134
134
|
// HPACK draft 10 section 4.4 states:
|
135
135
|
// If the size of the new entry is less than or equal to the maximum
|
136
136
|
// size, that entry is added to the table. It is not an error to
|
@@ -145,13 +145,13 @@ grpc_error_handle HPackTable::Add(Memento md) {
|
|
145
145
|
}
|
146
146
|
|
147
147
|
// evict entries to ensure no overflow
|
148
|
-
while (md.transport_size() >
|
148
|
+
while (md.md.transport_size() >
|
149
149
|
static_cast<size_t>(current_table_bytes_) - mem_used_) {
|
150
150
|
EvictOne();
|
151
151
|
}
|
152
152
|
|
153
153
|
// copy the finalized entry in
|
154
|
-
mem_used_ += md.transport_size();
|
154
|
+
mem_used_ += md.md.transport_size();
|
155
155
|
entries_.Put(std::move(md));
|
156
156
|
return absl::OkStatus();
|
157
157
|
}
|
@@ -228,12 +228,14 @@ const StaticTableEntry kStaticTable[hpack_constants::kLastStaticEntry] = {
|
|
228
228
|
|
229
229
|
HPackTable::Memento MakeMemento(size_t i) {
|
230
230
|
auto sm = kStaticTable[i];
|
231
|
-
return
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
231
|
+
return HPackTable::Memento{
|
232
|
+
grpc_metadata_batch::Parse(
|
233
|
+
sm.key, Slice::FromStaticString(sm.value),
|
234
|
+
strlen(sm.key) + strlen(sm.value) + hpack_constants::kEntryOverhead,
|
235
|
+
[](absl::string_view, const Slice&) {
|
236
|
+
abort(); // not expecting to see this
|
237
|
+
}),
|
238
|
+
absl::OkStatus()};
|
237
239
|
}
|
238
240
|
|
239
241
|
} // namespace
|
@@ -25,6 +25,8 @@
|
|
25
25
|
|
26
26
|
#include <vector>
|
27
27
|
|
28
|
+
#include "absl/status/status.h"
|
29
|
+
|
28
30
|
#include "src/core/ext/transport/chttp2/transport/hpack_constants.h"
|
29
31
|
#include "src/core/lib/gprpp/no_destruct.h"
|
30
32
|
#include "src/core/lib/iomgr/error.h"
|
@@ -45,7 +47,10 @@ class HPackTable {
|
|
45
47
|
void SetMaxBytes(uint32_t max_bytes);
|
46
48
|
grpc_error_handle SetCurrentTableSize(uint32_t bytes);
|
47
49
|
|
48
|
-
|
50
|
+
struct Memento {
|
51
|
+
ParsedMetadata<grpc_metadata_batch> md;
|
52
|
+
absl::Status parse_status;
|
53
|
+
};
|
49
54
|
|
50
55
|
// Lookup, but don't ref.
|
51
56
|
const Memento* Lookup(uint32_t index) const {
|
@@ -68,6 +73,9 @@ class HPackTable {
|
|
68
73
|
// Current entry count in the table.
|
69
74
|
uint32_t num_entries() const { return entries_.num_entries(); }
|
70
75
|
|
76
|
+
// Current size of the table.
|
77
|
+
uint32_t test_only_table_size() const { return mem_used_; }
|
78
|
+
|
71
79
|
private:
|
72
80
|
struct StaticMementos {
|
73
81
|
StaticMementos();
|
@@ -457,6 +457,8 @@ struct grpc_chttp2_transport
|
|
457
457
|
bool keepalive_ping_started = false;
|
458
458
|
/// keep-alive state machine state
|
459
459
|
grpc_chttp2_keepalive_state keepalive_state;
|
460
|
+
// Soft limit on max header size.
|
461
|
+
uint32_t max_header_list_size_soft_limit = 0;
|
460
462
|
grpc_core::ContextList* cl = nullptr;
|
461
463
|
grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode> channelz_socket;
|
462
464
|
uint32_t num_messages_in_next_write = 0;
|
@@ -475,6 +475,9 @@ static grpc_error_handle init_header_skip_frame_parser(
|
|
475
475
|
"header", grpc_chttp2_header_parser_parse, &t->hpack_parser};
|
476
476
|
t->hpack_parser.BeginFrame(
|
477
477
|
nullptr,
|
478
|
+
/*metadata_size_soft_limit=*/
|
479
|
+
t->max_header_list_size_soft_limit,
|
480
|
+
/*metadata_size_hard_limit=*/
|
478
481
|
t->settings[GRPC_ACKED_SETTINGS]
|
479
482
|
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE],
|
480
483
|
hpack_boundary_type(t, is_eoh), priority_type,
|
@@ -691,6 +694,9 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
|
|
691
694
|
}
|
692
695
|
t->hpack_parser.BeginFrame(
|
693
696
|
incoming_metadata_buffer,
|
697
|
+
/*metadata_size_soft_limit=*/
|
698
|
+
t->max_header_list_size_soft_limit,
|
699
|
+
/*metadata_size_hard_limit=*/
|
694
700
|
t->settings[GRPC_ACKED_SETTINGS]
|
695
701
|
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE],
|
696
702
|
hpack_boundary_type(t, is_eoh), priority_type,
|
@@ -0,0 +1,31 @@
|
|
1
|
+
// Copyright 2023 gRPC authors.
|
2
|
+
//
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
// you may not use this file except in compliance with the License.
|
5
|
+
// You may obtain a copy of the License at
|
6
|
+
//
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
//
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
// See the License for the specific language governing permissions and
|
13
|
+
// limitations under the License.
|
14
|
+
|
15
|
+
#include <grpc/support/port_platform.h>
|
16
|
+
|
17
|
+
#include "src/core/lib/backoff/random_early_detection.h"
|
18
|
+
|
19
|
+
namespace grpc_core {
|
20
|
+
|
21
|
+
bool RandomEarlyDetection::Reject(uint64_t size) {
|
22
|
+
if (size <= soft_limit_) return false;
|
23
|
+
if (size < hard_limit_) {
|
24
|
+
return absl::Bernoulli(bitgen_,
|
25
|
+
static_cast<double>(size - soft_limit_) /
|
26
|
+
static_cast<double>(hard_limit_ - soft_limit_));
|
27
|
+
}
|
28
|
+
return true;
|
29
|
+
}
|
30
|
+
|
31
|
+
} // namespace grpc_core
|
@@ -0,0 +1,59 @@
|
|
1
|
+
// Copyright 2023 gRPC authors.
|
2
|
+
//
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
// you may not use this file except in compliance with the License.
|
5
|
+
// You may obtain a copy of the License at
|
6
|
+
//
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
//
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
// See the License for the specific language governing permissions and
|
13
|
+
// limitations under the License.
|
14
|
+
|
15
|
+
#ifndef GRPC_SRC_CORE_LIB_BACKOFF_RANDOM_EARLY_DETECTION_H
|
16
|
+
#define GRPC_SRC_CORE_LIB_BACKOFF_RANDOM_EARLY_DETECTION_H
|
17
|
+
|
18
|
+
#include <grpc/support/port_platform.h>
|
19
|
+
|
20
|
+
#include <limits.h>
|
21
|
+
|
22
|
+
#include <cstdint>
|
23
|
+
|
24
|
+
#include "absl/random/random.h"
|
25
|
+
|
26
|
+
namespace grpc_core {
|
27
|
+
|
28
|
+
// Implements the random early detection algorithm - allows items to be rejected
|
29
|
+
// or accepted based upon their size.
|
30
|
+
class RandomEarlyDetection {
|
31
|
+
public:
|
32
|
+
RandomEarlyDetection() : soft_limit_(INT_MAX), hard_limit_(INT_MAX) {}
|
33
|
+
RandomEarlyDetection(uint64_t soft_limit, uint64_t hard_limit)
|
34
|
+
: soft_limit_(soft_limit), hard_limit_(hard_limit) {}
|
35
|
+
|
36
|
+
// Returns true if the size is greater than or equal to the hard limit - ie if
|
37
|
+
// this item must be rejected.
|
38
|
+
bool MustReject(uint64_t size) { return size >= hard_limit_; }
|
39
|
+
|
40
|
+
// Returns true if the item should be rejected.
|
41
|
+
bool Reject(uint64_t size);
|
42
|
+
|
43
|
+
uint64_t soft_limit() const { return soft_limit_; }
|
44
|
+
uint64_t hard_limit() const { return hard_limit_; }
|
45
|
+
|
46
|
+
private:
|
47
|
+
// The soft limit is the size at which we start rejecting items with a
|
48
|
+
// probability that increases linearly to 1 as the size approaches the hard
|
49
|
+
// limit.
|
50
|
+
uint64_t soft_limit_;
|
51
|
+
// The hard limit is the size at which we reject all items.
|
52
|
+
uint64_t hard_limit_;
|
53
|
+
// The bit generator used to generate random numbers.
|
54
|
+
absl::InsecureBitGen bitgen_;
|
55
|
+
};
|
56
|
+
|
57
|
+
} // namespace grpc_core
|
58
|
+
|
59
|
+
#endif // GRPC_SRC_CORE_LIB_BACKOFF_RANDOM_EARLY_DETECTION_H
|
@@ -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;
|
@@ -23,7 +23,9 @@
|
|
23
23
|
#include <sys/socket.h> // IWYU pragma: keep
|
24
24
|
#include <unistd.h> // IWYU pragma: keep
|
25
25
|
|
26
|
+
#include <atomic>
|
26
27
|
#include <string>
|
28
|
+
#include <tuple>
|
27
29
|
#include <utility>
|
28
30
|
|
29
31
|
#include "absl/functional/any_invocable.h"
|
@@ -41,6 +43,7 @@
|
|
41
43
|
#include "src/core/lib/event_engine/posix_engine/tcp_socket_utils.h"
|
42
44
|
#include "src/core/lib/event_engine/tcp_socket_utils.h"
|
43
45
|
#include "src/core/lib/gprpp/status_helper.h"
|
46
|
+
#include "src/core/lib/gprpp/time.h"
|
44
47
|
#include "src/core/lib/iomgr/socket_mutator.h"
|
45
48
|
|
46
49
|
namespace grpc_event_engine {
|
@@ -133,6 +136,32 @@ void PosixEngineListenerImpl::AsyncConnectionAcceptor::NotifyOnAccept(
|
|
133
136
|
switch (errno) {
|
134
137
|
case EINTR:
|
135
138
|
continue;
|
139
|
+
case EMFILE:
|
140
|
+
// When the process runs out of fds, accept4() returns EMFILE. When
|
141
|
+
// this happens, the connection is left in the accept queue until
|
142
|
+
// either a read event triggers the on_read callback, or time has
|
143
|
+
// passed and the accept should be re-tried regardless. This callback
|
144
|
+
// is not cancelled, so a spurious wakeup may occur even when there's
|
145
|
+
// nothing to accept. This is not a performant code path, but if an fd
|
146
|
+
// limit has been reached, the system is likely in an unhappy state
|
147
|
+
// regardless.
|
148
|
+
GRPC_LOG_EVERY_N_SEC(1, "%s",
|
149
|
+
"File descriptor limit reached. Retrying.");
|
150
|
+
handle_->NotifyOnRead(notify_on_accept_);
|
151
|
+
// Do not schedule another timer if one is already armed.
|
152
|
+
if (retry_timer_armed_.exchange(true)) return;
|
153
|
+
// Hold a ref while the retry timer is waiting, to prevent listener
|
154
|
+
// destruction and the races that would ensue.
|
155
|
+
Ref();
|
156
|
+
std::ignore =
|
157
|
+
engine_->RunAfter(grpc_core::Duration::Seconds(1), [this]() {
|
158
|
+
retry_timer_armed_.store(false);
|
159
|
+
if (!handle_->IsHandleShutdown()) {
|
160
|
+
handle_->SetReadable();
|
161
|
+
}
|
162
|
+
Unref();
|
163
|
+
});
|
164
|
+
return;
|
136
165
|
case EAGAIN:
|
137
166
|
case ECONNABORTED:
|
138
167
|
handle_->NotifyOnRead(notify_on_accept_);
|
@@ -121,6 +121,9 @@ class PosixEngineListenerImpl
|
|
121
121
|
ListenerSocketsContainer::ListenerSocket socket_;
|
122
122
|
EventHandle* handle_;
|
123
123
|
PosixEngineClosure* notify_on_accept_;
|
124
|
+
// Tracks the status of a backup timer to retry accept4 calls after file
|
125
|
+
// descriptor exhaustion.
|
126
|
+
std::atomic<bool> retry_timer_armed_{false};
|
124
127
|
};
|
125
128
|
class ListenerAsyncAcceptors : public ListenerSocketsContainer {
|
126
129
|
public:
|
@@ -28,7 +28,7 @@ struct grpc_endpoint_pair {
|
|
28
28
|
grpc_endpoint* server;
|
29
29
|
};
|
30
30
|
|
31
|
-
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
|
32
|
-
|
31
|
+
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
|
32
|
+
const char* name, const grpc_channel_args* args);
|
33
33
|
|
34
34
|
#endif // GRPC_SRC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H
|
@@ -55,8 +55,8 @@ static void create_sockets(int sv[2]) {
|
|
55
55
|
GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]) == absl::OkStatus());
|
56
56
|
}
|
57
57
|
|
58
|
-
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
|
59
|
-
|
58
|
+
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
|
59
|
+
const char* name, const grpc_channel_args* args) {
|
60
60
|
int sv[2];
|
61
61
|
grpc_endpoint_pair p;
|
62
62
|
create_sockets(sv);
|
@@ -80,7 +80,7 @@ static void create_sockets(SOCKET sv[2]) {
|
|
80
80
|
}
|
81
81
|
|
82
82
|
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
|
83
|
-
const char*, grpc_channel_args* channel_args) {
|
83
|
+
const char*, const grpc_channel_args* /* channel_args */) {
|
84
84
|
SOCKET sv[2];
|
85
85
|
grpc_endpoint_pair p;
|
86
86
|
create_sockets(sv);
|
@@ -16,13 +16,17 @@
|
|
16
16
|
//
|
17
17
|
//
|
18
18
|
|
19
|
+
#include <grpc/support/port_platform.h>
|
20
|
+
|
21
|
+
#include <utility>
|
22
|
+
|
23
|
+
#include <grpc/support/atm.h>
|
24
|
+
|
19
25
|
// FIXME: "posix" files shouldn't be depending on _GNU_SOURCE
|
20
26
|
#ifndef _GNU_SOURCE
|
21
27
|
#define _GNU_SOURCE
|
22
28
|
#endif
|
23
29
|
|
24
|
-
#include <grpc/support/port_platform.h>
|
25
|
-
|
26
30
|
#include "src/core/lib/iomgr/port.h"
|
27
31
|
|
28
32
|
#ifdef GRPC_POSIX_SOCKET_TCP_SERVER
|
@@ -45,6 +49,7 @@
|
|
45
49
|
|
46
50
|
#include <grpc/byte_buffer.h>
|
47
51
|
#include <grpc/event_engine/endpoint_config.h>
|
52
|
+
#include <grpc/event_engine/event_engine.h>
|
48
53
|
#include <grpc/support/alloc.h>
|
49
54
|
#include <grpc/support/log.h>
|
50
55
|
#include <grpc/support/sync.h>
|
@@ -74,6 +79,8 @@
|
|
74
79
|
#include "src/core/lib/transport/error_utils.h"
|
75
80
|
|
76
81
|
static std::atomic<int64_t> num_dropped_connections{0};
|
82
|
+
static constexpr grpc_core::Duration kRetryAcceptWaitTime{
|
83
|
+
grpc_core::Duration::Seconds(1)};
|
77
84
|
|
78
85
|
using ::grpc_event_engine::experimental::EndpointConfig;
|
79
86
|
using ::grpc_event_engine::experimental::EventEngine;
|
@@ -350,22 +357,38 @@ static void on_read(void* arg, grpc_error_handle err) {
|
|
350
357
|
if (fd < 0) {
|
351
358
|
if (errno == EINTR) {
|
352
359
|
continue;
|
353
|
-
}
|
354
|
-
|
360
|
+
}
|
361
|
+
// When the process runs out of fds, accept4() returns EMFILE. When this
|
362
|
+
// happens, the connection is left in the accept queue until either a
|
363
|
+
// read event triggers the on_read callback, or time has passed and the
|
364
|
+
// accept should be re-tried regardless. This callback is not cancelled,
|
365
|
+
// so a spurious wakeup may occur even when there's nothing to accept.
|
366
|
+
// This is not a performant code path, but if an fd limit has been
|
367
|
+
// reached, the system is likely in an unhappy state regardless.
|
368
|
+
if (errno == EMFILE) {
|
369
|
+
GRPC_LOG_EVERY_N_SEC(1, "%s",
|
370
|
+
"File descriptor limit reached. Retrying.");
|
371
|
+
grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
|
372
|
+
if (gpr_atm_full_xchg(&sp->retry_timer_armed, true)) return;
|
373
|
+
grpc_timer_init(&sp->retry_timer,
|
374
|
+
grpc_core::Timestamp::Now() + kRetryAcceptWaitTime,
|
375
|
+
&sp->retry_closure);
|
376
|
+
return;
|
377
|
+
}
|
378
|
+
if (errno == EAGAIN || errno == ECONNABORTED || errno == EWOULDBLOCK) {
|
355
379
|
grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
|
356
380
|
return;
|
381
|
+
}
|
382
|
+
gpr_mu_lock(&sp->server->mu);
|
383
|
+
if (!sp->server->shutdown_listeners) {
|
384
|
+
gpr_log(GPR_ERROR, "Failed accept4: %s",
|
385
|
+
grpc_core::StrError(errno).c_str());
|
357
386
|
} else {
|
358
|
-
|
359
|
-
|
360
|
-
gpr_log(GPR_ERROR, "Failed accept4: %s",
|
361
|
-
grpc_core::StrError(errno).c_str());
|
362
|
-
} else {
|
363
|
-
// if we have shutdown listeners, accept4 could fail, and we
|
364
|
-
// needn't notify users
|
365
|
-
}
|
366
|
-
gpr_mu_unlock(&sp->server->mu);
|
367
|
-
goto error;
|
387
|
+
// if we have shutdown listeners, accept4 could fail, and we
|
388
|
+
// needn't notify users
|
368
389
|
}
|
390
|
+
gpr_mu_unlock(&sp->server->mu);
|
391
|
+
goto error;
|
369
392
|
}
|
370
393
|
|
371
394
|
if (sp->server->memory_quota->IsMemoryPressureHigh()) {
|
@@ -558,6 +581,7 @@ static grpc_error_handle clone_port(grpc_tcp_listener* listener,
|
|
558
581
|
sp->port_index = listener->port_index;
|
559
582
|
sp->fd_index = listener->fd_index + count - i;
|
560
583
|
GPR_ASSERT(sp->emfd);
|
584
|
+
grpc_tcp_server_listener_initialize_retry_timer(sp);
|
561
585
|
while (listener->server->tail->next != nullptr) {
|
562
586
|
listener->server->tail = listener->server->tail->next;
|
563
587
|
}
|
@@ -791,6 +815,7 @@ static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {
|
|
791
815
|
if (s->active_ports) {
|
792
816
|
grpc_tcp_listener* sp;
|
793
817
|
for (sp = s->head; sp; sp = sp->next) {
|
818
|
+
grpc_timer_cancel(&sp->retry_timer);
|
794
819
|
grpc_fd_shutdown(sp->emfd, GRPC_ERROR_CREATE("Server shutdown"));
|
795
820
|
}
|
796
821
|
}
|
@@ -30,6 +30,7 @@
|
|
30
30
|
#include "src/core/lib/iomgr/resolve_address.h"
|
31
31
|
#include "src/core/lib/iomgr/socket_utils_posix.h"
|
32
32
|
#include "src/core/lib/iomgr/tcp_server.h"
|
33
|
+
#include "src/core/lib/iomgr/timer.h"
|
33
34
|
#include "src/core/lib/resource_quota/memory_quota.h"
|
34
35
|
|
35
36
|
// one listening port
|
@@ -52,6 +53,11 @@ typedef struct grpc_tcp_listener {
|
|
52
53
|
// identified while iterating through 'next'.
|
53
54
|
struct grpc_tcp_listener* sibling;
|
54
55
|
int is_sibling;
|
56
|
+
// If an accept4() call fails, a timer is started to drain the accept queue in
|
57
|
+
// case no further connection attempts reach the gRPC server.
|
58
|
+
grpc_closure retry_closure;
|
59
|
+
grpc_timer retry_timer;
|
60
|
+
gpr_atm retry_timer_armed;
|
55
61
|
} grpc_tcp_listener;
|
56
62
|
|
57
63
|
// the overall server
|
@@ -139,4 +145,10 @@ grpc_error_handle grpc_tcp_server_prepare_socket(
|
|
139
145
|
// Ruturn true if the platform supports ifaddrs
|
140
146
|
bool grpc_tcp_server_have_ifaddrs(void);
|
141
147
|
|
148
|
+
// Initialize (but don't start) the timer and callback to retry accept4() on a
|
149
|
+
// listening socket after file descriptors have been exhausted. This must be
|
150
|
+
// called when creating a new listener.
|
151
|
+
void grpc_tcp_server_listener_initialize_retry_timer(
|
152
|
+
grpc_tcp_listener* listener);
|
153
|
+
|
142
154
|
#endif // GRPC_SRC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H
|
@@ -18,6 +18,8 @@
|
|
18
18
|
|
19
19
|
#include <grpc/support/port_platform.h>
|
20
20
|
|
21
|
+
#include <grpc/support/atm.h>
|
22
|
+
|
21
23
|
#include "src/core/lib/iomgr/port.h"
|
22
24
|
|
23
25
|
#ifdef GRPC_POSIX_SOCKET_TCP_SERVER_UTILS_COMMON
|
@@ -81,6 +83,24 @@ static int get_max_accept_queue_size(void) {
|
|
81
83
|
return s_max_accept_queue_size;
|
82
84
|
}
|
83
85
|
|
86
|
+
static void listener_retry_timer_cb(void* arg, grpc_error_handle err) {
|
87
|
+
// Do nothing if cancelled.
|
88
|
+
if (!err.ok()) return;
|
89
|
+
grpc_tcp_listener* listener = static_cast<grpc_tcp_listener*>(arg);
|
90
|
+
gpr_atm_no_barrier_store(&listener->retry_timer_armed, false);
|
91
|
+
if (!grpc_fd_is_shutdown(listener->emfd)) {
|
92
|
+
grpc_fd_set_readable(listener->emfd);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
void grpc_tcp_server_listener_initialize_retry_timer(
|
97
|
+
grpc_tcp_listener* listener) {
|
98
|
+
gpr_atm_no_barrier_store(&listener->retry_timer_armed, false);
|
99
|
+
grpc_timer_init_unset(&listener->retry_timer);
|
100
|
+
GRPC_CLOSURE_INIT(&listener->retry_closure, listener_retry_timer_cb, listener,
|
101
|
+
grpc_schedule_on_exec_ctx);
|
102
|
+
}
|
103
|
+
|
84
104
|
static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, int fd,
|
85
105
|
const grpc_resolved_address* addr,
|
86
106
|
unsigned port_index,
|
@@ -112,6 +132,7 @@ static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, int fd,
|
|
112
132
|
sp->server = s;
|
113
133
|
sp->fd = fd;
|
114
134
|
sp->emfd = grpc_fd_create(fd, name.c_str(), true);
|
135
|
+
grpc_tcp_server_listener_initialize_retry_timer(sp);
|
115
136
|
|
116
137
|
// Check and set fd as prellocated
|
117
138
|
if (grpc_tcp_server_pre_allocated_fd(s) == fd) {
|
@@ -21,46 +21,20 @@
|
|
21
21
|
#include "src/core/lib/surface/validate_metadata.h"
|
22
22
|
|
23
23
|
#include "absl/status/status.h"
|
24
|
+
#include "absl/strings/escaping.h"
|
25
|
+
#include "absl/strings/str_cat.h"
|
24
26
|
#include "absl/strings/string_view.h"
|
25
27
|
|
26
28
|
#include <grpc/grpc.h>
|
27
29
|
|
28
|
-
#include "src/core/lib/gpr/string.h"
|
29
30
|
#include "src/core/lib/gprpp/bitset.h"
|
30
|
-
#include "src/core/lib/gprpp/memory.h"
|
31
|
-
#include "src/core/lib/gprpp/status_helper.h"
|
32
31
|
#include "src/core/lib/iomgr/error.h"
|
32
|
+
#include "src/core/lib/slice/slice_internal.h"
|
33
33
|
|
34
|
-
|
35
|
-
const grpc_core::BitSet<256>& legal_bits,
|
36
|
-
const char* err_desc) {
|
37
|
-
const uint8_t* p = GRPC_SLICE_START_PTR(slice);
|
38
|
-
const uint8_t* e = GRPC_SLICE_END_PTR(slice);
|
39
|
-
for (; p != e; p++) {
|
40
|
-
if (!legal_bits.is_set(*p)) {
|
41
|
-
size_t len;
|
42
|
-
grpc_core::UniquePtr<char> ptr(gpr_dump_return_len(
|
43
|
-
reinterpret_cast<const char*> GRPC_SLICE_START_PTR(slice),
|
44
|
-
GRPC_SLICE_LENGTH(slice), GPR_DUMP_HEX | GPR_DUMP_ASCII, &len));
|
45
|
-
grpc_error_handle error = grpc_error_set_str(
|
46
|
-
grpc_error_set_int(GRPC_ERROR_CREATE(err_desc),
|
47
|
-
grpc_core::StatusIntProperty::kOffset,
|
48
|
-
p - GRPC_SLICE_START_PTR(slice)),
|
49
|
-
grpc_core::StatusStrProperty::kRawBytes,
|
50
|
-
absl::string_view(ptr.get(), len));
|
51
|
-
return error;
|
52
|
-
}
|
53
|
-
}
|
54
|
-
return absl::OkStatus();
|
55
|
-
}
|
56
|
-
|
57
|
-
static int error2int(grpc_error_handle error) {
|
58
|
-
int r = (error.ok());
|
59
|
-
return r;
|
60
|
-
}
|
34
|
+
namespace grpc_core {
|
61
35
|
|
62
36
|
namespace {
|
63
|
-
class LegalHeaderKeyBits : public
|
37
|
+
class LegalHeaderKeyBits : public BitSet<256> {
|
64
38
|
public:
|
65
39
|
constexpr LegalHeaderKeyBits() {
|
66
40
|
for (int i = 'a'; i <= 'z'; i++) set(i);
|
@@ -71,19 +45,45 @@ class LegalHeaderKeyBits : public grpc_core::BitSet<256> {
|
|
71
45
|
}
|
72
46
|
};
|
73
47
|
constexpr LegalHeaderKeyBits g_legal_header_key_bits;
|
74
|
-
} // namespace
|
75
48
|
|
76
|
-
|
77
|
-
|
78
|
-
|
49
|
+
GPR_ATTRIBUTE_NOINLINE
|
50
|
+
absl::Status DoesNotConformTo(absl::string_view x, const char* err_desc) {
|
51
|
+
return absl::InternalError(absl::StrCat(err_desc, ": ", x, " (hex ",
|
52
|
+
absl::BytesToHexString(x), ")"));
|
53
|
+
}
|
54
|
+
|
55
|
+
absl::Status ConformsTo(absl::string_view x, const BitSet<256>& legal_bits,
|
56
|
+
const char* err_desc) {
|
57
|
+
for (uint8_t c : x) {
|
58
|
+
if (!legal_bits.is_set(c)) {
|
59
|
+
return DoesNotConformTo(x, err_desc);
|
60
|
+
}
|
79
61
|
}
|
80
|
-
|
81
|
-
|
62
|
+
return absl::OkStatus();
|
63
|
+
}
|
64
|
+
} // namespace
|
65
|
+
|
66
|
+
absl::Status ValidateHeaderKeyIsLegal(absl::string_view key) {
|
67
|
+
if (key.empty()) {
|
68
|
+
return absl::InternalError("Metadata keys cannot be zero length");
|
82
69
|
}
|
83
|
-
if (
|
84
|
-
return
|
70
|
+
if (key.size() > UINT32_MAX) {
|
71
|
+
return absl::InternalError(
|
72
|
+
"Metadata keys cannot be larger than UINT32_MAX");
|
85
73
|
}
|
86
|
-
return
|
74
|
+
return ConformsTo(key, g_legal_header_key_bits, "Illegal header key");
|
75
|
+
}
|
76
|
+
|
77
|
+
} // namespace grpc_core
|
78
|
+
|
79
|
+
static int error2int(grpc_error_handle error) {
|
80
|
+
int r = (error.ok());
|
81
|
+
return r;
|
82
|
+
}
|
83
|
+
|
84
|
+
grpc_error_handle grpc_validate_header_key_is_legal(const grpc_slice& slice) {
|
85
|
+
return grpc_core::ValidateHeaderKeyIsLegal(
|
86
|
+
grpc_core::StringViewFromSlice(slice));
|
87
87
|
}
|
88
88
|
|
89
89
|
int grpc_header_key_is_legal(grpc_slice slice) {
|
@@ -104,8 +104,9 @@ constexpr LegalHeaderNonBinValueBits g_legal_header_non_bin_value_bits;
|
|
104
104
|
|
105
105
|
grpc_error_handle grpc_validate_header_nonbin_value_is_legal(
|
106
106
|
const grpc_slice& slice) {
|
107
|
-
return
|
108
|
-
|
107
|
+
return grpc_core::ConformsTo(grpc_core::StringViewFromSlice(slice),
|
108
|
+
g_legal_header_non_bin_value_bits,
|
109
|
+
"Illegal header value");
|
109
110
|
}
|
110
111
|
|
111
112
|
int grpc_header_nonbin_value_is_legal(grpc_slice slice) {
|