blob: b45bf319975c74fad4c90c5f1dfda4428db47c4b [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
murgatroid993466c4b2016-01-12 10:26:04 -08003 * Copyright 2015-2016, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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_transport.h"
35
36#include <math.h>
37#include <stdio.h>
38#include <string.h>
39
40#include <grpc/support/alloc.h>
41#include <grpc/support/log.h>
42#include <grpc/support/slice_buffer.h>
Craig Tiller285b8822015-06-17 15:58:13 -070043#include <grpc/support/string_util.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080044#include <grpc/support/useful.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080045
Craig Tiller08a1cf82015-06-29 09:37:52 -070046#include "src/core/profiling/timers.h"
47#include "src/core/support/string.h"
48#include "src/core/transport/chttp2/http2_errors.h"
49#include "src/core/transport/chttp2/internal.h"
50#include "src/core/transport/chttp2/status_conversion.h"
51#include "src/core/transport/chttp2/timeout_encoding.h"
Craig Tillerb2b42612015-11-20 12:02:17 -080052#include "src/core/transport/static_metadata.h"
Craig Tiller08a1cf82015-06-29 09:37:52 -070053#include "src/core/transport/transport_impl.h"
54
ctiller493fbcc2014-12-07 15:09:10 -080055#define DEFAULT_WINDOW 65535
56#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080057#define MAX_WINDOW 0x7fffffffu
58
Craig Tiller7098c032015-05-04 10:18:28 -070059#define MAX_CLIENT_STREAM_ID 0x7fffffffu
60
Craig Tillerfaa84802015-03-01 21:56:38 -080061int grpc_http_trace = 0;
Craig Tiller6a8c0382015-04-28 10:01:22 -070062int grpc_flowctl_trace = 0;
Craig Tillerfaa84802015-03-01 21:56:38 -080063
Craig Tiller4aa71a12015-06-15 13:00:55 -070064#define TRANSPORT_FROM_WRITING(tw) \
65 ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
66 writing)))
Craig Tillerd20efd22015-06-12 16:17:09 -070067
Craig Tillercfb5db92015-06-15 17:14:41 -070068#define TRANSPORT_FROM_PARSING(tw) \
69 ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
70 parsing)))
71
Craig Tiller98505102015-06-16 11:33:15 -070072#define TRANSPORT_FROM_GLOBAL(tg) \
Craig Tiller5dc3b302015-06-15 16:06:50 -070073 ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \
74 global)))
75
76#define STREAM_FROM_GLOBAL(sg) \
Craig Tiller98505102015-06-16 11:33:15 -070077 ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global)))
Craig Tiller5dc3b302015-06-15 16:06:50 -070078
Craig Tiller9d35a1f2015-11-02 14:16:12 -080079#define STREAM_FROM_PARSING(sg) \
80 ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, parsing)))
81
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080082static const grpc_transport_vtable vtable;
83
Craig Tillera82950e2015-09-22 12:33:20 -070084static void lock(grpc_chttp2_transport *t);
85static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080086
Craig Tiller4aa71a12015-06-15 13:00:55 -070087/* forward declarations of various callbacks that we'll build closures around */
Craig Tillera82950e2015-09-22 12:33:20 -070088static void writing_action(grpc_exec_ctx *exec_ctx, void *t,
Craig Tiller6c396862016-01-28 13:53:40 -080089 bool iomgr_success_ignored);
Craig Tiller99f80552015-06-11 16:26:03 -070090
Craig Tiller4aa71a12015-06-15 13:00:55 -070091/** Set a transport level setting, and push it to our peer */
Craig Tillera82950e2015-09-22 12:33:20 -070092static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
Craig Tiller7536af02015-12-22 13:49:30 -080093 uint32_t value);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080094
Craig Tiller4aa71a12015-06-15 13:00:55 -070095/** Endpoint callback to process incoming data */
Craig Tiller6c396862016-01-28 13:53:40 -080096static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success);
Craig Tiller4aa71a12015-06-15 13:00:55 -070097
98/** Start disconnection chain */
Craig Tillera82950e2015-09-22 12:33:20 -070099static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
Craig Tiller4aa71a12015-06-15 13:00:55 -0700100
Craig Tiller5dc3b302015-06-15 16:06:50 -0700101/** Perform a transport_op */
Craig Tillera82950e2015-09-22 12:33:20 -0700102static void perform_stream_op_locked(
103 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
104 grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700105
106/** Cancel a stream: coming from the transport API */
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800107static void cancel_from_api(grpc_exec_ctx *exec_ctx,
108 grpc_chttp2_transport_global *transport_global,
Craig Tillera82950e2015-09-22 12:33:20 -0700109 grpc_chttp2_stream_global *stream_global,
110 grpc_status_code status);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700111
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800112static void close_from_api(grpc_exec_ctx *exec_ctx,
113 grpc_chttp2_transport_global *transport_global,
Craig Tillera82950e2015-09-22 12:33:20 -0700114 grpc_chttp2_stream_global *stream_global,
115 grpc_status_code status,
116 gpr_slice *optional_message);
Craig Tiller45ce9272015-07-31 11:22:35 -0700117
Craig Tiller5dc3b302015-06-15 16:06:50 -0700118/** Add endpoint from this transport to pollset */
Craig Tillera82950e2015-09-22 12:33:20 -0700119static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
120 grpc_chttp2_transport *t,
121 grpc_pollset *pollset);
122static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
123 grpc_chttp2_transport *t,
124 grpc_pollset_set *pollset_set);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700125
Craig Tiller564872d2015-06-18 11:21:22 -0700126/** Start new streams that have been created if we can */
Craig Tillera82950e2015-09-22 12:33:20 -0700127static void maybe_start_some_streams(
128 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global);
Craig Tiller564872d2015-06-18 11:21:22 -0700129
Craig Tillera82950e2015-09-22 12:33:20 -0700130static void connectivity_state_set(
131 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
132 grpc_connectivity_state state, const char *reason);
Craig Tillerff3ae682015-06-29 17:44:04 -0700133
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800134static void check_read_ops(grpc_exec_ctx *exec_ctx,
135 grpc_chttp2_transport_global *transport_global);
136
Craig Tillerc8b70132015-12-09 20:49:09 -0800137static void incoming_byte_stream_update_flow_control(
138 grpc_chttp2_transport_global *transport_global,
139 grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
140 size_t have_already);
141
Craig Tillera3f298f2015-12-16 19:42:09 -0800142static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
Craig Tillerabb2e3d2015-12-15 06:23:59 -0800143 grpc_chttp2_stream_global *stream_global);
144
Craig Tiller0cb803d2016-03-02 22:17:24 -0800145/*******************************************************************************
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800146 * CONSTRUCTION/DESTRUCTION/REFCOUNTING
147 */
148
Craig Tillera82950e2015-09-22 12:33:20 -0700149static void destruct_transport(grpc_exec_ctx *exec_ctx,
150 grpc_chttp2_transport *t) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800151 size_t i;
152
Craig Tillera82950e2015-09-22 12:33:20 -0700153 gpr_mu_lock(&t->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800154
Craig Tillera82950e2015-09-22 12:33:20 -0700155 GPR_ASSERT(t->ep == NULL);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800156
Craig Tillera82950e2015-09-22 12:33:20 -0700157 gpr_slice_buffer_destroy(&t->global.qbuf);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700158
Craig Tillera82950e2015-09-22 12:33:20 -0700159 gpr_slice_buffer_destroy(&t->writing.outbuf);
160 grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700161
Craig Tillera82950e2015-09-22 12:33:20 -0700162 gpr_slice_buffer_destroy(&t->parsing.qbuf);
163 gpr_slice_buffer_destroy(&t->read_buffer);
164 grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
165 grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800166
Craig Tillera82950e2015-09-22 12:33:20 -0700167 for (i = 0; i < STREAM_LIST_COUNT; i++) {
168 GPR_ASSERT(t->lists[i].head == NULL);
169 GPR_ASSERT(t->lists[i].tail == NULL);
170 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800171
Craig Tillera82950e2015-09-22 12:33:20 -0700172 GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0);
173 GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800174
Craig Tillera82950e2015-09-22 12:33:20 -0700175 grpc_chttp2_stream_map_destroy(&t->parsing_stream_map);
176 grpc_chttp2_stream_map_destroy(&t->new_stream_map);
177 grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800178
Craig Tillera82950e2015-09-22 12:33:20 -0700179 gpr_mu_unlock(&t->mu);
180 gpr_mu_destroy(&t->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800181
182 /* callback remaining pings: they're not allowed to call into the transpot,
183 and maybe they hold resources that need to be freed */
Craig Tillera82950e2015-09-22 12:33:20 -0700184 while (t->global.pings.next != &t->global.pings) {
185 grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
Craig Tiller6c396862016-01-28 13:53:40 -0800186 grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, false, NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700187 ping->next->prev = ping->prev;
188 ping->prev->next = ping->next;
189 gpr_free(ping);
190 }
Craig Tiller8ed35ea2015-01-30 11:27:43 -0800191
Craig Tillera82950e2015-09-22 12:33:20 -0700192 gpr_free(t->peer_string);
193 gpr_free(t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800194}
195
Craig Tiller759eb322015-06-16 22:41:18 -0700196#ifdef REFCOUNTING_DEBUG
197#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
Craig Tiller8af4c332015-09-22 12:32:31 -0700198#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__)
Craig Tillera82950e2015-09-22 12:33:20 -0700199static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
200 const char *reason, const char *file, int line) {
201 gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count,
202 t->refs.count - 1, reason, file, line);
203 if (!gpr_unref(&t->refs)) return;
204 destruct_transport(exec_ctx, t);
Craig Tiller759eb322015-06-16 22:41:18 -0700205}
206
Craig Tillera82950e2015-09-22 12:33:20 -0700207static void ref_transport(grpc_chttp2_transport *t, const char *reason,
208 const char *file, int line) {
209 gpr_log(GPR_DEBUG, "chttp2: ref:%p %d->%d %s [%s:%d]", t, t->refs.count,
210 t->refs.count + 1, reason, file, line);
211 gpr_ref(&t->refs);
Craig Tiller759eb322015-06-16 22:41:18 -0700212}
213#else
214#define REF_TRANSPORT(t, r) ref_transport(t)
Craig Tiller8af4c332015-09-22 12:32:31 -0700215#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t)
Craig Tillera82950e2015-09-22 12:33:20 -0700216static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
217 if (!gpr_unref(&t->refs)) return;
218 destruct_transport(exec_ctx, t);
Craig Tiller9be83ee2015-02-18 14:16:15 -0800219}
220
Craig Tillera82950e2015-09-22 12:33:20 -0700221static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
Craig Tiller759eb322015-06-16 22:41:18 -0700222#endif
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800223
Craig Tillera82950e2015-09-22 12:33:20 -0700224static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
225 const grpc_channel_args *channel_args,
Craig Tiller7536af02015-12-22 13:49:30 -0800226 grpc_endpoint *ep, uint8_t is_client) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800227 size_t i;
228 int j;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800229
Craig Tillera82950e2015-09-22 12:33:20 -0700230 GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
231 GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800232
Craig Tillera82950e2015-09-22 12:33:20 -0700233 memset(t, 0, sizeof(*t));
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700234
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800235 t->base.vtable = &vtable;
236 t->ep = ep;
237 /* one ref is for destroy, the other for when ep becomes NULL */
Craig Tillera82950e2015-09-22 12:33:20 -0700238 gpr_ref_init(&t->refs, 2);
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700239 /* ref is dropped at transport close() */
Craig Tillera82950e2015-09-22 12:33:20 -0700240 gpr_ref_init(&t->shutdown_ep_refs, 1);
241 gpr_mu_init(&t->mu);
Craig Tillera82950e2015-09-22 12:33:20 -0700242 t->peer_string = grpc_endpoint_get_peer(ep);
Craig Tiller606d8742015-06-15 06:58:50 -0700243 t->endpoint_reading = 1;
Craig Tiller606d8742015-06-15 06:58:50 -0700244 t->global.next_stream_id = is_client ? 1 : 2;
245 t->global.is_client = is_client;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800246 t->writing.outgoing_window = DEFAULT_WINDOW;
247 t->parsing.incoming_window = DEFAULT_WINDOW;
Craig Tillera8d68092015-11-17 08:02:29 -0800248 t->global.stream_lookahead = DEFAULT_WINDOW;
Craig Tillerd20efd22015-06-12 16:17:09 -0700249 t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
Craig Tiller606d8742015-06-15 06:58:50 -0700250 t->global.ping_counter = 1;
Craig Tiller83fb0702015-06-16 21:13:07 -0700251 t->global.pings.next = t->global.pings.prev = &t->global.pings;
Craig Tiller606d8742015-06-15 06:58:50 -0700252 t->parsing.is_client = is_client;
Craig Tillera82950e2015-09-22 12:33:20 -0700253 t->parsing.deframe_state =
254 is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
Craig Tiller285b8822015-06-17 15:58:13 -0700255 t->writing.is_client = is_client;
Craig Tillera82950e2015-09-22 12:33:20 -0700256 grpc_connectivity_state_init(
257 &t->channel_callback.state_tracker, GRPC_CHANNEL_READY,
258 is_client ? "client_transport" : "server_transport");
Craig Tiller42cdf942015-06-12 07:35:44 -0700259
Craig Tillera82950e2015-09-22 12:33:20 -0700260 gpr_slice_buffer_init(&t->global.qbuf);
Craig Tiller42cdf942015-06-12 07:35:44 -0700261
Craig Tillera82950e2015-09-22 12:33:20 -0700262 gpr_slice_buffer_init(&t->writing.outbuf);
Craig Tillerb2b42612015-11-20 12:02:17 -0800263 grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor);
Craig Tillera82950e2015-09-22 12:33:20 -0700264 grpc_closure_init(&t->writing_action, writing_action, t);
Craig Tiller42cdf942015-06-12 07:35:44 -0700265
Craig Tillera82950e2015-09-22 12:33:20 -0700266 gpr_slice_buffer_init(&t->parsing.qbuf);
267 grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
Craig Tillerb2b42612015-11-20 12:02:17 -0800268 grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser);
Craig Tiller42cdf942015-06-12 07:35:44 -0700269
Craig Tillera82950e2015-09-22 12:33:20 -0700270 grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
271 &t->writing);
272 grpc_closure_init(&t->recv_data, recv_data, t);
273 gpr_slice_buffer_init(&t->read_buffer);
Craig Tillerb0298592015-08-27 07:38:01 -0700274
Craig Tillera82950e2015-09-22 12:33:20 -0700275 if (is_client) {
276 gpr_slice_buffer_add(
277 &t->global.qbuf,
278 gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
279 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800280 /* 8 is a random stab in the dark as to a good initial size: it's small enough
281 that it shouldn't waste memory for infrequently used connections, yet
282 large enough that the exponential growth should happen nicely when it's
283 needed.
284 TODO(ctiller): tune this */
Craig Tillera82950e2015-09-22 12:33:20 -0700285 grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8);
286 grpc_chttp2_stream_map_init(&t->new_stream_map, 8);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800287
288 /* copy in initial settings to all setting sets */
Craig Tillera82950e2015-09-22 12:33:20 -0700289 for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) {
290 t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value;
291 for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) {
292 t->global.settings[j][i] =
293 grpc_chttp2_settings_parameters[i].default_value;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800294 }
Craig Tillera82950e2015-09-22 12:33:20 -0700295 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700296 t->global.dirtied_local_settings = 1;
ctiller493fbcc2014-12-07 15:09:10 -0800297 /* Hack: it's common for implementations to assume 65536 bytes initial send
298 window -- this should by rights be 0 */
Craig Tillerd20efd22015-06-12 16:17:09 -0700299 t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
300 t->global.sent_local_settings = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800301
302 /* configure http2 the way we like it */
Craig Tillera82950e2015-09-22 12:33:20 -0700303 if (is_client) {
304 push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
305 push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
306 }
307 push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW);
Craig Tiller45724b32015-09-22 10:42:19 -0700308
Craig Tillera82950e2015-09-22 12:33:20 -0700309 if (channel_args) {
310 for (i = 0; i < channel_args->num_args; i++) {
311 if (0 ==
312 strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) {
313 if (is_client) {
314 gpr_log(GPR_ERROR, "%s: is ignored on the client",
315 GRPC_ARG_MAX_CONCURRENT_STREAMS);
316 } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
317 gpr_log(GPR_ERROR, "%s: must be an integer",
318 GRPC_ARG_MAX_CONCURRENT_STREAMS);
319 } else {
320 push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
Craig Tiller7536af02015-12-22 13:49:30 -0800321 (uint32_t)channel_args->args[i].value.integer);
Craig Tillera82950e2015-09-22 12:33:20 -0700322 }
323 } else if (0 == strcmp(channel_args->args[i].key,
324 GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) {
325 if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
326 gpr_log(GPR_ERROR, "%s: must be an integer",
327 GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER);
328 } else if ((t->global.next_stream_id & 1) !=
329 (channel_args->args[i].value.integer & 1)) {
330 gpr_log(GPR_ERROR, "%s: low bit must be %d on %s",
331 GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER,
332 t->global.next_stream_id & 1,
333 is_client ? "client" : "server");
334 } else {
335 t->global.next_stream_id =
Craig Tiller7536af02015-12-22 13:49:30 -0800336 (uint32_t)channel_args->args[i].value.integer;
Craig Tillera82950e2015-09-22 12:33:20 -0700337 }
Craig Tiller3c53bb22015-11-10 14:24:36 +0000338 } else if (0 == strcmp(channel_args->args[i].key,
Craig Tillera8d68092015-11-17 08:02:29 -0800339 GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) {
340 if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
341 gpr_log(GPR_ERROR, "%s: must be an integer",
342 GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
343 } else if (channel_args->args[i].value.integer <= 5) {
344 gpr_log(GPR_ERROR, "%s: must be at least 5",
345 GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
346 } else {
347 t->global.stream_lookahead =
Craig Tiller7536af02015-12-22 13:49:30 -0800348 (uint32_t)channel_args->args[i].value.integer;
Craig Tillera8d68092015-11-17 08:02:29 -0800349 }
Craig Tillera869b5b2015-11-23 16:28:57 -0800350 } else if (0 == strcmp(channel_args->args[i].key,
Craig Tiller3c53bb22015-11-10 14:24:36 +0000351 GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) {
Craig Tiller027a74c2015-11-10 08:37:46 +0000352 if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
Craig Tiller3c53bb22015-11-10 14:24:36 +0000353 gpr_log(GPR_ERROR, "%s: must be an integer",
354 GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
Craig Tiller027a74c2015-11-10 08:37:46 +0000355 } else if (channel_args->args[i].value.integer < 0) {
yang-g575625c2015-12-17 13:58:24 -0800356 gpr_log(GPR_ERROR, "%s: must be non-negative",
Craig Tiller3c53bb22015-11-10 14:24:36 +0000357 GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
Craig Tiller027a74c2015-11-10 08:37:46 +0000358 } else {
Craig Tiller3c53bb22015-11-10 14:24:36 +0000359 push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
Craig Tiller7536af02015-12-22 13:49:30 -0800360 (uint32_t)channel_args->args[i].value.integer);
Craig Tiller027a74c2015-11-10 08:37:46 +0000361 }
Craig Tiller3c53bb22015-11-10 14:24:36 +0000362 } else if (0 == strcmp(channel_args->args[i].key,
363 GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
Craig Tiller027a74c2015-11-10 08:37:46 +0000364 if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
Craig Tiller3c53bb22015-11-10 14:24:36 +0000365 gpr_log(GPR_ERROR, "%s: must be an integer",
366 GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
Craig Tiller027a74c2015-11-10 08:37:46 +0000367 } else if (channel_args->args[i].value.integer < 0) {
yang-g575625c2015-12-17 13:58:24 -0800368 gpr_log(GPR_ERROR, "%s: must be non-negative",
Craig Tiller3c53bb22015-11-10 14:24:36 +0000369 GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
Craig Tiller027a74c2015-11-10 08:37:46 +0000370 } else {
Craig Tiller3c53bb22015-11-10 14:24:36 +0000371 grpc_chttp2_hpack_compressor_set_max_usable_size(
372 &t->writing.hpack_compressor,
Craig Tiller7536af02015-12-22 13:49:30 -0800373 (uint32_t)channel_args->args[i].value.integer);
Craig Tiller027a74c2015-11-10 08:37:46 +0000374 }
Craig Tillera82950e2015-09-22 12:33:20 -0700375 }
Craig Tiller45724b32015-09-22 10:42:19 -0700376 }
Craig Tillera82950e2015-09-22 12:33:20 -0700377 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800378}
379
Craig Tillera82950e2015-09-22 12:33:20 -0700380static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
381 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800382
Craig Tillera82950e2015-09-22 12:33:20 -0700383 lock(t);
Craig Tiller1fe7b9d2015-02-17 11:57:02 -0800384 t->destroying = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700385 drop_connection(exec_ctx, t);
386 unlock(exec_ctx, t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800387
Craig Tillera82950e2015-09-22 12:33:20 -0700388 UNREF_TRANSPORT(exec_ctx, t, "destroy");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800389}
390
Craig Tillerae96a502015-09-01 15:15:42 -0700391/** block grpc_endpoint_shutdown being called until a paired
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700392 allow_endpoint_shutdown is made */
Craig Tillera82950e2015-09-22 12:33:20 -0700393static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) {
394 GPR_ASSERT(t->ep);
395 gpr_ref(&t->shutdown_ep_refs);
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700396}
397
Craig Tillera82950e2015-09-22 12:33:20 -0700398static void allow_endpoint_shutdown_locked(grpc_exec_ctx *exec_ctx,
399 grpc_chttp2_transport *t) {
400 if (gpr_unref(&t->shutdown_ep_refs)) {
401 if (t->ep) {
402 grpc_endpoint_shutdown(exec_ctx, t->ep);
Craig Tillerb059ae52015-09-02 11:11:57 -0700403 }
Craig Tillera82950e2015-09-22 12:33:20 -0700404 }
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700405}
406
Craig Tillera82950e2015-09-22 12:33:20 -0700407static void allow_endpoint_shutdown_unlocked(grpc_exec_ctx *exec_ctx,
408 grpc_chttp2_transport *t) {
409 if (gpr_unref(&t->shutdown_ep_refs)) {
410 gpr_mu_lock(&t->mu);
411 if (t->ep) {
412 grpc_endpoint_shutdown(exec_ctx, t->ep);
Craig Tillerb059ae52015-09-02 11:11:57 -0700413 }
Craig Tillera82950e2015-09-22 12:33:20 -0700414 gpr_mu_unlock(&t->mu);
415 }
Craig Tillerb059ae52015-09-02 11:11:57 -0700416}
417
Craig Tillera82950e2015-09-22 12:33:20 -0700418static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
419 grpc_chttp2_transport *t) {
420 grpc_endpoint_destroy(exec_ctx, t->ep);
Craig Tillerb059ae52015-09-02 11:11:57 -0700421 t->ep = NULL;
Craig Tillerdfff1b82015-09-21 14:39:57 -0700422 /* safe because we'll still have the ref for write */
Craig Tillera82950e2015-09-22 12:33:20 -0700423 UNREF_TRANSPORT(exec_ctx, t, "disconnect");
Craig Tillerb059ae52015-09-02 11:11:57 -0700424}
425
Craig Tillera82950e2015-09-22 12:33:20 -0700426static void close_transport_locked(grpc_exec_ctx *exec_ctx,
427 grpc_chttp2_transport *t) {
428 if (!t->closed) {
429 t->closed = 1;
430 connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_FATAL_FAILURE,
431 "close_transport");
432 if (t->ep) {
433 allow_endpoint_shutdown_locked(exec_ctx, t);
Craig Tillerec3aa892015-05-29 17:22:17 -0700434 }
Craig Tillerad23ae12016-03-04 10:50:56 -0800435
436 /* flush writable stream list to avoid dangling references */
437 grpc_chttp2_stream_global *stream_global;
438 grpc_chttp2_stream_writing *stream_writing;
439 while (grpc_chttp2_list_pop_writable_stream(
440 &t->global, &t->writing, &stream_global, &stream_writing)) {
441 GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
442 }
Craig Tillera82950e2015-09-22 12:33:20 -0700443 }
Craig Tillerec3aa892015-05-29 17:22:17 -0700444}
445
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800446#ifdef GRPC_STREAM_REFCOUNT_DEBUG
447void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global,
448 const char *reason) {
449 grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount, reason);
450}
451void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
452 grpc_chttp2_stream_global *stream_global,
453 const char *reason) {
454 grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount,
455 reason);
456}
457#else
458void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global) {
459 grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount);
460}
461void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
462 grpc_chttp2_stream_global *stream_global) {
463 grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount);
464}
465#endif
466
Craig Tillera82950e2015-09-22 12:33:20 -0700467static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800468 grpc_stream *gs, grpc_stream_refcount *refcount,
469 const void *server_data) {
Craig Tillera82950e2015-09-22 12:33:20 -0700470 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
471 grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800472
Craig Tillera82950e2015-09-22 12:33:20 -0700473 memset(s, 0, sizeof(*s));
Craig Tillerc079c112015-04-22 15:23:39 -0700474
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800475 s->refcount = refcount;
476 GRPC_CHTTP2_STREAM_REF(&s->global, "chttp2");
477
478 grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[0]);
479 grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[1]);
480 grpc_chttp2_incoming_metadata_buffer_init(
481 &s->global.received_initial_metadata);
482 grpc_chttp2_incoming_metadata_buffer_init(
483 &s->global.received_trailing_metadata);
Craig Tillera82950e2015-09-22 12:33:20 -0700484 grpc_chttp2_data_parser_init(&s->parsing.data_parser);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800485 gpr_slice_buffer_init(&s->writing.flow_controlled_buffer);
Craig Tiller606d8742015-06-15 06:58:50 -0700486
Craig Tillera82950e2015-09-22 12:33:20 -0700487 REF_TRANSPORT(t, "stream");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800488
Craig Tillera82950e2015-09-22 12:33:20 -0700489 lock(t);
490 grpc_chttp2_register_stream(t, s);
491 if (server_data) {
492 GPR_ASSERT(t->parsing_active);
Craig Tiller7536af02015-12-22 13:49:30 -0800493 s->global.id = (uint32_t)(uintptr_t)server_data;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800494 s->parsing.id = s->global.id;
Craig Tillera82950e2015-09-22 12:33:20 -0700495 s->global.outgoing_window =
496 t->global.settings[GRPC_PEER_SETTINGS]
497 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800498 s->parsing.incoming_window = s->global.max_recv_bytes =
499 t->global.settings[GRPC_SENT_SETTINGS]
500 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tillera82950e2015-09-22 12:33:20 -0700501 *t->accepting_stream = s;
502 grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s);
503 s->global.in_stream_map = 1;
504 }
Craig Tillera82950e2015-09-22 12:33:20 -0700505 unlock(exec_ctx, t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800506
507 return 0;
508}
509
Craig Tillera82950e2015-09-22 12:33:20 -0700510static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
511 grpc_stream *gs) {
512 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
513 grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700514 int i;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800515 grpc_byte_stream *bs;
516
517 GPR_TIMER_BEGIN("destroy_stream", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800518
Craig Tillera82950e2015-09-22 12:33:20 -0700519 gpr_mu_lock(&t->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800520
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800521 GPR_ASSERT((s->global.write_closed && s->global.read_closed) ||
Craig Tillera82950e2015-09-22 12:33:20 -0700522 s->global.id == 0);
523 GPR_ASSERT(!s->global.in_stream_map);
524 if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
525 close_transport_locked(exec_ctx, t);
526 }
527 if (!t->parsing_active && s->global.id) {
528 GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
529 s->global.id) == NULL);
530 }
531
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800532 grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global,
533 &s->global);
yang-g0db90322015-12-21 13:38:56 -0800534 grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global);
Craig Tillera82950e2015-09-22 12:33:20 -0700535
536 gpr_mu_unlock(&t->mu);
537
538 for (i = 0; i < STREAM_LIST_COUNT; i++) {
539 if (s->included[i]) {
540 gpr_log(GPR_ERROR, "%s stream %d still included in list %d",
541 t->global.is_client ? "client" : "server", s->global.id, i);
542 abort();
Craig Tiller05cc0c42015-07-23 16:01:27 -0700543 }
Craig Tillera82950e2015-09-22 12:33:20 -0700544 }
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700545
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800546 while (
547 (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) {
Craig Tiller3b66ab92015-12-09 19:42:22 -0800548 grpc_byte_stream_destroy(exec_ctx, bs);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800549 }
550
551 GPR_ASSERT(s->global.send_initial_metadata_finished == NULL);
552 GPR_ASSERT(s->global.send_message_finished == NULL);
553 GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL);
Craig Tillera44cbfc2016-02-03 16:02:49 -0800554 GPR_ASSERT(s->global.recv_initial_metadata_ready == NULL);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800555 GPR_ASSERT(s->global.recv_message_ready == NULL);
556 GPR_ASSERT(s->global.recv_trailing_metadata_finished == NULL);
Craig Tiller7be556e2015-11-06 12:29:33 -0800557 grpc_chttp2_data_parser_destroy(exec_ctx, &s->parsing.data_parser);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800558 grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[0]);
559 grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[1]);
560 grpc_chttp2_incoming_metadata_buffer_destroy(
561 &s->global.received_initial_metadata);
562 grpc_chttp2_incoming_metadata_buffer_destroy(
563 &s->global.received_trailing_metadata);
564 gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800565
Craig Tillera82950e2015-09-22 12:33:20 -0700566 UNREF_TRANSPORT(exec_ctx, t, "stream");
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800567
568 GPR_TIMER_END("destroy_stream", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800569}
570
Craig Tillera82950e2015-09-22 12:33:20 -0700571grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
Craig Tiller7536af02015-12-22 13:49:30 -0800572 grpc_chttp2_transport_parsing *transport_parsing, uint32_t id) {
Craig Tillera82950e2015-09-22 12:33:20 -0700573 grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
574 grpc_chttp2_stream *s =
575 grpc_chttp2_stream_map_find(&t->parsing_stream_map, id);
Craig Tillercf1e3192015-06-16 14:28:22 -0700576 return s ? &s->parsing : NULL;
Craig Tillercfb5db92015-06-15 17:14:41 -0700577}
578
Craig Tillera82950e2015-09-22 12:33:20 -0700579grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800580 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
Craig Tiller7536af02015-12-22 13:49:30 -0800581 uint32_t id) {
Craig Tiller1937b062015-06-16 08:47:38 -0700582 grpc_chttp2_stream *accepting;
Craig Tillera82950e2015-09-22 12:33:20 -0700583 grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
584 GPR_ASSERT(t->accepting_stream == NULL);
Craig Tiller1937b062015-06-16 08:47:38 -0700585 t->accepting_stream = &accepting;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800586 t->channel_callback.accept_stream(exec_ctx,
587 t->channel_callback.accept_stream_user_data,
Craig Tiller7536af02015-12-22 13:49:30 -0800588 &t->base, (void *)(uintptr_t)id);
Craig Tiller1937b062015-06-16 08:47:38 -0700589 t->accepting_stream = NULL;
590 return &accepting->parsing;
591}
592
Craig Tiller0cb803d2016-03-02 22:17:24 -0800593/*******************************************************************************
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800594 * LOCK MANAGEMENT
595 */
596
Craig Tiller4aa71a12015-06-15 13:00:55 -0700597/* We take a grpc_chttp2_transport-global lock in response to calls coming in
598 from above,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800599 and in response to data being received from below. New data to be written
600 is always queued, as are callbacks to process data. During unlock() we
601 check our todo lists and initiate callbacks and flush writes. */
602
Craig Tillera82950e2015-09-22 12:33:20 -0700603static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800604
Craig Tillera82950e2015-09-22 12:33:20 -0700605static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
Craig Tiller0ba432d2015-10-09 16:57:11 -0700606 GPR_TIMER_BEGIN("unlock", 0);
Craig Tillera82950e2015-09-22 12:33:20 -0700607 if (!t->writing_active && !t->closed &&
yang-g276e32d2016-02-22 13:15:30 -0800608 grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing,
Craig Tiller3c53bb22015-11-10 14:24:36 +0000609 t->parsing_active)) {
Craig Tillera82950e2015-09-22 12:33:20 -0700610 t->writing_active = 1;
611 REF_TRANSPORT(t, "writing");
Craig Tiller6c396862016-01-28 13:53:40 -0800612 grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700613 prevent_endpoint_shutdown(t);
614 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800615 check_read_ops(exec_ctx, &t->global);
Craig Tiller99f80552015-06-11 16:26:03 -0700616
Craig Tillera82950e2015-09-22 12:33:20 -0700617 gpr_mu_unlock(&t->mu);
Craig Tiller0ba432d2015-10-09 16:57:11 -0700618 GPR_TIMER_END("unlock", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800619}
620
Craig Tiller0cb803d2016-03-02 22:17:24 -0800621/*******************************************************************************
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800622 * OUTPUT PROCESSING
623 */
624
Craig Tiller0cb803d2016-03-02 22:17:24 -0800625void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
626 grpc_chttp2_stream_global *stream_global) {
627 if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed &&
628 grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) {
629 GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
630 }
631}
632
Craig Tillera82950e2015-09-22 12:33:20 -0700633static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
Craig Tiller7536af02015-12-22 13:49:30 -0800634 uint32_t value) {
Craig Tillera82950e2015-09-22 12:33:20 -0700635 const grpc_chttp2_setting_parameters *sp =
636 &grpc_chttp2_settings_parameters[id];
Craig Tiller7536af02015-12-22 13:49:30 -0800637 uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value);
Craig Tillera82950e2015-09-22 12:33:20 -0700638 if (use_value != value) {
639 gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name,
640 value, use_value);
641 }
642 if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) {
643 t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value;
644 t->global.dirtied_local_settings = 1;
645 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800646}
647
Craig Tillera82950e2015-09-22 12:33:20 -0700648void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
Craig Tiller6c396862016-01-28 13:53:40 -0800649 void *transport_writing_ptr, bool success) {
Craig Tillerb0298592015-08-27 07:38:01 -0700650 grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
Craig Tillera82950e2015-09-22 12:33:20 -0700651 grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
Craig Tillerabb2e3d2015-12-15 06:23:59 -0800652 grpc_chttp2_stream_global *stream_global;
ctiller00297df2015-01-12 11:23:09 -0800653
Craig Tiller0ba432d2015-10-09 16:57:11 -0700654 GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0);
Craig Tiller8910ac62015-10-08 16:49:15 -0700655
Craig Tillera82950e2015-09-22 12:33:20 -0700656 lock(t);
Craig Tillerd20efd22015-06-12 16:17:09 -0700657
Craig Tillera82950e2015-09-22 12:33:20 -0700658 allow_endpoint_shutdown_locked(exec_ctx, t);
Craig Tillerb059ae52015-09-02 11:11:57 -0700659
Craig Tillera82950e2015-09-22 12:33:20 -0700660 if (!success) {
661 drop_connection(exec_ctx, t);
662 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700663
Craig Tillera82950e2015-09-22 12:33:20 -0700664 grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
Craig Tillerd20efd22015-06-12 16:17:09 -0700665
Craig Tillera3f298f2015-12-16 19:42:09 -0800666 while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
667 &stream_global)) {
Craig Tillerabb2e3d2015-12-15 06:23:59 -0800668 fail_pending_writes(exec_ctx, stream_global);
669 GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
670 }
671
ctiller00297df2015-01-12 11:23:09 -0800672 /* leave the writing flag up on shutdown to prevent further writes in unlock()
673 from starting */
Craig Tillerd20efd22015-06-12 16:17:09 -0700674 t->writing_active = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700675 if (t->ep && !t->endpoint_reading) {
676 destroy_endpoint(exec_ctx, t);
677 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700678
Craig Tillera82950e2015-09-22 12:33:20 -0700679 unlock(exec_ctx, t);
ctiller00297df2015-01-12 11:23:09 -0800680
Craig Tillera82950e2015-09-22 12:33:20 -0700681 UNREF_TRANSPORT(exec_ctx, t, "writing");
Craig Tiller1f41b6b2015-10-09 15:07:02 -0700682
Craig Tiller0ba432d2015-10-09 16:57:11 -0700683 GPR_TIMER_END("grpc_chttp2_terminate_writing", 0);
ctiller00297df2015-01-12 11:23:09 -0800684}
685
Craig Tillera82950e2015-09-22 12:33:20 -0700686static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
Craig Tiller6c396862016-01-28 13:53:40 -0800687 bool iomgr_success_ignored) {
Craig Tillerb084d902015-06-12 07:50:02 -0700688 grpc_chttp2_transport *t = gt;
Craig Tiller0ba432d2015-10-09 16:57:11 -0700689 GPR_TIMER_BEGIN("writing_action", 0);
Craig Tillera82950e2015-09-22 12:33:20 -0700690 grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep);
Craig Tiller0ba432d2015-10-09 16:57:11 -0700691 GPR_TIMER_END("writing_action", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800692}
693
Craig Tillera82950e2015-09-22 12:33:20 -0700694void grpc_chttp2_add_incoming_goaway(
695 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
Craig Tiller7536af02015-12-22 13:49:30 -0800696 uint32_t goaway_error, gpr_slice goaway_text) {
Craig Tillera82950e2015-09-22 12:33:20 -0700697 char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
698 gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg);
699 gpr_free(msg);
700 gpr_slice_unref(goaway_text);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700701 transport_global->seen_goaway = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700702 connectivity_state_set(exec_ctx, transport_global, GRPC_CHANNEL_FATAL_FAILURE,
703 "got_goaway");
Craig Tiller7098c032015-05-04 10:18:28 -0700704}
705
Craig Tillera82950e2015-09-22 12:33:20 -0700706static void maybe_start_some_streams(
707 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700708 grpc_chttp2_stream_global *stream_global;
Craig Tiller7536af02015-12-22 13:49:30 -0800709 uint32_t stream_incoming_window;
Craig Tiller4aa71a12015-06-15 13:00:55 -0700710 /* start streams where we have free grpc_chttp2_stream ids and free
711 * concurrency */
Craig Tillera82950e2015-09-22 12:33:20 -0700712 while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID &&
713 transport_global->concurrent_stream_count <
714 transport_global
715 ->settings[GRPC_PEER_SETTINGS]
716 [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] &&
717 grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
718 &stream_global)) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800719 /* safe since we can't (legally) be parsing this stream yet */
720 grpc_chttp2_stream_parsing *stream_parsing =
721 &STREAM_FROM_GLOBAL(stream_global)->parsing;
Craig Tillera82950e2015-09-22 12:33:20 -0700722 GRPC_CHTTP2_IF_TRACING(gpr_log(
723 GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d",
724 transport_global->is_client ? "CLI" : "SVR", stream_global,
725 transport_global->next_stream_id));
Craig Tillerc1f75602015-04-24 11:44:53 -0700726
Craig Tillera82950e2015-09-22 12:33:20 -0700727 GPR_ASSERT(stream_global->id == 0);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800728 stream_global->id = stream_parsing->id = transport_global->next_stream_id;
Craig Tillera82950e2015-09-22 12:33:20 -0700729 transport_global->next_stream_id += 2;
Craig Tiller564872d2015-06-18 11:21:22 -0700730
Craig Tillera82950e2015-09-22 12:33:20 -0700731 if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
732 connectivity_state_set(exec_ctx, transport_global,
733 GRPC_CHANNEL_TRANSIENT_FAILURE,
734 "no_more_stream_ids");
Craig Tiller7098c032015-05-04 10:18:28 -0700735 }
Craig Tillera82950e2015-09-22 12:33:20 -0700736
737 stream_global->outgoing_window =
738 transport_global->settings[GRPC_PEER_SETTINGS]
739 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800740 stream_parsing->incoming_window = stream_incoming_window =
Craig Tillera82950e2015-09-22 12:33:20 -0700741 transport_global->settings[GRPC_SENT_SETTINGS]
742 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
743 stream_global->max_recv_bytes =
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800744 GPR_MAX(stream_incoming_window, stream_global->max_recv_bytes);
Craig Tillera82950e2015-09-22 12:33:20 -0700745 grpc_chttp2_stream_map_add(
746 &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map,
747 stream_global->id, STREAM_FROM_GLOBAL(stream_global));
748 stream_global->in_stream_map = 1;
749 transport_global->concurrent_stream_count++;
Craig Tiller0cb803d2016-03-02 22:17:24 -0800750 grpc_chttp2_become_writable(transport_global, stream_global);
Craig Tillera82950e2015-09-22 12:33:20 -0700751 }
Craig Tiller7098c032015-05-04 10:18:28 -0700752 /* cancel out streams that will never be started */
Craig Tillera82950e2015-09-22 12:33:20 -0700753 while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
754 grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
755 &stream_global)) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800756 cancel_from_api(exec_ctx, transport_global, stream_global,
757 GRPC_STATUS_UNAVAILABLE);
Craig Tillera82950e2015-09-22 12:33:20 -0700758 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800759}
760
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800761static grpc_closure *add_closure_barrier(grpc_closure *closure) {
762 closure->final_data += 2;
763 return closure;
764}
765
766void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
767 grpc_closure **pclosure, int success) {
768 grpc_closure *closure = *pclosure;
769 if (closure == NULL) {
770 return;
771 }
772 closure->final_data -= 2;
773 if (!success) {
774 closure->final_data |= 1;
775 }
776 if (closure->final_data < 2) {
Craig Tiller6c396862016-01-28 13:53:40 -0800777 grpc_exec_ctx_enqueue(exec_ctx, closure, closure->final_data == 0, NULL);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800778 }
779 *pclosure = NULL;
780}
781
782static int contains_non_ok_status(
783 grpc_chttp2_transport_global *transport_global,
784 grpc_metadata_batch *batch) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800785 grpc_linked_mdelem *l;
786 for (l = batch->list.head; l; l = l->next) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800787 if (l->md->key == GRPC_MDSTR_GRPC_STATUS &&
788 l->md != GRPC_MDELEM_GRPC_STATUS_0) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800789 return 1;
790 }
791 }
792 return 0;
793}
794
Craig Tiller6c396862016-01-28 13:53:40 -0800795static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
Craig Tiller027a74c2015-11-10 08:37:46 +0000796
Craig Tillera82950e2015-09-22 12:33:20 -0700797static void perform_stream_op_locked(
798 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
799 grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800800 grpc_closure *on_complete;
801
Craig Tiller0ba432d2015-10-09 16:57:11 -0700802 GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800803
804 on_complete = op->on_complete;
Craig Tiller027a74c2015-11-10 08:37:46 +0000805 if (on_complete == NULL) {
806 on_complete = grpc_closure_create(do_nothing, NULL);
807 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800808 /* use final_data as a barrier until enqueue time; the inital counter is
809 dropped at the end of this function */
810 on_complete->final_data = 2;
811
Craig Tillera82950e2015-09-22 12:33:20 -0700812 if (op->cancel_with_status != GRPC_STATUS_OK) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800813 cancel_from_api(exec_ctx, transport_global, stream_global,
814 op->cancel_with_status);
Craig Tillera82950e2015-09-22 12:33:20 -0700815 }
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700816
Craig Tillera82950e2015-09-22 12:33:20 -0700817 if (op->close_with_status != GRPC_STATUS_OK) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800818 close_from_api(exec_ctx, transport_global, stream_global,
819 op->close_with_status, op->optional_close_message);
Craig Tillera82950e2015-09-22 12:33:20 -0700820 }
Craig Tiller45724b32015-09-22 10:42:19 -0700821
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800822 if (op->send_initial_metadata != NULL) {
823 GPR_ASSERT(stream_global->send_initial_metadata_finished == NULL);
824 stream_global->send_initial_metadata_finished =
825 add_closure_barrier(on_complete);
826 stream_global->send_initial_metadata = op->send_initial_metadata;
827 if (contains_non_ok_status(transport_global, op->send_initial_metadata)) {
828 stream_global->seen_error = 1;
829 grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
830 }
831 if (!stream_global->write_closed) {
832 if (transport_global->is_client) {
833 GPR_ASSERT(stream_global->id == 0);
Craig Tillera82950e2015-09-22 12:33:20 -0700834 grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
835 stream_global);
836 maybe_start_some_streams(exec_ctx, transport_global);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800837 } else {
838 GPR_ASSERT(stream_global->id != 0);
Craig Tiller0cb803d2016-03-02 22:17:24 -0800839 grpc_chttp2_become_writable(transport_global, stream_global);
Craig Tillera82950e2015-09-22 12:33:20 -0700840 }
841 } else {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800842 grpc_chttp2_complete_closure_step(
843 exec_ctx, &stream_global->send_initial_metadata_finished, 0);
Craig Tiller5c517b12015-07-15 13:28:10 -0700844 }
Craig Tillera82950e2015-09-22 12:33:20 -0700845 }
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700846
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800847 if (op->send_message != NULL) {
848 GPR_ASSERT(stream_global->send_message_finished == NULL);
849 GPR_ASSERT(stream_global->send_message == NULL);
850 stream_global->send_message_finished = add_closure_barrier(on_complete);
851 if (stream_global->write_closed) {
852 grpc_chttp2_complete_closure_step(
853 exec_ctx, &stream_global->send_message_finished, 0);
Jan Tattermuschfa45a5e2016-03-10 14:38:27 -0800854 } else {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800855 stream_global->send_message = op->send_message;
Jan Tattermuschfa45a5e2016-03-10 14:38:27 -0800856 if (stream_global->id != 0) {
857 grpc_chttp2_become_writable(transport_global, stream_global);
858 }
Craig Tiller45724b32015-09-22 10:42:19 -0700859 }
Craig Tillera82950e2015-09-22 12:33:20 -0700860 }
Craig Tiller45724b32015-09-22 10:42:19 -0700861
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800862 if (op->send_trailing_metadata != NULL) {
863 GPR_ASSERT(stream_global->send_trailing_metadata_finished == NULL);
864 stream_global->send_trailing_metadata_finished =
865 add_closure_barrier(on_complete);
866 stream_global->send_trailing_metadata = op->send_trailing_metadata;
867 if (contains_non_ok_status(transport_global, op->send_trailing_metadata)) {
868 stream_global->seen_error = 1;
869 grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
870 }
871 if (stream_global->write_closed) {
872 grpc_chttp2_complete_closure_step(
Craig Tillerb774be42015-11-19 07:56:13 -0800873 exec_ctx, &stream_global->send_trailing_metadata_finished,
Craig Tillere9c216e2015-11-06 14:48:46 -0800874 grpc_metadata_batch_is_empty(op->send_trailing_metadata));
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800875 } else if (stream_global->id != 0) {
876 /* TODO(ctiller): check if there's flow control for any outstanding
877 bytes before going writable */
Craig Tiller0cb803d2016-03-02 22:17:24 -0800878 grpc_chttp2_become_writable(transport_global, stream_global);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800879 }
Craig Tillera82950e2015-09-22 12:33:20 -0700880 }
881
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800882 if (op->recv_initial_metadata != NULL) {
Craig Tillera44cbfc2016-02-03 16:02:49 -0800883 GPR_ASSERT(stream_global->recv_initial_metadata_ready == NULL);
884 stream_global->recv_initial_metadata_ready =
885 op->recv_initial_metadata_ready;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800886 stream_global->recv_initial_metadata = op->recv_initial_metadata;
887 grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
888 }
889
890 if (op->recv_message != NULL) {
891 GPR_ASSERT(stream_global->recv_message_ready == NULL);
892 stream_global->recv_message_ready = op->recv_message_ready;
893 stream_global->recv_message = op->recv_message;
Craig Tiller8a095932015-12-16 19:40:49 -0800894 if (stream_global->id != 0 &&
895 (stream_global->incoming_frames.head == NULL ||
896 stream_global->incoming_frames.head->is_tail)) {
Craig Tillera3f298f2015-12-16 19:42:09 -0800897 incoming_byte_stream_update_flow_control(
898 transport_global, stream_global, transport_global->stream_lookahead,
899 0);
Craig Tillerc8b70132015-12-09 20:49:09 -0800900 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800901 grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
902 }
903
904 if (op->recv_trailing_metadata != NULL) {
905 GPR_ASSERT(stream_global->recv_trailing_metadata_finished == NULL);
906 stream_global->recv_trailing_metadata_finished =
907 add_closure_barrier(on_complete);
908 stream_global->recv_trailing_metadata = op->recv_trailing_metadata;
909 grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
910 }
911
912 grpc_chttp2_complete_closure_step(exec_ctx, &on_complete, 1);
913
Craig Tiller0ba432d2015-10-09 16:57:11 -0700914 GPR_TIMER_END("perform_stream_op_locked", 0);
Craig Tiller50d9db52015-04-23 10:52:14 -0700915}
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700916
Craig Tillera82950e2015-09-22 12:33:20 -0700917static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
918 grpc_stream *gs, grpc_transport_stream_op *op) {
919 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
920 grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
Craig Tiller50d9db52015-04-23 10:52:14 -0700921
Craig Tillera82950e2015-09-22 12:33:20 -0700922 lock(t);
923 perform_stream_op_locked(exec_ctx, &t->global, &s->global, op);
924 unlock(exec_ctx, t);
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700925}
926
Craig Tillera82950e2015-09-22 12:33:20 -0700927static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
928 grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p));
Craig Tiller606d8742015-06-15 06:58:50 -0700929 p->next = &t->global.pings;
930 p->prev = p->next->prev;
931 p->prev->next = p->next->prev = p;
Craig Tiller7536af02015-12-22 13:49:30 -0800932 p->id[0] = (uint8_t)((t->global.ping_counter >> 56) & 0xff);
933 p->id[1] = (uint8_t)((t->global.ping_counter >> 48) & 0xff);
934 p->id[2] = (uint8_t)((t->global.ping_counter >> 40) & 0xff);
935 p->id[3] = (uint8_t)((t->global.ping_counter >> 32) & 0xff);
936 p->id[4] = (uint8_t)((t->global.ping_counter >> 24) & 0xff);
937 p->id[5] = (uint8_t)((t->global.ping_counter >> 16) & 0xff);
938 p->id[6] = (uint8_t)((t->global.ping_counter >> 8) & 0xff);
939 p->id[7] = (uint8_t)(t->global.ping_counter & 0xff);
Craig Tiller606d8742015-06-15 06:58:50 -0700940 p->on_recv = on_recv;
Craig Tillera82950e2015-09-22 12:33:20 -0700941 gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
Craig Tiller1064f8b2015-06-25 13:52:57 -0700942}
943
Craig Tillere2c62372015-12-07 16:11:03 -0800944void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
945 grpc_chttp2_transport_parsing *transport_parsing,
Craig Tiller7536af02015-12-22 13:49:30 -0800946 const uint8_t *opaque_8bytes) {
Craig Tiller28bf8912015-12-07 16:07:04 -0800947 grpc_chttp2_outstanding_ping *ping;
948 grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
949 grpc_chttp2_transport_global *transport_global = &t->global;
950 lock(t);
Craig Tillere2c62372015-12-07 16:11:03 -0800951 for (ping = transport_global->pings.next; ping != &transport_global->pings;
952 ping = ping->next) {
Craig Tiller28bf8912015-12-07 16:07:04 -0800953 if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
Craig Tiller6c396862016-01-28 13:53:40 -0800954 grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, true, NULL);
Craig Tiller30798c02015-12-08 08:23:20 -0800955 ping->next->prev = ping->prev;
956 ping->prev->next = ping->next;
957 gpr_free(ping);
958 break;
Craig Tiller28bf8912015-12-07 16:07:04 -0800959 }
Craig Tiller28bf8912015-12-07 16:07:04 -0800960 }
961 unlock(exec_ctx, t);
962}
963
Craig Tillerd7f12e32016-03-03 10:08:31 -0800964static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
965 grpc_chttp2_transport *t,
966 grpc_transport_op *op) {
967 bool close_transport = false;
Craig Tiller1064f8b2015-06-25 13:52:57 -0700968
Craig Tiller6c396862016-01-28 13:53:40 -0800969 grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700970
Craig Tiller27e5aa42015-11-24 16:28:54 -0800971 if (op->on_connectivity_state_change != NULL) {
Craig Tiller48613042015-11-29 14:45:11 -0800972 grpc_connectivity_state_notify_on_state_change(
973 exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state,
974 op->on_connectivity_state_change);
Craig Tillera82950e2015-09-22 12:33:20 -0700975 }
Craig Tiller1064f8b2015-06-25 13:52:57 -0700976
Craig Tillera82950e2015-09-22 12:33:20 -0700977 if (op->send_goaway) {
978 t->global.sent_goaway = 1;
979 grpc_chttp2_goaway_append(
980 t->global.last_incoming_stream_id,
Craig Tiller7536af02015-12-22 13:49:30 -0800981 (uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
Craig Tillera82950e2015-09-22 12:33:20 -0700982 gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
983 close_transport = !grpc_chttp2_has_streams(t);
984 }
Craig Tiller1064f8b2015-06-25 13:52:57 -0700985
Craig Tillerd7f12e32016-03-03 10:08:31 -0800986 if (op->set_accept_stream) {
987 t->channel_callback.accept_stream = op->set_accept_stream_fn;
Craig Tillera82950e2015-09-22 12:33:20 -0700988 t->channel_callback.accept_stream_user_data =
989 op->set_accept_stream_user_data;
990 }
Craig Tiller1064f8b2015-06-25 13:52:57 -0700991
Craig Tillera82950e2015-09-22 12:33:20 -0700992 if (op->bind_pollset) {
993 add_to_pollset_locked(exec_ctx, t, op->bind_pollset);
994 }
Craig Tiller1064f8b2015-06-25 13:52:57 -0700995
Craig Tillera82950e2015-09-22 12:33:20 -0700996 if (op->bind_pollset_set) {
997 add_to_pollset_set_locked(exec_ctx, t, op->bind_pollset_set);
998 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700999
Craig Tillera82950e2015-09-22 12:33:20 -07001000 if (op->send_ping) {
1001 send_ping_locked(t, op->send_ping);
1002 }
Craig Tiller1064f8b2015-06-25 13:52:57 -07001003
Craig Tillera82950e2015-09-22 12:33:20 -07001004 if (op->disconnect) {
1005 close_transport_locked(exec_ctx, t);
1006 }
Craig Tiller1064f8b2015-06-25 13:52:57 -07001007
Craig Tillera82950e2015-09-22 12:33:20 -07001008 if (close_transport) {
Craig Tillera82950e2015-09-22 12:33:20 -07001009 close_transport_locked(exec_ctx, t);
Craig Tillera82950e2015-09-22 12:33:20 -07001010 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001011}
1012
Craig Tillerd7f12e32016-03-03 10:08:31 -08001013static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
1014 grpc_transport_op *op) {
1015 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
1016
1017 lock(t);
1018
Craig Tiller1bd9ea42016-03-03 21:09:31 -08001019 /* If there's a set_accept_stream ensure that we're not parsing
1020 to avoid changing things out from underneath */
Craig Tiller687bf622016-03-03 21:18:48 -08001021 if (t->parsing_active && op->set_accept_stream) {
Craig Tillerd7f12e32016-03-03 10:08:31 -08001022 GPR_ASSERT(t->post_parsing_op == NULL);
1023 t->post_parsing_op = gpr_malloc(sizeof(*op));
1024 memcpy(t->post_parsing_op, op, sizeof(*op));
1025 } else {
1026 perform_transport_op_locked(exec_ctx, t, op);
1027 }
1028
1029 unlock(exec_ctx, t);
1030}
1031
Craig Tiller0cb803d2016-03-02 22:17:24 -08001032/*******************************************************************************
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001033 * INPUT PROCESSING
1034 */
1035
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001036static void check_read_ops(grpc_exec_ctx *exec_ctx,
1037 grpc_chttp2_transport_global *transport_global) {
1038 grpc_chttp2_stream_global *stream_global;
1039 grpc_byte_stream *bs;
1040 while (
1041 grpc_chttp2_list_pop_check_read_ops(transport_global, &stream_global)) {
Craig Tillera44cbfc2016-02-03 16:02:49 -08001042 if (stream_global->recv_initial_metadata_ready != NULL &&
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001043 stream_global->published_initial_metadata) {
1044 grpc_chttp2_incoming_metadata_buffer_publish(
1045 &stream_global->received_initial_metadata,
1046 stream_global->recv_initial_metadata);
Craig Tillera44cbfc2016-02-03 16:02:49 -08001047 grpc_exec_ctx_enqueue(
1048 exec_ctx, stream_global->recv_initial_metadata_ready, true, NULL);
1049 stream_global->recv_initial_metadata_ready = NULL;
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001050 }
1051 if (stream_global->recv_message_ready != NULL) {
yang-gad0df7b2016-02-22 10:00:20 -08001052 while (stream_global->seen_error &&
1053 (bs = grpc_chttp2_incoming_frame_queue_pop(
1054 &stream_global->incoming_frames)) != NULL) {
1055 grpc_byte_stream_destroy(exec_ctx, bs);
1056 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001057 if (stream_global->incoming_frames.head != NULL) {
1058 *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
1059 &stream_global->incoming_frames);
1060 GPR_ASSERT(*stream_global->recv_message != NULL);
Craig Tiller6c396862016-01-28 13:53:40 -08001061 grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
1062 NULL);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001063 stream_global->recv_message_ready = NULL;
1064 } else if (stream_global->published_trailing_metadata) {
1065 *stream_global->recv_message = NULL;
Craig Tiller6c396862016-01-28 13:53:40 -08001066 grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
1067 NULL);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001068 stream_global->recv_message_ready = NULL;
1069 }
1070 }
1071 if (stream_global->recv_trailing_metadata_finished != NULL &&
1072 stream_global->read_closed && stream_global->write_closed) {
1073 while (stream_global->seen_error &&
1074 (bs = grpc_chttp2_incoming_frame_queue_pop(
1075 &stream_global->incoming_frames)) != NULL) {
Craig Tiller3b66ab92015-12-09 19:42:22 -08001076 grpc_byte_stream_destroy(exec_ctx, bs);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001077 }
1078 if (stream_global->incoming_frames.head == NULL) {
1079 grpc_chttp2_incoming_metadata_buffer_publish(
1080 &stream_global->received_trailing_metadata,
1081 stream_global->recv_trailing_metadata);
1082 grpc_chttp2_complete_closure_step(
1083 exec_ctx, &stream_global->recv_trailing_metadata_finished, 1);
1084 }
1085 }
1086 }
Craig Tillerf73fcd12015-06-16 16:25:26 -07001087}
1088
Craig Tillera82950e2015-09-22 12:33:20 -07001089static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
Craig Tiller7536af02015-12-22 13:49:30 -08001090 uint32_t id) {
Craig Tiller8823b142015-06-18 11:41:24 -07001091 size_t new_stream_count;
Craig Tillera82950e2015-09-22 12:33:20 -07001092 grpc_chttp2_stream *s =
1093 grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
1094 if (!s) {
1095 s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id);
1096 }
Craig Tillera82950e2015-09-22 12:33:20 -07001097 GPR_ASSERT(s);
Craig Tiller759eb322015-06-16 22:41:18 -07001098 s->global.in_stream_map = 0;
Craig Tillera82950e2015-09-22 12:33:20 -07001099 if (t->parsing.incoming_stream == &s->parsing) {
1100 t->parsing.incoming_stream = NULL;
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001101 grpc_chttp2_parsing_become_skip_parser(exec_ctx, &t->parsing);
Craig Tillera82950e2015-09-22 12:33:20 -07001102 }
Craig Tiller1a423ef2015-12-14 21:51:38 -08001103 if (s->parsing.data_parser.parsing_frame != NULL) {
1104 grpc_chttp2_incoming_byte_stream_finished(
1105 exec_ctx, s->parsing.data_parser.parsing_frame, 0, 0);
1106 s->parsing.data_parser.parsing_frame = NULL;
1107 }
1108
Craig Tillera82950e2015-09-22 12:33:20 -07001109 if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
1110 close_transport_locked(exec_ctx, t);
1111 }
Craig Tiller0cb803d2016-03-02 22:17:24 -08001112 if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
1113 GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
1114 }
Craig Tiller8823b142015-06-18 11:41:24 -07001115
Craig Tillera82950e2015-09-22 12:33:20 -07001116 new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
1117 grpc_chttp2_stream_map_size(&t->new_stream_map);
Craig Tiller7536af02015-12-22 13:49:30 -08001118 GPR_ASSERT(new_stream_count <= UINT32_MAX);
Craig Tillera82950e2015-09-22 12:33:20 -07001119 if (new_stream_count != t->global.concurrent_stream_count) {
Craig Tiller7536af02015-12-22 13:49:30 -08001120 t->global.concurrent_stream_count = (uint32_t)new_stream_count;
Craig Tillera82950e2015-09-22 12:33:20 -07001121 maybe_start_some_streams(exec_ctx, &t->global);
1122 }
Craig Tiller759eb322015-06-16 22:41:18 -07001123}
1124
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001125static void cancel_from_api(grpc_exec_ctx *exec_ctx,
1126 grpc_chttp2_transport_global *transport_global,
Craig Tillera82950e2015-09-22 12:33:20 -07001127 grpc_chttp2_stream_global *stream_global,
1128 grpc_status_code status) {
Craig Tillera82950e2015-09-22 12:33:20 -07001129 if (stream_global->id != 0) {
1130 gpr_slice_buffer_add(
1131 &transport_global->qbuf,
1132 grpc_chttp2_rst_stream_create(
1133 stream_global->id,
Craig Tiller7536af02015-12-22 13:49:30 -08001134 (uint32_t)grpc_chttp2_grpc_status_to_http2_error(status)));
Craig Tillera82950e2015-09-22 12:33:20 -07001135 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001136 grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
1137 NULL);
1138 grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
1139 1);
Craig Tillerb787c502015-06-15 16:14:52 -07001140}
1141
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001142void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
1143 grpc_chttp2_transport_global *transport_global,
1144 grpc_chttp2_stream_global *stream_global,
1145 grpc_status_code status, gpr_slice *slice) {
1146 if (status != GRPC_STATUS_OK) {
1147 stream_global->seen_error = 1;
1148 grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
1149 }
Craig Tiller4b65b1d2015-11-03 07:04:30 -08001150 /* stream_global->recv_trailing_metadata_finished gives us a
1151 last chance replacement: we've received trailing metadata,
1152 but something more important has become available to signal
1153 to the upper layers - drop what we've got, and then publish
1154 what we want - which is safe because we haven't told anyone
1155 about the metadata yet */
Craig Tillerb774be42015-11-19 07:56:13 -08001156 if (!stream_global->published_trailing_metadata ||
1157 stream_global->recv_trailing_metadata_finished != NULL) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001158 char status_string[GPR_LTOA_MIN_BUFSIZE];
1159 gpr_ltoa(status, status_string);
1160 grpc_chttp2_incoming_metadata_buffer_add(
1161 &stream_global->received_trailing_metadata,
Craig Tillerb2b42612015-11-20 12:02:17 -08001162 grpc_mdelem_from_metadata_strings(
1163 GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string)));
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001164 if (slice) {
1165 grpc_chttp2_incoming_metadata_buffer_add(
1166 &stream_global->received_trailing_metadata,
1167 grpc_mdelem_from_metadata_strings(
Craig Tillerb2b42612015-11-20 12:02:17 -08001168 GRPC_MDSTR_GRPC_MESSAGE,
1169 grpc_mdstr_from_slice(gpr_slice_ref(*slice))));
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001170 }
1171 stream_global->published_trailing_metadata = 1;
1172 grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
1173 }
1174 if (slice) {
1175 gpr_slice_unref(*slice);
1176 }
1177}
1178
Craig Tillera3f298f2015-12-16 19:42:09 -08001179static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
Craig Tillerabb2e3d2015-12-15 06:23:59 -08001180 grpc_chttp2_stream_global *stream_global) {
1181 grpc_chttp2_complete_closure_step(
1182 exec_ctx, &stream_global->send_initial_metadata_finished, 0);
1183 grpc_chttp2_complete_closure_step(
1184 exec_ctx, &stream_global->send_trailing_metadata_finished, 0);
1185 grpc_chttp2_complete_closure_step(exec_ctx,
1186 &stream_global->send_message_finished, 0);
1187}
1188
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001189void grpc_chttp2_mark_stream_closed(
1190 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
1191 grpc_chttp2_stream_global *stream_global, int close_reads,
1192 int close_writes) {
1193 if (stream_global->read_closed && stream_global->write_closed) {
1194 /* already closed */
1195 return;
1196 }
1197 grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
1198 if (close_reads && !stream_global->read_closed) {
1199 stream_global->read_closed = 1;
1200 stream_global->published_initial_metadata = 1;
1201 stream_global->published_trailing_metadata = 1;
1202 }
1203 if (close_writes && !stream_global->write_closed) {
1204 stream_global->write_closed = 1;
Craig Tillerabb2e3d2015-12-15 06:23:59 -08001205 if (TRANSPORT_FROM_GLOBAL(transport_global)->writing_active) {
1206 GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
1207 grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
1208 stream_global);
1209 } else {
1210 fail_pending_writes(exec_ctx, stream_global);
1211 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001212 }
1213 if (stream_global->read_closed && stream_global->write_closed) {
1214 if (stream_global->id != 0 &&
1215 TRANSPORT_FROM_GLOBAL(transport_global)->parsing_active) {
1216 grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
1217 stream_global);
1218 } else {
1219 if (stream_global->id != 0) {
1220 remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
1221 stream_global->id);
1222 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001223 GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
1224 }
1225 }
1226}
1227
1228static void close_from_api(grpc_exec_ctx *exec_ctx,
1229 grpc_chttp2_transport_global *transport_global,
Craig Tillera82950e2015-09-22 12:33:20 -07001230 grpc_chttp2_stream_global *stream_global,
1231 grpc_status_code status,
1232 gpr_slice *optional_message) {
Craig Tiller45ce9272015-07-31 11:22:35 -07001233 gpr_slice hdr;
1234 gpr_slice status_hdr;
1235 gpr_slice message_pfx;
Craig Tiller7536af02015-12-22 13:49:30 -08001236 uint8_t *p;
1237 uint32_t len = 0;
Craig Tiller45ce9272015-07-31 11:22:35 -07001238
Craig Tillera82950e2015-09-22 12:33:20 -07001239 GPR_ASSERT(status >= 0 && (int)status < 100);
Craig Tiller45ce9272015-07-31 11:22:35 -07001240
Craig Tillera82950e2015-09-22 12:33:20 -07001241 GPR_ASSERT(stream_global->id != 0);
Craig Tiller45ce9272015-07-31 11:22:35 -07001242
1243 /* Hand roll a header block.
1244 This is unnecessarily ugly - at some point we should find a more elegant
1245 solution.
1246 It's complicated by the fact that our send machinery would be dead by the
1247 time we got around to sending this, so instead we ignore HPACK compression
1248 and just write the uncompressed bytes onto the wire. */
Craig Tillera82950e2015-09-22 12:33:20 -07001249 status_hdr = gpr_slice_malloc(15 + (status >= 10));
1250 p = GPR_SLICE_START_PTR(status_hdr);
1251 *p++ = 0x40; /* literal header */
1252 *p++ = 11; /* len(grpc-status) */
Craig Tiller45ce9272015-07-31 11:22:35 -07001253 *p++ = 'g';
1254 *p++ = 'r';
1255 *p++ = 'p';
1256 *p++ = 'c';
1257 *p++ = '-';
1258 *p++ = 's';
1259 *p++ = 't';
1260 *p++ = 'a';
1261 *p++ = 't';
1262 *p++ = 'u';
1263 *p++ = 's';
Craig Tillera82950e2015-09-22 12:33:20 -07001264 if (status < 10) {
1265 *p++ = 1;
Craig Tiller7536af02015-12-22 13:49:30 -08001266 *p++ = (uint8_t)('0' + status);
Craig Tillera82950e2015-09-22 12:33:20 -07001267 } else {
1268 *p++ = 2;
Craig Tiller7536af02015-12-22 13:49:30 -08001269 *p++ = (uint8_t)('0' + (status / 10));
1270 *p++ = (uint8_t)('0' + (status % 10));
Craig Tillera82950e2015-09-22 12:33:20 -07001271 }
1272 GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr));
Craig Tiller7536af02015-12-22 13:49:30 -08001273 len += (uint32_t)GPR_SLICE_LENGTH(status_hdr);
Craig Tiller45ce9272015-07-31 11:22:35 -07001274
Craig Tillera82950e2015-09-22 12:33:20 -07001275 if (optional_message) {
1276 GPR_ASSERT(GPR_SLICE_LENGTH(*optional_message) < 127);
1277 message_pfx = gpr_slice_malloc(15);
1278 p = GPR_SLICE_START_PTR(message_pfx);
1279 *p++ = 0x40;
1280 *p++ = 12; /* len(grpc-message) */
1281 *p++ = 'g';
1282 *p++ = 'r';
1283 *p++ = 'p';
1284 *p++ = 'c';
1285 *p++ = '-';
1286 *p++ = 'm';
1287 *p++ = 'e';
1288 *p++ = 's';
1289 *p++ = 's';
1290 *p++ = 'a';
1291 *p++ = 'g';
1292 *p++ = 'e';
Craig Tiller7536af02015-12-22 13:49:30 -08001293 *p++ = (uint8_t)GPR_SLICE_LENGTH(*optional_message);
Craig Tillera82950e2015-09-22 12:33:20 -07001294 GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx));
Craig Tiller7536af02015-12-22 13:49:30 -08001295 len += (uint32_t)GPR_SLICE_LENGTH(message_pfx);
1296 len += (uint32_t)GPR_SLICE_LENGTH(*optional_message);
Craig Tillera82950e2015-09-22 12:33:20 -07001297 }
Craig Tiller45ce9272015-07-31 11:22:35 -07001298
Craig Tillera82950e2015-09-22 12:33:20 -07001299 hdr = gpr_slice_malloc(9);
1300 p = GPR_SLICE_START_PTR(hdr);
Craig Tiller7536af02015-12-22 13:49:30 -08001301 *p++ = (uint8_t)(len >> 16);
1302 *p++ = (uint8_t)(len >> 8);
1303 *p++ = (uint8_t)(len);
Craig Tiller45ce9272015-07-31 11:22:35 -07001304 *p++ = GRPC_CHTTP2_FRAME_HEADER;
1305 *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
Craig Tiller7536af02015-12-22 13:49:30 -08001306 *p++ = (uint8_t)(stream_global->id >> 24);
1307 *p++ = (uint8_t)(stream_global->id >> 16);
1308 *p++ = (uint8_t)(stream_global->id >> 8);
1309 *p++ = (uint8_t)(stream_global->id);
Craig Tillera82950e2015-09-22 12:33:20 -07001310 GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr));
Craig Tiller45ce9272015-07-31 11:22:35 -07001311
Craig Tillera82950e2015-09-22 12:33:20 -07001312 gpr_slice_buffer_add(&transport_global->qbuf, hdr);
1313 gpr_slice_buffer_add(&transport_global->qbuf, status_hdr);
1314 if (optional_message) {
1315 gpr_slice_buffer_add(&transport_global->qbuf, message_pfx);
1316 gpr_slice_buffer_add(&transport_global->qbuf,
1317 gpr_slice_ref(*optional_message));
1318 }
Craig Tiller45ce9272015-07-31 11:22:35 -07001319
Craig Tillera82950e2015-09-22 12:33:20 -07001320 gpr_slice_buffer_add(
1321 &transport_global->qbuf,
1322 grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR));
Craig Tiller45ce9272015-07-31 11:22:35 -07001323
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001324 if (optional_message) {
1325 gpr_slice_ref(*optional_message);
1326 }
1327 grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
1328 optional_message);
1329 grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
1330 1);
Craig Tiller45ce9272015-07-31 11:22:35 -07001331}
1332
Craig Tillera82950e2015-09-22 12:33:20 -07001333static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
1334 void *user_data,
1335 grpc_chttp2_stream_global *stream_global) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001336 cancel_from_api(user_data, transport_global, stream_global,
1337 GRPC_STATUS_UNAVAILABLE);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001338}
1339
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001340static void end_all_the_calls(grpc_exec_ctx *exec_ctx,
1341 grpc_chttp2_transport *t) {
1342 grpc_chttp2_for_all_streams(&t->global, exec_ctx, cancel_stream_cb);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001343}
1344
Craig Tillera82950e2015-09-22 12:33:20 -07001345static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
1346 close_transport_locked(exec_ctx, t);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001347 end_all_the_calls(exec_ctx, t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001348}
1349
Craig Tillerab630732015-06-25 11:20:01 -07001350/** update window from a settings change */
Craig Tiller7536af02015-12-22 13:49:30 -08001351static void update_global_window(void *args, uint32_t id, void *stream) {
Craig Tillerab630732015-06-25 11:20:01 -07001352 grpc_chttp2_transport *t = args;
1353 grpc_chttp2_stream *s = stream;
1354 grpc_chttp2_transport_global *transport_global = &t->global;
1355 grpc_chttp2_stream_global *stream_global = &s->global;
Craig Tiller6f7411f2015-07-06 15:37:28 -07001356 int was_zero;
1357 int is_zero;
Craig Tiller7536af02015-12-22 13:49:30 -08001358 int64_t initial_window_update = t->parsing.initial_window_update;
Craig Tillerab630732015-06-25 11:20:01 -07001359
Craig Tiller6f7411f2015-07-06 15:37:28 -07001360 was_zero = stream_global->outgoing_window <= 0;
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001361 GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", transport_global, stream_global,
1362 outgoing_window, initial_window_update);
Craig Tiller6f7411f2015-07-06 15:37:28 -07001363 is_zero = stream_global->outgoing_window <= 0;
1364
Craig Tillera82950e2015-09-22 12:33:20 -07001365 if (was_zero && !is_zero) {
Craig Tiller0cb803d2016-03-02 22:17:24 -08001366 grpc_chttp2_become_writable(transport_global, stream_global);
Craig Tillera82950e2015-09-22 12:33:20 -07001367 }
Craig Tillerab630732015-06-25 11:20:01 -07001368}
1369
Craig Tillera82950e2015-09-22 12:33:20 -07001370static void read_error_locked(grpc_exec_ctx *exec_ctx,
1371 grpc_chttp2_transport *t) {
Craig Tiller69f56162015-06-30 14:54:31 -07001372 t->endpoint_reading = 0;
Craig Tillera82950e2015-09-22 12:33:20 -07001373 if (!t->writing_active && t->ep) {
1374 destroy_endpoint(exec_ctx, t);
1375 }
Craig Tiller69f56162015-06-30 14:54:31 -07001376}
1377
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001378/* tcp read callback */
Craig Tiller6c396862016-01-28 13:53:40 -08001379static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001380 size_t i;
Craig Tillerb0298592015-08-27 07:38:01 -07001381 int keep_reading = 0;
Craig Tillerdfff1b82015-09-21 14:39:57 -07001382 grpc_chttp2_transport *t = tp;
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001383 grpc_chttp2_transport_global *transport_global = &t->global;
1384 grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
1385 grpc_chttp2_stream_global *stream_global;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001386
Craig Tiller0ba432d2015-10-09 16:57:11 -07001387 GPR_TIMER_BEGIN("recv_data", 0);
Craig Tiller86253ca2015-10-08 13:31:02 -07001388
Craig Tillera82950e2015-09-22 12:33:20 -07001389 lock(t);
Craig Tillerb0298592015-08-27 07:38:01 -07001390 i = 0;
Craig Tillera82950e2015-09-22 12:33:20 -07001391 GPR_ASSERT(!t->parsing_active);
1392 if (!t->closed) {
1393 t->parsing_active = 1;
1394 /* merge stream lists */
1395 grpc_chttp2_stream_map_move_into(&t->new_stream_map,
1396 &t->parsing_stream_map);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001397 grpc_chttp2_prepare_to_read(transport_global, transport_parsing);
Craig Tillera82950e2015-09-22 12:33:20 -07001398 gpr_mu_unlock(&t->mu);
Craig Tiller0ba432d2015-10-09 16:57:11 -07001399 GPR_TIMER_BEGIN("recv_data.parse", 0);
Craig Tillera82950e2015-09-22 12:33:20 -07001400 for (; i < t->read_buffer.count &&
Craig Tillerf40df232016-03-25 13:38:14 -07001401 grpc_chttp2_perform_read(exec_ctx, transport_parsing,
1402 t->read_buffer.slices[i]);
Craig Tillera82950e2015-09-22 12:33:20 -07001403 i++)
1404 ;
Craig Tiller0ba432d2015-10-09 16:57:11 -07001405 GPR_TIMER_END("recv_data.parse", 0);
Craig Tillera82950e2015-09-22 12:33:20 -07001406 gpr_mu_lock(&t->mu);
Craig Tiller5c3a1102015-12-02 16:13:24 -08001407 /* copy parsing qbuf to global qbuf */
1408 gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
Craig Tillera82950e2015-09-22 12:33:20 -07001409 if (i != t->read_buffer.count) {
Craig Tiller5c3a1102015-12-02 16:13:24 -08001410 unlock(exec_ctx, t);
1411 lock(t);
Craig Tillera82950e2015-09-22 12:33:20 -07001412 drop_connection(exec_ctx, t);
Craig Tillerb0298592015-08-27 07:38:01 -07001413 }
Craig Tillera82950e2015-09-22 12:33:20 -07001414 /* merge stream lists */
1415 grpc_chttp2_stream_map_move_into(&t->new_stream_map,
1416 &t->parsing_stream_map);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001417 transport_global->concurrent_stream_count =
Craig Tiller7536af02015-12-22 13:49:30 -08001418 (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001419 if (transport_parsing->initial_window_update != 0) {
Craig Tillera82950e2015-09-22 12:33:20 -07001420 grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
1421 update_global_window, t);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001422 transport_parsing->initial_window_update = 0;
Craig Tillerb0298592015-08-27 07:38:01 -07001423 }
Craig Tillera82950e2015-09-22 12:33:20 -07001424 /* handle higher level things */
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001425 grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing);
Craig Tillera82950e2015-09-22 12:33:20 -07001426 t->parsing_active = 0;
Craig Tillerd7f12e32016-03-03 10:08:31 -08001427 /* handle delayed transport ops (if there is one) */
1428 if (t->post_parsing_op) {
1429 grpc_transport_op *op = t->post_parsing_op;
1430 t->post_parsing_op = NULL;
1431 perform_transport_op_locked(exec_ctx, t, op);
1432 gpr_free(op);
1433 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001434 /* if a stream is in the stream map, and gets cancelled, we need to ensure
1435 * we are not parsing before continuing the cancellation to keep things in
1436 * a sane state */
1437 while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
1438 &stream_global)) {
1439 GPR_ASSERT(stream_global->in_stream_map);
1440 GPR_ASSERT(stream_global->write_closed);
1441 GPR_ASSERT(stream_global->read_closed);
1442 remove_stream(exec_ctx, t, stream_global->id);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001443 GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
1444 }
Craig Tillera82950e2015-09-22 12:33:20 -07001445 }
yang-g759f59a2015-10-02 10:38:22 -07001446 if (!success || i != t->read_buffer.count || t->closed) {
Craig Tillera82950e2015-09-22 12:33:20 -07001447 drop_connection(exec_ctx, t);
1448 read_error_locked(exec_ctx, t);
1449 } else if (!t->closed) {
1450 keep_reading = 1;
1451 REF_TRANSPORT(t, "keep_reading");
1452 prevent_endpoint_shutdown(t);
1453 }
1454 gpr_slice_buffer_reset_and_unref(&t->read_buffer);
1455 unlock(exec_ctx, t);
Craig Tillerb0298592015-08-27 07:38:01 -07001456
Craig Tillera82950e2015-09-22 12:33:20 -07001457 if (keep_reading) {
1458 grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->recv_data);
1459 allow_endpoint_shutdown_unlocked(exec_ctx, t);
1460 UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
1461 } else {
1462 UNREF_TRANSPORT(exec_ctx, t, "recv_data");
1463 }
Craig Tiller86253ca2015-10-08 13:31:02 -07001464
Craig Tiller0ba432d2015-10-09 16:57:11 -07001465 GPR_TIMER_END("recv_data", 0);
Craig Tiller8b2f1d72015-06-18 13:38:38 -07001466}
1467
Craig Tiller0cb803d2016-03-02 22:17:24 -08001468/*******************************************************************************
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001469 * CALLBACK LOOP
1470 */
1471
Craig Tillera82950e2015-09-22 12:33:20 -07001472static void connectivity_state_set(
1473 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
1474 grpc_connectivity_state state, const char *reason) {
1475 GRPC_CHTTP2_IF_TRACING(
1476 gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
Craig Tillerf40df232016-03-25 13:38:14 -07001477 grpc_connectivity_state_set(
1478 exec_ctx,
1479 &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
1480 state, reason);
Craig Tiller748fe3f2015-03-02 07:48:50 -08001481}
1482
Craig Tiller0cb803d2016-03-02 22:17:24 -08001483/*******************************************************************************
Craig Tillerc079c112015-04-22 15:23:39 -07001484 * POLLSET STUFF
1485 */
1486
Craig Tillera82950e2015-09-22 12:33:20 -07001487static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
1488 grpc_chttp2_transport *t,
1489 grpc_pollset *pollset) {
1490 if (t->ep) {
1491 grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset);
1492 }
Craig Tillerc079c112015-04-22 15:23:39 -07001493}
1494
Craig Tillera82950e2015-09-22 12:33:20 -07001495static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
1496 grpc_chttp2_transport *t,
1497 grpc_pollset_set *pollset_set) {
1498 if (t->ep) {
1499 grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set);
1500 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -07001501}
1502
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001503static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
1504 grpc_stream *gs, grpc_pollset *pollset) {
1505 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
1506 lock(t);
1507 add_to_pollset_locked(exec_ctx, t, pollset);
1508 unlock(exec_ctx, t);
1509}
1510
Craig Tiller0cb803d2016-03-02 22:17:24 -08001511/*******************************************************************************
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001512 * BYTE STREAM
1513 */
1514
Craig Tiller20df14e2015-11-06 09:10:49 -08001515static void incoming_byte_stream_update_flow_control(
1516 grpc_chttp2_transport_global *transport_global,
1517 grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
1518 size_t have_already) {
Craig Tiller7536af02015-12-22 13:49:30 -08001519 uint32_t max_recv_bytes;
Craig Tiller20df14e2015-11-06 09:10:49 -08001520
1521 /* clamp max recv hint to an allowable size */
Craig Tiller7536af02015-12-22 13:49:30 -08001522 if (max_size_hint >= UINT32_MAX - transport_global->stream_lookahead) {
1523 max_recv_bytes = UINT32_MAX - transport_global->stream_lookahead;
Craig Tiller20df14e2015-11-06 09:10:49 -08001524 } else {
Craig Tiller7536af02015-12-22 13:49:30 -08001525 max_recv_bytes = (uint32_t)max_size_hint;
Craig Tiller20df14e2015-11-06 09:10:49 -08001526 }
1527
1528 /* account for bytes already received but unknown to higher layers */
1529 if (max_recv_bytes >= have_already) {
Craig Tiller7536af02015-12-22 13:49:30 -08001530 max_recv_bytes -= (uint32_t)have_already;
Craig Tiller20df14e2015-11-06 09:10:49 -08001531 } else {
1532 max_recv_bytes = 0;
1533 }
1534
1535 /* add some small lookahead to keep pipelines flowing */
Craig Tiller7536af02015-12-22 13:49:30 -08001536 GPR_ASSERT(max_recv_bytes <= UINT32_MAX - transport_global->stream_lookahead);
Craig Tillera8d68092015-11-17 08:02:29 -08001537 max_recv_bytes += transport_global->stream_lookahead;
Craig Tiller20df14e2015-11-06 09:10:49 -08001538 if (stream_global->max_recv_bytes < max_recv_bytes) {
Craig Tiller7536af02015-12-22 13:49:30 -08001539 uint32_t add_max_recv_bytes =
Craig Tiller20df14e2015-11-06 09:10:49 -08001540 max_recv_bytes - stream_global->max_recv_bytes;
1541 GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
1542 max_recv_bytes, add_max_recv_bytes);
1543 GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
1544 unannounced_incoming_window_for_parse,
1545 add_max_recv_bytes);
1546 GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
1547 unannounced_incoming_window_for_writing,
1548 add_max_recv_bytes);
1549 grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global,
1550 stream_global);
Craig Tiller0cb803d2016-03-02 22:17:24 -08001551 grpc_chttp2_become_writable(transport_global, stream_global);
Craig Tiller20df14e2015-11-06 09:10:49 -08001552 }
1553}
1554
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001555static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
1556 grpc_byte_stream *byte_stream,
1557 gpr_slice *slice, size_t max_size_hint,
1558 grpc_closure *on_complete) {
1559 grpc_chttp2_incoming_byte_stream *bs =
1560 (grpc_chttp2_incoming_byte_stream *)byte_stream;
1561 grpc_chttp2_transport_global *transport_global = &bs->transport->global;
1562 grpc_chttp2_stream_global *stream_global = &bs->stream->global;
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001563
1564 lock(bs->transport);
1565 if (bs->is_tail) {
Craig Tiller20df14e2015-11-06 09:10:49 -08001566 incoming_byte_stream_update_flow_control(transport_global, stream_global,
1567 max_size_hint, bs->slices.length);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001568 }
1569 if (bs->slices.count > 0) {
1570 *slice = gpr_slice_buffer_take_first(&bs->slices);
1571 unlock(exec_ctx, bs->transport);
1572 return 1;
Craig Tiller38edec62015-12-14 15:01:29 -08001573 } else if (bs->failed) {
Craig Tiller6c396862016-01-28 13:53:40 -08001574 grpc_exec_ctx_enqueue(exec_ctx, on_complete, false, NULL);
Craig Tiller38edec62015-12-14 15:01:29 -08001575 unlock(exec_ctx, bs->transport);
1576 return 0;
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001577 } else {
1578 bs->on_next = on_complete;
1579 bs->next = slice;
1580 unlock(exec_ctx, bs->transport);
1581 return 0;
1582 }
1583}
1584
1585static void incoming_byte_stream_unref(grpc_chttp2_incoming_byte_stream *bs) {
1586 if (gpr_unref(&bs->refs)) {
1587 gpr_slice_buffer_destroy(&bs->slices);
1588 gpr_free(bs);
1589 }
1590}
1591
Craig Tillera3f298f2015-12-16 19:42:09 -08001592static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
1593 grpc_byte_stream *byte_stream) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001594 incoming_byte_stream_unref((grpc_chttp2_incoming_byte_stream *)byte_stream);
1595}
1596
1597void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
1598 grpc_chttp2_incoming_byte_stream *bs,
1599 gpr_slice slice) {
1600 gpr_mu_lock(&bs->transport->mu);
1601 if (bs->on_next != NULL) {
1602 *bs->next = slice;
Craig Tiller6c396862016-01-28 13:53:40 -08001603 grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL);
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001604 bs->on_next = NULL;
1605 } else {
1606 gpr_slice_buffer_add(&bs->slices, slice);
1607 }
1608 gpr_mu_unlock(&bs->transport->mu);
1609}
1610
1611void grpc_chttp2_incoming_byte_stream_finished(
Craig Tiller38edec62015-12-14 15:01:29 -08001612 grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
1613 int from_parsing_thread) {
1614 if (!success) {
1615 if (from_parsing_thread) {
1616 gpr_mu_lock(&bs->transport->mu);
1617 }
Craig Tiller6c396862016-01-28 13:53:40 -08001618 grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
Craig Tiller38edec62015-12-14 15:01:29 -08001619 bs->on_next = NULL;
1620 bs->failed = 1;
1621 if (from_parsing_thread) {
1622 gpr_mu_unlock(&bs->transport->mu);
1623 }
1624 } else {
1625#ifndef NDEBUG
1626 if (from_parsing_thread) {
1627 gpr_mu_lock(&bs->transport->mu);
1628 }
1629 GPR_ASSERT(bs->on_next == NULL);
1630 if (from_parsing_thread) {
1631 gpr_mu_unlock(&bs->transport->mu);
1632 }
1633#endif
1634 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001635 incoming_byte_stream_unref(bs);
1636}
1637
1638grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
Craig Tiller20df14e2015-11-06 09:10:49 -08001639 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
Craig Tiller7536af02015-12-22 13:49:30 -08001640 grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size,
1641 uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001642 grpc_chttp2_incoming_byte_stream *incoming_byte_stream =
1643 gpr_malloc(sizeof(*incoming_byte_stream));
1644 incoming_byte_stream->base.length = frame_size;
1645 incoming_byte_stream->base.flags = flags;
1646 incoming_byte_stream->base.next = incoming_byte_stream_next;
1647 incoming_byte_stream->base.destroy = incoming_byte_stream_destroy;
1648 gpr_ref_init(&incoming_byte_stream->refs, 2);
1649 incoming_byte_stream->next_message = NULL;
1650 incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing);
1651 incoming_byte_stream->stream = STREAM_FROM_PARSING(stream_parsing);
1652 gpr_slice_buffer_init(&incoming_byte_stream->slices);
1653 incoming_byte_stream->on_next = NULL;
1654 incoming_byte_stream->is_tail = 1;
Craig Tiller38edec62015-12-14 15:01:29 -08001655 incoming_byte_stream->failed = 0;
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001656 if (add_to_queue->head == NULL) {
1657 add_to_queue->head = incoming_byte_stream;
1658 } else {
1659 add_to_queue->tail->is_tail = 0;
1660 add_to_queue->tail->next_message = incoming_byte_stream;
1661 }
1662 add_to_queue->tail = incoming_byte_stream;
1663 return incoming_byte_stream;
1664}
1665
Craig Tiller0cb803d2016-03-02 22:17:24 -08001666/*******************************************************************************
Craig Tiller285b8822015-06-17 15:58:13 -07001667 * TRACING
1668 */
1669
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001670static char *format_flowctl_context_var(const char *context, const char *var,
Craig Tiller7536af02015-12-22 13:49:30 -08001671 int64_t val, uint32_t id,
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001672 char **scope) {
1673 char *underscore_pos;
1674 char *result;
1675 if (context == NULL) {
1676 *scope = NULL;
1677 gpr_asprintf(&result, "%s(%lld)", var, val);
1678 return result;
Craig Tillera82950e2015-09-22 12:33:20 -07001679 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001680 underscore_pos = strchr(context, '_');
1681 *scope = gpr_strdup(context);
1682 (*scope)[underscore_pos - context] = 0;
1683 if (id != 0) {
1684 char *tmp = *scope;
1685 gpr_asprintf(scope, "%s[%d]", tmp, id);
1686 gpr_free(tmp);
1687 }
1688 gpr_asprintf(&result, "%s.%s(%lld)", underscore_pos + 1, var, val);
1689 return result;
1690}
1691
1692static int samestr(char *a, char *b) {
1693 if (a == NULL) {
1694 return b == NULL;
1695 }
1696 if (b == NULL) {
1697 return 0;
1698 }
1699 return 0 == strcmp(a, b);
1700}
1701
1702void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
1703 grpc_chttp2_flowctl_op op, const char *context1,
1704 const char *var1, const char *context2,
1705 const char *var2, int is_client,
Craig Tiller7536af02015-12-22 13:49:30 -08001706 uint32_t stream_id, int64_t val1, int64_t val2) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -08001707 char *scope1;
1708 char *scope2;
1709 char *label1 =
1710 format_flowctl_context_var(context1, var1, val1, stream_id, &scope1);
1711 char *label2 =
1712 format_flowctl_context_var(context2, var2, val2, stream_id, &scope2);
1713 char *clisvr = is_client ? "client" : "server";
1714 char *prefix;
1715
1716 gpr_asprintf(&prefix, "FLOW % 8s: %s % 11s ", phase, clisvr, scope1);
1717
1718 switch (op) {
1719 case GRPC_CHTTP2_FLOWCTL_MOVE:
1720 GPR_ASSERT(samestr(scope1, scope2));
1721 if (val2 != 0) {
1722 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
1723 "%sMOVE % 40s <- % 40s giving %d", prefix, label1, label2,
1724 val1 + val2);
1725 }
1726 break;
1727 case GRPC_CHTTP2_FLOWCTL_CREDIT:
1728 GPR_ASSERT(val2 >= 0);
1729 if (val2 != 0) {
1730 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
1731 "%sCREDIT % 40s by % 40s giving %d", prefix, label1, label2,
1732 val1 + val2);
1733 }
1734 break;
1735 case GRPC_CHTTP2_FLOWCTL_DEBIT:
1736 GPR_ASSERT(val2 >= 0);
1737 if (val2 != 0) {
1738 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
1739 "%sDEBIT % 40s by % 40s giving %d", prefix, label1, label2,
1740 val1 - val2);
1741 }
1742 break;
1743 }
1744
1745 gpr_free(scope1);
1746 gpr_free(scope2);
1747 gpr_free(label1);
1748 gpr_free(label2);
1749 gpr_free(prefix);
Craig Tiller285b8822015-06-17 15:58:13 -07001750}
1751
Craig Tiller0cb803d2016-03-02 22:17:24 -08001752/*******************************************************************************
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001753 * INTEGRATION GLUE
1754 */
1755
Craig Tillera82950e2015-09-22 12:33:20 -07001756static char *chttp2_get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *t) {
1757 return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string);
Craig Tiller1b22b9d2015-07-20 13:42:22 -07001758}
1759
Craig Tillerf40df232016-03-25 13:38:14 -07001760static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
1761 "chttp2",
1762 init_stream,
1763 set_pollset,
1764 perform_stream_op,
1765 perform_transport_op,
1766 destroy_stream,
1767 destroy_transport,
1768 chttp2_get_peer};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001769
Craig Tillera82950e2015-09-22 12:33:20 -07001770grpc_transport *grpc_create_chttp2_transport(
1771 grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
Craig Tillerb2b42612015-11-20 12:02:17 -08001772 grpc_endpoint *ep, int is_client) {
Craig Tillera82950e2015-09-22 12:33:20 -07001773 grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport));
Craig Tillerb2b42612015-11-20 12:02:17 -08001774 init_transport(exec_ctx, t, channel_args, ep, is_client != 0);
Craig Tiller1064f8b2015-06-25 13:52:57 -07001775 return &t->base;
Craig Tiller190d3602015-02-18 09:23:38 -08001776}
Craig Tiller825b21c2015-07-06 08:35:02 -07001777
Craig Tillera82950e2015-09-22 12:33:20 -07001778void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
1779 grpc_transport *transport,
1780 gpr_slice *slices, size_t nslices) {
1781 grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
1782 REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */
1783 gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
1784 recv_data(exec_ctx, t, 1);
Craig Tiller06059952015-02-18 08:34:56 -08001785}