blob: b8705cc49bbdca9cd0ba6b5286b6dadf9efdc6db [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, 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"
52#include "src/core/transport/transport_impl.h"
53
ctiller493fbcc2014-12-07 15:09:10 -080054#define DEFAULT_WINDOW 65535
55#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080056#define MAX_WINDOW 0x7fffffffu
57
Craig Tiller7098c032015-05-04 10:18:28 -070058#define MAX_CLIENT_STREAM_ID 0x7fffffffu
59
Craig Tillerfaa84802015-03-01 21:56:38 -080060int grpc_http_trace = 0;
Craig Tiller6a8c0382015-04-28 10:01:22 -070061int grpc_flowctl_trace = 0;
Craig Tillerfaa84802015-03-01 21:56:38 -080062
Craig Tiller4aa71a12015-06-15 13:00:55 -070063#define TRANSPORT_FROM_WRITING(tw) \
64 ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
65 writing)))
Craig Tillerd20efd22015-06-12 16:17:09 -070066
Craig Tillercfb5db92015-06-15 17:14:41 -070067#define TRANSPORT_FROM_PARSING(tw) \
68 ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
69 parsing)))
70
Craig Tiller98505102015-06-16 11:33:15 -070071#define TRANSPORT_FROM_GLOBAL(tg) \
Craig Tiller5dc3b302015-06-15 16:06:50 -070072 ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \
73 global)))
74
75#define STREAM_FROM_GLOBAL(sg) \
Craig Tiller98505102015-06-16 11:33:15 -070076 ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global)))
Craig Tiller5dc3b302015-06-15 16:06:50 -070077
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080078static const grpc_transport_vtable vtable;
79
Craig Tillerb084d902015-06-12 07:50:02 -070080static void lock(grpc_chttp2_transport *t);
81static void unlock(grpc_chttp2_transport *t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080082
Craig Tiller83fb0702015-06-16 21:13:07 -070083static void unlock_check_read_write_state(grpc_chttp2_transport *t);
Craig Tiller5dc3b302015-06-15 16:06:50 -070084
Craig Tiller4aa71a12015-06-15 13:00:55 -070085/* forward declarations of various callbacks that we'll build closures around */
Craig Tiller1e6facb2015-06-11 22:47:11 -070086static void writing_action(void *t, int iomgr_success_ignored);
Craig Tiller99f80552015-06-11 16:26:03 -070087
Craig Tiller4aa71a12015-06-15 13:00:55 -070088/** Set a transport level setting, and push it to our peer */
89static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
90 gpr_uint32 value);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080091
Craig Tiller4aa71a12015-06-15 13:00:55 -070092/** Endpoint callback to process incoming data */
Craig Tillerb0298592015-08-27 07:38:01 -070093static void recv_data(void *tp, int success);
Craig Tiller4aa71a12015-06-15 13:00:55 -070094
95/** Start disconnection chain */
96static void drop_connection(grpc_chttp2_transport *t);
97
Craig Tiller5dc3b302015-06-15 16:06:50 -070098/** Perform a transport_op */
Craig Tiller1064f8b2015-06-25 13:52:57 -070099static void perform_stream_op_locked(
100 grpc_chttp2_transport_global *transport_global,
101 grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700102
103/** Cancel a stream: coming from the transport API */
Craig Tiller98505102015-06-16 11:33:15 -0700104static void cancel_from_api(grpc_chttp2_transport_global *transport_global,
105 grpc_chttp2_stream_global *stream_global,
106 grpc_status_code status);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700107
Craig Tiller45ce9272015-07-31 11:22:35 -0700108static void close_from_api(grpc_chttp2_transport_global *transport_global,
109 grpc_chttp2_stream_global *stream_global,
110 grpc_status_code status,
111 gpr_slice *optional_message);
112
Craig Tiller5dc3b302015-06-15 16:06:50 -0700113/** Add endpoint from this transport to pollset */
114static void add_to_pollset_locked(grpc_chttp2_transport *t,
115 grpc_pollset *pollset);
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700116static void add_to_pollset_set_locked(grpc_chttp2_transport *t,
Craig Tillerd6c98df2015-08-18 09:33:44 -0700117 grpc_pollset_set *pollset_set);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700118
Craig Tiller564872d2015-06-18 11:21:22 -0700119/** Start new streams that have been created if we can */
120static void maybe_start_some_streams(
121 grpc_chttp2_transport_global *transport_global);
122
Craig Tiller079a11b2015-06-30 10:07:15 -0700123static void connectivity_state_set(
124 grpc_chttp2_transport_global *transport_global,
Craig Tiller03dc6552015-07-17 23:12:34 -0700125 grpc_connectivity_state state, const char *reason);
Craig Tillerff3ae682015-06-29 17:44:04 -0700126
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800127/*
128 * CONSTRUCTION/DESTRUCTION/REFCOUNTING
129 */
130
Craig Tillerb084d902015-06-12 07:50:02 -0700131static void destruct_transport(grpc_chttp2_transport *t) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800132 size_t i;
133
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800134 gpr_mu_lock(&t->mu);
135
136 GPR_ASSERT(t->ep == NULL);
137
Craig Tiller99f80552015-06-11 16:26:03 -0700138 gpr_slice_buffer_destroy(&t->global.qbuf);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700139
Craig Tiller99f80552015-06-11 16:26:03 -0700140 gpr_slice_buffer_destroy(&t->writing.outbuf);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700141 grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor);
142
Craig Tiller99f80552015-06-11 16:26:03 -0700143 gpr_slice_buffer_destroy(&t->parsing.qbuf);
Craig Tillerb0298592015-08-27 07:38:01 -0700144 gpr_slice_buffer_destroy(&t->read_buffer);
Craig Tiller42cdf942015-06-12 07:35:44 -0700145 grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
146 grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800147
Craig Tiller1a65a232015-07-06 10:22:32 -0700148 GRPC_MDSTR_UNREF(t->parsing.str_grpc_timeout);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800149
150 for (i = 0; i < STREAM_LIST_COUNT; i++) {
151 GPR_ASSERT(t->lists[i].head == NULL);
152 GPR_ASSERT(t->lists[i].tail == NULL);
153 }
154
Craig Tiller606d8742015-06-15 06:58:50 -0700155 GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0);
156 GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800157
Craig Tiller606d8742015-06-15 06:58:50 -0700158 grpc_chttp2_stream_map_destroy(&t->parsing_stream_map);
159 grpc_chttp2_stream_map_destroy(&t->new_stream_map);
Craig Tiller08a1cf82015-06-29 09:37:52 -0700160 grpc_connectivity_state_destroy(&t->channel_callback.state_tracker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800161
162 gpr_mu_unlock(&t->mu);
163 gpr_mu_destroy(&t->mu);
164
165 /* callback remaining pings: they're not allowed to call into the transpot,
166 and maybe they hold resources that need to be freed */
Craig Tiller606d8742015-06-15 06:58:50 -0700167 while (t->global.pings.next != &t->global.pings) {
168 grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
169 grpc_iomgr_add_delayed_callback(ping->on_recv, 0);
170 ping->next->prev = ping->prev;
171 ping->prev->next = ping->next;
172 gpr_free(ping);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800173 }
Craig Tiller8ed35ea2015-01-30 11:27:43 -0800174
Craig Tiller9be83ee2015-02-18 14:16:15 -0800175 grpc_mdctx_unref(t->metadata_context);
176
Craig Tiller1b22b9d2015-07-20 13:42:22 -0700177 gpr_free(t->peer_string);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800178 gpr_free(t);
179}
180
Craig Tiller759eb322015-06-16 22:41:18 -0700181#ifdef REFCOUNTING_DEBUG
182#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
183#define UNREF_TRANSPORT(t, r) unref_transport(t, r, __FILE__, __LINE__)
Craig Tiller285b8822015-06-17 15:58:13 -0700184static void unref_transport(grpc_chttp2_transport *t, const char *reason,
185 const char *file, int line) {
186 gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count,
187 t->refs.count - 1, reason, file, line);
Craig Tiller759eb322015-06-16 22:41:18 -0700188 if (!gpr_unref(&t->refs)) return;
189 destruct_transport(t);
190}
191
Craig Tiller285b8822015-06-17 15:58:13 -0700192static void ref_transport(grpc_chttp2_transport *t, const char *reason,
193 const char *file, int line) {
194 gpr_log(GPR_DEBUG, "chttp2: ref:%p %d->%d %s [%s:%d]", t, t->refs.count,
195 t->refs.count + 1, reason, file, line);
196 gpr_ref(&t->refs);
Craig Tiller759eb322015-06-16 22:41:18 -0700197}
198#else
199#define REF_TRANSPORT(t, r) ref_transport(t)
200#define UNREF_TRANSPORT(t, r) unref_transport(t)
Craig Tillerb084d902015-06-12 07:50:02 -0700201static void unref_transport(grpc_chttp2_transport *t) {
Craig Tiller9be83ee2015-02-18 14:16:15 -0800202 if (!gpr_unref(&t->refs)) return;
203 destruct_transport(t);
204}
205
Craig Tillerb084d902015-06-12 07:50:02 -0700206static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
Craig Tiller759eb322015-06-16 22:41:18 -0700207#endif
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800208
Craig Tiller4aa71a12015-06-15 13:00:55 -0700209static void init_transport(grpc_chttp2_transport *t,
Craig Tiller4aa71a12015-06-15 13:00:55 -0700210 const grpc_channel_args *channel_args,
Craig Tiller825b21c2015-07-06 08:35:02 -0700211 grpc_endpoint *ep, grpc_mdctx *mdctx,
212 int is_client) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800213 size_t i;
214 int j;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800215
Craig Tiller4aa71a12015-06-15 13:00:55 -0700216 GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
217 GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800218
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700219 memset(t, 0, sizeof(*t));
220
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800221 t->base.vtable = &vtable;
222 t->ep = ep;
223 /* one ref is for destroy, the other for when ep becomes NULL */
224 gpr_ref_init(&t->refs, 2);
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700225 /* ref is dropped at transport close() */
226 gpr_ref_init(&t->shutdown_ep_refs, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800227 gpr_mu_init(&t->mu);
Craig Tiller9be83ee2015-02-18 14:16:15 -0800228 grpc_mdctx_ref(mdctx);
Craig Tiller1b22b9d2015-07-20 13:42:22 -0700229 t->peer_string = grpc_endpoint_get_peer(ep);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800230 t->metadata_context = mdctx;
Craig Tiller606d8742015-06-15 06:58:50 -0700231 t->endpoint_reading = 1;
Craig Tiller606d8742015-06-15 06:58:50 -0700232 t->global.next_stream_id = is_client ? 1 : 2;
233 t->global.is_client = is_client;
Craig Tillerd20efd22015-06-12 16:17:09 -0700234 t->global.outgoing_window = DEFAULT_WINDOW;
235 t->global.incoming_window = DEFAULT_WINDOW;
236 t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
Craig Tiller606d8742015-06-15 06:58:50 -0700237 t->global.ping_counter = 1;
Craig Tiller83fb0702015-06-16 21:13:07 -0700238 t->global.pings.next = t->global.pings.prev = &t->global.pings;
Craig Tiller606d8742015-06-15 06:58:50 -0700239 t->parsing.is_client = is_client;
240 t->parsing.str_grpc_timeout =
Craig Tiller6999c092015-07-22 08:14:12 -0700241 grpc_mdstr_from_string(t->metadata_context, "grpc-timeout", 0);
Craig Tillerab630732015-06-25 11:20:01 -0700242 t->parsing.deframe_state =
243 is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
Craig Tiller285b8822015-06-17 15:58:13 -0700244 t->writing.is_client = is_client;
Craig Tiller08a1cf82015-06-29 09:37:52 -0700245 grpc_connectivity_state_init(&t->channel_callback.state_tracker,
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700246 GRPC_CHANNEL_READY, "transport");
Craig Tiller42cdf942015-06-12 07:35:44 -0700247
Craig Tiller99f80552015-06-11 16:26:03 -0700248 gpr_slice_buffer_init(&t->global.qbuf);
Craig Tiller42cdf942015-06-12 07:35:44 -0700249
Craig Tiller99f80552015-06-11 16:26:03 -0700250 gpr_slice_buffer_init(&t->writing.outbuf);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700251 grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx);
Craig Tillerd20efd22015-06-12 16:17:09 -0700252 grpc_iomgr_closure_init(&t->writing_action, writing_action, t);
Craig Tiller42cdf942015-06-12 07:35:44 -0700253
Craig Tiller99f80552015-06-11 16:26:03 -0700254 gpr_slice_buffer_init(&t->parsing.qbuf);
Craig Tiller42cdf942015-06-12 07:35:44 -0700255 grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
256 grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context);
257
Craig Tillerb0298592015-08-27 07:38:01 -0700258 grpc_iomgr_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
259 &t->writing);
260 grpc_iomgr_closure_init(&t->recv_data, recv_data, t);
261 gpr_slice_buffer_init(&t->read_buffer);
262
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800263 if (is_client) {
Craig Tiller4aa71a12015-06-15 13:00:55 -0700264 gpr_slice_buffer_add(
265 &t->global.qbuf,
266 gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800267 }
268 /* 8 is a random stab in the dark as to a good initial size: it's small enough
269 that it shouldn't waste memory for infrequently used connections, yet
270 large enough that the exponential growth should happen nicely when it's
271 needed.
272 TODO(ctiller): tune this */
Craig Tiller606d8742015-06-15 06:58:50 -0700273 grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8);
274 grpc_chttp2_stream_map_init(&t->new_stream_map, 8);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800275
276 /* copy in initial settings to all setting sets */
Craig Tillercdf52bc2015-06-16 13:00:27 -0700277 for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) {
278 t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value;
Craig Tillerab630732015-06-25 11:20:01 -0700279 for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) {
Craig Tillercdf52bc2015-06-16 13:00:27 -0700280 t->global.settings[j][i] =
281 grpc_chttp2_settings_parameters[i].default_value;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800282 }
283 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700284 t->global.dirtied_local_settings = 1;
ctiller493fbcc2014-12-07 15:09:10 -0800285 /* Hack: it's common for implementations to assume 65536 bytes initial send
286 window -- this should by rights be 0 */
Craig Tillerd20efd22015-06-12 16:17:09 -0700287 t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
288 t->global.sent_local_settings = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800289
290 /* configure http2 the way we like it */
Craig Tiller606d8742015-06-15 06:58:50 -0700291 if (is_client) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800292 push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
293 push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
294 }
ctiller493fbcc2014-12-07 15:09:10 -0800295 push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800296
297 if (channel_args) {
298 for (i = 0; i < channel_args->num_args; i++) {
299 if (0 ==
300 strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) {
Craig Tiller606d8742015-06-15 06:58:50 -0700301 if (is_client) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800302 gpr_log(GPR_ERROR, "%s: is ignored on the client",
303 GRPC_ARG_MAX_CONCURRENT_STREAMS);
304 } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
305 gpr_log(GPR_ERROR, "%s: must be an integer",
306 GRPC_ARG_MAX_CONCURRENT_STREAMS);
307 } else {
308 push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
309 channel_args->args[i].value.integer);
310 }
Craig Tiller88025582015-05-04 09:41:10 -0700311 } else if (0 == strcmp(channel_args->args[i].key,
312 GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) {
313 if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
314 gpr_log(GPR_ERROR, "%s: must be an integer",
315 GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER);
Craig Tiller606d8742015-06-15 06:58:50 -0700316 } else if ((t->global.next_stream_id & 1) !=
Craig Tiller88025582015-05-04 09:41:10 -0700317 (channel_args->args[i].value.integer & 1)) {
318 gpr_log(GPR_ERROR, "%s: low bit must be %d on %s",
Craig Tiller4aa71a12015-06-15 13:00:55 -0700319 GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER,
320 t->global.next_stream_id & 1,
Craig Tiller606d8742015-06-15 06:58:50 -0700321 is_client ? "client" : "server");
Craig Tiller88025582015-05-04 09:41:10 -0700322 } else {
Craig Tiller606d8742015-06-15 06:58:50 -0700323 t->global.next_stream_id = channel_args->args[i].value.integer;
Craig Tiller88025582015-05-04 09:41:10 -0700324 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800325 }
326 }
327 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800328}
329
330static void destroy_transport(grpc_transport *gt) {
Craig Tillerb084d902015-06-12 07:50:02 -0700331 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800332
Craig Tiller748fe3f2015-03-02 07:48:50 -0800333 lock(t);
Craig Tiller1fe7b9d2015-02-17 11:57:02 -0800334 t->destroying = 1;
Craig Tiller748fe3f2015-03-02 07:48:50 -0800335 drop_connection(t);
336 unlock(t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800337
Craig Tiller759eb322015-06-16 22:41:18 -0700338 UNREF_TRANSPORT(t, "destroy");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800339}
340
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700341/** block grpc_endpoint_shutdown being called until a paired
342 allow_endpoint_shutdown is made */
343static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) {
344 GPR_ASSERT(t->shutdown_ep_refs.count);
345 gpr_ref(&t->shutdown_ep_refs);
346}
347
348static void allow_endpoint_shutdown(grpc_chttp2_transport *t) {
349 if (gpr_unref(&t->shutdown_ep_refs)) {
350 grpc_endpoint_shutdown(t->ep);
351 }
352}
353
Craig Tillerb084d902015-06-12 07:50:02 -0700354static void close_transport_locked(grpc_chttp2_transport *t) {
Craig Tillerec3aa892015-05-29 17:22:17 -0700355 if (!t->closed) {
356 t->closed = 1;
Craig Tiller03dc6552015-07-17 23:12:34 -0700357 connectivity_state_set(&t->global, GRPC_CHANNEL_FATAL_FAILURE,
358 "close_transport");
Craig Tillerec3aa892015-05-29 17:22:17 -0700359 if (t->ep) {
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700360 allow_endpoint_shutdown(t);
Craig Tillerec3aa892015-05-29 17:22:17 -0700361 }
362 }
363}
364
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800365static int init_stream(grpc_transport *gt, grpc_stream *gs,
Craig Tiller079a11b2015-06-30 10:07:15 -0700366 const void *server_data,
367 grpc_transport_stream_op *initial_op) {
Craig Tillerb084d902015-06-12 07:50:02 -0700368 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
369 grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800370
Craig Tillerc079c112015-04-22 15:23:39 -0700371 memset(s, 0, sizeof(*s));
372
Craig Tiller5dc3b302015-06-15 16:06:50 -0700373 grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.incoming_metadata);
374 grpc_chttp2_incoming_metadata_buffer_init(&s->global.incoming_metadata);
Craig Tiller606d8742015-06-15 06:58:50 -0700375 grpc_sopb_init(&s->writing.sopb);
Craig Tillerf73fcd12015-06-16 16:25:26 -0700376 grpc_sopb_init(&s->global.incoming_sopb);
Craig Tiller606d8742015-06-15 06:58:50 -0700377 grpc_chttp2_data_parser_init(&s->parsing.data_parser);
378
Craig Tiller759eb322015-06-16 22:41:18 -0700379 REF_TRANSPORT(t, "stream");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800380
Craig Tillere0617622015-06-11 09:37:17 -0700381 lock(t);
Craig Tiller6459db42015-06-15 17:11:45 -0700382 grpc_chttp2_register_stream(t, s);
Craig Tiller606d8742015-06-15 06:58:50 -0700383 if (server_data) {
384 GPR_ASSERT(t->parsing_active);
Craig Tillerd20efd22015-06-12 16:17:09 -0700385 s->global.id = (gpr_uint32)(gpr_uintptr)server_data;
386 s->global.outgoing_window =
Craig Tillerab630732015-06-25 11:20:01 -0700387 t->global.settings[GRPC_PEER_SETTINGS]
388 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tillerd6c98df2015-08-18 09:33:44 -0700389 s->global.max_recv_bytes = s->parsing.incoming_window =
Craig Tiller27166a62015-07-05 21:08:33 -0700390 s->global.incoming_window =
Craig Tillerd6c98df2015-08-18 09:33:44 -0700391 t->global.settings[GRPC_SENT_SETTINGS]
392 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tiller606d8742015-06-15 06:58:50 -0700393 *t->accepting_stream = s;
Craig Tiller285b8822015-06-17 15:58:13 -0700394 grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s);
Craig Tiller31123db2015-06-16 17:06:31 -0700395 s->global.in_stream_map = 1;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800396 }
397
Craig Tiller1064f8b2015-06-25 13:52:57 -0700398 if (initial_op) perform_stream_op_locked(&t->global, &s->global, initial_op);
Craig Tillere0617622015-06-11 09:37:17 -0700399 unlock(t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800400
401 return 0;
402}
403
404static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
Craig Tillerb084d902015-06-12 07:50:02 -0700405 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
406 grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700407 int i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800408
409 gpr_mu_lock(&t->mu);
410
Craig Tiller4aa71a12015-06-15 13:00:55 -0700411 GPR_ASSERT(s->global.published_state == GRPC_STREAM_CLOSED ||
412 s->global.id == 0);
Craig Tiller83fb0702015-06-16 21:13:07 -0700413 GPR_ASSERT(!s->global.in_stream_map);
Craig Tiller9188d7a2015-07-05 12:44:37 -0700414 if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
415 close_transport_locked(t);
416 }
Craig Tiller759eb322015-06-16 22:41:18 -0700417 if (!t->parsing_active && s->global.id) {
Craig Tiller285b8822015-06-17 15:58:13 -0700418 GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
419 s->global.id) == NULL);
Craig Tiller759eb322015-06-16 22:41:18 -0700420 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800421
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700422 grpc_chttp2_list_remove_incoming_window_updated(&t->global, &s->global);
Craig Tillere3086f82015-07-23 16:25:00 -0700423 grpc_chttp2_list_remove_writable_stream(&t->global, &s->global);
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700424
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800425 gpr_mu_unlock(&t->mu);
426
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700427 for (i = 0; i < STREAM_LIST_COUNT; i++) {
Craig Tiller05cc0c42015-07-23 16:01:27 -0700428 if (s->included[i]) {
429 gpr_log(GPR_ERROR, "%s stream %d still included in list %d",
430 t->global.is_client ? "client" : "server", s->global.id, i);
431 abort();
432 }
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700433 }
434
Craig Tillerd20efd22015-06-12 16:17:09 -0700435 GPR_ASSERT(s->global.outgoing_sopb == NULL);
Craig Tiller6905b7c2015-06-16 15:33:33 -0700436 GPR_ASSERT(s->global.publish_sopb == NULL);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700437 grpc_sopb_destroy(&s->writing.sopb);
Craig Tiller0b442a82015-06-30 17:04:32 -0700438 grpc_sopb_destroy(&s->global.incoming_sopb);
Craig Tiller606d8742015-06-15 06:58:50 -0700439 grpc_chttp2_data_parser_destroy(&s->parsing.data_parser);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700440 grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.incoming_metadata);
441 grpc_chttp2_incoming_metadata_buffer_destroy(&s->global.incoming_metadata);
Craig Tiller47073d52015-06-30 10:19:22 -0700442 grpc_chttp2_incoming_metadata_live_op_buffer_end(
443 &s->global.outstanding_metadata);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800444
Craig Tiller759eb322015-06-16 22:41:18 -0700445 UNREF_TRANSPORT(t, "stream");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800446}
447
Craig Tillercfb5db92015-06-15 17:14:41 -0700448grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
449 grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id) {
450 grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
Craig Tiller98505102015-06-16 11:33:15 -0700451 grpc_chttp2_stream *s =
452 grpc_chttp2_stream_map_find(&t->parsing_stream_map, id);
Craig Tillercf1e3192015-06-16 14:28:22 -0700453 return s ? &s->parsing : NULL;
Craig Tillercfb5db92015-06-15 17:14:41 -0700454}
455
Craig Tiller1937b062015-06-16 08:47:38 -0700456grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
457 grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id) {
458 grpc_chttp2_stream *accepting;
459 grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
460 GPR_ASSERT(t->accepting_stream == NULL);
461 t->accepting_stream = &accepting;
Craig Tiller1064f8b2015-06-25 13:52:57 -0700462 t->channel_callback.accept_stream(t->channel_callback.accept_stream_user_data,
463 &t->base, (void *)(gpr_uintptr)id);
Craig Tiller1937b062015-06-16 08:47:38 -0700464 t->accepting_stream = NULL;
465 return &accepting->parsing;
466}
467
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800468/*
469 * LOCK MANAGEMENT
470 */
471
Craig Tiller4aa71a12015-06-15 13:00:55 -0700472/* We take a grpc_chttp2_transport-global lock in response to calls coming in
473 from above,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800474 and in response to data being received from below. New data to be written
475 is always queued, as are callbacks to process data. During unlock() we
476 check our todo lists and initiate callbacks and flush writes. */
477
Craig Tillerb084d902015-06-12 07:50:02 -0700478static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800479
Craig Tillerb084d902015-06-12 07:50:02 -0700480static void unlock(grpc_chttp2_transport *t) {
Craig Tiller1e6facb2015-06-11 22:47:11 -0700481 grpc_iomgr_closure *run_closures;
Craig Tiller99f80552015-06-11 16:26:03 -0700482
Craig Tiller8823b142015-06-18 11:41:24 -0700483 unlock_check_read_write_state(t);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700484 if (!t->writing_active && !t->closed &&
Craig Tiller4aa71a12015-06-15 13:00:55 -0700485 grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
Craig Tillerd20efd22015-06-12 16:17:09 -0700486 t->writing_active = 1;
Craig Tiller759eb322015-06-16 22:41:18 -0700487 REF_TRANSPORT(t, "writing");
Craig Tiller1937b062015-06-16 08:47:38 -0700488 grpc_chttp2_schedule_closure(&t->global, &t->writing_action, 1);
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700489 prevent_endpoint_shutdown(t);
Craig Tillerd20efd22015-06-12 16:17:09 -0700490 }
Craig Tiller99f80552015-06-11 16:26:03 -0700491
Craig Tillerff3ae682015-06-29 17:44:04 -0700492 run_closures = t->global.pending_closures_head;
493 t->global.pending_closures_head = NULL;
494 t->global.pending_closures_tail = NULL;
Craig Tiller99f80552015-06-11 16:26:03 -0700495
496 gpr_mu_unlock(&t->mu);
497
Craig Tiller1e6facb2015-06-11 22:47:11 -0700498 while (run_closures) {
499 grpc_iomgr_closure *next = run_closures->next;
500 run_closures->cb(run_closures->cb_arg, run_closures->success);
501 run_closures = next;
Craig Tiller99f80552015-06-11 16:26:03 -0700502 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800503}
504
505/*
506 * OUTPUT PROCESSING
507 */
508
Craig Tillerb084d902015-06-12 07:50:02 -0700509static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800510 gpr_uint32 value) {
511 const grpc_chttp2_setting_parameters *sp =
512 &grpc_chttp2_settings_parameters[id];
513 gpr_uint32 use_value = GPR_CLAMP(value, sp->min_value, sp->max_value);
514 if (use_value != value) {
515 gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name,
516 value, use_value);
517 }
Craig Tillerab630732015-06-25 11:20:01 -0700518 if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) {
519 t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value;
Craig Tillerd20efd22015-06-12 16:17:09 -0700520 t->global.dirtied_local_settings = 1;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800521 }
522}
523
Craig Tillerb0298592015-08-27 07:38:01 -0700524void grpc_chttp2_terminate_writing(void *transport_writing_ptr, int success) {
525 grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
Craig Tillerd20efd22015-06-12 16:17:09 -0700526 grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
ctiller00297df2015-01-12 11:23:09 -0800527
528 lock(t);
Craig Tillerd20efd22015-06-12 16:17:09 -0700529
ctiller00297df2015-01-12 11:23:09 -0800530 if (!success) {
531 drop_connection(t);
532 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700533
534 /* cleanup writing related jazz */
Craig Tiller606d8742015-06-15 06:58:50 -0700535 grpc_chttp2_cleanup_writing(&t->global, &t->writing);
Craig Tillerd20efd22015-06-12 16:17:09 -0700536
ctiller00297df2015-01-12 11:23:09 -0800537 /* leave the writing flag up on shutdown to prevent further writes in unlock()
538 from starting */
Craig Tillerd20efd22015-06-12 16:17:09 -0700539 t->writing_active = 0;
Craig Tillerf932fd52015-06-17 07:38:20 -0700540 if (t->ep && !t->endpoint_reading) {
ctiller00297df2015-01-12 11:23:09 -0800541 grpc_endpoint_destroy(t->ep);
542 t->ep = NULL;
Craig Tiller285b8822015-06-17 15:58:13 -0700543 UNREF_TRANSPORT(
544 t, "disconnect"); /* safe because we'll still have the ref for write */
ctiller00297df2015-01-12 11:23:09 -0800545 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700546
ctiller00297df2015-01-12 11:23:09 -0800547 unlock(t);
548
Craig Tiller759eb322015-06-16 22:41:18 -0700549 UNREF_TRANSPORT(t, "writing");
ctiller00297df2015-01-12 11:23:09 -0800550}
551
Craig Tiller1e6facb2015-06-11 22:47:11 -0700552static void writing_action(void *gt, int iomgr_success_ignored) {
Craig Tillerb084d902015-06-12 07:50:02 -0700553 grpc_chttp2_transport *t = gt;
Craig Tillerd20efd22015-06-12 16:17:09 -0700554 grpc_chttp2_perform_writes(&t->writing, t->ep);
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700555 allow_endpoint_shutdown(t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800556}
557
Craig Tiller98505102015-06-16 11:33:15 -0700558void grpc_chttp2_add_incoming_goaway(
559 grpc_chttp2_transport_global *transport_global, gpr_uint32 goaway_error,
560 gpr_slice goaway_text) {
Julien Boeuf0ac7cdd2015-06-30 14:53:05 +0200561 char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
Julien Boeufbe1a4992015-06-29 22:10:32 +0200562 gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg);
Craig Tiller564872d2015-06-18 11:21:22 -0700563 gpr_free(msg);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700564 gpr_slice_unref(goaway_text);
565 transport_global->seen_goaway = 1;
Craig Tiller03dc6552015-07-17 23:12:34 -0700566 connectivity_state_set(transport_global, GRPC_CHANNEL_FATAL_FAILURE,
567 "got_goaway");
Craig Tiller7098c032015-05-04 10:18:28 -0700568}
569
Craig Tiller98505102015-06-16 11:33:15 -0700570static void maybe_start_some_streams(
571 grpc_chttp2_transport_global *transport_global) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700572 grpc_chttp2_stream_global *stream_global;
Craig Tiller4aa71a12015-06-15 13:00:55 -0700573 /* start streams where we have free grpc_chttp2_stream ids and free
574 * concurrency */
Craig Tiller5dc3b302015-06-15 16:06:50 -0700575 while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID &&
576 transport_global->concurrent_stream_count <
Craig Tillerab630732015-06-25 11:20:01 -0700577 transport_global
578 ->settings[GRPC_PEER_SETTINGS]
579 [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] &&
Craig Tiller98505102015-06-16 11:33:15 -0700580 grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
581 &stream_global)) {
Craig Tillerab630732015-06-25 11:20:01 -0700582 GRPC_CHTTP2_IF_TRACING(gpr_log(
583 GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d",
584 transport_global->is_client ? "CLI" : "SVR", stream_global,
585 transport_global->next_stream_id));
Craig Tillerc1f75602015-04-24 11:44:53 -0700586
Craig Tiller564872d2015-06-18 11:21:22 -0700587 GPR_ASSERT(stream_global->id == 0);
588 stream_global->id = transport_global->next_stream_id;
589 transport_global->next_stream_id += 2;
590
591 if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
Craig Tiller03dc6552015-07-17 23:12:34 -0700592 connectivity_state_set(transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
593 "no_more_stream_ids");
Craig Tiller7098c032015-05-04 10:18:28 -0700594 }
595
Craig Tiller5dc3b302015-06-15 16:06:50 -0700596 stream_global->outgoing_window =
Craig Tillerab630732015-06-25 11:20:01 -0700597 transport_global->settings[GRPC_PEER_SETTINGS]
598 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tiller5dc3b302015-06-15 16:06:50 -0700599 stream_global->incoming_window =
Craig Tillerab630732015-06-25 11:20:01 -0700600 transport_global->settings[GRPC_SENT_SETTINGS]
601 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tillerd6c98df2015-08-18 09:33:44 -0700602 stream_global->max_recv_bytes =
Craig Tiller27166a62015-07-05 21:08:33 -0700603 GPR_MAX(stream_global->incoming_window, stream_global->max_recv_bytes);
Craig Tiller98505102015-06-16 11:33:15 -0700604 grpc_chttp2_stream_map_add(
605 &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map,
606 stream_global->id, STREAM_FROM_GLOBAL(stream_global));
Craig Tiller31123db2015-06-16 17:06:31 -0700607 stream_global->in_stream_map = 1;
Craig Tiller5dc3b302015-06-15 16:06:50 -0700608 transport_global->concurrent_stream_count++;
Craig Tiller285b8822015-06-17 15:58:13 -0700609 grpc_chttp2_list_add_incoming_window_updated(transport_global,
610 stream_global);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700611 grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800612 }
Craig Tiller7098c032015-05-04 10:18:28 -0700613 /* cancel out streams that will never be started */
Craig Tiller564872d2015-06-18 11:21:22 -0700614 while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
Craig Tiller98505102015-06-16 11:33:15 -0700615 grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
616 &stream_global)) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700617 cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE);
Craig Tiller7098c032015-05-04 10:18:28 -0700618 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800619}
620
Craig Tiller1064f8b2015-06-25 13:52:57 -0700621static void perform_stream_op_locked(
622 grpc_chttp2_transport_global *transport_global,
623 grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
Craig Tiller2ea37fd2015-04-24 13:03:49 -0700624 if (op->cancel_with_status != GRPC_STATUS_OK) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700625 cancel_from_api(transport_global, stream_global, op->cancel_with_status);
Craig Tiller2ea37fd2015-04-24 13:03:49 -0700626 }
627
Craig Tiller45ce9272015-07-31 11:22:35 -0700628 if (op->close_with_status != GRPC_STATUS_OK) {
629 close_from_api(transport_global, stream_global, op->close_with_status,
630 op->optional_close_message);
631 }
632
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700633 if (op->send_ops) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700634 GPR_ASSERT(stream_global->outgoing_sopb == NULL);
635 stream_global->send_done_closure = op->on_done_send;
636 if (!stream_global->cancelled) {
Craig Tiller45ce9272015-07-31 11:22:35 -0700637 stream_global->written_anything = 1;
Craig Tiller5dc3b302015-06-15 16:06:50 -0700638 stream_global->outgoing_sopb = op->send_ops;
Craig Tillerab630732015-06-25 11:20:01 -0700639 if (op->is_last_send &&
640 stream_global->write_state == GRPC_WRITE_STATE_OPEN) {
641 stream_global->write_state = GRPC_WRITE_STATE_QUEUED_CLOSE;
Craig Tillerc079c112015-04-22 15:23:39 -0700642 }
Craig Tiller5dc3b302015-06-15 16:06:50 -0700643 if (stream_global->id == 0) {
Craig Tillerab630732015-06-25 11:20:01 -0700644 GRPC_CHTTP2_IF_TRACING(gpr_log(
Craig Tiller98505102015-06-16 11:33:15 -0700645 GPR_DEBUG,
646 "HTTP:%s: New grpc_chttp2_stream %p waiting for concurrency",
647 transport_global->is_client ? "CLI" : "SVR", stream_global));
648 grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
649 stream_global);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700650 maybe_start_some_streams(transport_global);
651 } else if (stream_global->outgoing_window > 0) {
652 grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
Craig Tillerc079c112015-04-22 15:23:39 -0700653 }
654 } else {
Craig Tiller606d8742015-06-15 06:58:50 -0700655 grpc_sopb_reset(op->send_ops);
Craig Tiller98505102015-06-16 11:33:15 -0700656 grpc_chttp2_schedule_closure(transport_global,
657 stream_global->send_done_closure, 0);
Craig Tillerc079c112015-04-22 15:23:39 -0700658 }
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700659 }
660
661 if (op->recv_ops) {
Craig Tiller6905b7c2015-06-16 15:33:33 -0700662 GPR_ASSERT(stream_global->publish_sopb == NULL);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700663 GPR_ASSERT(stream_global->published_state != GRPC_STREAM_CLOSED);
664 stream_global->recv_done_closure = op->on_done_recv;
Craig Tiller6905b7c2015-06-16 15:33:33 -0700665 stream_global->publish_sopb = op->recv_ops;
666 stream_global->publish_sopb->nops = 0;
Craig Tiller31123db2015-06-16 17:06:31 -0700667 stream_global->publish_state = op->recv_state;
Craig Tiller27166a62015-07-05 21:08:33 -0700668 if (stream_global->max_recv_bytes < op->max_recv_bytes) {
Craig Tillerd6c98df2015-08-18 09:33:44 -0700669 GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
670 "op", transport_global, stream_global, max_recv_bytes,
671 op->max_recv_bytes - stream_global->max_recv_bytes);
Craig Tiller5c517b12015-07-15 13:28:10 -0700672 GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
673 "op", transport_global, stream_global, unannounced_incoming_window,
674 op->max_recv_bytes - stream_global->max_recv_bytes);
Craig Tillerd6c98df2015-08-18 09:33:44 -0700675 stream_global->unannounced_incoming_window +=
676 op->max_recv_bytes - stream_global->max_recv_bytes;
Craig Tiller27166a62015-07-05 21:08:33 -0700677 stream_global->max_recv_bytes = op->max_recv_bytes;
Craig Tiller4efb6962015-06-03 09:32:41 -0700678 }
Craig Tiller98505102015-06-16 11:33:15 -0700679 grpc_chttp2_incoming_metadata_live_op_buffer_end(
680 &stream_global->outstanding_metadata);
Craig Tiller5c517b12015-07-15 13:28:10 -0700681 if (stream_global->id != 0) {
682 grpc_chttp2_list_add_read_write_state_changed(transport_global,
683 stream_global);
Craig Tiller994c2622015-07-23 14:00:58 -0700684 grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
Craig Tiller5c517b12015-07-15 13:28:10 -0700685 }
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700686 }
687
688 if (op->bind_pollset) {
Craig Tiller98505102015-06-16 11:33:15 -0700689 add_to_pollset_locked(TRANSPORT_FROM_GLOBAL(transport_global),
690 op->bind_pollset);
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700691 }
Craig Tiller5dde66e2015-06-02 09:05:23 -0700692
693 if (op->on_consumed) {
Craig Tiller1937b062015-06-16 08:47:38 -0700694 grpc_chttp2_schedule_closure(transport_global, op->on_consumed, 1);
Craig Tiller5dde66e2015-06-02 09:05:23 -0700695 }
Craig Tiller50d9db52015-04-23 10:52:14 -0700696}
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700697
Craig Tiller1064f8b2015-06-25 13:52:57 -0700698static void perform_stream_op(grpc_transport *gt, grpc_stream *gs,
699 grpc_transport_stream_op *op) {
Craig Tillerb084d902015-06-12 07:50:02 -0700700 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
701 grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
Craig Tiller50d9db52015-04-23 10:52:14 -0700702
703 lock(t);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700704 perform_stream_op_locked(&t->global, &s->global, op);
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700705 unlock(t);
706}
707
Craig Tiller1064f8b2015-06-25 13:52:57 -0700708static void send_ping_locked(grpc_chttp2_transport *t,
709 grpc_iomgr_closure *on_recv) {
Craig Tiller606d8742015-06-15 06:58:50 -0700710 grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p));
Craig Tiller606d8742015-06-15 06:58:50 -0700711 p->next = &t->global.pings;
712 p->prev = p->next->prev;
713 p->prev->next = p->next->prev = p;
714 p->id[0] = (t->global.ping_counter >> 56) & 0xff;
715 p->id[1] = (t->global.ping_counter >> 48) & 0xff;
716 p->id[2] = (t->global.ping_counter >> 40) & 0xff;
717 p->id[3] = (t->global.ping_counter >> 32) & 0xff;
718 p->id[4] = (t->global.ping_counter >> 24) & 0xff;
719 p->id[5] = (t->global.ping_counter >> 16) & 0xff;
720 p->id[6] = (t->global.ping_counter >> 8) & 0xff;
721 p->id[7] = t->global.ping_counter & 0xff;
722 p->on_recv = on_recv;
Craig Tiller1e6facb2015-06-11 22:47:11 -0700723 gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
Craig Tiller1064f8b2015-06-25 13:52:57 -0700724}
725
726static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
727 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700728 int close_transport = 0;
Craig Tiller1064f8b2015-06-25 13:52:57 -0700729
730 lock(t);
731
732 if (op->on_consumed) {
733 grpc_chttp2_schedule_closure(&t->global, op->on_consumed, 1);
734 }
735
736 if (op->on_connectivity_state_change) {
Craig Tiller08a1cf82015-06-29 09:37:52 -0700737 grpc_connectivity_state_notify_on_state_change(
738 &t->channel_callback.state_tracker, op->connectivity_state,
739 op->on_connectivity_state_change);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700740 }
741
742 if (op->send_goaway) {
Craig Tiller9188d7a2015-07-05 12:44:37 -0700743 t->global.sent_goaway = 1;
Craig Tiller1064f8b2015-06-25 13:52:57 -0700744 grpc_chttp2_goaway_append(
745 t->global.last_incoming_stream_id,
746 grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
Craig Tillerbea1e622015-07-07 09:53:40 -0700747 gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700748 close_transport = !grpc_chttp2_has_streams(t);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700749 }
750
751 if (op->set_accept_stream != NULL) {
752 t->channel_callback.accept_stream = op->set_accept_stream;
753 t->channel_callback.accept_stream_user_data =
754 op->set_accept_stream_user_data;
755 }
756
757 if (op->bind_pollset) {
758 add_to_pollset_locked(t, op->bind_pollset);
759 }
760
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700761 if (op->bind_pollset_set) {
762 add_to_pollset_set_locked(t, op->bind_pollset_set);
763 }
764
Craig Tiller1064f8b2015-06-25 13:52:57 -0700765 if (op->send_ping) {
766 send_ping_locked(t, op->send_ping);
767 }
768
769 if (op->disconnect) {
770 close_transport_locked(t);
771 }
772
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800773 unlock(t);
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700774
775 if (close_transport) {
776 lock(t);
777 close_transport_locked(t);
778 unlock(t);
779 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800780}
781
782/*
783 * INPUT PROCESSING
784 */
785
Craig Tillerf73fcd12015-06-16 16:25:26 -0700786static grpc_stream_state compute_state(gpr_uint8 write_closed,
787 gpr_uint8 read_closed) {
788 if (write_closed && read_closed) return GRPC_STREAM_CLOSED;
789 if (write_closed) return GRPC_STREAM_SEND_CLOSED;
790 if (read_closed) return GRPC_STREAM_RECV_CLOSED;
791 return GRPC_STREAM_OPEN;
792}
793
Craig Tiller759eb322015-06-16 22:41:18 -0700794static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) {
Craig Tiller8823b142015-06-18 11:41:24 -0700795 size_t new_stream_count;
Craig Tiller285b8822015-06-17 15:58:13 -0700796 grpc_chttp2_stream *s =
797 grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700798 if (!s) {
799 s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id);
800 }
Craig Tiller994c2622015-07-23 14:00:58 -0700801 grpc_chttp2_list_remove_writable_stream(&t->global, &s->global);
Craig Tiller759eb322015-06-16 22:41:18 -0700802 GPR_ASSERT(s);
803 s->global.in_stream_map = 0;
Craig Tiller66abdaa2015-06-17 08:00:39 -0700804 if (t->parsing.incoming_stream == &s->parsing) {
805 t->parsing.incoming_stream = NULL;
806 grpc_chttp2_parsing_become_skip_parser(&t->parsing);
807 }
Craig Tiller9188d7a2015-07-05 12:44:37 -0700808 if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
809 close_transport_locked(t);
810 }
Craig Tiller8823b142015-06-18 11:41:24 -0700811
Craig Tiller079a11b2015-06-30 10:07:15 -0700812 new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
813 grpc_chttp2_stream_map_size(&t->new_stream_map);
Craig Tiller8823b142015-06-18 11:41:24 -0700814 if (new_stream_count != t->global.concurrent_stream_count) {
815 t->global.concurrent_stream_count = new_stream_count;
816 maybe_start_some_streams(&t->global);
817 }
Craig Tiller759eb322015-06-16 22:41:18 -0700818}
819
Craig Tiller83fb0702015-06-16 21:13:07 -0700820static void unlock_check_read_write_state(grpc_chttp2_transport *t) {
821 grpc_chttp2_transport_global *transport_global = &t->global;
Craig Tillerf73fcd12015-06-16 16:25:26 -0700822 grpc_chttp2_stream_global *stream_global;
Craig Tiller31123db2015-06-16 17:06:31 -0700823 grpc_stream_state state;
Craig Tillerf73fcd12015-06-16 16:25:26 -0700824
Craig Tiller83fb0702015-06-16 21:13:07 -0700825 if (!t->parsing_active) {
Craig Tiller8823b142015-06-18 11:41:24 -0700826 /* if a stream is in the stream map, and gets cancelled, we need to ensure
827 we are not parsing before continuing the cancellation to keep things in
828 a sane state */
Craig Tiller83fb0702015-06-16 21:13:07 -0700829 while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
830 &stream_global)) {
831 GPR_ASSERT(stream_global->in_stream_map);
Craig Tillerab630732015-06-25 11:20:01 -0700832 GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_OPEN);
Craig Tiller83fb0702015-06-16 21:13:07 -0700833 GPR_ASSERT(stream_global->read_closed);
Craig Tiller759eb322015-06-16 22:41:18 -0700834 remove_stream(t, stream_global->id);
Craig Tiller83fb0702015-06-16 21:13:07 -0700835 grpc_chttp2_list_add_read_write_state_changed(transport_global,
836 stream_global);
837 }
838 }
839
Craig Tiller17be5dc2015-07-01 10:36:27 -0700840 if (!t->writing_active) {
Craig Tillerb3671532015-07-01 10:37:40 -0700841 while (grpc_chttp2_list_pop_cancelled_waiting_for_writing(transport_global,
842 &stream_global)) {
843 grpc_chttp2_list_add_read_write_state_changed(transport_global,
844 stream_global);
Craig Tiller17be5dc2015-07-01 10:36:27 -0700845 }
846 }
847
Craig Tiller285b8822015-06-17 15:58:13 -0700848 while (grpc_chttp2_list_pop_read_write_state_changed(transport_global,
849 &stream_global)) {
Craig Tillercec9eb92015-06-17 17:16:48 -0700850 if (stream_global->cancelled) {
Craig Tillerb3671532015-07-01 10:37:40 -0700851 if (t->writing_active &&
852 stream_global->write_state != GRPC_WRITE_STATE_SENT_CLOSE) {
853 grpc_chttp2_list_add_cancelled_waiting_for_writing(transport_global,
854 stream_global);
Craig Tiller17be5dc2015-07-01 10:36:27 -0700855 } else {
856 stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE;
Craig Tillerd1c00342015-07-30 15:29:49 -0700857 if (stream_global->outgoing_sopb != NULL) {
858 grpc_sopb_reset(stream_global->outgoing_sopb);
859 stream_global->outgoing_sopb = NULL;
860 grpc_chttp2_schedule_closure(transport_global,
861 stream_global->send_done_closure, 1);
862 }
Craig Tiller17be5dc2015-07-01 10:36:27 -0700863 stream_global->read_closed = 1;
864 if (!stream_global->published_cancelled) {
865 char buffer[GPR_LTOA_MIN_BUFSIZE];
866 gpr_ltoa(stream_global->cancelled_status, buffer);
867 grpc_chttp2_incoming_metadata_buffer_add(
868 &stream_global->incoming_metadata,
869 grpc_mdelem_from_strings(t->metadata_context, "grpc-status",
870 buffer));
871 grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into(
872 &stream_global->incoming_metadata, &stream_global->incoming_sopb);
873 stream_global->published_cancelled = 1;
874 }
Craig Tillercec9eb92015-06-17 17:16:48 -0700875 }
Craig Tillerf73fcd12015-06-16 16:25:26 -0700876 }
Craig Tillerab630732015-06-25 11:20:01 -0700877 if (stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE &&
Craig Tiller285b8822015-06-17 15:58:13 -0700878 stream_global->read_closed && stream_global->in_stream_map) {
Craig Tiller83fb0702015-06-16 21:13:07 -0700879 if (t->parsing_active) {
Craig Tiller285b8822015-06-17 15:58:13 -0700880 grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
881 stream_global);
Craig Tiller83fb0702015-06-16 21:13:07 -0700882 } else {
Craig Tiller759eb322015-06-16 22:41:18 -0700883 remove_stream(t, stream_global->id);
Craig Tiller83fb0702015-06-16 21:13:07 -0700884 }
885 }
Craig Tillercec9eb92015-06-17 17:16:48 -0700886 if (!stream_global->publish_sopb) {
Craig Tillercec9eb92015-06-17 17:16:48 -0700887 continue;
888 }
Craig Tiller0c23f292015-08-03 10:18:05 -0700889 if (stream_global->writing_now != 0) {
Craig Tiller994c2622015-07-23 14:00:58 -0700890 continue;
891 }
Craig Tillereaa660e2015-06-18 16:36:12 -0700892 /* FIXME(ctiller): we include in_stream_map in our computation of
893 whether the stream is write-closed. This is completely bogus,
894 but has the effect of delaying stream-closed until the stream
895 is indeed evicted from the stream map, making it safe to delete.
896 To fix this will require having an edge after stream-closed
897 indicating that the stream is closed AND safe to delete. */
Craig Tiller285b8822015-06-17 15:58:13 -0700898 state = compute_state(
Craig Tillerab630732015-06-25 11:20:01 -0700899 stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE &&
900 !stream_global->in_stream_map,
Craig Tillerb951df12015-06-18 15:46:58 -0700901 stream_global->read_closed);
Craig Tiller285b8822015-06-17 15:58:13 -0700902 if (stream_global->incoming_sopb.nops == 0 &&
903 state == stream_global->published_state) {
Craig Tiller31123db2015-06-16 17:06:31 -0700904 continue;
905 }
Craig Tiller285b8822015-06-17 15:58:13 -0700906 grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op(
907 &stream_global->incoming_metadata, &stream_global->incoming_sopb,
908 &stream_global->outstanding_metadata);
Craig Tillerf73fcd12015-06-16 16:25:26 -0700909 grpc_sopb_swap(stream_global->publish_sopb, &stream_global->incoming_sopb);
Craig Tiller31123db2015-06-16 17:06:31 -0700910 stream_global->published_state = *stream_global->publish_state = state;
Craig Tiller285b8822015-06-17 15:58:13 -0700911 grpc_chttp2_schedule_closure(transport_global,
912 stream_global->recv_done_closure, 1);
Craig Tiller31123db2015-06-16 17:06:31 -0700913 stream_global->recv_done_closure = NULL;
914 stream_global->publish_sopb = NULL;
915 stream_global->publish_state = NULL;
Craig Tillerf73fcd12015-06-16 16:25:26 -0700916 }
917}
918
Craig Tiller98505102015-06-16 11:33:15 -0700919static void cancel_from_api(grpc_chttp2_transport_global *transport_global,
920 grpc_chttp2_stream_global *stream_global,
921 grpc_status_code status) {
Craig Tillerb787c502015-06-15 16:14:52 -0700922 stream_global->cancelled = 1;
Craig Tillercec9eb92015-06-17 17:16:48 -0700923 stream_global->cancelled_status = status;
924 if (stream_global->id != 0) {
Craig Tiller079a11b2015-06-30 10:07:15 -0700925 gpr_slice_buffer_add(
926 &transport_global->qbuf,
927 grpc_chttp2_rst_stream_create(
928 stream_global->id, grpc_chttp2_grpc_status_to_http2_error(status)));
Craig Tillerb787c502015-06-15 16:14:52 -0700929 }
Craig Tillercec9eb92015-06-17 17:16:48 -0700930 grpc_chttp2_list_add_read_write_state_changed(transport_global,
931 stream_global);
Craig Tillerb787c502015-06-15 16:14:52 -0700932}
933
Craig Tiller45ce9272015-07-31 11:22:35 -0700934static void close_from_api(grpc_chttp2_transport_global *transport_global,
935 grpc_chttp2_stream_global *stream_global,
936 grpc_status_code status,
937 gpr_slice *optional_message) {
938 gpr_slice hdr;
939 gpr_slice status_hdr;
940 gpr_slice message_pfx;
941 gpr_uint8 *p;
942 gpr_uint32 len = 0;
943
944 GPR_ASSERT(status >= 0 && (int)status < 100);
945
946 stream_global->cancelled = 1;
947 stream_global->cancelled_status = status;
948 GPR_ASSERT(stream_global->id != 0);
949 GPR_ASSERT(!stream_global->written_anything);
950
951 /* Hand roll a header block.
952 This is unnecessarily ugly - at some point we should find a more elegant
953 solution.
954 It's complicated by the fact that our send machinery would be dead by the
955 time we got around to sending this, so instead we ignore HPACK compression
956 and just write the uncompressed bytes onto the wire. */
957 status_hdr = gpr_slice_malloc(15 + (status >= 10));
958 p = GPR_SLICE_START_PTR(status_hdr);
959 *p++ = 0x40; /* literal header */
960 *p++ = 11; /* len(grpc-status) */
961 *p++ = 'g';
962 *p++ = 'r';
963 *p++ = 'p';
964 *p++ = 'c';
965 *p++ = '-';
966 *p++ = 's';
967 *p++ = 't';
968 *p++ = 'a';
969 *p++ = 't';
970 *p++ = 'u';
971 *p++ = 's';
972 if (status < 10) {
973 *p++ = 1;
974 *p++ = '0' + status;
975 } else {
976 *p++ = 2;
977 *p++ = '0' + (status / 10);
978 *p++ = '0' + (status % 10);
979 }
980 GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr));
981 len += GPR_SLICE_LENGTH(status_hdr);
982
983 if (optional_message) {
984 GPR_ASSERT(GPR_SLICE_LENGTH(*optional_message) < 127);
985 message_pfx = gpr_slice_malloc(15);
986 p = GPR_SLICE_START_PTR(message_pfx);
987 *p++ = 0x40;
988 *p++ = 12; /* len(grpc-message) */
989 *p++ = 'g';
990 *p++ = 'r';
991 *p++ = 'p';
992 *p++ = 'c';
993 *p++ = '-';
994 *p++ = 'm';
995 *p++ = 'e';
996 *p++ = 's';
997 *p++ = 's';
998 *p++ = 'a';
999 *p++ = 'g';
1000 *p++ = 'e';
1001 *p++ = GPR_SLICE_LENGTH(*optional_message);
1002 GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx));
1003 len += GPR_SLICE_LENGTH(message_pfx);
1004 len += GPR_SLICE_LENGTH(*optional_message);
1005 }
1006
1007 hdr = gpr_slice_malloc(9);
1008 p = GPR_SLICE_START_PTR(hdr);
1009 *p++ = len >> 16;
1010 *p++ = len >> 8;
1011 *p++ = len;
1012 *p++ = GRPC_CHTTP2_FRAME_HEADER;
1013 *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
1014 *p++ = stream_global->id >> 24;
1015 *p++ = stream_global->id >> 16;
1016 *p++ = stream_global->id >> 8;
1017 *p++ = stream_global->id;
1018 GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr));
1019
1020 gpr_slice_buffer_add(&transport_global->qbuf, hdr);
1021 gpr_slice_buffer_add(&transport_global->qbuf, status_hdr);
1022 if (optional_message) {
1023 gpr_slice_buffer_add(&transport_global->qbuf, message_pfx);
1024 gpr_slice_buffer_add(&transport_global->qbuf,
1025 gpr_slice_ref(*optional_message));
1026 }
1027
1028 gpr_slice_buffer_add(
1029 &transport_global->qbuf,
1030 grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR));
1031
1032 grpc_chttp2_list_add_read_write_state_changed(transport_global,
1033 stream_global);
1034}
1035
Craig Tiller98505102015-06-16 11:33:15 -07001036static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
1037 void *user_data,
1038 grpc_chttp2_stream_global *stream_global) {
Craig Tiller5dc3b302015-06-15 16:06:50 -07001039 cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001040}
1041
Craig Tillerb084d902015-06-12 07:50:02 -07001042static void end_all_the_calls(grpc_chttp2_transport *t) {
Craig Tiller5dc3b302015-06-15 16:06:50 -07001043 grpc_chttp2_for_all_streams(&t->global, NULL, cancel_stream_cb);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001044}
1045
Craig Tillerb084d902015-06-12 07:50:02 -07001046static void drop_connection(grpc_chttp2_transport *t) {
Craig Tillerec3aa892015-05-29 17:22:17 -07001047 close_transport_locked(t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001048 end_all_the_calls(t);
1049}
1050
Craig Tillerab630732015-06-25 11:20:01 -07001051/** update window from a settings change */
1052static void update_global_window(void *args, gpr_uint32 id, void *stream) {
1053 grpc_chttp2_transport *t = args;
1054 grpc_chttp2_stream *s = stream;
1055 grpc_chttp2_transport_global *transport_global = &t->global;
1056 grpc_chttp2_stream_global *stream_global = &s->global;
Craig Tiller6f7411f2015-07-06 15:37:28 -07001057 int was_zero;
1058 int is_zero;
Craig Tillerab630732015-06-25 11:20:01 -07001059
1060 GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("settings", transport_global, stream_global,
1061 outgoing_window,
1062 t->parsing.initial_window_update);
Craig Tiller6f7411f2015-07-06 15:37:28 -07001063 was_zero = stream_global->outgoing_window <= 0;
Craig Tillerab630732015-06-25 11:20:01 -07001064 stream_global->outgoing_window += t->parsing.initial_window_update;
Craig Tiller6f7411f2015-07-06 15:37:28 -07001065 is_zero = stream_global->outgoing_window <= 0;
1066
1067 if (was_zero && !is_zero) {
1068 grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
1069 }
Craig Tillerab630732015-06-25 11:20:01 -07001070}
1071
Craig Tiller69f56162015-06-30 14:54:31 -07001072static void read_error_locked(grpc_chttp2_transport *t) {
1073 t->endpoint_reading = 0;
1074 if (!t->writing_active && t->ep) {
1075 grpc_endpoint_destroy(t->ep);
1076 t->ep = NULL;
1077 /* safe as we still have a ref for read */
1078 UNREF_TRANSPORT(t, "disconnect");
1079 }
1080}
1081
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001082/* tcp read callback */
Craig Tillerb0298592015-08-27 07:38:01 -07001083static int recv_data_loop(grpc_chttp2_transport *t, int *success) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001084 size_t i;
Craig Tillerb0298592015-08-27 07:38:01 -07001085 int keep_reading = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001086
Craig Tillerb0298592015-08-27 07:38:01 -07001087 lock(t);
1088 i = 0;
1089 GPR_ASSERT(!t->parsing_active);
1090 if (!t->closed) {
1091 t->parsing_active = 1;
1092 /* merge stream lists */
1093 grpc_chttp2_stream_map_move_into(&t->new_stream_map,
1094 &t->parsing_stream_map);
1095 grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
1096 gpr_mu_unlock(&t->mu);
1097 for (; i < t->read_buffer.count &&
1098 grpc_chttp2_perform_read(&t->parsing, t->read_buffer.slices[i]);
1099 i++)
1100 ;
1101 gpr_mu_lock(&t->mu);
1102 if (i != t->read_buffer.count) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001103 drop_connection(t);
Craig Tillerb0298592015-08-27 07:38:01 -07001104 }
1105 /* merge stream lists */
1106 grpc_chttp2_stream_map_move_into(&t->new_stream_map,
1107 &t->parsing_stream_map);
1108 t->global.concurrent_stream_count =
1109 grpc_chttp2_stream_map_size(&t->parsing_stream_map);
1110 if (t->parsing.initial_window_update != 0) {
1111 grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
1112 update_global_window, t);
1113 t->parsing.initial_window_update = 0;
1114 }
1115 /* handle higher level things */
1116 grpc_chttp2_publish_reads(&t->global, &t->parsing);
1117 t->parsing_active = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001118 }
Craig Tillerb0298592015-08-27 07:38:01 -07001119 if (!*success || i != t->read_buffer.count) {
1120 drop_connection(t);
1121 read_error_locked(t);
Craig Tiller5100ea02015-09-01 12:23:28 -07001122 } else if (!t->closed) {
Craig Tillerb0298592015-08-27 07:38:01 -07001123 keep_reading = 1;
Craig Tiller9f80fcf2015-08-28 08:22:48 -07001124 prevent_endpoint_shutdown(t);
Craig Tillerb0298592015-08-27 07:38:01 -07001125 }
1126 gpr_slice_buffer_reset_and_unref(&t->read_buffer);
1127 unlock(t);
1128
1129 if (keep_reading) {
Craig Tiller9f80fcf2015-08-28 08:22:48 -07001130 int ret = -1;
Craig Tillerb0298592015-08-27 07:38:01 -07001131 switch (grpc_endpoint_read(t->ep, &t->read_buffer, &t->recv_data)) {
1132 case GRPC_ENDPOINT_DONE:
1133 *success = 1;
Craig Tiller9f80fcf2015-08-28 08:22:48 -07001134 ret = 1;
1135 break;
Craig Tillerb0298592015-08-27 07:38:01 -07001136 case GRPC_ENDPOINT_ERROR:
1137 *success = 0;
Craig Tiller9f80fcf2015-08-28 08:22:48 -07001138 ret = 1;
1139 break;
Craig Tillerb0298592015-08-27 07:38:01 -07001140 case GRPC_ENDPOINT_PENDING:
Craig Tiller9f80fcf2015-08-28 08:22:48 -07001141 ret = 0;
1142 break;
Craig Tillerb0298592015-08-27 07:38:01 -07001143 }
Craig Tiller9f80fcf2015-08-28 08:22:48 -07001144 allow_endpoint_shutdown(t);
1145 return ret;
Craig Tillerb0298592015-08-27 07:38:01 -07001146 } else {
Craig Tillerec9acab2015-08-21 13:06:00 -07001147 UNREF_TRANSPORT(t, "recv_data");
Craig Tillerb0298592015-08-27 07:38:01 -07001148 return 0;
Craig Tillerec9acab2015-08-21 13:06:00 -07001149 }
Craig Tillerb0298592015-08-27 07:38:01 -07001150
1151 gpr_log(GPR_ERROR, "should never reach here");
1152 abort();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001153}
1154
Craig Tillerb0298592015-08-27 07:38:01 -07001155static void recv_data(void *tp, int success) {
1156 grpc_chttp2_transport *t = tp;
1157
1158 while (recv_data_loop(t, &success))
1159 ;
Craig Tiller8b2f1d72015-06-18 13:38:38 -07001160}
1161
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001162/*
1163 * CALLBACK LOOP
1164 */
1165
Craig Tiller079a11b2015-06-30 10:07:15 -07001166static void schedule_closure_for_connectivity(void *a,
1167 grpc_iomgr_closure *closure) {
Craig Tillerff3ae682015-06-29 17:44:04 -07001168 grpc_chttp2_schedule_closure(a, closure, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001169}
1170
Craig Tiller079a11b2015-06-30 10:07:15 -07001171static void connectivity_state_set(
1172 grpc_chttp2_transport_global *transport_global,
Craig Tiller03dc6552015-07-17 23:12:34 -07001173 grpc_connectivity_state state, const char *reason) {
Craig Tiller079a11b2015-06-30 10:07:15 -07001174 GRPC_CHTTP2_IF_TRACING(
1175 gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
Craig Tillerff3ae682015-06-29 17:44:04 -07001176 grpc_connectivity_state_set_with_scheduler(
Craig Tiller079a11b2015-06-30 10:07:15 -07001177 &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
Craig Tiller03dc6552015-07-17 23:12:34 -07001178 state, schedule_closure_for_connectivity, transport_global, reason);
Craig Tiller4aa71a12015-06-15 13:00:55 -07001179}
1180
Craig Tiller98505102015-06-16 11:33:15 -07001181void grpc_chttp2_schedule_closure(
1182 grpc_chttp2_transport_global *transport_global, grpc_iomgr_closure *closure,
1183 int success) {
Craig Tiller1e6facb2015-06-11 22:47:11 -07001184 closure->success = success;
Craig Tillerff3ae682015-06-29 17:44:04 -07001185 if (transport_global->pending_closures_tail == NULL) {
1186 transport_global->pending_closures_head =
1187 transport_global->pending_closures_tail = closure;
1188 } else {
1189 transport_global->pending_closures_tail->next = closure;
1190 transport_global->pending_closures_tail = closure;
1191 }
1192 closure->next = NULL;
Craig Tiller748fe3f2015-03-02 07:48:50 -08001193}
1194
Craig Tillerc079c112015-04-22 15:23:39 -07001195/*
1196 * POLLSET STUFF
1197 */
1198
Craig Tiller4aa71a12015-06-15 13:00:55 -07001199static void add_to_pollset_locked(grpc_chttp2_transport *t,
1200 grpc_pollset *pollset) {
ctillerd79b4862014-12-17 16:36:59 -08001201 if (t->ep) {
1202 grpc_endpoint_add_to_pollset(t->ep, pollset);
1203 }
Craig Tillerc079c112015-04-22 15:23:39 -07001204}
1205
Craig Tiller1ada6ad2015-07-16 16:19:14 -07001206static void add_to_pollset_set_locked(grpc_chttp2_transport *t,
Craig Tillerd6c98df2015-08-18 09:33:44 -07001207 grpc_pollset_set *pollset_set) {
Craig Tiller1ada6ad2015-07-16 16:19:14 -07001208 if (t->ep) {
1209 grpc_endpoint_add_to_pollset_set(t->ep, pollset_set);
1210 }
1211}
1212
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001213/*
Craig Tiller285b8822015-06-17 15:58:13 -07001214 * TRACING
1215 */
1216
1217void grpc_chttp2_flowctl_trace(const char *file, int line, const char *reason,
1218 const char *context, const char *var,
1219 int is_client, gpr_uint32 stream_id,
1220 gpr_int64 current_value, gpr_int64 delta) {
1221 char *identifier;
1222 char *context_scope;
1223 char *context_thread;
1224 char *underscore_pos = strchr(context, '_');
1225 GPR_ASSERT(underscore_pos);
1226 context_thread = gpr_strdup(underscore_pos + 1);
1227 context_scope = gpr_strdup(context);
1228 context_scope[underscore_pos - context] = 0;
1229 if (stream_id) {
1230 gpr_asprintf(&identifier, "%s[%d]", context_scope, stream_id);
1231 } else {
1232 identifier = gpr_strdup(context_scope);
1233 }
Craig Tiller8b2f1d72015-06-18 13:38:38 -07001234 gpr_log(GPR_INFO,
Craig Tiller5c517b12015-07-15 13:28:10 -07001235 "FLOWCTL: %s %-10s %8s %-27s %8lld %c %8lld = %8lld %-10s [%s:%d]",
Craig Tiller285b8822015-06-17 15:58:13 -07001236 is_client ? "client" : "server", identifier, context_thread, var,
1237 current_value, delta < 0 ? '-' : '+', delta < 0 ? -delta : delta,
1238 current_value + delta, reason, file, line);
1239 gpr_free(identifier);
1240 gpr_free(context_thread);
1241 gpr_free(context_scope);
1242}
1243
1244/*
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001245 * INTEGRATION GLUE
1246 */
1247
Craig Tiller1b22b9d2015-07-20 13:42:22 -07001248static char *chttp2_get_peer(grpc_transport *t) {
1249 return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string);
1250}
1251
1252static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
1253 init_stream,
1254 perform_stream_op,
1255 perform_transport_op,
1256 destroy_stream,
1257 destroy_transport,
1258 chttp2_get_peer};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001259
Craig Tiller1064f8b2015-06-25 13:52:57 -07001260grpc_transport *grpc_create_chttp2_transport(
Craig Tiller825b21c2015-07-06 08:35:02 -07001261 const grpc_channel_args *channel_args, grpc_endpoint *ep, grpc_mdctx *mdctx,
1262 int is_client) {
Craig Tillerb084d902015-06-12 07:50:02 -07001263 grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport));
Craig Tiller825b21c2015-07-06 08:35:02 -07001264 init_transport(t, channel_args, ep, mdctx, is_client);
Craig Tiller1064f8b2015-06-25 13:52:57 -07001265 return &t->base;
Craig Tiller190d3602015-02-18 09:23:38 -08001266}
Craig Tiller825b21c2015-07-06 08:35:02 -07001267
1268void grpc_chttp2_transport_start_reading(grpc_transport *transport,
1269 gpr_slice *slices, size_t nslices) {
1270 grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
1271 REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */
Craig Tillerb0298592015-08-27 07:38:01 -07001272 gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
1273 recv_data(t, 1);
Craig Tiller06059952015-02-18 08:34:56 -08001274}