Home | History | Annotate | Download | only in transport
      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