blob: daea331d3139215ccc624790b13ac43656754f56 [file] [log] [blame]
Craig Tillerd8df50c2015-06-12 07:53:56 -07001/*
2 *
yang-g897925e2016-01-28 09:23:46 -08003 * Copyright 2015-2016, Google Inc.
Craig Tillerd8df50c2015-06-12 07:53:56 -07004 * 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
Craig Tiller9533d042016-03-25 17:11:06 -070034#include "src/core/lib/transport/chttp2/internal.h"
Craig Tillerf96dfc32015-09-10 14:43:18 -070035
36#include <limits.h>
Craig Tiller3208e392015-06-12 08:17:02 -070037
38#include <grpc/support/log.h>
39
Craig Tiller9533d042016-03-25 17:11:06 -070040#include "src/core/lib/profiling/timers.h"
41#include "src/core/lib/transport/chttp2/http2_errors.h"
Craig Tillerf96dfc32015-09-10 14:43:18 -070042
Craig Tiller9d35a1f2015-11-02 14:16:12 -080043static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
44 grpc_chttp2_transport_writing *transport_writing);
Craig Tillerd20efd22015-06-12 16:17:09 -070045
Craig Tillera82950e2015-09-22 12:33:20 -070046int grpc_chttp2_unlocking_check_writes(
yang-g276e32d2016-02-22 13:15:30 -080047 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
Craig Tiller3c53bb22015-11-10 14:24:36 +000048 grpc_chttp2_transport_writing *transport_writing, int is_parsing) {
Craig Tillerd20efd22015-06-12 16:17:09 -070049 grpc_chttp2_stream_global *stream_global;
50 grpc_chttp2_stream_writing *stream_writing;
Craig Tiller9d35a1f2015-11-02 14:16:12 -080051
52 GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0);
Craig Tiller3208e392015-06-12 08:17:02 -070053
Craig Tiller3208e392015-06-12 08:17:02 -070054 /* simple writes are queued to qbuf, and flushed here */
Craig Tillera82950e2015-09-22 12:33:20 -070055 gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
56 GPR_ASSERT(transport_global->qbuf.count == 0);
Craig Tiller3208e392015-06-12 08:17:02 -070057
Craig Tiller3c53bb22015-11-10 14:24:36 +000058 grpc_chttp2_hpack_compressor_set_max_table_size(
59 &transport_writing->hpack_compressor,
60 transport_global->settings[GRPC_PEER_SETTINGS]
61 [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
Craig Tiller027a74c2015-11-10 08:37:46 +000062
Craig Tillera82950e2015-09-22 12:33:20 -070063 if (transport_global->dirtied_local_settings &&
Craig Tiller3c53bb22015-11-10 14:24:36 +000064 !transport_global->sent_local_settings && !is_parsing) {
Craig Tillera82950e2015-09-22 12:33:20 -070065 gpr_slice_buffer_add(
66 &transport_writing->outbuf,
67 grpc_chttp2_settings_create(
68 transport_global->settings[GRPC_SENT_SETTINGS],
69 transport_global->settings[GRPC_LOCAL_SETTINGS],
70 transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
71 transport_global->force_send_settings = 0;
72 transport_global->dirtied_local_settings = 0;
73 transport_global->sent_local_settings = 1;
74 }
Craig Tiller3208e392015-06-12 08:17:02 -070075
Craig Tiller9d35a1f2015-11-02 14:16:12 -080076 GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
77 transport_global, outgoing_window);
yang-g6494e8b2016-02-05 23:54:03 -080078 bool is_window_available = transport_writing->outgoing_window > 0;
yang-g276e32d2016-02-22 13:15:30 -080079 grpc_chttp2_list_flush_writing_stalled_by_transport(
80 exec_ctx, transport_writing, is_window_available);
Craig Tiller9d35a1f2015-11-02 14:16:12 -080081
Craig Tiller4aa71a12015-06-15 13:00:55 -070082 /* for each grpc_chttp2_stream that's become writable, frame it's data
Craig Tiller994c2622015-07-23 14:00:58 -070083 (according to available window sizes) and add to the output buffer */
Craig Tillera82950e2015-09-22 12:33:20 -070084 while (grpc_chttp2_list_pop_writable_stream(
85 transport_global, transport_writing, &stream_global, &stream_writing)) {
Craig Tiller0cb803d2016-03-02 22:17:24 -080086 bool sent_initial_metadata = stream_writing->sent_initial_metadata;
87 bool become_writable = false;
Craig Tillerd20efd22015-06-12 16:17:09 -070088
Craig Tillera82950e2015-09-22 12:33:20 -070089 stream_writing->id = stream_global->id;
Craig Tiller9d35a1f2015-11-02 14:16:12 -080090 stream_writing->read_closed = stream_global->read_closed;
Craig Tillera82950e2015-09-22 12:33:20 -070091
Craig Tiller9d35a1f2015-11-02 14:16:12 -080092 GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing,
93 outgoing_window, stream_global,
94 outgoing_window);
Craig Tillera82950e2015-09-22 12:33:20 -070095
Craig Tiller9d35a1f2015-11-02 14:16:12 -080096 if (!sent_initial_metadata && stream_global->send_initial_metadata) {
97 stream_writing->send_initial_metadata =
98 stream_global->send_initial_metadata;
99 stream_global->send_initial_metadata = NULL;
Craig Tiller0cb803d2016-03-02 22:17:24 -0800100 become_writable = true;
101 sent_initial_metadata = true;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800102 }
103 if (sent_initial_metadata) {
104 if (stream_global->send_message != NULL) {
105 gpr_slice hdr = gpr_slice_malloc(5);
Craig Tiller7536af02015-12-22 13:49:30 -0800106 uint8_t *p = GPR_SLICE_START_PTR(hdr);
107 uint32_t len = stream_global->send_message->length;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800108 GPR_ASSERT(stream_writing->send_message == NULL);
109 p[0] = (stream_global->send_message->flags &
110 GRPC_WRITE_INTERNAL_COMPRESS) != 0;
Craig Tiller7536af02015-12-22 13:49:30 -0800111 p[1] = (uint8_t)(len >> 24);
112 p[2] = (uint8_t)(len >> 16);
113 p[3] = (uint8_t)(len >> 8);
114 p[4] = (uint8_t)(len);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800115 gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr);
116 if (stream_global->send_message->length > 0) {
117 stream_writing->send_message = stream_global->send_message;
Craig Tillera82950e2015-09-22 12:33:20 -0700118 } else {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800119 stream_writing->send_message = NULL;
120 }
121 stream_writing->stream_fetched = 0;
122 stream_global->send_message = NULL;
123 }
124 if ((stream_writing->send_message != NULL ||
125 stream_writing->flow_controlled_buffer.length > 0) &&
126 stream_writing->outgoing_window > 0) {
127 if (transport_writing->outgoing_window > 0) {
Craig Tiller0cb803d2016-03-02 22:17:24 -0800128 become_writable = true;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800129 } else {
yang-g276e32d2016-02-22 13:15:30 -0800130 grpc_chttp2_list_add_stalled_by_transport(transport_writing,
131 stream_writing);
Craig Tillera82950e2015-09-22 12:33:20 -0700132 }
133 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800134 if (stream_global->send_trailing_metadata) {
135 stream_writing->send_trailing_metadata =
136 stream_global->send_trailing_metadata;
137 stream_global->send_trailing_metadata = NULL;
Craig Tiller0cb803d2016-03-02 22:17:24 -0800138 become_writable = true;
Craig Tillera82950e2015-09-22 12:33:20 -0700139 }
140 }
141
142 if (!stream_global->read_closed &&
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800143 stream_global->unannounced_incoming_window_for_writing > 1024) {
144 GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing,
145 announce_window, stream_global,
146 unannounced_incoming_window_for_writing);
Craig Tiller0cb803d2016-03-02 22:17:24 -0800147 become_writable = true;
148 }
149
150 if (become_writable) {
151 grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
152 } else {
153 GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
Craig Tillera82950e2015-09-22 12:33:20 -0700154 }
155 }
156
Craig Tiller4aa71a12015-06-15 13:00:55 -0700157 /* if the grpc_chttp2_transport is ready to send a window update, do so here
Craig Tillerab630732015-06-25 11:20:01 -0700158 also; 3/4 is a magic number that will likely get tuned soon */
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800159 if (transport_global->announce_incoming_window > 0) {
Craig Tiller7536af02015-12-22 13:49:30 -0800160 uint32_t announced = (uint32_t)GPR_MIN(
161 transport_global->announce_incoming_window, UINT32_MAX);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800162 GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_global,
163 announce_incoming_window, announced);
Craig Tillera82950e2015-09-22 12:33:20 -0700164 gpr_slice_buffer_add(&transport_writing->outbuf,
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800165 grpc_chttp2_window_update_create(0, announced));
Craig Tillera82950e2015-09-22 12:33:20 -0700166 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700167
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800168 GPR_TIMER_END("grpc_chttp2_unlocking_check_writes", 0);
169
Craig Tillera82950e2015-09-22 12:33:20 -0700170 return transport_writing->outbuf.count > 0 ||
171 grpc_chttp2_list_have_writing_streams(transport_writing);
Craig Tillerd20efd22015-06-12 16:17:09 -0700172}
173
Craig Tillera82950e2015-09-22 12:33:20 -0700174void grpc_chttp2_perform_writes(
175 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
176 grpc_endpoint *endpoint) {
177 GPR_ASSERT(transport_writing->outbuf.count > 0 ||
178 grpc_chttp2_list_have_writing_streams(transport_writing));
Craig Tillercdf52bc2015-06-16 13:00:27 -0700179
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800180 finalize_outbuf(exec_ctx, transport_writing);
Craig Tillerd20efd22015-06-12 16:17:09 -0700181
Craig Tillera82950e2015-09-22 12:33:20 -0700182 GPR_ASSERT(endpoint);
Craig Tillerf932fd52015-06-17 07:38:20 -0700183
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800184 if (transport_writing->outbuf.count > 0) {
185 grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
186 &transport_writing->done_cb);
187 } else {
Craig Tiller6c396862016-01-28 13:53:40 -0800188 grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, true, NULL);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800189 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700190}
191
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800192static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
193 grpc_chttp2_transport_writing *transport_writing) {
Craig Tillerd20efd22015-06-12 16:17:09 -0700194 grpc_chttp2_stream_writing *stream_writing;
195
Craig Tiller0ba432d2015-10-09 16:57:11 -0700196 GPR_TIMER_BEGIN("finalize_outbuf", 0);
Craig Tiller1f41b6b2015-10-09 15:07:02 -0700197
Craig Tillera82950e2015-09-22 12:33:20 -0700198 while (
199 grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
Craig Tiller7536af02015-12-22 13:49:30 -0800200 uint32_t max_outgoing =
201 (uint32_t)GPR_MIN(GRPC_CHTTP2_MAX_PAYLOAD_LENGTH,
202 GPR_MIN(stream_writing->outgoing_window,
203 transport_writing->outgoing_window));
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800204 /* send initial metadata if it's available */
205 if (stream_writing->send_initial_metadata != NULL) {
206 grpc_chttp2_encode_header(
207 &transport_writing->hpack_compressor, stream_writing->id,
208 stream_writing->send_initial_metadata, 0, &transport_writing->outbuf);
209 stream_writing->send_initial_metadata = NULL;
210 stream_writing->sent_initial_metadata = 1;
Craig Tiller86316522015-07-15 11:35:07 -0700211 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800212 /* send any window updates */
213 if (stream_writing->announce_window > 0 &&
214 stream_writing->send_initial_metadata == NULL) {
Craig Tiller7536af02015-12-22 13:49:30 -0800215 uint32_t announce = stream_writing->announce_window;
Craig Tillera82950e2015-09-22 12:33:20 -0700216 gpr_slice_buffer_add(
217 &transport_writing->outbuf,
218 grpc_chttp2_window_update_create(stream_writing->id,
219 stream_writing->announce_window));
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800220 GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, stream_writing,
221 announce_window, announce);
Craig Tillera82950e2015-09-22 12:33:20 -0700222 stream_writing->announce_window = 0;
223 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800224 /* fetch any body bytes */
225 while (!stream_writing->fetching && stream_writing->send_message &&
226 stream_writing->flow_controlled_buffer.length < max_outgoing &&
227 stream_writing->stream_fetched <
228 stream_writing->send_message->length) {
229 if (grpc_byte_stream_next(exec_ctx, stream_writing->send_message,
230 &stream_writing->fetching_slice, max_outgoing,
231 &stream_writing->finished_fetch)) {
232 stream_writing->stream_fetched +=
233 GPR_SLICE_LENGTH(stream_writing->fetching_slice);
234 if (stream_writing->stream_fetched ==
235 stream_writing->send_message->length) {
236 stream_writing->send_message = NULL;
237 }
238 gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer,
239 stream_writing->fetching_slice);
240 } else {
241 stream_writing->fetching = 1;
242 }
Craig Tillera82950e2015-09-22 12:33:20 -0700243 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800244 /* send any body bytes */
245 if (stream_writing->flow_controlled_buffer.length > 0) {
246 if (max_outgoing > 0) {
Craig Tiller7536af02015-12-22 13:49:30 -0800247 uint32_t send_bytes = (uint32_t)GPR_MIN(
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800248 max_outgoing, stream_writing->flow_controlled_buffer.length);
249 int is_last_data_frame =
250 stream_writing->send_message == NULL &&
251 send_bytes == stream_writing->flow_controlled_buffer.length;
252 int is_last_frame = is_last_data_frame &&
253 stream_writing->send_trailing_metadata != NULL &&
254 grpc_metadata_batch_is_empty(
255 stream_writing->send_trailing_metadata);
256 grpc_chttp2_encode_data(
257 stream_writing->id, &stream_writing->flow_controlled_buffer,
258 send_bytes, is_last_frame, &transport_writing->outbuf);
259 GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing,
260 stream_writing, outgoing_window,
261 send_bytes);
262 GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_writing,
263 outgoing_window, send_bytes);
264 if (is_last_frame) {
265 stream_writing->send_trailing_metadata = NULL;
266 stream_writing->sent_trailing_metadata = 1;
267 }
268 if (is_last_data_frame) {
269 GPR_ASSERT(stream_writing->send_message == NULL);
270 stream_writing->sent_message = 1;
271 }
272 } else if (transport_writing->outgoing_window == 0) {
yang-g348f3a22016-01-27 16:17:32 -0800273 grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
274 stream_writing);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800275 grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
276 }
277 }
278 /* send trailing metadata if it's available and we're ready for it */
279 if (stream_writing->send_message == NULL &&
280 stream_writing->flow_controlled_buffer.length == 0 &&
281 stream_writing->send_trailing_metadata != NULL) {
282 if (grpc_metadata_batch_is_empty(
283 stream_writing->send_trailing_metadata)) {
284 grpc_chttp2_encode_data(stream_writing->id,
285 &stream_writing->flow_controlled_buffer, 0, 1,
286 &transport_writing->outbuf);
287 } else {
288 grpc_chttp2_encode_header(&transport_writing->hpack_compressor,
289 stream_writing->id,
290 stream_writing->send_trailing_metadata, 1,
291 &transport_writing->outbuf);
292 }
293 if (!transport_writing->is_client && !stream_writing->read_closed) {
294 gpr_slice_buffer_add(&transport_writing->outbuf,
295 grpc_chttp2_rst_stream_create(
296 stream_writing->id, GRPC_CHTTP2_NO_ERROR));
297 }
298 stream_writing->send_trailing_metadata = NULL;
299 stream_writing->sent_trailing_metadata = 1;
300 }
301 /* if there's more to write, then loop, otherwise prepare to finish the
302 * write */
303 if ((stream_writing->flow_controlled_buffer.length > 0 ||
304 (stream_writing->send_message && !stream_writing->fetching)) &&
305 stream_writing->outgoing_window > 0) {
306 if (transport_writing->outgoing_window > 0) {
Craig Tiller0cb803d2016-03-02 22:17:24 -0800307 grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800308 } else {
yang-g348f3a22016-01-27 16:17:32 -0800309 grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
310 stream_writing);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800311 grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
312 }
313 } else {
314 grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
315 }
Craig Tillera82950e2015-09-22 12:33:20 -0700316 }
Craig Tiller61ead3e2015-11-03 11:03:48 -0800317
318 GPR_TIMER_END("finalize_outbuf", 0);
Craig Tillerd20efd22015-06-12 16:17:09 -0700319}
320
Craig Tillera82950e2015-09-22 12:33:20 -0700321void grpc_chttp2_cleanup_writing(
322 grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
323 grpc_chttp2_transport_writing *transport_writing) {
Craig Tillerd20efd22015-06-12 16:17:09 -0700324 grpc_chttp2_stream_writing *stream_writing;
325 grpc_chttp2_stream_global *stream_global;
yang-g348f3a22016-01-27 16:17:32 -0800326
Craig Tillera82950e2015-09-22 12:33:20 -0700327 while (grpc_chttp2_list_pop_written_stream(
328 transport_global, transport_writing, &stream_global, &stream_writing)) {
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800329 if (stream_writing->sent_initial_metadata) {
330 grpc_chttp2_complete_closure_step(
331 exec_ctx, &stream_global->send_initial_metadata_finished, 1);
Craig Tillera82950e2015-09-22 12:33:20 -0700332 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800333 if (stream_writing->sent_message) {
334 GPR_ASSERT(stream_writing->send_message == NULL);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800335 grpc_chttp2_complete_closure_step(
336 exec_ctx, &stream_global->send_message_finished, 1);
337 stream_writing->sent_message = 0;
338 }
339 if (stream_writing->sent_trailing_metadata) {
340 grpc_chttp2_complete_closure_step(
341 exec_ctx, &stream_global->send_trailing_metadata_finished, 1);
342 }
Craig Tiller45798462015-12-14 21:42:53 -0800343 if (stream_writing->sent_trailing_metadata) {
344 grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
345 !transport_global->is_client, 1);
346 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800347 GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
Craig Tillera82950e2015-09-22 12:33:20 -0700348 }
349 gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf);
Craig Tiller3208e392015-06-12 08:17:02 -0700350}