• 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_goaway.h"
20 
21 #include <grpc/slice_buffer.h>
22 #include <grpc/support/alloc.h>
23 #include <grpc/support/port_platform.h>
24 #include <string.h>
25 
26 #include "absl/base/attributes.h"
27 #include "absl/log/check.h"
28 #include "absl/status/status.h"
29 #include "absl/strings/str_format.h"
30 #include "absl/strings/string_view.h"
31 #include "src/core/ext/transport/chttp2/transport/internal.h"
32 
grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser * p)33 void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser* p) {
34   p->debug_data = nullptr;
35 }
36 
grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser * p)37 void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser* p) {
38   gpr_free(p->debug_data);
39 }
40 
grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser * p,uint32_t length,uint8_t)41 grpc_error_handle grpc_chttp2_goaway_parser_begin_frame(
42     grpc_chttp2_goaway_parser* p, uint32_t length, uint8_t /*flags*/) {
43   if (length < 8) {
44     return GRPC_ERROR_CREATE(
45         absl::StrFormat("goaway frame too short (%d bytes)", length));
46   }
47 
48   gpr_free(p->debug_data);
49   p->debug_length = length - 8;
50   p->debug_data = static_cast<char*>(gpr_malloc(p->debug_length));
51   p->debug_pos = 0;
52   p->state = GRPC_CHTTP2_GOAWAY_LSI0;
53   return absl::OkStatus();
54 }
55 
grpc_chttp2_goaway_parser_parse(void * parser,grpc_chttp2_transport * t,grpc_chttp2_stream *,const grpc_slice & slice,int is_last)56 grpc_error_handle grpc_chttp2_goaway_parser_parse(void* parser,
57                                                   grpc_chttp2_transport* t,
58                                                   grpc_chttp2_stream* /*s*/,
59                                                   const grpc_slice& slice,
60                                                   int is_last) {
61   const uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
62   const uint8_t* const end = GRPC_SLICE_END_PTR(slice);
63   const uint8_t* cur = beg;
64   grpc_chttp2_goaway_parser* p =
65       static_cast<grpc_chttp2_goaway_parser*>(parser);
66 
67   switch (p->state) {
68     case GRPC_CHTTP2_GOAWAY_LSI0:
69       if (cur == end) {
70         p->state = GRPC_CHTTP2_GOAWAY_LSI0;
71         return absl::OkStatus();
72       }
73       p->last_stream_id = (static_cast<uint32_t>(*cur)) << 24;
74       ++cur;
75       ABSL_FALLTHROUGH_INTENDED;
76     case GRPC_CHTTP2_GOAWAY_LSI1:
77       if (cur == end) {
78         p->state = GRPC_CHTTP2_GOAWAY_LSI1;
79         return absl::OkStatus();
80       }
81       p->last_stream_id |= (static_cast<uint32_t>(*cur)) << 16;
82       ++cur;
83       ABSL_FALLTHROUGH_INTENDED;
84     case GRPC_CHTTP2_GOAWAY_LSI2:
85       if (cur == end) {
86         p->state = GRPC_CHTTP2_GOAWAY_LSI2;
87         return absl::OkStatus();
88       }
89       p->last_stream_id |= (static_cast<uint32_t>(*cur)) << 8;
90       ++cur;
91       ABSL_FALLTHROUGH_INTENDED;
92     case GRPC_CHTTP2_GOAWAY_LSI3:
93       if (cur == end) {
94         p->state = GRPC_CHTTP2_GOAWAY_LSI3;
95         return absl::OkStatus();
96       }
97       p->last_stream_id |= (static_cast<uint32_t>(*cur));
98       ++cur;
99       ABSL_FALLTHROUGH_INTENDED;
100     case GRPC_CHTTP2_GOAWAY_ERR0:
101       if (cur == end) {
102         p->state = GRPC_CHTTP2_GOAWAY_ERR0;
103         return absl::OkStatus();
104       }
105       p->error_code = (static_cast<uint32_t>(*cur)) << 24;
106       ++cur;
107       ABSL_FALLTHROUGH_INTENDED;
108     case GRPC_CHTTP2_GOAWAY_ERR1:
109       if (cur == end) {
110         p->state = GRPC_CHTTP2_GOAWAY_ERR1;
111         return absl::OkStatus();
112       }
113       p->error_code |= (static_cast<uint32_t>(*cur)) << 16;
114       ++cur;
115       ABSL_FALLTHROUGH_INTENDED;
116     case GRPC_CHTTP2_GOAWAY_ERR2:
117       if (cur == end) {
118         p->state = GRPC_CHTTP2_GOAWAY_ERR2;
119         return absl::OkStatus();
120       }
121       p->error_code |= (static_cast<uint32_t>(*cur)) << 8;
122       ++cur;
123       ABSL_FALLTHROUGH_INTENDED;
124     case GRPC_CHTTP2_GOAWAY_ERR3:
125       if (cur == end) {
126         p->state = GRPC_CHTTP2_GOAWAY_ERR3;
127         return absl::OkStatus();
128       }
129       p->error_code |= (static_cast<uint32_t>(*cur));
130       ++cur;
131       ABSL_FALLTHROUGH_INTENDED;
132     case GRPC_CHTTP2_GOAWAY_DEBUG:
133       if (end != cur) {
134         memcpy(p->debug_data + p->debug_pos, cur,
135                static_cast<size_t>(end - cur));
136       }
137       CHECK((size_t)(end - cur) < UINT32_MAX - p->debug_pos);
138       p->debug_pos += static_cast<uint32_t>(end - cur);
139       p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
140       if (is_last) {
141         grpc_chttp2_add_incoming_goaway(
142             t, p->error_code, p->last_stream_id,
143             absl::string_view(p->debug_data, p->debug_length));
144         gpr_free(p->debug_data);
145         p->debug_data = nullptr;
146       }
147       return absl::OkStatus();
148   }
149   GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
150 }
151 
grpc_chttp2_goaway_append(uint32_t last_stream_id,uint32_t error_code,const grpc_slice & debug_data,grpc_slice_buffer * slice_buffer)152 void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
153                                const grpc_slice& debug_data,
154                                grpc_slice_buffer* slice_buffer) {
155   grpc_slice header = GRPC_SLICE_MALLOC(9 + 4 + 4);
156   uint8_t* p = GRPC_SLICE_START_PTR(header);
157   uint32_t frame_length;
158   CHECK(GRPC_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4);
159   frame_length = 4 + 4 + static_cast<uint32_t> GRPC_SLICE_LENGTH(debug_data);
160 
161   // frame header: length
162   *p++ = static_cast<uint8_t>(frame_length >> 16);
163   *p++ = static_cast<uint8_t>(frame_length >> 8);
164   *p++ = static_cast<uint8_t>(frame_length);
165   // frame header: type
166   *p++ = GRPC_CHTTP2_FRAME_GOAWAY;
167   // frame header: flags
168   *p++ = 0;
169   // frame header: stream id
170   *p++ = 0;
171   *p++ = 0;
172   *p++ = 0;
173   *p++ = 0;
174   // payload: last stream id
175   *p++ = static_cast<uint8_t>(last_stream_id >> 24);
176   *p++ = static_cast<uint8_t>(last_stream_id >> 16);
177   *p++ = static_cast<uint8_t>(last_stream_id >> 8);
178   *p++ = static_cast<uint8_t>(last_stream_id);
179   // payload: error code
180   *p++ = static_cast<uint8_t>(error_code >> 24);
181   *p++ = static_cast<uint8_t>(error_code >> 16);
182   *p++ = static_cast<uint8_t>(error_code >> 8);
183   *p++ = static_cast<uint8_t>(error_code);
184   CHECK(p == GRPC_SLICE_END_PTR(header));
185   grpc_slice_buffer_add(slice_buffer, header);
186   grpc_slice_buffer_add(slice_buffer, debug_data);
187 }
188