• 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 <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