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