Beispiel #1
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) {
    gpr_slice_buffer_move_into(&conn->server_read_buffer,
                               &conn->client_deferred_write_buffer);
  } else {
    gpr_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 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 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);
  }
}
Beispiel #4
0
void grpc_do_security_handshake(
    grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker,
    grpc_security_connector *connector, bool is_client_side,
    grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
    gpr_timespec deadline, grpc_security_handshake_done_cb cb,
    void *user_data) {
    grpc_security_connector_handshake_list *handshake_node;
    grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
    memset(h, 0, sizeof(grpc_security_handshake));
    h->handshaker = handshaker;
    h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
    h->is_client_side = is_client_side;
    h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
    h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
    h->wrapped_endpoint = nonsecure_endpoint;
    h->user_data = user_data;
    h->cb = cb;
    gpr_ref_init(&h->refs, 2); /* timer and handshake proper each get a ref */
    grpc_closure_init(&h->on_handshake_data_sent_to_peer,
                      on_handshake_data_sent_to_peer, h);
    grpc_closure_init(&h->on_handshake_data_received_from_peer,
                      on_handshake_data_received_from_peer, h);
    gpr_slice_buffer_init(&h->left_overs);
    gpr_slice_buffer_init(&h->outgoing);
    gpr_slice_buffer_init(&h->incoming);
    if (read_buffer != NULL) {
        gpr_slice_buffer_move_into(read_buffer, &h->incoming);
        gpr_free(read_buffer);
    }
    if (!is_client_side) {
        grpc_server_security_connector *server_connector =
            (grpc_server_security_connector *)connector;
        handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list));
        handshake_node->handshake = h;
        gpr_mu_lock(&server_connector->mu);
        handshake_node->next = server_connector->handshaking_handshakes;
        server_connector->handshaking_handshakes = handshake_node;
        gpr_mu_unlock(&server_connector->mu);
    }
    send_handshake_bytes_to_peer(exec_ctx, h);
    grpc_timer_init(exec_ctx, &h->timer,
                    gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                    on_timeout, h, gpr_now(GPR_CLOCK_MONOTONIC));
}
Beispiel #5
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).
  gpr_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) {
    gpr_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);
  }
}
Beispiel #6
0
void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n,
                                 gpr_slice_buffer *dst) {
  size_t src_idx;
  size_t output_len = dst->length + n;
  size_t new_input_len = src->length - n;
  GPR_ASSERT(src->length >= n);
  if (src->length == n) {
    gpr_slice_buffer_move_into(src, dst);
    return;
  }
  src_idx = 0;
  while (src_idx < src->capacity) {
    gpr_slice slice = src->slices[src_idx];
    size_t slice_len = GPR_SLICE_LENGTH(slice);
    if (n > slice_len) {
      gpr_slice_buffer_add(dst, slice);
      n -= slice_len;
      src_idx++;
    } else if (n == slice_len) {
      gpr_slice_buffer_add(dst, slice);
      src_idx++;
      break;
    } else { /* n < slice_len */
      src->slices[src_idx] = gpr_slice_split_tail(&slice, n);
      GPR_ASSERT(GPR_SLICE_LENGTH(slice) == n);
      GPR_ASSERT(GPR_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n);
      gpr_slice_buffer_add(dst, slice);
      break;
    }
  }
  GPR_ASSERT(dst->length == output_len);
  memmove(src->slices, src->slices + src_idx,
          sizeof(gpr_slice) * (src->count - src_idx));
  src->count -= src_idx;
  src->length = new_input_len;
  GPR_ASSERT(src->count > 0);
}
Beispiel #7
0
void grpc_chttp2_publish_reads(
    grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_parsing *transport_parsing) {
    grpc_chttp2_stream_global *stream_global;
    grpc_chttp2_stream_parsing *stream_parsing;

    /* 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->incoming_stream_id;
    }

    /* copy parsing qbuf to global qbuf */
    gpr_slice_buffer_move_into(&transport_parsing->qbuf, &transport_global->qbuf);

    /* 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(gpr_uint32));
        transport_parsing->settings_ack_received = 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(transport_global,
                                        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 */
    if (transport_parsing->outgoing_window_update) {
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
            "parsed", transport_global, outgoing_window,
            transport_parsing->outgoing_window_update);
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
            "parsed", transport_parsing, outgoing_window_update,
            -(gpr_int64)transport_parsing->outgoing_window_update);
        transport_global->outgoing_window +=
            transport_parsing->outgoing_window_update;
        transport_parsing->outgoing_window_update = 0;
    }

    if (transport_parsing->incoming_window_delta) {
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
            "parsed", transport_global, incoming_window,
            -(gpr_int64)transport_parsing->incoming_window_delta);
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
            "parsed", transport_parsing, incoming_window_delta,
            -(gpr_int64)transport_parsing->incoming_window_delta);
        transport_global->incoming_window -=
            transport_parsing->incoming_window_delta;
        transport_parsing->incoming_window_delta = 0;
    }

    /* 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)) {
        /* update incoming flow control window */
        if (stream_parsing->incoming_window_delta) {
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
                "parsed", transport_parsing, stream_global, incoming_window,
                -(gpr_int64)stream_parsing->incoming_window_delta);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
                "parsed", transport_parsing, stream_parsing, incoming_window_delta,
                -(gpr_int64)stream_parsing->incoming_window_delta);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
                "parsed", transport_parsing, stream_global, max_recv_bytes,
                -(gpr_int64)stream_parsing->incoming_window_delta);
            stream_global->incoming_window -= stream_parsing->incoming_window_delta;
            GPR_ASSERT(stream_global->max_recv_bytes >=
                       stream_parsing->incoming_window_delta);
            stream_global->max_recv_bytes -=
                stream_parsing->incoming_window_delta;
            stream_parsing->incoming_window_delta = 0;
            grpc_chttp2_list_add_writable_window_update_stream(transport_global,
                    stream_global);
        }

        /* update outgoing flow control window */
        if (stream_parsing->outgoing_window_update) {
            int was_zero = stream_global->outgoing_window <= 0;
            int is_zero;
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("parsed", transport_parsing,
                                             stream_global, outgoing_window,
                                             stream_parsing->outgoing_window_update);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
                "parsed", transport_parsing, stream_parsing, outgoing_window_update,
                -(gpr_int64)stream_parsing->outgoing_window_update);
            stream_global->outgoing_window += stream_parsing->outgoing_window_update;
            stream_parsing->outgoing_window_update = 0;
            is_zero = stream_global->outgoing_window <= 0;
            if (was_zero && !is_zero) {
                grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
            }
        }

        /* updating closed status */
        if (stream_parsing->received_close) {
            stream_global->read_closed = 1;
            grpc_chttp2_list_add_read_write_state_changed(transport_global,
                    stream_global);
        }
        if (stream_parsing->saw_rst_stream) {
            stream_global->cancelled = 1;
            stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status(
                                                  stream_parsing->rst_stream_reason);
            if (stream_parsing->rst_stream_reason == GRPC_CHTTP2_NO_ERROR) {
                stream_global->published_cancelled = 1;
            }
            grpc_chttp2_list_add_read_write_state_changed(transport_global,
                    stream_global);
        }

        /* publish incoming stream ops */
        if (stream_parsing->data_parser.incoming_sopb.nops > 0) {
            grpc_incoming_metadata_buffer_move_to_referencing_sopb(
                &stream_parsing->incoming_metadata, &stream_global->incoming_metadata,
                &stream_parsing->data_parser.incoming_sopb);
            grpc_sopb_move_to(&stream_parsing->data_parser.incoming_sopb,
                              &stream_global->incoming_sopb);
            grpc_chttp2_list_add_read_write_state_changed(transport_global,
                    stream_global);
        }
    }
}
Beispiel #8
0
int grpc_chttp2_unlocking_check_writes(
    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_writing *transport_writing) {
  grpc_chttp2_stream_global *stream_global;
  grpc_chttp2_stream_writing *stream_writing;

  GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0);

  transport_writing->max_frame_size =
      transport_global->settings[GRPC_ACKED_SETTINGS]
                                [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE];

  if (transport_global->dirtied_local_settings &&
      !transport_global->sent_local_settings) {
    gpr_slice_buffer_add(
        &transport_writing->outbuf,
        grpc_chttp2_settings_create(
            transport_global->settings[GRPC_SENT_SETTINGS],
            transport_global->settings[GRPC_LOCAL_SETTINGS],
            transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
    transport_global->force_send_settings = 0;
    transport_global->dirtied_local_settings = 0;
    transport_global->sent_local_settings = 1;
  }

  /* simple writes are queued to qbuf, and flushed here */
  gpr_slice_buffer_move_into(&transport_global->qbuf,
                             &transport_writing->outbuf);
  GPR_ASSERT(transport_global->qbuf.count == 0);

  grpc_chttp2_hpack_compressor_set_max_table_size(
      &transport_writing->hpack_compressor,
      transport_global->settings[GRPC_PEER_SETTINGS]
                                [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);

  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
                                  transport_global, outgoing_window);
  if (transport_writing->outgoing_window > 0) {
    while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
                                                     &stream_global)) {
      grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
                                  false, "transport.read_flow_control");
    }
  }

  /* for each grpc_chttp2_stream that's become writable, frame it's data
     (according to available window sizes) and add to the output buffer */
  while (grpc_chttp2_list_pop_writable_stream(
      transport_global, transport_writing, &stream_global, &stream_writing)) {
    bool sent_initial_metadata = stream_writing->sent_initial_metadata;
    bool become_writable = false;

    stream_writing->id = stream_global->id;
    stream_writing->read_closed = stream_global->read_closed;

    GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing,
                                 outgoing_window, stream_global,
                                 outgoing_window);

    if (!sent_initial_metadata && stream_global->send_initial_metadata) {
      stream_writing->send_initial_metadata =
          stream_global->send_initial_metadata;
      stream_global->send_initial_metadata = NULL;
      become_writable = true;
      sent_initial_metadata = true;
    }
    if (sent_initial_metadata) {
      if (stream_global->send_message != NULL) {
        gpr_slice hdr = gpr_slice_malloc(5);
        uint8_t *p = GPR_SLICE_START_PTR(hdr);
        uint32_t len = stream_global->send_message->length;
        GPR_ASSERT(stream_writing->send_message == NULL);
        p[0] = (stream_global->send_message->flags &
                GRPC_WRITE_INTERNAL_COMPRESS) != 0;
        p[1] = (uint8_t)(len >> 24);
        p[2] = (uint8_t)(len >> 16);
        p[3] = (uint8_t)(len >> 8);
        p[4] = (uint8_t)(len);
        gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr);
        if (stream_global->send_message->length > 0) {
          stream_writing->send_message = stream_global->send_message;
        } else {
          stream_writing->send_message = NULL;
        }
        stream_writing->stream_fetched = 0;
        stream_global->send_message = NULL;
      }
      if ((stream_writing->send_message != NULL ||
           stream_writing->flow_controlled_buffer.length > 0) &&
          stream_writing->outgoing_window > 0) {
        if (transport_writing->outgoing_window > 0) {
          become_writable = true;
        } else {
          grpc_chttp2_list_add_stalled_by_transport(transport_writing,
                                                    stream_writing);
        }
      }
      if (stream_global->send_trailing_metadata) {
        stream_writing->send_trailing_metadata =
            stream_global->send_trailing_metadata;
        stream_global->send_trailing_metadata = NULL;
        become_writable = true;
      }
    }

    if (!stream_global->read_closed &&
        stream_global->unannounced_incoming_window_for_writing > 1024) {
      GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing,
                                   announce_window, stream_global,
                                   unannounced_incoming_window_for_writing);
      become_writable = true;
    }

    if (become_writable) {
      grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
    } else {
      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
    }
  }