grpc 1.53.0 → 1.53.2
Sign up to get free protection for your applications and to get access to all the features.
- 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) {
|