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 <grpc/support/alloc.h>
27 #include <grpc/support/log.h>
28 #include <grpc/support/string_util.h>
29
grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser * p)30 void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser* p) {
31 p->debug_data = nullptr;
32 }
33
grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser * p)34 void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser* p) {
35 gpr_free(p->debug_data);
36 }
37
grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser * p,uint32_t length,uint8_t flags)38 grpc_error* grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser* p,
39 uint32_t length,
40 uint8_t flags) {
41 if (length < 8) {
42 char* msg;
43 gpr_asprintf(&msg, "goaway frame too short (%d bytes)", length);
44 grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
45 gpr_free(msg);
46 return err;
47 }
48
49 gpr_free(p->debug_data);
50 p->debug_length = length - 8;
51 p->debug_data = static_cast<char*>(gpr_malloc(p->debug_length));
52 p->debug_pos = 0;
53 p->state = GRPC_CHTTP2_GOAWAY_LSI0;
54 return GRPC_ERROR_NONE;
55 }
56
grpc_chttp2_goaway_parser_parse(void * parser,grpc_chttp2_transport * t,grpc_chttp2_stream * s,grpc_slice slice,int is_last)57 grpc_error* grpc_chttp2_goaway_parser_parse(void* parser,
58 grpc_chttp2_transport* t,
59 grpc_chttp2_stream* s,
60 grpc_slice slice, int is_last) {
61 uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
62 uint8_t* const end = GRPC_SLICE_END_PTR(slice);
63 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 GRPC_ERROR_NONE;
72 }
73 p->last_stream_id = (static_cast<uint32_t>(*cur)) << 24;
74 ++cur;
75 /* fallthrough */
76 case GRPC_CHTTP2_GOAWAY_LSI1:
77 if (cur == end) {
78 p->state = GRPC_CHTTP2_GOAWAY_LSI1;
79 return GRPC_ERROR_NONE;
80 }
81 p->last_stream_id |= (static_cast<uint32_t>(*cur)) << 16;
82 ++cur;
83 /* fallthrough */
84 case GRPC_CHTTP2_GOAWAY_LSI2:
85 if (cur == end) {
86 p->state = GRPC_CHTTP2_GOAWAY_LSI2;
87 return GRPC_ERROR_NONE;
88 }
89 p->last_stream_id |= (static_cast<uint32_t>(*cur)) << 8;
90 ++cur;
91 /* fallthrough */
92 case GRPC_CHTTP2_GOAWAY_LSI3:
93 if (cur == end) {
94 p->state = GRPC_CHTTP2_GOAWAY_LSI3;
95 return GRPC_ERROR_NONE;
96 }
97 p->last_stream_id |= (static_cast<uint32_t>(*cur));
98 ++cur;
99 /* fallthrough */
100 case GRPC_CHTTP2_GOAWAY_ERR0:
101 if (cur == end) {
102 p->state = GRPC_CHTTP2_GOAWAY_ERR0;
103 return GRPC_ERROR_NONE;
104 }
105 p->error_code = (static_cast<uint32_t>(*cur)) << 24;
106 ++cur;
107 /* fallthrough */
108 case GRPC_CHTTP2_GOAWAY_ERR1:
109 if (cur == end) {
110 p->state = GRPC_CHTTP2_GOAWAY_ERR1;
111 return GRPC_ERROR_NONE;
112 }
113 p->error_code |= (static_cast<uint32_t>(*cur)) << 16;
114 ++cur;
115 /* fallthrough */
116 case GRPC_CHTTP2_GOAWAY_ERR2:
117 if (cur == end) {
118 p->state = GRPC_CHTTP2_GOAWAY_ERR2;
119 return GRPC_ERROR_NONE;
120 }
121 p->error_code |= (static_cast<uint32_t>(*cur)) << 8;
122 ++cur;
123 /* fallthrough */
124 case GRPC_CHTTP2_GOAWAY_ERR3:
125 if (cur == end) {
126 p->state = GRPC_CHTTP2_GOAWAY_ERR3;
127 return GRPC_ERROR_NONE;
128 }
129 p->error_code |= (static_cast<uint32_t>(*cur));
130 ++cur;
131 /* fallthrough */
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 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,
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,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 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