static grpc_error *parse_frame_slice( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, gpr_slice slice, int is_last) { grpc_chttp2_stream_parsing *stream_parsing = transport_parsing->incoming_stream; grpc_error *err = transport_parsing->parser( exec_ctx, transport_parsing->parser_data, transport_parsing, stream_parsing, slice, is_last); if (err == GRPC_ERROR_NONE) { if (stream_parsing) { grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); } return GRPC_ERROR_NONE; } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) { if (grpc_http_trace) { const char *msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); grpc_error_free_string(msg); } grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing); if (stream_parsing) { stream_parsing->forced_close_error = err; gpr_slice_buffer_add( &transport_parsing->qbuf, grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, GRPC_CHTTP2_PROTOCOL_ERROR, &stream_parsing->stats.outgoing)); } else { GRPC_ERROR_UNREF(err); } } return err; }
static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint, grpc_channel_args *args, gpr_slice_buffer *read_buffer, void *user_data, grpc_error *error) { server_secure_connect *state = user_data; if (error != GRPC_ERROR_NONE) { const char *error_str = grpc_error_string(error); gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str); grpc_error_free_string(error_str); GRPC_ERROR_UNREF(error); grpc_channel_args_destroy(args); gpr_free(read_buffer); grpc_handshake_manager_shutdown(exec_ctx, state->handshake_mgr); grpc_handshake_manager_destroy(exec_ctx, state->handshake_mgr); state_unref(state->state); gpr_free(state); return; } grpc_handshake_manager_destroy(exec_ctx, state->handshake_mgr); state->handshake_mgr = NULL; // TODO(roth, jboeuf): Convert security connector handshaking to use new // handshake API, and then move the code from on_secure_handshake_done() // into this function. state->args = args; grpc_server_security_connector_do_handshake( exec_ctx, state->state->sc, state->acceptor, endpoint, read_buffer, state->deadline, on_secure_handshake_done, state); }
// If the handshake failed or we're shutting down, clean up and invoke the // callback with the error. static void security_handshake_failed_locked(grpc_exec_ctx *exec_ctx, security_handshaker *h, grpc_error *error) { if (error == GRPC_ERROR_NONE) { // If we were shut down after the handshake succeeded but before an // endpoint callback was invoked, we need to generate our own error. error = GRPC_ERROR_CREATE("Handshaker shutdown"); } const char *msg = grpc_error_string(error); gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg); grpc_error_free_string(msg); if (!h->shutdown) { // TODO(ctiller): It is currently necessary to shutdown endpoints // before destroying them, even if we know that there are no // pending read/write callbacks. This should be fixed, at which // point this can be removed. grpc_endpoint_shutdown(exec_ctx, h->args->endpoint); // Not shutting down, so the write failed. Clean up before // invoking the callback. cleanup_args_for_failure_locked(h); // Set shutdown to true so that subsequent calls to // security_handshaker_shutdown() do nothing. h->shutdown = true; } // Invoke callback. grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, error, NULL); }
static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, grpc_error *error) { grpc_tcp *tcp = (grpc_tcp *)arg; grpc_closure *cb; if (error != GRPC_ERROR_NONE) { cb = tcp->write_cb; tcp->write_cb = NULL; cb->cb(exec_ctx, cb->cb_arg, error); TCP_UNREF(exec_ctx, tcp, "write"); return; } if (!tcp_flush(tcp, &error)) { if (grpc_tcp_trace) { gpr_log(GPR_DEBUG, "write: delayed"); } grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); } else { cb = tcp->write_cb; tcp->write_cb = NULL; if (grpc_tcp_trace) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "write: %s", str); grpc_error_free_string(str); } grpc_closure_run(exec_ctx, cb, error); TCP_UNREF(exec_ctx, tcp, "write"); } }
static void security_handshake_done(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h, grpc_error *error) { grpc_timer_cancel(exec_ctx, &h->timer); if (!h->is_client_side) { security_connector_remove_handshake(h); } if (error == GRPC_ERROR_NONE) { h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint, h->auth_context); } else { const char *msg = grpc_error_string(error); gpr_log(GPR_ERROR, "Security handshake failed: %s", msg); grpc_error_free_string(msg); if (h->secure_endpoint != NULL) { grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint); grpc_endpoint_destroy(exec_ctx, h->secure_endpoint); } else { grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint); } h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL); } unref_handshake(h); GRPC_ERROR_UNREF(error); }
static void got_port_from_server(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { size_t i; int port = 0; portreq *pr = arg; int failed = 0; grpc_httpcli_response *response = &pr->response; if (error != GRPC_ERROR_NONE) { failed = 1; const char *msg = grpc_error_string(error); gpr_log(GPR_DEBUG, "failed port pick from server: retrying [%s]", msg); grpc_error_free_string(msg); } else if (response->status != 200) { failed = 1; gpr_log(GPR_DEBUG, "failed port pick from server: status=%d", response->status); } if (failed) { grpc_httpcli_request req; memset(&req, 0, sizeof(req)); GPR_ASSERT(pr->retries < 10); gpr_sleep_until(gpr_time_add( gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis( (int64_t)(1000.0 * (1 + pow(1.3, pr->retries) * rand() / RAND_MAX)), GPR_TIMESPAN))); pr->retries++; req.host = pr->server; req.http.path = "/get"; grpc_http_response_destroy(&pr->response); memset(&pr->response, 0, sizeof(pr->response)); grpc_resource_quota *resource_quota = grpc_resource_quota_create("port_server_client/pick_retry"); grpc_httpcli_get(exec_ctx, pr->ctx, &pr->pops, resource_quota, &req, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), grpc_closure_create(got_port_from_server, pr), &pr->response); grpc_resource_quota_internal_unref(exec_ctx, resource_quota); return; } GPR_ASSERT(response); GPR_ASSERT(response->status == 200); for (i = 0; i < response->body_length; i++) { GPR_ASSERT(response->body[i] >= '0' && response->body[i] <= '9'); port = port * 10 + response->body[i] - '0'; } GPR_ASSERT(port > 1024); gpr_mu_lock(pr->mu); pr->port = port; GRPC_LOG_IF_ERROR( "pollset_kick", grpc_pollset_kick(grpc_polling_entity_pollset(&pr->pops), NULL)); gpr_mu_unlock(pr->mu); }
// Helper function to shut down the proxy connection. // Does NOT take ownership of a reference to error. static void proxy_connection_failed(grpc_exec_ctx* exec_ctx, proxy_connection* conn, bool is_client, const char* prefix, grpc_error* error) { const char* msg = grpc_error_string(error); gpr_log(GPR_INFO, "%s: %s", prefix, msg); grpc_error_free_string(msg); grpc_endpoint_shutdown(exec_ctx, conn->client_endpoint); if (conn->server_endpoint != NULL) grpc_endpoint_shutdown(exec_ctx, conn->server_endpoint); proxy_connection_unref(exec_ctx, conn); }
static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, grpc_error *err) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; if (err == GRPC_ERROR_NONE) { server_filter_args a; a.elem = elem; a.exec_ctx = exec_ctx; grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, &a); /* Have we seen the required http2 transport headers? (:method, :scheme, content-type, with :path and :authority covered at the channel level right now) */ if (calld->seen_method && calld->seen_scheme && calld->seen_te_trailers && calld->seen_path && calld->seen_authority) { /* do nothing */ } else { err = GRPC_ERROR_CREATE("Bad incoming HTTP headers"); if (!calld->seen_path) { err = grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :path header")); } if (!calld->seen_authority) { err = grpc_error_add_child( err, GRPC_ERROR_CREATE("Missing :authority header")); } if (!calld->seen_method) { err = grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :method header")); } if (!calld->seen_scheme) { err = grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :scheme header")); } if (!calld->seen_te_trailers) { err = grpc_error_add_child( err, GRPC_ERROR_CREATE("Missing te: trailers header")); } /* Error this call out */ if (grpc_http_trace) { const char *error_str = grpc_error_string(err); gpr_log(GPR_ERROR, "Invalid http2 headers: %s", error_str); grpc_error_free_string(error_str); } grpc_call_element_send_cancel(exec_ctx, elem); } } else { GRPC_ERROR_REF(err); } calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, err); GRPC_ERROR_UNREF(err); }
static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_slice_buffer *buf, grpc_closure *cb) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_error *error = GRPC_ERROR_NONE; if (grpc_tcp_trace) { size_t i; for (i = 0; i < buf->count; i++) { char *data = grpc_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string, data); gpr_free(data); } } GPR_TIMER_BEGIN("tcp_write", 0); GPR_ASSERT(tcp->write_cb == NULL); if (buf->length == 0) { GPR_TIMER_END("tcp_write", 0); grpc_exec_ctx_sched(exec_ctx, cb, grpc_fd_is_shutdown(tcp->em_fd) ? tcp_annotate_error(GRPC_ERROR_CREATE("EOF"), tcp) : GRPC_ERROR_NONE, NULL); return; } tcp->outgoing_buffer = buf; tcp->outgoing_slice_idx = 0; tcp->outgoing_byte_idx = 0; if (!tcp_flush(tcp, &error)) { TCP_REF(tcp, "write"); tcp->write_cb = cb; if (grpc_tcp_trace) { gpr_log(GPR_DEBUG, "write: delayed"); } grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); } else { if (grpc_tcp_trace) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "write: %s", str); grpc_error_free_string(str); } grpc_exec_ctx_sched(exec_ctx, cb, error, NULL); } GPR_TIMER_END("tcp_write", 0); }
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_error *err = GRPC_ERROR_NONE; grpc_server_security_connector *sc = NULL; int port_num = 0; 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) { err = GRPC_ERROR_CREATE( "No credentials specified for secure server port (creds==NULL)"); goto done; } grpc_security_status status = grpc_server_credentials_create_security_connector(&exec_ctx, creds, &sc); if (status != GRPC_SECURITY_OK) { char *msg; gpr_asprintf(&msg, "Unable to create secure server with credentials of type %s.", creds->type); err = grpc_error_set_int(GRPC_ERROR_CREATE(msg), GRPC_ERROR_INT_SECURITY_STATUS, status); gpr_free(msg); goto done; } // Create channel args. grpc_arg args_to_add[2]; args_to_add[0] = grpc_server_credentials_to_arg(creds); args_to_add[1] = grpc_security_connector_to_arg(&sc->base); grpc_channel_args *args = grpc_channel_args_copy_and_add(grpc_server_get_channel_args(server), args_to_add, GPR_ARRAY_SIZE(args_to_add)); // Add server port. err = grpc_chttp2_server_add_port(&exec_ctx, server, addr, args, &port_num); done: if (sc != NULL) { GRPC_SECURITY_CONNECTOR_UNREF(&exec_ctx, &sc->base, "server"); } grpc_exec_ctx_finish(&exec_ctx); if (err != GRPC_ERROR_NONE) { const char *msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); grpc_error_free_string(msg); GRPC_ERROR_UNREF(err); } return port_num; }
static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { dns_resolver *r = arg; grpc_channel_args *result = NULL; gpr_mu_lock(&r->mu); GPR_ASSERT(r->resolving); r->resolving = false; if (r->addresses != NULL) { grpc_lb_addresses *addresses = grpc_lb_addresses_create( r->addresses->naddrs, NULL /* user_data_vtable */); for (size_t i = 0; i < r->addresses->naddrs; ++i) { grpc_lb_addresses_set_address( addresses, i, &r->addresses->addrs[i].addr, r->addresses->addrs[i].len, false /* is_balancer */, NULL /* balancer_name */, NULL /* user_data */); } grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses); result = grpc_channel_args_copy_and_add(r->channel_args, &new_arg, 1); grpc_resolved_addresses_destroy(r->addresses); grpc_lb_addresses_destroy(addresses); } else { gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now); gpr_timespec timeout = gpr_time_sub(next_try, now); const char *msg = grpc_error_string(error); gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg); grpc_error_free_string(msg); GPR_ASSERT(!r->have_retry_timer); r->have_retry_timer = true; GRPC_RESOLVER_REF(&r->base, "retry-timer"); if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) { gpr_log(GPR_DEBUG, "retrying in %" PRId64 ".%09d seconds", timeout.tv_sec, timeout.tv_nsec); } else { gpr_log(GPR_DEBUG, "retrying immediately"); } grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r, now); } if (r->resolved_result != NULL) { grpc_channel_args_destroy(r->resolved_result); } r->resolved_result = result; r->resolved_version++; dns_maybe_finish_next_locked(exec_ctx, r); gpr_mu_unlock(&r->mu); GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "dns-resolving"); }
static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_handshaker_args *args = arg; on_done_closure *c = args->user_data; if (error != GRPC_ERROR_NONE) { const char *msg = grpc_error_string(error); gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg); grpc_error_free_string(msg); c->func(exec_ctx, c->arg, NULL); } else { grpc_channel_args_destroy(args->args); grpc_slice_buffer_destroy(args->read_buffer); gpr_free(args->read_buffer); c->func(exec_ctx, c->arg, args->endpoint); } grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr); gpr_free(c); }
/* Queue a GRPC_OP_COMPLETED operation */ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, void *tag, grpc_error *error, void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, grpc_cq_completion *storage), void *done_arg, grpc_cq_completion *storage) { int shutdown; int i; grpc_pollset_worker *pluck_worker; #ifndef NDEBUG int found = 0; #endif GPR_TIMER_BEGIN("grpc_cq_end_op", 0); if (grpc_api_trace || (grpc_trace_operation_failures && error != GRPC_ERROR_NONE)) { const char *errmsg = grpc_error_string(error); GRPC_API_TRACE( "grpc_cq_end_op(exec_ctx=%p, cc=%p, tag=%p, error=%s, done=%p, " "done_arg=%p, storage=%p)", 7, (exec_ctx, cc, tag, errmsg, done, done_arg, storage)); if (grpc_trace_operation_failures) { gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg); } grpc_error_free_string(errmsg); } storage->tag = tag; storage->done = done; storage->done_arg = done_arg; storage->next = ((uintptr_t)&cc->completed_head) | ((uintptr_t)(error == GRPC_ERROR_NONE)); gpr_mu_lock(cc->mu); #ifndef NDEBUG for (i = 0; i < (int)cc->outstanding_tag_count; i++) { if (cc->outstanding_tags[i] == tag) { cc->outstanding_tag_count--; GPR_SWAP(void *, cc->outstanding_tags[i], cc->outstanding_tags[cc->outstanding_tag_count]); found = 1; break; } }
static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, grpc_error *error) { grpc_closure *cb = tcp->read_cb; if (grpc_tcp_trace) { size_t i; const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "read: error=%s", str); grpc_error_free_string(str); for (i = 0; i < tcp->incoming_buffer->count; i++) { char *dump = grpc_dump_slice(tcp->incoming_buffer->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string, dump); gpr_free(dump); } } tcp->read_cb = NULL; tcp->incoming_buffer = NULL; grpc_closure_run(exec_ctx, cb, error); }
static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { int done; async_connect *ac = acp; if (grpc_tcp_trace) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s", ac->addr_str, str); grpc_error_free_string(str); } gpr_mu_lock(&ac->mu); if (ac->fd != NULL) { grpc_fd_shutdown(exec_ctx, ac->fd); } done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (done) { gpr_mu_destroy(&ac->mu); gpr_free(ac->addr_str); grpc_channel_args_destroy(ac->channel_args); gpr_free(ac); } }
void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state, grpc_error *error, const char *reason) { grpc_connectivity_state_watcher *w; if (grpc_connectivity_state_trace) { const char *error_string = grpc_error_string(error); gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s] error=%p %s", tracker, tracker->name, grpc_connectivity_state_name(tracker->current_state), grpc_connectivity_state_name(state), reason, error, error_string); grpc_error_free_string(error_string); } switch (state) { case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_IDLE: case GRPC_CHANNEL_READY: GPR_ASSERT(error == GRPC_ERROR_NONE); break; case GRPC_CHANNEL_SHUTDOWN: case GRPC_CHANNEL_TRANSIENT_FAILURE: GPR_ASSERT(error != GRPC_ERROR_NONE); break; } GRPC_ERROR_UNREF(tracker->current_error); tracker->current_error = error; if (tracker->current_state == state) { return; } GPR_ASSERT(tracker->current_state != GRPC_CHANNEL_SHUTDOWN); tracker->current_state = state; while ((w = tracker->watchers) != NULL) { *w->current = tracker->current_state; tracker->watchers = w->next; grpc_exec_ctx_sched(exec_ctx, w->notify, GRPC_ERROR_REF(tracker->current_error), NULL); gpr_free(w); } }
static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { async_connect *ac = acp; int so_error = 0; socklen_t so_error_size; int err; int done; grpc_endpoint **ep = ac->ep; grpc_closure *closure = ac->closure; grpc_fd *fd; GRPC_ERROR_REF(error); if (grpc_tcp_trace) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: error=%s", ac->addr_str, str); grpc_error_free_string(str); } gpr_mu_lock(&ac->mu); GPR_ASSERT(ac->fd); fd = ac->fd; ac->fd = NULL; gpr_mu_unlock(&ac->mu); grpc_timer_cancel(exec_ctx, &ac->alarm); gpr_mu_lock(&ac->mu); if (error != GRPC_ERROR_NONE) { error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, "Timeout occurred"); goto finish; } do { so_error_size = sizeof(so_error); err = getsockopt(grpc_fd_wrapped_fd(fd), SOL_SOCKET, SO_ERROR, &so_error, &so_error_size); } while (err < 0 && errno == EINTR); if (err < 0) { error = GRPC_OS_ERROR(errno, "getsockopt"); goto finish; } switch (so_error) { case 0: grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); *ep = grpc_tcp_client_create_from_fd(exec_ctx, fd, ac->channel_args, ac->addr_str); fd = NULL; break; case ENOBUFS: /* We will get one of these errors if we have run out of memory in the kernel for the data structures allocated when you connect a socket. If this happens it is very likely that if we wait a little bit then try again the connection will work (since other programs or this program will close their network connections and free up memory). This does _not_ indicate that there is anything wrong with the server we are connecting to, this is a local problem. If you are looking at this code, then chances are that your program or another program on the same computer opened too many network connections. The "easy" fix: don't do that! */ gpr_log(GPR_ERROR, "kernel out of buffers"); gpr_mu_unlock(&ac->mu); grpc_fd_notify_on_write(exec_ctx, fd, &ac->write_closure); return; case ECONNREFUSED: /* This error shouldn't happen for anything other than connect(). */ error = GRPC_OS_ERROR(so_error, "connect"); break; default: /* We don't really know which syscall triggered the problem here, so punt by reporting getsockopt(). */ error = GRPC_OS_ERROR(so_error, "getsockopt(SO_ERROR)"); break; } finish: if (fd != NULL) { grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan"); fd = NULL; } done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (error != GRPC_ERROR_NONE) { error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION, "Failed to connect to remote host"); error = grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, ac->addr_str); } if (done) { gpr_mu_destroy(&ac->mu); gpr_free(ac->addr_str); grpc_channel_args_destroy(ac->channel_args); gpr_free(ac); } grpc_exec_ctx_sched(exec_ctx, closure, error, NULL); }
char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { char *tmp; char *out; gpr_strvec b; gpr_strvec_init(&b); gpr_strvec_add( &b, gpr_strdup(op->covered_by_poller ? "[COVERED]" : "[UNCOVERED]")); if (op->send_initial_metadata != NULL) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{")); put_metadata_list(&b, *op->send_initial_metadata); gpr_strvec_add(&b, gpr_strdup("}")); } if (op->send_message != NULL) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d", op->send_message->flags, op->send_message->length); gpr_strvec_add(&b, tmp); } if (op->send_trailing_metadata != NULL) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{")); put_metadata_list(&b, *op->send_trailing_metadata); gpr_strvec_add(&b, gpr_strdup("}")); } if (op->recv_initial_metadata != NULL) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA")); } if (op->recv_message != NULL) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); } if (op->recv_trailing_metadata != NULL) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("RECV_TRAILING_METADATA")); } if (op->cancel_error != GRPC_ERROR_NONE) { gpr_strvec_add(&b, gpr_strdup(" ")); const char *msg = grpc_error_string(op->cancel_error); gpr_asprintf(&tmp, "CANCEL:%s", msg); grpc_error_free_string(msg); gpr_strvec_add(&b, tmp); } if (op->close_error != GRPC_ERROR_NONE) { gpr_strvec_add(&b, gpr_strdup(" ")); const char *msg = grpc_error_string(op->close_error); gpr_asprintf(&tmp, "CLOSE:%s", msg); grpc_error_free_string(msg); gpr_strvec_add(&b, tmp); } out = gpr_strvec_flatten(&b, NULL); gpr_strvec_destroy(&b); return out; }
char *grpc_transport_op_string(grpc_transport_op *op) { char *tmp; char *out; bool first = true; gpr_strvec b; gpr_strvec_init(&b); if (op->on_connectivity_state_change != NULL) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = false; if (op->connectivity_state != NULL) { gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:from=%s", op->on_connectivity_state_change, grpc_connectivity_state_name(*op->connectivity_state)); gpr_strvec_add(&b, tmp); } else { gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:unsubscribe", op->on_connectivity_state_change); gpr_strvec_add(&b, tmp); } } if (op->disconnect_with_error != GRPC_ERROR_NONE) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = false; const char *err = grpc_error_string(op->disconnect_with_error); gpr_asprintf(&tmp, "DISCONNECT:%s", err); gpr_strvec_add(&b, tmp); grpc_error_free_string(err); } if (op->send_goaway) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = false; char *msg = op->goaway_message == NULL ? "null" : grpc_dump_slice(*op->goaway_message, GPR_DUMP_ASCII | GPR_DUMP_HEX); gpr_asprintf(&tmp, "SEND_GOAWAY:status=%d:msg=%s", op->goaway_status, msg); if (op->goaway_message != NULL) gpr_free(msg); gpr_strvec_add(&b, tmp); } if (op->set_accept_stream) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = false; gpr_asprintf(&tmp, "SET_ACCEPT_STREAM:%p(%p,...)", op->set_accept_stream_fn, op->set_accept_stream_user_data); gpr_strvec_add(&b, tmp); } if (op->bind_pollset != NULL) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = false; gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET")); } if (op->bind_pollset_set != NULL) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = false; gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET_SET")); } if (op->send_ping != NULL) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = false; gpr_strvec_add(&b, gpr_strdup("SEND_PING")); } out = gpr_strvec_flatten(&b, NULL); gpr_strvec_destroy(&b); return out; }
int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) { grpc_resolved_addresses *resolved = NULL; grpc_tcp_server *tcp = NULL; size_t i; size_t count = 0; int port_num = -1; int port_temp; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_error *err = GRPC_ERROR_NONE; GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2, (server, addr)); grpc_error **errors = NULL; err = grpc_blocking_resolve_address(addr, "https", &resolved); if (err != GRPC_ERROR_NONE) { goto error; } err = grpc_tcp_server_create(NULL, &tcp); if (err != GRPC_ERROR_NONE) { goto error; } const size_t naddrs = resolved->naddrs; errors = gpr_malloc(sizeof(*errors) * naddrs); for (i = 0; i < naddrs; i++) { errors[i] = grpc_tcp_server_add_port( tcp, (struct sockaddr *)&resolved->addrs[i].addr, resolved->addrs[i].len, &port_temp); if (errors[i] == GRPC_ERROR_NONE) { if (port_num == -1) { port_num = port_temp; } else { GPR_ASSERT(port_num == port_temp); } count++; } } if (count == 0) { char *msg; gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved", naddrs); err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); gpr_free(msg); goto error; } else if (count != naddrs) { char *msg; gpr_asprintf(&msg, "Only %" PRIuPTR " addresses added out of total %" PRIuPTR " resolved", count, naddrs); err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); gpr_free(msg); const char *warning_message = grpc_error_string(err); gpr_log(GPR_INFO, "WARNING: %s", warning_message); grpc_error_free_string(warning_message); /* we managed to bind some addresses: continue */ } grpc_resolved_addresses_destroy(resolved); /* Register with the server only upon success */ grpc_server_add_listener(&exec_ctx, server, tcp, start, destroy); goto done; /* Error path: cleanup and return */ error: GPR_ASSERT(err != GRPC_ERROR_NONE); if (resolved) { grpc_resolved_addresses_destroy(resolved); } if (tcp) { grpc_tcp_server_unref(&exec_ctx, tcp); } port_num = 0; const char *msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); grpc_error_free_string(msg); GRPC_ERROR_UNREF(err); done: grpc_exec_ctx_finish(&exec_ctx); if (errors != NULL) { for (i = 0; i < naddrs; i++) { GRPC_ERROR_UNREF(errors[i]); } } gpr_free(errors); return port_num; }
void grpc_chttp2_publish_reads( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_parsing *transport_parsing) { grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_parsing *stream_parsing; int was_zero; int is_zero; /* transport_parsing->last_incoming_stream_id is used as last-grpc_chttp2_stream-id when sending GOAWAY frame. https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8 says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream ID. So, since we don't have server pushed streams, client should send GOAWAY last-grpc_chttp2_stream-id=0 in this case. */ if (!transport_parsing->is_client) { transport_global->last_incoming_stream_id = transport_parsing->last_incoming_stream_id; } /* update global settings */ if (transport_parsing->settings_updated) { memcpy(transport_global->settings[GRPC_PEER_SETTINGS], transport_parsing->settings, sizeof(transport_parsing->settings)); transport_parsing->settings_updated = 0; } /* update settings based on ack if received */ if (transport_parsing->settings_ack_received) { memcpy(transport_global->settings[GRPC_ACKED_SETTINGS], transport_global->settings[GRPC_SENT_SETTINGS], GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); transport_parsing->settings_ack_received = 0; transport_global->sent_local_settings = 0; } /* move goaway to the global state if we received one (it will be published later */ if (transport_parsing->goaway_received) { grpc_chttp2_add_incoming_goaway(exec_ctx, transport_global, (uint32_t)transport_parsing->goaway_error, transport_parsing->goaway_text); transport_parsing->goaway_text = gpr_empty_slice(); transport_parsing->goaway_received = 0; } /* propagate flow control tokens to global state */ was_zero = transport_global->outgoing_window <= 0; GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window, transport_parsing, outgoing_window); is_zero = transport_global->outgoing_window <= 0; if (was_zero && !is_zero) { while (grpc_chttp2_list_pop_stalled_by_transport(transport_global, &stream_global)) { grpc_chttp2_become_writable(transport_global, stream_global); } } if (transport_parsing->incoming_window < transport_global->connection_window_target * 3 / 4) { int64_t announce_bytes = transport_global->connection_window_target - transport_parsing->incoming_window; GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global, announce_incoming_window, announce_bytes); GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing, incoming_window, announce_bytes); } /* for each stream that saw an update, fixup global state */ while (grpc_chttp2_list_pop_parsing_seen_stream( transport_global, transport_parsing, &stream_global, &stream_parsing)) { if (stream_parsing->seen_error) { stream_global->seen_error = true; stream_global->exceeded_metadata_size = stream_parsing->exceeded_metadata_size; grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); } /* flush stats to global stream state */ grpc_transport_move_stats(&stream_parsing->stats, &stream_global->stats); /* update outgoing flow control window */ was_zero = stream_global->outgoing_window <= 0; GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global, outgoing_window, stream_parsing, outgoing_window); is_zero = stream_global->outgoing_window <= 0; if (was_zero && !is_zero) { grpc_chttp2_become_writable(transport_global, stream_global); } stream_global->max_recv_bytes -= (uint32_t)GPR_MIN( stream_global->max_recv_bytes, stream_parsing->received_bytes); stream_parsing->received_bytes = 0; /* publish incoming stream ops */ if (stream_global->incoming_frames.tail != NULL) { stream_global->incoming_frames.tail->is_tail = 0; } if (stream_parsing->data_parser.incoming_frames.head != NULL) { grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); } grpc_chttp2_incoming_frame_queue_merge( &stream_global->incoming_frames, &stream_parsing->data_parser.incoming_frames); if (stream_global->incoming_frames.tail != NULL) { stream_global->incoming_frames.tail->is_tail = 1; } if (!stream_global->published_initial_metadata && stream_parsing->got_metadata_on_parse[0]) { stream_parsing->got_metadata_on_parse[0] = 0; stream_global->published_initial_metadata = 1; GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, stream_parsing->metadata_buffer[0], stream_global->received_initial_metadata); grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); } if (!stream_global->published_trailing_metadata && stream_parsing->got_metadata_on_parse[1]) { stream_parsing->got_metadata_on_parse[1] = 0; stream_global->published_trailing_metadata = 1; GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, stream_parsing->metadata_buffer[1], stream_global->received_trailing_metadata); grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); } if (stream_parsing->forced_close_error != GRPC_ERROR_NONE) { intptr_t reason; bool has_reason = grpc_error_get_int(stream_parsing->forced_close_error, GRPC_ERROR_INT_HTTP2_ERROR, &reason); if (has_reason && reason != GRPC_CHTTP2_NO_ERROR) { grpc_status_code status_code = has_reason ? grpc_chttp2_http2_error_to_grpc_status( (grpc_chttp2_error_code)reason, stream_global->deadline) : GRPC_STATUS_INTERNAL; const char *status_details = grpc_error_string(stream_parsing->forced_close_error); gpr_slice slice_details = gpr_slice_from_copied_string(status_details); grpc_error_free_string(status_details); grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status_code, &slice_details); } grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, 1, stream_parsing->forced_close_error); } if (stream_parsing->received_close) { grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, 0, GRPC_ERROR_NONE); } } }
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; server_secure_state *state = NULL; size_t i; size_t count = 0; int port_num = -1; int port_temp; grpc_security_status status = GRPC_SECURITY_ERROR; grpc_server_security_connector *sc = NULL; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_error *err = GRPC_ERROR_NONE; grpc_error **errors = NULL; 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) { err = GRPC_ERROR_CREATE( "No credentials specified for secure server port (creds==NULL)"); goto error; } status = grpc_server_credentials_create_security_connector(creds, &sc); if (status != GRPC_SECURITY_OK) { char *msg; gpr_asprintf(&msg, "Unable to create secure server with credentials of type %s.", creds->type); err = grpc_error_set_int(GRPC_ERROR_CREATE(msg), GRPC_ERROR_INT_SECURITY_STATUS, status); gpr_free(msg); goto error; } sc->channel_args = grpc_server_get_channel_args(server); /* resolve address */ err = grpc_blocking_resolve_address(addr, "https", &resolved); if (err != GRPC_ERROR_NONE) { goto error; } state = gpr_malloc(sizeof(*state)); memset(state, 0, sizeof(*state)); grpc_closure_init(&state->destroy_closure, destroy_done, state); err = grpc_tcp_server_create(&state->destroy_closure, grpc_server_get_channel_args(server), &tcp); if (err != GRPC_ERROR_NONE) { goto error; } state->server = server; state->tcp = tcp; state->sc = sc; state->creds = grpc_server_credentials_ref(creds); state->is_shutdown = false; gpr_mu_init(&state->mu); gpr_ref_init(&state->refcount, 1); errors = gpr_malloc(sizeof(*errors) * resolved->naddrs); for (i = 0; i < resolved->naddrs; i++) { errors[i] = grpc_tcp_server_add_port( tcp, (struct sockaddr *)&resolved->addrs[i].addr, resolved->addrs[i].len, &port_temp); if (errors[i] == GRPC_ERROR_NONE) { if (port_num == -1) { port_num = port_temp; } else { GPR_ASSERT(port_num == port_temp); } count++; } } if (count == 0) { char *msg; gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved", resolved->naddrs); err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs); gpr_free(msg); goto error; } else if (count != resolved->naddrs) { char *msg; gpr_asprintf(&msg, "Only %" PRIuPTR " addresses added out of total %" PRIuPTR " resolved", count, resolved->naddrs); err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs); gpr_free(msg); const char *warning_message = grpc_error_string(err); gpr_log(GPR_INFO, "WARNING: %s", warning_message); grpc_error_free_string(warning_message); /* we managed to bind some addresses: continue */ } else { for (i = 0; i < resolved->naddrs; i++) { GRPC_ERROR_UNREF(errors[i]); } } gpr_free(errors); errors = NULL; 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: GPR_ASSERT(err != GRPC_ERROR_NONE); if (errors != NULL) { for (i = 0; i < resolved->naddrs; i++) { GRPC_ERROR_UNREF(errors[i]); } gpr_free(errors); } if (resolved) { grpc_resolved_addresses_destroy(resolved); } if (tcp) { grpc_tcp_server_unref(&exec_ctx, tcp); } else { if (sc) { GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server"); } if (state) { gpr_free(state); } } grpc_exec_ctx_finish(&exec_ctx); const char *msg = grpc_error_string(err); GRPC_ERROR_UNREF(err); gpr_log(GPR_ERROR, "%s", msg); grpc_error_free_string(msg); return 0; }