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_ping.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 static bool g_disable_ping_ack = false; 31 32 grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) { 33 grpc_slice slice = GRPC_SLICE_MALLOC(9 + 8); 34 uint8_t* p = GRPC_SLICE_START_PTR(slice); 35 36 *p++ = 0; 37 *p++ = 0; 38 *p++ = 8; 39 *p++ = GRPC_CHTTP2_FRAME_PING; 40 *p++ = ack ? 1 : 0; 41 *p++ = 0; 42 *p++ = 0; 43 *p++ = 0; 44 *p++ = 0; 45 *p++ = static_cast<uint8_t>(opaque_8bytes >> 56); 46 *p++ = static_cast<uint8_t>(opaque_8bytes >> 48); 47 *p++ = static_cast<uint8_t>(opaque_8bytes >> 40); 48 *p++ = static_cast<uint8_t>(opaque_8bytes >> 32); 49 *p++ = static_cast<uint8_t>(opaque_8bytes >> 24); 50 *p++ = static_cast<uint8_t>(opaque_8bytes >> 16); 51 *p++ = static_cast<uint8_t>(opaque_8bytes >> 8); 52 *p++ = static_cast<uint8_t>(opaque_8bytes); 53 54 return slice; 55 } 56 57 grpc_error* grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser* parser, 58 uint32_t length, 59 uint8_t flags) { 60 if (flags & 0xfe || length != 8) { 61 char* msg; 62 gpr_asprintf(&msg, "invalid ping: length=%d, flags=%02x", length, flags); 63 grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); 64 gpr_free(msg); 65 return error; 66 } 67 parser->byte = 0; 68 parser->is_ack = flags; 69 parser->opaque_8bytes = 0; 70 return GRPC_ERROR_NONE; 71 } 72 73 grpc_error* grpc_chttp2_ping_parser_parse(void* parser, 74 grpc_chttp2_transport* t, 75 grpc_chttp2_stream* s, 76 grpc_slice slice, int is_last) { 77 uint8_t* const beg = GRPC_SLICE_START_PTR(slice); 78 uint8_t* const end = GRPC_SLICE_END_PTR(slice); 79 uint8_t* cur = beg; 80 grpc_chttp2_ping_parser* p = static_cast<grpc_chttp2_ping_parser*>(parser); 81 82 while (p->byte != 8 && cur != end) { 83 p->opaque_8bytes |= ((static_cast<uint64_t>(*cur)) << (56 - 8 * p->byte)); 84 cur++; 85 p->byte++; 86 } 87 88 if (p->byte == 8) { 89 GPR_ASSERT(is_last); 90 if (p->is_ack) { 91 grpc_chttp2_ack_ping(t, p->opaque_8bytes); 92 } else { 93 if (!t->is_client) { 94 grpc_millis now = grpc_core::ExecCtx::Get()->Now(); 95 grpc_millis next_allowed_ping = 96 t->ping_recv_state.last_ping_recv_time + 97 t->ping_policy.min_recv_ping_interval_without_data; 98 99 if (t->keepalive_permit_without_calls == 0 && 100 grpc_chttp2_stream_map_size(&t->stream_map) == 0) { 101 /* According to RFC1122, the interval of TCP Keep-Alive is default to 102 no less than two hours. When there is no outstanding streams, we 103 restrict the number of PINGS equivalent to TCP Keep-Alive. */ 104 next_allowed_ping = 105 t->ping_recv_state.last_ping_recv_time + 7200 * GPR_MS_PER_SEC; 106 } 107 108 if (next_allowed_ping > now) { 109 grpc_chttp2_add_ping_strike(t); 110 } 111 112 t->ping_recv_state.last_ping_recv_time = now; 113 } 114 if (!g_disable_ping_ack) { 115 if (t->ping_ack_count == t->ping_ack_capacity) { 116 t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3); 117 t->ping_acks = static_cast<uint64_t*>(gpr_realloc( 118 t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks))); 119 } 120 t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes; 121 grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_PING_RESPONSE); 122 } 123 } 124 } 125 126 return GRPC_ERROR_NONE; 127 } 128 129 void grpc_set_disable_ping_ack(bool disable_ping_ack) { 130 g_disable_ping_ack = disable_ping_ack; 131 } 132