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