static grpc_resolver *sockaddr_create( grpc_resolver_args *args, const char *default_lb_policy_name, int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) { bool errors_found = false; sockaddr_resolver *r; gpr_slice path_slice; gpr_slice_buffer path_parts; if (0 != strcmp(args->uri->authority, "")) { gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme", args->uri->scheme); return NULL; } r = gpr_malloc(sizeof(sockaddr_resolver)); memset(r, 0, sizeof(*r)); r->lb_policy_name = gpr_strdup(grpc_uri_get_query_arg(args->uri, "lb_policy")); const char *lb_enabled_qpart = grpc_uri_get_query_arg(args->uri, "lb_enabled"); /* anything other than "0" is interpreted as true */ const bool lb_enabled = (lb_enabled_qpart != NULL && (strcmp("0", lb_enabled_qpart) != 0)); if (r->lb_policy_name != NULL && strcmp("grpclb", r->lb_policy_name) == 0 && !lb_enabled) { /* we want grpclb but the "resolved" addresses aren't LB enabled. Bail * out, as this is meant mostly for tests. */ gpr_log(GPR_ERROR, "Requested 'grpclb' LB policy but resolved addresses don't " "support load balancing."); abort(); } if (r->lb_policy_name == NULL) { r->lb_policy_name = gpr_strdup(default_lb_policy_name); } path_slice = gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing); gpr_slice_buffer_init(&path_parts); gpr_slice_split(path_slice, ",", &path_parts); r->addresses = grpc_lb_addresses_create(path_parts.count); for (size_t i = 0; i < r->addresses->num_addresses; i++) { grpc_uri ith_uri = *args->uri; char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII); ith_uri.path = part_str; if (!parse(&ith_uri, (struct sockaddr_storage *)(&r->addresses->addresses[i] .address.addr), &r->addresses->addresses[i].address.len)) { errors_found = true; } gpr_free(part_str); r->addresses->addresses[i].is_balancer = lb_enabled; if (errors_found) break; } r->target_name = gpr_strdup(args->uri->path); gpr_slice_buffer_destroy(&path_parts); gpr_slice_unref(path_slice); if (errors_found) { gpr_free(r->lb_policy_name); gpr_free(r->target_name); grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */); gpr_free(r); return NULL; } gpr_ref_init(&r->refs, 1); gpr_mu_init(&r->mu); grpc_resolver_init(&r->base, &sockaddr_resolver_vtable); return &r->base; }
static int normal_state(gpr_cmdline *cl, char *str) { char *eq = NULL; char *tmp = NULL; char *arg_name = NULL; int r = 1; if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") || 0 == strcmp(str, "-h")) { return print_usage_and_die(cl); } cl->cur_arg = NULL; if (str[0] == '-') { if (str[1] == '-') { if (str[2] == 0) { /* handle '--' to move to just extra args */ cl->state = extra_state; return 1; } str += 2; } else { str += 1; } /* first byte of str is now past the leading '-' or '--' */ if (str[0] == 'n' && str[1] == 'o' && str[2] == '-') { /* str is of the form '--no-foo' - it's a flag disable */ str += 3; cl->cur_arg = find_arg(cl, str); if (cl->cur_arg == NULL) { return print_usage_and_die(cl); } if (cl->cur_arg->type != ARGTYPE_BOOL) { fprintf(stderr, "%s is not a flag argument\n", str); return print_usage_and_die(cl); } *(int *)cl->cur_arg->value = 0; return 1; /* early out */ } eq = strchr(str, '='); if (eq != NULL) { /* copy the string into a temp buffer and extract the name */ tmp = arg_name = gpr_malloc((size_t)(eq - str + 1)); memcpy(arg_name, str, (size_t)(eq - str)); arg_name[eq - str] = 0; } else { arg_name = str; } cl->cur_arg = find_arg(cl, arg_name); if (cl->cur_arg == NULL) { return print_usage_and_die(cl); } if (eq != NULL) { /* str was of the type --foo=value, parse the value */ r = value_state(cl, eq + 1); } else if (cl->cur_arg->type != ARGTYPE_BOOL) { /* flag types don't have a '--foo value' variant, other types do */ cl->state = value_state; } else { /* flag parameter: just set the value */ *(int *)cl->cur_arg->value = 1; } } else { r = extra_state(cl, str); } gpr_free(tmp); return r; }
grpc_resolved_addresses *grpc_blocking_resolve_address( const char *name, const char *default_port) { struct addrinfo hints; struct addrinfo *result = NULL, *resp; char *host; char *port; int s; size_t i; grpc_resolved_addresses *addrs = NULL; struct sockaddr_un *un; if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' && name[4] == ':' && name[5] != 0) { addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); addrs->naddrs = 1; addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address)); un = (struct sockaddr_un *)addrs->addrs->addr; un->sun_family = AF_UNIX; strcpy(un->sun_path, name + 5); addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; return addrs; } /* parse name, splitting it into host and port parts */ gpr_split_host_port(name, &host, &port); if (host == NULL) { gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); goto done; } if (port == NULL) { if (default_port == NULL) { gpr_log(GPR_ERROR, "no port in name '%s'", name); goto done; } port = gpr_strdup(default_port); } /* Call getaddrinfo */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ hints.ai_socktype = SOCK_STREAM; /* stream socket */ hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ s = getaddrinfo(host, port, &hints, &result); if (s != 0) { /* Retry if well-known service name is recognized */ char *svc[][2] = {{"http", "80"}, {"https", "443"}}; int i; for (i = 0; i < (int)(sizeof(svc) / sizeof(svc[0])); i++) { if (strcmp(port, svc[i][0]) == 0) { s = getaddrinfo(host, svc[i][1], &hints, &result); break; } } } if (s != 0) { gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s)); goto done; } /* Success path: set addrs non-NULL, fill it in */ addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); addrs->naddrs = 0; for (resp = result; resp != NULL; resp = resp->ai_next) { addrs->naddrs++; } addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs); i = 0; for (resp = result; resp != NULL; resp = resp->ai_next) { memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); addrs->addrs[i].len = resp->ai_addrlen; i++; } done: gpr_free(host); gpr_free(port); if (result) { freeaddrinfo(result); } return addrs; }
/* Initiates a write. */ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, gpr_slice_buffer *slices, grpc_closure *cb) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_winsocket *socket = tcp->socket; grpc_winsocket_callback_info *info = &socket->write_info; unsigned i; DWORD bytes_sent; int status; WSABUF local_buffers[16]; WSABUF *allocated = NULL; WSABUF *buffers = local_buffers; size_t len; if (tcp->shutting_down) { grpc_exec_ctx_enqueue(exec_ctx, cb, 0); return; } tcp->write_cb = cb; tcp->write_slices = slices; GPR_ASSERT(tcp->write_slices->count <= UINT_MAX); if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) { buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count); allocated = buffers; } for (i = 0; i < tcp->write_slices->count; i++) { len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]); GPR_ASSERT(len <= ULONG_MAX); buffers[i].len = (ULONG)len; buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]); } /* First, let's try a synchronous, non-blocking write. */ status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count, &bytes_sent, 0, NULL, NULL); info->wsa_error = status == 0 ? 0 : WSAGetLastError(); /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy connection that has its send queue filled up. But if we don't, then we can avoid doing an async write operation at all. */ if (info->wsa_error != WSAEWOULDBLOCK) { int ok = 0; if (status == 0) { ok = 1; GPR_ASSERT(bytes_sent == tcp->write_slices->length); } else { if (socket->read_info.wsa_error != WSAECONNRESET) { char *utf8_message = gpr_format_message(info->wsa_error); gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message); gpr_free(utf8_message); } } if (allocated) gpr_free(allocated); grpc_exec_ctx_enqueue(exec_ctx, cb, ok); return; } TCP_REF(tcp, "write"); /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same operation, this time asynchronously. */ memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED)); status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count, &bytes_sent, 0, &socket->write_info.overlapped, NULL); if (allocated) gpr_free(allocated); if (status != 0) { int wsa_error = WSAGetLastError(); if (wsa_error != WSA_IO_PENDING) { TCP_UNREF(tcp, "write"); grpc_exec_ctx_enqueue(exec_ctx, cb, 0); return; } } /* As all is now setup, we can now ask for the IOCP notification. It may trigger the callback immediately however, but no matter. */ grpc_socket_notify_on_write(exec_ctx, socket, &tcp->on_write); }
grpc_channel *grpc_channel_create_from_filters( grpc_exec_ctx *exec_ctx, const char *target, const grpc_channel_filter **filters, size_t num_filters, const grpc_channel_args *args, int is_client) { size_t i; size_t size = sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters); grpc_channel *channel = gpr_malloc(size); memset(channel, 0, sizeof(*channel)); channel->target = gpr_strdup(target); GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); channel->is_client = is_client; /* decremented by grpc_channel_destroy */ gpr_ref_init(&channel->refs, 1); gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = NULL; channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH; if (args) { for (i = 0; i < args->num_args; i++) { if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) { if (args->args[i].type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s ignored: it must be an integer", GRPC_ARG_MAX_MESSAGE_LENGTH); } else if (args->args[i].value.integer < 0) { gpr_log(GPR_ERROR, "%s ignored: it must be >= 0", GRPC_ARG_MAX_MESSAGE_LENGTH); } else { channel->max_message_length = (gpr_uint32)args->args[i].value.integer; } } else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) { if (args->args[i].type != GRPC_ARG_STRING) { gpr_log(GPR_ERROR, "%s: must be an string", GRPC_ARG_DEFAULT_AUTHORITY); } else { if (channel->default_authority) { /* setting this takes precedence over anything else */ GRPC_MDELEM_UNREF(channel->default_authority); } channel->default_authority = grpc_mdelem_from_strings( ":authority", args->args[i].value.string); } } else if (0 == strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { if (args->args[i].type != GRPC_ARG_STRING) { gpr_log(GPR_ERROR, "%s: must be an string", GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); } else { if (channel->default_authority) { /* other ways of setting this (notably ssl) take precedence */ gpr_log(GPR_ERROR, "%s: default host already set some other way", GRPC_ARG_DEFAULT_AUTHORITY); } else { channel->default_authority = grpc_mdelem_from_strings( ":authority", args->args[i].value.string); } } } } } if (channel->is_client && channel->default_authority == NULL && target != NULL) { char *default_authority = grpc_get_default_authority(target); if (default_authority) { channel->default_authority = grpc_mdelem_from_strings(":authority", default_authority); } gpr_free(default_authority); } grpc_channel_stack_init(exec_ctx, filters, num_filters, channel, args, CHANNEL_STACK_FROM_CHANNEL(channel)); return channel; }
void grpc_mdctx_global_init(void) { size_t i, j; if (!g_forced_hash_seed) { g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec; } g_static_strtab_maxprobe = 0; g_static_mdtab_maxprobe = 0; /* build static tables */ memset(g_static_mdtab, 0, sizeof(g_static_mdtab)); memset(g_static_strtab, 0, sizeof(g_static_strtab)); for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) { grpc_mdstr *elem = &grpc_static_mdstr_table[i]; const char *str = grpc_static_metadata_strings[i]; uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed); *(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str); *(uint32_t *)&elem->hash = hash; for (j = 0;; j++) { size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab); if (g_static_strtab[idx] == NULL) { g_static_strtab[idx] = &grpc_static_mdstr_table[i]; break; } } if (j > g_static_strtab_maxprobe) { g_static_strtab_maxprobe = j; } } for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) { grpc_mdelem *elem = &grpc_static_mdelem_table[i]; grpc_mdstr *key = &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]]; grpc_mdstr *value = &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]]; uint32_t hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash); *(grpc_mdstr **)&elem->key = key; *(grpc_mdstr **)&elem->value = value; for (j = 0;; j++) { size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab); if (g_static_mdtab[idx] == NULL) { g_static_mdtab[idx] = elem; break; } } if (j > g_static_mdtab_maxprobe) { g_static_mdtab_maxprobe = j; } } /* initialize shards */ for (i = 0; i < STRTAB_SHARD_COUNT; i++) { strtab_shard *shard = &g_strtab_shard[i]; gpr_mu_init(&shard->mu); shard->count = 0; shard->capacity = INITIAL_STRTAB_CAPACITY; shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity); memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity); } for (i = 0; i < MDTAB_SHARD_COUNT; i++) { mdtab_shard *shard = &g_mdtab_shard[i]; gpr_mu_init(&shard->mu); shard->count = 0; shard->free = 0; shard->capacity = INITIAL_MDTAB_CAPACITY; shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity); memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity); } }
/* Request with a large amount of metadata.*/ static void test_request_with_large_metadata(grpc_end2end_test_config config) { grpc_call *c; grpc_call *s; gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world"); grpc_byte_buffer *request_payload = grpc_byte_buffer_create(&request_payload_slice, 1); gpr_timespec deadline = five_seconds_time(); grpc_metadata meta; grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq); grpc_op ops[6]; grpc_op *op; grpc_metadata_array initial_metadata_recv; grpc_metadata_array trailing_metadata_recv; grpc_metadata_array request_metadata_recv; grpc_byte_buffer *request_payload_recv = NULL; grpc_call_details call_details; grpc_status_code status; char *details = NULL; size_t details_capacity = 0; int was_cancelled = 2; const int large_size = 64 * 1024; c = grpc_channel_create_call(f.client, f.client_cq, "/foo", "foo.test.google.fr", deadline); GPR_ASSERT(c); meta.key = "key"; meta.value = gpr_malloc(large_size + 1); memset((char *)meta.value, 'a', large_size); ((char *)meta.value)[large_size] = 0; meta.value_length = large_size; grpc_metadata_array_init(&initial_metadata_recv); grpc_metadata_array_init(&trailing_metadata_recv); grpc_metadata_array_init(&request_metadata_recv); grpc_call_details_init(&call_details); op = ops; op->op = GRPC_OP_SEND_INITIAL_METADATA; op->data.send_initial_metadata.count = 1; op->data.send_initial_metadata.metadata = &meta; op++; op->op = GRPC_OP_SEND_MESSAGE; op->data.send_message = request_payload; op++; op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; op++; op->op = GRPC_OP_RECV_INITIAL_METADATA; op->data.recv_initial_metadata = &initial_metadata_recv; op++; op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; op->data.recv_status_on_client.status = &status; op->data.recv_status_on_client.status_details = &details; op->data.recv_status_on_client.status_details_capacity = &details_capacity; op++; GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1))); GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s, &call_details, &request_metadata_recv, f.server_cq, tag(101))); cq_expect_completion(v_server, tag(101), GRPC_OP_OK); cq_verify(v_server); op = ops; op->op = GRPC_OP_SEND_INITIAL_METADATA; op->data.send_initial_metadata.count = 0; op++; op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; op->data.send_status_from_server.trailing_metadata_count = 0; op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED; op->data.send_status_from_server.status_details = "xyz"; op++; op->op = GRPC_OP_RECV_MESSAGE; op->data.recv_message = &request_payload_recv; op++; op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; op->data.recv_close_on_server.cancelled = &was_cancelled; op++; GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102))); cq_expect_completion(v_server, tag(102), GRPC_OP_OK); cq_verify(v_server); cq_expect_completion(v_client, tag(1), GRPC_OP_OK); cq_verify(v_client); GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); GPR_ASSERT(0 == strcmp(details, "xyz")); GPR_ASSERT(0 == strcmp(call_details.method, "/foo")); GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr")); GPR_ASSERT(was_cancelled == 0); GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world")); GPR_ASSERT(contains_metadata(&request_metadata_recv, "key", meta.value)); gpr_free(details); grpc_metadata_array_destroy(&initial_metadata_recv); grpc_metadata_array_destroy(&trailing_metadata_recv); grpc_metadata_array_destroy(&request_metadata_recv); grpc_call_details_destroy(&call_details); grpc_call_destroy(c); grpc_call_destroy(s); cq_verifier_destroy(v_client); cq_verifier_destroy(v_server); grpc_byte_buffer_destroy(request_payload); grpc_byte_buffer_destroy(request_payload_recv); gpr_free((char *)meta.value); end_test(&f); config.tear_down_data(&f); }
/* event manager callback when reads are ready */ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) { grpc_tcp_listener *sp = arg; if (err != GRPC_ERROR_NONE) { goto error; } grpc_pollset *read_notifier_pollset = sp->server->pollsets[(size_t)gpr_atm_no_barrier_fetch_add( &sp->server->next_pollset_to_assign, 1) % sp->server->pollset_count]; /* loop until accept4 returns EAGAIN, and then re-arm notification */ for (;;) { grpc_resolved_address addr; char *addr_str; char *name; addr.len = sizeof(struct sockaddr_storage); /* Note: If we ever decide to return this address to the user, remember to strip off the ::ffff:0.0.0.0/96 prefix first. */ int fd = grpc_accept4(sp->fd, &addr, 1, 1); if (fd < 0) { switch (errno) { case EINTR: continue; case EAGAIN: grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); return; default: gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno)); goto error; } } grpc_set_socket_no_sigpipe_if_possible(fd); addr_str = grpc_sockaddr_to_uri(&addr); gpr_asprintf(&name, "tcp-server-connection:%s", addr_str); if (grpc_tcp_trace) { gpr_log(GPR_DEBUG, "SERVER_CONNECT: incoming connection: %s", addr_str); } grpc_fd *fdobj = grpc_fd_create(fd, name); if (read_notifier_pollset == NULL) { gpr_log(GPR_ERROR, "Read notifier pollset is not set on the fd"); goto error; } grpc_pollset_add_fd(exec_ctx, read_notifier_pollset, fdobj); // Create acceptor. grpc_tcp_server_acceptor *acceptor = gpr_malloc(sizeof(*acceptor)); acceptor->from_server = sp->server; acceptor->port_index = sp->port_index; acceptor->fd_index = sp->fd_index; sp->server->on_accept_cb( exec_ctx, sp->server->on_accept_cb_arg, grpc_tcp_create(fdobj, sp->server->resource_quota, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str), read_notifier_pollset, acceptor); gpr_free(name); gpr_free(addr_str); } GPR_UNREACHABLE_CODE(return ); error: gpr_mu_lock(&sp->server->mu); if (0 == --sp->server->active_ports) { gpr_mu_unlock(&sp->server->mu); deactivated_all_ports(exec_ctx, sp->server); } else { gpr_mu_unlock(&sp->server->mu); } }
/** Returns connection sequence (server indices), which must be freed */ static int *perform_request(servers_fixture *f, grpc_channel *client, request_data *rdata, const test_spec *spec) { grpc_call *c; int s_idx; int *s_valid; grpc_op ops[6]; grpc_op *op; int was_cancelled; size_t i, iter_num; grpc_event ev; int read_tag; int *connection_sequence; int completed_client; s_valid = gpr_malloc(sizeof(int) * f->num_servers); connection_sequence = gpr_malloc(sizeof(int) * spec->num_iters); for (iter_num = 0; iter_num < spec->num_iters; iter_num++) { cq_verifier *cqv = cq_verifier_create(f->cq); rdata->details = NULL; rdata->details_capacity = 0; was_cancelled = 2; for (i = 0; i < f->num_servers; i++) { if (spec->kill_at[iter_num][i] != 0) { kill_server(f, i); } else if (spec->revive_at[iter_num][i] != 0) { /* killing takes precedence */ revive_server(f, rdata, i); } } connection_sequence[iter_num] = -1; grpc_metadata_array_init(&rdata->initial_metadata_recv); grpc_metadata_array_init(&rdata->trailing_metadata_recv); for (i = 0; i < f->num_servers; i++) { grpc_call_details_init(&rdata->call_details[i]); } memset(s_valid, 0, f->num_servers * sizeof(int)); c = grpc_channel_create_call(client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq, "/foo", "foo.test.google.fr", gpr_inf_future(GPR_CLOCK_REALTIME), NULL); GPR_ASSERT(c); completed_client = 0; memset(ops, 0, sizeof(ops)); op = ops; op->op = GRPC_OP_SEND_INITIAL_METADATA; op->data.send_initial_metadata.count = 0; op->flags = 0; op->reserved = NULL; op++; op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; op->flags = 0; op->reserved = NULL; op++; op->op = GRPC_OP_RECV_INITIAL_METADATA; op->data.recv_initial_metadata = &rdata->initial_metadata_recv; op->flags = 0; op->reserved = NULL; op++; op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; op->data.recv_status_on_client.trailing_metadata = &rdata->trailing_metadata_recv; op->data.recv_status_on_client.status = &rdata->status; op->data.recv_status_on_client.status_details = &rdata->details; op->data.recv_status_on_client.status_details_capacity = &rdata->details_capacity; op->flags = 0; op->reserved = NULL; op++; GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL)); s_idx = -1; while ( (ev = grpc_completion_queue_next( f->cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(10 * RETRY_TIMEOUT), NULL)) .type != GRPC_QUEUE_TIMEOUT) { GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); read_tag = ((int)(intptr_t)ev.tag); gpr_log(GPR_DEBUG, "EVENT: success:%d, type:%d, tag:%d iter:%" PRIuPTR, ev.success, ev.type, read_tag, iter_num); if (ev.success && read_tag >= 1000) { GPR_ASSERT(s_idx == -1); /* only one server must reply */ /* only server notifications for non-shutdown events */ s_idx = read_tag - 1000; s_valid[s_idx] = 1; connection_sequence[iter_num] = s_idx; break; } else if (read_tag == 1) { gpr_log(GPR_DEBUG, "client timed out"); GPR_ASSERT(ev.success); completed_client = 1; } } if (s_idx >= 0) { memset(ops, 0, sizeof(ops)); op = ops; op->op = GRPC_OP_SEND_INITIAL_METADATA; op->data.send_initial_metadata.count = 0; op->flags = 0; op->reserved = NULL; op++; op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; op->data.send_status_from_server.trailing_metadata_count = 0; op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED; op->data.send_status_from_server.status_details = "xyz"; op->flags = 0; op->reserved = NULL; op++; op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; op->data.recv_close_on_server.cancelled = &was_cancelled; op->flags = 0; op->reserved = NULL; op++; GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(f->server_calls[s_idx], ops, (size_t)(op - ops), tag(102), NULL)); cq_expect_completion(cqv, tag(102), 1); if (!completed_client) { cq_expect_completion(cqv, tag(1), 1); } cq_verify(cqv); gpr_log(GPR_DEBUG, "status=%d; %s", rdata->status, rdata->details); GPR_ASSERT(rdata->status == GRPC_STATUS_UNIMPLEMENTED); GPR_ASSERT(0 == strcmp(rdata->details, "xyz")); GPR_ASSERT(0 == strcmp(rdata->call_details[s_idx].method, "/foo")); GPR_ASSERT(0 == strcmp(rdata->call_details[s_idx].host, "foo.test.google.fr")); GPR_ASSERT(was_cancelled == 1); grpc_call_destroy(f->server_calls[s_idx]); /* ask for the next request on this server */ GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call( f->servers[s_idx], &f->server_calls[s_idx], &rdata->call_details[s_idx], &f->request_metadata_recv[s_idx], f->cq, f->cq, tag(1000 + (int)s_idx))); } else { /* no response from server */ grpc_call_cancel(c, NULL); if (!completed_client) { cq_expect_completion(cqv, tag(1), 1); cq_verify(cqv); } } GPR_ASSERT( grpc_completion_queue_next( f->cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(2 * RETRY_TIMEOUT), NULL) .type == GRPC_QUEUE_TIMEOUT); grpc_metadata_array_destroy(&rdata->initial_metadata_recv); grpc_metadata_array_destroy(&rdata->trailing_metadata_recv); cq_verifier_destroy(cqv); grpc_call_destroy(c); for (i = 0; i < f->num_servers; i++) { grpc_call_details_destroy(&rdata->call_details[i]); } gpr_free(rdata->details); } gpr_free(s_valid); return connection_sequence; }
grpc_client_security_context *grpc_client_security_context_create(void) { grpc_client_security_context *ctx = gpr_malloc(sizeof(grpc_client_security_context)); memset(ctx, 0, sizeof(grpc_client_security_context)); return ctx; }
grpc_security_status grpc_ssl_channel_security_connector_create( grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); const unsigned char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); unsigned char *alpn_protocol_string_lengths = gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); tsi_result result = TSI_OK; grpc_ssl_channel_security_connector *c; size_t i; const unsigned char *pem_root_certs; size_t pem_root_certs_size; char *port; for (i = 0; i < num_alpn_protocols; i++) { alpn_protocol_strings[i] = (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); alpn_protocol_string_lengths[i] = strlen(grpc_chttp2_get_alpn_version_index(i)); } if (config == NULL || target_name == NULL) { gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); goto error; } if (!check_request_metadata_creds(request_metadata_creds)) { goto error; } c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector)); memset(c, 0, sizeof(grpc_ssl_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.vtable = &ssl_channel_vtable; c->base.base.is_client_side = 1; c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); c->base.check_call_host = ssl_channel_check_call_host; gpr_split_host_port(target_name, &c->target_name, &port); gpr_free(port); if (overridden_target_name != NULL) { c->overridden_target_name = gpr_strdup(overridden_target_name); } if (config->pem_root_certs == NULL) { pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); if (pem_root_certs == NULL || pem_root_certs_size == 0) { gpr_log(GPR_ERROR, "Could not get default pem root certs."); goto error; } } else { pem_root_certs = config->pem_root_certs; pem_root_certs_size = config->pem_root_certs_size; } result = tsi_create_ssl_client_handshaker_factory( config->pem_private_key, config->pem_private_key_size, config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs, pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings, alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); ssl_channel_destroy(&c->base.base); *sc = NULL; goto error; } *sc = &c->base; gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_OK; error: gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_ERROR; }
static void test_strsplit(void) { gpr_slice_buffer *parts; gpr_slice str; LOG_TEST_NAME("test_strsplit"); parts = gpr_malloc(sizeof(gpr_slice_buffer)); gpr_slice_buffer_init(parts); str = gpr_slice_from_copied_string("one, two, three, four"); gpr_slice_split(str, ", ", parts); GPR_ASSERT(4 == parts->count); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "one")); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], "two")); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[2], "three")); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[3], "four")); gpr_slice_buffer_reset_and_unref(parts); gpr_slice_unref(str); /* separator not present in string */ str = gpr_slice_from_copied_string("one two three four"); gpr_slice_split(str, ", ", parts); GPR_ASSERT(1 == parts->count); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "one two three four")); gpr_slice_buffer_reset_and_unref(parts); gpr_slice_unref(str); /* separator at the end */ str = gpr_slice_from_copied_string("foo,"); gpr_slice_split(str, ",", parts); GPR_ASSERT(2 == parts->count); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "foo")); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], "")); gpr_slice_buffer_reset_and_unref(parts); gpr_slice_unref(str); /* separator at the beginning */ str = gpr_slice_from_copied_string(",foo"); gpr_slice_split(str, ",", parts); GPR_ASSERT(2 == parts->count); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "")); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], "foo")); gpr_slice_buffer_reset_and_unref(parts); gpr_slice_unref(str); /* standalone separator */ str = gpr_slice_from_copied_string(","); gpr_slice_split(str, ",", parts); GPR_ASSERT(2 == parts->count); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "")); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], "")); gpr_slice_buffer_reset_and_unref(parts); gpr_slice_unref(str); /* empty input */ str = gpr_slice_from_copied_string(""); gpr_slice_split(str, ", ", parts); GPR_ASSERT(1 == parts->count); GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "")); gpr_slice_buffer_reset_and_unref(parts); gpr_slice_unref(str); gpr_slice_buffer_destroy(parts); gpr_free(parts); }
grpc_channel *grpc_channel_create_from_filters( grpc_exec_ctx *exec_ctx, const char *target, const grpc_channel_filter **filters, size_t num_filters, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client) { size_t i; size_t size = sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters); grpc_channel *channel = gpr_malloc(size); memset(channel, 0, sizeof(*channel)); channel->target = gpr_strdup(target); GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); channel->is_client = is_client; /* decremented by grpc_channel_destroy */ gpr_ref_init(&channel->refs, 1); channel->metadata_context = mdctx; channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status", 0); channel->grpc_compression_algorithm_string = grpc_mdstr_from_string(mdctx, "grpc-encoding", 0); channel->grpc_encodings_accepted_by_peer_string = grpc_mdstr_from_string(mdctx, "grpc-accept-encoding", 0); channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message", 0); for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) { char buf[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa((long)i, buf); channel->grpc_status_elem[i] = grpc_mdelem_from_metadata_strings( mdctx, GRPC_MDSTR_REF(channel->grpc_status_string), grpc_mdstr_from_string(mdctx, buf, 0)); } channel->path_string = grpc_mdstr_from_string(mdctx, ":path", 0); channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority", 0); gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = NULL; channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH; if (args) { for (i = 0; i < args->num_args; i++) { if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) { if (args->args[i].type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s ignored: it must be an integer", GRPC_ARG_MAX_MESSAGE_LENGTH); } else if (args->args[i].value.integer < 0) { gpr_log(GPR_ERROR, "%s ignored: it must be >= 0", GRPC_ARG_MAX_MESSAGE_LENGTH); } else { channel->max_message_length = (gpr_uint32)args->args[i].value.integer; } } else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) { if (args->args[i].type != GRPC_ARG_STRING) { gpr_log(GPR_ERROR, "%s: must be an string", GRPC_ARG_DEFAULT_AUTHORITY); } else { if (channel->default_authority) { /* setting this takes precedence over anything else */ GRPC_MDELEM_UNREF(channel->default_authority); } channel->default_authority = grpc_mdelem_from_strings( mdctx, ":authority", args->args[i].value.string); } } else if (0 == strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { if (args->args[i].type != GRPC_ARG_STRING) { gpr_log(GPR_ERROR, "%s: must be an string", GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); } else { if (channel->default_authority) { /* other ways of setting this (notably ssl) take precedence */ gpr_log(GPR_ERROR, "%s: default host already set some other way", GRPC_ARG_DEFAULT_AUTHORITY); } else { channel->default_authority = grpc_mdelem_from_strings( mdctx, ":authority", args->args[i].value.string); } } } } } if (channel->is_client && channel->default_authority == NULL && target != NULL) { char *default_authority = grpc_get_default_authority(target); if (default_authority) { channel->default_authority = grpc_mdelem_from_strings( channel->metadata_context, ":authority", default_authority); } gpr_free(default_authority); } grpc_channel_stack_init(exec_ctx, filters, num_filters, channel, args, channel->metadata_context, CHANNEL_STACK_FROM_CHANNEL(channel)); return channel; }
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) { grpc_resolved_addresses *resolved = NULL; grpc_tcp_server *tcp = NULL; grpc_server_secure_state *state = NULL; size_t i; unsigned count = 0; int port_num = -1; int port_temp; grpc_security_status status = GRPC_SECURITY_ERROR; grpc_security_context *ctx = NULL; /* create security context */ if (creds == NULL) goto error; if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL) == 0) { status = grpc_ssl_server_security_context_create( grpc_ssl_server_credentials_get_config(creds), &ctx); } else if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) == 0) { ctx = grpc_fake_server_security_context_create(); status = GRPC_SECURITY_OK; } if (status != GRPC_SECURITY_OK) { gpr_log(GPR_ERROR, "Unable to create secure server with credentials of type %s.", creds->type); goto error; } /* resolve address */ resolved = grpc_blocking_resolve_address(addr, "https"); if (!resolved) { goto error; } tcp = grpc_tcp_server_create(); if (!tcp) { goto error; } for (i = 0; i < resolved->naddrs; i++) { port_temp = grpc_tcp_server_add_port( tcp, (struct sockaddr *)&resolved->addrs[i].addr, resolved->addrs[i].len); if (port_temp >= 0) { if (port_num == -1) { port_num = port_temp; } else { GPR_ASSERT(port_num == port_temp); } count++; } } if (count == 0) { gpr_log(GPR_ERROR, "No address added out of total %d resolved", resolved->naddrs); goto error; } if (count != resolved->naddrs) { gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", count, resolved->naddrs); /* if it's an error, don't we want to goto error; here ? */ } grpc_resolved_addresses_destroy(resolved); state = gpr_malloc(sizeof(*state)); state->server = server; state->tcp = tcp; state->ctx = ctx; state->is_shutdown = 0; gpr_mu_init(&state->mu); gpr_ref_init(&state->refcount, 1); /* Register with the server only upon success */ grpc_server_add_listener(server, state, start, destroy); return port_num; /* Error path: cleanup and return */ error: if (ctx) { grpc_security_context_unref(ctx); } if (resolved) { grpc_resolved_addresses_destroy(resolved); } if (tcp) { grpc_tcp_server_destroy(tcp, NULL, NULL); } if (state) { gpr_free(state); } return 0; }
void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep), void *arg, grpc_pollset_set *interested_parties, const struct sockaddr *addr, int addr_len, gpr_timespec deadline) { int fd; grpc_dualstack_mode dsmode; int err; async_connect *ac; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in addr4_copy; grpc_fd *fdobj; char *name; char *addr_str; /* Use dualstack sockets where available. */ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } if (dsmode == GRPC_DSMODE_IPV4) { /* If we got an AF_INET socket, map the address back to IPv4. */ GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy)); addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } if (!prepare_socket(addr, fd)) { cb(arg, NULL); return; } do { err = connect(fd, addr, addr_len); } while (err < 0 && errno == EINTR); addr_str = grpc_sockaddr_to_uri(addr); gpr_asprintf(&name, "tcp-client:%s", addr_str); fdobj = grpc_fd_create(fd, name); if (err >= 0) { cb(arg, grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str)); goto done; } if (errno != EWOULDBLOCK && errno != EINPROGRESS) { gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno)); grpc_fd_orphan(fdobj, NULL, "tcp_client_connect_error"); cb(arg, NULL); goto done; } grpc_pollset_set_add_fd(interested_parties, fdobj); ac = gpr_malloc(sizeof(async_connect)); ac->cb = cb; ac->cb_arg = arg; ac->fd = fdobj; ac->interested_parties = interested_parties; ac->addr_str = addr_str; addr_str = NULL; gpr_mu_init(&ac->mu); ac->refs = 2; ac->write_closure.cb = on_writable; ac->write_closure.cb_arg = ac; gpr_mu_lock(&ac->mu); grpc_alarm_init(&ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_fd_notify_on_write(ac->fd, &ac->write_closure); gpr_mu_unlock(&ac->mu); done: gpr_free(name); gpr_free(addr_str); }
static void verify_rebirth_round_robin(const servers_fixture *f, grpc_channel *client, const int *actual_connection_sequence, const size_t num_iters) { int *expected_connection_sequence; size_t i, j, unique_seq_last_idx, unique_seq_first_idx; const size_t expected_seq_length = f->num_servers; int *seen_elements; dump_array("actual_connection_sequence", actual_connection_sequence, num_iters); /* verify conn. seq. expectation */ /* get the first unique run of length "num_servers". */ expected_connection_sequence = gpr_malloc(sizeof(int) * expected_seq_length); seen_elements = gpr_malloc(sizeof(int) * expected_seq_length); unique_seq_last_idx = ~(size_t)0; memset(seen_elements, 0, sizeof(int) * expected_seq_length); for (i = 0; i < num_iters; i++) { if (actual_connection_sequence[i] < 0 || seen_elements[actual_connection_sequence[i]] != 0) { /* if anything breaks the uniqueness of the run, back to square zero */ memset(seen_elements, 0, sizeof(int) * expected_seq_length); continue; } seen_elements[actual_connection_sequence[i]] = 1; for (j = 0; j < expected_seq_length; j++) { if (seen_elements[j] == 0) break; } if (j == expected_seq_length) { /* seen all the elements */ unique_seq_last_idx = i; break; } } /* make sure we found a valid run */ dump_array("seen_elements", seen_elements, expected_seq_length); for (j = 0; j < expected_seq_length; j++) { GPR_ASSERT(seen_elements[j] != 0); } GPR_ASSERT(unique_seq_last_idx != ~(size_t)0); unique_seq_first_idx = (unique_seq_last_idx - expected_seq_length + 1); memcpy(expected_connection_sequence, actual_connection_sequence + unique_seq_first_idx, sizeof(int) * expected_seq_length); /* first iteration succeeds */ GPR_ASSERT(actual_connection_sequence[0] != -1); /* then we fail for a while... */ GPR_ASSERT(actual_connection_sequence[1] == -1); /* ... but should be up at "unique_seq_first_idx" */ GPR_ASSERT(actual_connection_sequence[unique_seq_first_idx] != -1); for (j = 0, i = unique_seq_first_idx; i < num_iters; i++) { const int actual = actual_connection_sequence[i]; const int expected = expected_connection_sequence[j++ % expected_seq_length]; if (actual != expected) { print_failed_expectations(expected_connection_sequence, actual_connection_sequence, expected_seq_length, num_iters); abort(); } } /* things are fine once the servers are brought back up */ assert_channel_connectivity(client, 1, GRPC_CHANNEL_READY); gpr_free(expected_connection_sequence); gpr_free(seen_elements); }
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); }
grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, const grpc_resolved_address *addr, int *port) { // This function is mostly copied from tcp_server_windows.c grpc_tcp_listener *sp = NULL; uv_tcp_t *handle; grpc_resolved_address addr6_v4mapped; grpc_resolved_address wildcard; grpc_resolved_address *allocated_addr = NULL; grpc_resolved_address sockname_temp; unsigned port_index = 0; int status; grpc_error *error = GRPC_ERROR_NONE; if (s->tail != NULL) { port_index = s->tail->port_index + 1; } /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ if (grpc_sockaddr_get_port(addr) == 0) { for (sp = s->head; sp; sp = sp->next) { sockname_temp.len = sizeof(struct sockaddr_storage); if (0 == uv_tcp_getsockname(sp->handle, (struct sockaddr *)&sockname_temp.addr, (int *)&sockname_temp.len)) { *port = grpc_sockaddr_get_port(&sockname_temp); if (*port > 0) { allocated_addr = gpr_malloc(sizeof(grpc_resolved_address)); memcpy(allocated_addr, addr, sizeof(grpc_resolved_address)); grpc_sockaddr_set_port(allocated_addr, *port); addr = allocated_addr; break; } } } } if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = &addr6_v4mapped; } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, port)) { grpc_sockaddr_make_wildcard6(*port, &wildcard); addr = &wildcard; } handle = gpr_malloc(sizeof(uv_tcp_t)); status = uv_tcp_init(uv_default_loop(), handle); if (status == 0) { error = add_socket_to_server(s, handle, addr, port_index, &sp); } else { error = GRPC_ERROR_CREATE("Failed to initialize UV tcp handle"); error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); } gpr_free(allocated_addr); if (error != GRPC_ERROR_NONE) { grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING( "Failed to add port to server", &error, 1); GRPC_ERROR_UNREF(error); error = error_out; *port = -1; } else { GPR_ASSERT(sp != NULL); *port = sp->port; } return error; }
static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem md) { grpc_chttp2_transport *t = tp; grpc_chttp2_stream *s = t->incoming_stream; GPR_TIMER_BEGIN("on_initial_header", 0); GPR_ASSERT(s != NULL); if (grpc_http_trace) { char *key = grpc_slice_to_c_string(GRPC_MDKEY(md)); char *value = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR", key, value); gpr_free(key); gpr_free(value); } if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { /* TODO(ctiller): check for a status like " 0" */ s->seen_error = true; } if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) { gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); gpr_timespec timeout; if (cached_timeout == NULL) { /* not already parsed: parse it now, and store the result away */ cached_timeout = gpr_malloc(sizeof(gpr_timespec)); if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), cached_timeout)) { char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val); gpr_free(val); *cached_timeout = gpr_inf_future(GPR_TIMESPAN); } timeout = *cached_timeout; grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); } else { timeout = *cached_timeout; } grpc_chttp2_incoming_metadata_buffer_set_deadline( &s->metadata_buffer[0], gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), timeout)); GRPC_MDELEM_UNREF(exec_ctx, md); } else { const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); const size_t metadata_size_limit = t->settings[GRPC_ACKED_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; if (new_size > metadata_size_limit) { gpr_log(GPR_DEBUG, "received initial metadata size exceeds limit (%" PRIuPTR " vs. %" PRIuPTR ")", new_size, metadata_size_limit); grpc_chttp2_cancel_stream( exec_ctx, t, s, grpc_error_set_int( GRPC_ERROR_CREATE_FROM_STATIC_STRING( "received initial metadata size exceeds limit"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); s->seen_error = true; GRPC_MDELEM_UNREF(exec_ctx, md); } else { grpc_error *error = grpc_chttp2_incoming_metadata_buffer_add( exec_ctx, &s->metadata_buffer[0], md); if (error != GRPC_ERROR_NONE) { grpc_chttp2_cancel_stream(exec_ctx, t, s, error); grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); s->seen_error = true; GRPC_MDELEM_UNREF(exec_ctx, md); } } } GPR_TIMER_END("on_initial_header", 0); }
// This test launches a gRPC server on a separate thread and then establishes a // TLS handshake via a minimal TLS client. The TLS client has configurable (via // alpn_list) ALPN settings and can probe at the supported ALPN preferences // using this (via alpn_expected). static bool server_ssl_test(const char *alpn_list[], unsigned int alpn_list_len, const char *alpn_expected) { bool success = true; grpc_init(); int port = grpc_pick_unused_port_or_die(); gpr_event_init(&client_handshake_complete); // Launch the gRPC server thread. gpr_thd_options thdopt = gpr_thd_options_default(); gpr_thd_id thdid; gpr_thd_options_set_joinable(&thdopt); GPR_ASSERT(gpr_thd_new(&thdid, server_thread, &port, &thdopt)); SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); const SSL_METHOD *method = TLSv1_2_client_method(); SSL_CTX *ctx = SSL_CTX_new(method); if (!ctx) { perror("Unable to create SSL context"); ERR_print_errors_fp(stderr); abort(); } // Load key pair. if (SSL_CTX_use_certificate_file(ctx, SSL_CERT_PATH, SSL_FILETYPE_PEM) < 0) { ERR_print_errors_fp(stderr); abort(); } if (SSL_CTX_use_PrivateKey_file(ctx, SSL_KEY_PATH, SSL_FILETYPE_PEM) < 0) { ERR_print_errors_fp(stderr); abort(); } // Set the cipher list to match the one expressed in // src/core/lib/tsi/ssl_transport_security.c. const char *cipher_list = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" "SHA384:ECDHE-RSA-AES256-GCM-SHA384"; if (!SSL_CTX_set_cipher_list(ctx, cipher_list)) { ERR_print_errors_fp(stderr); gpr_log(GPR_ERROR, "Couldn't set server cipher list."); abort(); } // Configure ALPN list the client will send to the server. This must match the // wire format, see documentation for SSL_CTX_set_alpn_protos. unsigned int alpn_protos_len = alpn_list_len; for (unsigned int i = 0; i < alpn_list_len; ++i) { alpn_protos_len += (unsigned int)strlen(alpn_list[i]); } unsigned char *alpn_protos = gpr_malloc(alpn_protos_len); unsigned char *p = alpn_protos; for (unsigned int i = 0; i < alpn_list_len; ++i) { const uint8_t len = (uint8_t)strlen(alpn_list[i]); *p++ = len; memcpy(p, alpn_list[i], len); p += len; } GPR_ASSERT(SSL_CTX_set_alpn_protos(ctx, alpn_protos, alpn_protos_len) == 0); // Try and connect to server. We allow a bounded number of retries as we might // be racing with the server setup on its separate thread. int retries = 10; int sock = -1; while (sock == -1 && retries-- > 0) { sock = create_socket(port); if (sock < 0) { sleep(1); } } GPR_ASSERT(sock > 0); gpr_log(GPR_INFO, "Connected to server on port %d", port); // Establish a SSL* and connect at SSL layer. SSL *ssl = SSL_new(ctx); GPR_ASSERT(ssl); SSL_set_fd(ssl, sock); if (SSL_connect(ssl) <= 0) { ERR_print_errors_fp(stderr); gpr_log(GPR_ERROR, "Handshake failed."); success = false; } else { gpr_log(GPR_INFO, "Handshake successful."); // Validate ALPN preferred by server matches alpn_expected. const unsigned char *alpn_selected; unsigned int alpn_selected_len; SSL_get0_alpn_selected(ssl, &alpn_selected, &alpn_selected_len); if (strlen(alpn_expected) != alpn_selected_len || strncmp((const char *)alpn_selected, alpn_expected, alpn_selected_len) != 0) { gpr_log(GPR_ERROR, "Unexpected ALPN protocol preference"); success = false; } } gpr_event_set(&client_handshake_complete, &client_handshake_complete); SSL_free(ssl); gpr_free(alpn_protos); SSL_CTX_free(ctx); EVP_cleanup(); close(sock); gpr_thd_join(thdid); grpc_shutdown(); return success; }
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->addresses != NULL); GPR_ASSERT(args->client_channel_factory != NULL); /* Find the number of backend addresses. We ignore balancer * addresses, since we don't know how to handle them. */ size_t num_addrs = 0; for (size_t i = 0; i < args->addresses->num_addresses; i++) { if (!args->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 < args->addresses->num_addresses; i++) { /* Skip balancer addresses, since we only know how to handle backends. */ if (args->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 args->server_name (a borrowed pointer) OK. */ sc_args.server_name = args->server_name; sc_args.addr = (struct sockaddr *)(&args->addresses->addresses[i].address.addr); sc_args.addr_len = args->addresses->addresses[i].address.len; sc_args.args = args->additional_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 = args->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"); gpr_mu_init(&p->mu); return &p->base; }
census_rpc_stats* census_rpc_stats_create_empty(void) { census_rpc_stats* ret = (census_rpc_stats*)gpr_malloc(sizeof(census_rpc_stats)); memset(ret, 0, sizeof(census_rpc_stats)); return ret; }
grpc_client_config *grpc_client_config_create() { grpc_client_config *c = gpr_malloc(sizeof(*c)); memset(c, 0, sizeof(*c)); gpr_ref_init(&c->refs, 1); return c; }
static grpc_resolver *sockaddr_create( grpc_resolver_args *args, const char *default_lb_policy_name, int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) { size_t i; int errors_found = 0; /* GPR_FALSE */ sockaddr_resolver *r; gpr_slice path_slice; gpr_slice_buffer path_parts; if (0 != strcmp(args->uri->authority, "")) { gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme", args->uri->scheme); return NULL; } r = gpr_malloc(sizeof(sockaddr_resolver)); memset(r, 0, sizeof(*r)); r->lb_policy_name = NULL; if (0 != strcmp(args->uri->query, "")) { gpr_slice query_slice; gpr_slice_buffer query_parts; query_slice = gpr_slice_new(args->uri->query, strlen(args->uri->query), do_nothing); gpr_slice_buffer_init(&query_parts); gpr_slice_split(query_slice, "=", &query_parts); GPR_ASSERT(query_parts.count == 2); if (0 == gpr_slice_str_cmp(query_parts.slices[0], "lb_policy")) { r->lb_policy_name = gpr_dump_slice(query_parts.slices[1], GPR_DUMP_ASCII); } gpr_slice_buffer_destroy(&query_parts); gpr_slice_unref(query_slice); } if (r->lb_policy_name == NULL) { r->lb_policy_name = gpr_strdup(default_lb_policy_name); } path_slice = gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing); gpr_slice_buffer_init(&path_parts); gpr_slice_split(path_slice, ",", &path_parts); r->num_addrs = path_parts.count; r->addrs = gpr_malloc(sizeof(struct sockaddr_storage) * r->num_addrs); r->addrs_len = gpr_malloc(sizeof(*r->addrs_len) * r->num_addrs); for (i = 0; i < r->num_addrs; i++) { grpc_uri ith_uri = *args->uri; char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII); ith_uri.path = part_str; if (!parse(&ith_uri, &r->addrs[i], &r->addrs_len[i])) { errors_found = 1; /* GPR_TRUE */ } gpr_free(part_str); if (errors_found) break; } gpr_slice_buffer_destroy(&path_parts); gpr_slice_unref(path_slice); if (errors_found) { gpr_free(r->lb_policy_name); gpr_free(r->addrs); gpr_free(r->addrs_len); gpr_free(r); return NULL; } gpr_ref_init(&r->refs, 1); gpr_mu_init(&r->mu); grpc_resolver_init(&r->base, &sockaddr_resolver_vtable); r->subchannel_factory = args->subchannel_factory; grpc_subchannel_factory_ref(r->subchannel_factory); return &r->base; }
grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, size_t addr_len, int *out_port) { grpc_tcp_listener *sp; grpc_tcp_listener *sp2 = NULL; int fd; grpc_dualstack_mode dsmode; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in wild4; struct sockaddr_in6 wild6; struct sockaddr_in addr4_copy; struct sockaddr *allocated_addr = NULL; struct sockaddr_storage sockname_temp; socklen_t sockname_len; int port; unsigned port_index = 0; unsigned fd_index = 0; grpc_error *errs[2] = {GRPC_ERROR_NONE, GRPC_ERROR_NONE}; if (s->tail != NULL) { port_index = s->tail->port_index + 1; } grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr); /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ if (grpc_sockaddr_get_port(addr) == 0) { for (sp = s->head; sp; sp = sp->next) { sockname_len = sizeof(sockname_temp); if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp, &sockname_len)) { port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); if (port > 0) { allocated_addr = gpr_malloc(addr_len); memcpy(allocated_addr, addr, addr_len); grpc_sockaddr_set_port(allocated_addr, port); addr = allocated_addr; break; } } } } sp = NULL; if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcards(port, &wild4, &wild6); /* Try listening on IPv6 first. */ addr = (struct sockaddr *)&wild6; addr_len = sizeof(wild6); errs[0] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd); if (errs[0] == GRPC_ERROR_NONE) { errs[0] = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index, &sp); if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { goto done; } if (sp != NULL) { ++fd_index; } /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ if (port == 0 && sp != NULL) { grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port); } } addr = (struct sockaddr *)&wild4; addr_len = sizeof(wild4); } errs[1] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd); if (errs[1] == GRPC_ERROR_NONE) { if (dsmode == GRPC_DSMODE_IPV4 && grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } sp2 = sp; errs[1] = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index, &sp); if (sp2 != NULL && sp != NULL) { sp2->sibling = sp; sp->is_sibling = 1; } } done: gpr_free(allocated_addr); if (sp != NULL) { *out_port = sp->port; GRPC_ERROR_UNREF(errs[0]); GRPC_ERROR_UNREF(errs[1]); return GRPC_ERROR_NONE; } else { *out_port = -1; char *addr_str = grpc_sockaddr_to_uri(addr); grpc_error *err = grpc_error_set_str( GRPC_ERROR_CREATE_REFERENCING("Failed to add port to server", errs, GPR_ARRAY_SIZE(errs)), GRPC_ERROR_STR_TARGET_ADDRESS, addr_str); GRPC_ERROR_UNREF(errs[0]); GRPC_ERROR_UNREF(errs[1]); gpr_free(addr_str); return err; } }
static void ssl_copy_key_material(const char *input, unsigned char **output, size_t *output_size) { *output_size = strlen(input); *output = gpr_malloc(*output_size); memcpy(*output, input, *output_size); }
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) { grpc_resolved_addresses *resolved = NULL; grpc_tcp_server *tcp = NULL; grpc_server_secure_state *state = NULL; size_t i; unsigned count = 0; int port_num = -1; int port_temp; grpc_security_status status = GRPC_SECURITY_ERROR; grpc_security_connector *sc = NULL; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GRPC_API_TRACE( "grpc_server_add_secure_http2_port(" "server=%p, addr=%s, creds=%p)", 3, (server, addr, creds)); /* create security context */ if (creds == NULL) goto error; status = grpc_server_credentials_create_security_connector(creds, &sc); if (status != GRPC_SECURITY_OK) { gpr_log(GPR_ERROR, "Unable to create secure server with credentials of type %s.", creds->type); goto error; } sc->channel_args = grpc_server_get_channel_args(server); /* resolve address */ resolved = grpc_blocking_resolve_address(addr, "https"); if (!resolved) { goto error; } state = gpr_malloc(sizeof(*state)); memset(state, 0, sizeof(*state)); grpc_closure_init(&state->destroy_closure, destroy_done, state); tcp = grpc_tcp_server_create(&state->destroy_closure); if (!tcp) { goto error; } state->server = server; state->tcp = tcp; state->sc = sc; state->creds = grpc_server_credentials_ref(creds); state->is_shutdown = 0; gpr_mu_init(&state->mu); gpr_ref_init(&state->refcount, 1); for (i = 0; i < resolved->naddrs; i++) { port_temp = grpc_tcp_server_add_port( tcp, (struct sockaddr *)&resolved->addrs[i].addr, resolved->addrs[i].len); if (port_temp > 0) { if (port_num == -1) { port_num = port_temp; } else { GPR_ASSERT(port_num == port_temp); } count++; } } if (count == 0) { gpr_log(GPR_ERROR, "No address added out of total %d resolved", resolved->naddrs); goto error; } if (count != resolved->naddrs) { gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", count, resolved->naddrs); /* if it's an error, don't we want to goto error; here ? */ } grpc_resolved_addresses_destroy(resolved); /* Register with the server only upon success */ grpc_server_add_listener(&exec_ctx, server, state, start, destroy); grpc_exec_ctx_finish(&exec_ctx); return port_num; /* Error path: cleanup and return */ error: if (resolved) { grpc_resolved_addresses_destroy(resolved); } if (tcp) { grpc_tcp_server_unref(&exec_ctx, tcp); } else { if (sc) { GRPC_SECURITY_CONNECTOR_UNREF(sc, "server"); } if (state) { gpr_free(state); } } grpc_exec_ctx_finish(&exec_ctx); return 0; }
grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( const grpc_httpcli_response *response, grpc_mdctx *ctx, grpc_mdelem **token_elem, gpr_timespec *token_lifetime) { char *null_terminated_body = NULL; char *new_access_token = NULL; grpc_credentials_status status = GRPC_CREDENTIALS_OK; grpc_json *json = NULL; if (response == NULL) { gpr_log(GPR_ERROR, "Received NULL response."); status = GRPC_CREDENTIALS_ERROR; goto end; } if (response->body_length > 0) { null_terminated_body = gpr_malloc(response->body_length + 1); null_terminated_body[response->body_length] = '\0'; memcpy(null_terminated_body, response->body, response->body_length); } if (response->status != 200) { gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].", response->status, null_terminated_body != NULL ? null_terminated_body : ""); status = GRPC_CREDENTIALS_ERROR; goto end; } else { grpc_json *access_token = NULL; grpc_json *token_type = NULL; grpc_json *expires_in = NULL; grpc_json *ptr; json = grpc_json_parse_string(null_terminated_body); if (json == NULL) { gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body); status = GRPC_CREDENTIALS_ERROR; goto end; } if (json->type != GRPC_JSON_OBJECT) { gpr_log(GPR_ERROR, "Response should be a JSON object"); status = GRPC_CREDENTIALS_ERROR; goto end; } for (ptr = json->child; ptr; ptr = ptr->next) { if (strcmp(ptr->key, "access_token") == 0) { access_token = ptr; } else if (strcmp(ptr->key, "token_type") == 0) { token_type = ptr; } else if (strcmp(ptr->key, "expires_in") == 0) { expires_in = ptr; } } if (access_token == NULL || access_token->type != GRPC_JSON_STRING) { gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON."); status = GRPC_CREDENTIALS_ERROR; goto end; } if (token_type == NULL || token_type->type != GRPC_JSON_STRING) { gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON."); status = GRPC_CREDENTIALS_ERROR; goto end; } if (expires_in == NULL || expires_in->type != GRPC_JSON_NUMBER) { gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON."); status = GRPC_CREDENTIALS_ERROR; goto end; } gpr_asprintf(&new_access_token, "%s %s", token_type->value, access_token->value); token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10); token_lifetime->tv_nsec = 0; if (*token_elem != NULL) grpc_mdelem_unref(*token_elem); *token_elem = grpc_mdelem_from_strings(ctx, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token); status = GRPC_CREDENTIALS_OK; } end: if (status != GRPC_CREDENTIALS_OK && (*token_elem != NULL)) { grpc_mdelem_unref(*token_elem); *token_elem = NULL; } if (null_terminated_body != NULL) gpr_free(null_terminated_body); if (new_access_token != NULL) gpr_free(new_access_token); if (json != NULL) grpc_json_destroy(json); return status; }
int pygrpc_produce_op(PyObject *op, grpc_op *result) { static const int OP_TUPLE_SIZE = 6; static const int STATUS_TUPLE_SIZE = 2; static const int TYPE_INDEX = 0; static const int INITIAL_METADATA_INDEX = 1; static const int TRAILING_METADATA_INDEX = 2; static const int MESSAGE_INDEX = 3; static const int STATUS_INDEX = 4; static const int STATUS_CODE_INDEX = 0; static const int STATUS_DETAILS_INDEX = 1; static const int WRITE_FLAGS_INDEX = 5; int type; Py_ssize_t message_size; char *message; char *status_details; gpr_slice message_slice; grpc_op c_op; if (!PyTuple_Check(op)) { PyErr_SetString(PyExc_TypeError, "expected tuple op"); return 0; } if (PyTuple_Size(op) != OP_TUPLE_SIZE) { char *buf; gpr_asprintf(&buf, "expected tuple op of length %d", OP_TUPLE_SIZE); PyErr_SetString(PyExc_ValueError, buf); gpr_free(buf); return 0; } type = PyInt_AsLong(PyTuple_GET_ITEM(op, TYPE_INDEX)); if (PyErr_Occurred()) { return 0; } c_op.op = type; c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX)); if (PyErr_Occurred()) { return 0; } switch (type) { case GRPC_OP_SEND_INITIAL_METADATA: if (!pygrpc_cast_pyseq_to_send_metadata( PyTuple_GetItem(op, INITIAL_METADATA_INDEX), &c_op.data.send_initial_metadata.metadata, &c_op.data.send_initial_metadata.count)) { return 0; } break; case GRPC_OP_SEND_MESSAGE: PyString_AsStringAndSize( PyTuple_GET_ITEM(op, MESSAGE_INDEX), &message, &message_size); message_slice = gpr_slice_from_copied_buffer(message, message_size); c_op.data.send_message = grpc_raw_byte_buffer_create(&message_slice, 1); gpr_slice_unref(message_slice); break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: /* Don't need to fill in any other fields. */ break; case GRPC_OP_SEND_STATUS_FROM_SERVER: if (!pygrpc_cast_pyseq_to_send_metadata( PyTuple_GetItem(op, TRAILING_METADATA_INDEX), &c_op.data.send_status_from_server.trailing_metadata, &c_op.data.send_status_from_server.trailing_metadata_count)) { return 0; } if (!PyTuple_Check(PyTuple_GET_ITEM(op, STATUS_INDEX))) { char *buf; gpr_asprintf(&buf, "expected tuple status in op of length %d", STATUS_TUPLE_SIZE); PyErr_SetString(PyExc_ValueError, buf); gpr_free(buf); return 0; } c_op.data.send_status_from_server.status = PyInt_AsLong( PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_CODE_INDEX)); status_details = PyString_AsString( PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_DETAILS_INDEX)); if (PyErr_Occurred()) { return 0; } c_op.data.send_status_from_server.status_details = gpr_malloc(strlen(status_details) + 1); strcpy((char *)c_op.data.send_status_from_server.status_details, status_details); break; case GRPC_OP_RECV_INITIAL_METADATA: c_op.data.recv_initial_metadata = gpr_malloc(sizeof(grpc_metadata_array)); grpc_metadata_array_init(c_op.data.recv_initial_metadata); break; case GRPC_OP_RECV_MESSAGE: c_op.data.recv_message = gpr_malloc(sizeof(grpc_byte_buffer *)); break; case GRPC_OP_RECV_STATUS_ON_CLIENT: c_op.data.recv_status_on_client.trailing_metadata = gpr_malloc(sizeof(grpc_metadata_array)); grpc_metadata_array_init(c_op.data.recv_status_on_client.trailing_metadata); c_op.data.recv_status_on_client.status = gpr_malloc(sizeof(grpc_status_code *)); c_op.data.recv_status_on_client.status_details = gpr_malloc(sizeof(char *)); *c_op.data.recv_status_on_client.status_details = NULL; c_op.data.recv_status_on_client.status_details_capacity = gpr_malloc(sizeof(size_t)); *c_op.data.recv_status_on_client.status_details_capacity = 0; break; case GRPC_OP_RECV_CLOSE_ON_SERVER: c_op.data.recv_close_on_server.cancelled = gpr_malloc(sizeof(int)); break; default: return 0; } *result = c_op; return 1; }
grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask, grpc_completion_queue *cq, const void *server_transport_data, grpc_mdelem **add_initial_metadata, size_t add_initial_metadata_count, gpr_timespec send_deadline) { size_t i, j; grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_call *call; GPR_TIMER_BEGIN("grpc_call_create", 0); call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); memset(call, 0, sizeof(grpc_call)); gpr_mu_init(&call->mu); call->channel = channel; call->cq = cq; call->parent = parent_call; call->is_client = server_transport_data == NULL; if (call->is_client) { GPR_ASSERT(add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT); for (i = 0; i < add_initial_metadata_count; i++) { call->send_extra_metadata[i].md = add_initial_metadata[i]; } call->send_extra_metadata_count = (int)add_initial_metadata_count; } else { GPR_ASSERT(add_initial_metadata_count == 0); call->send_extra_metadata_count = 0; } for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { call->metadata_batch[i][j].deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); } } call->send_deadline = send_deadline; GRPC_CHANNEL_INTERNAL_REF(channel, "call"); /* initial refcount dropped by grpc_call_destroy */ grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call, call->context, server_transport_data, CALL_STACK_FROM_CALL(call)); if (cq != NULL) { GRPC_CQ_INTERNAL_REF(cq, "bind"); grpc_call_stack_set_pollset(&exec_ctx, CALL_STACK_FROM_CALL(call), grpc_cq_pollset(cq)); } if (parent_call != NULL) { GRPC_CALL_INTERNAL_REF(parent_call, "child"); GPR_ASSERT(call->is_client); GPR_ASSERT(!parent_call->is_client); gpr_mu_lock(&parent_call->mu); if (propagation_mask & GRPC_PROPAGATE_DEADLINE) { send_deadline = gpr_time_min( gpr_convert_clock_type(send_deadline, parent_call->send_deadline.clock_type), parent_call->send_deadline); } /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with * GRPC_PROPAGATE_STATS_CONTEXT */ /* TODO(ctiller): This should change to use the appropriate census start_op * call. */ if (propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) { GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); grpc_call_context_set(call, GRPC_CONTEXT_TRACING, parent_call->context[GRPC_CONTEXT_TRACING].value, NULL); } else { GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); } if (propagation_mask & GRPC_PROPAGATE_CANCELLATION) { call->cancellation_is_inherited = 1; } if (parent_call->first_child == NULL) { parent_call->first_child = call; call->sibling_next = call->sibling_prev = call; } else { call->sibling_next = parent_call->first_child; call->sibling_prev = parent_call->first_child->sibling_prev; call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = call; } gpr_mu_unlock(&parent_call->mu); } if (gpr_time_cmp(send_deadline, gpr_inf_future(send_deadline.clock_type)) != 0) { set_deadline_alarm(&exec_ctx, call, send_deadline); } grpc_exec_ctx_finish(&exec_ctx); GPR_TIMER_END("grpc_call_create", 0); return call; }