Exemple #1
0
static grpc_error *send_handshake_bytes_to_peer_locked(grpc_exec_ctx *exec_ctx,
                                                       security_handshaker *h) {
  // Get data to send.
  tsi_result result = TSI_OK;
  size_t offset = 0;
  do {
    size_t to_send_size = h->handshake_buffer_size - offset;
    result = tsi_handshaker_get_bytes_to_send_to_peer(
        h->handshaker, h->handshake_buffer + offset, &to_send_size);
    offset += to_send_size;
    if (result == TSI_INCOMPLETE_DATA) {
      h->handshake_buffer_size *= 2;
      h->handshake_buffer =
          gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
    }
  } while (result == TSI_INCOMPLETE_DATA);
  if (result != TSI_OK) {
    return grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Handshake failed"),
                                     result);
  }
  // Send data.
  grpc_slice to_send =
      grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
  grpc_slice_buffer_reset_and_unref(&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);
  return GRPC_ERROR_NONE;
}
Exemple #2
0
// 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);
}
Exemple #3
0
static void read_and_write_test_write_handler(grpc_exec_ctx *exec_ctx,
                                              void *data, bool success) {
  struct read_and_write_test_state *state = data;
  gpr_slice *slices = NULL;
  size_t nslices;

  if (success) {
    state->bytes_written += state->current_write_size;
    if (state->target_bytes - state->bytes_written <
        state->current_write_size) {
      state->current_write_size = state->target_bytes - state->bytes_written;
    }
    if (state->current_write_size != 0) {
      slices = allocate_blocks(state->current_write_size, 8192, &nslices,
                               &state->current_write_data);
      gpr_slice_buffer_reset_and_unref(&state->outgoing);
      gpr_slice_buffer_addn(&state->outgoing, slices, nslices);
      grpc_endpoint_write(exec_ctx, state->write_ep, &state->outgoing,
                          &state->done_write);
      free(slices);
      return;
    }
  }

  gpr_log(GPR_INFO, "Write handler done");
  gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
  state->write_done = 1 + success;
  grpc_pollset_kick(g_pollset, NULL);
  gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
}
Exemple #4
0
static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
    connector *c = arg;
    grpc_endpoint *tcp = c->newly_connecting_endpoint;
    if (tcp != NULL) {
        gpr_mu_lock(&c->mu);
        GPR_ASSERT(c->connecting_endpoint == NULL);
        c->connecting_endpoint = tcp;
        gpr_mu_unlock(&c->mu);
        if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
            grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
                              c);
            grpc_slice_buffer_init(&c->initial_string_buffer);
            grpc_slice_buffer_add(&c->initial_string_buffer,
                                  c->args.initial_connect_string);
            grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
                                &c->initial_string_sent);
        } else {
            grpc_handshake_manager_do_handshake(
                exec_ctx, c->handshake_mgr, tcp, c->args.channel_args,
                c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
        }
    } else {
        memset(c->result, 0, sizeof(*c->result));
        grpc_closure *notify = c->notify;
        c->notify = NULL;
        grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
    }
}
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;
  gpr_mu_lock(&handshaker->mu);
  // Save state in the handshaker object.
  handshaker->args = args;
  handshaker->on_handshake_done = on_handshake_done;
  // Send HTTP CONNECT request.
  gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s",
          handshaker->server_name, handshaker->proxy_server);
  grpc_httpcli_request request;
  memset(&request, 0, sizeof(request));
  request.host = handshaker->proxy_server;
  request.http.method = "CONNECT";
  request.http.path = handshaker->server_name;
  request.handshaker = &grpc_httpcli_plaintext;
  grpc_slice request_slice = grpc_httpcli_format_connect_request(&request);
  grpc_slice_buffer_add(&handshaker->write_buffer, request_slice);
  // 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);
}
Exemple #6
0
static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
  chttp2_connector *c = arg;
  gpr_mu_lock(&c->mu);
  GPR_ASSERT(c->connecting);
  c->connecting = false;
  if (error != GRPC_ERROR_NONE || c->shutdown) {
    if (error == GRPC_ERROR_NONE) {
      error = GRPC_ERROR_CREATE("connector shutdown");
    } else {
      error = GRPC_ERROR_REF(error);
    }
    memset(c->result, 0, sizeof(*c->result));
    grpc_closure *notify = c->notify;
    c->notify = NULL;
    grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
    if (c->endpoint != NULL) grpc_endpoint_shutdown(exec_ctx, c->endpoint);
    gpr_mu_unlock(&c->mu);
    chttp2_connector_unref(exec_ctx, arg);
  } else {
    GPR_ASSERT(c->endpoint != NULL);
    if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
      grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
                        c);
      grpc_slice_buffer_init(&c->initial_string_buffer);
      grpc_slice_buffer_add(&c->initial_string_buffer,
                            c->args.initial_connect_string);
      grpc_endpoint_write(exec_ctx, c->endpoint, &c->initial_string_buffer,
                          &c->initial_string_sent);
    } else {
      start_handshake_locked(exec_ctx, c);
    }
    gpr_mu_unlock(&c->mu);
  }
}
Exemple #7
0
static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
  connector *c = arg;
  grpc_closure *notify;
  grpc_endpoint *tcp = c->tcp;
  if (tcp != NULL) {
    if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
      grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
                        c);
      gpr_slice_buffer_init(&c->initial_string_buffer);
      gpr_slice_buffer_add(&c->initial_string_buffer,
                           c->args.initial_connect_string);
      connector_ref(arg);
      grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
                          &c->initial_string_sent);
    }
    c->result->transport =
        grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1);
    grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
                                        0);
    GPR_ASSERT(c->result->transport);
    c->result->channel_args = c->args.channel_args;
  } else {
    memset(c->result, 0, sizeof(*c->result));
  }
  notify = c->notify;
  c->notify = NULL;
  notify->cb(exec_ctx, notify->cb_arg, 1);
}
Exemple #8
0
static void read_and_write_test_write_handler(grpc_exec_ctx *exec_ctx,
                                              void *data, grpc_error *error) {
  struct read_and_write_test_state *state = data;
  grpc_slice *slices = NULL;
  size_t nslices;

  if (error == GRPC_ERROR_NONE) {
    state->bytes_written += state->current_write_size;
    if (state->target_bytes - state->bytes_written <
        state->current_write_size) {
      state->current_write_size = state->target_bytes - state->bytes_written;
    }
    if (state->current_write_size != 0) {
      slices = allocate_blocks(state->current_write_size, 8192, &nslices,
                               &state->current_write_data);
      grpc_slice_buffer_reset_and_unref(&state->outgoing);
      grpc_slice_buffer_addn(&state->outgoing, slices, nslices);
      grpc_endpoint_write(exec_ctx, state->write_ep, &state->outgoing,
                          &state->done_write);
      gpr_free(slices);
      return;
    }
  }

  gpr_log(GPR_INFO, "Write handler done");
  gpr_mu_lock(g_mu);
  state->write_done = 1 + (error == GRPC_ERROR_NONE);
  GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL));
  gpr_mu_unlock(g_mu);
}
Exemple #9
0
static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
        grpc_security_handshake *h) {
    size_t offset = 0;
    tsi_result result = TSI_OK;
    gpr_slice to_send;

    do {
        size_t to_send_size = h->handshake_buffer_size - offset;
        result = tsi_handshaker_get_bytes_to_send_to_peer(
                     h->handshaker, h->handshake_buffer + offset, &to_send_size);
        offset += to_send_size;
        if (result == TSI_INCOMPLETE_DATA) {
            h->handshake_buffer_size *= 2;
            h->handshake_buffer =
                gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
        }
    } while (result == TSI_INCOMPLETE_DATA);

    if (result != TSI_OK) {
        security_handshake_done(exec_ctx, h,
                                grpc_set_tsi_error_result(
                                    GRPC_ERROR_CREATE("Handshake failed"), result));
        return;
    }

    to_send =
        gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
    gpr_slice_buffer_reset_and_unref(&h->outgoing);
    gpr_slice_buffer_add(&h->outgoing, to_send);
    /* TODO(klempner,jboeuf): This should probably use the client setup
       deadline */
    grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing,
                        &h->on_handshake_data_sent_to_peer);
}
Exemple #10
0
static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
  connector *c = arg;
  grpc_closure *notify;
  grpc_endpoint *tcp = c->newly_connecting_endpoint;
  if (tcp != NULL) {
    gpr_mu_lock(&c->mu);
    GPR_ASSERT(c->connecting_endpoint == NULL);
    c->connecting_endpoint = tcp;
    gpr_mu_unlock(&c->mu);
    if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
      grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
                        c);
      gpr_slice_buffer_init(&c->initial_string_buffer);
      gpr_slice_buffer_add(&c->initial_string_buffer,
                           c->args.initial_connect_string);
      grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
                          &c->initial_string_sent);
    } else {
      grpc_security_connector_do_handshake(exec_ctx,
                                           &c->security_connector->base, tcp,
                                           on_secure_handshake_done, c);
    }
  } else {
    memset(c->result, 0, sizeof(*c->result));
    notify = c->notify;
    c->notify = NULL;
    notify->cb(exec_ctx, notify->cb_arg, 1);
  }
}
static void handle_write(grpc_exec_ctx *exec_ctx) {
  gpr_slice slice = gpr_slice_from_copied_buffer(state.response_payload,
                                                 state.response_payload_length);

  gpr_slice_buffer_reset_and_unref(&state.outgoing_buffer);
  gpr_slice_buffer_add(&state.outgoing_buffer, slice);
  grpc_endpoint_write(exec_ctx, state.tcp, &state.outgoing_buffer, &on_write);
}
Exemple #12
0
/* Write to a socket using the grpc_tcp API, then drain it directly.
   Note that if the write does not complete immediately we need to drain the
   socket in parallel with the read. */
