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 <grpc/support/port_platform.h>
20 
21 #include "src/core/ext/transport/chttp2/transport/frame_settings.h"
22 
23 #include <string.h>
24 
25 #include <initializer_list>
26 #include <string>
27 
28 #include "absl/base/attributes.h"
29 #include "absl/status/status.h"
30 #include "absl/strings/str_format.h"
31 #include "absl/strings/string_view.h"
32 
33 #include <grpc/slice_buffer.h>
34 #include <grpc/support/log.h>
35 
36 #include "src/core/ext/transport/chttp2/transport/flow_control.h"
37 #include "src/core/ext/transport/chttp2/transport/frame.h"
38 #include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
39 #include "src/core/ext/transport/chttp2/transport/http_trace.h"
40 #include "src/core/ext/transport/chttp2/transport/internal.h"
41 #include "src/core/lib/debug/trace.h"
42 #include "src/core/lib/gpr/useful.h"
43 #include "src/core/lib/gprpp/debug_location.h"
44 #include "src/core/lib/iomgr/exec_ctx.h"
45 #include "src/core/lib/slice/slice.h"
46 
fill_header(uint8_t * out,uint32_t length,uint8_t flags)47 static uint8_t* fill_header(uint8_t* out, uint32_t length, uint8_t flags) {
48   *out++ = static_cast<uint8_t>(length >> 16);
49   *out++ = static_cast<uint8_t>(length >> 8);
50   *out++ = static_cast<uint8_t>(length);
51   *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
52   *out++ = flags;
53   *out++ = 0;
54   *out++ = 0;
55   *out++ = 0;
56   *out++ = 0;
57   return out;
58 }
59 
grpc_chttp2_settings_create(uint32_t * old_settings,const uint32_t * new_settings,uint32_t force_mask,size_t count)60 grpc_slice grpc_chttp2_settings_create(uint32_t* old_settings,
61                                        const uint32_t* new_settings,
62                                        uint32_t force_mask, size_t count) {
63   size_t i;
64   uint32_t n = 0;
65   grpc_slice output;
66   uint8_t* p;
67 
68   for (i = 0; i < count; i++) {
69     n += (new_settings[i] != old_settings[i] || (force_mask & (1u << i)) != 0);
70   }
71 
72   output = GRPC_SLICE_MALLOC(9 + 6 * n);
73   p = fill_header(GRPC_SLICE_START_PTR(output), 6 * n, 0);
74 
75   for (i = 0; i < count; i++) {
76     if (new_settings[i] != old_settings[i] || (force_mask & (1u << i)) != 0) {
77       *p++ = static_cast<uint8_t>(grpc_setting_id_to_wire_id[i] >> 8);
78       *p++ = static_cast<uint8_t>(grpc_setting_id_to_wire_id[i]);
79       *p++ = static_cast<uint8_t>(new_settings[i] >> 24);
80       *p++ = static_cast<uint8_t>(new_settings[i] >> 16);
81       *p++ = static_cast<uint8_t>(new_settings[i] >> 8);
82       *p++ = static_cast<uint8_t>(new_settings[i]);
83       old_settings[i] = new_settings[i];
84     }
85   }
86 
87   GPR_ASSERT(p == GRPC_SLICE_END_PTR(output));
88 
89   return output;
90 }
91 
grpc_chttp2_settings_ack_create(void)92 grpc_slice grpc_chttp2_settings_ack_create(void) {
93   grpc_slice output = GRPC_SLICE_MALLOC(9);
94   fill_header(GRPC_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
95   return output;
96 }
97 
grpc_chttp2_settings_parser_begin_frame(grpc_chttp2_settings_parser * parser,uint32_t length,uint8_t flags,uint32_t * settings)98 grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
99     grpc_chttp2_settings_parser* parser, uint32_t length, uint8_t flags,
100     uint32_t* settings) {
101   parser->target_settings = settings;
102   memcpy(parser->incoming_settings, settings,
103          GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
104   parser->is_ack = 0;
105   parser->state = GRPC_CHTTP2_SPS_ID0;
106   if (flags == GRPC_CHTTP2_FLAG_ACK) {
107     parser->is_ack = 1;
108     if (length != 0) {
109       return GRPC_ERROR_CREATE("non-empty settings ack frame received");
110     }
111     return absl::OkStatus();
112   } else if (flags != 0) {
113     return GRPC_ERROR_CREATE("invalid flags on settings frame");
114   } else if (length % 6 != 0) {
115     return GRPC_ERROR_CREATE("settings frames must be a multiple of six bytes");
116   } else {
117     return absl::OkStatus();
118   }
119 }
120 
grpc_chttp2_settings_parser_parse(void * p,grpc_chttp2_transport * t,grpc_chttp2_stream *,const grpc_slice & slice,int is_last)121 grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
122                                                     grpc_chttp2_transport* t,
123                                                     grpc_chttp2_stream* /*s*/,
124                                                     const grpc_slice& slice,
125                                                     int is_last) {
126   grpc_chttp2_settings_parser* parser =
127       static_cast<grpc_chttp2_settings_parser*>(p);
128   const uint8_t* cur = GRPC_SLICE_START_PTR(slice);
129   const uint8_t* end = GRPC_SLICE_END_PTR(slice);
130   grpc_chttp2_setting_id id;
131 
132   if (parser->is_ack) {
133     return absl::OkStatus();
134   }
135 
136   for (;;) {
137     switch (parser->state) {
138       case GRPC_CHTTP2_SPS_ID0:
139         if (cur == end) {
140           parser->state = GRPC_CHTTP2_SPS_ID0;
141           if (is_last) {
142             memcpy(parser->target_settings, parser->incoming_settings,
143                    GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
144             t->num_pending_induced_frames++;
145             grpc_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
146             grpc_chttp2_initiate_write(t,
147                                        GRPC_CHTTP2_INITIATE_WRITE_SETTINGS_ACK);
148             if (t->notify_on_receive_settings != nullptr) {
149               grpc_core::ExecCtx::Run(DEBUG_LOCATION,
150                                       t->notify_on_receive_settings,
151                                       absl::OkStatus());
152               t->notify_on_receive_settings = nullptr;
153             }
154           }
155           return absl::OkStatus();
156         }
157         parser->id = static_cast<uint16_t>((static_cast<uint16_t>(*cur)) << 8);
158         cur++;
159         ABSL_FALLTHROUGH_INTENDED;
160       case GRPC_CHTTP2_SPS_ID1:
161         if (cur == end) {
162           parser->state = GRPC_CHTTP2_SPS_ID1;
163           return absl::OkStatus();
164         }
165         parser->id = static_cast<uint16_t>(parser->id | (*cur));
166         cur++;
167         ABSL_FALLTHROUGH_INTENDED;
168       case GRPC_CHTTP2_SPS_VAL0:
169         if (cur == end) {
170           parser->state = GRPC_CHTTP2_SPS_VAL0;
171           return absl::OkStatus();
172         }
173         parser->value = (static_cast<uint32_t>(*cur)) << 24;
174         cur++;
175         ABSL_FALLTHROUGH_INTENDED;
176       case GRPC_CHTTP2_SPS_VAL1:
177         if (cur == end) {
178           parser->state = GRPC_CHTTP2_SPS_VAL1;
179           return absl::OkStatus();
180         }
181         parser->value |= (static_cast<uint32_t>(*cur)) << 16;
182         cur++;
183         ABSL_FALLTHROUGH_INTENDED;
184       case GRPC_CHTTP2_SPS_VAL2:
185         if (cur == end) {
186           parser->state = GRPC_CHTTP2_SPS_VAL2;
187           return absl::OkStatus();
188         }
189         parser->value |= (static_cast<uint32_t>(*cur)) << 8;
190         cur++;
191         ABSL_FALLTHROUGH_INTENDED;
192       case GRPC_CHTTP2_SPS_VAL3:
193         if (cur == end) {
194           parser->state = GRPC_CHTTP2_SPS_VAL3;
195           return absl::OkStatus();
196         } else {
197           parser->state = GRPC_CHTTP2_SPS_ID0;
198         }
199         parser->value |= *cur;
200         cur++;
201 
202         if (grpc_wire_id_to_setting_id(parser->id, &id)) {
203           const grpc_chttp2_setting_parameters* sp =
204               &grpc_chttp2_settings_parameters[id];
205           if (parser->value < sp->min_value || parser->value > sp->max_value) {
206             switch (sp->invalid_value_behavior) {
207               case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
208                 parser->value = grpc_core::Clamp(parser->value, sp->min_value,
209                                                  sp->max_value);
210                 break;
211               case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
212                 grpc_chttp2_goaway_append(
213                     t->last_new_stream_id, sp->error_value,
214                     grpc_slice_from_static_string("HTTP2 settings error"),
215                     &t->qbuf);
216                 return GRPC_ERROR_CREATE(absl::StrFormat(
217                     "invalid value %u passed for %s", parser->value, sp->name));
218             }
219           }
220           if (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
221               parser->incoming_settings[id] != parser->value) {
222             t->initial_window_update += static_cast<int64_t>(parser->value) -
223                                         parser->incoming_settings[id];
224             if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) ||
225                 GRPC_TRACE_FLAG_ENABLED(grpc_flowctl_trace)) {
226               gpr_log(GPR_INFO, "%p[%s] adding %d for initial_window change", t,
227                       t->is_client ? "cli" : "svr",
228                       static_cast<int>(t->initial_window_update));
229             }
230           }
231           parser->incoming_settings[id] = parser->value;
232           if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
233             gpr_log(GPR_INFO, "CHTTP2:%s:%s: got setting %s = %d",
234                     t->is_client ? "CLI" : "SVR",
235                     std::string(t->peer_string.as_string_view()).c_str(),
236                     sp->name, parser->value);
237           }
238         } else if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
239           gpr_log(GPR_DEBUG, "CHTTP2: Ignoring unknown setting %d (value %d)",
240                   parser->id, parser->value);
241         }
242         break;
243     }
244   }
245 }
246