blob: 5f49b2ddd604b5e618e8357fb92cfae7d1d5f537 [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)))
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080066
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)))
Craig Tillerd50e5652015-02-24 16:46:22 -080070
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)))
Craig Tiller6a8c0382015-04-28 10:01:22 -070074
Craig Tiller5dc3b302015-06-15 16:06:50 -070075#define STREAM_FROM_GLOBAL(sg) \
Craig Tiller98505102015-06-16 11:33:15 -070076 ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global)))
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080077
78static 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 Tiller8b2f1d72015-06-18 13:38:38 -070087static void reading_action(void *t, int iomgr_success_ignored);
Craig Tiller99f80552015-06-11 16:26:03 -070088
Craig Tiller4aa71a12015-06-15 13:00:55 -070089/** Set a transport level setting, and push it to our peer */
90static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080091 gpr_uint32 value);
92
Craig Tiller4aa71a12015-06-15 13:00:55 -070093/** Endpoint callback to process incoming data */
Nicolas Noble5ea99bb2015-02-04 14:13:09 -080094static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
95 grpc_endpoint_cb_status error);
96
Craig Tiller4aa71a12015-06-15 13:00:55 -070097/** Start disconnection chain */
98static void drop_connection(grpc_chttp2_transport *t);
Craig Tillerc079c112015-04-22 15:23:39 -070099
Craig Tiller5dc3b302015-06-15 16:06:50 -0700100/** Perform a transport_op */
Craig Tiller1064f8b2015-06-25 13:52:57 -0700101static void perform_stream_op_locked(
102 grpc_chttp2_transport_global *transport_global,
103 grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700104
105/** Cancel a stream: coming from the transport API */
Craig Tiller98505102015-06-16 11:33:15 -0700106static void cancel_from_api(grpc_chttp2_transport_global *transport_global,
107 grpc_chttp2_stream_global *stream_global,
108 grpc_status_code status);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700109
110/** Add endpoint from this transport to pollset */
111static void add_to_pollset_locked(grpc_chttp2_transport *t,
112 grpc_pollset *pollset);
113
Craig Tiller564872d2015-06-18 11:21:22 -0700114/** Start new streams that have been created if we can */
115static void maybe_start_some_streams(
116 grpc_chttp2_transport_global *transport_global);
Craig Tiller6a8c0382015-04-28 10:01:22 -0700117
Craig Tiller079a11b2015-06-30 10:07:15 -0700118static void connectivity_state_set(
119 grpc_chttp2_transport_global *transport_global,
120 grpc_connectivity_state state);
Craig Tillerff3ae682015-06-29 17:44:04 -0700121
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800122/*
123 * CONSTRUCTION/DESTRUCTION/REFCOUNTING
124 */
125
Craig Tillerb084d902015-06-12 07:50:02 -0700126static void destruct_transport(grpc_chttp2_transport *t) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800127 size_t i;
128
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800129 gpr_mu_lock(&t->mu);
130
131 GPR_ASSERT(t->ep == NULL);
132
Craig Tiller99f80552015-06-11 16:26:03 -0700133 gpr_slice_buffer_destroy(&t->global.qbuf);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800134
Craig Tiller99f80552015-06-11 16:26:03 -0700135 gpr_slice_buffer_destroy(&t->writing.outbuf);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700136 grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor);
137
Craig Tiller99f80552015-06-11 16:26:03 -0700138 gpr_slice_buffer_destroy(&t->parsing.qbuf);
Craig Tiller42cdf942015-06-12 07:35:44 -0700139 grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
140 grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800141
Craig Tiller1a65a232015-07-06 10:22:32 -0700142 GRPC_MDSTR_UNREF(t->parsing.str_grpc_timeout);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800143
144 for (i = 0; i < STREAM_LIST_COUNT; i++) {
145 GPR_ASSERT(t->lists[i].head == NULL);
146 GPR_ASSERT(t->lists[i].tail == NULL);
147 }
148
Craig Tiller606d8742015-06-15 06:58:50 -0700149 GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0);
150 GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800151
Craig Tiller606d8742015-06-15 06:58:50 -0700152 grpc_chttp2_stream_map_destroy(&t->parsing_stream_map);
153 grpc_chttp2_stream_map_destroy(&t->new_stream_map);
Craig Tiller08a1cf82015-06-29 09:37:52 -0700154 grpc_connectivity_state_destroy(&t->channel_callback.state_tracker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800155
156 gpr_mu_unlock(&t->mu);
157 gpr_mu_destroy(&t->mu);
158
159 /* callback remaining pings: they're not allowed to call into the transpot,
160 and maybe they hold resources that need to be freed */
Craig Tiller606d8742015-06-15 06:58:50 -0700161 while (t->global.pings.next != &t->global.pings) {
162 grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
163 grpc_iomgr_add_delayed_callback(ping->on_recv, 0);
164 ping->next->prev = ping->prev;
165 ping->prev->next = ping->next;
166 gpr_free(ping);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800167 }
Craig Tiller8ed35ea2015-01-30 11:27:43 -0800168
Craig Tiller9be83ee2015-02-18 14:16:15 -0800169 grpc_mdctx_unref(t->metadata_context);
170
Craig Tiller1b22b9d2015-07-20 13:42:22 -0700171 gpr_free(t->peer_string);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800172 gpr_free(t);
173}
174
Craig Tiller759eb322015-06-16 22:41:18 -0700175#ifdef REFCOUNTING_DEBUG
176#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
177#define UNREF_TRANSPORT(t, r) unref_transport(t, r, __FILE__, __LINE__)
Craig Tiller285b8822015-06-17 15:58:13 -0700178static void unref_transport(grpc_chttp2_transport *t, const char *reason,
179 const char *file, int line) {
180 gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count,
181 t->refs.count - 1, reason, file, line);
Craig Tiller9be83ee2015-02-18 14:16:15 -0800182 if (!gpr_unref(&t->refs)) return;
183 destruct_transport(t);
184}
185
Craig Tiller285b8822015-06-17 15:58:13 -0700186static void ref_transport(grpc_chttp2_transport *t, const char *reason,
187 const char *file, int line) {
188 gpr_log(GPR_DEBUG, "chttp2: ref:%p %d->%d %s [%s:%d]", t, t->refs.count,
189 t->refs.count + 1, reason, file, line);
190 gpr_ref(&t->refs);
Craig Tiller759eb322015-06-16 22:41:18 -0700191}
192#else
193#define REF_TRANSPORT(t, r) ref_transport(t)
194#define UNREF_TRANSPORT(t, r) unref_transport(t)
Craig Tillerb084d902015-06-12 07:50:02 -0700195static void unref_transport(grpc_chttp2_transport *t) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800196 if (!gpr_unref(&t->refs)) return;
197 destruct_transport(t);
198}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800199
Craig Tillerb084d902015-06-12 07:50:02 -0700200static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
Craig Tiller759eb322015-06-16 22:41:18 -0700201#endif
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800202
Craig Tiller4aa71a12015-06-15 13:00:55 -0700203static void init_transport(grpc_chttp2_transport *t,
Craig Tiller4aa71a12015-06-15 13:00:55 -0700204 const grpc_channel_args *channel_args,
Craig Tiller825b21c2015-07-06 08:35:02 -0700205 grpc_endpoint *ep, grpc_mdctx *mdctx,
206 int is_client) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800207 size_t i;
208 int j;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800209
Craig Tiller4aa71a12015-06-15 13:00:55 -0700210 GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
211 GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800212
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700213 memset(t, 0, sizeof(*t));
214
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800215 t->base.vtable = &vtable;
216 t->ep = ep;
217 /* one ref is for destroy, the other for when ep becomes NULL */
218 gpr_ref_init(&t->refs, 2);
219 gpr_mu_init(&t->mu);
Craig Tiller9be83ee2015-02-18 14:16:15 -0800220 grpc_mdctx_ref(mdctx);
Craig Tiller1b22b9d2015-07-20 13:42:22 -0700221 t->peer_string = grpc_endpoint_get_peer(ep);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800222 t->metadata_context = mdctx;
Craig Tiller606d8742015-06-15 06:58:50 -0700223 t->endpoint_reading = 1;
Craig Tiller606d8742015-06-15 06:58:50 -0700224 t->global.next_stream_id = is_client ? 1 : 2;
225 t->global.is_client = is_client;
Craig Tillerd20efd22015-06-12 16:17:09 -0700226 t->global.outgoing_window = DEFAULT_WINDOW;
227 t->global.incoming_window = DEFAULT_WINDOW;
228 t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
Craig Tiller606d8742015-06-15 06:58:50 -0700229 t->global.ping_counter = 1;
Craig Tiller83fb0702015-06-16 21:13:07 -0700230 t->global.pings.next = t->global.pings.prev = &t->global.pings;
Craig Tiller606d8742015-06-15 06:58:50 -0700231 t->parsing.is_client = is_client;
232 t->parsing.str_grpc_timeout =
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800233 grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
Craig Tillerab630732015-06-25 11:20:01 -0700234 t->parsing.deframe_state =
235 is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
Craig Tiller285b8822015-06-17 15:58:13 -0700236 t->writing.is_client = is_client;
Craig Tiller08a1cf82015-06-29 09:37:52 -0700237 grpc_connectivity_state_init(&t->channel_callback.state_tracker,
238 GRPC_CHANNEL_READY);
Craig Tiller42cdf942015-06-12 07:35:44 -0700239
Craig Tiller99f80552015-06-11 16:26:03 -0700240 gpr_slice_buffer_init(&t->global.qbuf);
Craig Tiller42cdf942015-06-12 07:35:44 -0700241
Craig Tiller99f80552015-06-11 16:26:03 -0700242 gpr_slice_buffer_init(&t->writing.outbuf);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700243 grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx);
Craig Tillerd20efd22015-06-12 16:17:09 -0700244 grpc_iomgr_closure_init(&t->writing_action, writing_action, t);
Craig Tiller8b2f1d72015-06-18 13:38:38 -0700245 grpc_iomgr_closure_init(&t->reading_action, reading_action, t);
Craig Tiller42cdf942015-06-12 07:35:44 -0700246
Craig Tiller99f80552015-06-11 16:26:03 -0700247 gpr_slice_buffer_init(&t->parsing.qbuf);
Craig Tiller42cdf942015-06-12 07:35:44 -0700248 grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
249 grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context);
250
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800251 if (is_client) {
Craig Tiller4aa71a12015-06-15 13:00:55 -0700252 gpr_slice_buffer_add(
253 &t->global.qbuf,
254 gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800255 }
256 /* 8 is a random stab in the dark as to a good initial size: it's small enough
257 that it shouldn't waste memory for infrequently used connections, yet
258 large enough that the exponential growth should happen nicely when it's
259 needed.
260 TODO(ctiller): tune this */
Craig Tiller606d8742015-06-15 06:58:50 -0700261 grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8);
262 grpc_chttp2_stream_map_init(&t->new_stream_map, 8);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800263
264 /* copy in initial settings to all setting sets */
Craig Tillercdf52bc2015-06-16 13:00:27 -0700265 for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) {
266 t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value;
Craig Tillerab630732015-06-25 11:20:01 -0700267 for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) {
Craig Tillercdf52bc2015-06-16 13:00:27 -0700268 t->global.settings[j][i] =
269 grpc_chttp2_settings_parameters[i].default_value;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800270 }
271 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700272 t->global.dirtied_local_settings = 1;
ctiller493fbcc2014-12-07 15:09:10 -0800273 /* Hack: it's common for implementations to assume 65536 bytes initial send
274 window -- this should by rights be 0 */
Craig Tillerd20efd22015-06-12 16:17:09 -0700275 t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
276 t->global.sent_local_settings = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800277
278 /* configure http2 the way we like it */
Craig Tiller606d8742015-06-15 06:58:50 -0700279 if (is_client) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800280 push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
281 push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
282 }
ctiller493fbcc2014-12-07 15:09:10 -0800283 push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800284
285 if (channel_args) {
286 for (i = 0; i < channel_args->num_args; i++) {
287 if (0 ==
288 strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) {
Craig Tiller606d8742015-06-15 06:58:50 -0700289 if (is_client) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800290 gpr_log(GPR_ERROR, "%s: is ignored on the client",
291 GRPC_ARG_MAX_CONCURRENT_STREAMS);
292 } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
293 gpr_log(GPR_ERROR, "%s: must be an integer",
294 GRPC_ARG_MAX_CONCURRENT_STREAMS);
295 } else {
296 push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
297 channel_args->args[i].value.integer);
298 }
Craig Tiller88025582015-05-04 09:41:10 -0700299 } else if (0 == strcmp(channel_args->args[i].key,
300 GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) {
301 if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
302 gpr_log(GPR_ERROR, "%s: must be an integer",
303 GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER);
Craig Tiller606d8742015-06-15 06:58:50 -0700304 } else if ((t->global.next_stream_id & 1) !=
Craig Tiller88025582015-05-04 09:41:10 -0700305 (channel_args->args[i].value.integer & 1)) {
306 gpr_log(GPR_ERROR, "%s: low bit must be %d on %s",
Craig Tiller4aa71a12015-06-15 13:00:55 -0700307 GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER,
308 t->global.next_stream_id & 1,
Craig Tiller606d8742015-06-15 06:58:50 -0700309 is_client ? "client" : "server");
Craig Tiller88025582015-05-04 09:41:10 -0700310 } else {
Craig Tiller606d8742015-06-15 06:58:50 -0700311 t->global.next_stream_id = channel_args->args[i].value.integer;
Craig Tiller88025582015-05-04 09:41:10 -0700312 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800313 }
314 }
315 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800316}
317
318static void destroy_transport(grpc_transport *gt) {
Craig Tillerb084d902015-06-12 07:50:02 -0700319 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800320
Craig Tiller748fe3f2015-03-02 07:48:50 -0800321 lock(t);
Craig Tiller1fe7b9d2015-02-17 11:57:02 -0800322 t->destroying = 1;
Craig Tiller748fe3f2015-03-02 07:48:50 -0800323 drop_connection(t);
324 unlock(t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800325
Craig Tiller759eb322015-06-16 22:41:18 -0700326 UNREF_TRANSPORT(t, "destroy");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800327}
328
Craig Tillerb084d902015-06-12 07:50:02 -0700329static void close_transport_locked(grpc_chttp2_transport *t) {
Craig Tillerec3aa892015-05-29 17:22:17 -0700330 if (!t->closed) {
331 t->closed = 1;
Craig Tiller079a11b2015-06-30 10:07:15 -0700332 connectivity_state_set(&t->global, GRPC_CHANNEL_FATAL_FAILURE);
Craig Tillerec3aa892015-05-29 17:22:17 -0700333 if (t->ep) {
334 grpc_endpoint_shutdown(t->ep);
335 }
336 }
337}
338
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800339static int init_stream(grpc_transport *gt, grpc_stream *gs,
Craig Tiller079a11b2015-06-30 10:07:15 -0700340 const void *server_data,
341 grpc_transport_stream_op *initial_op) {
Craig Tillerb084d902015-06-12 07:50:02 -0700342 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
343 grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800344
Craig Tillerc079c112015-04-22 15:23:39 -0700345 memset(s, 0, sizeof(*s));
346
Craig Tiller5dc3b302015-06-15 16:06:50 -0700347 grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.incoming_metadata);
348 grpc_chttp2_incoming_metadata_buffer_init(&s->global.incoming_metadata);
Craig Tiller606d8742015-06-15 06:58:50 -0700349 grpc_sopb_init(&s->writing.sopb);
Craig Tillerf73fcd12015-06-16 16:25:26 -0700350 grpc_sopb_init(&s->global.incoming_sopb);
Craig Tiller606d8742015-06-15 06:58:50 -0700351 grpc_chttp2_data_parser_init(&s->parsing.data_parser);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800352
Craig Tiller759eb322015-06-16 22:41:18 -0700353 REF_TRANSPORT(t, "stream");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800354
Craig Tillere0617622015-06-11 09:37:17 -0700355 lock(t);
Craig Tiller6459db42015-06-15 17:11:45 -0700356 grpc_chttp2_register_stream(t, s);
Craig Tiller606d8742015-06-15 06:58:50 -0700357 if (server_data) {
358 GPR_ASSERT(t->parsing_active);
Craig Tillerd20efd22015-06-12 16:17:09 -0700359 s->global.id = (gpr_uint32)(gpr_uintptr)server_data;
360 s->global.outgoing_window =
Craig Tillerab630732015-06-25 11:20:01 -0700361 t->global.settings[GRPC_PEER_SETTINGS]
362 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tiller27166a62015-07-05 21:08:33 -0700363 s->global.max_recv_bytes =
364 s->parsing.incoming_window =
365 s->global.incoming_window =
Craig Tillerab630732015-06-25 11:20:01 -0700366 t->global.settings[GRPC_SENT_SETTINGS]
367 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tiller606d8742015-06-15 06:58:50 -0700368 *t->accepting_stream = s;
Craig Tiller285b8822015-06-17 15:58:13 -0700369 grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s);
Craig Tiller31123db2015-06-16 17:06:31 -0700370 s->global.in_stream_map = 1;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800371 }
372
Craig Tiller1064f8b2015-06-25 13:52:57 -0700373 if (initial_op) perform_stream_op_locked(&t->global, &s->global, initial_op);
Craig Tillere0617622015-06-11 09:37:17 -0700374 unlock(t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800375
376 return 0;
377}
378
379static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
Craig Tillerb084d902015-06-12 07:50:02 -0700380 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
381 grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700382 int i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800383
384 gpr_mu_lock(&t->mu);
385
Craig Tiller4aa71a12015-06-15 13:00:55 -0700386 GPR_ASSERT(s->global.published_state == GRPC_STREAM_CLOSED ||
387 s->global.id == 0);
Craig Tiller83fb0702015-06-16 21:13:07 -0700388 GPR_ASSERT(!s->global.in_stream_map);
Craig Tiller9188d7a2015-07-05 12:44:37 -0700389 if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
390 close_transport_locked(t);
391 }
Craig Tiller759eb322015-06-16 22:41:18 -0700392 if (!t->parsing_active && s->global.id) {
Craig Tiller285b8822015-06-17 15:58:13 -0700393 GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
394 s->global.id) == NULL);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800395 }
396
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700397 grpc_chttp2_list_remove_incoming_window_updated(&t->global, &s->global);
Craig Tillere3086f82015-07-23 16:25:00 -0700398 grpc_chttp2_list_remove_writable_stream(&t->global, &s->global);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800399
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800400 gpr_mu_unlock(&t->mu);
401
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700402 for (i = 0; i < STREAM_LIST_COUNT; i++) {
Craig Tiller05cc0c42015-07-23 16:01:27 -0700403 if (s->included[i]) {
404 gpr_log(GPR_ERROR, "%s stream %d still included in list %d",
405 t->global.is_client ? "client" : "server", s->global.id, i);
406 abort();
407 }
Craig Tiller9c71b6f2015-04-24 16:02:00 -0700408 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800409
Craig Tillerd20efd22015-06-12 16:17:09 -0700410 GPR_ASSERT(s->global.outgoing_sopb == NULL);
Craig Tiller6905b7c2015-06-16 15:33:33 -0700411 GPR_ASSERT(s->global.publish_sopb == NULL);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700412 grpc_sopb_destroy(&s->writing.sopb);
Craig Tiller0b442a82015-06-30 17:04:32 -0700413 grpc_sopb_destroy(&s->global.incoming_sopb);
Craig Tiller606d8742015-06-15 06:58:50 -0700414 grpc_chttp2_data_parser_destroy(&s->parsing.data_parser);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700415 grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.incoming_metadata);
416 grpc_chttp2_incoming_metadata_buffer_destroy(&s->global.incoming_metadata);
Craig Tiller47073d52015-06-30 10:19:22 -0700417 grpc_chttp2_incoming_metadata_live_op_buffer_end(
418 &s->global.outstanding_metadata);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800419
Craig Tiller759eb322015-06-16 22:41:18 -0700420 UNREF_TRANSPORT(t, "stream");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800421}
422
Craig Tillercfb5db92015-06-15 17:14:41 -0700423grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
424 grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id) {
425 grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
Craig Tiller98505102015-06-16 11:33:15 -0700426 grpc_chttp2_stream *s =
427 grpc_chttp2_stream_map_find(&t->parsing_stream_map, id);
Craig Tillercf1e3192015-06-16 14:28:22 -0700428 return s ? &s->parsing : NULL;
ctiller00297df2015-01-12 11:23:09 -0800429}
430
Craig Tiller1937b062015-06-16 08:47:38 -0700431grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
432 grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id) {
433 grpc_chttp2_stream *accepting;
434 grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
435 GPR_ASSERT(t->accepting_stream == NULL);
436 t->accepting_stream = &accepting;
Craig Tiller1064f8b2015-06-25 13:52:57 -0700437 t->channel_callback.accept_stream(t->channel_callback.accept_stream_user_data,
438 &t->base, (void *)(gpr_uintptr)id);
Craig Tiller1937b062015-06-16 08:47:38 -0700439 t->accepting_stream = NULL;
440 return &accepting->parsing;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800441}
442
443/*
444 * LOCK MANAGEMENT
445 */
446
Craig Tiller4aa71a12015-06-15 13:00:55 -0700447/* We take a grpc_chttp2_transport-global lock in response to calls coming in
448 from above,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800449 and in response to data being received from below. New data to be written
450 is always queued, as are callbacks to process data. During unlock() we
451 check our todo lists and initiate callbacks and flush writes. */
452
Craig Tillerb084d902015-06-12 07:50:02 -0700453static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800454
Craig Tillerb084d902015-06-12 07:50:02 -0700455static void unlock(grpc_chttp2_transport *t) {
Craig Tiller1e6facb2015-06-11 22:47:11 -0700456 grpc_iomgr_closure *run_closures;
Craig Tiller06059952015-02-18 08:34:56 -0800457
Craig Tiller8823b142015-06-18 11:41:24 -0700458 unlock_check_read_write_state(t);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700459 if (!t->writing_active && !t->closed &&
Craig Tiller4aa71a12015-06-15 13:00:55 -0700460 grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
Craig Tillerd20efd22015-06-12 16:17:09 -0700461 t->writing_active = 1;
Craig Tiller759eb322015-06-16 22:41:18 -0700462 REF_TRANSPORT(t, "writing");
Craig Tiller1937b062015-06-16 08:47:38 -0700463 grpc_chttp2_schedule_closure(&t->global, &t->writing_action, 1);
Craig Tillercb818ba2015-01-29 17:08:01 -0800464 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800465
Craig Tillerff3ae682015-06-29 17:44:04 -0700466 run_closures = t->global.pending_closures_head;
467 t->global.pending_closures_head = NULL;
468 t->global.pending_closures_tail = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800469
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800470 gpr_mu_unlock(&t->mu);
471
Craig Tiller1e6facb2015-06-11 22:47:11 -0700472 while (run_closures) {
473 grpc_iomgr_closure *next = run_closures->next;
474 run_closures->cb(run_closures->cb_arg, run_closures->success);
475 run_closures = next;
nnoble0c475f02014-12-05 15:37:39 -0800476 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800477}
478
479/*
480 * OUTPUT PROCESSING
481 */
482
Craig Tillerb084d902015-06-12 07:50:02 -0700483static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800484 gpr_uint32 value) {
485 const grpc_chttp2_setting_parameters *sp =
486 &grpc_chttp2_settings_parameters[id];
487 gpr_uint32 use_value = GPR_CLAMP(value, sp->min_value, sp->max_value);
488 if (use_value != value) {
489 gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name,
490 value, use_value);
491 }
Craig Tillerab630732015-06-25 11:20:01 -0700492 if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) {
493 t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value;
Craig Tillerd20efd22015-06-12 16:17:09 -0700494 t->global.dirtied_local_settings = 1;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800495 }
496}
497
Craig Tiller4aa71a12015-06-15 13:00:55 -0700498void grpc_chttp2_terminate_writing(
499 grpc_chttp2_transport_writing *transport_writing, int success) {
Craig Tillerd20efd22015-06-12 16:17:09 -0700500 grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
ctiller00297df2015-01-12 11:23:09 -0800501
502 lock(t);
Craig Tillerd20efd22015-06-12 16:17:09 -0700503
ctiller00297df2015-01-12 11:23:09 -0800504 if (!success) {
505 drop_connection(t);
506 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700507
508 /* cleanup writing related jazz */
Craig Tiller606d8742015-06-15 06:58:50 -0700509 grpc_chttp2_cleanup_writing(&t->global, &t->writing);
Craig Tillerd20efd22015-06-12 16:17:09 -0700510
ctiller00297df2015-01-12 11:23:09 -0800511 /* leave the writing flag up on shutdown to prevent further writes in unlock()
512 from starting */
Craig Tillerd20efd22015-06-12 16:17:09 -0700513 t->writing_active = 0;
Craig Tillerf932fd52015-06-17 07:38:20 -0700514 if (t->ep && !t->endpoint_reading) {
ctiller00297df2015-01-12 11:23:09 -0800515 grpc_endpoint_destroy(t->ep);
516 t->ep = NULL;
Craig Tiller285b8822015-06-17 15:58:13 -0700517 UNREF_TRANSPORT(
518 t, "disconnect"); /* safe because we'll still have the ref for write */
ctiller00297df2015-01-12 11:23:09 -0800519 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700520
ctiller00297df2015-01-12 11:23:09 -0800521 unlock(t);
522
Craig Tiller759eb322015-06-16 22:41:18 -0700523 UNREF_TRANSPORT(t, "writing");
ctiller00297df2015-01-12 11:23:09 -0800524}
525
Craig Tiller1e6facb2015-06-11 22:47:11 -0700526static void writing_action(void *gt, int iomgr_success_ignored) {
Craig Tillerb084d902015-06-12 07:50:02 -0700527 grpc_chttp2_transport *t = gt;
Craig Tillerd20efd22015-06-12 16:17:09 -0700528 grpc_chttp2_perform_writes(&t->writing, t->ep);
ctiller00297df2015-01-12 11:23:09 -0800529}
530
Craig Tiller98505102015-06-16 11:33:15 -0700531void grpc_chttp2_add_incoming_goaway(
532 grpc_chttp2_transport_global *transport_global, gpr_uint32 goaway_error,
533 gpr_slice goaway_text) {
Julien Boeuf0ac7cdd2015-06-30 14:53:05 +0200534 char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700535 gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg);
Craig Tiller564872d2015-06-18 11:21:22 -0700536 gpr_free(msg);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700537 gpr_slice_unref(goaway_text);
538 transport_global->seen_goaway = 1;
Craig Tiller079a11b2015-06-30 10:07:15 -0700539 connectivity_state_set(transport_global, GRPC_CHANNEL_FATAL_FAILURE);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800540}
541
Craig Tiller98505102015-06-16 11:33:15 -0700542static void maybe_start_some_streams(
543 grpc_chttp2_transport_global *transport_global) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700544 grpc_chttp2_stream_global *stream_global;
Craig Tiller4aa71a12015-06-15 13:00:55 -0700545 /* start streams where we have free grpc_chttp2_stream ids and free
546 * concurrency */
Craig Tiller5dc3b302015-06-15 16:06:50 -0700547 while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID &&
548 transport_global->concurrent_stream_count <
Craig Tillerab630732015-06-25 11:20:01 -0700549 transport_global
550 ->settings[GRPC_PEER_SETTINGS]
551 [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] &&
Craig Tiller98505102015-06-16 11:33:15 -0700552 grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
553 &stream_global)) {
Craig Tillerab630732015-06-25 11:20:01 -0700554 GRPC_CHTTP2_IF_TRACING(gpr_log(
555 GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d",
556 transport_global->is_client ? "CLI" : "SVR", stream_global,
557 transport_global->next_stream_id));
Craig Tiller7098c032015-05-04 10:18:28 -0700558
Craig Tiller564872d2015-06-18 11:21:22 -0700559 GPR_ASSERT(stream_global->id == 0);
560 stream_global->id = transport_global->next_stream_id;
561 transport_global->next_stream_id += 2;
Craig Tiller7098c032015-05-04 10:18:28 -0700562
Craig Tiller564872d2015-06-18 11:21:22 -0700563 if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
Craig Tiller49924e02015-06-29 22:42:33 -0700564 connectivity_state_set(transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE);
Craig Tiller7098c032015-05-04 10:18:28 -0700565 }
566
Craig Tiller5dc3b302015-06-15 16:06:50 -0700567 stream_global->outgoing_window =
Craig Tillerab630732015-06-25 11:20:01 -0700568 transport_global->settings[GRPC_PEER_SETTINGS]
569 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tiller5dc3b302015-06-15 16:06:50 -0700570 stream_global->incoming_window =
Craig Tillerab630732015-06-25 11:20:01 -0700571 transport_global->settings[GRPC_SENT_SETTINGS]
572 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
Craig Tiller27166a62015-07-05 21:08:33 -0700573 stream_global->max_recv_bytes =
574 GPR_MAX(stream_global->incoming_window, stream_global->max_recv_bytes);
Craig Tiller98505102015-06-16 11:33:15 -0700575 grpc_chttp2_stream_map_add(
576 &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map,
577 stream_global->id, STREAM_FROM_GLOBAL(stream_global));
Craig Tiller31123db2015-06-16 17:06:31 -0700578 stream_global->in_stream_map = 1;
Craig Tiller5dc3b302015-06-15 16:06:50 -0700579 transport_global->concurrent_stream_count++;
Craig Tiller285b8822015-06-17 15:58:13 -0700580 grpc_chttp2_list_add_incoming_window_updated(transport_global,
581 stream_global);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700582 grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
Craig Tiller27166a62015-07-05 21:08:33 -0700583
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800584 }
Craig Tiller7098c032015-05-04 10:18:28 -0700585 /* cancel out streams that will never be started */
Craig Tiller564872d2015-06-18 11:21:22 -0700586 while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
Craig Tiller98505102015-06-16 11:33:15 -0700587 grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
588 &stream_global)) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700589 cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE);
Craig Tiller7098c032015-05-04 10:18:28 -0700590 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800591}
592
Craig Tiller1064f8b2015-06-25 13:52:57 -0700593static void perform_stream_op_locked(
594 grpc_chttp2_transport_global *transport_global,
595 grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
Craig Tiller2ea37fd2015-04-24 13:03:49 -0700596 if (op->cancel_with_status != GRPC_STATUS_OK) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700597 cancel_from_api(transport_global, stream_global, op->cancel_with_status);
Craig Tiller2ea37fd2015-04-24 13:03:49 -0700598 }
599
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700600 if (op->send_ops) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700601 GPR_ASSERT(stream_global->outgoing_sopb == NULL);
602 stream_global->send_done_closure = op->on_done_send;
603 if (!stream_global->cancelled) {
604 stream_global->outgoing_sopb = op->send_ops;
Craig Tillerab630732015-06-25 11:20:01 -0700605 if (op->is_last_send &&
606 stream_global->write_state == GRPC_WRITE_STATE_OPEN) {
607 stream_global->write_state = GRPC_WRITE_STATE_QUEUED_CLOSE;
Craig Tillerc079c112015-04-22 15:23:39 -0700608 }
Craig Tiller5dc3b302015-06-15 16:06:50 -0700609 if (stream_global->id == 0) {
Craig Tillerab630732015-06-25 11:20:01 -0700610 GRPC_CHTTP2_IF_TRACING(gpr_log(
Craig Tiller98505102015-06-16 11:33:15 -0700611 GPR_DEBUG,
612 "HTTP:%s: New grpc_chttp2_stream %p waiting for concurrency",
613 transport_global->is_client ? "CLI" : "SVR", stream_global));
614 grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
615 stream_global);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700616 maybe_start_some_streams(transport_global);
617 } else if (stream_global->outgoing_window > 0) {
618 grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
Craig Tillerc079c112015-04-22 15:23:39 -0700619 }
620 } else {
Craig Tiller606d8742015-06-15 06:58:50 -0700621 grpc_sopb_reset(op->send_ops);
Craig Tiller98505102015-06-16 11:33:15 -0700622 grpc_chttp2_schedule_closure(transport_global,
623 stream_global->send_done_closure, 0);
Craig Tillerc079c112015-04-22 15:23:39 -0700624 }
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700625 }
626
627 if (op->recv_ops) {
Craig Tiller6905b7c2015-06-16 15:33:33 -0700628 GPR_ASSERT(stream_global->publish_sopb == NULL);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700629 GPR_ASSERT(stream_global->published_state != GRPC_STREAM_CLOSED);
630 stream_global->recv_done_closure = op->on_done_recv;
Craig Tiller6905b7c2015-06-16 15:33:33 -0700631 stream_global->publish_sopb = op->recv_ops;
632 stream_global->publish_sopb->nops = 0;
Craig Tiller31123db2015-06-16 17:06:31 -0700633 stream_global->publish_state = op->recv_state;
Craig Tiller27166a62015-07-05 21:08:33 -0700634 if (stream_global->max_recv_bytes < op->max_recv_bytes) {
635 GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("op", transport_global, stream_global,
Craig Tiller27166a62015-07-05 21:08:33 -0700636 max_recv_bytes, op->max_recv_bytes - stream_global->max_recv_bytes);
Craig Tiller5c517b12015-07-15 13:28:10 -0700637 GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
638 "op", transport_global, stream_global, unannounced_incoming_window,
639 op->max_recv_bytes - stream_global->max_recv_bytes);
Craig Tiller27166a62015-07-05 21:08:33 -0700640 stream_global->unannounced_incoming_window += op->max_recv_bytes - stream_global->max_recv_bytes;
641 stream_global->max_recv_bytes = op->max_recv_bytes;
Craig Tiller4efb6962015-06-03 09:32:41 -0700642 }
Craig Tiller98505102015-06-16 11:33:15 -0700643 grpc_chttp2_incoming_metadata_live_op_buffer_end(
644 &stream_global->outstanding_metadata);
Craig Tiller5c517b12015-07-15 13:28:10 -0700645 if (stream_global->id != 0) {
646 grpc_chttp2_list_add_read_write_state_changed(transport_global,
647 stream_global);
Craig Tiller994c2622015-07-23 14:00:58 -0700648 grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
Craig Tiller5c517b12015-07-15 13:28:10 -0700649 }
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700650 }
651
652 if (op->bind_pollset) {
Craig Tiller98505102015-06-16 11:33:15 -0700653 add_to_pollset_locked(TRANSPORT_FROM_GLOBAL(transport_global),
654 op->bind_pollset);
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700655 }
Craig Tiller5dde66e2015-06-02 09:05:23 -0700656
657 if (op->on_consumed) {
Craig Tiller1937b062015-06-16 08:47:38 -0700658 grpc_chttp2_schedule_closure(transport_global, op->on_consumed, 1);
Craig Tiller5dde66e2015-06-02 09:05:23 -0700659 }
Craig Tiller50d9db52015-04-23 10:52:14 -0700660}
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700661
Craig Tiller1064f8b2015-06-25 13:52:57 -0700662static void perform_stream_op(grpc_transport *gt, grpc_stream *gs,
663 grpc_transport_stream_op *op) {
Craig Tillerb084d902015-06-12 07:50:02 -0700664 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
665 grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
Craig Tiller50d9db52015-04-23 10:52:14 -0700666
667 lock(t);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700668 perform_stream_op_locked(&t->global, &s->global, op);
Craig Tillerbe18b8d2015-04-22 14:00:47 -0700669 unlock(t);
670}
671
Craig Tiller1064f8b2015-06-25 13:52:57 -0700672static void send_ping_locked(grpc_chttp2_transport *t,
673 grpc_iomgr_closure *on_recv) {
Craig Tiller606d8742015-06-15 06:58:50 -0700674 grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p));
Craig Tiller606d8742015-06-15 06:58:50 -0700675 p->next = &t->global.pings;
676 p->prev = p->next->prev;
677 p->prev->next = p->next->prev = p;
678 p->id[0] = (t->global.ping_counter >> 56) & 0xff;
679 p->id[1] = (t->global.ping_counter >> 48) & 0xff;
680 p->id[2] = (t->global.ping_counter >> 40) & 0xff;
681 p->id[3] = (t->global.ping_counter >> 32) & 0xff;
682 p->id[4] = (t->global.ping_counter >> 24) & 0xff;
683 p->id[5] = (t->global.ping_counter >> 16) & 0xff;
684 p->id[6] = (t->global.ping_counter >> 8) & 0xff;
685 p->id[7] = t->global.ping_counter & 0xff;
686 p->on_recv = on_recv;
Craig Tiller1e6facb2015-06-11 22:47:11 -0700687 gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
Craig Tiller1064f8b2015-06-25 13:52:57 -0700688}
689
690static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
691 grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
692
693 lock(t);
694
695 if (op->on_consumed) {
696 grpc_chttp2_schedule_closure(&t->global, op->on_consumed, 1);
697 }
698
699 if (op->on_connectivity_state_change) {
Craig Tiller08a1cf82015-06-29 09:37:52 -0700700 grpc_connectivity_state_notify_on_state_change(
701 &t->channel_callback.state_tracker, op->connectivity_state,
702 op->on_connectivity_state_change);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700703 }
704
705 if (op->send_goaway) {
Craig Tiller9188d7a2015-07-05 12:44:37 -0700706 t->global.sent_goaway = 1;
Craig Tiller1064f8b2015-06-25 13:52:57 -0700707 grpc_chttp2_goaway_append(
708 t->global.last_incoming_stream_id,
709 grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
Craig Tillerbea1e622015-07-07 09:53:40 -0700710 gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
Craig Tiller9188d7a2015-07-05 12:44:37 -0700711 if (!grpc_chttp2_has_streams(t)) {
712 close_transport_locked(t);
713 }
Craig Tiller1064f8b2015-06-25 13:52:57 -0700714 }
715
716 if (op->set_accept_stream != NULL) {
717 t->channel_callback.accept_stream = op->set_accept_stream;
718 t->channel_callback.accept_stream_user_data =
719 op->set_accept_stream_user_data;
720 }
721
722 if (op->bind_pollset) {
723 add_to_pollset_locked(t, op->bind_pollset);
724 }
725
726 if (op->send_ping) {
727 send_ping_locked(t, op->send_ping);
728 }
729
730 if (op->disconnect) {
731 close_transport_locked(t);
732 }
733
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800734 unlock(t);
735}
736
737/*
738 * INPUT PROCESSING
739 */
740
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800741static grpc_stream_state compute_state(gpr_uint8 write_closed,
742 gpr_uint8 read_closed) {
743 if (write_closed && read_closed) return GRPC_STREAM_CLOSED;
744 if (write_closed) return GRPC_STREAM_SEND_CLOSED;
745 if (read_closed) return GRPC_STREAM_RECV_CLOSED;
746 return GRPC_STREAM_OPEN;
747}
748
Craig Tiller759eb322015-06-16 22:41:18 -0700749static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) {
Craig Tiller8823b142015-06-18 11:41:24 -0700750 size_t new_stream_count;
Craig Tiller285b8822015-06-17 15:58:13 -0700751 grpc_chttp2_stream *s =
752 grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700753 if (!s) {
754 s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id);
Craig Tiller48bfcdc2015-04-24 14:24:27 -0700755 }
Craig Tiller994c2622015-07-23 14:00:58 -0700756 grpc_chttp2_list_remove_writable_stream(&t->global, &s->global);
Craig Tiller759eb322015-06-16 22:41:18 -0700757 GPR_ASSERT(s);
758 s->global.in_stream_map = 0;
Craig Tiller66abdaa2015-06-17 08:00:39 -0700759 if (t->parsing.incoming_stream == &s->parsing) {
760 t->parsing.incoming_stream = NULL;
761 grpc_chttp2_parsing_become_skip_parser(&t->parsing);
762 }
Craig Tiller9188d7a2015-07-05 12:44:37 -0700763 if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
764 close_transport_locked(t);
765 }
Craig Tiller8823b142015-06-18 11:41:24 -0700766
Craig Tiller079a11b2015-06-30 10:07:15 -0700767 new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
768 grpc_chttp2_stream_map_size(&t->new_stream_map);
Craig Tiller8823b142015-06-18 11:41:24 -0700769 if (new_stream_count != t->global.concurrent_stream_count) {
770 t->global.concurrent_stream_count = new_stream_count;
771 maybe_start_some_streams(&t->global);
Craig Tiller59abfc22015-04-27 09:29:35 -0700772 }
Craig Tiller48bfcdc2015-04-24 14:24:27 -0700773}
774
Craig Tiller83fb0702015-06-16 21:13:07 -0700775static void unlock_check_read_write_state(grpc_chttp2_transport *t) {
776 grpc_chttp2_transport_global *transport_global = &t->global;
Craig Tillerf73fcd12015-06-16 16:25:26 -0700777 grpc_chttp2_stream_global *stream_global;
Craig Tiller31123db2015-06-16 17:06:31 -0700778 grpc_stream_state state;
Craig Tillerc079c112015-04-22 15:23:39 -0700779
Craig Tiller83fb0702015-06-16 21:13:07 -0700780 if (!t->parsing_active) {
Craig Tiller8823b142015-06-18 11:41:24 -0700781 /* if a stream is in the stream map, and gets cancelled, we need to ensure
782 we are not parsing before continuing the cancellation to keep things in
783 a sane state */
Craig Tiller83fb0702015-06-16 21:13:07 -0700784 while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
785 &stream_global)) {
786 GPR_ASSERT(stream_global->in_stream_map);
Craig Tillerab630732015-06-25 11:20:01 -0700787 GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_OPEN);
Craig Tiller83fb0702015-06-16 21:13:07 -0700788 GPR_ASSERT(stream_global->read_closed);
Craig Tiller759eb322015-06-16 22:41:18 -0700789 remove_stream(t, stream_global->id);
Craig Tiller83fb0702015-06-16 21:13:07 -0700790 grpc_chttp2_list_add_read_write_state_changed(transport_global,
791 stream_global);
792 }
793 }
794
Craig Tiller17be5dc2015-07-01 10:36:27 -0700795 if (!t->writing_active) {
Craig Tillerb3671532015-07-01 10:37:40 -0700796 while (grpc_chttp2_list_pop_cancelled_waiting_for_writing(transport_global,
797 &stream_global)) {
798 grpc_chttp2_list_add_read_write_state_changed(transport_global,
799 stream_global);
Craig Tiller17be5dc2015-07-01 10:36:27 -0700800 }
801 }
802
Craig Tiller285b8822015-06-17 15:58:13 -0700803 while (grpc_chttp2_list_pop_read_write_state_changed(transport_global,
804 &stream_global)) {
Craig Tillercec9eb92015-06-17 17:16:48 -0700805 if (stream_global->cancelled) {
Craig Tillerb3671532015-07-01 10:37:40 -0700806 if (t->writing_active &&
807 stream_global->write_state != GRPC_WRITE_STATE_SENT_CLOSE) {
808 grpc_chttp2_list_add_cancelled_waiting_for_writing(transport_global,
809 stream_global);
Craig Tiller17be5dc2015-07-01 10:36:27 -0700810 } else {
811 stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE;
812 stream_global->read_closed = 1;
813 if (!stream_global->published_cancelled) {
814 char buffer[GPR_LTOA_MIN_BUFSIZE];
815 gpr_ltoa(stream_global->cancelled_status, buffer);
816 grpc_chttp2_incoming_metadata_buffer_add(
817 &stream_global->incoming_metadata,
818 grpc_mdelem_from_strings(t->metadata_context, "grpc-status",
819 buffer));
820 grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into(
821 &stream_global->incoming_metadata, &stream_global->incoming_sopb);
822 stream_global->published_cancelled = 1;
823 }
Craig Tillerc1f75602015-04-24 11:44:53 -0700824 }
Craig Tillerc079c112015-04-22 15:23:39 -0700825 }
Craig Tillerab630732015-06-25 11:20:01 -0700826 if (stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE &&
Craig Tiller285b8822015-06-17 15:58:13 -0700827 stream_global->read_closed && stream_global->in_stream_map) {
Craig Tiller83fb0702015-06-16 21:13:07 -0700828 if (t->parsing_active) {
Craig Tiller285b8822015-06-17 15:58:13 -0700829 grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
830 stream_global);
Craig Tiller83fb0702015-06-16 21:13:07 -0700831 } else {
Craig Tiller759eb322015-06-16 22:41:18 -0700832 remove_stream(t, stream_global->id);
Craig Tiller48bfcdc2015-04-24 14:24:27 -0700833 }
Craig Tiller83fb0702015-06-16 21:13:07 -0700834 }
Craig Tillercec9eb92015-06-17 17:16:48 -0700835 if (!stream_global->publish_sopb) {
Craig Tillercec9eb92015-06-17 17:16:48 -0700836 continue;
837 }
Craig Tiller994c2622015-07-23 14:00:58 -0700838 if (stream_global->writing_now) {
839 continue;
840 }
Craig Tillereaa660e2015-06-18 16:36:12 -0700841 /* FIXME(ctiller): we include in_stream_map in our computation of
842 whether the stream is write-closed. This is completely bogus,
843 but has the effect of delaying stream-closed until the stream
844 is indeed evicted from the stream map, making it safe to delete.
845 To fix this will require having an edge after stream-closed
846 indicating that the stream is closed AND safe to delete. */
Craig Tiller285b8822015-06-17 15:58:13 -0700847 state = compute_state(
Craig Tillerab630732015-06-25 11:20:01 -0700848 stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE &&
849 !stream_global->in_stream_map,
Craig Tillerb951df12015-06-18 15:46:58 -0700850 stream_global->read_closed);
Craig Tiller285b8822015-06-17 15:58:13 -0700851 if (stream_global->incoming_sopb.nops == 0 &&
852 state == stream_global->published_state) {
Craig Tiller31123db2015-06-16 17:06:31 -0700853 continue;
854 }
Craig Tiller285b8822015-06-17 15:58:13 -0700855 grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op(
856 &stream_global->incoming_metadata, &stream_global->incoming_sopb,
857 &stream_global->outstanding_metadata);
Craig Tillerf73fcd12015-06-16 16:25:26 -0700858 grpc_sopb_swap(stream_global->publish_sopb, &stream_global->incoming_sopb);
Craig Tiller31123db2015-06-16 17:06:31 -0700859 stream_global->published_state = *stream_global->publish_state = state;
Craig Tiller285b8822015-06-17 15:58:13 -0700860 grpc_chttp2_schedule_closure(transport_global,
861 stream_global->recv_done_closure, 1);
Craig Tiller31123db2015-06-16 17:06:31 -0700862 stream_global->recv_done_closure = NULL;
863 stream_global->publish_sopb = NULL;
864 stream_global->publish_state = NULL;
Craig Tillerf73fcd12015-06-16 16:25:26 -0700865 }
866}
867
Craig Tiller98505102015-06-16 11:33:15 -0700868static void cancel_from_api(grpc_chttp2_transport_global *transport_global,
869 grpc_chttp2_stream_global *stream_global,
870 grpc_status_code status) {
Craig Tillerb787c502015-06-15 16:14:52 -0700871 stream_global->cancelled = 1;
Craig Tillercec9eb92015-06-17 17:16:48 -0700872 stream_global->cancelled_status = status;
873 if (stream_global->id != 0) {
Craig Tiller079a11b2015-06-30 10:07:15 -0700874 gpr_slice_buffer_add(
875 &transport_global->qbuf,
876 grpc_chttp2_rst_stream_create(
877 stream_global->id, grpc_chttp2_grpc_status_to_http2_error(status)));
Craig Tillerb787c502015-06-15 16:14:52 -0700878 }
Craig Tillercec9eb92015-06-17 17:16:48 -0700879 grpc_chttp2_list_add_read_write_state_changed(transport_global,
880 stream_global);
Craig Tillerb787c502015-06-15 16:14:52 -0700881}
882
Craig Tiller98505102015-06-16 11:33:15 -0700883static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
884 void *user_data,
885 grpc_chttp2_stream_global *stream_global) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700886 cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800887}
888
Craig Tillerb084d902015-06-12 07:50:02 -0700889static void end_all_the_calls(grpc_chttp2_transport *t) {
Craig Tiller5dc3b302015-06-15 16:06:50 -0700890 grpc_chttp2_for_all_streams(&t->global, NULL, cancel_stream_cb);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800891}
892
Craig Tillerb084d902015-06-12 07:50:02 -0700893static void drop_connection(grpc_chttp2_transport *t) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800894 close_transport_locked(t);
895 end_all_the_calls(t);
896}
897
Craig Tillerab630732015-06-25 11:20:01 -0700898/** update window from a settings change */
899static void update_global_window(void *args, gpr_uint32 id, void *stream) {
900 grpc_chttp2_transport *t = args;
901 grpc_chttp2_stream *s = stream;
902 grpc_chttp2_transport_global *transport_global = &t->global;
903 grpc_chttp2_stream_global *stream_global = &s->global;
Craig Tiller6f7411f2015-07-06 15:37:28 -0700904 int was_zero;
905 int is_zero;
Craig Tillerab630732015-06-25 11:20:01 -0700906
907 GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("settings", transport_global, stream_global,
908 outgoing_window,
909 t->parsing.initial_window_update);
Craig Tiller6f7411f2015-07-06 15:37:28 -0700910 was_zero = stream_global->outgoing_window <= 0;
Craig Tillerab630732015-06-25 11:20:01 -0700911 stream_global->outgoing_window += t->parsing.initial_window_update;
Craig Tiller6f7411f2015-07-06 15:37:28 -0700912 is_zero = stream_global->outgoing_window <= 0;
913
914 if (was_zero && !is_zero) {
915 grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
916 }
Craig Tillerab630732015-06-25 11:20:01 -0700917}
918
Craig Tiller69f56162015-06-30 14:54:31 -0700919static void read_error_locked(grpc_chttp2_transport *t) {
920 t->endpoint_reading = 0;
921 if (!t->writing_active && t->ep) {
922 grpc_endpoint_destroy(t->ep);
923 t->ep = NULL;
924 /* safe as we still have a ref for read */
925 UNREF_TRANSPORT(t, "disconnect");
926 }
927}
928
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800929/* tcp read callback */
930static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
931 grpc_endpoint_cb_status error) {
Craig Tillerb084d902015-06-12 07:50:02 -0700932 grpc_chttp2_transport *t = tp;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800933 size_t i;
Craig Tiller69f56162015-06-30 14:54:31 -0700934 int unref = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800935
936 switch (error) {
937 case GRPC_ENDPOINT_CB_SHUTDOWN:
938 case GRPC_ENDPOINT_CB_EOF:
939 case GRPC_ENDPOINT_CB_ERROR:
940 lock(t);
941 drop_connection(t);
Craig Tiller69f56162015-06-30 14:54:31 -0700942 read_error_locked(t);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800943 unlock(t);
Craig Tiller69f56162015-06-30 14:54:31 -0700944 unref = 1;
Craig Tiller5dc3b302015-06-15 16:06:50 -0700945 for (i = 0; i < nslices; i++) gpr_slice_unref(slices[i]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800946 break;
947 case GRPC_ENDPOINT_CB_OK:
Craig Tiller1e6facb2015-06-11 22:47:11 -0700948 lock(t);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700949 i = 0;
Craig Tiller606d8742015-06-15 06:58:50 -0700950 GPR_ASSERT(!t->parsing_active);
Craig Tiller1064f8b2015-06-25 13:52:57 -0700951 if (!t->closed) {
Craig Tiller606d8742015-06-15 06:58:50 -0700952 t->parsing_active = 1;
Craig Tiller759eb322015-06-16 22:41:18 -0700953 /* merge stream lists */
954 grpc_chttp2_stream_map_move_into(&t->new_stream_map,
955 &t->parsing_stream_map);
Craig Tiller606d8742015-06-15 06:58:50 -0700956 grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
Craig Tiller1e6facb2015-06-11 22:47:11 -0700957 gpr_mu_unlock(&t->mu);
Craig Tiller98505102015-06-16 11:33:15 -0700958 for (; i < nslices && grpc_chttp2_perform_read(&t->parsing, slices[i]);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700959 i++) {
960 gpr_slice_unref(slices[i]);
961 }
Craig Tiller02f254e2015-06-11 23:06:07 -0700962 gpr_mu_lock(&t->mu);
Craig Tillerd20efd22015-06-12 16:17:09 -0700963 if (i != nslices) {
964 drop_connection(t);
965 }
Craig Tiller606d8742015-06-15 06:58:50 -0700966 /* merge stream lists */
Craig Tiller4aa71a12015-06-15 13:00:55 -0700967 grpc_chttp2_stream_map_move_into(&t->new_stream_map,
968 &t->parsing_stream_map);
Craig Tiller079a11b2015-06-30 10:07:15 -0700969 t->global.concurrent_stream_count =
970 grpc_chttp2_stream_map_size(&t->parsing_stream_map);
Craig Tillerab630732015-06-25 11:20:01 -0700971 if (t->parsing.initial_window_update != 0) {
972 grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
973 update_global_window, t);
Craig Tiller0e640a82015-07-01 15:41:52 -0700974 t->parsing.initial_window_update = 0;
Craig Tillerab630732015-06-25 11:20:01 -0700975 }
Craig Tiller606d8742015-06-15 06:58:50 -0700976 /* handle higher level things */
977 grpc_chttp2_publish_reads(&t->global, &t->parsing);
978 t->parsing_active = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800979 }
Craig Tiller5dc3b302015-06-15 16:06:50 -0700980 if (i == nslices) {
Craig Tiller8b2f1d72015-06-18 13:38:38 -0700981 grpc_chttp2_schedule_closure(&t->global, &t->reading_action, 1);
Craig Tiller69f56162015-06-30 14:54:31 -0700982 } else {
983 read_error_locked(t);
984 unref = 1;
Craig Tiller5dc3b302015-06-15 16:06:50 -0700985 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800986 unlock(t);
Craig Tiller5dc3b302015-06-15 16:06:50 -0700987 for (; i < nslices; i++) gpr_slice_unref(slices[i]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800988 break;
989 }
Craig Tiller69f56162015-06-30 14:54:31 -0700990 if (unref) {
991 UNREF_TRANSPORT(t, "recv_data");
992 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800993}
994
Craig Tiller8b2f1d72015-06-18 13:38:38 -0700995static void reading_action(void *pt, int iomgr_success_ignored) {
996 grpc_chttp2_transport *t = pt;
997 grpc_endpoint_notify_on_read(t->ep, recv_data, t);
998}
999
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001000/*
1001 * CALLBACK LOOP
1002 */
1003
Craig Tiller079a11b2015-06-30 10:07:15 -07001004static void schedule_closure_for_connectivity(void *a,
1005 grpc_iomgr_closure *closure) {
Craig Tillerff3ae682015-06-29 17:44:04 -07001006 grpc_chttp2_schedule_closure(a, closure, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001007}
1008
Craig Tiller079a11b2015-06-30 10:07:15 -07001009static void connectivity_state_set(
1010 grpc_chttp2_transport_global *transport_global,
1011 grpc_connectivity_state state) {
1012 GRPC_CHTTP2_IF_TRACING(
1013 gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
Craig Tillerff3ae682015-06-29 17:44:04 -07001014 grpc_connectivity_state_set_with_scheduler(
Craig Tiller079a11b2015-06-30 10:07:15 -07001015 &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
1016 state, schedule_closure_for_connectivity, transport_global);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001017}
1018
Craig Tiller98505102015-06-16 11:33:15 -07001019void grpc_chttp2_schedule_closure(
1020 grpc_chttp2_transport_global *transport_global, grpc_iomgr_closure *closure,
1021 int success) {
Craig Tiller1e6facb2015-06-11 22:47:11 -07001022 closure->success = success;
Craig Tillerff3ae682015-06-29 17:44:04 -07001023 if (transport_global->pending_closures_tail == NULL) {
1024 transport_global->pending_closures_head =
1025 transport_global->pending_closures_tail = closure;
1026 } else {
1027 transport_global->pending_closures_tail->next = closure;
1028 transport_global->pending_closures_tail = closure;
1029 }
1030 closure->next = NULL;
Craig Tiller748fe3f2015-03-02 07:48:50 -08001031}
1032
Craig Tillerc079c112015-04-22 15:23:39 -07001033/*
1034 * POLLSET STUFF
1035 */
1036
Craig Tiller4aa71a12015-06-15 13:00:55 -07001037static void add_to_pollset_locked(grpc_chttp2_transport *t,
1038 grpc_pollset *pollset) {
ctillerd79b4862014-12-17 16:36:59 -08001039 if (t->ep) {
1040 grpc_endpoint_add_to_pollset(t->ep, pollset);
1041 }
Craig Tillerc079c112015-04-22 15:23:39 -07001042}
1043
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001044/*
Craig Tiller285b8822015-06-17 15:58:13 -07001045 * TRACING
1046 */
1047
1048void grpc_chttp2_flowctl_trace(const char *file, int line, const char *reason,
1049 const char *context, const char *var,
1050 int is_client, gpr_uint32 stream_id,
1051 gpr_int64 current_value, gpr_int64 delta) {
1052 char *identifier;
1053 char *context_scope;
1054 char *context_thread;
1055 char *underscore_pos = strchr(context, '_');
1056 GPR_ASSERT(underscore_pos);
1057 context_thread = gpr_strdup(underscore_pos + 1);
1058 context_scope = gpr_strdup(context);
1059 context_scope[underscore_pos - context] = 0;
1060 if (stream_id) {
1061 gpr_asprintf(&identifier, "%s[%d]", context_scope, stream_id);
1062 } else {
1063 identifier = gpr_strdup(context_scope);
1064 }
Craig Tiller8b2f1d72015-06-18 13:38:38 -07001065 gpr_log(GPR_INFO,
Craig Tiller5c517b12015-07-15 13:28:10 -07001066 "FLOWCTL: %s %-10s %8s %-27s %8lld %c %8lld = %8lld %-10s [%s:%d]",
Craig Tiller285b8822015-06-17 15:58:13 -07001067 is_client ? "client" : "server", identifier, context_thread, var,
1068 current_value, delta < 0 ? '-' : '+', delta < 0 ? -delta : delta,
1069 current_value + delta, reason, file, line);
1070 gpr_free(identifier);
1071 gpr_free(context_thread);
1072 gpr_free(context_scope);
1073}
1074
1075/*
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001076 * INTEGRATION GLUE
1077 */
1078
Craig Tiller1b22b9d2015-07-20 13:42:22 -07001079static char *chttp2_get_peer(grpc_transport *t) {
1080 return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string);
1081}
1082
1083static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
1084 init_stream,
1085 perform_stream_op,
1086 perform_transport_op,
1087 destroy_stream,
1088 destroy_transport,
1089 chttp2_get_peer};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001090
Craig Tiller1064f8b2015-06-25 13:52:57 -07001091grpc_transport *grpc_create_chttp2_transport(
Craig Tiller825b21c2015-07-06 08:35:02 -07001092 const grpc_channel_args *channel_args, grpc_endpoint *ep, grpc_mdctx *mdctx,
1093 int is_client) {
Craig Tillerb084d902015-06-12 07:50:02 -07001094 grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport));
Craig Tiller825b21c2015-07-06 08:35:02 -07001095 init_transport(t, channel_args, ep, mdctx, is_client);
Craig Tiller1064f8b2015-06-25 13:52:57 -07001096 return &t->base;
Craig Tiller190d3602015-02-18 09:23:38 -08001097}
Craig Tiller825b21c2015-07-06 08:35:02 -07001098
1099void grpc_chttp2_transport_start_reading(grpc_transport *transport,
1100 gpr_slice *slices, size_t nslices) {
1101 grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
1102 REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */
1103 recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK);
Craig Tiller06059952015-02-18 08:34:56 -08001104}