static void write_test(ssize_t num_bytes, ssize_t slice_size) {
  int sv[2];
  grpc_endpoint *ep;
  struct write_socket_state state;
  ssize_t read_bytes;
  size_t num_blocks;
  gpr_slice *slices;
  int current_data = 0;
  gpr_slice_buffer outgoing;
  grpc_iomgr_closure write_done_closure;
  gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20);

  gpr_log(GPR_INFO, "Start write test with %d bytes, slice size %d", num_bytes,
          slice_size);

  create_sockets(sv);

  ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"),
                       GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "test");
  grpc_endpoint_add_to_pollset(ep, &g_pollset);

  state.ep = ep;
  state.write_done = 0;

  slices = allocate_blocks(num_bytes, slice_size, &num_blocks, &current_data);

  gpr_slice_buffer_init(&outgoing);
  gpr_slice_buffer_addn(&outgoing, slices, num_blocks);
  grpc_iomgr_closure_init(&write_done_closure, write_done, &state);

  switch (grpc_endpoint_write(ep, &outgoing, &write_done_closure)) {
    case GRPC_ENDPOINT_DONE:
      /* Write completed immediately */
      read_bytes = drain_socket(sv[0]);
      GPR_ASSERT(read_bytes == num_bytes);
      break;
    case GRPC_ENDPOINT_PENDING:
      drain_socket_blocking(sv[0], num_bytes, num_bytes);
      gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
      for (;;) {
        grpc_pollset_worker worker;
        if (state.write_done) {
          break;
        }
        grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
                          deadline);
      }
      gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
      break;
    case GRPC_ENDPOINT_ERROR:
      gpr_log(GPR_ERROR, "endpoint got error");
      abort();
  }

  gpr_slice_buffer_destroy(&outgoing);
  grpc_endpoint_destroy(ep);
  gpr_free(slices);
}
Exemple #13
0
/* Write to a socket using the grpc_tcp API, then drain it directly.
   Note that if the write does not complete immediately we need to drain the
   socket in parallel with the read. */
