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