static void on_accept(grpc_exec_ctx* exec_ctx, void* arg, grpc_endpoint* endpoint, grpc_pollset* accepting_pollset, grpc_tcp_server_acceptor* acceptor) { grpc_end2end_http_proxy* proxy = arg; // Instantiate proxy_connection. proxy_connection* conn = gpr_malloc(sizeof(*conn)); memset(conn, 0, sizeof(*conn)); conn->client_endpoint = endpoint; gpr_ref_init(&conn->refcount, 1); conn->pollset_set = grpc_pollset_set_create(); grpc_pollset_set_add_pollset(exec_ctx, conn->pollset_set, proxy->pollset); grpc_closure_init(&conn->on_read_request_done, on_read_request_done, conn); grpc_closure_init(&conn->on_server_connect_done, on_server_connect_done, conn); grpc_closure_init(&conn->on_write_response_done, on_write_response_done, conn); grpc_closure_init(&conn->on_client_read_done, on_client_read_done, conn); grpc_closure_init(&conn->on_client_write_done, on_client_write_done, conn); grpc_closure_init(&conn->on_server_read_done, on_server_read_done, conn); grpc_closure_init(&conn->on_server_write_done, on_server_write_done, conn); grpc_slice_buffer_init(&conn->client_read_buffer); grpc_slice_buffer_init(&conn->client_deferred_write_buffer); grpc_slice_buffer_init(&conn->client_write_buffer); grpc_slice_buffer_init(&conn->server_read_buffer); grpc_slice_buffer_init(&conn->server_deferred_write_buffer); grpc_slice_buffer_init(&conn->server_write_buffer); grpc_http_parser_init(&conn->http_parser, GRPC_HTTP_REQUEST, &conn->http_request); grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer, &conn->on_read_request_done); }
static void test_leftover(grpc_endpoint_test_config config, size_t slice_size) { grpc_endpoint_test_fixture f = config.create_fixture(slice_size); gpr_slice_buffer incoming; gpr_slice s = gpr_slice_from_copied_string("hello world 12345678900987654321"); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; int n = 0; grpc_closure done_closure; gpr_log(GPR_INFO, "Start test left over"); gpr_slice_buffer_init(&incoming); grpc_closure_init(&done_closure, inc_call_ctr, &n); grpc_endpoint_read(&exec_ctx, f.client_ep, &incoming, &done_closure); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(n == 1); GPR_ASSERT(incoming.count == 1); GPR_ASSERT(0 == gpr_slice_cmp(s, incoming.slices[0])); grpc_endpoint_shutdown(&exec_ctx, f.client_ep); grpc_endpoint_shutdown(&exec_ctx, f.server_ep); grpc_endpoint_destroy(&exec_ctx, f.client_ep); grpc_endpoint_destroy(&exec_ctx, f.server_ep); grpc_exec_ctx_finish(&exec_ctx); gpr_slice_unref(s); gpr_slice_buffer_destroy(&incoming); clean_up(); }
static void read_cb(void *user_data, int success) { struct read_socket_state *state = (struct read_socket_state *)user_data; ssize_t read_bytes; int current_data; GPR_ASSERT(success); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); current_data = state->read_bytes % 256; read_bytes = count_slices(state->incoming.slices, state->incoming.count, ¤t_data); state->read_bytes += read_bytes; gpr_log(GPR_INFO, "Read %d bytes of %d", read_bytes, state->target_read_bytes); if (state->read_bytes >= state->target_read_bytes) { gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); } else { switch (grpc_endpoint_read(state->ep, &state->incoming, &state->read_cb)) { case GRPC_ENDPOINT_DONE: gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); read_cb(user_data, 1); break; case GRPC_ENDPOINT_ERROR: gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); read_cb(user_data, 0); break; case GRPC_ENDPOINT_PENDING: gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); break; } } }
// Callback to read the HTTP CONNECT request. // TODO(roth): Technically, for any of the failure modes handled by this // function, we should handle the error by returning an HTTP response to // the client indicating that the request failed. However, for the purposes // of this test code, it's fine to pretend this is a client-side error, // which will cause the client connection to be dropped. static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { proxy_connection* conn = arg; if (error != GRPC_ERROR_NONE) { proxy_connection_failed(exec_ctx, conn, true /* is_client */, "HTTP proxy read request", error); return; } // Read request and feed it to the parser. for (size_t i = 0; i < conn->client_read_buffer.count; ++i) { if (GRPC_SLICE_LENGTH(conn->client_read_buffer.slices[i]) > 0) { error = grpc_http_parser_parse(&conn->http_parser, conn->client_read_buffer.slices[i], NULL); if (error != GRPC_ERROR_NONE) { proxy_connection_failed(exec_ctx, conn, true /* is_client */, "HTTP proxy request parse", error); GRPC_ERROR_UNREF(error); return; } } } grpc_slice_buffer_reset_and_unref(&conn->client_read_buffer); // If we're not done reading the request, read more data. if (conn->http_parser.state != GRPC_HTTP_BODY) { grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer, &conn->on_read_request_done); return; } // Make sure we got a CONNECT request. if (strcmp(conn->http_request.method, "CONNECT") != 0) { char* msg; gpr_asprintf(&msg, "HTTP proxy got request method %s", conn->http_request.method); error = GRPC_ERROR_CREATE(msg); gpr_free(msg); proxy_connection_failed(exec_ctx, conn, true /* is_client */, "HTTP proxy read request", error); GRPC_ERROR_UNREF(error); return; } // Resolve address. grpc_resolved_addresses* resolved_addresses = NULL; error = grpc_blocking_resolve_address(conn->http_request.path, "80", &resolved_addresses); if (error != GRPC_ERROR_NONE) { proxy_connection_failed(exec_ctx, conn, true /* is_client */, "HTTP proxy DNS lookup", error); GRPC_ERROR_UNREF(error); return; } GPR_ASSERT(resolved_addresses->naddrs >= 1); // Connect to requested address. // The connection callback inherits our reference to conn. const gpr_timespec deadline = gpr_time_add( gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(10, GPR_TIMESPAN)); grpc_tcp_client_connect(exec_ctx, &conn->on_server_connect_done, &conn->server_endpoint, conn->pollset_set, NULL, &resolved_addresses->addrs[0], deadline); grpc_resolved_addresses_destroy(resolved_addresses); }
// Callback for reading data from the backend server, which will be // proxied to the client. static void on_server_read_done(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { proxy_connection* conn = arg; if (error != GRPC_ERROR_NONE) { proxy_connection_failed(exec_ctx, conn, false /* is_client */, "HTTP proxy server read", error); return; } // If there is already a pending write (i.e., client_write_buffer is // not empty), then move the read data into client_deferred_write_buffer, // and the next write will be requested in on_client_write_done(), when // the current write is finished. // // Otherwise, move the read data into the write buffer and write it. if (conn->client_write_buffer.length > 0) { grpc_slice_buffer_move_into(&conn->server_read_buffer, &conn->client_deferred_write_buffer); } else { grpc_slice_buffer_move_into(&conn->server_read_buffer, &conn->client_write_buffer); gpr_ref(&conn->refcount); grpc_endpoint_write(exec_ctx, conn->client_endpoint, &conn->client_write_buffer, &conn->on_client_write_done); } // Read more data. grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer, &conn->on_server_read_done); }
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { security_handshaker *h = arg; gpr_mu_lock(&h->mu); if (error != GRPC_ERROR_NONE || h->shutdown) { security_handshake_failed_locked( exec_ctx, h, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Handshake write failed", &error, 1)); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); return; } // We may be done. if (h->handshaker_result == NULL) { grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, &h->on_handshake_data_received_from_peer); } else { error = check_peer_locked(exec_ctx, h); if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(exec_ctx, h, error); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); return; } } gpr_mu_unlock(&h->mu); }
static void read_and_write_test_read_handler(void *data, int success) { struct read_and_write_test_state *state = data; loop: state->bytes_read += count_slices( state->incoming.slices, state->incoming.count, &state->current_read_data); if (state->bytes_read == state->target_bytes || !success) { gpr_log(GPR_INFO, "Read handler done"); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); state->read_done = 1 + success; grpc_pollset_kick(g_pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); } else if (success) { switch (grpc_endpoint_read(state->read_ep, &state->incoming, &state->done_read)) { case GRPC_ENDPOINT_ERROR: success = 0; goto loop; case GRPC_ENDPOINT_DONE: success = 1; goto loop; case GRPC_ENDPOINT_PENDING: break; } } }
/* tcp read callback */ static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, int success) { size_t i; int keep_reading = 0; grpc_chttp2_transport *t = tp; lock(t); i = 0; GPR_ASSERT(!t->parsing_active); if (!t->closed) { t->parsing_active = 1; /* merge stream lists */ grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map); grpc_chttp2_prepare_to_read(&t->global, &t->parsing); gpr_mu_unlock(&t->mu); for (; i < t->read_buffer.count && grpc_chttp2_perform_read(exec_ctx, &t->parsing, t->read_buffer.slices[i]); i++) ; gpr_mu_lock(&t->mu); if (i != t->read_buffer.count) { drop_connection(exec_ctx, t); } /* merge stream lists */ grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map); t->global.concurrent_stream_count = (gpr_uint32)grpc_chttp2_stream_map_size(&t->parsing_stream_map); if (t->parsing.initial_window_update != 0) { grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, update_global_window, t); t->parsing.initial_window_update = 0; } /* handle higher level things */ grpc_chttp2_publish_reads(exec_ctx, &t->global, &t->parsing); t->parsing_active = 0; } if (!success || i != t->read_buffer.count) { drop_connection(exec_ctx, t); read_error_locked(exec_ctx, t); } else if (!t->closed) { keep_reading = 1; REF_TRANSPORT(t, "keep_reading"); prevent_endpoint_shutdown(t); } gpr_slice_buffer_reset_and_unref(&t->read_buffer); unlock(exec_ctx, t); if (keep_reading) { grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->recv_data); allow_endpoint_shutdown_unlocked(exec_ctx, t); UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); } else { UNREF_TRANSPORT(exec_ctx, t, "recv_data"); } }
// Callback to write the HTTP response for the CONNECT request. static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { proxy_connection* conn = arg; if (error != GRPC_ERROR_NONE) { proxy_connection_failed(exec_ctx, conn, true /* is_client */, "HTTP proxy write response", error); return; } // Clear write buffer. grpc_slice_buffer_reset_and_unref(&conn->client_write_buffer); // Start reading from both client and server. One of the read // requests inherits our ref to conn, but we need to take a new ref // for the other one. gpr_ref(&conn->refcount); grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer, &conn->on_client_read_done); grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer, &conn->on_server_read_done); }
static void on_connect(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, grpc_pollset *accepting_pollset, grpc_tcp_server_acceptor *acceptor) { test_tcp_server *server = arg; grpc_closure_init(&on_read, handle_read, NULL); gpr_slice_buffer_init(&state.incoming_buffer); gpr_slice_buffer_init(&state.temp_incoming_buffer); state.tcp = tcp; grpc_endpoint_add_to_pollset(exec_ctx, tcp, server->pollset); grpc_endpoint_read(exec_ctx, tcp, &state.temp_incoming_buffer, &on_read); }
static grpc_error *on_handshake_next_done_locked( grpc_exec_ctx *exec_ctx, security_handshaker *h, tsi_result result, const unsigned char *bytes_to_send, size_t bytes_to_send_size, tsi_handshaker_result *handshaker_result) { grpc_error *error = GRPC_ERROR_NONE; // Read more if we need to. if (result == TSI_INCOMPLETE_DATA) { GPR_ASSERT(bytes_to_send_size == 0); grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, &h->on_handshake_data_received_from_peer); return error; } if (result != TSI_OK) { return grpc_set_tsi_error_result( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result); } // Update handshaker result. if (handshaker_result != NULL) { GPR_ASSERT(h->handshaker_result == NULL); h->handshaker_result = handshaker_result; } if (bytes_to_send_size > 0) { // Send data to peer, if needed. grpc_slice to_send = grpc_slice_from_copied_buffer( (const char *)bytes_to_send, bytes_to_send_size); grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing); grpc_slice_buffer_add(&h->outgoing, to_send); grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, &h->on_handshake_data_sent_to_peer); } else if (handshaker_result == NULL) { // There is nothing to send, but need to read from peer. grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, &h->on_handshake_data_received_from_peer); } else { // Handshake has finished, check peer and so on. error = check_peer_locked(exec_ctx, h); } return error; }
static void handle_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_ASSERT(error == GRPC_ERROR_NONE); gpr_slice_buffer_move_into(&state.temp_incoming_buffer, &state.incoming_buffer); gpr_log(GPR_DEBUG, "got %" PRIuPTR " bytes, magic is %" PRIuPTR " bytes", state.incoming_buffer.length, strlen(magic_connect_string)); if (state.incoming_buffer.length > strlen(magic_connect_string)) { gpr_atm_rel_store(&state.done_atm, 1); grpc_endpoint_shutdown(exec_ctx, state.tcp); grpc_endpoint_destroy(exec_ctx, state.tcp); } else { grpc_endpoint_read(exec_ctx, state.tcp, &state.temp_incoming_buffer, &on_read); } }
static void multiple_shutdown_test(grpc_endpoint_test_config config) { grpc_endpoint_test_fixture f = begin_test(config, "multiple_shutdown_test", 128); int fail_count = 0; grpc_slice_buffer slice_buffer; grpc_slice_buffer_init(&slice_buffer); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_endpoint_add_to_pollset(&exec_ctx, f.client_ep, g_pollset); grpc_endpoint_read(&exec_ctx, f.client_ep, &slice_buffer, GRPC_CLOSURE_CREATE(inc_on_failure, &fail_count, grpc_schedule_on_exec_ctx)); wait_for_fail_count(&exec_ctx, &fail_count, 0); grpc_endpoint_shutdown(&exec_ctx, f.client_ep, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test Shutdown")); wait_for_fail_count(&exec_ctx, &fail_count, 1); grpc_endpoint_read(&exec_ctx, f.client_ep, &slice_buffer, GRPC_CLOSURE_CREATE(inc_on_failure, &fail_count, grpc_schedule_on_exec_ctx)); wait_for_fail_count(&exec_ctx, &fail_count, 2); grpc_slice_buffer_add(&slice_buffer, grpc_slice_from_copied_string("a")); grpc_endpoint_write(&exec_ctx, f.client_ep, &slice_buffer, GRPC_CLOSURE_CREATE(inc_on_failure, &fail_count, grpc_schedule_on_exec_ctx)); wait_for_fail_count(&exec_ctx, &fail_count, 3); grpc_endpoint_shutdown(&exec_ctx, f.client_ep, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test Shutdown")); wait_for_fail_count(&exec_ctx, &fail_count, 3); grpc_slice_buffer_destroy_internal(&exec_ctx, &slice_buffer); grpc_endpoint_destroy(&exec_ctx, f.client_ep); grpc_endpoint_destroy(&exec_ctx, f.server_ep); grpc_exec_ctx_finish(&exec_ctx); }
static void handle_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) { GPR_ASSERT(success); gpr_slice_buffer_move_into(&state.temp_incoming_buffer, &state.incoming_buffer); gpr_log(GPR_DEBUG, "got %d bytes, magic is %d bytes", state.incoming_buffer.length, strlen(magic_connect_string)); if (state.incoming_buffer.length > strlen(magic_connect_string)) { gpr_atm_rel_store(&state.done_atm, 1); grpc_endpoint_shutdown(exec_ctx, state.tcp); grpc_endpoint_destroy(exec_ctx, state.tcp); } else { grpc_endpoint_read(exec_ctx, state.tcp, &state.temp_incoming_buffer, &on_read); } }
/* Write to a socket until it fills up, then read from it using the grpc_tcp API. */ static void large_read_test(size_t slice_size) { int sv[2]; grpc_endpoint *ep; struct read_socket_state state; ssize_t written_bytes; gpr_timespec deadline = grpc_timeout_seconds_to_deadline(20); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; gpr_log(GPR_INFO, "Start large read test, slice size %" PRIuPTR, slice_size); create_sockets(sv); grpc_resource_quota *resource_quota = grpc_resource_quota_create("large_read_test"); ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), resource_quota, slice_size, "test"); grpc_resource_quota_unref_internal(&exec_ctx, resource_quota); grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset); written_bytes = fill_socket(sv[0]); gpr_log(GPR_INFO, "Wrote %" PRIuPTR " bytes", written_bytes); state.ep = ep; state.read_bytes = 0; state.target_read_bytes = (size_t)written_bytes; grpc_slice_buffer_init(&state.incoming); grpc_closure_init(&state.read_cb, read_cb, &state, grpc_schedule_on_exec_ctx); grpc_endpoint_read(&exec_ctx, ep, &state.incoming, &state.read_cb); gpr_mu_lock(g_mu); while (state.read_bytes < state.target_read_bytes) { grpc_pollset_worker *worker = NULL; GPR_ASSERT(GRPC_LOG_IF_ERROR( "pollset_work", grpc_pollset_work(&exec_ctx, g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC), deadline))); gpr_mu_unlock(g_mu); grpc_exec_ctx_finish(&exec_ctx); gpr_mu_lock(g_mu); } GPR_ASSERT(state.read_bytes == state.target_read_bytes); gpr_mu_unlock(g_mu); grpc_slice_buffer_destroy_internal(&exec_ctx, &state.incoming); grpc_endpoint_destroy(&exec_ctx, ep); grpc_exec_ctx_finish(&exec_ctx); }
/* Write to a socket until it fills up, then read from it using the grpc_tcp API. */ static void large_read_test(ssize_t slice_size) { int sv[2]; grpc_endpoint *ep; struct read_socket_state state; ssize_t written_bytes; gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20); gpr_log(GPR_INFO, "Start large read test, slice size %d", slice_size); create_sockets(sv); ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), slice_size, "test"); grpc_endpoint_add_to_pollset(ep, &g_pollset); written_bytes = fill_socket(sv[0]); gpr_log(GPR_INFO, "Wrote %d bytes", written_bytes); state.ep = ep; state.read_bytes = 0; state.target_read_bytes = written_bytes; gpr_slice_buffer_init(&state.incoming); grpc_iomgr_closure_init(&state.read_cb, read_cb, &state); switch (grpc_endpoint_read(ep, &state.incoming, &state.read_cb)) { case GRPC_ENDPOINT_DONE: read_cb(&state, 1); break; case GRPC_ENDPOINT_ERROR: read_cb(&state, 0); break; case GRPC_ENDPOINT_PENDING: break; } gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); while (state.read_bytes < state.target_read_bytes) { grpc_pollset_worker worker; grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC), deadline); } GPR_ASSERT(state.read_bytes == state.target_read_bytes); gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); gpr_slice_buffer_destroy(&state.incoming); grpc_endpoint_destroy(ep); }
static void read_and_write_test_read_handler(grpc_exec_ctx *exec_ctx, void *data, grpc_error *error) { struct read_and_write_test_state *state = data; state->bytes_read += count_slices( state->incoming.slices, state->incoming.count, &state->current_read_data); if (state->bytes_read == state->target_bytes || error != GRPC_ERROR_NONE) { gpr_log(GPR_INFO, "Read handler done"); gpr_mu_lock(g_mu); state->read_done = 1 + (error == GRPC_ERROR_NONE); GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL)); gpr_mu_unlock(g_mu); } else if (error == GRPC_ERROR_NONE) { grpc_endpoint_read(exec_ctx, state->read_ep, &state->incoming, &state->done_read); } }
static void read_and_write_test_read_handler(grpc_exec_ctx *exec_ctx, void *data, bool success) { struct read_and_write_test_state *state = data; state->bytes_read += count_slices( state->incoming.slices, state->incoming.count, &state->current_read_data); if (state->bytes_read == state->target_bytes || !success) { gpr_log(GPR_INFO, "Read handler done"); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); state->read_done = 1 + success; grpc_pollset_kick(g_pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); } else if (success) { grpc_endpoint_read(exec_ctx, state->read_ep, &state->incoming, &state->done_read); } }
static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, gpr_slice_buffer *slices, grpc_closure *cb) { secure_endpoint *ep = (secure_endpoint *)secure_ep; ep->read_cb = cb; ep->read_buffer = slices; gpr_slice_buffer_reset_and_unref(ep->read_buffer); SECURE_ENDPOINT_REF(ep, "read"); if (ep->leftover_bytes.count) { gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer); GPR_ASSERT(ep->leftover_bytes.count == 0); on_read(exec_ctx, ep, GRPC_ERROR_NONE); return; } grpc_endpoint_read(exec_ctx, ep->wrapped_ep, &ep->source_buffer, &ep->on_read); }
// Callback invoked when finished writing HTTP CONNECT request. static void on_write_done(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { http_connect_handshaker* handshaker = arg; gpr_mu_lock(&handshaker->mu); if (error != GRPC_ERROR_NONE || handshaker->shutdown) { // If the write failed or we're shutting down, clean up and invoke the // callback with the error. handshake_failed_locked(exec_ctx, handshaker, GRPC_ERROR_REF(error)); gpr_mu_unlock(&handshaker->mu); http_connect_handshaker_unref(exec_ctx, handshaker); } else { // Otherwise, read the response. // The read callback inherits our ref to the handshaker. grpc_endpoint_read(exec_ctx, handshaker->args->endpoint, handshaker->args->read_buffer, &handshaker->response_read_closure); gpr_mu_unlock(&handshaker->mu); } }
/* Write to a socket until it fills up, then read from it using the grpc_tcp API. */ static void large_read_test(size_t slice_size) { int sv[2]; grpc_endpoint *ep; struct read_socket_state state; ssize_t written_bytes; gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; gpr_log(GPR_INFO, "Start large read test, slice size %d", slice_size); create_sockets(sv); ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), slice_size, "test"); grpc_endpoint_add_to_pollset(&exec_ctx, ep, &g_pollset); written_bytes = fill_socket(sv[0]); gpr_log(GPR_INFO, "Wrote %d bytes", written_bytes); state.ep = ep; state.read_bytes = 0; state.target_read_bytes = (size_t)written_bytes; gpr_slice_buffer_init(&state.incoming); grpc_closure_init(&state.read_cb, read_cb, &state); grpc_endpoint_read(&exec_ctx, ep, &state.incoming, &state.read_cb); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); while (state.read_bytes < state.target_read_bytes) { grpc_pollset_worker worker; grpc_pollset_work(&exec_ctx, &g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC), deadline); gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); grpc_exec_ctx_finish(&exec_ctx); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); } GPR_ASSERT(state.read_bytes == state.target_read_bytes); gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); gpr_slice_buffer_destroy(&state.incoming); grpc_endpoint_destroy(&exec_ctx, ep); grpc_exec_ctx_finish(&exec_ctx); }
static void handle_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_ASSERT(error == GRPC_ERROR_NONE); state.incoming_data_length += state.temp_incoming_buffer.length; size_t i; for (i = 0; i < state.temp_incoming_buffer.count; i++) { char *dump = gpr_dump_slice(state.temp_incoming_buffer.slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "Server received: %s", dump); gpr_free(dump); } gpr_log(GPR_DEBUG, "got %" PRIuPTR " bytes, expected %" PRIuPTR " bytes", state.incoming_data_length, EXPECTED_INCOMING_DATA_LENGTH); if (state.incoming_data_length > EXPECTED_INCOMING_DATA_LENGTH) { handle_write(exec_ctx); } else { grpc_endpoint_read(exec_ctx, state.tcp, &state.temp_incoming_buffer, &on_read); } }
static void read_cb(grpc_exec_ctx *exec_ctx, void *user_data, int success) { struct read_socket_state *state = (struct read_socket_state *)user_data; size_t read_bytes; int current_data; GPR_ASSERT(success); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); current_data = state->read_bytes % 256; read_bytes = count_slices(state->incoming.slices, state->incoming.count, ¤t_data); state->read_bytes += read_bytes; gpr_log(GPR_INFO, "Read %d bytes of %d", read_bytes, state->target_read_bytes); if (state->read_bytes >= state->target_read_bytes) { gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); } else { grpc_endpoint_read(exec_ctx, state->ep, &state->incoming, &state->read_cb); gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); } }
static void read_cb(grpc_exec_ctx *exec_ctx, void *user_data, grpc_error *error) { struct read_socket_state *state = (struct read_socket_state *)user_data; size_t read_bytes; int current_data; GPR_ASSERT(error == GRPC_ERROR_NONE); gpr_mu_lock(g_mu); current_data = state->read_bytes % 256; read_bytes = count_slices(state->incoming.slices, state->incoming.count, ¤t_data); state->read_bytes += read_bytes; gpr_log(GPR_INFO, "Read %" PRIuPTR " bytes of %" PRIuPTR, read_bytes, state->target_read_bytes); if (state->read_bytes >= state->target_read_bytes) { gpr_mu_unlock(g_mu); } else { grpc_endpoint_read(exec_ctx, state->ep, &state->incoming, &state->read_cb); gpr_mu_unlock(g_mu); } }
/* If handshake is NULL, the handshake is done. */ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *handshake, grpc_error *error) { grpc_security_handshake *h = handshake; /* Make sure that write is OK. */ if (error != GRPC_ERROR_NONE) { if (handshake != NULL) security_handshake_done( exec_ctx, h, GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1)); return; } /* We may be done. */ if (tsi_handshaker_is_in_progress(h->handshaker)) { /* TODO(klempner,jboeuf): This should probably use the client setup deadline */ grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, &h->on_handshake_data_received_from_peer); } else { check_peer(exec_ctx, h); } }
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, void *handshake, grpc_error *error) { grpc_security_handshake *h = handshake; size_t consumed_slice_size = 0; tsi_result result = TSI_OK; size_t i; size_t num_left_overs; int has_left_overs_in_current_slice = 0; if (error != GRPC_ERROR_NONE) { security_handshake_done( exec_ctx, h, GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1)); return; } for (i = 0; i < h->incoming.count; i++) { consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]); result = tsi_handshaker_process_bytes_from_peer( h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]), &consumed_slice_size); if (!tsi_handshaker_is_in_progress(h->handshaker)) break; } if (tsi_handshaker_is_in_progress(h->handshaker)) { /* We may need more data. */ if (result == TSI_INCOMPLETE_DATA) { grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, &h->on_handshake_data_received_from_peer); return; } else { send_handshake_bytes_to_peer(exec_ctx, h); return; } } if (result != TSI_OK) { security_handshake_done(exec_ctx, h, grpc_set_tsi_error_result( GRPC_ERROR_CREATE("Handshake failed"), result)); return; } /* Handshake is done and successful this point. */ has_left_overs_in_current_slice = (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i])); num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1; if (num_left_overs == 0) { check_peer(exec_ctx, h); return; } /* Put the leftovers in our buffer (ownership transfered). */ if (has_left_overs_in_current_slice) { gpr_slice_buffer_add( &h->left_overs, gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size)); gpr_slice_unref( h->incoming.slices[i]); /* split_tail above increments refcount. */ } gpr_slice_buffer_addn( &h->left_overs, &h->incoming.slices[i + 1], num_left_overs - (size_t)has_left_overs_in_current_slice); check_peer(exec_ctx, h); }
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { security_handshaker *h = arg; gpr_mu_lock(&h->mu); if (error != GRPC_ERROR_NONE || h->shutdown) { security_handshake_failed_locked( exec_ctx, h, GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1)); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); return; } // Process received data. tsi_result result = TSI_OK; size_t consumed_slice_size = 0; size_t i; for (i = 0; i < h->args->read_buffer->count; i++) { consumed_slice_size = GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]); result = tsi_handshaker_process_bytes_from_peer( h->handshaker, GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]), &consumed_slice_size); if (!tsi_handshaker_is_in_progress(h->handshaker)) break; } if (tsi_handshaker_is_in_progress(h->handshaker)) { /* We may need more data. */ if (result == TSI_INCOMPLETE_DATA) { grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, &h->on_handshake_data_received_from_peer); goto done; } else { error = send_handshake_bytes_to_peer_locked(exec_ctx, h); if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(exec_ctx, h, error); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); return; } goto done; } } if (result != TSI_OK) { security_handshake_failed_locked( exec_ctx, h, grpc_set_tsi_error_result( GRPC_ERROR_CREATE("Handshake failed"), result)); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); return; } /* Handshake is done and successful this point. */ bool has_left_overs_in_current_slice = (consumed_slice_size < GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i])); size_t num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + h->args->read_buffer->count - i - 1; if (num_left_overs > 0) { /* Put the leftovers in our buffer (ownership transfered). */ if (has_left_overs_in_current_slice) { grpc_slice_buffer_add( &h->left_overs, grpc_slice_split_tail(&h->args->read_buffer->slices[i], consumed_slice_size)); /* split_tail above increments refcount. */ grpc_slice_unref(h->args->read_buffer->slices[i]); } grpc_slice_buffer_addn( &h->left_overs, &h->args->read_buffer->slices[i + 1], num_left_overs - (size_t)has_left_overs_in_current_slice); } // Check peer. error = check_peer_locked(exec_ctx, h); if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(exec_ctx, h, error); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); return; } done: gpr_mu_unlock(&h->mu); }
/* Do both reading and writing using the grpc_endpoint API. This also includes a test of the shutdown behavior. */ static void read_and_write_test(grpc_endpoint_test_config config, size_t num_bytes, size_t write_size, size_t slice_size, int shutdown) { struct read_and_write_test_state state; gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20); grpc_endpoint_test_fixture f = begin_test(config, "read_and_write_test", slice_size); gpr_log(GPR_DEBUG, "num_bytes=%d write_size=%d slice_size=%d shutdown=%d", num_bytes, write_size, slice_size, shutdown); if (shutdown) { gpr_log(GPR_INFO, "Start read and write shutdown test"); } else { gpr_log(GPR_INFO, "Start read and write test with %d bytes, slice size %d", num_bytes, slice_size); } state.read_ep = f.client_ep; state.write_ep = f.server_ep; state.target_bytes = num_bytes; state.bytes_read = 0; state.current_write_size = write_size; state.bytes_written = 0; state.read_done = 0; state.write_done = 0; state.current_read_data = 0; state.current_write_data = 0; grpc_iomgr_closure_init(&state.done_read, read_and_write_test_read_handler, &state); grpc_iomgr_closure_init(&state.done_write, read_and_write_test_write_handler, &state); gpr_slice_buffer_init(&state.outgoing); gpr_slice_buffer_init(&state.incoming); /* Get started by pretending an initial write completed */ /* NOTE: Sets up initial conditions so we can have the same write handler for the first iteration as for later iterations. It does the right thing even when bytes_written is unsigned. */ state.bytes_written -= state.current_write_size; read_and_write_test_write_handler(&state, 1); switch ( grpc_endpoint_read(state.read_ep, &state.incoming, &state.done_read)) { case GRPC_ENDPOINT_PENDING: break; case GRPC_ENDPOINT_ERROR: read_and_write_test_read_handler(&state, 0); break; case GRPC_ENDPOINT_DONE: read_and_write_test_read_handler(&state, 1); break; } if (shutdown) { gpr_log(GPR_DEBUG, "shutdown read"); grpc_endpoint_shutdown(state.read_ep); gpr_log(GPR_DEBUG, "shutdown write"); grpc_endpoint_shutdown(state.write_ep); } gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); while (!state.read_done || !state.write_done) { grpc_pollset_worker worker; GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), deadline) < 0); grpc_pollset_work(g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC), deadline); } gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); end_test(config); gpr_slice_buffer_destroy(&state.outgoing); gpr_slice_buffer_destroy(&state.incoming); grpc_endpoint_destroy(state.read_ep); grpc_endpoint_destroy(state.write_ep); }
static void test_code(void) { /* iomgr.h */ grpc_iomgr_init(); grpc_iomgr_shutdown(); /* closure.h */ grpc_closure closure; closure.cb = NULL; closure.cb_arg = NULL; closure.next_data.scratch = 0; grpc_closure_list closure_list = GRPC_CLOSURE_LIST_INIT; closure_list.head = NULL; closure_list.tail = NULL; grpc_closure_init(&closure, NULL, NULL); grpc_closure_create(NULL, NULL); grpc_closure_list_move(NULL, NULL); grpc_closure_list_append(NULL, NULL, GRPC_ERROR_CREATE("Foo")); grpc_closure_list_empty(closure_list); /* exec_ctx.h */ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx_flush(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_sched(&exec_ctx, &closure, GRPC_ERROR_CREATE("Foo"), NULL); grpc_exec_ctx_enqueue_list(&exec_ctx, &closure_list, NULL); /* endpoint.h */ grpc_endpoint endpoint; grpc_endpoint_vtable vtable = {grpc_endpoint_read, grpc_endpoint_write, grpc_endpoint_get_workqueue, grpc_endpoint_add_to_pollset, grpc_endpoint_add_to_pollset_set, grpc_endpoint_shutdown, grpc_endpoint_destroy, grpc_endpoint_get_resource_user, grpc_endpoint_get_peer}; endpoint.vtable = &vtable; grpc_endpoint_read(&exec_ctx, &endpoint, NULL, NULL); grpc_endpoint_get_peer(&endpoint); grpc_endpoint_write(&exec_ctx, &endpoint, NULL, NULL); grpc_endpoint_shutdown(&exec_ctx, &endpoint); grpc_endpoint_destroy(&exec_ctx, &endpoint); grpc_endpoint_add_to_pollset(&exec_ctx, &endpoint, NULL); grpc_endpoint_add_to_pollset_set(&exec_ctx, &endpoint, NULL); /* executor.h */ grpc_executor_init(); grpc_executor_push(&closure, GRPC_ERROR_CREATE("Phi")); grpc_executor_shutdown(); /* pollset.h */ grpc_pollset_size(); grpc_pollset_init(NULL, NULL); grpc_pollset_shutdown(NULL, NULL, NULL); grpc_pollset_reset(NULL); grpc_pollset_destroy(NULL); GRPC_ERROR_UNREF(grpc_pollset_work(NULL, NULL, NULL, gpr_now(GPR_CLOCK_REALTIME), gpr_now(GPR_CLOCK_MONOTONIC))); GRPC_ERROR_UNREF(grpc_pollset_kick(NULL, NULL)); }
/* Do both reading and writing using the grpc_endpoint API. This also includes a test of the shutdown behavior. */ static void read_and_write_test(grpc_endpoint_test_config config, size_t num_bytes, size_t write_size, size_t slice_size, int shutdown) { struct read_and_write_test_state state; gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20); grpc_endpoint_test_fixture f = begin_test(config, "read_and_write_test", slice_size); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; gpr_log(GPR_DEBUG, "num_bytes=%" PRIuPTR " write_size=%" PRIuPTR " slice_size=%" PRIuPTR " shutdown=%d", num_bytes, write_size, slice_size, shutdown); if (shutdown) { gpr_log(GPR_INFO, "Start read and write shutdown test"); } else { gpr_log(GPR_INFO, "Start read and write test with %" PRIuPTR " bytes, slice size %" PRIuPTR, num_bytes, slice_size); } state.read_ep = f.client_ep; state.write_ep = f.server_ep; state.target_bytes = num_bytes; state.bytes_read = 0; state.current_write_size = write_size; state.bytes_written = 0; state.read_done = 0; state.write_done = 0; state.current_read_data = 0; state.current_write_data = 0; grpc_closure_init(&state.done_read, read_and_write_test_read_handler, &state); grpc_closure_init(&state.done_write, read_and_write_test_write_handler, &state); gpr_slice_buffer_init(&state.outgoing); gpr_slice_buffer_init(&state.incoming); /* Get started by pretending an initial write completed */ /* NOTE: Sets up initial conditions so we can have the same write handler for the first iteration as for later iterations. It does the right thing even when bytes_written is unsigned. */ state.bytes_written -= state.current_write_size; read_and_write_test_write_handler(&exec_ctx, &state, 1); grpc_exec_ctx_finish(&exec_ctx); grpc_endpoint_read(&exec_ctx, state.read_ep, &state.incoming, &state.done_read); if (shutdown) { gpr_log(GPR_DEBUG, "shutdown read"); grpc_endpoint_shutdown(&exec_ctx, state.read_ep); gpr_log(GPR_DEBUG, "shutdown write"); grpc_endpoint_shutdown(&exec_ctx, state.write_ep); } grpc_exec_ctx_finish(&exec_ctx); gpr_mu_lock(g_mu); while (!state.read_done || !state.write_done) { grpc_pollset_worker *worker = NULL; GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), deadline) < 0); grpc_pollset_work(&exec_ctx, g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC), deadline); } gpr_mu_unlock(g_mu); grpc_exec_ctx_finish(&exec_ctx); end_test(config); gpr_slice_buffer_destroy(&state.outgoing); gpr_slice_buffer_destroy(&state.incoming); grpc_endpoint_destroy(&exec_ctx, state.read_ep); grpc_endpoint_destroy(&exec_ctx, state.write_ep); grpc_exec_ctx_finish(&exec_ctx); }