• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/core/ext/transport/chttp2/transport/frame_settings.h"
20 
21 #include <grpc/slice_buffer.h>
22 #include <grpc/support/port_platform.h>
23 #include <string.h>
24 
25 #include <string>
26 
27 #include "absl/base/attributes.h"
28 #include "absl/log/log.h"
29 #include "absl/status/status.h"
30 #include "absl/strings/str_format.h"
31 #include "src/core/ext/transport/chttp2/transport/flow_control.h"
32 #include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
33 #include "src/core/ext/transport/chttp2/transport/http2_settings.h"
34 #include "src/core/ext/transport/chttp2/transport/internal.h"
35 #include "src/core/ext/transport/chttp2/transport/legacy_frame.h"
36 #include "src/core/lib/debug/trace.h"
37 #include "src/core/lib/iomgr/exec_ctx.h"
38 #include "src/core/lib/slice/slice.h"
39 #include "src/core/telemetry/stats.h"
40 #include "src/core/util/debug_location.h"
41 #include "src/core/util/useful.h"
42 
fill_header(uint8_t * out,uint32_t length,uint8_t flags)43 static uint8_t* fill_header(uint8_t* out, uint32_t length, uint8_t flags) {
44   *out++ = static_cast<uint8_t>(length >> 16);
45   *out++ = static_cast<uint8_t>(length >> 8);
46   *out++ = static_cast<uint8_t>(length);
47   *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
48   *out++ = flags;
49   *out++ = 0;
50   *out++ = 0;
51   *out++ = 0;
52   *out++ = 0;
53   return out;
54 }
55 
grpc_chttp2_settings_ack_create(void)56 grpc_slice grpc_chttp2_settings_ack_create(void) {
57   grpc_slice output = GRPC_SLICE_MALLOC(9);
58   fill_header(GRPC_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
59   return output;
60 }
61 
grpc_chttp2_settings_parser_begin_frame(grpc_chttp2_settings_parser * parser,uint32_t length,uint8_t flags,grpc_core::Http2Settings & settings)62 grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
63     grpc_chttp2_settings_parser* parser, uint32_t length, uint8_t flags,
64     grpc_core::Http2Settings& settings) {
65   parser->target_settings = &settings;
66   parser->incoming_settings.Init(settings);
67   parser->is_ack = 0;
68   parser->state = GRPC_CHTTP2_SPS_ID0;
69   if (flags == GRPC_CHTTP2_FLAG_ACK) {
70     parser->is_ack = 1;
71     if (length != 0) {
72       return GRPC_ERROR_CREATE("non-empty settings ack frame received");
73     }
74     return absl::OkStatus();
75   } else if (flags != 0) {
76     return GRPC_ERROR_CREATE("invalid flags on settings frame");
77   } else if (length % 6 != 0) {
78     return GRPC_ERROR_CREATE("settings frames must be a multiple of six bytes");
79   } else {
80     return absl::OkStatus();
81   }
82 }
83 
grpc_chttp2_settings_parser_parse(void * p,grpc_chttp2_transport * t,grpc_chttp2_stream *,const grpc_slice & slice,int is_last)84 grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
85                                                     grpc_chttp2_transport* t,
86                                                     grpc_chttp2_stream* /*s*/,
87                                                     const grpc_slice& slice,
88                                                     int is_last) {
89   grpc_chttp2_settings_parser* parser =
90       static_cast<grpc_chttp2_settings_parser*>(p);
91   const uint8_t* cur = GRPC_SLICE_START_PTR(slice);
92   const uint8_t* end = GRPC_SLICE_END_PTR(slice);
93 
94   if (parser->is_ack) {
95     return absl::OkStatus();
96   }
97 
98   for (;;) {
99     switch (parser->state) {
100       case GRPC_CHTTP2_SPS_ID0:
101         if (cur == end) {
102           parser->state = GRPC_CHTTP2_SPS_ID0;
103           if (is_last) {
104             grpc_core::Http2Settings* target_settings =
105                 parser->incoming_settings.get();
106             grpc_core::global_stats().IncrementHttp2HeaderTableSize(
107                 target_settings->header_table_size());
108             grpc_core::global_stats().IncrementHttp2InitialWindowSize(
109                 target_settings->initial_window_size());
110             grpc_core::global_stats().IncrementHttp2MaxConcurrentStreams(
111                 target_settings->max_concurrent_streams());
112             grpc_core::global_stats().IncrementHttp2MaxFrameSize(
113                 target_settings->max_frame_size());
114             grpc_core::global_stats().IncrementHttp2MaxHeaderListSize(
115                 target_settings->max_header_list_size());
116             grpc_core::global_stats()
117                 .IncrementHttp2PreferredReceiveCryptoMessageSize(
118                     target_settings->preferred_receive_crypto_message_size());
119             *parser->target_settings = *parser->incoming_settings;
120             t->num_pending_induced_frames++;
121             grpc_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
122             grpc_chttp2_initiate_write(t,
123                                        GRPC_CHTTP2_INITIATE_WRITE_SETTINGS_ACK);
124             if (t->notify_on_receive_settings != nullptr) {
125               if (t->interested_parties_until_recv_settings != nullptr) {
126                 grpc_endpoint_delete_from_pollset_set(
127                     t->ep.get(), t->interested_parties_until_recv_settings);
128                 t->interested_parties_until_recv_settings = nullptr;
129               }
130               grpc_core::ExecCtx::Run(DEBUG_LOCATION,
131                                       t->notify_on_receive_settings,
132                                       absl::OkStatus());
133               t->notify_on_receive_settings = nullptr;
134             }
135           }
136           return absl::OkStatus();
137         }
138         parser->id = static_cast<uint16_t>((static_cast<uint16_t>(*cur)) << 8);
139         cur++;
140         ABSL_FALLTHROUGH_INTENDED;
141       case GRPC_CHTTP2_SPS_ID1:
142         if (cur == end) {
143           parser->state = GRPC_CHTTP2_SPS_ID1;
144           return absl::OkStatus();
145         }
146         parser->id = static_cast<uint16_t>(parser->id | (*cur));
147         cur++;
148         ABSL_FALLTHROUGH_INTENDED;
149       case GRPC_CHTTP2_SPS_VAL0:
150         if (cur == end) {
151           parser->state = GRPC_CHTTP2_SPS_VAL0;
152           return absl::OkStatus();
153         }
154         parser->value = (static_cast<uint32_t>(*cur)) << 24;
155         cur++;
156         ABSL_FALLTHROUGH_INTENDED;
157       case GRPC_CHTTP2_SPS_VAL1:
158         if (cur == end) {
159           parser->state = GRPC_CHTTP2_SPS_VAL1;
160           return absl::OkStatus();
161         }
162         parser->value |= (static_cast<uint32_t>(*cur)) << 16;
163         cur++;
164         ABSL_FALLTHROUGH_INTENDED;
165       case GRPC_CHTTP2_SPS_VAL2:
166         if (cur == end) {
167           parser->state = GRPC_CHTTP2_SPS_VAL2;
168           return absl::OkStatus();
169         }
170         parser->value |= (static_cast<uint32_t>(*cur)) << 8;
171         cur++;
172         ABSL_FALLTHROUGH_INTENDED;
173       case GRPC_CHTTP2_SPS_VAL3: {
174         if (cur == end) {
175           parser->state = GRPC_CHTTP2_SPS_VAL3;
176           return absl::OkStatus();
177         } else {
178           parser->state = GRPC_CHTTP2_SPS_ID0;
179         }
180         parser->value |= *cur;
181         cur++;
182 
183         if (parser->id == grpc_core::Http2Settings::kInitialWindowSizeWireId) {
184           t->initial_window_update +=
185               static_cast<int64_t>(parser->value) -
186               parser->incoming_settings->initial_window_size();
187           if (GRPC_TRACE_FLAG_ENABLED(http) ||
188               GRPC_TRACE_FLAG_ENABLED(flowctl)) {
189             LOG(INFO) << t << "[" << (t->is_client ? "cli" : "svr")
190                       << "] adding " << t->initial_window_update
191                       << " for initial_window change";
192           }
193         }
194         auto error =
195             parser->incoming_settings->Apply(parser->id, parser->value);
196         if (error != GRPC_HTTP2_NO_ERROR) {
197           grpc_chttp2_goaway_append(
198               t->last_new_stream_id, error,
199               grpc_slice_from_static_string("HTTP2 settings error"), &t->qbuf);
200           return GRPC_ERROR_CREATE(absl::StrFormat(
201               "invalid value %u passed for %s", parser->value,
202               grpc_core::Http2Settings::WireIdToName(parser->id).c_str()));
203         }
204         GRPC_TRACE_LOG(http, INFO)
205             << "CHTTP2:" << (t->is_client ? "CLI" : "SVR") << ":"
206             << t->peer_string.as_string_view() << ": got setting "
207             << grpc_core::Http2Settings::WireIdToName(parser->id) << " = "
208             << parser->value;
209       } break;
210     }
211   }
212 }
213