Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [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 | |
Mark D. Roth | 412e6ac | 2016-12-01 08:24:45 -0800 | [diff] [blame] | 34 | #include "src/core/ext/transport/chttp2/client/chttp2_connector.h" |
| 35 | |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 36 | #include <grpc/grpc.h> |
| 37 | |
| 38 | #include <string.h> |
| 39 | |
| 40 | #include <grpc/slice_buffer.h> |
| 41 | #include <grpc/support/alloc.h> |
Mark D. Roth | 412e6ac | 2016-12-01 08:24:45 -0800 | [diff] [blame] | 42 | #include <grpc/support/string_util.h> |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 43 | |
Mark D. Roth | a561785 | 2016-12-01 08:48:22 -0800 | [diff] [blame] | 44 | #include "src/core/ext/client_channel/connector.h" |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 45 | #include "src/core/ext/client_channel/http_connect_handshaker.h" |
Mark D. Roth | 0748f39 | 2017-01-13 09:22:44 -0800 | [diff] [blame] | 46 | #include "src/core/ext/client_channel/subchannel.h" |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 47 | #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 48 | #include "src/core/lib/channel/channel_args.h" |
| 49 | #include "src/core/lib/channel/handshaker.h" |
Mark D. Roth | 1f0f23c | 2017-01-06 13:07:19 -0800 | [diff] [blame] | 50 | #include "src/core/lib/channel/handshaker_registry.h" |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 51 | #include "src/core/lib/iomgr/tcp_client.h" |
Craig Tiller | 6822a7a | 2016-12-06 19:28:52 -0800 | [diff] [blame] | 52 | #include "src/core/lib/slice/slice_internal.h" |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 53 | |
| 54 | typedef struct { |
| 55 | grpc_connector base; |
| 56 | |
| 57 | gpr_mu mu; |
| 58 | gpr_refcount refs; |
| 59 | |
| 60 | bool shutdown; |
Craig Tiller | 4ee9bb0 | 2016-12-05 15:37:47 -0800 | [diff] [blame] | 61 | bool connecting; |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 62 | |
| 63 | grpc_closure *notify; |
| 64 | grpc_connect_in_args args; |
| 65 | grpc_connect_out_args *result; |
| 66 | grpc_closure initial_string_sent; |
| 67 | grpc_slice_buffer initial_string_buffer; |
| 68 | |
| 69 | grpc_endpoint *endpoint; // Non-NULL until handshaking starts. |
| 70 | |
| 71 | grpc_closure connected; |
| 72 | |
| 73 | grpc_handshake_manager *handshake_mgr; |
| 74 | } chttp2_connector; |
| 75 | |
| 76 | static void chttp2_connector_ref(grpc_connector *con) { |
| 77 | chttp2_connector *c = (chttp2_connector *)con; |
| 78 | gpr_ref(&c->refs); |
| 79 | } |
| 80 | |
| 81 | static void chttp2_connector_unref(grpc_exec_ctx *exec_ctx, |
| 82 | grpc_connector *con) { |
| 83 | chttp2_connector *c = (chttp2_connector *)con; |
| 84 | if (gpr_unref(&c->refs)) { |
| 85 | /* c->initial_string_buffer does not need to be destroyed */ |
| 86 | gpr_mu_destroy(&c->mu); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 87 | // If handshaking is not yet in progress, destroy the endpoint. |
| 88 | // Otherwise, the handshaker will do this for us. |
| 89 | if (c->endpoint != NULL) grpc_endpoint_destroy(exec_ctx, c->endpoint); |
| 90 | gpr_free(c); |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | static void chttp2_connector_shutdown(grpc_exec_ctx *exec_ctx, |
Craig Tiller | cda759d | 2017-01-27 11:37:37 -0800 | [diff] [blame] | 95 | grpc_connector *con, grpc_error *why) { |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 96 | chttp2_connector *c = (chttp2_connector *)con; |
| 97 | gpr_mu_lock(&c->mu); |
| 98 | c->shutdown = true; |
Mark D. Roth | 412e6ac | 2016-12-01 08:24:45 -0800 | [diff] [blame] | 99 | if (c->handshake_mgr != NULL) { |
Craig Tiller | cda759d | 2017-01-27 11:37:37 -0800 | [diff] [blame] | 100 | grpc_handshake_manager_shutdown(exec_ctx, c->handshake_mgr, |
| 101 | GRPC_ERROR_REF(why)); |
Mark D. Roth | 412e6ac | 2016-12-01 08:24:45 -0800 | [diff] [blame] | 102 | } |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 103 | // If handshaking is not yet in progress, shutdown the endpoint. |
| 104 | // Otherwise, the handshaker will do this for us. |
Craig Tiller | 4ee9bb0 | 2016-12-05 15:37:47 -0800 | [diff] [blame] | 105 | if (!c->connecting && c->endpoint != NULL) { |
Craig Tiller | cda759d | 2017-01-27 11:37:37 -0800 | [diff] [blame] | 106 | grpc_endpoint_shutdown(exec_ctx, c->endpoint, GRPC_ERROR_REF(why)); |
Craig Tiller | 4ee9bb0 | 2016-12-05 15:37:47 -0800 | [diff] [blame] | 107 | } |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 108 | gpr_mu_unlock(&c->mu); |
Craig Tiller | cda759d | 2017-01-27 11:37:37 -0800 | [diff] [blame] | 109 | GRPC_ERROR_UNREF(why); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, |
| 113 | grpc_error *error) { |
| 114 | grpc_handshaker_args *args = arg; |
| 115 | chttp2_connector *c = args->user_data; |
| 116 | gpr_mu_lock(&c->mu); |
| 117 | if (error != GRPC_ERROR_NONE || c->shutdown) { |
| 118 | if (error == GRPC_ERROR_NONE) { |
| 119 | error = GRPC_ERROR_CREATE("connector shutdown"); |
| 120 | // We were shut down after handshaking completed successfully, so |
Mark D. Roth | b62f364 | 2016-11-30 11:41:25 -0800 | [diff] [blame] | 121 | // destroy the endpoint here. |
| 122 | // TODO(ctiller): It is currently necessary to shutdown endpoints |
| 123 | // before destroying them, even if we know that there are no |
| 124 | // pending read/write callbacks. This should be fixed, at which |
| 125 | // point this can be removed. |
Craig Tiller | cda759d | 2017-01-27 11:37:37 -0800 | [diff] [blame] | 126 | grpc_endpoint_shutdown(exec_ctx, args->endpoint, GRPC_ERROR_REF(error)); |
Mark D. Roth | b62f364 | 2016-11-30 11:41:25 -0800 | [diff] [blame] | 127 | grpc_endpoint_destroy(exec_ctx, args->endpoint); |
Craig Tiller | 397bff3 | 2016-12-06 15:05:59 -0800 | [diff] [blame] | 128 | grpc_channel_args_destroy(exec_ctx, args->args); |
Craig Tiller | 6822a7a | 2016-12-06 19:28:52 -0800 | [diff] [blame] | 129 | grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer); |
Mark D. Roth | b62f364 | 2016-11-30 11:41:25 -0800 | [diff] [blame] | 130 | gpr_free(args->read_buffer); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 131 | } else { |
| 132 | error = GRPC_ERROR_REF(error); |
| 133 | } |
| 134 | memset(c->result, 0, sizeof(*c->result)); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 135 | } else { |
| 136 | c->result->transport = |
| 137 | grpc_create_chttp2_transport(exec_ctx, args->args, args->endpoint, 1); |
| 138 | GPR_ASSERT(c->result->transport); |
| 139 | grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, |
| 140 | args->read_buffer); |
| 141 | c->result->channel_args = args->args; |
| 142 | } |
| 143 | grpc_closure *notify = c->notify; |
| 144 | c->notify = NULL; |
Craig Tiller | 91031da | 2016-12-28 15:44:25 -0800 | [diff] [blame] | 145 | grpc_closure_sched(exec_ctx, notify, error); |
Mark D. Roth | 412e6ac | 2016-12-01 08:24:45 -0800 | [diff] [blame] | 146 | grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr); |
| 147 | c->handshake_mgr = NULL; |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 148 | gpr_mu_unlock(&c->mu); |
Mark D. Roth | a561785 | 2016-12-01 08:48:22 -0800 | [diff] [blame] | 149 | chttp2_connector_unref(exec_ctx, (grpc_connector *)c); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 150 | } |
| 151 | |
Mark D. Roth | 412e6ac | 2016-12-01 08:24:45 -0800 | [diff] [blame] | 152 | static void start_handshake_locked(grpc_exec_ctx *exec_ctx, |
| 153 | chttp2_connector *c) { |
| 154 | c->handshake_mgr = grpc_handshake_manager_create(); |
Mark D. Roth | 1f0f23c | 2017-01-06 13:07:19 -0800 | [diff] [blame] | 155 | grpc_handshakers_add(exec_ctx, HANDSHAKER_CLIENT, c->args.channel_args, |
Mark D. Roth | 65b79c8 | 2016-12-06 07:20:20 -0800 | [diff] [blame] | 156 | c->handshake_mgr); |
Mark D. Roth | 412e6ac | 2016-12-01 08:24:45 -0800 | [diff] [blame] | 157 | grpc_handshake_manager_do_handshake( |
| 158 | exec_ctx, c->handshake_mgr, c->endpoint, c->args.channel_args, |
| 159 | c->args.deadline, NULL /* acceptor */, on_handshake_done, c); |
| 160 | c->endpoint = NULL; // Endpoint handed off to handshake manager. |
| 161 | } |
| 162 | |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 163 | static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, |
| 164 | grpc_error *error) { |
| 165 | chttp2_connector *c = arg; |
| 166 | gpr_mu_lock(&c->mu); |
| 167 | if (error != GRPC_ERROR_NONE || c->shutdown) { |
| 168 | if (error == GRPC_ERROR_NONE) { |
| 169 | error = GRPC_ERROR_CREATE("connector shutdown"); |
| 170 | } else { |
| 171 | error = GRPC_ERROR_REF(error); |
| 172 | } |
| 173 | memset(c->result, 0, sizeof(*c->result)); |
| 174 | grpc_closure *notify = c->notify; |
| 175 | c->notify = NULL; |
Craig Tiller | 91031da | 2016-12-28 15:44:25 -0800 | [diff] [blame] | 176 | grpc_closure_sched(exec_ctx, notify, error); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 177 | gpr_mu_unlock(&c->mu); |
| 178 | chttp2_connector_unref(exec_ctx, arg); |
| 179 | } else { |
Mark D. Roth | 412e6ac | 2016-12-01 08:24:45 -0800 | [diff] [blame] | 180 | start_handshake_locked(exec_ctx, c); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 181 | gpr_mu_unlock(&c->mu); |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { |
| 186 | chttp2_connector *c = arg; |
| 187 | gpr_mu_lock(&c->mu); |
Craig Tiller | 4ee9bb0 | 2016-12-05 15:37:47 -0800 | [diff] [blame] | 188 | GPR_ASSERT(c->connecting); |
| 189 | c->connecting = false; |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 190 | if (error != GRPC_ERROR_NONE || c->shutdown) { |
| 191 | if (error == GRPC_ERROR_NONE) { |
| 192 | error = GRPC_ERROR_CREATE("connector shutdown"); |
| 193 | } else { |
| 194 | error = GRPC_ERROR_REF(error); |
| 195 | } |
| 196 | memset(c->result, 0, sizeof(*c->result)); |
| 197 | grpc_closure *notify = c->notify; |
| 198 | c->notify = NULL; |
Craig Tiller | 91031da | 2016-12-28 15:44:25 -0800 | [diff] [blame] | 199 | grpc_closure_sched(exec_ctx, notify, error); |
Craig Tiller | cda759d | 2017-01-27 11:37:37 -0800 | [diff] [blame] | 200 | if (c->endpoint != NULL) { |
| 201 | grpc_endpoint_shutdown(exec_ctx, c->endpoint, GRPC_ERROR_REF(error)); |
| 202 | } |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 203 | gpr_mu_unlock(&c->mu); |
| 204 | chttp2_connector_unref(exec_ctx, arg); |
| 205 | } else { |
| 206 | GPR_ASSERT(c->endpoint != NULL); |
| 207 | if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) { |
| 208 | grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent, |
Craig Tiller | 91031da | 2016-12-28 15:44:25 -0800 | [diff] [blame] | 209 | c, grpc_schedule_on_exec_ctx); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 210 | grpc_slice_buffer_init(&c->initial_string_buffer); |
| 211 | grpc_slice_buffer_add(&c->initial_string_buffer, |
| 212 | c->args.initial_connect_string); |
| 213 | grpc_endpoint_write(exec_ctx, c->endpoint, &c->initial_string_buffer, |
| 214 | &c->initial_string_sent); |
| 215 | } else { |
Mark D. Roth | 412e6ac | 2016-12-01 08:24:45 -0800 | [diff] [blame] | 216 | start_handshake_locked(exec_ctx, c); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 217 | } |
| 218 | gpr_mu_unlock(&c->mu); |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | static void chttp2_connector_connect(grpc_exec_ctx *exec_ctx, |
| 223 | grpc_connector *con, |
| 224 | const grpc_connect_in_args *args, |
| 225 | grpc_connect_out_args *result, |
| 226 | grpc_closure *notify) { |
| 227 | chttp2_connector *c = (chttp2_connector *)con; |
Mark D. Roth | 0748f39 | 2017-01-13 09:22:44 -0800 | [diff] [blame] | 228 | grpc_resolved_address addr; |
Mark D. Roth | df8f122 | 2017-01-13 22:59:39 +0000 | [diff] [blame] | 229 | grpc_get_subchannel_address_arg(args->channel_args, &addr); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 230 | gpr_mu_lock(&c->mu); |
| 231 | GPR_ASSERT(c->notify == NULL); |
| 232 | c->notify = notify; |
| 233 | c->args = *args; |
| 234 | c->result = result; |
| 235 | GPR_ASSERT(c->endpoint == NULL); |
| 236 | chttp2_connector_ref(con); // Ref taken for callback. |
Craig Tiller | 91031da | 2016-12-28 15:44:25 -0800 | [diff] [blame] | 237 | grpc_closure_init(&c->connected, connected, c, grpc_schedule_on_exec_ctx); |
Craig Tiller | 4ee9bb0 | 2016-12-05 15:37:47 -0800 | [diff] [blame] | 238 | GPR_ASSERT(!c->connecting); |
| 239 | c->connecting = true; |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 240 | grpc_tcp_client_connect(exec_ctx, &c->connected, &c->endpoint, |
Mark D. Roth | 0748f39 | 2017-01-13 09:22:44 -0800 | [diff] [blame] | 241 | args->interested_parties, args->channel_args, &addr, |
| 242 | args->deadline); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 243 | gpr_mu_unlock(&c->mu); |
| 244 | } |
| 245 | |
| 246 | static const grpc_connector_vtable chttp2_connector_vtable = { |
| 247 | chttp2_connector_ref, chttp2_connector_unref, chttp2_connector_shutdown, |
| 248 | chttp2_connector_connect}; |
| 249 | |
Mark D. Roth | 1f0f23c | 2017-01-06 13:07:19 -0800 | [diff] [blame] | 250 | grpc_connector *grpc_chttp2_connector_create() { |
Craig Tiller | 6f41788 | 2017-02-16 14:09:39 -0800 | [diff] [blame] | 251 | chttp2_connector *c = gpr_zalloc(sizeof(*c)); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 252 | c->base.vtable = &chttp2_connector_vtable; |
| 253 | gpr_mu_init(&c->mu); |
| 254 | gpr_ref_init(&c->refs, 1); |
Mark D. Roth | 8686cab | 2016-11-17 13:12:17 -0800 | [diff] [blame] | 255 | return &c->base; |
| 256 | } |