blob: fc5e17d8fc9b47595322237c5ff623d20121e702 [file] [log] [blame]
Mark D. Roth8686cab2016-11-17 13:12:17 -08001/*
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. Roth412e6ac2016-12-01 08:24:45 -080034#include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
35
Mark D. Roth8686cab2016-11-17 13:12:17 -080036#include <grpc/grpc.h>
37
38#include <string.h>
39
40#include <grpc/slice_buffer.h>
41#include <grpc/support/alloc.h>
Mark D. Roth412e6ac2016-12-01 08:24:45 -080042#include <grpc/support/string_util.h>
Mark D. Roth8686cab2016-11-17 13:12:17 -080043
Mark D. Rotha5617852016-12-01 08:48:22 -080044#include "src/core/ext/client_channel/connector.h"
Mark D. Roth8686cab2016-11-17 13:12:17 -080045#include "src/core/ext/client_channel/http_connect_handshaker.h"
Mark D. Roth0748f392017-01-13 09:22:44 -080046#include "src/core/ext/client_channel/subchannel.h"
Mark D. Roth8686cab2016-11-17 13:12:17 -080047#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
Mark D. Roth8686cab2016-11-17 13:12:17 -080048#include "src/core/lib/channel/channel_args.h"
49#include "src/core/lib/channel/handshaker.h"
Mark D. Roth1f0f23c2017-01-06 13:07:19 -080050#include "src/core/lib/channel/handshaker_registry.h"
Mark D. Roth8686cab2016-11-17 13:12:17 -080051#include "src/core/lib/iomgr/tcp_client.h"
Craig Tiller6822a7a2016-12-06 19:28:52 -080052#include "src/core/lib/slice/slice_internal.h"
Mark D. Roth8686cab2016-11-17 13:12:17 -080053
54typedef struct {
55 grpc_connector base;
56
57 gpr_mu mu;
58 gpr_refcount refs;
59
60 bool shutdown;
Craig Tiller4ee9bb02016-12-05 15:37:47 -080061 bool connecting;
Mark D. Roth8686cab2016-11-17 13:12:17 -080062
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
76static void chttp2_connector_ref(grpc_connector *con) {
77 chttp2_connector *c = (chttp2_connector *)con;
78 gpr_ref(&c->refs);
79}
80
81static 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. Roth8686cab2016-11-17 13:12:17 -080087 // 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
94static void chttp2_connector_shutdown(grpc_exec_ctx *exec_ctx,
Craig Tillercda759d2017-01-27 11:37:37 -080095 grpc_connector *con, grpc_error *why) {
Mark D. Roth8686cab2016-11-17 13:12:17 -080096 chttp2_connector *c = (chttp2_connector *)con;
97 gpr_mu_lock(&c->mu);
98 c->shutdown = true;
Mark D. Roth412e6ac2016-12-01 08:24:45 -080099 if (c->handshake_mgr != NULL) {
Craig Tillercda759d2017-01-27 11:37:37 -0800100 grpc_handshake_manager_shutdown(exec_ctx, c->handshake_mgr,
101 GRPC_ERROR_REF(why));
Mark D. Roth412e6ac2016-12-01 08:24:45 -0800102 }
Mark D. Roth8686cab2016-11-17 13:12:17 -0800103 // If handshaking is not yet in progress, shutdown the endpoint.
104 // Otherwise, the handshaker will do this for us.
Craig Tiller4ee9bb02016-12-05 15:37:47 -0800105 if (!c->connecting && c->endpoint != NULL) {
Craig Tillercda759d2017-01-27 11:37:37 -0800106 grpc_endpoint_shutdown(exec_ctx, c->endpoint, GRPC_ERROR_REF(why));
Craig Tiller4ee9bb02016-12-05 15:37:47 -0800107 }
Mark D. Roth8686cab2016-11-17 13:12:17 -0800108 gpr_mu_unlock(&c->mu);
Craig Tillercda759d2017-01-27 11:37:37 -0800109 GRPC_ERROR_UNREF(why);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800110}
111
112static 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. Rothb62f3642016-11-30 11:41:25 -0800121 // 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 Tillercda759d2017-01-27 11:37:37 -0800126 grpc_endpoint_shutdown(exec_ctx, args->endpoint, GRPC_ERROR_REF(error));
Mark D. Rothb62f3642016-11-30 11:41:25 -0800127 grpc_endpoint_destroy(exec_ctx, args->endpoint);
Craig Tiller397bff32016-12-06 15:05:59 -0800128 grpc_channel_args_destroy(exec_ctx, args->args);
Craig Tiller6822a7a2016-12-06 19:28:52 -0800129 grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer);
Mark D. Rothb62f3642016-11-30 11:41:25 -0800130 gpr_free(args->read_buffer);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800131 } else {
132 error = GRPC_ERROR_REF(error);
133 }
134 memset(c->result, 0, sizeof(*c->result));
Mark D. Roth8686cab2016-11-17 13:12:17 -0800135 } 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 Tiller91031da2016-12-28 15:44:25 -0800145 grpc_closure_sched(exec_ctx, notify, error);
Mark D. Roth412e6ac2016-12-01 08:24:45 -0800146 grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr);
147 c->handshake_mgr = NULL;
Mark D. Roth8686cab2016-11-17 13:12:17 -0800148 gpr_mu_unlock(&c->mu);
Mark D. Rotha5617852016-12-01 08:48:22 -0800149 chttp2_connector_unref(exec_ctx, (grpc_connector *)c);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800150}
151
Mark D. Roth412e6ac2016-12-01 08:24:45 -0800152static void start_handshake_locked(grpc_exec_ctx *exec_ctx,
153 chttp2_connector *c) {
154 c->handshake_mgr = grpc_handshake_manager_create();
Mark D. Roth1f0f23c2017-01-06 13:07:19 -0800155 grpc_handshakers_add(exec_ctx, HANDSHAKER_CLIENT, c->args.channel_args,
Mark D. Roth65b79c82016-12-06 07:20:20 -0800156 c->handshake_mgr);
Mark D. Roth412e6ac2016-12-01 08:24:45 -0800157 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. Roth8686cab2016-11-17 13:12:17 -0800163static 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 Tiller91031da2016-12-28 15:44:25 -0800176 grpc_closure_sched(exec_ctx, notify, error);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800177 gpr_mu_unlock(&c->mu);
178 chttp2_connector_unref(exec_ctx, arg);
179 } else {
Mark D. Roth412e6ac2016-12-01 08:24:45 -0800180 start_handshake_locked(exec_ctx, c);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800181 gpr_mu_unlock(&c->mu);
182 }
183}
184
185static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
186 chttp2_connector *c = arg;
187 gpr_mu_lock(&c->mu);
Craig Tiller4ee9bb02016-12-05 15:37:47 -0800188 GPR_ASSERT(c->connecting);
189 c->connecting = false;
Mark D. Roth8686cab2016-11-17 13:12:17 -0800190 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 Tiller91031da2016-12-28 15:44:25 -0800199 grpc_closure_sched(exec_ctx, notify, error);
Craig Tillercda759d2017-01-27 11:37:37 -0800200 if (c->endpoint != NULL) {
201 grpc_endpoint_shutdown(exec_ctx, c->endpoint, GRPC_ERROR_REF(error));
202 }
Mark D. Roth8686cab2016-11-17 13:12:17 -0800203 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 Tiller91031da2016-12-28 15:44:25 -0800209 c, grpc_schedule_on_exec_ctx);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800210 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. Roth412e6ac2016-12-01 08:24:45 -0800216 start_handshake_locked(exec_ctx, c);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800217 }
218 gpr_mu_unlock(&c->mu);
219 }
220}
221
222static 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. Roth0748f392017-01-13 09:22:44 -0800228 grpc_resolved_address addr;
Mark D. Rothdf8f1222017-01-13 22:59:39 +0000229 grpc_get_subchannel_address_arg(args->channel_args, &addr);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800230 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 Tiller91031da2016-12-28 15:44:25 -0800237 grpc_closure_init(&c->connected, connected, c, grpc_schedule_on_exec_ctx);
Craig Tiller4ee9bb02016-12-05 15:37:47 -0800238 GPR_ASSERT(!c->connecting);
239 c->connecting = true;
Mark D. Roth8686cab2016-11-17 13:12:17 -0800240 grpc_tcp_client_connect(exec_ctx, &c->connected, &c->endpoint,
Mark D. Roth0748f392017-01-13 09:22:44 -0800241 args->interested_parties, args->channel_args, &addr,
242 args->deadline);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800243 gpr_mu_unlock(&c->mu);
244}
245
246static const grpc_connector_vtable chttp2_connector_vtable = {
247 chttp2_connector_ref, chttp2_connector_unref, chttp2_connector_shutdown,
248 chttp2_connector_connect};
249
Mark D. Roth1f0f23c2017-01-06 13:07:19 -0800250grpc_connector *grpc_chttp2_connector_create() {
Craig Tiller6f417882017-02-16 14:09:39 -0800251 chttp2_connector *c = gpr_zalloc(sizeof(*c));
Mark D. Roth8686cab2016-11-17 13:12:17 -0800252 c->base.vtable = &chttp2_connector_vtable;
253 gpr_mu_init(&c->mu);
254 gpr_ref_init(&c->refs, 1);
Mark D. Roth8686cab2016-11-17 13:12:17 -0800255 return &c->base;
256}