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 30 void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser* p) { 31 p->debug_data = nullptr; 32 } 33 34 void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser* p) { 35 gpr_free(p->debug_data); 36 } 37 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 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 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