blob: d39b0c42f7f2fd661101e4dbb5e08f3ed27a9136 [file] [log] [blame]
Craig Tillerd8df50c2015-06-12 07:53:56 -07001/*
2 *
3 * Copyright 2015, Google Inc.
4 * 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/internal.h"
Craig Tillerd20efd22015-06-12 16:17:09 -070035#include "src/core/transport/chttp2/http2_errors.h"
Craig Tiller3208e392015-06-12 08:17:02 -070036
37#include <grpc/support/log.h>
38
Craig Tillerd20efd22015-06-12 16:17:09 -070039static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing);
40static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status);
41
Craig Tiller4aa71a12015-06-15 13:00:55 -070042int grpc_chttp2_unlocking_check_writes(
43 grpc_chttp2_transport_global *transport_global,
44 grpc_chttp2_transport_writing *transport_writing) {
Craig Tillerd20efd22015-06-12 16:17:09 -070045 grpc_chttp2_stream_global *stream_global;
46 grpc_chttp2_stream_writing *stream_writing;
Craig Tiller994c2622015-07-23 14:00:58 -070047 grpc_chttp2_stream_global *first_reinserted_stream = NULL;
Craig Tiller3208e392015-06-12 08:17:02 -070048 gpr_uint32 window_delta;
49
Craig Tiller3208e392015-06-12 08:17:02 -070050 /* simple writes are queued to qbuf, and flushed here */
Craig Tillerd20efd22015-06-12 16:17:09 -070051 gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
52 GPR_ASSERT(transport_global->qbuf.count == 0);
Craig Tiller3208e392015-06-12 08:17:02 -070053
Craig Tiller4aa71a12015-06-15 13:00:55 -070054 if (transport_global->dirtied_local_settings &&
55 !transport_global->sent_local_settings) {
Craig Tiller3208e392015-06-12 08:17:02 -070056 gpr_slice_buffer_add(
Craig Tiller4aa71a12015-06-15 13:00:55 -070057 &transport_writing->outbuf,
Craig Tillerab630732015-06-25 11:20:01 -070058 grpc_chttp2_settings_create(
59 transport_global->settings[GRPC_SENT_SETTINGS],
60 transport_global->settings[GRPC_LOCAL_SETTINGS],
61 transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
Craig Tillerd20efd22015-06-12 16:17:09 -070062 transport_global->force_send_settings = 0;
63 transport_global->dirtied_local_settings = 0;
64 transport_global->sent_local_settings = 1;
Craig Tiller3208e392015-06-12 08:17:02 -070065 }
66
Craig Tiller4aa71a12015-06-15 13:00:55 -070067 /* for each grpc_chttp2_stream that's become writable, frame it's data
Craig Tiller994c2622015-07-23 14:00:58 -070068 (according to available window sizes) and add to the output buffer */
69 while (grpc_chttp2_list_pop_writable_stream(
70 transport_global, transport_writing, &stream_global, &stream_writing)) {
71 if (stream_global == first_reinserted_stream) {
72 /* prevent infinite loop */
73 grpc_chttp2_list_add_first_writable_stream(transport_global,
74 stream_global);
75 break;
76 }
Craig Tiller3208e392015-06-12 08:17:02 -070077
Craig Tiller994c2622015-07-23 14:00:58 -070078 stream_writing->id = stream_global->id;
79 stream_writing->send_closed = GRPC_DONT_SEND_CLOSED;
Craig Tiller05cc0c42015-07-23 16:01:27 -070080 GPR_ASSERT(!stream_global->writing_now);
Craig Tiller994c2622015-07-23 14:00:58 -070081
82 if (stream_global->outgoing_sopb) {
83 window_delta =
84 grpc_chttp2_preencode(stream_global->outgoing_sopb->ops,
85 &stream_global->outgoing_sopb->nops,
86 GPR_MIN(transport_global->outgoing_window,
87 stream_global->outgoing_window),
88 &stream_writing->sopb);
89 GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
90 "write", transport_global, outgoing_window, -(gpr_int64)window_delta);
91 GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
92 outgoing_window,
93 -(gpr_int64)window_delta);
94 transport_global->outgoing_window -= window_delta;
95 stream_global->outgoing_window -= window_delta;
96
97 if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE &&
98 stream_global->outgoing_sopb->nops == 0) {
99 if (!transport_global->is_client && !stream_global->read_closed) {
100 stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM;
101 } else {
102 stream_writing->send_closed = GRPC_SEND_CLOSED;
103 }
104 }
105
106 if (stream_global->outgoing_window > 0 &&
107 stream_global->outgoing_sopb->nops != 0) {
108 grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
109 if (first_reinserted_stream == NULL &&
110 transport_global->outgoing_window == 0) {
111 first_reinserted_stream = stream_global;
112 }
Craig Tiller3208e392015-06-12 08:17:02 -0700113 }
114 }
Craig Tiller3208e392015-06-12 08:17:02 -0700115
Craig Tiller27166a62015-07-05 21:08:33 -0700116 if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) {
Craig Tiller86316522015-07-15 11:35:07 -0700117 stream_writing->announce_window = stream_global->unannounced_incoming_window;
Craig Tiller285b8822015-06-17 15:58:13 -0700118 GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
Craig Tiller27166a62015-07-05 21:08:33 -0700119 incoming_window, stream_global->unannounced_incoming_window);
120 GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
121 unannounced_incoming_window, -(gpr_int64)stream_global->unannounced_incoming_window);
122 stream_global->incoming_window += stream_global->unannounced_incoming_window;
123 stream_global->unannounced_incoming_window = 0;
Craig Tiller285b8822015-06-17 15:58:13 -0700124 grpc_chttp2_list_add_incoming_window_updated(transport_global,
125 stream_global);
Craig Tiller994c2622015-07-23 14:00:58 -0700126 stream_global->writing_now = 1;
127 grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
128 } else if (stream_writing->sopb.nops > 0 ||
129 stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
130 stream_global->writing_now = 1;
Craig Tiller86316522015-07-15 11:35:07 -0700131 grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
Craig Tillerd20efd22015-06-12 16:17:09 -0700132 }
133 }
134
Craig Tiller4aa71a12015-06-15 13:00:55 -0700135 /* if the grpc_chttp2_transport is ready to send a window update, do so here
Craig Tillerab630732015-06-25 11:20:01 -0700136 also; 3/4 is a magic number that will likely get tuned soon */
Craig Tiller4aa71a12015-06-15 13:00:55 -0700137 if (transport_global->incoming_window <
138 transport_global->connection_window_target * 3 / 4) {
139 window_delta = transport_global->connection_window_target -
140 transport_global->incoming_window;
Craig Tillerd20efd22015-06-12 16:17:09 -0700141 gpr_slice_buffer_add(&transport_writing->outbuf,
142 grpc_chttp2_window_update_create(0, window_delta));
Craig Tiller285b8822015-06-17 15:58:13 -0700143 GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("write", transport_global,
144 incoming_window, window_delta);
Craig Tillerd20efd22015-06-12 16:17:09 -0700145 transport_global->incoming_window += window_delta;
146 }
147
Craig Tillercdf52bc2015-06-16 13:00:27 -0700148 return transport_writing->outbuf.count > 0 ||
Craig Tiller4aa71a12015-06-15 13:00:55 -0700149 grpc_chttp2_list_have_writing_streams(transport_writing);
Craig Tillerd20efd22015-06-12 16:17:09 -0700150}
151
Craig Tiller4aa71a12015-06-15 13:00:55 -0700152void grpc_chttp2_perform_writes(
153 grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint) {
Craig Tiller285b8822015-06-17 15:58:13 -0700154 GPR_ASSERT(transport_writing->outbuf.count > 0 ||
155 grpc_chttp2_list_have_writing_streams(transport_writing));
Craig Tillercdf52bc2015-06-16 13:00:27 -0700156
Craig Tillerd20efd22015-06-12 16:17:09 -0700157 finalize_outbuf(transport_writing);
158
159 GPR_ASSERT(transport_writing->outbuf.count > 0);
Craig Tillerc3fdaf92015-06-18 10:16:52 -0700160 GPR_ASSERT(endpoint);
Craig Tillerf932fd52015-06-17 07:38:20 -0700161
Craig Tiller4aa71a12015-06-15 13:00:55 -0700162 switch (grpc_endpoint_write(endpoint, transport_writing->outbuf.slices,
163 transport_writing->outbuf.count, finish_write_cb,
164 transport_writing)) {
Craig Tillerd20efd22015-06-12 16:17:09 -0700165 case GRPC_ENDPOINT_WRITE_DONE:
166 grpc_chttp2_terminate_writing(transport_writing, 1);
167 break;
168 case GRPC_ENDPOINT_WRITE_ERROR:
169 grpc_chttp2_terminate_writing(transport_writing, 0);
170 break;
171 case GRPC_ENDPOINT_WRITE_PENDING:
172 break;
173 }
174}
175
176static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
177 grpc_chttp2_stream_writing *stream_writing;
178
Craig Tiller4aa71a12015-06-15 13:00:55 -0700179 while (
180 grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
Craig Tiller86316522015-07-15 11:35:07 -0700181 if (stream_writing->sopb.nops > 0 || stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
182 grpc_chttp2_encode(stream_writing->sopb.ops, stream_writing->sopb.nops,
183 stream_writing->send_closed != GRPC_DONT_SEND_CLOSED,
184 stream_writing->id, &transport_writing->hpack_compressor,
185 &transport_writing->outbuf);
186 }
187 if (stream_writing->announce_window > 0) {
188 gpr_slice_buffer_add(
189 &transport_writing->outbuf,
190 grpc_chttp2_window_update_create(
191 stream_writing->id, stream_writing->announce_window));
192 stream_writing->announce_window = 0;
193 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700194 stream_writing->sopb.nops = 0;
Craig Tillerab630732015-06-25 11:20:01 -0700195 if (stream_writing->send_closed == GRPC_SEND_CLOSED_WITH_RST_STREAM) {
Craig Tiller4aa71a12015-06-15 13:00:55 -0700196 gpr_slice_buffer_add(&transport_writing->outbuf,
197 grpc_chttp2_rst_stream_create(stream_writing->id,
198 GRPC_CHTTP2_NO_ERROR));
Craig Tillerd20efd22015-06-12 16:17:09 -0700199 }
200 grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
201 }
202}
203
204static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status) {
205 grpc_chttp2_transport_writing *transport_writing = tw;
Craig Tiller4aa71a12015-06-15 13:00:55 -0700206 grpc_chttp2_terminate_writing(transport_writing,
207 write_status == GRPC_ENDPOINT_CB_OK);
Craig Tillerd20efd22015-06-12 16:17:09 -0700208}
209
Craig Tiller4aa71a12015-06-15 13:00:55 -0700210void grpc_chttp2_cleanup_writing(
211 grpc_chttp2_transport_global *transport_global,
212 grpc_chttp2_transport_writing *transport_writing) {
Craig Tillerd20efd22015-06-12 16:17:09 -0700213 grpc_chttp2_stream_writing *stream_writing;
214 grpc_chttp2_stream_global *stream_global;
215
Craig Tiller4aa71a12015-06-15 13:00:55 -0700216 while (grpc_chttp2_list_pop_written_stream(
217 transport_global, transport_writing, &stream_global, &stream_writing)) {
Craig Tiller994c2622015-07-23 14:00:58 -0700218 GPR_ASSERT(stream_global->writing_now);
219 stream_global->writing_now = 0;
Craig Tiller5c517b12015-07-15 13:28:10 -0700220 if (stream_global->outgoing_sopb != NULL &&
221 stream_global->outgoing_sopb->nops == 0) {
Craig Tiller298b0b92015-07-07 12:44:22 -0700222 stream_global->outgoing_sopb = NULL;
223 grpc_chttp2_schedule_closure(transport_global,
224 stream_global->send_done_closure, 1);
225 }
Craig Tillerab630732015-06-25 11:20:01 -0700226 if (stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
227 stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE;
Craig Tiller3719f072015-06-12 17:19:51 -0700228 if (!transport_global->is_client) {
Craig Tillerd20efd22015-06-12 16:17:09 -0700229 stream_global->read_closed = 1;
Craig Tiller3208e392015-06-12 08:17:02 -0700230 }
Craig Tiller3208e392015-06-12 08:17:02 -0700231 }
Craig Tiller05cc0c42015-07-23 16:01:27 -0700232 grpc_chttp2_list_add_read_write_state_changed(transport_global,
233 stream_global);
Craig Tiller3208e392015-06-12 08:17:02 -0700234 }
Craig Tillerd20efd22015-06-12 16:17:09 -0700235 transport_writing->outbuf.count = 0;
236 transport_writing->outbuf.length = 0;
Craig Tiller3208e392015-06-12 08:17:02 -0700237}