static grpc_resolver *dns_create(grpc_exec_ctx *exec_ctx, grpc_resolver_args *args, const char *default_port) { if (0 != strcmp(args->uri->authority, "")) { gpr_log(GPR_ERROR, "authority based dns uri's not supported"); return NULL; } // Get name from args. const char *path = args->uri->path; if (path[0] == '/') ++path; // Get proxy name, if any. char *proxy_name = grpc_get_http_proxy_server(); // Create resolver. dns_resolver *r = gpr_malloc(sizeof(dns_resolver)); memset(r, 0, sizeof(*r)); gpr_mu_init(&r->mu); grpc_resolver_init(&r->base, &dns_resolver_vtable); r->name_to_resolve = proxy_name == NULL ? gpr_strdup(path) : proxy_name; r->default_port = gpr_strdup(default_port); r->channel_args = grpc_channel_args_copy(args->args); r->interested_parties = grpc_pollset_set_create(); if (args->pollset_set != NULL) { grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties, args->pollset_set); } gpr_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS, GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER, GRPC_DNS_RECONNECT_JITTER, GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000, GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000); return &r->base; }
void grpc_polling_entity_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_polling_entity *pollent, grpc_pollset_set *pss_dst) { if (pollent->tag == POPS_POLLSET) { GPR_ASSERT(pollent->pollent.pollset != NULL); grpc_pollset_set_add_pollset(exec_ctx, pss_dst, pollent->pollent.pollset); } else if (pollent->tag == POPS_POLLSET_SET) { GPR_ASSERT(pollent->pollent.pollset_set != NULL); grpc_pollset_set_add_pollset_set(exec_ctx, pss_dst, pollent->pollent.pollset_set); } else { gpr_log(GPR_ERROR, "Invalid grpc_polling_entity tag '%d'", pollent->tag); abort(); } }
static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { channel_data *chand = arg; grpc_lb_policy *lb_policy = NULL; grpc_lb_policy *old_lb_policy; grpc_mdstr_hash_table *method_params_table = NULL; grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; bool exit_idle = false; grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy"); if (chand->resolver_result != NULL) { grpc_lb_policy_args lb_policy_args; lb_policy_args.args = chand->resolver_result; lb_policy_args.client_channel_factory = chand->client_channel_factory; // Find LB policy name. const char *lb_policy_name = NULL; const grpc_arg *channel_arg = grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_POLICY_NAME); if (channel_arg != NULL) { GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); lb_policy_name = channel_arg->value.string; } // Special case: If all of the addresses are balancer addresses, // assume that we should use the grpclb policy, regardless of what the // resolver actually specified. channel_arg = grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_ADDRESSES); if (channel_arg != NULL) { GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); grpc_lb_addresses *addresses = channel_arg->value.pointer.p; bool found_backend_address = false; for (size_t i = 0; i < addresses->num_addresses; ++i) { if (!addresses->addresses[i].is_balancer) { found_backend_address = true; break; } } if (!found_backend_address) { if (lb_policy_name != NULL && strcmp(lb_policy_name, "grpclb") != 0) { gpr_log(GPR_INFO, "resolver requested LB policy %s but provided only balancer " "addresses, no backend addresses -- forcing use of grpclb LB " "policy", lb_policy_name); } lb_policy_name = "grpclb"; } } // Use pick_first if nothing was specified and we didn't select grpclb // above. if (lb_policy_name == NULL) lb_policy_name = "pick_first"; lb_policy = grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args); if (lb_policy != NULL) { GRPC_LB_POLICY_REF(lb_policy, "config_change"); GRPC_ERROR_UNREF(state_error); state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error); } channel_arg = grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_SERVICE_CONFIG); if (channel_arg != NULL) { GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); method_params_table = grpc_method_config_table_convert( (grpc_method_config_table *)channel_arg->value.pointer.p, method_config_convert_value, &method_parameters_vtable); } grpc_channel_args_destroy(chand->resolver_result); chand->resolver_result = NULL; } if (lb_policy != NULL) { grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties, chand->interested_parties); } gpr_mu_lock(&chand->mu); old_lb_policy = chand->lb_policy; chand->lb_policy = lb_policy; if (chand->method_params_table != NULL) { grpc_mdstr_hash_table_unref(chand->method_params_table); } chand->method_params_table = method_params_table; if (lb_policy != NULL) { grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, NULL); } else if (chand->resolver == NULL /* disconnected */) { grpc_closure_list_fail_all( &chand->waiting_for_config_closures, GRPC_ERROR_CREATE_REFERENCING("Channel disconnected", &error, 1)); grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, NULL); } if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) { GRPC_LB_POLICY_REF(lb_policy, "exit_idle"); exit_idle = true; chand->exit_idle_when_lb_policy_arrives = false; } if (error == GRPC_ERROR_NONE && chand->resolver) { set_channel_connectivity_state_locked( exec_ctx, chand, state, GRPC_ERROR_REF(state_error), "new_lb+resolver"); if (lb_policy != NULL) { watch_lb_policy(exec_ctx, chand, lb_policy, state); } GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, &chand->on_resolver_result_changed); gpr_mu_unlock(&chand->mu); } else { if (chand->resolver != NULL) { grpc_resolver_shutdown(exec_ctx, chand->resolver); GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); chand->resolver = NULL; } grpc_error *refs[] = {error, state_error}; set_channel_connectivity_state_locked( exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_CREATE_REFERENCING("Got config after disconnection", refs, GPR_ARRAY_SIZE(refs)), "resolver_gone"); gpr_mu_unlock(&chand->mu); } if (exit_idle) { grpc_lb_policy_exit_idle(exec_ctx, lb_policy); GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "exit_idle"); } if (old_lb_policy != NULL) { grpc_pollset_set_del_pollset_set( exec_ctx, old_lb_policy->interested_parties, chand->interested_parties); GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel"); } if (lb_policy != NULL) { GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change"); } GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver"); GRPC_ERROR_UNREF(state_error); }
static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { channel_data *chand = arg; grpc_lb_policy *lb_policy = NULL; grpc_lb_policy *old_lb_policy; grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; bool exit_idle = false; grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy"); if (chand->resolver_result != NULL) { lb_policy = grpc_resolver_result_get_lb_policy(chand->resolver_result); if (lb_policy != NULL) { GRPC_LB_POLICY_REF(lb_policy, "channel"); GRPC_LB_POLICY_REF(lb_policy, "config_change"); GRPC_ERROR_UNREF(state_error); state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error); } grpc_resolver_result_unref(exec_ctx, chand->resolver_result); } chand->resolver_result = NULL; if (lb_policy != NULL) { grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties, chand->interested_parties); } gpr_mu_lock(&chand->mu); old_lb_policy = chand->lb_policy; chand->lb_policy = lb_policy; if (lb_policy != NULL) { grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, NULL); } else if (chand->resolver == NULL /* disconnected */) { grpc_closure_list_fail_all( &chand->waiting_for_config_closures, GRPC_ERROR_CREATE_REFERENCING("Channel disconnected", &error, 1)); grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, NULL); } if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) { GRPC_LB_POLICY_REF(lb_policy, "exit_idle"); exit_idle = true; chand->exit_idle_when_lb_policy_arrives = false; } if (error == GRPC_ERROR_NONE && chand->resolver) { set_channel_connectivity_state_locked( exec_ctx, chand, state, GRPC_ERROR_REF(state_error), "new_lb+resolver"); if (lb_policy != NULL) { watch_lb_policy(exec_ctx, chand, lb_policy, state); } GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, &chand->on_resolver_result_changed); gpr_mu_unlock(&chand->mu); } else { if (chand->resolver != NULL) { grpc_resolver_shutdown(exec_ctx, chand->resolver); GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); chand->resolver = NULL; } grpc_error *refs[] = {error, state_error}; set_channel_connectivity_state_locked( exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_CREATE_REFERENCING("Got config after disconnection", refs, GPR_ARRAY_SIZE(refs)), "resolver_gone"); gpr_mu_unlock(&chand->mu); } if (exit_idle) { grpc_lb_policy_exit_idle(exec_ctx, lb_policy); GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "exit_idle"); } if (old_lb_policy != NULL) { grpc_pollset_set_del_pollset_set( exec_ctx, old_lb_policy->interested_parties, chand->interested_parties); GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel"); } if (lb_policy != NULL) { GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change"); } GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver"); GRPC_ERROR_UNREF(state_error); }
static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) { channel_data *chand = arg; grpc_lb_policy *lb_policy = NULL; grpc_lb_policy *old_lb_policy; grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; int exit_idle = 0; if (chand->incoming_configuration != NULL) { lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration); if (lb_policy != NULL) { GRPC_LB_POLICY_REF(lb_policy, "channel"); GRPC_LB_POLICY_REF(lb_policy, "config_change"); state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy); } grpc_client_config_unref(exec_ctx, chand->incoming_configuration); } chand->incoming_configuration = NULL; if (lb_policy != NULL) { grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties, chand->interested_parties); } gpr_mu_lock(&chand->mu_config); old_lb_policy = chand->lb_policy; chand->lb_policy = lb_policy; if (lb_policy != NULL || chand->resolver == NULL /* disconnected */) { grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, NULL); } if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) { GRPC_LB_POLICY_REF(lb_policy, "exit_idle"); exit_idle = 1; chand->exit_idle_when_lb_policy_arrives = 0; } if (iomgr_success && chand->resolver) { set_channel_connectivity_state_locked(exec_ctx, chand, state, "new_lb+resolver"); if (lb_policy != NULL) { watch_lb_policy(exec_ctx, chand, lb_policy, state); } GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); grpc_resolver_next(exec_ctx, chand->resolver, &chand->incoming_configuration, &chand->on_config_changed); gpr_mu_unlock(&chand->mu_config); } else { if (chand->resolver != NULL) { grpc_resolver_shutdown(exec_ctx, chand->resolver); GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); chand->resolver = NULL; } set_channel_connectivity_state_locked( exec_ctx, chand, GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone"); gpr_mu_unlock(&chand->mu_config); } if (exit_idle) { grpc_lb_policy_exit_idle(exec_ctx, lb_policy); GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "exit_idle"); } if (old_lb_policy != NULL) { grpc_pollset_set_del_pollset_set( exec_ctx, old_lb_policy->interested_parties, chand->interested_parties); GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel"); } if (lb_policy != NULL) { GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change"); } GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver"); }
/* Same FD added multiple times to the pollset_set tree */ void pollset_set_test_dup_fds() { /* We construct the following structure for this test: * * +---> FD0 * | * | * PSS0---+ * | +---> FD0 (also under PSS0) * | | * +---> PSS1--+ +--> FD1 (also under PSS1) * | | * +---> PS ---+ * | | * | +--> FD2 * +---> FD1 */ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_pollset_worker *worker; gpr_timespec deadline; test_fd tfds[3]; test_pollset pollset; test_pollset_set pollset_sets[2]; const int num_fds = GPR_ARRAY_SIZE(tfds); const int num_ps = 1; const int num_pss = GPR_ARRAY_SIZE(pollset_sets); init_test_fds(&exec_ctx, tfds, num_fds); init_test_pollsets(&pollset, num_ps); init_test_pollset_sets(pollset_sets, num_pss); /* Construct the structure */ grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[0].pss, tfds[0].fd); grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[1].pss, tfds[0].fd); grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[1].pss, tfds[1].fd); grpc_pollset_add_fd(&exec_ctx, pollset.ps, tfds[1].fd); grpc_pollset_add_fd(&exec_ctx, pollset.ps, tfds[2].fd); grpc_pollset_set_add_pollset(&exec_ctx, pollset_sets[1].pss, pollset.ps); grpc_pollset_set_add_pollset_set(&exec_ctx, pollset_sets[0].pss, pollset_sets[1].pss); /* Test. Make all FDs readable and make sure that can be observed by doing a * grpc_pollset_work on the pollset 'PS' */ make_test_fds_readable(tfds, num_fds); gpr_mu_lock(pollset.mu); deadline = grpc_timeout_milliseconds_to_deadline(2); GPR_ASSERT(GRPC_ERROR_NONE == grpc_pollset_work(&exec_ctx, pollset.ps, &worker, gpr_now(GPR_CLOCK_MONOTONIC), deadline)); gpr_mu_unlock(pollset.mu); grpc_exec_ctx_flush(&exec_ctx); verify_readable_and_reset(&exec_ctx, tfds, num_fds); grpc_exec_ctx_flush(&exec_ctx); /* Tear down */ grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[0].pss, tfds[0].fd); grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[1].pss, tfds[0].fd); grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[1].pss, tfds[1].fd); grpc_pollset_set_del_pollset(&exec_ctx, pollset_sets[1].pss, pollset.ps); grpc_pollset_set_del_pollset_set(&exec_ctx, pollset_sets[0].pss, pollset_sets[1].pss); grpc_exec_ctx_flush(&exec_ctx); cleanup_test_fds(&exec_ctx, tfds, num_fds); cleanup_test_pollsets(&exec_ctx, &pollset, num_ps); cleanup_test_pollset_sets(&exec_ctx, pollset_sets, num_pss); grpc_exec_ctx_finish(&exec_ctx); }
/* Test some typical scenarios in pollset_set */ static void pollset_set_test_basic() { /* We construct the following structure for this test: * * +---> FD0 (Added before PSS1, PS1 and PS2 are added to PSS0) * | * +---> FD5 (Added after PSS1, PS1 and PS2 are added to PSS0) * | * | * | +---> FD1 (Added before PSS1 is added to PSS0) * | | * | +---> FD6 (Added after PSS1 is added to PSS0) * | | * +---> PSS1--+ +--> FD2 (Added before PS0 is added to PSS1) * | | | * | +---> PS0---+ * | | * PSS0---+ +--> FD7 (Added after PS0 is added to PSS1) * | * | * | +---> FD3 (Added before PS1 is added to PSS0) * | | * +---> PS1---+ * | | * | +---> FD8 (Added after PS1 added to PSS0) * | * | * | +---> FD4 (Added before PS2 is added to PSS0) * | | * +---> PS2---+ * | * +---> FD9 (Added after PS2 is added to PSS0) */ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_pollset_worker *worker; gpr_timespec deadline; test_fd tfds[10]; test_pollset pollsets[3]; test_pollset_set pollset_sets[2]; const int num_fds = GPR_ARRAY_SIZE(tfds); const int num_ps = GPR_ARRAY_SIZE(pollsets); const int num_pss = GPR_ARRAY_SIZE(pollset_sets); init_test_fds(&exec_ctx, tfds, num_fds); init_test_pollsets(pollsets, num_ps); init_test_pollset_sets(pollset_sets, num_pss); /* Construct the pollset_set/pollset/fd tree (see diagram above) */ grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[0].pss, tfds[0].fd); grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[1].pss, tfds[1].fd); grpc_pollset_add_fd(&exec_ctx, pollsets[0].ps, tfds[2].fd); grpc_pollset_add_fd(&exec_ctx, pollsets[1].ps, tfds[3].fd); grpc_pollset_add_fd(&exec_ctx, pollsets[2].ps, tfds[4].fd); grpc_pollset_set_add_pollset_set(&exec_ctx, pollset_sets[0].pss, pollset_sets[1].pss); grpc_pollset_set_add_pollset(&exec_ctx, pollset_sets[1].pss, pollsets[0].ps); grpc_pollset_set_add_pollset(&exec_ctx, pollset_sets[0].pss, pollsets[1].ps); grpc_pollset_set_add_pollset(&exec_ctx, pollset_sets[0].pss, pollsets[2].ps); grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[0].pss, tfds[5].fd); grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[1].pss, tfds[6].fd); grpc_pollset_add_fd(&exec_ctx, pollsets[0].ps, tfds[7].fd); grpc_pollset_add_fd(&exec_ctx, pollsets[1].ps, tfds[8].fd); grpc_pollset_add_fd(&exec_ctx, pollsets[2].ps, tfds[9].fd); grpc_exec_ctx_flush(&exec_ctx); /* Test that if any FD in the above structure is readable, it is observable by * doing grpc_pollset_work on any pollset * * For every pollset, do the following: * - (Ensure that all FDs are in reset state) * - Make all FDs readable * - Call grpc_pollset_work() on the pollset * - Flush the exec_ctx * - Verify that on_readable call back was called for all FDs (and * reset the FDs) * */ for (int i = 0; i < num_ps; i++) { make_test_fds_readable(tfds, num_fds); gpr_mu_lock(pollsets[i].mu); deadline = grpc_timeout_milliseconds_to_deadline(2); GPR_ASSERT(GRPC_ERROR_NONE == grpc_pollset_work(&exec_ctx, pollsets[i].ps, &worker, gpr_now(GPR_CLOCK_MONOTONIC), deadline)); gpr_mu_unlock(pollsets[i].mu); grpc_exec_ctx_flush(&exec_ctx); verify_readable_and_reset(&exec_ctx, tfds, num_fds); grpc_exec_ctx_flush(&exec_ctx); } /* Test tear down */ grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[0].pss, tfds[0].fd); grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[0].pss, tfds[5].fd); grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[1].pss, tfds[1].fd); grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[1].pss, tfds[6].fd); grpc_exec_ctx_flush(&exec_ctx); grpc_pollset_set_del_pollset(&exec_ctx, pollset_sets[1].pss, pollsets[0].ps); grpc_pollset_set_del_pollset(&exec_ctx, pollset_sets[0].pss, pollsets[1].ps); grpc_pollset_set_del_pollset(&exec_ctx, pollset_sets[0].pss, pollsets[2].ps); grpc_pollset_set_del_pollset_set(&exec_ctx, pollset_sets[0].pss, pollset_sets[1].pss); grpc_exec_ctx_flush(&exec_ctx); cleanup_test_fds(&exec_ctx, tfds, num_fds); cleanup_test_pollsets(&exec_ctx, pollsets, num_ps); cleanup_test_pollset_sets(&exec_ctx, pollset_sets, num_pss); grpc_exec_ctx_finish(&exec_ctx); }