xref: /aosp_15_r20/external/grpc-grpc/src/core/ext/transport/chttp2/transport/ping_abuse_policy.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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/ext/transport/chttp2/transport/ping_abuse_policy.h"
18 
19 #include <algorithm>
20 
21 #include "absl/strings/str_cat.h"
22 #include "absl/types/optional.h"
23 
24 #include <grpc/impl/channel_arg_names.h>
25 
26 namespace grpc_core {
27 
28 namespace {
29 Duration g_default_min_recv_ping_interval_without_data = Duration::Minutes(5);
30 int g_default_max_ping_strikes = 2;
31 }  // namespace
32 
Chttp2PingAbusePolicy(const ChannelArgs & args)33 Chttp2PingAbusePolicy::Chttp2PingAbusePolicy(const ChannelArgs& args)
34     : min_recv_ping_interval_without_data_(std::max(
35           Duration::Zero(),
36           args.GetDurationFromIntMillis(
37                   GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS)
38               .value_or(g_default_min_recv_ping_interval_without_data))),
39       max_ping_strikes_(
40           std::max(0, args.GetInt(GRPC_ARG_HTTP2_MAX_PING_STRIKES)
41                           .value_or(g_default_max_ping_strikes))) {}
42 
SetDefaults(const ChannelArgs & args)43 void Chttp2PingAbusePolicy::SetDefaults(const ChannelArgs& args) {
44   g_default_max_ping_strikes =
45       std::max(0, args.GetInt(GRPC_ARG_HTTP2_MAX_PING_STRIKES)
46                       .value_or(g_default_max_ping_strikes));
47   g_default_min_recv_ping_interval_without_data =
48       std::max(Duration::Zero(),
49                args.GetDurationFromIntMillis(
50                        GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS)
51                    .value_or(g_default_min_recv_ping_interval_without_data));
52 }
53 
ReceivedOnePing(bool transport_idle)54 bool Chttp2PingAbusePolicy::ReceivedOnePing(bool transport_idle) {
55   const Timestamp now = Timestamp::Now();
56   const Timestamp next_allowed_ping =
57       last_ping_recv_time_ + RecvPingIntervalWithoutData(transport_idle);
58   last_ping_recv_time_ = now;
59   if (next_allowed_ping <= now) return false;
60   // Received ping too soon: increment strike count.
61   ++ping_strikes_;
62   return ping_strikes_ > max_ping_strikes_ && max_ping_strikes_ != 0;
63 }
64 
GetDebugString(bool transport_idle) const65 std::string Chttp2PingAbusePolicy::GetDebugString(bool transport_idle) const {
66   return absl::StrCat(
67       "now=", Timestamp::Now().ToString(), " transport_idle=", transport_idle,
68       " next_allowed_ping=",
69       (last_ping_recv_time_ + RecvPingIntervalWithoutData(transport_idle))
70           .ToString(),
71       " ping_strikes=", ping_strikes_);
72 }
73 
RecvPingIntervalWithoutData(bool transport_idle) const74 Duration Chttp2PingAbusePolicy::RecvPingIntervalWithoutData(
75     bool transport_idle) const {
76   if (transport_idle) {
77     // According to RFC1122, the interval of TCP Keep-Alive is default to
78     // no less than two hours. When there is no outstanding streams, we
79     // restrict the number of PINGS equivalent to TCP Keep-Alive.
80     return Duration::Hours(2);
81   }
82   return min_recv_ping_interval_without_data_;
83 }
84 
ResetPingStrikes()85 void Chttp2PingAbusePolicy::ResetPingStrikes() {
86   last_ping_recv_time_ = Timestamp::InfPast();
87   ping_strikes_ = 0;
88 }
89 
90 }  // namespace grpc_core
91