static void write_test(size_t num_bytes, size_t slice_size) {
  int sv[2];
  grpc_endpoint *ep;
  struct write_socket_state state;
  size_t num_blocks;
  grpc_slice *slices;
  uint8_t current_data = 0;
  grpc_slice_buffer outgoing;
  grpc_closure write_done_closure;
  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(20);
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;

  gpr_log(GPR_INFO,
          "Start write test with %" PRIuPTR " bytes, slice size %" PRIuPTR,
          num_bytes, slice_size);

  create_sockets(sv);

  grpc_resource_quota *resource_quota =
      grpc_resource_quota_create("write_test");
  ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"), resource_quota,
                       GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "test");
  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
  grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);

  state.ep = ep;
  state.write_done = 0;

  slices = allocate_blocks(num_bytes, slice_size, &num_blocks, &current_data);

  grpc_slice_buffer_init(&outgoing);
  grpc_slice_buffer_addn(&outgoing, slices, num_blocks);
  grpc_closure_init(&write_done_closure, write_done, &state,
                    grpc_schedule_on_exec_ctx);

  grpc_endpoint_write(&exec_ctx, ep, &outgoing, &write_done_closure);
  drain_socket_blocking(sv[0], num_bytes, num_bytes);
  gpr_mu_lock(g_mu);
  for (;;) {
    grpc_pollset_worker *worker = NULL;
    if (state.write_done) {
      break;
    }
    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_mu_unlock(g_mu);

  grpc_slice_buffer_destroy_internal(&exec_ctx, &outgoing);
  grpc_endpoint_destroy(&exec_ctx, ep);
  gpr_free(slices);
  grpc_exec_ctx_finish(&exec_ctx);
}
Exemple #14
0
static void shutdown_during_write_test(grpc_endpoint_test_config config,
                                       size_t slice_size) {
    /* test that shutdown with a pending write creates no leaks */
    gpr_timespec deadline;
    size_t size;
    size_t nblocks;
    int current_data = 1;
    shutdown_during_write_test_state read_st;
    shutdown_during_write_test_state write_st;
    gpr_slice *slices;
    grpc_endpoint_test_fixture f =
        begin_test(config, "shutdown_during_write_test", slice_size);

    gpr_log(GPR_INFO, "testing shutdown during a write");

    read_st.ep = f.client_ep;
    write_st.ep = f.server_ep;
    read_st.done = 0;
    write_st.done = 0;

    grpc_endpoint_notify_on_read(
        read_st.ep, shutdown_during_write_test_read_handler, &read_st);
    for (size = 1;; size *= 2) {
        slices = allocate_blocks(size, 1, &nblocks, &current_data);
        switch (grpc_endpoint_write(write_st.ep, slices, nblocks,
                                    shutdown_during_write_test_write_handler,
                                    &write_st)) {
        case GRPC_ENDPOINT_WRITE_DONE:
            break;
        case GRPC_ENDPOINT_WRITE_ERROR:
            gpr_log(GPR_ERROR, "error writing");
            abort();
        case GRPC_ENDPOINT_WRITE_PENDING:
            grpc_endpoint_shutdown(write_st.ep);
            deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
            gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
            while (!write_st.done) {
                GPR_ASSERT(gpr_time_cmp(gpr_now(deadline.clock_type), deadline) < 0);
                grpc_pollset_work(g_pollset, deadline);
            }
            gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
            grpc_endpoint_destroy(write_st.ep);
            gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
            while (!read_st.done) {
                GPR_ASSERT(gpr_time_cmp(gpr_now(deadline.clock_type), deadline) < 0);
                grpc_pollset_work(g_pollset, deadline);
            }
            gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
            gpr_free(slices);
            end_test(config);
            return;
        }
        gpr_free(slices);
    }

    gpr_log(GPR_ERROR, "should never reach here");
    abort();
}
Exemple #15
0
static void read_and_write_test_write_handler(void *data,
        grpc_endpoint_cb_status error) {
    struct read_and_write_test_state *state = data;
    gpr_slice *slices = NULL;
    size_t nslices;
    grpc_endpoint_write_status write_status;

    GPR_ASSERT(error != GRPC_ENDPOINT_CB_ERROR);

    gpr_log(GPR_DEBUG, "%s: error=%d", "read_and_write_test_write_handler",
            error);

    if (error == GRPC_ENDPOINT_CB_SHUTDOWN) {
        gpr_log(GPR_INFO, "Write handler shutdown");
        gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
        state->write_done = 1;
        grpc_pollset_kick(g_pollset);
        gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
        return;
    }

    for (;;) {
        /* Need to do inline writes until they don't succeed synchronously or we
           finish writing */
        state->bytes_written += state->current_write_size;
        if (state->target_bytes - state->bytes_written <
                state->current_write_size) {
            state->current_write_size = state->target_bytes - state->bytes_written;
        }
        if (state->current_write_size == 0) {
            break;
        }

        slices = allocate_blocks(state->current_write_size, 8192, &nslices,
                                 &state->current_write_data);
        write_status =
            grpc_endpoint_write(state->write_ep, slices, nslices,
                                read_and_write_test_write_handler, state);
        gpr_log(GPR_DEBUG, "write_status=%d", write_status);
        GPR_ASSERT(write_status != GRPC_ENDPOINT_WRITE_ERROR);
        free(slices);
        if (write_status == GRPC_ENDPOINT_WRITE_PENDING) {
            return;
        }
    }
    GPR_ASSERT(state->bytes_written == state->target_bytes);

    gpr_log(GPR_INFO, "Write handler done");
    gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
    state->write_done = 1;
    grpc_pollset_kick(g_pollset);
    gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
}
Exemple #16
0
/* Write to a socket using the grpc_tcp API, then drain it directly.
   Note that if the write does not complete immediately we need to drain the
   socket in parallel with the read. */
