Craig Tiller | d8df50c | 2015-06-12 07:53:56 -0700 | [diff] [blame] | 1 | /* |
| 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 Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 35 | #include "src/core/transport/chttp2/http2_errors.h" |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 36 | |
| 37 | #include <grpc/support/log.h> |
| 38 | |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 39 | static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing); |
| 40 | static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status); |
| 41 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 42 | int grpc_chttp2_unlocking_check_writes( |
| 43 | grpc_chttp2_transport_global *transport_global, |
| 44 | grpc_chttp2_transport_writing *transport_writing) { |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 45 | grpc_chttp2_stream_global *stream_global; |
| 46 | grpc_chttp2_stream_writing *stream_writing; |
Craig Tiller | 994c262 | 2015-07-23 14:00:58 -0700 | [diff] [blame] | 47 | grpc_chttp2_stream_global *first_reinserted_stream = NULL; |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 48 | gpr_uint32 window_delta; |
| 49 | |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 50 | /* simple writes are queued to qbuf, and flushed here */ |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 51 | gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf); |
| 52 | GPR_ASSERT(transport_global->qbuf.count == 0); |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 53 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 54 | if (transport_global->dirtied_local_settings && |
| 55 | !transport_global->sent_local_settings) { |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 56 | gpr_slice_buffer_add( |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 57 | &transport_writing->outbuf, |
Craig Tiller | ab63073 | 2015-06-25 11:20:01 -0700 | [diff] [blame] | 58 | 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 Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 62 | transport_global->force_send_settings = 0; |
| 63 | transport_global->dirtied_local_settings = 0; |
| 64 | transport_global->sent_local_settings = 1; |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 65 | } |
| 66 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 67 | /* for each grpc_chttp2_stream that's become writable, frame it's data |
Craig Tiller | 994c262 | 2015-07-23 14:00:58 -0700 | [diff] [blame] | 68 | (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 Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 77 | |
Craig Tiller | 994c262 | 2015-07-23 14:00:58 -0700 | [diff] [blame] | 78 | stream_writing->id = stream_global->id; |
| 79 | stream_writing->send_closed = GRPC_DONT_SEND_CLOSED; |
Craig Tiller | 05cc0c4 | 2015-07-23 16:01:27 -0700 | [diff] [blame] | 80 | GPR_ASSERT(!stream_global->writing_now); |
Craig Tiller | 994c262 | 2015-07-23 14:00:58 -0700 | [diff] [blame] | 81 | |
| 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 Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 113 | } |
| 114 | } |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 115 | |
Craig Tiller | 27166a6 | 2015-07-05 21:08:33 -0700 | [diff] [blame] | 116 | if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) { |
Craig Tiller | 8631652 | 2015-07-15 11:35:07 -0700 | [diff] [blame] | 117 | stream_writing->announce_window = stream_global->unannounced_incoming_window; |
Craig Tiller | 285b882 | 2015-06-17 15:58:13 -0700 | [diff] [blame] | 118 | GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, |
Craig Tiller | 27166a6 | 2015-07-05 21:08:33 -0700 | [diff] [blame] | 119 | 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 Tiller | 285b882 | 2015-06-17 15:58:13 -0700 | [diff] [blame] | 124 | grpc_chttp2_list_add_incoming_window_updated(transport_global, |
| 125 | stream_global); |
Craig Tiller | 994c262 | 2015-07-23 14:00:58 -0700 | [diff] [blame] | 126 | 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 Tiller | 8631652 | 2015-07-15 11:35:07 -0700 | [diff] [blame] | 131 | grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 132 | } |
| 133 | } |
| 134 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 135 | /* if the grpc_chttp2_transport is ready to send a window update, do so here |
Craig Tiller | ab63073 | 2015-06-25 11:20:01 -0700 | [diff] [blame] | 136 | also; 3/4 is a magic number that will likely get tuned soon */ |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 137 | 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 Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 141 | gpr_slice_buffer_add(&transport_writing->outbuf, |
| 142 | grpc_chttp2_window_update_create(0, window_delta)); |
Craig Tiller | 285b882 | 2015-06-17 15:58:13 -0700 | [diff] [blame] | 143 | GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("write", transport_global, |
| 144 | incoming_window, window_delta); |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 145 | transport_global->incoming_window += window_delta; |
| 146 | } |
| 147 | |
Craig Tiller | cdf52bc | 2015-06-16 13:00:27 -0700 | [diff] [blame] | 148 | return transport_writing->outbuf.count > 0 || |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 149 | grpc_chttp2_list_have_writing_streams(transport_writing); |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 150 | } |
| 151 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 152 | void grpc_chttp2_perform_writes( |
| 153 | grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint) { |
Craig Tiller | 285b882 | 2015-06-17 15:58:13 -0700 | [diff] [blame] | 154 | GPR_ASSERT(transport_writing->outbuf.count > 0 || |
| 155 | grpc_chttp2_list_have_writing_streams(transport_writing)); |
Craig Tiller | cdf52bc | 2015-06-16 13:00:27 -0700 | [diff] [blame] | 156 | |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 157 | finalize_outbuf(transport_writing); |
| 158 | |
| 159 | GPR_ASSERT(transport_writing->outbuf.count > 0); |
Craig Tiller | c3fdaf9 | 2015-06-18 10:16:52 -0700 | [diff] [blame] | 160 | GPR_ASSERT(endpoint); |
Craig Tiller | f932fd5 | 2015-06-17 07:38:20 -0700 | [diff] [blame] | 161 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 162 | switch (grpc_endpoint_write(endpoint, transport_writing->outbuf.slices, |
| 163 | transport_writing->outbuf.count, finish_write_cb, |
| 164 | transport_writing)) { |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 165 | 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 | |
| 176 | static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) { |
| 177 | grpc_chttp2_stream_writing *stream_writing; |
| 178 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 179 | while ( |
| 180 | grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) { |
Craig Tiller | 8631652 | 2015-07-15 11:35:07 -0700 | [diff] [blame] | 181 | 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 Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 194 | stream_writing->sopb.nops = 0; |
Craig Tiller | ab63073 | 2015-06-25 11:20:01 -0700 | [diff] [blame] | 195 | if (stream_writing->send_closed == GRPC_SEND_CLOSED_WITH_RST_STREAM) { |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 196 | gpr_slice_buffer_add(&transport_writing->outbuf, |
| 197 | grpc_chttp2_rst_stream_create(stream_writing->id, |
| 198 | GRPC_CHTTP2_NO_ERROR)); |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 199 | } |
| 200 | grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status) { |
| 205 | grpc_chttp2_transport_writing *transport_writing = tw; |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 206 | grpc_chttp2_terminate_writing(transport_writing, |
| 207 | write_status == GRPC_ENDPOINT_CB_OK); |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 208 | } |
| 209 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 210 | void grpc_chttp2_cleanup_writing( |
| 211 | grpc_chttp2_transport_global *transport_global, |
| 212 | grpc_chttp2_transport_writing *transport_writing) { |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 213 | grpc_chttp2_stream_writing *stream_writing; |
| 214 | grpc_chttp2_stream_global *stream_global; |
| 215 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 216 | while (grpc_chttp2_list_pop_written_stream( |
| 217 | transport_global, transport_writing, &stream_global, &stream_writing)) { |
Craig Tiller | 994c262 | 2015-07-23 14:00:58 -0700 | [diff] [blame] | 218 | GPR_ASSERT(stream_global->writing_now); |
| 219 | stream_global->writing_now = 0; |
Craig Tiller | 5c517b1 | 2015-07-15 13:28:10 -0700 | [diff] [blame] | 220 | if (stream_global->outgoing_sopb != NULL && |
| 221 | stream_global->outgoing_sopb->nops == 0) { |
Craig Tiller | 298b0b9 | 2015-07-07 12:44:22 -0700 | [diff] [blame] | 222 | stream_global->outgoing_sopb = NULL; |
| 223 | grpc_chttp2_schedule_closure(transport_global, |
| 224 | stream_global->send_done_closure, 1); |
| 225 | } |
Craig Tiller | ab63073 | 2015-06-25 11:20:01 -0700 | [diff] [blame] | 226 | if (stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { |
| 227 | stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE; |
Craig Tiller | 3719f07 | 2015-06-12 17:19:51 -0700 | [diff] [blame] | 228 | if (!transport_global->is_client) { |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 229 | stream_global->read_closed = 1; |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 230 | } |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 231 | } |
Craig Tiller | 05cc0c4 | 2015-07-23 16:01:27 -0700 | [diff] [blame] | 232 | grpc_chttp2_list_add_read_write_state_changed(transport_global, |
| 233 | stream_global); |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 234 | } |
Craig Tiller | d20efd2 | 2015-06-12 16:17:09 -0700 | [diff] [blame] | 235 | transport_writing->outbuf.count = 0; |
| 236 | transport_writing->outbuf.length = 0; |
Craig Tiller | 3208e39 | 2015-06-12 08:17:02 -0700 | [diff] [blame] | 237 | } |