// Constructor for channel_data. static void init_channel_elem(grpc_exec_ctx* exec_ctx, grpc_channel_element* elem, grpc_channel_element_args* args) { GPR_ASSERT(!args->is_last); channel_data* chand = elem->channel_data; memset(chand, 0, sizeof(*chand)); chand->max_send_size = DEFAULT_MAX_SEND_MESSAGE_LENGTH; chand->max_recv_size = DEFAULT_MAX_RECV_MESSAGE_LENGTH; for (size_t i = 0; i < args->channel_args->num_args; ++i) { if (strcmp(args->channel_args->args[i].key, GRPC_ARG_MAX_SEND_MESSAGE_LENGTH) == 0) { const grpc_integer_options options = {DEFAULT_MAX_SEND_MESSAGE_LENGTH, 0, INT_MAX}; chand->max_send_size = grpc_channel_arg_get_integer(&args->channel_args->args[i], options); } if (strcmp(args->channel_args->args[i].key, GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH) == 0) { const grpc_integer_options options = {DEFAULT_MAX_RECV_MESSAGE_LENGTH, 0, INT_MAX}; chand->max_recv_size = grpc_channel_arg_get_integer(&args->channel_args->args[i], options); } } // Get method config table from channel args. const grpc_arg* channel_arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG); if (channel_arg != NULL) { GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); chand->method_limit_table = grpc_method_config_table_convert( (grpc_method_config_table*)channel_arg->value.pointer.p, method_config_convert_value, &message_size_limits_vtable); } }
grpc_fake_resolver_response_generator* grpc_fake_resolver_get_response_generator(const grpc_channel_args* args) { const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR); if (arg == NULL || arg->type != GRPC_ARG_POINTER) return NULL; return (grpc_fake_resolver_response_generator*)arg->value.pointer.p; }
static grpc_socket_factory *get_socket_factory(const grpc_channel_args *args) { if (args) { const grpc_arg *arg = grpc_channel_args_find(args, GRPC_ARG_SOCKET_FACTORY); if (arg) { GPR_ASSERT(arg->type == GRPC_ARG_POINTER); return arg->value.pointer.p; } } return NULL; }
const char *grpc_fake_transport_get_expected_targets( const grpc_channel_args *args) { const grpc_arg *expected_target_arg = grpc_channel_args_find(args, GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS); if (expected_target_arg != NULL && expected_target_arg->type == GRPC_ARG_STRING) { return expected_target_arg->value.string; } return NULL; }
static bool maybe_add_optional_filter(grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) { if (!is_building_http_like_transport(builder)) return true; optional_filter *filtarg = arg; const grpc_channel_args *channel_args = grpc_channel_stack_builder_get_channel_arguments(builder); bool enable = grpc_channel_arg_get_bool( grpc_channel_args_find(channel_args, filtarg->control_channel_arg), !grpc_channel_args_want_minimal_stack(channel_args)); return enable ? grpc_channel_stack_builder_prepend_filter( builder, filtarg->filter, NULL, NULL) : true; }
grpc_channel_args *grpc_channel_args_union(const grpc_channel_args *a, const grpc_channel_args *b) { const size_t max_out = (a->num_args + b->num_args); grpc_arg *uniques = (grpc_arg *)gpr_malloc(sizeof(*uniques) * max_out); for (size_t i = 0; i < a->num_args; ++i) uniques[i] = a->args[i]; size_t uniques_idx = a->num_args; for (size_t i = 0; i < b->num_args; ++i) { const char *b_key = b->args[i].key; if (grpc_channel_args_find(a, b_key) == NULL) { // not found uniques[uniques_idx++] = b->args[i]; } } grpc_channel_args *result = grpc_channel_args_copy_and_add(NULL, uniques, uniques_idx); gpr_free(uniques); return result; }
static bool maybe_add_message_size_filter(grpc_exec_ctx* exec_ctx, grpc_channel_stack_builder* builder, void* arg) { const grpc_channel_args* channel_args = grpc_channel_stack_builder_get_channel_arguments(builder); bool enable = false; message_size_limits lim = get_message_size_limits(channel_args); if (lim.max_send_size != -1 || lim.max_recv_size != -1) { enable = true; } const grpc_arg* a = grpc_channel_args_find(channel_args, GRPC_ARG_SERVICE_CONFIG); if (a != NULL) { enable = true; } if (enable) { return grpc_channel_stack_builder_prepend_filter( builder, &grpc_message_size_filter, NULL, NULL); } else { return true; } }
// Constructor for channel_data. static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx, grpc_channel_element* elem, grpc_channel_element_args* args) { GPR_ASSERT(!args->is_last); channel_data* chand = (channel_data*)elem->channel_data; chand->limits = get_message_size_limits(args->channel_args); // Get method config table from channel args. const grpc_arg* channel_arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG); if (channel_arg != NULL) { GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); grpc_service_config* service_config = grpc_service_config_create(channel_arg->value.string); if (service_config != NULL) { chand->method_limit_table = grpc_service_config_create_method_config_table( exec_ctx, service_config, message_size_limits_create_from_json, message_size_limits_free); grpc_service_config_destroy(service_config); } } return GRPC_ERROR_NONE; }
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); }
bool grpc_channel_args_want_minimal_stack(const grpc_channel_args *args) { return grpc_channel_arg_get_bool( grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK), false); }
static void http_connect_handshaker_do_handshake( grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker_in, grpc_tcp_server_acceptor* acceptor, grpc_closure* on_handshake_done, grpc_handshaker_args* args) { http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in; // Check for HTTP CONNECT channel arg. // If not found, invoke on_handshake_done without doing anything. const grpc_arg* arg = grpc_channel_args_find(args->args, GRPC_ARG_HTTP_CONNECT_SERVER); if (arg == NULL) { // Set shutdown to true so that subsequent calls to // http_connect_handshaker_shutdown() do nothing. gpr_mu_lock(&handshaker->mu); handshaker->shutdown = true; gpr_mu_unlock(&handshaker->mu); grpc_closure_sched(exec_ctx, on_handshake_done, GRPC_ERROR_NONE); return; } GPR_ASSERT(arg->type == GRPC_ARG_STRING); char* server_name = arg->value.string; // Get headers from channel args. arg = grpc_channel_args_find(args->args, GRPC_ARG_HTTP_CONNECT_HEADERS); grpc_http_header* headers = NULL; size_t num_headers = 0; char** header_strings = NULL; size_t num_header_strings = 0; if (arg != NULL) { GPR_ASSERT(arg->type == GRPC_ARG_STRING); gpr_string_split(arg->value.string, "\n", &header_strings, &num_header_strings); headers = gpr_malloc(sizeof(grpc_http_header) * num_header_strings); for (size_t i = 0; i < num_header_strings; ++i) { char* sep = strchr(header_strings[i], ':'); if (sep == NULL) { gpr_log(GPR_ERROR, "skipping unparseable HTTP CONNECT header: %s", header_strings[i]); continue; } *sep = '\0'; headers[num_headers].key = header_strings[i]; headers[num_headers].value = sep + 1; ++num_headers; } } // Save state in the handshaker object. gpr_mu_lock(&handshaker->mu); handshaker->args = args; handshaker->on_handshake_done = on_handshake_done; // Log connection via proxy. char* proxy_name = grpc_endpoint_get_peer(args->endpoint); gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s", server_name, proxy_name); gpr_free(proxy_name); // Construct HTTP CONNECT request. grpc_httpcli_request request; memset(&request, 0, sizeof(request)); request.host = server_name; request.http.method = "CONNECT"; request.http.path = server_name; request.http.hdrs = headers; request.http.hdr_count = num_headers; request.handshaker = &grpc_httpcli_plaintext; grpc_slice request_slice = grpc_httpcli_format_connect_request(&request); grpc_slice_buffer_add(&handshaker->write_buffer, request_slice); // Clean up. gpr_free(headers); for (size_t i = 0; i < num_header_strings; ++i) { gpr_free(header_strings[i]); } gpr_free(header_strings); // Take a new ref to be held by the write callback. gpr_ref(&handshaker->refcount); grpc_endpoint_write(exec_ctx, args->endpoint, &handshaker->write_buffer, &handshaker->request_done_closure); gpr_mu_unlock(&handshaker->mu); }
static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx, grpc_lb_policy_factory *factory, grpc_lb_policy_args *args) { GPR_ASSERT(args->client_channel_factory != NULL); /* Get server name. */ const grpc_arg *arg = grpc_channel_args_find(args->args, GRPC_ARG_SERVER_NAME); const char *server_name = arg != NULL && arg->type == GRPC_ARG_STRING ? arg->value.string : NULL; /* Find the number of backend addresses. We ignore balancer * addresses, since we don't know how to handle them. */ arg = grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER); grpc_lb_addresses *addresses = arg->value.pointer.p; size_t num_addrs = 0; for (size_t i = 0; i < addresses->num_addresses; i++) { if (!addresses->addresses[i].is_balancer) ++num_addrs; } if (num_addrs == 0) return NULL; round_robin_lb_policy *p = gpr_malloc(sizeof(*p)); memset(p, 0, sizeof(*p)); p->num_addresses = num_addrs; p->subchannels = gpr_malloc(sizeof(*p->subchannels) * num_addrs); memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs); grpc_subchannel_args sc_args; size_t subchannel_idx = 0; for (size_t i = 0; i < addresses->num_addresses; i++) { /* Skip balancer addresses, since we only know how to handle backends. */ if (addresses->addresses[i].is_balancer) continue; memset(&sc_args, 0, sizeof(grpc_subchannel_args)); /* server_name will be copied as part of the subchannel creation. This makes * the copying of server_name (a borrowed pointer) OK. */ sc_args.server_name = server_name; sc_args.addr = &addresses->addresses[i].address; sc_args.args = args->args; grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( exec_ctx, args->client_channel_factory, &sc_args); if (subchannel != NULL) { subchannel_data *sd = gpr_malloc(sizeof(*sd)); memset(sd, 0, sizeof(*sd)); p->subchannels[subchannel_idx] = sd; sd->policy = p; sd->index = subchannel_idx; sd->subchannel = subchannel; sd->user_data_vtable = addresses->user_data_vtable; if (sd->user_data_vtable != NULL) { sd->user_data = sd->user_data_vtable->copy(addresses->addresses[i].user_data); } ++subchannel_idx; grpc_closure_init(&sd->connectivity_changed_closure, rr_connectivity_changed, sd); } } if (subchannel_idx == 0) { /* couldn't create any subchannel. Bail out */ gpr_free(p->subchannels); gpr_free(p); return NULL; } p->num_subchannels = subchannel_idx; /* The (dummy node) root of the ready list */ p->ready_list.subchannel = NULL; p->ready_list.prev = NULL; p->ready_list.next = NULL; p->ready_list_last_pick = &p->ready_list; grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable); grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, "round_robin"); if (grpc_lb_round_robin_trace) { gpr_log(GPR_DEBUG, "Created RR policy at %p with %lu subchannels", (void *)p, (unsigned long)p->num_subchannels); } gpr_mu_init(&p->mu); return &p->base; }
static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx, grpc_lb_policy_factory *factory, grpc_lb_policy_args *args) { GPR_ASSERT(args->client_channel_factory != NULL); /* Get server name. */ const grpc_arg *arg = grpc_channel_args_find(args->args, GRPC_ARG_SERVER_NAME); const char *server_name = arg != NULL && arg->type == GRPC_ARG_STRING ? arg->value.string : NULL; /* Find the number of backend addresses. We ignore balancer * addresses, since we don't know how to handle them. */ arg = grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER); grpc_lb_addresses *addresses = arg->value.pointer.p; size_t num_addrs = 0; for (size_t i = 0; i < addresses->num_addresses; i++) { if (!addresses->addresses[i].is_balancer) ++num_addrs; } if (num_addrs == 0) return NULL; pick_first_lb_policy *p = gpr_malloc(sizeof(*p)); memset(p, 0, sizeof(*p)); p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * num_addrs); memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs); grpc_subchannel_args sc_args; size_t subchannel_idx = 0; for (size_t i = 0; i < addresses->num_addresses; i++) { /* Skip balancer addresses, since we only know how to handle backends. */ if (addresses->addresses[i].is_balancer) continue; if (addresses->addresses[i].user_data != NULL) { gpr_log(GPR_ERROR, "This LB policy doesn't support user data. It will be ignored"); } memset(&sc_args, 0, sizeof(grpc_subchannel_args)); /* server_name will be copied as part of the subchannel creation. This makes * the copying of server_name (a borrowed pointer) OK. */ sc_args.server_name = server_name; sc_args.addr = &addresses->addresses[i].address; sc_args.args = args->args; grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( exec_ctx, args->client_channel_factory, &sc_args); if (subchannel != NULL) { p->subchannels[subchannel_idx++] = subchannel; } } if (subchannel_idx == 0) { gpr_free(p->subchannels); gpr_free(p); return NULL; } p->num_subchannels = subchannel_idx; grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable); grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p); gpr_mu_init(&p->mu); return &p->base; }