static void write_test(size_t num_bytes, size_t slice_size) {
  int sv[2];
  grpc_endpoint *ep;
  struct write_socket_state state;
  size_t num_blocks;
  gpr_slice *slices;
  gpr_uint8 current_data = 0;
  gpr_slice_buffer outgoing;
  grpc_closure write_done_closure;
  gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20);
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;

  gpr_log(GPR_INFO, "Start write test with %d bytes, slice size %d", num_bytes,
          slice_size);

  create_sockets(sv);

  ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"),
                       GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "test");
  grpc_endpoint_add_to_pollset(&exec_ctx, ep, &g_pollset);

  state.ep = ep;
  state.write_done = 0;

  slices = allocate_blocks(num_bytes, slice_size, &num_blocks, &current_data);

  gpr_slice_buffer_init(&outgoing);
  gpr_slice_buffer_addn(&outgoing, slices, num_blocks);
  grpc_closure_init(&write_done_closure, write_done, &state);

  grpc_endpoint_write(&exec_ctx, ep, &outgoing, &write_done_closure);
  drain_socket_blocking(sv[0], num_bytes, num_bytes);
  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
  for (;;) {
    grpc_pollset_worker worker;
    if (state.write_done) {
      break;
    }
    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_mu_unlock(GRPC_POLLSET_MU(&g_pollset));

  gpr_slice_buffer_destroy(&outgoing);
  grpc_endpoint_destroy(&exec_ctx, ep);
  gpr_free(slices);
  grpc_exec_ctx_finish(&exec_ctx);
}
Exemple #17
0
void grpc_chttp2_perform_writes(
    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
    grpc_endpoint *endpoint) {
  GPR_ASSERT(transport_writing->outbuf.count > 0 ||
             grpc_chttp2_list_have_writing_streams(transport_writing));

  finalize_outbuf(transport_writing);

  GPR_ASSERT(transport_writing->outbuf.count > 0);
  GPR_ASSERT(endpoint);

  grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
                      &transport_writing->done_cb);
}
Exemple #18
0
static void start_write(internal_request *req) {
  gpr_slice_ref(req->request_text);
  switch (
      grpc_endpoint_write(req->ep, &req->request_text, 1, done_write, req)) {
    case GRPC_ENDPOINT_WRITE_DONE:
      on_written(req);
      break;
    case GRPC_ENDPOINT_WRITE_PENDING:
      break;
    case GRPC_ENDPOINT_WRITE_ERROR:
      finish(req, 0);
      break;
  }
}
Exemple #19
0
static void read_and_write_test_write_handler(void *data, int success) {
  struct read_and_write_test_state *state = data;
  gpr_slice *slices = NULL;
  size_t nslices;
  grpc_endpoint_op_status write_status;

  if (success) {
    for (;;) {
      /* Need to do inline writes until they don't succeed synchronously or we
         finish writing */
      state->bytes_written += state->current_write_size;
      if (state->target_bytes - state->bytes_written <
          state->current_write_size) {
        state->current_write_size = state->target_bytes - state->bytes_written;
      }
      if (state->current_write_size == 0) {
        break;
      }

      slices = allocate_blocks(state->current_write_size, 8192, &nslices,
                               &state->current_write_data);
      gpr_slice_buffer_reset_and_unref(&state->outgoing);
      gpr_slice_buffer_addn(&state->outgoing, slices, nslices);
      write_status = grpc_endpoint_write(state->write_ep, &state->outgoing,
                                         &state->done_write);
      free(slices);
      if (write_status == GRPC_ENDPOINT_PENDING) {
        return;
      } else if (write_status == GRPC_ENDPOINT_ERROR) {
        goto cleanup;
      }
    }
    GPR_ASSERT(state->bytes_written == state->target_bytes);
  }

cleanup:
  gpr_log(GPR_INFO, "Write handler done");
  gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
  state->write_done = 1 + success;
  grpc_pollset_kick(g_pollset, NULL);
  gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
}
Exemple #20
0
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 send_handshake_bytes_to_peer(grpc_secure_transport_setup *s) {
  size_t offset = 0;
  tsi_result result = TSI_OK;
  gpr_slice to_send;
  grpc_endpoint_write_status write_status;

  do {
    size_t to_send_size = s->handshake_buffer_size - offset;
    result = tsi_handshaker_get_bytes_to_send_to_peer(
        s->handshaker, s->handshake_buffer + offset, &to_send_size);
    offset += to_send_size;
    if (result == TSI_INCOMPLETE_DATA) {
      s->handshake_buffer_size *= 2;
      s->handshake_buffer =
          gpr_realloc(s->handshake_buffer, s->handshake_buffer_size);
    }
  } while (result == TSI_INCOMPLETE_DATA);

  if (result != TSI_OK) {
    gpr_log(GPR_ERROR, "Handshake failed with error %s",
            tsi_result_to_string(result));
    secure_transport_setup_done(s, 0);
    return;
  }

  to_send =
      gpr_slice_from_copied_buffer((const char *)s->handshake_buffer, offset);
  /* TODO(klempner,jboeuf): This should probably use the client setup
         deadline */
  write_status = grpc_endpoint_write(s->endpoint, &to_send, 1,
                                     on_handshake_data_sent_to_peer, s);
  if (write_status == GRPC_ENDPOINT_WRITE_ERROR) {
    gpr_log(GPR_ERROR, "Could not send handshake data to peer.");
    secure_transport_setup_done(s, 0);
  } else if (write_status == GRPC_ENDPOINT_WRITE_DONE) {
    on_handshake_data_sent_to_peer(s, GRPC_ENDPOINT_CB_OK);
  }
}
Exemple #22
0
// Callback for writing proxy data to the backend server.
static void on_server_write_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 write", error);
    return;
  }
  // Clear write buffer (the data we just wrote).
  grpc_slice_buffer_reset_and_unref(&conn->server_write_buffer);
  // If more data was read from the client since we started this write,
  // write that data now.
  if (conn->server_deferred_write_buffer.length > 0) {
    grpc_slice_buffer_move_into(&conn->server_deferred_write_buffer,
                                &conn->server_write_buffer);
    grpc_endpoint_write(exec_ctx, conn->server_endpoint,
                        &conn->server_write_buffer,
                        &conn->on_server_write_done);
  } else {
    // No more writes.  Unref the connection.
    proxy_connection_unref(exec_ctx, conn);
  }
}
Exemple #23
0
// Callback to connect to the backend server specified by the HTTP
// CONNECT request.
static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg,
                                   grpc_error* error) {
  proxy_connection* conn = arg;
  if (error != GRPC_ERROR_NONE) {
    // TODO(roth): Technically, in this case, we should handle the error
    // by returning an HTTP response to the client indicating that the
    // connection 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.
    proxy_connection_failed(exec_ctx, conn, true /* is_client */,
                            "HTTP proxy server connect", error);
    return;
  }
  // We've established a connection, so send back a 200 response code to
  // the client.
  // The write callback inherits our reference to conn.
  grpc_slice slice =
      grpc_slice_from_copied_string("HTTP/1.0 200 connected\r\n\r\n");
  grpc_slice_buffer_add(&conn->client_write_buffer, slice);
  grpc_endpoint_write(exec_ctx, conn->client_endpoint,
                      &conn->client_write_buffer,
                      &conn->on_write_response_done);
}
Exemple #24
0
void grpc_chttp2_perform_writes(
    grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint) {
    GPR_ASSERT(transport_writing->outbuf.count > 0 ||
               grpc_chttp2_list_have_writing_streams(transport_writing));

    finalize_outbuf(transport_writing);

    GPR_ASSERT(transport_writing->outbuf.count > 0);
    GPR_ASSERT(endpoint);

    switch (grpc_endpoint_write(endpoint, transport_writing->outbuf.slices,
                                transport_writing->outbuf.count, finish_write_cb,
                                transport_writing)) {
    case GRPC_ENDPOINT_WRITE_DONE:
        grpc_chttp2_terminate_writing(transport_writing, 1);
        break;
    case GRPC_ENDPOINT_WRITE_ERROR:
        grpc_chttp2_terminate_writing(transport_writing, 0);
        break;
    case GRPC_ENDPOINT_WRITE_PENDING:
        break;
    }
}
Exemple #25
0
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);
}
Exemple #26
0
void grpc_run_bad_client_test(const char *name, const char *client_payload,
                              size_t client_payload_length,
                              grpc_bad_client_server_side_validator validator) {
  grpc_endpoint_pair sfd;
  thd_args a;
  gpr_thd_id id;
  gpr_slice slice =
      gpr_slice_from_copied_buffer(client_payload, client_payload_length);

  /* Add a debug log */
  gpr_log(GPR_INFO, "TEST: %s", name);

  /* Init grpc */
  grpc_init();

  /* Create endpoints */
  sfd = grpc_iomgr_create_endpoint_pair(65536);

  /* Create server, completion events */
  a.server = grpc_server_create_from_filters(NULL, 0, NULL);
  a.cq = grpc_completion_queue_create();
  gpr_event_init(&a.done_thd);
  gpr_event_init(&a.done_write);
  a.validator = validator;
  grpc_server_register_completion_queue(a.server, a.cq);
  grpc_server_start(a.server);
  grpc_create_chttp2_transport(server_setup_transport, &a, NULL, sfd.server,
                               NULL, 0, grpc_mdctx_create(), 0);

  /* Bind everything into the same pollset */
  grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(a.cq));
  grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq));

  /* Check a ground truth */
  GPR_ASSERT(grpc_server_has_open_connections(a.server));

  /* Start validator */
  gpr_thd_new(&id, thd_func, &a, NULL);

  /* Write data */
  switch (grpc_endpoint_write(sfd.client, &slice, 1, done_write, &a)) {
    case GRPC_ENDPOINT_WRITE_DONE:
      done_write(&a, 1);
      break;
    case GRPC_ENDPOINT_WRITE_PENDING:
      break;
    case GRPC_ENDPOINT_WRITE_ERROR:
      done_write(&a, 0);
      break;
  }

  /* Await completion */
  GPR_ASSERT(
      gpr_event_wait(&a.done_write, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)));
  GPR_ASSERT(gpr_event_wait(&a.done_thd, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)));

  /* Shutdown */
  grpc_endpoint_destroy(sfd.client);
  grpc_server_destroy(a.server);
  grpc_completion_queue_destroy(a.cq);

  grpc_shutdown();
}
Exemple #27
0
static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
                           gpr_slice_buffer *slices, grpc_closure *cb) {
  unsigned i;
  tsi_result result = TSI_OK;
  secure_endpoint *ep = (secure_endpoint *)secure_ep;
  uint8_t *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
  uint8_t *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);

  gpr_slice_buffer_reset_and_unref(&ep->output_buffer);

  if (false && grpc_trace_secure_endpoint) {
    for (i = 0; i < slices->count; i++) {
      char *data =
          gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
      gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data);
      gpr_free(data);
    }
  }

  for (i = 0; i < slices->count; i++) {
    gpr_slice plain = slices->slices[i];
    uint8_t *message_bytes = GPR_SLICE_START_PTR(plain);
    size_t message_size = GPR_SLICE_LENGTH(plain);
    while (message_size > 0) {
      size_t protected_buffer_size_to_send = (size_t)(end - cur);
      size_t processed_message_size = message_size;
      gpr_mu_lock(&ep->protector_mu);
      result = tsi_frame_protector_protect(ep->protector, message_bytes,
                                           &processed_message_size, cur,
                                           &protected_buffer_size_to_send);
      gpr_mu_unlock(&ep->protector_mu);
      if (result != TSI_OK) {
        gpr_log(GPR_ERROR, "Encryption error: %s",
                tsi_result_to_string(result));
        break;
      }
      message_bytes += processed_message_size;
      message_size -= processed_message_size;
      cur += protected_buffer_size_to_send;

      if (cur == end) {
        flush_write_staging_buffer(ep, &cur, &end);
      }
    }
    if (result != TSI_OK) break;
  }
  if (result == TSI_OK) {
    size_t still_pending_size;
    do {
      size_t protected_buffer_size_to_send = (size_t)(end - cur);
      gpr_mu_lock(&ep->protector_mu);
      result = tsi_frame_protector_protect_flush(ep->protector, cur,
                                                 &protected_buffer_size_to_send,
                                                 &still_pending_size);
      gpr_mu_unlock(&ep->protector_mu);
      if (result != TSI_OK) break;
      cur += protected_buffer_size_to_send;
      if (cur == end) {
        flush_write_staging_buffer(ep, &cur, &end);
      }
    } while (still_pending_size > 0);
    if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) {
      gpr_slice_buffer_add(
          &ep->output_buffer,
          gpr_slice_split_head(
              &ep->write_staging_buffer,
              (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer))));
    }
  }

  if (result != TSI_OK) {
    /* TODO(yangg) do different things according to the error type? */
    gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
    grpc_exec_ctx_sched(
        exec_ctx, cb,
        grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result),
        NULL);
    return;
  }

  grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb);
}
Exemple #28
0
void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator,
                              const char *client_payload,
                              size_t client_payload_length, gpr_uint32 flags) {
  grpc_endpoint_pair sfd;
  thd_args a;
  gpr_thd_id id;
  char *hex;
  grpc_transport *transport;
  grpc_mdctx *mdctx = grpc_mdctx_create();
  gpr_slice slice =
      gpr_slice_from_copied_buffer(client_payload, client_payload_length);

  hex = gpr_dump(client_payload, client_payload_length,
                 GPR_DUMP_HEX | GPR_DUMP_ASCII);

  /* Add a debug log */
  gpr_log(GPR_INFO, "TEST: %s", hex);

  gpr_free(hex);

  /* Init grpc */
  grpc_init();

  /* Create endpoints */
  sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);

  /* Create server, completion events */
  a.server = grpc_server_create_from_filters(NULL, 0, NULL);
  a.cq = grpc_completion_queue_create(NULL);
  gpr_event_init(&a.done_thd);
  gpr_event_init(&a.done_write);
  a.validator = validator;
  grpc_server_register_completion_queue(a.server, a.cq, NULL);
  grpc_server_start(a.server);
  transport = grpc_create_chttp2_transport(NULL, sfd.server, mdctx, 0);
  server_setup_transport(&a, transport, mdctx);
  grpc_chttp2_transport_start_reading(transport, NULL, 0);

  /* Bind everything into the same pollset */
  grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(a.cq));
  grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq));

  /* Check a ground truth */
  GPR_ASSERT(grpc_server_has_open_connections(a.server));

  /* Start validator */
  gpr_thd_new(&id, thd_func, &a, NULL);

  /* Write data */
  switch (grpc_endpoint_write(sfd.client, &slice, 1, done_write, &a)) {
    case GRPC_ENDPOINT_WRITE_DONE:
      done_write(&a, 1);
      break;
    case GRPC_ENDPOINT_WRITE_PENDING:
      break;
    case GRPC_ENDPOINT_WRITE_ERROR:
      done_write(&a, 0);
      break;
  }

  /* Await completion */
  GPR_ASSERT(
      gpr_event_wait(&a.done_write, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)));

  if (flags & GRPC_BAD_CLIENT_DISCONNECT) {
    grpc_endpoint_destroy(sfd.client);
    sfd.client = NULL;
  }

  GPR_ASSERT(gpr_event_wait(&a.done_thd, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)));

  /* Shutdown */
  if (sfd.client) {
    grpc_endpoint_destroy(sfd.client);
  }
  grpc_server_shutdown_and_notify(a.server, a.cq, NULL);
  GPR_ASSERT(grpc_completion_queue_pluck(
                 a.cq, NULL, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), NULL)
                 .type == GRPC_OP_COMPLETE);
  grpc_server_destroy(a.server);
  grpc_completion_queue_destroy(a.cq);

  grpc_shutdown();
}
Exemple #29
0
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));
}
Exemple #30
0
static void start_write(grpc_exec_ctx *exec_ctx, internal_request *req) {
  gpr_slice_ref(req->request_text);
  gpr_slice_buffer_add(&req->outgoing, req->request_text);
  grpc_endpoint_write(exec_ctx, req->ep, &req->outgoing, &req->done_write);
}