Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include "src/core/transport/chttp2/frame_goaway.h"
35 : #include "src/core/transport/chttp2/internal.h"
36 :
37 : #include <string.h>
38 :
39 : #include <grpc/support/alloc.h>
40 : #include <grpc/support/log.h>
41 :
42 4014 : void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) {
43 4014 : p->debug_data = NULL;
44 4014 : }
45 :
46 4014 : void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p) {
47 4014 : gpr_free(p->debug_data);
48 4014 : }
49 :
50 229 : grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
51 : grpc_chttp2_goaway_parser *p, gpr_uint32 length, gpr_uint8 flags) {
52 229 : if (length < 8) {
53 0 : gpr_log(GPR_ERROR, "goaway frame too short (%d bytes)", length);
54 0 : return GRPC_CHTTP2_CONNECTION_ERROR;
55 : }
56 :
57 229 : gpr_free(p->debug_data);
58 229 : p->debug_length = length - 8;
59 229 : p->debug_data = gpr_malloc(p->debug_length);
60 229 : p->debug_pos = 0;
61 229 : p->state = GRPC_CHTTP2_GOAWAY_LSI0;
62 229 : return GRPC_CHTTP2_PARSE_OK;
63 : }
64 :
65 317 : grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
66 : grpc_exec_ctx *exec_ctx, void *parser,
67 : grpc_chttp2_transport_parsing *transport_parsing,
68 : grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
69 317 : gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
70 317 : gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
71 317 : gpr_uint8 *cur = beg;
72 317 : grpc_chttp2_goaway_parser *p = parser;
73 :
74 317 : switch (p->state) {
75 : case GRPC_CHTTP2_GOAWAY_LSI0:
76 229 : if (cur == end) {
77 0 : p->state = GRPC_CHTTP2_GOAWAY_LSI0;
78 0 : return GRPC_CHTTP2_PARSE_OK;
79 : }
80 229 : p->last_stream_id = ((gpr_uint32)*cur) << 24;
81 229 : ++cur;
82 : /* fallthrough */
83 : case GRPC_CHTTP2_GOAWAY_LSI1:
84 233 : if (cur == end) {
85 4 : p->state = GRPC_CHTTP2_GOAWAY_LSI1;
86 4 : return GRPC_CHTTP2_PARSE_OK;
87 : }
88 229 : p->last_stream_id |= ((gpr_uint32)*cur) << 16;
89 229 : ++cur;
90 : /* fallthrough */
91 : case GRPC_CHTTP2_GOAWAY_LSI2:
92 233 : if (cur == end) {
93 4 : p->state = GRPC_CHTTP2_GOAWAY_LSI2;
94 4 : return GRPC_CHTTP2_PARSE_OK;
95 : }
96 229 : p->last_stream_id |= ((gpr_uint32)*cur) << 8;
97 229 : ++cur;
98 : /* fallthrough */
99 : case GRPC_CHTTP2_GOAWAY_LSI3:
100 233 : if (cur == end) {
101 4 : p->state = GRPC_CHTTP2_GOAWAY_LSI3;
102 4 : return GRPC_CHTTP2_PARSE_OK;
103 : }
104 229 : p->last_stream_id |= ((gpr_uint32)*cur);
105 229 : ++cur;
106 : /* fallthrough */
107 : case GRPC_CHTTP2_GOAWAY_ERR0:
108 233 : if (cur == end) {
109 4 : p->state = GRPC_CHTTP2_GOAWAY_ERR0;
110 4 : return GRPC_CHTTP2_PARSE_OK;
111 : }
112 229 : p->error_code = ((gpr_uint32)*cur) << 24;
113 229 : ++cur;
114 : /* fallthrough */
115 : case GRPC_CHTTP2_GOAWAY_ERR1:
116 233 : if (cur == end) {
117 4 : p->state = GRPC_CHTTP2_GOAWAY_ERR1;
118 4 : return GRPC_CHTTP2_PARSE_OK;
119 : }
120 229 : p->error_code |= ((gpr_uint32)*cur) << 16;
121 229 : ++cur;
122 : /* fallthrough */
123 : case GRPC_CHTTP2_GOAWAY_ERR2:
124 233 : if (cur == end) {
125 4 : p->state = GRPC_CHTTP2_GOAWAY_ERR2;
126 4 : return GRPC_CHTTP2_PARSE_OK;
127 : }
128 229 : p->error_code |= ((gpr_uint32)*cur) << 8;
129 229 : ++cur;
130 : /* fallthrough */
131 : case GRPC_CHTTP2_GOAWAY_ERR3:
132 233 : if (cur == end) {
133 4 : p->state = GRPC_CHTTP2_GOAWAY_ERR3;
134 4 : return GRPC_CHTTP2_PARSE_OK;
135 : }
136 229 : p->error_code |= ((gpr_uint32)*cur);
137 229 : ++cur;
138 : /* fallthrough */
139 : case GRPC_CHTTP2_GOAWAY_DEBUG:
140 289 : memcpy(p->debug_data + p->debug_pos, cur, (size_t)(end - cur));
141 289 : GPR_ASSERT((size_t)(end - cur) < GPR_UINT32_MAX - p->debug_pos);
142 289 : p->debug_pos += (gpr_uint32)(end - cur);
143 289 : p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
144 289 : if (is_last) {
145 229 : transport_parsing->goaway_received = 1;
146 229 : transport_parsing->goaway_last_stream_index = p->last_stream_id;
147 229 : gpr_slice_unref(transport_parsing->goaway_text);
148 229 : transport_parsing->goaway_error = (grpc_status_code)p->error_code;
149 229 : transport_parsing->goaway_text =
150 229 : gpr_slice_new(p->debug_data, p->debug_length, gpr_free);
151 229 : p->debug_data = NULL;
152 : }
153 289 : return GRPC_CHTTP2_PARSE_OK;
154 : }
155 0 : GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
156 : }
157 :
158 1772 : void grpc_chttp2_goaway_append(gpr_uint32 last_stream_id, gpr_uint32 error_code,
159 : gpr_slice debug_data,
160 : gpr_slice_buffer *slice_buffer) {
161 1772 : gpr_slice header = gpr_slice_malloc(9 + 4 + 4);
162 1772 : gpr_uint8 *p = GPR_SLICE_START_PTR(header);
163 : gpr_uint32 frame_length;
164 1772 : GPR_ASSERT(GPR_SLICE_LENGTH(debug_data) < GPR_UINT32_MAX - 4 - 4);
165 1772 : frame_length = 4 + 4 + (gpr_uint32)GPR_SLICE_LENGTH(debug_data);
166 :
167 : /* frame header: length */
168 1772 : *p++ = (gpr_uint8)(frame_length >> 16);
169 1772 : *p++ = (gpr_uint8)(frame_length >> 8);
170 1772 : *p++ = (gpr_uint8)(frame_length);
171 : /* frame header: type */
172 1772 : *p++ = GRPC_CHTTP2_FRAME_GOAWAY;
173 : /* frame header: flags */
174 1772 : *p++ = 0;
175 : /* frame header: stream id */
176 1772 : *p++ = 0;
177 1772 : *p++ = 0;
178 1772 : *p++ = 0;
179 1772 : *p++ = 0;
180 : /* payload: last stream id */
181 1772 : *p++ = (gpr_uint8)(last_stream_id >> 24);
182 1772 : *p++ = (gpr_uint8)(last_stream_id >> 16);
183 1772 : *p++ = (gpr_uint8)(last_stream_id >> 8);
184 1772 : *p++ = (gpr_uint8)(last_stream_id);
185 : /* payload: error code */
186 1772 : *p++ = (gpr_uint8)(error_code >> 24);
187 1772 : *p++ = (gpr_uint8)(error_code >> 16);
188 1772 : *p++ = (gpr_uint8)(error_code >> 8);
189 1772 : *p++ = (gpr_uint8)(error_code);
190 1772 : GPR_ASSERT(p == GPR_SLICE_END_PTR(header));
191 1772 : gpr_slice_buffer_add(slice_buffer, header);
192 1772 : gpr_slice_buffer_add(slice_buffer, debug_data);
193 1772 : }
|