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_window_update.h" 22 #include "src/core/ext/transport/chttp2/transport/internal.h" 23 24 #include <grpc/support/alloc.h> 25 #include <grpc/support/log.h> 26 #include <grpc/support/string_util.h> 27 28 grpc_slice grpc_chttp2_window_update_create( 29 uint32_t id, uint32_t window_update, grpc_transport_one_way_stats* stats) { 30 static const size_t frame_size = 13; 31 grpc_slice slice = GRPC_SLICE_MALLOC(frame_size); 32 stats->header_bytes += frame_size; 33 uint8_t* p = GRPC_SLICE_START_PTR(slice); 34 35 GPR_ASSERT(window_update); 36 37 *p++ = 0; 38 *p++ = 0; 39 *p++ = 4; 40 *p++ = GRPC_CHTTP2_FRAME_WINDOW_UPDATE; 41 *p++ = 0; 42 *p++ = static_cast<uint8_t>(id >> 24); 43 *p++ = static_cast<uint8_t>(id >> 16); 44 *p++ = static_cast<uint8_t>(id >> 8); 45 *p++ = static_cast<uint8_t>(id); 46 *p++ = static_cast<uint8_t>(window_update >> 24); 47 *p++ = static_cast<uint8_t>(window_update >> 16); 48 *p++ = static_cast<uint8_t>(window_update >> 8); 49 *p++ = static_cast<uint8_t>(window_update); 50 51 return slice; 52 } 53 54 grpc_error* grpc_chttp2_window_update_parser_begin_frame( 55 grpc_chttp2_window_update_parser* parser, uint32_t length, uint8_t flags) { 56 if (flags || length != 4) { 57 char* msg; 58 gpr_asprintf(&msg, "invalid window update: length=%d, flags=%02x", length, 59 flags); 60 grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); 61 gpr_free(msg); 62 return err; 63 } 64 parser->byte = 0; 65 parser->amount = 0; 66 return GRPC_ERROR_NONE; 67 } 68 69 grpc_error* grpc_chttp2_window_update_parser_parse(void* parser, 70 grpc_chttp2_transport* t, 71 grpc_chttp2_stream* s, 72 grpc_slice slice, 73 int is_last) { 74 uint8_t* const beg = GRPC_SLICE_START_PTR(slice); 75 uint8_t* const end = GRPC_SLICE_END_PTR(slice); 76 uint8_t* cur = beg; 77 grpc_chttp2_window_update_parser* p = 78 static_cast<grpc_chttp2_window_update_parser*>(parser); 79 80 while (p->byte != 4 && cur != end) { 81 p->amount |= (static_cast<uint32_t>(*cur)) << (8 * (3 - p->byte)); 82 cur++; 83 p->byte++; 84 } 85 86 if (s != nullptr) { 87 s->stats.incoming.framing_bytes += static_cast<uint32_t>(end - cur); 88 } 89 90 if (p->byte == 4) { 91 uint32_t received_update = p->amount; 92 if (received_update == 0 || (received_update & 0x80000000u)) { 93 char* msg; 94 gpr_asprintf(&msg, "invalid window update bytes: %d", p->amount); 95 grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); 96 gpr_free(msg); 97 return err; 98 } 99 GPR_ASSERT(is_last); 100 101 if (t->incoming_stream_id != 0) { 102 if (s != nullptr) { 103 s->flow_control->RecvUpdate(received_update); 104 if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) { 105 grpc_chttp2_mark_stream_writable(t, s); 106 grpc_chttp2_initiate_write( 107 t, GRPC_CHTTP2_INITIATE_WRITE_FLOW_CONTROL_UNSTALLED_BY_UPDATE); 108 } 109 } 110 } else { 111 bool was_zero = t->flow_control->remote_window() <= 0; 112 t->flow_control->RecvUpdate(received_update); 113 bool is_zero = t->flow_control->remote_window() <= 0; 114 if (was_zero && !is_zero) { 115 grpc_chttp2_initiate_write( 116 t, GRPC_CHTTP2_INITIATE_WRITE_TRANSPORT_FLOW_CONTROL_UNSTALLED); 117 } 118 } 119 } 120 121 return GRPC_ERROR_NONE; 122 } 123