blob: fc8210569e8a0a2a161502aa2d9131c4f393b3b1 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080016 *
17 */
18
Yash Tibrewal37fdb732017-09-25 16:45:02 -070019#include <grpc/support/port_platform.h>
20
Craig Tiller9eb0fde2017-03-31 16:59:30 -070021#include "src/core/ext/filters/client_channel/client_channel.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080022
Yash Tibrewalfcd26bc2017-09-25 15:08:28 -070023#include <inttypes.h>
Mark D. Roth4c0fe492016-08-31 13:51:55 -070024#include <stdbool.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080025#include <stdio.h>
Craig Tillereb3b12e2015-06-26 14:42:49 -070026#include <string.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080027
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080028#include <grpc/support/alloc.h>
29#include <grpc/support/log.h>
Mark D. Rothb2d24882016-10-27 15:44:07 -070030#include <grpc/support/string_util.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080031#include <grpc/support/sync.h>
32#include <grpc/support/useful.h>
33
Yuchen Zeng0bad30a2017-10-05 21:47:39 -070034#include "src/core/ext/filters/client_channel/backup_poller.h"
Craig Tiller9eb0fde2017-03-31 16:59:30 -070035#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
36#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
37#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
38#include "src/core/ext/filters/client_channel/resolver_registry.h"
39#include "src/core/ext/filters/client_channel/retry_throttle.h"
40#include "src/core/ext/filters/client_channel/subchannel.h"
Craig Tiller3be7dd02017-04-03 14:30:03 -070041#include "src/core/ext/filters/deadline/deadline_filter.h"
Craig Tiller9533d042016-03-25 17:11:06 -070042#include "src/core/lib/channel/channel_args.h"
43#include "src/core/lib/channel/connected_channel.h"
Craig Tillerbefafe62017-02-09 11:30:54 -080044#include "src/core/lib/iomgr/combiner.h"
Craig Tiller9533d042016-03-25 17:11:06 -070045#include "src/core/lib/iomgr/iomgr.h"
Mark D. Roth4c0fe492016-08-31 13:51:55 -070046#include "src/core/lib/iomgr/polling_entity.h"
Craig Tiller9533d042016-03-25 17:11:06 -070047#include "src/core/lib/profiling/timers.h"
Craig Tiller7c70b6c2017-01-23 07:48:42 -080048#include "src/core/lib/slice/slice_internal.h"
Craig Tiller9533d042016-03-25 17:11:06 -070049#include "src/core/lib/support/string.h"
50#include "src/core/lib/surface/channel.h"
51#include "src/core/lib/transport/connectivity_state.h"
Mark D. Roth9fe284e2016-09-12 11:22:27 -070052#include "src/core/lib/transport/metadata.h"
53#include "src/core/lib/transport/metadata_batch.h"
Mark D. Rothea846a02016-11-03 11:32:54 -070054#include "src/core/lib/transport/service_config.h"
Mark D. Roth9fe284e2016-09-12 11:22:27 -070055#include "src/core/lib/transport/static_metadata.h"
Craig Tiller8910ac62015-10-08 16:49:15 -070056
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080057/* Client channel implementation */
58
Craig Tiller694580f2017-10-18 14:48:14 -070059grpc_core::TraceFlag grpc_client_channel_trace(false, "client_channel");
Mark D. Roth60751fe2017-07-07 12:50:33 -070060
Mark D. Roth26b7be42016-10-24 10:08:07 -070061/*************************************************************************
62 * METHOD-CONFIG TABLE
63 */
64
Mark D. Roth9d480942016-10-19 14:18:05 -070065typedef enum {
Craig Tiller7acc37e2017-02-28 10:01:37 -080066 /* zero so it can be default initialized */
67 WAIT_FOR_READY_UNSET = 0,
Mark D. Roth9d480942016-10-19 14:18:05 -070068 WAIT_FOR_READY_FALSE,
69 WAIT_FOR_READY_TRUE
70} wait_for_ready_value;
71
Mark D. Roth95b627b2017-02-24 11:02:58 -080072typedef struct {
73 gpr_refcount refs;
Craig Tiller89c14282017-07-19 15:32:27 -070074 grpc_millis timeout;
Mark D. Roth9d480942016-10-19 14:18:05 -070075 wait_for_ready_value wait_for_ready;
76} method_parameters;
77
Craig Tillerbaa14a92017-11-03 09:09:36 -070078static method_parameters* method_parameters_ref(
79 method_parameters* method_params) {
Mark D. Roth95b627b2017-02-24 11:02:58 -080080 gpr_ref(&method_params->refs);
81 return method_params;
Mark D. Roth9d480942016-10-19 14:18:05 -070082}
83
Craig Tillerbaa14a92017-11-03 09:09:36 -070084static void method_parameters_unref(method_parameters* method_params) {
Mark D. Roth95b627b2017-02-24 11:02:58 -080085 if (gpr_unref(&method_params->refs)) {
86 gpr_free(method_params);
87 }
88}
89
Mark D. Roth76d0ec42017-10-26 11:08:14 -070090// Wrappers to pass to grpc_service_config_create_method_config_table().
Craig Tillera64b2b12017-11-03 15:23:13 -070091static void* method_parameters_ref_wrapper(void* value) {
92 return method_parameters_ref((method_parameters*)value);
Mark D. Roth76d0ec42017-10-26 11:08:14 -070093}
Craig Tillera64b2b12017-11-03 15:23:13 -070094static void method_parameters_unref_wrapper(grpc_exec_ctx* exec_ctx,
95 void* value) {
Craig Tillerbaa14a92017-11-03 09:09:36 -070096 method_parameters_unref((method_parameters*)value);
Craig Tiller87a7e1f2016-11-09 09:42:19 -080097}
98
Craig Tillerbaa14a92017-11-03 09:09:36 -070099static bool parse_wait_for_ready(grpc_json* field,
100 wait_for_ready_value* wait_for_ready) {
Mark D. Roth95b627b2017-02-24 11:02:58 -0800101 if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
102 return false;
103 }
104 *wait_for_ready = field->type == GRPC_JSON_TRUE ? WAIT_FOR_READY_TRUE
105 : WAIT_FOR_READY_FALSE;
106 return true;
107}
108
Craig Tillerbaa14a92017-11-03 09:09:36 -0700109static bool parse_timeout(grpc_json* field, grpc_millis* timeout) {
Mark D. Roth95b627b2017-02-24 11:02:58 -0800110 if (field->type != GRPC_JSON_STRING) return false;
111 size_t len = strlen(field->value);
112 if (field->value[len - 1] != 's') return false;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700113 char* buf = gpr_strdup(field->value);
Mark D. Roth95b627b2017-02-24 11:02:58 -0800114 buf[len - 1] = '\0'; // Remove trailing 's'.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700115 char* decimal_point = strchr(buf, '.');
Craig Tiller89c14282017-07-19 15:32:27 -0700116 int nanos = 0;
Noah Eisen6870e6f2017-11-13 17:08:48 -0800117 if (decimal_point != nullptr) {
Mark D. Roth95b627b2017-02-24 11:02:58 -0800118 *decimal_point = '\0';
Craig Tiller89c14282017-07-19 15:32:27 -0700119 nanos = gpr_parse_nonnegative_int(decimal_point + 1);
120 if (nanos == -1) {
Mark D. Roth95b627b2017-02-24 11:02:58 -0800121 gpr_free(buf);
122 return false;
123 }
Mark D. Rotha2821462017-10-26 11:31:58 -0700124 int num_digits = (int)strlen(decimal_point + 1);
125 if (num_digits > 9) { // We don't accept greater precision than nanos.
126 gpr_free(buf);
127 return false;
Mark D. Roth95b627b2017-02-24 11:02:58 -0800128 }
Mark D. Rotha2821462017-10-26 11:31:58 -0700129 for (int i = 0; i < (9 - num_digits); ++i) {
130 nanos *= 10;
131 }
Mark D. Roth95b627b2017-02-24 11:02:58 -0800132 }
Mark D. Rotha2821462017-10-26 11:31:58 -0700133 int seconds = decimal_point == buf ? 0 : gpr_parse_nonnegative_int(buf);
Mark D. Roth95b627b2017-02-24 11:02:58 -0800134 gpr_free(buf);
Craig Tiller89c14282017-07-19 15:32:27 -0700135 if (seconds == -1) return false;
136 *timeout = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
Mark D. Roth95b627b2017-02-24 11:02:58 -0800137 return true;
138}
139
Craig Tillerbaa14a92017-11-03 09:09:36 -0700140static void* method_parameters_create_from_json(const grpc_json* json) {
Mark D. Rothc968e602016-11-02 14:07:36 -0700141 wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET;
Craig Tiller89c14282017-07-19 15:32:27 -0700142 grpc_millis timeout = 0;
Noah Eisen6870e6f2017-11-13 17:08:48 -0800143 for (grpc_json* field = json->child; field != nullptr; field = field->next) {
144 if (field->key == nullptr) continue;
Mark D. Roth84c8a022016-11-10 09:39:34 -0800145 if (strcmp(field->key, "waitForReady") == 0) {
Noah Eisen6870e6f2017-11-13 17:08:48 -0800146 if (wait_for_ready != WAIT_FOR_READY_UNSET) return nullptr; // Duplicate.
147 if (!parse_wait_for_ready(field, &wait_for_ready)) return nullptr;
Mark D. Rothc968e602016-11-02 14:07:36 -0700148 } else if (strcmp(field->key, "timeout") == 0) {
Noah Eisen6870e6f2017-11-13 17:08:48 -0800149 if (timeout > 0) return nullptr; // Duplicate.
150 if (!parse_timeout(field, &timeout)) return nullptr;
Mark D. Rothc968e602016-11-02 14:07:36 -0700151 }
152 }
Craig Tillerbaa14a92017-11-03 09:09:36 -0700153 method_parameters* value =
154 (method_parameters*)gpr_malloc(sizeof(method_parameters));
Mark D. Roth95b627b2017-02-24 11:02:58 -0800155 gpr_ref_init(&value->refs, 1);
Mark D. Rothc968e602016-11-02 14:07:36 -0700156 value->timeout = timeout;
157 value->wait_for_ready = wait_for_ready;
Mark D. Roth9d480942016-10-19 14:18:05 -0700158 return value;
159}
160
Alexander Polcync3b1f182017-04-18 13:51:36 -0700161struct external_connectivity_watcher;
162
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700163/*************************************************************************
164 * CHANNEL-WIDE FUNCTIONS
165 */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800166
Craig Tiller800dacb2015-10-06 09:10:26 -0700167typedef struct client_channel_channel_data {
Craig Tillerf5f17122015-06-25 08:47:26 -0700168 /** resolver for this channel */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700169 grpc_resolver* resolver;
Craig Tiller20a3c352015-08-05 08:39:50 -0700170 /** have we started resolving this channel */
Mark D. Roth4c0fe492016-08-31 13:51:55 -0700171 bool started_resolving;
Craig Tiller3be7dd02017-04-03 14:30:03 -0700172 /** is deadline checking enabled? */
173 bool deadline_checking_enabled;
Mark D. Roth0e48a9a2016-09-08 14:14:39 -0700174 /** client channel factory */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700175 grpc_client_channel_factory* client_channel_factory;
Craig Tillerf5f17122015-06-25 08:47:26 -0700176
Craig Tillerbefafe62017-02-09 11:30:54 -0800177 /** combiner protecting all variables below in this data structure */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700178 grpc_combiner* combiner;
Mark D. Roth046cf762016-09-26 11:13:51 -0700179 /** currently active load balancer */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700180 grpc_lb_policy* lb_policy;
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800181 /** retry throttle data */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700182 grpc_server_retry_throttle_data* retry_throttle_data;
Mark D. Roth9d480942016-10-19 14:18:05 -0700183 /** maps method names to method_parameters structs */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700184 grpc_slice_hash_table* method_params_table;
Mark D. Roth046cf762016-09-26 11:13:51 -0700185 /** incoming resolver result - set by resolver.next() */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700186 grpc_channel_args* resolver_result;
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700187 /** a list of closures that are all waiting for resolver result to come in */
188 grpc_closure_list waiting_for_resolver_result_closures;
Craig Tiller3f475422015-06-25 10:43:05 -0700189 /** resolver callback */
Mark D. Rothff4df062016-08-22 15:02:49 -0700190 grpc_closure on_resolver_result_changed;
Craig Tiller3f475422015-06-25 10:43:05 -0700191 /** connectivity state being tracked */
Craig Tillerca3e9d32015-06-27 18:37:27 -0700192 grpc_connectivity_state_tracker state_tracker;
Craig Tiller48cb07c2015-07-15 16:16:15 -0700193 /** when an lb_policy arrives, should we try to exit idle */
Mark D. Roth4c0fe492016-08-31 13:51:55 -0700194 bool exit_idle_when_lb_policy_arrives;
Craig Tiller906e3bc2015-11-24 07:31:31 -0800195 /** owning stack */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700196 grpc_channel_stack* owning_stack;
Craig Tiller69b093b2016-02-25 19:04:07 -0800197 /** interested parties (owned) */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700198 grpc_pollset_set* interested_parties;
Craig Tiller613dafa2017-02-09 12:00:43 -0800199
Alexander Polcync3b1f182017-04-18 13:51:36 -0700200 /* external_connectivity_watcher_list head is guarded by its own mutex, since
201 * counts need to be grabbed immediately without polling on a cq */
202 gpr_mu external_connectivity_watcher_list_mu;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700203 struct external_connectivity_watcher* external_connectivity_watcher_list_head;
Alexander Polcync3b1f182017-04-18 13:51:36 -0700204
Craig Tiller613dafa2017-02-09 12:00:43 -0800205 /* the following properties are guarded by a mutex since API's require them
Craig Tiller46dd7902017-02-23 09:42:16 -0800206 to be instantaneously available */
Craig Tiller613dafa2017-02-09 12:00:43 -0800207 gpr_mu info_mu;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700208 char* info_lb_policy_name;
Craig Tiller613dafa2017-02-09 12:00:43 -0800209 /** service config in JSON form */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700210 char* info_service_config_json;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800211} channel_data;
212
Juanli Shen592cf342017-12-04 20:52:01 -0800213typedef struct {
214 channel_data* chand;
215 /** used as an identifier, don't dereference it because the LB policy may be
216 * non-existing when the callback is run */
217 grpc_lb_policy* lb_policy;
218 grpc_closure closure;
219} reresolution_request_args;
220
Craig Tillerd6c98df2015-08-18 09:33:44 -0700221/** We create one watcher for each new lb_policy that is returned from a
Mark D. Roth4c0fe492016-08-31 13:51:55 -0700222 resolver, to watch for state changes from the lb_policy. When a state
223 change is seen, we update the channel, and create a new watcher. */
Craig Tillera82950e2015-09-22 12:33:20 -0700224typedef struct {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700225 channel_data* chand;
Craig Tiller33825112015-09-18 07:44:19 -0700226 grpc_closure on_changed;
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700227 grpc_connectivity_state state;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700228 grpc_lb_policy* lb_policy;
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700229} lb_policy_connectivity_watcher;
230
Craig Tillerbaa14a92017-11-03 09:09:36 -0700231static void watch_lb_policy_locked(grpc_exec_ctx* exec_ctx, channel_data* chand,
232 grpc_lb_policy* lb_policy,
Craig Tiller2400bf52017-02-09 16:25:19 -0800233 grpc_connectivity_state current_state);
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700234
Craig Tillerbaa14a92017-11-03 09:09:36 -0700235static void set_channel_connectivity_state_locked(grpc_exec_ctx* exec_ctx,
236 channel_data* chand,
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800237 grpc_connectivity_state state,
Craig Tillerbaa14a92017-11-03 09:09:36 -0700238 grpc_error* error,
239 const char* reason) {
David Garcia Quintas37251282017-04-14 13:46:03 -0700240 /* TODO: Improve failure handling:
241 * - Make it possible for policies to return GRPC_CHANNEL_TRANSIENT_FAILURE.
242 * - Hand over pending picks from old policies during the switch that happens
243 * when resolver provides an update. */
Noah Eisen6870e6f2017-11-13 17:08:48 -0800244 if (chand->lb_policy != nullptr) {
David Garcia Quintas956f7002017-04-13 15:40:06 -0700245 if (state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
246 /* cancel picks with wait_for_ready=false */
247 grpc_lb_policy_cancel_picks_locked(
248 exec_ctx, chand->lb_policy,
249 /* mask= */ GRPC_INITIAL_METADATA_WAIT_FOR_READY,
250 /* check= */ 0, GRPC_ERROR_REF(error));
251 } else if (state == GRPC_CHANNEL_SHUTDOWN) {
252 /* cancel all picks */
253 grpc_lb_policy_cancel_picks_locked(exec_ctx, chand->lb_policy,
254 /* mask= */ 0, /* check= */ 0,
255 GRPC_ERROR_REF(error));
256 }
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800257 }
Craig Tiller6014e8a2017-10-16 13:50:29 -0700258 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700259 gpr_log(GPR_DEBUG, "chand=%p: setting connectivity state to %s", chand,
260 grpc_connectivity_state_name(state));
261 }
Craig Tiller9ccf5f12016-05-07 21:41:01 -0700262 grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, error,
263 reason);
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800264}
265
Craig Tillerbaa14a92017-11-03 09:09:36 -0700266static void on_lb_policy_state_changed_locked(grpc_exec_ctx* exec_ctx,
267 void* arg, grpc_error* error) {
268 lb_policy_connectivity_watcher* w = (lb_policy_connectivity_watcher*)arg;
Craig Tillerc5de8352017-02-09 14:08:05 -0800269 /* check if the notification is for the latest policy */
270 if (w->lb_policy == w->chand->lb_policy) {
Craig Tiller6014e8a2017-10-16 13:50:29 -0700271 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700272 gpr_log(GPR_DEBUG, "chand=%p: lb_policy=%p state changed to %s", w->chand,
273 w->lb_policy, grpc_connectivity_state_name(w->state));
274 }
Juanli Shen592cf342017-12-04 20:52:01 -0800275 set_channel_connectivity_state_locked(exec_ctx, w->chand, w->state,
Craig Tillerc5de8352017-02-09 14:08:05 -0800276 GRPC_ERROR_REF(error), "lb_changed");
277 if (w->state != GRPC_CHANNEL_SHUTDOWN) {
Craig Tiller2400bf52017-02-09 16:25:19 -0800278 watch_lb_policy_locked(exec_ctx, w->chand, w->lb_policy, w->state);
Craig Tillerc5de8352017-02-09 14:08:05 -0800279 }
Craig Tillera82950e2015-09-22 12:33:20 -0700280 }
Craig Tiller906e3bc2015-11-24 07:31:31 -0800281 GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy");
Craig Tillera82950e2015-09-22 12:33:20 -0700282 gpr_free(w);
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700283}
284
Craig Tillerbaa14a92017-11-03 09:09:36 -0700285static void watch_lb_policy_locked(grpc_exec_ctx* exec_ctx, channel_data* chand,
286 grpc_lb_policy* lb_policy,
Craig Tiller2400bf52017-02-09 16:25:19 -0800287 grpc_connectivity_state current_state) {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700288 lb_policy_connectivity_watcher* w =
289 (lb_policy_connectivity_watcher*)gpr_malloc(sizeof(*w));
Craig Tiller906e3bc2015-11-24 07:31:31 -0800290 GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy");
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700291 w->chand = chand;
ncteisen274bbbe2017-06-08 14:57:11 -0700292 GRPC_CLOSURE_INIT(&w->on_changed, on_lb_policy_state_changed_locked, w,
Craig Tilleree4b1452017-05-12 10:56:03 -0700293 grpc_combiner_scheduler(chand->combiner));
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700294 w->state = current_state;
295 w->lb_policy = lb_policy;
Craig Tiller2400bf52017-02-09 16:25:19 -0800296 grpc_lb_policy_notify_on_state_change_locked(exec_ctx, lb_policy, &w->state,
297 &w->on_changed);
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700298}
299
Craig Tillerbaa14a92017-11-03 09:09:36 -0700300static void start_resolving_locked(grpc_exec_ctx* exec_ctx,
301 channel_data* chand) {
Craig Tiller6014e8a2017-10-16 13:50:29 -0700302 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700303 gpr_log(GPR_DEBUG, "chand=%p: starting name resolution", chand);
304 }
305 GPR_ASSERT(!chand->started_resolving);
306 chand->started_resolving = true;
307 GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
308 grpc_resolver_next_locked(exec_ctx, chand->resolver, &chand->resolver_result,
309 &chand->on_resolver_result_changed);
310}
311
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800312typedef struct {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700313 char* server_name;
314 grpc_server_retry_throttle_data* retry_throttle_data;
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800315} service_config_parsing_state;
316
Craig Tillerbaa14a92017-11-03 09:09:36 -0700317static void parse_retry_throttle_params(const grpc_json* field, void* arg) {
318 service_config_parsing_state* parsing_state =
319 (service_config_parsing_state*)arg;
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800320 if (strcmp(field->key, "retryThrottling") == 0) {
Noah Eisen6870e6f2017-11-13 17:08:48 -0800321 if (parsing_state->retry_throttle_data != nullptr) return; // Duplicate.
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800322 if (field->type != GRPC_JSON_OBJECT) return;
323 int max_milli_tokens = 0;
324 int milli_token_ratio = 0;
Noah Eisen6870e6f2017-11-13 17:08:48 -0800325 for (grpc_json* sub_field = field->child; sub_field != nullptr;
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800326 sub_field = sub_field->next) {
Noah Eisen6870e6f2017-11-13 17:08:48 -0800327 if (sub_field->key == nullptr) return;
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800328 if (strcmp(sub_field->key, "maxTokens") == 0) {
329 if (max_milli_tokens != 0) return; // Duplicate.
330 if (sub_field->type != GRPC_JSON_NUMBER) return;
331 max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value);
332 if (max_milli_tokens == -1) return;
333 max_milli_tokens *= 1000;
334 } else if (strcmp(sub_field->key, "tokenRatio") == 0) {
335 if (milli_token_ratio != 0) return; // Duplicate.
336 if (sub_field->type != GRPC_JSON_NUMBER) return;
337 // We support up to 3 decimal digits.
338 size_t whole_len = strlen(sub_field->value);
339 uint32_t multiplier = 1;
340 uint32_t decimal_value = 0;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700341 const char* decimal_point = strchr(sub_field->value, '.');
Noah Eisen6870e6f2017-11-13 17:08:48 -0800342 if (decimal_point != nullptr) {
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800343 whole_len = (size_t)(decimal_point - sub_field->value);
344 multiplier = 1000;
345 size_t decimal_len = strlen(decimal_point + 1);
346 if (decimal_len > 3) decimal_len = 3;
347 if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
348 &decimal_value)) {
349 return;
350 }
351 uint32_t decimal_multiplier = 1;
352 for (size_t i = 0; i < (3 - decimal_len); ++i) {
353 decimal_multiplier *= 10;
354 }
355 decimal_value *= decimal_multiplier;
356 }
357 uint32_t whole_value;
358 if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len,
359 &whole_value)) {
360 return;
361 }
362 milli_token_ratio = (int)((whole_value * multiplier) + decimal_value);
Mark D. Rothb3322562017-02-23 14:38:02 -0800363 if (milli_token_ratio <= 0) return;
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800364 }
365 }
366 parsing_state->retry_throttle_data =
367 grpc_retry_throttle_map_get_data_for_server(
368 parsing_state->server_name, max_milli_tokens, milli_token_ratio);
369 }
370}
371
Juanli Shen592cf342017-12-04 20:52:01 -0800372static void request_reresolution_locked(grpc_exec_ctx* exec_ctx, void* arg,
373 grpc_error* error) {
374 reresolution_request_args* args = (reresolution_request_args*)arg;
375 channel_data* chand = args->chand;
376 // If this invocation is for a stale LB policy, treat it as an LB shutdown
377 // signal.
378 if (args->lb_policy != chand->lb_policy || error != GRPC_ERROR_NONE ||
379 chand->resolver == nullptr) {
380 GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "re-resolution");
381 gpr_free(args);
382 return;
383 }
384 if (grpc_client_channel_trace.enabled()) {
385 gpr_log(GPR_DEBUG, "chand=%p: started name re-resolving", chand);
386 }
387 grpc_resolver_channel_saw_error_locked(exec_ctx, chand->resolver);
388 // Give back the closure to the LB policy.
389 grpc_lb_policy_set_reresolve_closure_locked(exec_ctx, chand->lb_policy,
390 &args->closure);
391}
392
Craig Tillerbaa14a92017-11-03 09:09:36 -0700393static void on_resolver_result_changed_locked(grpc_exec_ctx* exec_ctx,
394 void* arg, grpc_error* error) {
395 channel_data* chand = (channel_data*)arg;
Craig Tiller6014e8a2017-10-16 13:50:29 -0700396 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700397 gpr_log(GPR_DEBUG, "chand=%p: got resolver result: error=%s", chand,
398 grpc_error_string(error));
399 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700400 // Extract the following fields from the resolver result, if non-NULL.
Mark D. Roth15494b52017-07-12 15:26:55 -0700401 bool lb_policy_updated = false;
Noah Eisen6870e6f2017-11-13 17:08:48 -0800402 char* lb_policy_name_dup = nullptr;
Mark D. Roth60751fe2017-07-07 12:50:33 -0700403 bool lb_policy_name_changed = false;
Noah Eisen6870e6f2017-11-13 17:08:48 -0800404 grpc_lb_policy* new_lb_policy = nullptr;
405 char* service_config_json = nullptr;
406 grpc_server_retry_throttle_data* retry_throttle_data = nullptr;
407 grpc_slice_hash_table* method_params_table = nullptr;
408 if (chand->resolver_result != nullptr) {
Juanli Shen592cf342017-12-04 20:52:01 -0800409 if (chand->resolver != nullptr) {
410 // Find LB policy name.
411 const char* lb_policy_name = nullptr;
412 const grpc_arg* channel_arg = grpc_channel_args_find(
413 chand->resolver_result, GRPC_ARG_LB_POLICY_NAME);
414 if (channel_arg != nullptr) {
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800415 GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
Juanli Shen592cf342017-12-04 20:52:01 -0800416 lb_policy_name = channel_arg->value.string;
Mark D. Rothbdc58b22016-11-04 09:25:57 -0700417 }
Juanli Shen592cf342017-12-04 20:52:01 -0800418 // Special case: If at least one balancer address is present, we use
419 // the grpclb policy, regardless of what the resolver actually specified.
420 channel_arg =
421 grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
422 if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) {
423 grpc_lb_addresses* addresses =
424 (grpc_lb_addresses*)channel_arg->value.pointer.p;
425 bool found_balancer_address = false;
426 for (size_t i = 0; i < addresses->num_addresses; ++i) {
427 if (addresses->addresses[i].is_balancer) {
428 found_balancer_address = true;
429 break;
430 }
431 }
432 if (found_balancer_address) {
433 if (lb_policy_name != nullptr &&
434 strcmp(lb_policy_name, "grpclb") != 0) {
435 gpr_log(GPR_INFO,
436 "resolver requested LB policy %s but provided at least one "
437 "balancer address -- forcing use of grpclb LB policy",
438 lb_policy_name);
439 }
440 lb_policy_name = "grpclb";
441 }
442 }
443 // Use pick_first if nothing was specified and we didn't select grpclb
444 // above.
445 if (lb_policy_name == nullptr) lb_policy_name = "pick_first";
446 grpc_lb_policy_args lb_policy_args;
447 lb_policy_args.args = chand->resolver_result;
448 lb_policy_args.client_channel_factory = chand->client_channel_factory;
449 lb_policy_args.combiner = chand->combiner;
450 // Check to see if we're already using the right LB policy.
451 // Note: It's safe to use chand->info_lb_policy_name here without
452 // taking a lock on chand->info_mu, because this function is the
453 // only thing that modifies its value, and it can only be invoked
454 // once at any given time.
455 lb_policy_name_changed =
456 chand->info_lb_policy_name == nullptr ||
457 gpr_stricmp(chand->info_lb_policy_name, lb_policy_name) != 0;
458 if (chand->lb_policy != nullptr && !lb_policy_name_changed) {
459 // Continue using the same LB policy. Update with new addresses.
460 lb_policy_updated = true;
461 grpc_lb_policy_update_locked(exec_ctx, chand->lb_policy,
462 &lb_policy_args);
463 } else {
464 // Instantiate new LB policy.
465 new_lb_policy =
466 grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args);
467 if (new_lb_policy == nullptr) {
468 gpr_log(GPR_ERROR, "could not create LB policy \"%s\"",
469 lb_policy_name);
470 } else {
471 reresolution_request_args* args =
472 (reresolution_request_args*)gpr_zalloc(sizeof(*args));
473 args->chand = chand;
474 args->lb_policy = new_lb_policy;
475 GRPC_CLOSURE_INIT(&args->closure, request_reresolution_locked, args,
476 grpc_combiner_scheduler(chand->combiner));
477 GRPC_CHANNEL_STACK_REF(chand->owning_stack, "re-resolution");
478 grpc_lb_policy_set_reresolve_closure_locked(exec_ctx, new_lb_policy,
479 &args->closure);
480 }
481 }
482 // Find service config.
483 channel_arg = grpc_channel_args_find(chand->resolver_result,
484 GRPC_ARG_SERVICE_CONFIG);
485 if (channel_arg != nullptr) {
486 GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
487 service_config_json = gpr_strdup(channel_arg->value.string);
488 grpc_service_config* service_config =
489 grpc_service_config_create(service_config_json);
490 if (service_config != nullptr) {
491 channel_arg = grpc_channel_args_find(chand->resolver_result,
492 GRPC_ARG_SERVER_URI);
493 GPR_ASSERT(channel_arg != nullptr);
494 GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
495 grpc_uri* uri =
496 grpc_uri_parse(exec_ctx, channel_arg->value.string, true);
497 GPR_ASSERT(uri->path[0] != '\0');
498 service_config_parsing_state parsing_state;
499 memset(&parsing_state, 0, sizeof(parsing_state));
500 parsing_state.server_name =
501 uri->path[0] == '/' ? uri->path + 1 : uri->path;
502 grpc_service_config_parse_global_params(
503 service_config, parse_retry_throttle_params, &parsing_state);
504 grpc_uri_destroy(uri);
505 retry_throttle_data = parsing_state.retry_throttle_data;
506 method_params_table = grpc_service_config_create_method_config_table(
507 exec_ctx, service_config, method_parameters_create_from_json,
508 method_parameters_ref_wrapper, method_parameters_unref_wrapper);
509 grpc_service_config_destroy(service_config);
510 }
511 }
512 // Before we clean up, save a copy of lb_policy_name, since it might
513 // be pointing to data inside chand->resolver_result.
514 // The copy will be saved in chand->lb_policy_name below.
515 lb_policy_name_dup = gpr_strdup(lb_policy_name);
Mark D. Roth9fe284e2016-09-12 11:22:27 -0700516 }
Craig Tiller87a7e1f2016-11-09 09:42:19 -0800517 grpc_channel_args_destroy(exec_ctx, chand->resolver_result);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800518 chand->resolver_result = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -0700519 }
Craig Tiller6014e8a2017-10-16 13:50:29 -0700520 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700521 gpr_log(GPR_DEBUG,
522 "chand=%p: resolver result: lb_policy_name=\"%s\"%s, "
523 "service_config=\"%s\"",
Yash Tibrewal9eb86722017-09-17 23:43:30 -0700524 chand, lb_policy_name_dup,
525 lb_policy_name_changed ? " (changed)" : "", service_config_json);
Mark D. Roth60751fe2017-07-07 12:50:33 -0700526 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700527 // Now swap out fields in chand. Note that the new values may still
528 // be NULL if (e.g.) the resolver failed to return results or the
529 // results did not contain the necessary data.
530 //
531 // First, swap out the data used by cc_get_channel_info().
Craig Tiller613dafa2017-02-09 12:00:43 -0800532 gpr_mu_lock(&chand->info_mu);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800533 if (lb_policy_name_dup != nullptr) {
Craig Tiller613dafa2017-02-09 12:00:43 -0800534 gpr_free(chand->info_lb_policy_name);
Yash Tibrewal9eb86722017-09-17 23:43:30 -0700535 chand->info_lb_policy_name = lb_policy_name_dup;
Mark D. Rothb2d24882016-10-27 15:44:07 -0700536 }
Noah Eisen6870e6f2017-11-13 17:08:48 -0800537 if (service_config_json != nullptr) {
Craig Tiller613dafa2017-02-09 12:00:43 -0800538 gpr_free(chand->info_service_config_json);
539 chand->info_service_config_json = service_config_json;
Mark D. Rothc625c7a2016-11-09 14:12:37 -0800540 }
Craig Tiller613dafa2017-02-09 12:00:43 -0800541 gpr_mu_unlock(&chand->info_mu);
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700542 // Swap out the retry throttle data.
Noah Eisen6870e6f2017-11-13 17:08:48 -0800543 if (chand->retry_throttle_data != nullptr) {
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800544 grpc_server_retry_throttle_data_unref(chand->retry_throttle_data);
545 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700546 chand->retry_throttle_data = retry_throttle_data;
547 // Swap out the method params table.
Noah Eisen6870e6f2017-11-13 17:08:48 -0800548 if (chand->method_params_table != nullptr) {
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800549 grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
Mark D. Roth046cf762016-09-26 11:13:51 -0700550 }
Mark D. Roth9d480942016-10-19 14:18:05 -0700551 chand->method_params_table = method_params_table;
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700552 // If we have a new LB policy or are shutting down (in which case
Juanli Shen592cf342017-12-04 20:52:01 -0800553 // new_lb_policy will be NULL), swap out the LB policy, unreffing the old one
554 // and removing its fds from chand->interested_parties. Note that we do NOT do
555 // this if either (a) we updated the existing LB policy above or (b) we failed
556 // to create the new LB policy (in which case we want to continue using the
557 // most recent one we had).
Noah Eisen6870e6f2017-11-13 17:08:48 -0800558 if (new_lb_policy != nullptr || error != GRPC_ERROR_NONE ||
559 chand->resolver == nullptr) {
560 if (chand->lb_policy != nullptr) {
Craig Tiller6014e8a2017-10-16 13:50:29 -0700561 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700562 gpr_log(GPR_DEBUG, "chand=%p: unreffing lb_policy=%p", chand,
563 chand->lb_policy);
564 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700565 grpc_pollset_set_del_pollset_set(exec_ctx,
566 chand->lb_policy->interested_parties,
567 chand->interested_parties);
568 GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
Craig Tiller45724b32015-09-22 10:42:19 -0700569 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700570 chand->lb_policy = new_lb_policy;
571 }
572 // Now that we've swapped out the relevant fields of chand, check for
573 // error or shutdown.
Noah Eisen6870e6f2017-11-13 17:08:48 -0800574 if (error != GRPC_ERROR_NONE || chand->resolver == nullptr) {
Craig Tiller6014e8a2017-10-16 13:50:29 -0700575 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700576 gpr_log(GPR_DEBUG, "chand=%p: shutting down", chand);
577 }
Noah Eisen6870e6f2017-11-13 17:08:48 -0800578 if (chand->resolver != nullptr) {
Craig Tiller6014e8a2017-10-16 13:50:29 -0700579 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700580 gpr_log(GPR_DEBUG, "chand=%p: shutting down resolver", chand);
581 }
Craig Tiller972470b2017-02-09 15:05:36 -0800582 grpc_resolver_shutdown_locked(exec_ctx, chand->resolver);
Craig Tiller76a5c0e2016-03-09 09:05:30 -0800583 GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
Noah Eisen6870e6f2017-11-13 17:08:48 -0800584 chand->resolver = nullptr;
Craig Tiller76a5c0e2016-03-09 09:05:30 -0800585 }
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800586 set_channel_connectivity_state_locked(
Craig Tillerd925c932016-06-06 08:38:50 -0700587 exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
ncteisen4b36a3d2017-03-13 19:08:06 -0700588 GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700589 "Got resolver result after disconnection", &error, 1),
Craig Tiller804ff712016-05-05 16:25:40 -0700590 "resolver_gone");
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700591 GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver");
592 grpc_closure_list_fail_all(&chand->waiting_for_resolver_result_closures,
593 GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
594 "Channel disconnected", &error, 1));
595 GRPC_CLOSURE_LIST_SCHED(exec_ctx,
596 &chand->waiting_for_resolver_result_closures);
597 } else { // Not shutting down.
598 grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700599 grpc_error* state_error =
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700600 GRPC_ERROR_CREATE_FROM_STATIC_STRING("No load balancing policy");
Noah Eisen6870e6f2017-11-13 17:08:48 -0800601 if (new_lb_policy != nullptr) {
Craig Tiller6014e8a2017-10-16 13:50:29 -0700602 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700603 gpr_log(GPR_DEBUG, "chand=%p: initializing new LB policy", chand);
604 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700605 GRPC_ERROR_UNREF(state_error);
606 state = grpc_lb_policy_check_connectivity_locked(exec_ctx, new_lb_policy,
607 &state_error);
608 grpc_pollset_set_add_pollset_set(exec_ctx,
609 new_lb_policy->interested_parties,
610 chand->interested_parties);
611 GRPC_CLOSURE_LIST_SCHED(exec_ctx,
612 &chand->waiting_for_resolver_result_closures);
613 if (chand->exit_idle_when_lb_policy_arrives) {
614 grpc_lb_policy_exit_idle_locked(exec_ctx, new_lb_policy);
615 chand->exit_idle_when_lb_policy_arrives = false;
616 }
617 watch_lb_policy_locked(exec_ctx, chand, new_lb_policy, state);
618 }
Mark D. Roth15494b52017-07-12 15:26:55 -0700619 if (!lb_policy_updated) {
620 set_channel_connectivity_state_locked(exec_ctx, chand, state,
621 GRPC_ERROR_REF(state_error),
622 "new_lb+resolver");
623 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700624 grpc_resolver_next_locked(exec_ctx, chand->resolver,
625 &chand->resolver_result,
626 &chand->on_resolver_result_changed);
627 GRPC_ERROR_UNREF(state_error);
Craig Tillera82950e2015-09-22 12:33:20 -0700628 }
Craig Tiller3f475422015-06-25 10:43:05 -0700629}
630
Craig Tillerbaa14a92017-11-03 09:09:36 -0700631static void start_transport_op_locked(grpc_exec_ctx* exec_ctx, void* arg,
632 grpc_error* error_ignored) {
633 grpc_transport_op* op = (grpc_transport_op*)arg;
634 grpc_channel_element* elem =
635 (grpc_channel_element*)op->handler_private.extra_arg;
636 channel_data* chand = (channel_data*)elem->channel_data;
Craig Tiller000cd8f2015-09-18 07:20:29 -0700637
Noah Eisen6870e6f2017-11-13 17:08:48 -0800638 if (op->on_connectivity_state_change != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700639 grpc_connectivity_state_notify_on_state_change(
640 exec_ctx, &chand->state_tracker, op->connectivity_state,
641 op->on_connectivity_state_change);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800642 op->on_connectivity_state_change = nullptr;
643 op->connectivity_state = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -0700644 }
645
Yuchen Zengc272dd72017-12-05 12:18:34 -0800646 if (op->send_ping.on_initiate != nullptr || op->send_ping.on_ack != nullptr) {
Noah Eisen6870e6f2017-11-13 17:08:48 -0800647 if (chand->lb_policy == nullptr) {
ncteisen274bbbe2017-06-08 14:57:11 -0700648 GRPC_CLOSURE_SCHED(
Yuchen Zengc272dd72017-12-05 12:18:34 -0800649 exec_ctx, op->send_ping.on_initiate,
650 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Ping with no load balancing"));
651 GRPC_CLOSURE_SCHED(
652 exec_ctx, op->send_ping.on_ack,
ncteisen4b36a3d2017-03-13 19:08:06 -0700653 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Ping with no load balancing"));
Craig Tiller26dab312015-12-07 14:43:47 -0800654 } else {
Yuchen Zengc272dd72017-12-05 12:18:34 -0800655 grpc_lb_policy_ping_one_locked(exec_ctx, chand->lb_policy,
656 op->send_ping.on_initiate,
657 op->send_ping.on_ack);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800658 op->bind_pollset = nullptr;
Craig Tiller26dab312015-12-07 14:43:47 -0800659 }
Yuchen Zengc272dd72017-12-05 12:18:34 -0800660 op->send_ping.on_initiate = nullptr;
661 op->send_ping.on_ack = nullptr;
Craig Tiller26dab312015-12-07 14:43:47 -0800662 }
663
Craig Tiller1c51edc2016-05-07 16:18:43 -0700664 if (op->disconnect_with_error != GRPC_ERROR_NONE) {
Noah Eisen6870e6f2017-11-13 17:08:48 -0800665 if (chand->resolver != nullptr) {
Craig Tiller1c51edc2016-05-07 16:18:43 -0700666 set_channel_connectivity_state_locked(
Craig Tillerd925c932016-06-06 08:38:50 -0700667 exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
Craig Tiller1c51edc2016-05-07 16:18:43 -0700668 GRPC_ERROR_REF(op->disconnect_with_error), "disconnect");
Craig Tiller972470b2017-02-09 15:05:36 -0800669 grpc_resolver_shutdown_locked(exec_ctx, chand->resolver);
Craig Tiller1c51edc2016-05-07 16:18:43 -0700670 GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
Noah Eisen6870e6f2017-11-13 17:08:48 -0800671 chand->resolver = nullptr;
Craig Tiller1c51edc2016-05-07 16:18:43 -0700672 if (!chand->started_resolving) {
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700673 grpc_closure_list_fail_all(&chand->waiting_for_resolver_result_closures,
Craig Tiller1c51edc2016-05-07 16:18:43 -0700674 GRPC_ERROR_REF(op->disconnect_with_error));
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700675 GRPC_CLOSURE_LIST_SCHED(exec_ctx,
676 &chand->waiting_for_resolver_result_closures);
Craig Tiller1c51edc2016-05-07 16:18:43 -0700677 }
Noah Eisen6870e6f2017-11-13 17:08:48 -0800678 if (chand->lb_policy != nullptr) {
Craig Tiller1c51edc2016-05-07 16:18:43 -0700679 grpc_pollset_set_del_pollset_set(exec_ctx,
680 chand->lb_policy->interested_parties,
681 chand->interested_parties);
682 GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
Noah Eisen6870e6f2017-11-13 17:08:48 -0800683 chand->lb_policy = nullptr;
Craig Tiller1c51edc2016-05-07 16:18:43 -0700684 }
Craig Tillerb12d22a2016-04-23 12:50:21 -0700685 }
Craig Tiller1c51edc2016-05-07 16:18:43 -0700686 GRPC_ERROR_UNREF(op->disconnect_with_error);
Craig Tillera82950e2015-09-22 12:33:20 -0700687 }
Craig Tillerd2e5cfc2017-02-09 13:02:20 -0800688 GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "start_transport_op");
689
ncteisen274bbbe2017-06-08 14:57:11 -0700690 GRPC_CLOSURE_SCHED(exec_ctx, op->on_consumed, GRPC_ERROR_NONE);
Craig Tillerbefafe62017-02-09 11:30:54 -0800691}
692
Craig Tillerbaa14a92017-11-03 09:09:36 -0700693static void cc_start_transport_op(grpc_exec_ctx* exec_ctx,
694 grpc_channel_element* elem,
695 grpc_transport_op* op) {
696 channel_data* chand = (channel_data*)elem->channel_data;
Craig Tillerbefafe62017-02-09 11:30:54 -0800697
Craig Tillerbefafe62017-02-09 11:30:54 -0800698 GPR_ASSERT(op->set_accept_stream == false);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800699 if (op->bind_pollset != nullptr) {
Craig Tillerbefafe62017-02-09 11:30:54 -0800700 grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties,
701 op->bind_pollset);
702 }
703
Craig Tillerc55c1022017-03-10 10:26:42 -0800704 op->handler_private.extra_arg = elem;
Craig Tillerd2e5cfc2017-02-09 13:02:20 -0800705 GRPC_CHANNEL_STACK_REF(chand->owning_stack, "start_transport_op");
ncteisen274bbbe2017-06-08 14:57:11 -0700706 GRPC_CLOSURE_SCHED(
Craig Tillerc55c1022017-03-10 10:26:42 -0800707 exec_ctx,
ncteisen274bbbe2017-06-08 14:57:11 -0700708 GRPC_CLOSURE_INIT(&op->handler_private.closure, start_transport_op_locked,
Craig Tilleree4b1452017-05-12 10:56:03 -0700709 op, grpc_combiner_scheduler(chand->combiner)),
Craig Tillerbefafe62017-02-09 11:30:54 -0800710 GRPC_ERROR_NONE);
Craig Tillerca3e9d32015-06-27 18:37:27 -0700711}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800712
Craig Tillerbaa14a92017-11-03 09:09:36 -0700713static void cc_get_channel_info(grpc_exec_ctx* exec_ctx,
714 grpc_channel_element* elem,
715 const grpc_channel_info* info) {
716 channel_data* chand = (channel_data*)elem->channel_data;
Craig Tiller613dafa2017-02-09 12:00:43 -0800717 gpr_mu_lock(&chand->info_mu);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800718 if (info->lb_policy_name != nullptr) {
719 *info->lb_policy_name = chand->info_lb_policy_name == nullptr
720 ? nullptr
Craig Tiller613dafa2017-02-09 12:00:43 -0800721 : gpr_strdup(chand->info_lb_policy_name);
Mark D. Rothb2d24882016-10-27 15:44:07 -0700722 }
Noah Eisen6870e6f2017-11-13 17:08:48 -0800723 if (info->service_config_json != nullptr) {
Craig Tiller613dafa2017-02-09 12:00:43 -0800724 *info->service_config_json =
Noah Eisen6870e6f2017-11-13 17:08:48 -0800725 chand->info_service_config_json == nullptr
726 ? nullptr
Craig Tiller613dafa2017-02-09 12:00:43 -0800727 : gpr_strdup(chand->info_service_config_json);
Mark D. Rothc625c7a2016-11-09 14:12:37 -0800728 }
Craig Tiller613dafa2017-02-09 12:00:43 -0800729 gpr_mu_unlock(&chand->info_mu);
Mark D. Rothb2d24882016-10-27 15:44:07 -0700730}
731
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700732/* Constructor for channel_data */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700733static grpc_error* cc_init_channel_elem(grpc_exec_ctx* exec_ctx,
734 grpc_channel_element* elem,
735 grpc_channel_element_args* args) {
736 channel_data* chand = (channel_data*)elem->channel_data;
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700737 GPR_ASSERT(args->is_last);
738 GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
Mark D. Roth21d4b2d2016-11-18 09:53:41 -0800739 // Initialize data members.
Craig Tilleree4b1452017-05-12 10:56:03 -0700740 chand->combiner = grpc_combiner_create();
Craig Tillerd85477512017-02-09 12:02:39 -0800741 gpr_mu_init(&chand->info_mu);
Alexander Polcync3b1f182017-04-18 13:51:36 -0700742 gpr_mu_init(&chand->external_connectivity_watcher_list_mu);
743
744 gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800745 chand->external_connectivity_watcher_list_head = nullptr;
Alexander Polcync3b1f182017-04-18 13:51:36 -0700746 gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
747
Mark D. Roth21d4b2d2016-11-18 09:53:41 -0800748 chand->owning_stack = args->channel_stack;
ncteisen274bbbe2017-06-08 14:57:11 -0700749 GRPC_CLOSURE_INIT(&chand->on_resolver_result_changed,
Craig Tillerbefafe62017-02-09 11:30:54 -0800750 on_resolver_result_changed_locked, chand,
Craig Tilleree4b1452017-05-12 10:56:03 -0700751 grpc_combiner_scheduler(chand->combiner));
Mark D. Roth21d4b2d2016-11-18 09:53:41 -0800752 chand->interested_parties = grpc_pollset_set_create();
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700753 grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
754 "client_channel");
Yuchen Zeng6f9985e2017-10-10 19:00:01 -0700755 grpc_client_channel_start_backup_polling(exec_ctx, chand->interested_parties);
Mark D. Roth21d4b2d2016-11-18 09:53:41 -0800756 // Record client channel factory.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700757 const grpc_arg* arg = grpc_channel_args_find(args->channel_args,
Mark D. Roth21d4b2d2016-11-18 09:53:41 -0800758 GRPC_ARG_CLIENT_CHANNEL_FACTORY);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800759 if (arg == nullptr) {
David Garcia Quintas228a5142017-03-30 19:43:00 -0700760 return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
761 "Missing client channel factory in args for client channel filter");
762 }
763 if (arg->type != GRPC_ARG_POINTER) {
764 return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
765 "client channel factory arg must be a pointer");
766 }
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700767 grpc_client_channel_factory_ref(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700768 (grpc_client_channel_factory*)arg->value.pointer.p);
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700769 chand->client_channel_factory =
Craig Tillerbaa14a92017-11-03 09:09:36 -0700770 (grpc_client_channel_factory*)arg->value.pointer.p;
Mark D. Rothdc9bee72017-02-07 12:29:14 -0800771 // Get server name to resolve, using proxy mapper if needed.
Mark D. Roth86e90592016-11-18 09:56:40 -0800772 arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800773 if (arg == nullptr) {
David Garcia Quintas228a5142017-03-30 19:43:00 -0700774 return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
775 "Missing server uri in args for client channel filter");
776 }
777 if (arg->type != GRPC_ARG_STRING) {
778 return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
779 "server uri arg must be a string");
780 }
Noah Eisen6870e6f2017-11-13 17:08:48 -0800781 char* proxy_name = nullptr;
782 grpc_channel_args* new_args = nullptr;
Mark D. Rothdc9bee72017-02-07 12:29:14 -0800783 grpc_proxy_mappers_map_name(exec_ctx, arg->value.string, args->channel_args,
784 &proxy_name, &new_args);
785 // Instantiate resolver.
Mark D. Roth45ccec52017-01-18 14:04:01 -0800786 chand->resolver = grpc_resolver_create(
Noah Eisen6870e6f2017-11-13 17:08:48 -0800787 exec_ctx, proxy_name != nullptr ? proxy_name : arg->value.string,
788 new_args != nullptr ? new_args : args->channel_args,
Craig Tiller972470b2017-02-09 15:05:36 -0800789 chand->interested_parties, chand->combiner);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800790 if (proxy_name != nullptr) gpr_free(proxy_name);
791 if (new_args != nullptr) grpc_channel_args_destroy(exec_ctx, new_args);
792 if (chand->resolver == nullptr) {
ncteisen4b36a3d2017-03-13 19:08:06 -0700793 return GRPC_ERROR_CREATE_FROM_STATIC_STRING("resolver creation failed");
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800794 }
Craig Tiller3be7dd02017-04-03 14:30:03 -0700795 chand->deadline_checking_enabled =
796 grpc_deadline_checking_enabled(args->channel_args);
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800797 return GRPC_ERROR_NONE;
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700798}
799
Craig Tillerbaa14a92017-11-03 09:09:36 -0700800static void shutdown_resolver_locked(grpc_exec_ctx* exec_ctx, void* arg,
801 grpc_error* error) {
802 grpc_resolver* resolver = (grpc_resolver*)arg;
Craig Tiller972470b2017-02-09 15:05:36 -0800803 grpc_resolver_shutdown_locked(exec_ctx, resolver);
804 GRPC_RESOLVER_UNREF(exec_ctx, resolver, "channel");
805}
806
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700807/* Destructor for channel_data */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700808static void cc_destroy_channel_elem(grpc_exec_ctx* exec_ctx,
809 grpc_channel_element* elem) {
810 channel_data* chand = (channel_data*)elem->channel_data;
Noah Eisen6870e6f2017-11-13 17:08:48 -0800811 if (chand->resolver != nullptr) {
ncteisen274bbbe2017-06-08 14:57:11 -0700812 GRPC_CLOSURE_SCHED(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700813 exec_ctx,
814 GRPC_CLOSURE_CREATE(shutdown_resolver_locked, chand->resolver,
815 grpc_combiner_scheduler(chand->combiner)),
Craig Tiller972470b2017-02-09 15:05:36 -0800816 GRPC_ERROR_NONE);
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700817 }
Noah Eisen6870e6f2017-11-13 17:08:48 -0800818 if (chand->client_channel_factory != nullptr) {
Mark D. Roth0e48a9a2016-09-08 14:14:39 -0700819 grpc_client_channel_factory_unref(exec_ctx, chand->client_channel_factory);
820 }
Noah Eisen6870e6f2017-11-13 17:08:48 -0800821 if (chand->lb_policy != nullptr) {
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700822 grpc_pollset_set_del_pollset_set(exec_ctx,
823 chand->lb_policy->interested_parties,
824 chand->interested_parties);
825 GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
826 }
Craig Tiller613dafa2017-02-09 12:00:43 -0800827 gpr_free(chand->info_lb_policy_name);
828 gpr_free(chand->info_service_config_json);
Noah Eisen6870e6f2017-11-13 17:08:48 -0800829 if (chand->retry_throttle_data != nullptr) {
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800830 grpc_server_retry_throttle_data_unref(chand->retry_throttle_data);
831 }
Noah Eisen6870e6f2017-11-13 17:08:48 -0800832 if (chand->method_params_table != nullptr) {
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800833 grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
Mark D. Roth9fe284e2016-09-12 11:22:27 -0700834 }
Yuchen Zeng0bad30a2017-10-05 21:47:39 -0700835 grpc_client_channel_stop_backup_polling(exec_ctx, chand->interested_parties);
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700836 grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
Craig Tiller9e5ac1b2017-02-14 22:25:50 -0800837 grpc_pollset_set_destroy(exec_ctx, chand->interested_parties);
Craig Tillerf1021672017-02-09 21:29:50 -0800838 GRPC_COMBINER_UNREF(exec_ctx, chand->combiner, "client_channel");
Craig Tillerd85477512017-02-09 12:02:39 -0800839 gpr_mu_destroy(&chand->info_mu);
Alexander Polcync3b1f182017-04-18 13:51:36 -0700840 gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu);
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700841}
842
843/*************************************************************************
844 * PER-CALL FUNCTIONS
845 */
846
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700847// Max number of batches that can be pending on a call at any given
848// time. This includes:
849// recv_initial_metadata
850// send_initial_metadata
851// recv_message
852// send_message
853// recv_trailing_metadata
854// send_trailing_metadata
Mark D. Roth76e264b2017-08-25 09:03:33 -0700855// We also add room for a single cancel_stream batch.
856#define MAX_WAITING_BATCHES 7
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700857
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700858/** Call data. Holds a pointer to grpc_subchannel_call and the
859 associated machinery to create such a pointer.
860 Handles queueing of stream ops until a call object is ready, waiting
861 for initial metadata before trying to create a call object,
862 and handling cancellation gracefully. */
863typedef struct client_channel_call_data {
Mark D. Roth72f6da82016-09-02 13:42:38 -0700864 // State for handling deadlines.
865 // The code in deadline_filter.c requires this to be the first field.
Mark D. Roth72f6da82016-09-02 13:42:38 -0700866 // TODO(roth): This is slightly sub-optimal in that grpc_deadline_state
Mark D. Roth66f3d2b2017-09-01 09:02:17 -0700867 // and this struct both independently store pointers to the call stack
868 // and call combiner. If/when we have time, find a way to avoid this
869 // without breaking the grpc_deadline_state abstraction.
Mark D. Roth72f6da82016-09-02 13:42:38 -0700870 grpc_deadline_state deadline_state;
Mark D. Rothf28763c2016-09-14 15:18:40 -0700871
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800872 grpc_slice path; // Request path.
Mark D. Rothe40dd292016-10-05 14:58:37 -0700873 gpr_timespec call_start_time;
Craig Tiller89c14282017-07-19 15:32:27 -0700874 grpc_millis deadline;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700875 gpr_arena* arena;
876 grpc_call_stack* owning_call;
877 grpc_call_combiner* call_combiner;
Mark D. Roth76e264b2017-08-25 09:03:33 -0700878
Craig Tillerbaa14a92017-11-03 09:09:36 -0700879 grpc_server_retry_throttle_data* retry_throttle_data;
880 method_parameters* method_params;
Mark D. Rothaa850a72016-09-26 13:38:02 -0700881
Craig Tillerbaa14a92017-11-03 09:09:36 -0700882 grpc_subchannel_call* subchannel_call;
883 grpc_error* error;
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700884
Craig Tillerbaa14a92017-11-03 09:09:36 -0700885 grpc_lb_policy* lb_policy; // Holds ref while LB pick is pending.
Mark D. Roth60751fe2017-07-07 12:50:33 -0700886 grpc_closure lb_pick_closure;
Mark D. Roth66f3d2b2017-09-01 09:02:17 -0700887 grpc_closure lb_pick_cancel_closure;
Mark D. Roth60751fe2017-07-07 12:50:33 -0700888
Craig Tillerbaa14a92017-11-03 09:09:36 -0700889 grpc_connected_subchannel* connected_subchannel;
Mark D. Roth09e458c2017-05-02 08:13:26 -0700890 grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT];
Craig Tillerbaa14a92017-11-03 09:09:36 -0700891 grpc_polling_entity* pollent;
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700892
Craig Tillerbaa14a92017-11-03 09:09:36 -0700893 grpc_transport_stream_op_batch* waiting_for_pick_batches[MAX_WAITING_BATCHES];
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700894 size_t waiting_for_pick_batches_count;
Mark D. Roth76e264b2017-08-25 09:03:33 -0700895 grpc_closure handle_pending_batch_in_call_combiner[MAX_WAITING_BATCHES];
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700896
Craig Tillerbaa14a92017-11-03 09:09:36 -0700897 grpc_transport_stream_op_batch* initial_metadata_batch;
David Garcia Quintasd1a47f12016-09-02 12:46:44 +0200898
899 grpc_linked_mdelem lb_token_mdelem;
Mark D. Rothd6d192d2017-02-23 08:58:42 -0800900
901 grpc_closure on_complete;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700902 grpc_closure* original_on_complete;
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700903} call_data;
904
Craig Tillerbaa14a92017-11-03 09:09:36 -0700905grpc_subchannel_call* grpc_client_channel_get_subchannel_call(
906 grpc_call_element* elem) {
907 call_data* calld = (call_data*)elem->call_data;
Mark D. Roth76e264b2017-08-25 09:03:33 -0700908 return calld->subchannel_call;
Craig Tiller8b1d59c2016-12-27 15:15:30 -0800909}
910
Mark D. Roth76e264b2017-08-25 09:03:33 -0700911// This is called via the call combiner, so access to calld is synchronized.
912static void waiting_for_pick_batches_add(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700913 call_data* calld, grpc_transport_stream_op_batch* batch) {
Mark D. Roth76e264b2017-08-25 09:03:33 -0700914 if (batch->send_initial_metadata) {
Noah Eisen6870e6f2017-11-13 17:08:48 -0800915 GPR_ASSERT(calld->initial_metadata_batch == nullptr);
Mark D. Roth76e264b2017-08-25 09:03:33 -0700916 calld->initial_metadata_batch = batch;
917 } else {
918 GPR_ASSERT(calld->waiting_for_pick_batches_count < MAX_WAITING_BATCHES);
919 calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count++] =
920 batch;
921 }
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700922}
923
Mark D. Roth76e264b2017-08-25 09:03:33 -0700924// This is called via the call combiner, so access to calld is synchronized.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700925static void fail_pending_batch_in_call_combiner(grpc_exec_ctx* exec_ctx,
926 void* arg, grpc_error* error) {
927 call_data* calld = (call_data*)arg;
Mark D. Roth76e264b2017-08-25 09:03:33 -0700928 if (calld->waiting_for_pick_batches_count > 0) {
929 --calld->waiting_for_pick_batches_count;
930 grpc_transport_stream_op_batch_finish_with_failure(
931 exec_ctx,
932 calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count],
933 GRPC_ERROR_REF(error), calld->call_combiner);
934 }
935}
936
937// This is called via the call combiner, so access to calld is synchronized.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700938static void waiting_for_pick_batches_fail(grpc_exec_ctx* exec_ctx,
939 grpc_call_element* elem,
940 grpc_error* error) {
941 call_data* calld = (call_data*)elem->call_data;
Craig Tiller6014e8a2017-10-16 13:50:29 -0700942 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -0700943 gpr_log(GPR_DEBUG,
Mark D. Rothe9b10832017-10-26 13:18:25 -0700944 "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s",
Mark D. Roth60751fe2017-07-07 12:50:33 -0700945 elem->channel_data, calld, calld->waiting_for_pick_batches_count,
946 grpc_error_string(error));
947 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700948 for (size_t i = 0; i < calld->waiting_for_pick_batches_count; ++i) {
Mark D. Roth76e264b2017-08-25 09:03:33 -0700949 GRPC_CLOSURE_INIT(&calld->handle_pending_batch_in_call_combiner[i],
950 fail_pending_batch_in_call_combiner, calld,
951 grpc_schedule_on_exec_ctx);
952 GRPC_CALL_COMBINER_START(exec_ctx, calld->call_combiner,
953 &calld->handle_pending_batch_in_call_combiner[i],
954 GRPC_ERROR_REF(error),
955 "waiting_for_pick_batches_fail");
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700956 }
Noah Eisen6870e6f2017-11-13 17:08:48 -0800957 if (calld->initial_metadata_batch != nullptr) {
Mark D. Roth76e264b2017-08-25 09:03:33 -0700958 grpc_transport_stream_op_batch_finish_with_failure(
959 exec_ctx, calld->initial_metadata_batch, GRPC_ERROR_REF(error),
960 calld->call_combiner);
961 } else {
962 GRPC_CALL_COMBINER_STOP(exec_ctx, calld->call_combiner,
963 "waiting_for_pick_batches_fail");
964 }
Mark D. Roth2a5959f2016-09-01 08:20:27 -0700965 GRPC_ERROR_UNREF(error);
966}
967
Mark D. Roth76e264b2017-08-25 09:03:33 -0700968// This is called via the call combiner, so access to calld is synchronized.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700969static void run_pending_batch_in_call_combiner(grpc_exec_ctx* exec_ctx,
970 void* arg, grpc_error* ignored) {
971 call_data* calld = (call_data*)arg;
Mark D. Roth76e264b2017-08-25 09:03:33 -0700972 if (calld->waiting_for_pick_batches_count > 0) {
973 --calld->waiting_for_pick_batches_count;
974 grpc_subchannel_call_process_op(
975 exec_ctx, calld->subchannel_call,
976 calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count]);
Craig Tiller57726ca2016-09-12 11:59:45 -0700977 }
Mark D. Roth76e264b2017-08-25 09:03:33 -0700978}
979
980// This is called via the call combiner, so access to calld is synchronized.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700981static void waiting_for_pick_batches_resume(grpc_exec_ctx* exec_ctx,
982 grpc_call_element* elem) {
983 channel_data* chand = (channel_data*)elem->channel_data;
984 call_data* calld = (call_data*)elem->call_data;
Craig Tiller6014e8a2017-10-16 13:50:29 -0700985 if (grpc_client_channel_trace.enabled()) {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700986 gpr_log(GPR_DEBUG,
987 "chand=%p calld=%p: sending %" PRIuPTR
988 " pending batches to subchannel_call=%p",
Mark D. Roth76e264b2017-08-25 09:03:33 -0700989 chand, calld, calld->waiting_for_pick_batches_count,
990 calld->subchannel_call);
Mark D. Roth60751fe2017-07-07 12:50:33 -0700991 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -0700992 for (size_t i = 0; i < calld->waiting_for_pick_batches_count; ++i) {
Mark D. Roth76e264b2017-08-25 09:03:33 -0700993 GRPC_CLOSURE_INIT(&calld->handle_pending_batch_in_call_combiner[i],
994 run_pending_batch_in_call_combiner, calld,
995 grpc_schedule_on_exec_ctx);
996 GRPC_CALL_COMBINER_START(exec_ctx, calld->call_combiner,
997 &calld->handle_pending_batch_in_call_combiner[i],
998 GRPC_ERROR_NONE,
999 "waiting_for_pick_batches_resume");
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001000 }
Noah Eisen6870e6f2017-11-13 17:08:48 -08001001 GPR_ASSERT(calld->initial_metadata_batch != nullptr);
Mark D. Roth76e264b2017-08-25 09:03:33 -07001002 grpc_subchannel_call_process_op(exec_ctx, calld->subchannel_call,
1003 calld->initial_metadata_batch);
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001004}
1005
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001006// Applies service config to the call. Must be invoked once we know
1007// that the resolver has returned results to the channel.
Craig Tillerbaa14a92017-11-03 09:09:36 -07001008static void apply_service_config_to_call_locked(grpc_exec_ctx* exec_ctx,
1009 grpc_call_element* elem) {
1010 channel_data* chand = (channel_data*)elem->channel_data;
1011 call_data* calld = (call_data*)elem->call_data;
Craig Tiller6014e8a2017-10-16 13:50:29 -07001012 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -07001013 gpr_log(GPR_DEBUG, "chand=%p calld=%p: applying service config to call",
1014 chand, calld);
1015 }
Noah Eisen6870e6f2017-11-13 17:08:48 -08001016 if (chand->retry_throttle_data != nullptr) {
Mark D. Roth9ccbc4d2017-03-15 08:30:04 -07001017 calld->retry_throttle_data =
1018 grpc_server_retry_throttle_data_ref(chand->retry_throttle_data);
1019 }
Noah Eisen6870e6f2017-11-13 17:08:48 -08001020 if (chand->method_params_table != nullptr) {
Craig Tillerbaa14a92017-11-03 09:09:36 -07001021 calld->method_params = (method_parameters*)grpc_method_config_table_get(
Craig Tiller11c17d42017-03-13 13:36:34 -07001022 exec_ctx, chand->method_params_table, calld->path);
Noah Eisen6870e6f2017-11-13 17:08:48 -08001023 if (calld->method_params != nullptr) {
Craig Tiller11c17d42017-03-13 13:36:34 -07001024 method_parameters_ref(calld->method_params);
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001025 // If the deadline from the service config is shorter than the one
1026 // from the client API, reset the deadline timer.
1027 if (chand->deadline_checking_enabled &&
Craig Tiller89c14282017-07-19 15:32:27 -07001028 calld->method_params->timeout != 0) {
1029 const grpc_millis per_method_deadline =
Craig Tiller9a8c3f32017-07-21 13:14:14 -07001030 grpc_timespec_to_millis_round_up(calld->call_start_time) +
Craig Tiller89c14282017-07-19 15:32:27 -07001031 calld->method_params->timeout;
1032 if (per_method_deadline < calld->deadline) {
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001033 calld->deadline = per_method_deadline;
1034 grpc_deadline_state_reset(exec_ctx, elem, calld->deadline);
1035 }
Craig Tiller11c17d42017-03-13 13:36:34 -07001036 }
1037 }
1038 }
Craig Tiller11c17d42017-03-13 13:36:34 -07001039}
Craig Tillerea4a4f12017-03-13 13:36:52 -07001040
Craig Tillerbaa14a92017-11-03 09:09:36 -07001041static void create_subchannel_call_locked(grpc_exec_ctx* exec_ctx,
1042 grpc_call_element* elem,
1043 grpc_error* error) {
1044 channel_data* chand = (channel_data*)elem->channel_data;
1045 call_data* calld = (call_data*)elem->call_data;
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001046 const grpc_connected_subchannel_call_args call_args = {
Yash Tibrewald8b84a22017-09-25 13:38:03 -07001047 calld->pollent, // pollent
1048 calld->path, // path
1049 calld->call_start_time, // start_time
1050 calld->deadline, // deadline
1051 calld->arena, // arena
1052 calld->subchannel_call_context, // context
1053 calld->call_combiner // call_combiner
1054 };
Craig Tillerbaa14a92017-11-03 09:09:36 -07001055 grpc_error* new_error = grpc_connected_subchannel_create_call(
Mark D. Roth76e264b2017-08-25 09:03:33 -07001056 exec_ctx, calld->connected_subchannel, &call_args,
1057 &calld->subchannel_call);
Craig Tiller6014e8a2017-10-16 13:50:29 -07001058 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -07001059 gpr_log(GPR_DEBUG, "chand=%p calld=%p: create subchannel_call=%p: error=%s",
Mark D. Roth76e264b2017-08-25 09:03:33 -07001060 chand, calld, calld->subchannel_call, grpc_error_string(new_error));
Mark D. Roth60751fe2017-07-07 12:50:33 -07001061 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001062 if (new_error != GRPC_ERROR_NONE) {
1063 new_error = grpc_error_add_child(new_error, error);
Mark D. Roth76e264b2017-08-25 09:03:33 -07001064 waiting_for_pick_batches_fail(exec_ctx, elem, new_error);
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001065 } else {
Mark D. Roth76e264b2017-08-25 09:03:33 -07001066 waiting_for_pick_batches_resume(exec_ctx, elem);
Craig Tiller11c17d42017-03-13 13:36:34 -07001067 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001068 GRPC_ERROR_UNREF(error);
Craig Tiller11c17d42017-03-13 13:36:34 -07001069}
1070
Mark D. Rothb2929602017-09-11 09:31:11 -07001071// Invoked when a pick is completed, on both success or failure.
Craig Tillerbaa14a92017-11-03 09:09:36 -07001072static void pick_done_locked(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
1073 grpc_error* error) {
1074 call_data* calld = (call_data*)elem->call_data;
1075 channel_data* chand = (channel_data*)elem->channel_data;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001076 if (calld->connected_subchannel == nullptr) {
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001077 // Failed to create subchannel.
Mark D. Roth76e264b2017-08-25 09:03:33 -07001078 GRPC_ERROR_UNREF(calld->error);
1079 calld->error = error == GRPC_ERROR_NONE
1080 ? GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1081 "Call dropped by load balancing policy")
1082 : GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
1083 "Failed to create subchannel", &error, 1);
Craig Tiller6014e8a2017-10-16 13:50:29 -07001084 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -07001085 gpr_log(GPR_DEBUG,
1086 "chand=%p calld=%p: failed to create subchannel: error=%s", chand,
Mark D. Roth76e264b2017-08-25 09:03:33 -07001087 calld, grpc_error_string(calld->error));
Mark D. Roth60751fe2017-07-07 12:50:33 -07001088 }
Mark D. Roth76e264b2017-08-25 09:03:33 -07001089 waiting_for_pick_batches_fail(exec_ctx, elem, GRPC_ERROR_REF(calld->error));
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001090 } else {
Mark D. Roth9fe284e2016-09-12 11:22:27 -07001091 /* Create call on subchannel. */
Mark D. Roth60751fe2017-07-07 12:50:33 -07001092 create_subchannel_call_locked(exec_ctx, elem, GRPC_ERROR_REF(error));
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001093 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001094 GRPC_ERROR_UNREF(error);
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001095}
1096
Mark D. Rothb2929602017-09-11 09:31:11 -07001097// A wrapper around pick_done_locked() that is used in cases where
1098// either (a) the pick was deferred pending a resolver result or (b) the
1099// pick was done asynchronously. Removes the call's polling entity from
1100// chand->interested_parties before invoking pick_done_locked().
Craig Tillerbaa14a92017-11-03 09:09:36 -07001101static void async_pick_done_locked(grpc_exec_ctx* exec_ctx,
1102 grpc_call_element* elem, grpc_error* error) {
1103 channel_data* chand = (channel_data*)elem->channel_data;
1104 call_data* calld = (call_data*)elem->call_data;
Mark D. Rothb2929602017-09-11 09:31:11 -07001105 grpc_polling_entity_del_from_pollset_set(exec_ctx, calld->pollent,
1106 chand->interested_parties);
1107 pick_done_locked(exec_ctx, elem, error);
1108}
1109
1110// Note: This runs under the client_channel combiner, but will NOT be
1111// holding the call combiner.
Craig Tillerbaa14a92017-11-03 09:09:36 -07001112static void pick_callback_cancel_locked(grpc_exec_ctx* exec_ctx, void* arg,
1113 grpc_error* error) {
1114 grpc_call_element* elem = (grpc_call_element*)arg;
1115 channel_data* chand = (channel_data*)elem->channel_data;
1116 call_data* calld = (call_data*)elem->call_data;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001117 if (calld->lb_policy != nullptr) {
Craig Tiller6014e8a2017-10-16 13:50:29 -07001118 if (grpc_client_channel_trace.enabled()) {
Mark D. Rothb2929602017-09-11 09:31:11 -07001119 gpr_log(GPR_DEBUG, "chand=%p calld=%p: cancelling pick from LB policy %p",
1120 chand, calld, calld->lb_policy);
1121 }
1122 grpc_lb_policy_cancel_pick_locked(exec_ctx, calld->lb_policy,
1123 &calld->connected_subchannel,
1124 GRPC_ERROR_REF(error));
1125 }
1126 GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_callback_cancel");
1127}
1128
1129// Callback invoked by grpc_lb_policy_pick_locked() for async picks.
1130// Unrefs the LB policy and invokes async_pick_done_locked().
Craig Tillerbaa14a92017-11-03 09:09:36 -07001131static void pick_callback_done_locked(grpc_exec_ctx* exec_ctx, void* arg,
1132 grpc_error* error) {
1133 grpc_call_element* elem = (grpc_call_element*)arg;
1134 channel_data* chand = (channel_data*)elem->channel_data;
1135 call_data* calld = (call_data*)elem->call_data;
Craig Tiller6014e8a2017-10-16 13:50:29 -07001136 if (grpc_client_channel_trace.enabled()) {
Mark D. Rothb2929602017-09-11 09:31:11 -07001137 gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed asynchronously",
1138 chand, calld);
1139 }
Noah Eisen6870e6f2017-11-13 17:08:48 -08001140 GPR_ASSERT(calld->lb_policy != nullptr);
Mark D. Rothb2929602017-09-11 09:31:11 -07001141 GRPC_LB_POLICY_UNREF(exec_ctx, calld->lb_policy, "pick_subchannel");
Noah Eisen6870e6f2017-11-13 17:08:48 -08001142 calld->lb_policy = nullptr;
Mark D. Rothb2929602017-09-11 09:31:11 -07001143 async_pick_done_locked(exec_ctx, elem, GRPC_ERROR_REF(error));
1144}
1145
1146// Takes a ref to chand->lb_policy and calls grpc_lb_policy_pick_locked().
1147// If the pick was completed synchronously, unrefs the LB policy and
1148// returns true.
Craig Tillerbaa14a92017-11-03 09:09:36 -07001149static bool pick_callback_start_locked(grpc_exec_ctx* exec_ctx,
1150 grpc_call_element* elem) {
1151 channel_data* chand = (channel_data*)elem->channel_data;
1152 call_data* calld = (call_data*)elem->call_data;
Craig Tiller6014e8a2017-10-16 13:50:29 -07001153 if (grpc_client_channel_trace.enabled()) {
Mark D. Rothb2929602017-09-11 09:31:11 -07001154 gpr_log(GPR_DEBUG, "chand=%p calld=%p: starting pick on lb_policy=%p",
1155 chand, calld, chand->lb_policy);
1156 }
1157 apply_service_config_to_call_locked(exec_ctx, elem);
1158 // If the application explicitly set wait_for_ready, use that.
1159 // Otherwise, if the service config specified a value for this
1160 // method, use that.
1161 uint32_t initial_metadata_flags =
1162 calld->initial_metadata_batch->payload->send_initial_metadata
1163 .send_initial_metadata_flags;
1164 const bool wait_for_ready_set_from_api =
1165 initial_metadata_flags &
1166 GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET;
1167 const bool wait_for_ready_set_from_service_config =
Noah Eisen6870e6f2017-11-13 17:08:48 -08001168 calld->method_params != nullptr &&
Mark D. Rothb2929602017-09-11 09:31:11 -07001169 calld->method_params->wait_for_ready != WAIT_FOR_READY_UNSET;
1170 if (!wait_for_ready_set_from_api && wait_for_ready_set_from_service_config) {
1171 if (calld->method_params->wait_for_ready == WAIT_FOR_READY_TRUE) {
1172 initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY;
1173 } else {
1174 initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY;
1175 }
1176 }
1177 const grpc_lb_policy_pick_args inputs = {
1178 calld->initial_metadata_batch->payload->send_initial_metadata
1179 .send_initial_metadata,
1180 initial_metadata_flags, &calld->lb_token_mdelem};
1181 // Keep a ref to the LB policy in calld while the pick is pending.
1182 GRPC_LB_POLICY_REF(chand->lb_policy, "pick_subchannel");
1183 calld->lb_policy = chand->lb_policy;
1184 GRPC_CLOSURE_INIT(&calld->lb_pick_closure, pick_callback_done_locked, elem,
1185 grpc_combiner_scheduler(chand->combiner));
1186 const bool pick_done = grpc_lb_policy_pick_locked(
1187 exec_ctx, chand->lb_policy, &inputs, &calld->connected_subchannel,
Noah Eisen6870e6f2017-11-13 17:08:48 -08001188 calld->subchannel_call_context, nullptr, &calld->lb_pick_closure);
Mark D. Rothb2929602017-09-11 09:31:11 -07001189 if (pick_done) {
1190 /* synchronous grpc_lb_policy_pick call. Unref the LB policy. */
Craig Tiller6014e8a2017-10-16 13:50:29 -07001191 if (grpc_client_channel_trace.enabled()) {
Mark D. Rothb2929602017-09-11 09:31:11 -07001192 gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed synchronously",
1193 chand, calld);
1194 }
1195 GRPC_LB_POLICY_UNREF(exec_ctx, calld->lb_policy, "pick_subchannel");
Noah Eisen6870e6f2017-11-13 17:08:48 -08001196 calld->lb_policy = nullptr;
Mark D. Rothb2929602017-09-11 09:31:11 -07001197 } else {
1198 GRPC_CALL_STACK_REF(calld->owning_call, "pick_callback_cancel");
1199 grpc_call_combiner_set_notify_on_cancel(
1200 exec_ctx, calld->call_combiner,
1201 GRPC_CLOSURE_INIT(&calld->lb_pick_cancel_closure,
1202 pick_callback_cancel_locked, elem,
1203 grpc_combiner_scheduler(chand->combiner)));
1204 }
1205 return pick_done;
1206}
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001207
Craig Tiller577c9b22015-11-02 14:11:15 -08001208typedef struct {
Craig Tillerbaa14a92017-11-03 09:09:36 -07001209 grpc_call_element* elem;
Mark D. Roth66f3d2b2017-09-01 09:02:17 -07001210 bool finished;
Craig Tiller577c9b22015-11-02 14:11:15 -08001211 grpc_closure closure;
Mark D. Roth66f3d2b2017-09-01 09:02:17 -07001212 grpc_closure cancel_closure;
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001213} pick_after_resolver_result_args;
Craig Tiller577c9b22015-11-02 14:11:15 -08001214
Mark D. Roth76e264b2017-08-25 09:03:33 -07001215// Note: This runs under the client_channel combiner, but will NOT be
1216// holding the call combiner.
Craig Tillerbaa14a92017-11-03 09:09:36 -07001217static void pick_after_resolver_result_cancel_locked(grpc_exec_ctx* exec_ctx,
1218 void* arg,
1219 grpc_error* error) {
1220 pick_after_resolver_result_args* args = (pick_after_resolver_result_args*)arg;
Mark D. Roth66f3d2b2017-09-01 09:02:17 -07001221 if (args->finished) {
1222 gpr_free(args);
Mark D. Rothb2b9a0f2017-09-01 09:06:47 -07001223 return;
Mark D. Roth764cf042017-09-01 09:00:06 -07001224 }
Mark D. Roth76e264b2017-08-25 09:03:33 -07001225 // If we don't yet have a resolver result, then a closure for
1226 // pick_after_resolver_result_done_locked() will have been added to
1227 // chand->waiting_for_resolver_result_closures, and it may not be invoked
1228 // until after this call has been destroyed. We mark the operation as
Mark D. Rothb2b9a0f2017-09-01 09:06:47 -07001229 // finished, so that when pick_after_resolver_result_done_locked()
Mark D. Roth76e264b2017-08-25 09:03:33 -07001230 // is called, it will be a no-op. We also immediately invoke
Mark D. Rothb2929602017-09-11 09:31:11 -07001231 // async_pick_done_locked() to propagate the error back to the caller.
1232 args->finished = true;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001233 grpc_call_element* elem = args->elem;
1234 channel_data* chand = (channel_data*)elem->channel_data;
1235 call_data* calld = (call_data*)elem->call_data;
Craig Tiller6014e8a2017-10-16 13:50:29 -07001236 if (grpc_client_channel_trace.enabled()) {
Mark D. Rothb2b9a0f2017-09-01 09:06:47 -07001237 gpr_log(GPR_DEBUG,
1238 "chand=%p calld=%p: cancelling pick waiting for resolver result",
1239 chand, calld);
Mark D. Roth76e264b2017-08-25 09:03:33 -07001240 }
Mark D. Rothb2b9a0f2017-09-01 09:06:47 -07001241 // Note: Although we are not in the call combiner here, we are
1242 // basically stealing the call combiner from the pending pick, so
Mark D. Rothb2929602017-09-11 09:31:11 -07001243 // it's safe to call async_pick_done_locked() here -- we are
Mark D. Rothb2b9a0f2017-09-01 09:06:47 -07001244 // essentially calling it here instead of calling it in
1245 // pick_after_resolver_result_done_locked().
Mark D. Rothb2929602017-09-11 09:31:11 -07001246 async_pick_done_locked(exec_ctx, elem,
1247 GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
1248 "Pick cancelled", &error, 1));
Mark D. Roth76e264b2017-08-25 09:03:33 -07001249}
1250
Craig Tillerbaa14a92017-11-03 09:09:36 -07001251static void pick_after_resolver_result_start_locked(grpc_exec_ctx* exec_ctx,
1252 grpc_call_element* elem);
Mark D. Roth48be9de2017-10-23 12:27:37 -07001253
Craig Tillerbaa14a92017-11-03 09:09:36 -07001254static void pick_after_resolver_result_done_locked(grpc_exec_ctx* exec_ctx,
1255 void* arg,
1256 grpc_error* error) {
1257 pick_after_resolver_result_args* args = (pick_after_resolver_result_args*)arg;
Mark D. Roth66f3d2b2017-09-01 09:02:17 -07001258 if (args->finished) {
Craig Tiller577c9b22015-11-02 14:11:15 -08001259 /* cancelled, do nothing */
Craig Tiller6014e8a2017-10-16 13:50:29 -07001260 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -07001261 gpr_log(GPR_DEBUG, "call cancelled before resolver result");
1262 }
Mark D. Roth66f3d2b2017-09-01 09:02:17 -07001263 gpr_free(args);
Mark D. Rothb2b9a0f2017-09-01 09:06:47 -07001264 return;
1265 }
1266 args->finished = true;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001267 grpc_call_element* elem = args->elem;
1268 channel_data* chand = (channel_data*)elem->channel_data;
1269 call_data* calld = (call_data*)elem->call_data;
Mark D. Rothb2b9a0f2017-09-01 09:06:47 -07001270 if (error != GRPC_ERROR_NONE) {
Craig Tiller6014e8a2017-10-16 13:50:29 -07001271 if (grpc_client_channel_trace.enabled()) {
Mark D. Rothb2b9a0f2017-09-01 09:06:47 -07001272 gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver failed to return data",
1273 chand, calld);
1274 }
Mark D. Rothb2929602017-09-11 09:31:11 -07001275 async_pick_done_locked(exec_ctx, elem, GRPC_ERROR_REF(error));
Noah Eisen6870e6f2017-11-13 17:08:48 -08001276 } else if (chand->lb_policy != nullptr) {
Craig Tiller6014e8a2017-10-16 13:50:29 -07001277 if (grpc_client_channel_trace.enabled()) {
Mark D. Rothb2b9a0f2017-09-01 09:06:47 -07001278 gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver returned, doing pick",
1279 chand, calld);
1280 }
Mark D. Rothb2929602017-09-11 09:31:11 -07001281 if (pick_callback_start_locked(exec_ctx, elem)) {
1282 // Even if the LB policy returns a result synchronously, we have
1283 // already added our polling entity to chand->interested_parties
1284 // in order to wait for the resolver result, so we need to
1285 // remove it here. Therefore, we call async_pick_done_locked()
1286 // instead of pick_done_locked().
1287 async_pick_done_locked(exec_ctx, elem, GRPC_ERROR_NONE);
Mark D. Roth9dab7d52016-10-07 07:48:03 -07001288 }
Craig Tiller577c9b22015-11-02 14:11:15 -08001289 }
Mark D. Roth48be9de2017-10-23 12:27:37 -07001290 // TODO(roth): It should be impossible for chand->lb_policy to be NULL
1291 // here, so the rest of this code should never actually be executed.
1292 // However, we have reports of a crash on iOS that triggers this case,
1293 // so we are temporarily adding this to restore branches that were
1294 // removed in https://github.com/grpc/grpc/pull/12297. Need to figure
1295 // out what is actually causing this to occur and then figure out the
1296 // right way to deal with it.
Noah Eisen6870e6f2017-11-13 17:08:48 -08001297 else if (chand->resolver != nullptr) {
Mark D. Roth48be9de2017-10-23 12:27:37 -07001298 // No LB policy, so try again.
ncteisen72afb762017-11-10 12:23:12 -08001299 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth48be9de2017-10-23 12:27:37 -07001300 gpr_log(GPR_DEBUG,
1301 "chand=%p calld=%p: resolver returned but no LB policy, "
1302 "trying again",
1303 chand, calld);
1304 }
1305 pick_after_resolver_result_start_locked(exec_ctx, elem);
1306 } else {
ncteisen72afb762017-11-10 12:23:12 -08001307 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth48be9de2017-10-23 12:27:37 -07001308 gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver disconnected", chand,
1309 calld);
1310 }
1311 async_pick_done_locked(
1312 exec_ctx, elem, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
1313 }
Craig Tiller577c9b22015-11-02 14:11:15 -08001314}
1315
Craig Tillerbaa14a92017-11-03 09:09:36 -07001316static void pick_after_resolver_result_start_locked(grpc_exec_ctx* exec_ctx,
1317 grpc_call_element* elem) {
1318 channel_data* chand = (channel_data*)elem->channel_data;
1319 call_data* calld = (call_data*)elem->call_data;
Craig Tiller6014e8a2017-10-16 13:50:29 -07001320 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -07001321 gpr_log(GPR_DEBUG,
1322 "chand=%p calld=%p: deferring pick pending resolver result", chand,
1323 calld);
Mark D. Roth64a317c2017-05-02 08:27:08 -07001324 }
Craig Tillerbaa14a92017-11-03 09:09:36 -07001325 pick_after_resolver_result_args* args =
1326 (pick_after_resolver_result_args*)gpr_zalloc(sizeof(*args));
Mark D. Roth60751fe2017-07-07 12:50:33 -07001327 args->elem = elem;
1328 GRPC_CLOSURE_INIT(&args->closure, pick_after_resolver_result_done_locked,
1329 args, grpc_combiner_scheduler(chand->combiner));
1330 grpc_closure_list_append(&chand->waiting_for_resolver_result_closures,
1331 &args->closure, GRPC_ERROR_NONE);
Mark D. Roth76e264b2017-08-25 09:03:33 -07001332 grpc_call_combiner_set_notify_on_cancel(
1333 exec_ctx, calld->call_combiner,
Mark D. Roth66f3d2b2017-09-01 09:02:17 -07001334 GRPC_CLOSURE_INIT(&args->cancel_closure,
1335 pick_after_resolver_result_cancel_locked, args,
Mark D. Roth76e264b2017-08-25 09:03:33 -07001336 grpc_combiner_scheduler(chand->combiner)));
Mark D. Roth60751fe2017-07-07 12:50:33 -07001337}
1338
Craig Tillerbaa14a92017-11-03 09:09:36 -07001339static void start_pick_locked(grpc_exec_ctx* exec_ctx, void* arg,
1340 grpc_error* ignored) {
1341 grpc_call_element* elem = (grpc_call_element*)arg;
1342 call_data* calld = (call_data*)elem->call_data;
1343 channel_data* chand = (channel_data*)elem->channel_data;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001344 GPR_ASSERT(calld->connected_subchannel == nullptr);
1345 if (chand->lb_policy != nullptr) {
Mark D. Rothb2929602017-09-11 09:31:11 -07001346 // We already have an LB policy, so ask it for a pick.
1347 if (pick_callback_start_locked(exec_ctx, elem)) {
1348 // Pick completed synchronously.
1349 pick_done_locked(exec_ctx, elem, GRPC_ERROR_NONE);
1350 return;
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001351 }
Mark D. Roth76e264b2017-08-25 09:03:33 -07001352 } else {
Mark D. Rothb2929602017-09-11 09:31:11 -07001353 // We do not yet have an LB policy, so wait for a resolver result.
Noah Eisen6870e6f2017-11-13 17:08:48 -08001354 if (chand->resolver == nullptr) {
Mark D. Rothb2929602017-09-11 09:31:11 -07001355 pick_done_locked(exec_ctx, elem,
1356 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
1357 return;
1358 }
1359 if (!chand->started_resolving) {
1360 start_resolving_locked(exec_ctx, chand);
1361 }
1362 pick_after_resolver_result_start_locked(exec_ctx, elem);
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001363 }
Mark D. Rothb2929602017-09-11 09:31:11 -07001364 // We need to wait for either a resolver result or for an async result
1365 // from the LB policy. Add the polling entity from call_data to the
1366 // channel_data's interested_parties, so that the I/O of the LB policy
1367 // and resolver can be done under it. The polling entity will be
1368 // removed in async_pick_done_locked().
1369 grpc_polling_entity_add_to_pollset_set(exec_ctx, calld->pollent,
1370 chand->interested_parties);
Craig Tillera11bfc82017-02-14 09:56:33 -08001371}
1372
Craig Tillerbaa14a92017-11-03 09:09:36 -07001373static void on_complete(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
1374 grpc_call_element* elem = (grpc_call_element*)arg;
1375 call_data* calld = (call_data*)elem->call_data;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001376 if (calld->retry_throttle_data != nullptr) {
Mark D. Rothd6d192d2017-02-23 08:58:42 -08001377 if (error == GRPC_ERROR_NONE) {
1378 grpc_server_retry_throttle_data_record_success(
Mark D. Roth9ccbc4d2017-03-15 08:30:04 -07001379 calld->retry_throttle_data);
Mark D. Rothd6d192d2017-02-23 08:58:42 -08001380 } else {
1381 // TODO(roth): In a subsequent PR, check the return value here and
Mark D. Rothb3322562017-02-23 14:38:02 -08001382 // decide whether or not to retry. Note that we should only
1383 // record failures whose statuses match the configured retryable
1384 // or non-fatal status codes.
Mark D. Rothd6d192d2017-02-23 08:58:42 -08001385 grpc_server_retry_throttle_data_record_failure(
Mark D. Roth9ccbc4d2017-03-15 08:30:04 -07001386 calld->retry_throttle_data);
Mark D. Rothd6d192d2017-02-23 08:58:42 -08001387 }
1388 }
ncteisen274bbbe2017-06-08 14:57:11 -07001389 GRPC_CLOSURE_RUN(exec_ctx, calld->original_on_complete,
Mark D. Roth95039b52017-02-24 07:59:45 -08001390 GRPC_ERROR_REF(error));
Mark D. Rothd6d192d2017-02-23 08:58:42 -08001391}
1392
Craig Tillere1b51da2017-03-31 15:44:33 -07001393static void cc_start_transport_stream_op_batch(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001394 grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
1395 grpc_transport_stream_op_batch* batch) {
1396 call_data* calld = (call_data*)elem->call_data;
1397 channel_data* chand = (channel_data*)elem->channel_data;
Craig Tiller3be7dd02017-04-03 14:30:03 -07001398 if (chand->deadline_checking_enabled) {
Craig Tiller29ebc572017-04-04 08:00:55 -07001399 grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem,
Mark D. Roth60751fe2017-07-07 12:50:33 -07001400 batch);
Craig Tiller3be7dd02017-04-03 14:30:03 -07001401 }
Mark D. Roth76e264b2017-08-25 09:03:33 -07001402 GPR_TIMER_BEGIN("cc_start_transport_stream_op_batch", 0);
1403 // If we've previously been cancelled, immediately fail any new batches.
1404 if (calld->error != GRPC_ERROR_NONE) {
Craig Tiller6014e8a2017-10-16 13:50:29 -07001405 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth76e264b2017-08-25 09:03:33 -07001406 gpr_log(GPR_DEBUG, "chand=%p calld=%p: failing batch with error: %s",
1407 chand, calld, grpc_error_string(calld->error));
1408 }
1409 grpc_transport_stream_op_batch_finish_with_failure(
1410 exec_ctx, batch, GRPC_ERROR_REF(calld->error), calld->call_combiner);
1411 goto done;
1412 }
1413 if (batch->cancel_stream) {
1414 // Stash a copy of cancel_error in our call data, so that we can use
1415 // it for subsequent operations. This ensures that if the call is
1416 // cancelled before any batches are passed down (e.g., if the deadline
1417 // is in the past when the call starts), we can return the right
1418 // error to the caller when the first batch does get passed down.
1419 GRPC_ERROR_UNREF(calld->error);
1420 calld->error = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
Craig Tiller6014e8a2017-10-16 13:50:29 -07001421 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth76e264b2017-08-25 09:03:33 -07001422 gpr_log(GPR_DEBUG, "chand=%p calld=%p: recording cancel_error=%s", chand,
1423 calld, grpc_error_string(calld->error));
1424 }
1425 // If we have a subchannel call, send the cancellation batch down.
1426 // Otherwise, fail all pending batches.
Noah Eisen6870e6f2017-11-13 17:08:48 -08001427 if (calld->subchannel_call != nullptr) {
Mark D. Roth76e264b2017-08-25 09:03:33 -07001428 grpc_subchannel_call_process_op(exec_ctx, calld->subchannel_call, batch);
1429 } else {
1430 waiting_for_pick_batches_add(calld, batch);
1431 waiting_for_pick_batches_fail(exec_ctx, elem,
1432 GRPC_ERROR_REF(calld->error));
1433 }
1434 goto done;
1435 }
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001436 // Intercept on_complete for recv_trailing_metadata so that we can
1437 // check retry throttle status.
Mark D. Roth60751fe2017-07-07 12:50:33 -07001438 if (batch->recv_trailing_metadata) {
Noah Eisen6870e6f2017-11-13 17:08:48 -08001439 GPR_ASSERT(batch->on_complete != nullptr);
Mark D. Roth60751fe2017-07-07 12:50:33 -07001440 calld->original_on_complete = batch->on_complete;
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001441 GRPC_CLOSURE_INIT(&calld->on_complete, on_complete, elem,
1442 grpc_schedule_on_exec_ctx);
Mark D. Roth60751fe2017-07-07 12:50:33 -07001443 batch->on_complete = &calld->on_complete;
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001444 }
Mark D. Roth76e264b2017-08-25 09:03:33 -07001445 // Check if we've already gotten a subchannel call.
1446 // Note that once we have completed the pick, we do not need to enter
1447 // the channel combiner, which is more efficient (especially for
1448 // streaming calls).
Noah Eisen6870e6f2017-11-13 17:08:48 -08001449 if (calld->subchannel_call != nullptr) {
Craig Tiller6014e8a2017-10-16 13:50:29 -07001450 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth60751fe2017-07-07 12:50:33 -07001451 gpr_log(GPR_DEBUG,
1452 "chand=%p calld=%p: sending batch to subchannel_call=%p", chand,
Mark D. Roth76e264b2017-08-25 09:03:33 -07001453 calld, calld->subchannel_call);
Mark D. Roth60751fe2017-07-07 12:50:33 -07001454 }
Mark D. Roth76e264b2017-08-25 09:03:33 -07001455 grpc_subchannel_call_process_op(exec_ctx, calld->subchannel_call, batch);
Mark D. Roth60751fe2017-07-07 12:50:33 -07001456 goto done;
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001457 }
Mark D. Roth76e264b2017-08-25 09:03:33 -07001458 // We do not yet have a subchannel call.
1459 // Add the batch to the waiting-for-pick list.
1460 waiting_for_pick_batches_add(calld, batch);
1461 // For batches containing a send_initial_metadata op, enter the channel
1462 // combiner to start a pick.
1463 if (batch->send_initial_metadata) {
Craig Tiller6014e8a2017-10-16 13:50:29 -07001464 if (grpc_client_channel_trace.enabled()) {
Mark D. Rothb2929602017-09-11 09:31:11 -07001465 gpr_log(GPR_DEBUG, "chand=%p calld=%p: entering client_channel combiner",
1466 chand, calld);
Mark D. Roth76e264b2017-08-25 09:03:33 -07001467 }
1468 GRPC_CLOSURE_SCHED(
1469 exec_ctx,
1470 GRPC_CLOSURE_INIT(&batch->handler_private.closure, start_pick_locked,
1471 elem, grpc_combiner_scheduler(chand->combiner)),
1472 GRPC_ERROR_NONE);
1473 } else {
1474 // For all other batches, release the call combiner.
Craig Tiller6014e8a2017-10-16 13:50:29 -07001475 if (grpc_client_channel_trace.enabled()) {
Mark D. Roth76e264b2017-08-25 09:03:33 -07001476 gpr_log(GPR_DEBUG,
1477 "chand=%p calld=%p: saved batch, yeilding call combiner", chand,
1478 calld);
1479 }
1480 GRPC_CALL_COMBINER_STOP(exec_ctx, calld->call_combiner,
1481 "batch does not include send_initial_metadata");
Mark D. Roth60751fe2017-07-07 12:50:33 -07001482 }
Mark D. Roth60751fe2017-07-07 12:50:33 -07001483done:
Craig Tillera0f3abd2017-03-31 15:42:16 -07001484 GPR_TIMER_END("cc_start_transport_stream_op_batch", 0);
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001485}
1486
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001487/* Constructor for call_data */
Craig Tillerbaa14a92017-11-03 09:09:36 -07001488static grpc_error* cc_init_call_elem(grpc_exec_ctx* exec_ctx,
1489 grpc_call_element* elem,
1490 const grpc_call_element_args* args) {
1491 call_data* calld = (call_data*)elem->call_data;
1492 channel_data* chand = (channel_data*)elem->channel_data;
Mark D. Rothe40dd292016-10-05 14:58:37 -07001493 // Initialize data members.
Craig Tiller7c70b6c2017-01-23 07:48:42 -08001494 calld->path = grpc_slice_ref_internal(args->path);
Mark D. Rothff08f332016-10-14 13:01:01 -07001495 calld->call_start_time = args->start_time;
Craig Tiller89c14282017-07-19 15:32:27 -07001496 calld->deadline = args->deadline;
Craig Tillerd426cac2017-03-13 12:30:45 -07001497 calld->arena = args->arena;
Mark D. Roth66f3d2b2017-09-01 09:02:17 -07001498 calld->owning_call = args->call_stack;
Mark D. Roth76e264b2017-08-25 09:03:33 -07001499 calld->call_combiner = args->call_combiner;
Craig Tiller3be7dd02017-04-03 14:30:03 -07001500 if (chand->deadline_checking_enabled) {
Mark D. Roth76e264b2017-08-25 09:03:33 -07001501 grpc_deadline_state_init(exec_ctx, elem, args->call_stack,
1502 args->call_combiner, calld->deadline);
Craig Tiller3be7dd02017-04-03 14:30:03 -07001503 }
Mark D. Roth0badbe82016-06-23 10:15:12 -07001504 return GRPC_ERROR_NONE;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001505}
1506
1507/* Destructor for call_data */
Craig Tillerbaa14a92017-11-03 09:09:36 -07001508static void cc_destroy_call_elem(grpc_exec_ctx* exec_ctx,
1509 grpc_call_element* elem,
1510 const grpc_call_final_info* final_info,
1511 grpc_closure* then_schedule_closure) {
1512 call_data* calld = (call_data*)elem->call_data;
1513 channel_data* chand = (channel_data*)elem->channel_data;
Craig Tiller3be7dd02017-04-03 14:30:03 -07001514 if (chand->deadline_checking_enabled) {
1515 grpc_deadline_state_destroy(exec_ctx, elem);
1516 }
Craig Tiller7c70b6c2017-01-23 07:48:42 -08001517 grpc_slice_unref_internal(exec_ctx, calld->path);
Noah Eisen6870e6f2017-11-13 17:08:48 -08001518 if (calld->method_params != nullptr) {
Mark D. Roth95b627b2017-02-24 11:02:58 -08001519 method_parameters_unref(calld->method_params);
1520 }
Mark D. Roth76e264b2017-08-25 09:03:33 -07001521 GRPC_ERROR_UNREF(calld->error);
Noah Eisen6870e6f2017-11-13 17:08:48 -08001522 if (calld->subchannel_call != nullptr) {
Mark D. Roth76e264b2017-08-25 09:03:33 -07001523 grpc_subchannel_call_set_cleanup_closure(calld->subchannel_call,
Craig Tillerf7c8c9f2017-05-17 15:22:05 -07001524 then_schedule_closure);
Noah Eisen6870e6f2017-11-13 17:08:48 -08001525 then_schedule_closure = nullptr;
Mark D. Roth76e264b2017-08-25 09:03:33 -07001526 GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, calld->subchannel_call,
Craig Tillerf7c8c9f2017-05-17 15:22:05 -07001527 "client_channel_destroy_call");
Mark D. Roth4c0fe492016-08-31 13:51:55 -07001528 }
Noah Eisen6870e6f2017-11-13 17:08:48 -08001529 GPR_ASSERT(calld->lb_policy == nullptr);
Mark D. Roth0ca0be82017-06-20 07:49:33 -07001530 GPR_ASSERT(calld->waiting_for_pick_batches_count == 0);
Noah Eisen6870e6f2017-11-13 17:08:48 -08001531 if (calld->connected_subchannel != nullptr) {
Craig Tiller693d3942016-10-27 16:51:25 -07001532 GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, calld->connected_subchannel,
1533 "picked");
1534 }
Mark D. Roth09e458c2017-05-02 08:13:26 -07001535 for (size_t i = 0; i < GRPC_CONTEXT_COUNT; ++i) {
Noah Eisen882dfed2017-11-14 14:58:20 -08001536 if (calld->subchannel_call_context[i].value != nullptr) {
Mark D. Roth09e458c2017-05-02 08:13:26 -07001537 calld->subchannel_call_context[i].destroy(
1538 calld->subchannel_call_context[i].value);
1539 }
1540 }
ncteisen274bbbe2017-06-08 14:57:11 -07001541 GRPC_CLOSURE_SCHED(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001542}
1543
Craig Tillerbaa14a92017-11-03 09:09:36 -07001544static void cc_set_pollset_or_pollset_set(grpc_exec_ctx* exec_ctx,
1545 grpc_call_element* elem,
1546 grpc_polling_entity* pollent) {
1547 call_data* calld = (call_data*)elem->call_data;
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -07001548 calld->pollent = pollent;
Craig Tiller577c9b22015-11-02 14:11:15 -08001549}
1550
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001551/*************************************************************************
1552 * EXPORTED SYMBOLS
1553 */
1554
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001555const grpc_channel_filter grpc_client_channel_filter = {
Craig Tillera0f3abd2017-03-31 15:42:16 -07001556 cc_start_transport_stream_op_batch,
Craig Tillerf40df232016-03-25 13:38:14 -07001557 cc_start_transport_op,
1558 sizeof(call_data),
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001559 cc_init_call_elem,
David Garcia Quintas4afce7e2016-04-18 16:25:17 -07001560 cc_set_pollset_or_pollset_set,
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001561 cc_destroy_call_elem,
Craig Tillerf40df232016-03-25 13:38:14 -07001562 sizeof(channel_data),
Mark D. Roth2a5959f2016-09-01 08:20:27 -07001563 cc_init_channel_elem,
1564 cc_destroy_channel_elem,
Mark D. Rothb2d24882016-10-27 15:44:07 -07001565 cc_get_channel_info,
Craig Tillerf40df232016-03-25 13:38:14 -07001566 "client-channel",
Craig Tiller87d5b192015-04-16 14:37:57 -07001567};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001568
Craig Tillerbaa14a92017-11-03 09:09:36 -07001569static void try_to_connect_locked(grpc_exec_ctx* exec_ctx, void* arg,
1570 grpc_error* error_ignored) {
1571 channel_data* chand = (channel_data*)arg;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001572 if (chand->lb_policy != nullptr) {
Craig Tiller2400bf52017-02-09 16:25:19 -08001573 grpc_lb_policy_exit_idle_locked(exec_ctx, chand->lb_policy);
Craig Tiller613dafa2017-02-09 12:00:43 -08001574 } else {
1575 chand->exit_idle_when_lb_policy_arrives = true;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001576 if (!chand->started_resolving && chand->resolver != nullptr) {
Mark D. Roth60751fe2017-07-07 12:50:33 -07001577 start_resolving_locked(exec_ctx, chand);
Craig Tiller613dafa2017-02-09 12:00:43 -08001578 }
1579 }
Craig Tillerd2e5cfc2017-02-09 13:02:20 -08001580 GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "try_to_connect");
Craig Tiller613dafa2017-02-09 12:00:43 -08001581}
1582
Craig Tillera82950e2015-09-22 12:33:20 -07001583grpc_connectivity_state grpc_client_channel_check_connectivity_state(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001584 grpc_exec_ctx* exec_ctx, grpc_channel_element* elem, int try_to_connect) {
1585 channel_data* chand = (channel_data*)elem->channel_data;
Craig Tillera8610c02017-02-14 10:05:11 -08001586 grpc_connectivity_state out =
1587 grpc_connectivity_state_check(&chand->state_tracker);
Craig Tillera82950e2015-09-22 12:33:20 -07001588 if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
Craig Tillerd2e5cfc2017-02-09 13:02:20 -08001589 GRPC_CHANNEL_STACK_REF(chand->owning_stack, "try_to_connect");
ncteisen274bbbe2017-06-08 14:57:11 -07001590 GRPC_CLOSURE_SCHED(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001591 exec_ctx,
1592 GRPC_CLOSURE_CREATE(try_to_connect_locked, chand,
1593 grpc_combiner_scheduler(chand->combiner)),
Craig Tiller613dafa2017-02-09 12:00:43 -08001594 GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -07001595 }
Craig Tiller48cb07c2015-07-15 16:16:15 -07001596 return out;
1597}
1598
Alexander Polcync3b1f182017-04-18 13:51:36 -07001599typedef struct external_connectivity_watcher {
Craig Tillerbaa14a92017-11-03 09:09:36 -07001600 channel_data* chand;
David Garcia Quintas87d5a312017-06-06 19:45:58 -07001601 grpc_polling_entity pollent;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001602 grpc_closure* on_complete;
1603 grpc_closure* watcher_timer_init;
1604 grpc_connectivity_state* state;
Craig Tiller86c99582015-11-25 15:22:26 -08001605 grpc_closure my_closure;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001606 struct external_connectivity_watcher* next;
Craig Tiller86c99582015-11-25 15:22:26 -08001607} external_connectivity_watcher;
1608
Craig Tillerbaa14a92017-11-03 09:09:36 -07001609static external_connectivity_watcher* lookup_external_connectivity_watcher(
1610 channel_data* chand, grpc_closure* on_complete) {
Alexander Polcync3b1f182017-04-18 13:51:36 -07001611 gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
Craig Tillerbaa14a92017-11-03 09:09:36 -07001612 external_connectivity_watcher* w =
Alexander Polcync3b1f182017-04-18 13:51:36 -07001613 chand->external_connectivity_watcher_list_head;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001614 while (w != nullptr && w->on_complete != on_complete) {
Alexander Polcync3b1f182017-04-18 13:51:36 -07001615 w = w->next;
1616 }
1617 gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
1618 return w;
1619}
1620
1621static void external_connectivity_watcher_list_append(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001622 channel_data* chand, external_connectivity_watcher* w) {
Alexander Polcync3b1f182017-04-18 13:51:36 -07001623 GPR_ASSERT(!lookup_external_connectivity_watcher(chand, w->on_complete));
1624
1625 gpr_mu_lock(&w->chand->external_connectivity_watcher_list_mu);
1626 GPR_ASSERT(!w->next);
1627 w->next = chand->external_connectivity_watcher_list_head;
1628 chand->external_connectivity_watcher_list_head = w;
1629 gpr_mu_unlock(&w->chand->external_connectivity_watcher_list_mu);
1630}
1631
1632static void external_connectivity_watcher_list_remove(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001633 channel_data* chand, external_connectivity_watcher* too_remove) {
Alexander Polcync3b1f182017-04-18 13:51:36 -07001634 GPR_ASSERT(
1635 lookup_external_connectivity_watcher(chand, too_remove->on_complete));
1636 gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
1637 if (too_remove == chand->external_connectivity_watcher_list_head) {
1638 chand->external_connectivity_watcher_list_head = too_remove->next;
1639 gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
1640 return;
1641 }
Craig Tillerbaa14a92017-11-03 09:09:36 -07001642 external_connectivity_watcher* w =
Alexander Polcync3b1f182017-04-18 13:51:36 -07001643 chand->external_connectivity_watcher_list_head;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001644 while (w != nullptr) {
Alexander Polcync3b1f182017-04-18 13:51:36 -07001645 if (w->next == too_remove) {
1646 w->next = w->next->next;
1647 gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
1648 return;
1649 }
1650 w = w->next;
1651 }
1652 GPR_UNREACHABLE_CODE(return );
1653}
1654
1655int grpc_client_channel_num_external_connectivity_watchers(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001656 grpc_channel_element* elem) {
1657 channel_data* chand = (channel_data*)elem->channel_data;
Alexander Polcync3b1f182017-04-18 13:51:36 -07001658 int count = 0;
1659
1660 gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
Craig Tillerbaa14a92017-11-03 09:09:36 -07001661 external_connectivity_watcher* w =
Alexander Polcync3b1f182017-04-18 13:51:36 -07001662 chand->external_connectivity_watcher_list_head;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001663 while (w != nullptr) {
Alexander Polcync3b1f182017-04-18 13:51:36 -07001664 count++;
1665 w = w->next;
1666 }
1667 gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
1668
1669 return count;
1670}
1671
Craig Tillerbaa14a92017-11-03 09:09:36 -07001672static void on_external_watch_complete_locked(grpc_exec_ctx* exec_ctx,
1673 void* arg, grpc_error* error) {
1674 external_connectivity_watcher* w = (external_connectivity_watcher*)arg;
1675 grpc_closure* follow_up = w->on_complete;
David Garcia Quintas87d5a312017-06-06 19:45:58 -07001676 grpc_polling_entity_del_from_pollset_set(exec_ctx, &w->pollent,
1677 w->chand->interested_parties);
Craig Tiller1d881fb2015-12-01 07:39:04 -08001678 GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
1679 "external_connectivity_watcher");
Alexander Polcync3b1f182017-04-18 13:51:36 -07001680 external_connectivity_watcher_list_remove(w->chand, w);
Craig Tiller86c99582015-11-25 15:22:26 -08001681 gpr_free(w);
ncteisen274bbbe2017-06-08 14:57:11 -07001682 GRPC_CLOSURE_RUN(exec_ctx, follow_up, GRPC_ERROR_REF(error));
Craig Tiller613dafa2017-02-09 12:00:43 -08001683}
1684
Craig Tillerbaa14a92017-11-03 09:09:36 -07001685static void watch_connectivity_state_locked(grpc_exec_ctx* exec_ctx, void* arg,
1686 grpc_error* error_ignored) {
1687 external_connectivity_watcher* w = (external_connectivity_watcher*)arg;
Noah Eisen6870e6f2017-11-13 17:08:48 -08001688 external_connectivity_watcher* found = nullptr;
1689 if (w->state != nullptr) {
Alexander Polcync3b1f182017-04-18 13:51:36 -07001690 external_connectivity_watcher_list_append(w->chand, w);
ncteisen274bbbe2017-06-08 14:57:11 -07001691 GRPC_CLOSURE_RUN(exec_ctx, w->watcher_timer_init, GRPC_ERROR_NONE);
Alexander Polcyn2004e392017-10-16 15:14:46 -07001692 GRPC_CLOSURE_INIT(&w->my_closure, on_external_watch_complete_locked, w,
1693 grpc_combiner_scheduler(w->chand->combiner));
Alexander Polcync3b1f182017-04-18 13:51:36 -07001694 grpc_connectivity_state_notify_on_state_change(
1695 exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure);
1696 } else {
Noah Eisen6870e6f2017-11-13 17:08:48 -08001697 GPR_ASSERT(w->watcher_timer_init == nullptr);
Alexander Polcync3b1f182017-04-18 13:51:36 -07001698 found = lookup_external_connectivity_watcher(w->chand, w->on_complete);
1699 if (found) {
1700 GPR_ASSERT(found->on_complete == w->on_complete);
1701 grpc_connectivity_state_notify_on_state_change(
Noah Eisen6870e6f2017-11-13 17:08:48 -08001702 exec_ctx, &found->chand->state_tracker, nullptr, &found->my_closure);
Alexander Polcync3b1f182017-04-18 13:51:36 -07001703 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -07001704 grpc_polling_entity_del_from_pollset_set(exec_ctx, &w->pollent,
1705 w->chand->interested_parties);
Alexander Polcync3b1f182017-04-18 13:51:36 -07001706 GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
1707 "external_connectivity_watcher");
1708 gpr_free(w);
1709 }
Craig Tiller86c99582015-11-25 15:22:26 -08001710}
1711
Craig Tillera82950e2015-09-22 12:33:20 -07001712void grpc_client_channel_watch_connectivity_state(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001713 grpc_exec_ctx* exec_ctx, grpc_channel_element* elem,
1714 grpc_polling_entity pollent, grpc_connectivity_state* state,
1715 grpc_closure* closure, grpc_closure* watcher_timer_init) {
1716 channel_data* chand = (channel_data*)elem->channel_data;
1717 external_connectivity_watcher* w =
1718 (external_connectivity_watcher*)gpr_zalloc(sizeof(*w));
Craig Tiller86c99582015-11-25 15:22:26 -08001719 w->chand = chand;
David Garcia Quintas87d5a312017-06-06 19:45:58 -07001720 w->pollent = pollent;
Mark D. Roth92210832017-05-02 15:04:39 -07001721 w->on_complete = closure;
Craig Tiller613dafa2017-02-09 12:00:43 -08001722 w->state = state;
Alexander Polcync3b1f182017-04-18 13:51:36 -07001723 w->watcher_timer_init = watcher_timer_init;
David Garcia Quintas87d5a312017-06-06 19:45:58 -07001724 grpc_polling_entity_add_to_pollset_set(exec_ctx, &w->pollent,
1725 chand->interested_parties);
Craig Tiller1d881fb2015-12-01 07:39:04 -08001726 GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
1727 "external_connectivity_watcher");
ncteisen274bbbe2017-06-08 14:57:11 -07001728 GRPC_CLOSURE_SCHED(
Craig Tiller613dafa2017-02-09 12:00:43 -08001729 exec_ctx,
ncteisen274bbbe2017-06-08 14:57:11 -07001730 GRPC_CLOSURE_INIT(&w->my_closure, watch_connectivity_state_locked, w,
Craig Tilleree4b1452017-05-12 10:56:03 -07001731 grpc_combiner_scheduler(chand->combiner)),
Craig Tiller613dafa2017-02-09 12:00:43 -08001732 GRPC_ERROR_NONE);
Craig Tiller48cb07c2015-07-15 16:16:15 -07001733}