int main(int argc, char **argv) {
    int four[4];
    int five[5];
    uint32_t bitset = 0;
    grpc_test_init(argc, argv);

    GPR_ASSERT(GPR_MIN(1, 2) == 1);
    GPR_ASSERT(GPR_MAX(1, 2) == 2);
    GPR_ASSERT(GPR_MIN(2, 1) == 1);
    GPR_ASSERT(GPR_MAX(2, 1) == 2);
    GPR_ASSERT(GPR_CLAMP(1, 0, 2) == 1);
    GPR_ASSERT(GPR_CLAMP(0, 0, 2) == 0);
    GPR_ASSERT(GPR_CLAMP(2, 0, 2) == 2);
    GPR_ASSERT(GPR_CLAMP(-1, 0, 2) == 0);
    GPR_ASSERT(GPR_CLAMP(3, 0, 2) == 2);
    GPR_ASSERT(GPR_ROTL((uint32_t)0x80000001, 1) == 3);
    GPR_ASSERT(GPR_ROTR((uint32_t)0x80000001, 1) == 0xc0000000);
    GPR_ASSERT(GPR_ARRAY_SIZE(four) == 4);
    GPR_ASSERT(GPR_ARRAY_SIZE(five) == 5);

    GPR_ASSERT(GPR_BITCOUNT((1u << 31) - 1) == 31);
    GPR_ASSERT(GPR_BITCOUNT(1u << 3) == 1);
    GPR_ASSERT(GPR_BITCOUNT(0) == 0);

    GPR_ASSERT(GPR_BITSET(&bitset, 3) == 8);
    GPR_ASSERT(GPR_BITCOUNT(bitset) == 1);
    GPR_ASSERT(GPR_BITGET(bitset, 3) == 1);
    GPR_ASSERT(GPR_BITSET(&bitset, 1) == 10);
    GPR_ASSERT(GPR_BITCOUNT(bitset) == 2);
    GPR_ASSERT(GPR_BITCLEAR(&bitset, 3) == 2);
    GPR_ASSERT(GPR_BITCOUNT(bitset) == 1);
    GPR_ASSERT(GPR_BITGET(bitset, 3) == 0);

    return 0;
}
static void match_initial_magic_string(gpr_slice_buffer *buffer) {
  size_t i, j, cmp_length;
  size_t magic_length = strlen(magic_connect_string);
  GPR_ASSERT(buffer->length >= magic_length);
  for (i = 0, j = 0; i < state.incoming_buffer.count && j < magic_length; i++) {
    char *dump =
        gpr_dump_slice(state.incoming_buffer.slices[i], GPR_DUMP_ASCII);
    cmp_length = GPR_MIN(strlen(dump), magic_length - j);
    GPR_ASSERT(strncmp(dump, magic_connect_string + j, cmp_length) == 0);
    j += cmp_length;
    gpr_free(dump);
  }
}
Esempio n. 3
0
void grpc_channel_update_call_size_estimate(grpc_channel *channel,
                                            size_t size) {
  size_t cur = (size_t)gpr_atm_no_barrier_load(&channel->call_size_estimate);
  if (cur < size) {
    /* size grew: update estimate */
    gpr_atm_no_barrier_cas(&channel->call_size_estimate, (gpr_atm)cur,
                           (gpr_atm)size);
    /* if we lose: never mind, something else will likely update soon enough */
  } else if (cur == size) {
    /* no change: holding pattern */
  } else if (cur > 0) {
    /* size shrank: decrease estimate */
    gpr_atm_no_barrier_cas(
        &channel->call_size_estimate, (gpr_atm)cur,
        (gpr_atm)(GPR_MIN(cur - 1, (255 * cur + size) / 256)));
    /* if we lose: never mind, something else will likely update soon enough */
  }
}
Esempio n. 4
0
/* When we try adding a measurement above the current interval range, we
   need to "shift" the buckets sufficiently to cover the new range. */
static void cws_shift_buckets(const window_stats *wstats,
                              cws_interval_stats *is, int64_t when_ns) {
  int i;
  /* number of bucket time widths to "shift" */
  int shift;
  /* number of buckets to clear */
  int nclear;
  GPR_ASSERT(when_ns >= is->top);
  /* number of bucket time widths to "shift" */
  shift = ((when_ns - is->top) / is->width) + 1;
  /* number of buckets to clear - limited by actual number of buckets */
  nclear = GPR_MIN(shift, wstats->nbuckets);
  for (i = 0; i < nclear; i++) {
    int b = BUCKET_IDX(is, i, wstats);
    is->buckets[b].count = 0;
    cws_initialize_statistic(is->buckets[b].statistic, &wstats->stat_info);
  }
  /* adjust top/bottom times and current bottom bucket */
  is->bottom_bucket = BUCKET_IDX(is, shift, wstats);
  is->top += shift * is->width;
  is->bottom += shift * is->width;
}
Esempio n. 5
0
void grpc_chttp2_hpack_compressor_set_max_table_size(
    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) {
  max_table_size = GPR_MIN(max_table_size, c->max_usable_size);
  if (max_table_size == c->max_table_size) {
    return;
  }
  while (c->table_size > 0 && c->table_size > max_table_size) {
    evict_entry(c);
  }
  c->max_table_size = max_table_size;
  c->max_table_elems = elems_for_bytes(max_table_size);
  if (c->max_table_elems > c->cap_table_elems) {
    rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems));
  } else if (c->max_table_elems < c->cap_table_elems / 3) {
    uint32_t new_cap = GPR_MAX(c->max_table_elems, 16);
    if (new_cap != c->cap_table_elems) {
      rebuild_elems(c, new_cap);
    }
  }
  c->advertise_table_size_change = 1;
  gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
}
Esempio n. 6
0
gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now) {
  const double new_timeout_millis =
      backoff->multiplier * (double)backoff->current_timeout_millis;
  backoff->current_timeout_millis =
      GPR_MIN((int64_t)new_timeout_millis, backoff->max_timeout_millis);

  const double jitter_range_width = backoff->jitter * new_timeout_millis;
  const double jitter =
      (2 * generate_uniform_random_number(&backoff->rng_state) - 1) *
      jitter_range_width;

  backoff->current_timeout_millis =
      (int64_t)((double)(backoff->current_timeout_millis) + jitter);

  const gpr_timespec current_deadline = gpr_time_add(
      now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN));

  const gpr_timespec min_deadline = gpr_time_add(
      now, gpr_time_from_millis(backoff->min_timeout_millis, GPR_TIMESPAN));

  return gpr_time_max(current_deadline, min_deadline);
}
Esempio n. 7
0
static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx,
                                          grpc_chttp2_transport *t,
                                          grpc_chttp2_stream *s) {
  uint32_t incoming_frame_size = t->incoming_frame_size;
  if (incoming_frame_size > t->incoming_window) {
    char *msg;
    gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
                 t->incoming_frame_size, t->incoming_window);
    grpc_error *err = GRPC_ERROR_CREATE(msg);
    gpr_free(msg);
    return err;
  }

  GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", t, incoming_window,
                                   incoming_frame_size);

  if (s != NULL) {
    if (incoming_frame_size > s->incoming_window) {
      char *msg;
      gpr_asprintf(&msg,
                   "frame of size %d overflows incoming window of %" PRId64,
                   t->incoming_frame_size, s->incoming_window);
      grpc_error *err = GRPC_ERROR_CREATE(msg);
      gpr_free(msg);
      return err;
    }

    GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", t, s, incoming_window,
                                  incoming_frame_size);
    s->received_bytes += incoming_frame_size;
    s->max_recv_bytes -=
        (uint32_t)GPR_MIN(s->max_recv_bytes, incoming_frame_size);
  }

  return GRPC_ERROR_NONE;
}
Esempio n. 8
0
void grpc_chttp2_hpack_compressor_set_max_usable_size(
    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) {
  c->max_usable_size = max_table_size;
  grpc_chttp2_hpack_compressor_set_max_table_size(
      c, GPR_MIN(c->max_table_size, max_table_size));
}
Esempio n. 9
0
int grpc_chttp2_unlocking_check_writes(
    grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_writing *transport_writing) {
    grpc_chttp2_stream_global *stream_global;
    grpc_chttp2_stream_writing *stream_writing;
    grpc_chttp2_stream_global *first_reinserted_stream = NULL;
    gpr_uint32 window_delta;

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

    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;
    }

    /* 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)) {
        if (stream_global == first_reinserted_stream) {
            /* prevent infinite loop */
            grpc_chttp2_list_add_first_writable_stream(transport_global,
                    stream_global);
            break;
        }

        stream_writing->id = stream_global->id;
        stream_writing->send_closed = GRPC_DONT_SEND_CLOSED;

        if (stream_global->outgoing_sopb) {
            window_delta =
                grpc_chttp2_preencode(stream_global->outgoing_sopb->ops,
                                      &stream_global->outgoing_sopb->nops,
                                      GPR_MIN(transport_global->outgoing_window,
                                              stream_global->outgoing_window),
                                      &stream_writing->sopb);
            GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
                "write", transport_global, outgoing_window, -(gpr_int64)window_delta);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
                                             outgoing_window,
                                             -(gpr_int64)window_delta);
            transport_global->outgoing_window -= window_delta;
            stream_global->outgoing_window -= window_delta;

            if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE &&
                    stream_global->outgoing_sopb->nops == 0) {
                if (!transport_global->is_client && !stream_global->read_closed) {
                    stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM;
                } else {
                    stream_writing->send_closed = GRPC_SEND_CLOSED;
                }
            }

            if (stream_global->outgoing_window > 0 &&
                    stream_global->outgoing_sopb->nops != 0) {
                grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
                if (first_reinserted_stream == NULL &&
                        transport_global->outgoing_window == 0) {
                    first_reinserted_stream = stream_global;
                }
            }
        }

        if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) {
            stream_writing->announce_window = stream_global->unannounced_incoming_window;
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
                                             incoming_window, stream_global->unannounced_incoming_window);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
                                             unannounced_incoming_window, -(gpr_int64)stream_global->unannounced_incoming_window);
            stream_global->incoming_window += stream_global->unannounced_incoming_window;
            stream_global->unannounced_incoming_window = 0;
            grpc_chttp2_list_add_incoming_window_updated(transport_global,
                    stream_global);
            stream_global->writing_now |= GRPC_CHTTP2_WRITING_WINDOW;
        }
        if (stream_writing->sopb.nops > 0 ||
                stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
            stream_global->writing_now |= GRPC_CHTTP2_WRITING_DATA;
        }
        if (stream_global->writing_now != 0) {
            grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
        }
    }

    /* if the grpc_chttp2_transport is ready to send a window update, do so here
       also; 3/4 is a magic number that will likely get tuned soon */
    if (transport_global->incoming_window <
            transport_global->connection_window_target * 3 / 4) {
        window_delta = transport_global->connection_window_target -
                       transport_global->incoming_window;
        gpr_slice_buffer_add(&transport_writing->outbuf,
                             grpc_chttp2_window_update_create(0, window_delta));
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("write", transport_global,
                                            incoming_window, window_delta);
        transport_global->incoming_window += window_delta;
    }

    return transport_writing->outbuf.count > 0 ||
           grpc_chttp2_list_have_writing_streams(transport_writing);
}
Esempio n. 10
0
void grpc_chttp2_publish_reads(
    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_parsing *transport_parsing) {
  grpc_chttp2_stream_global *stream_global;
  grpc_chttp2_stream_parsing *stream_parsing;
  int was_zero;
  int is_zero;

  /* transport_parsing->last_incoming_stream_id is used as
     last-grpc_chttp2_stream-id when
     sending GOAWAY frame.
     https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8
     says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream
     ID.  So,
     since we don't have server pushed streams, client should send
     GOAWAY last-grpc_chttp2_stream-id=0 in this case. */
  if (!transport_parsing->is_client) {
    transport_global->last_incoming_stream_id =
        transport_parsing->last_incoming_stream_id;
  }

  /* update global settings */
  if (transport_parsing->settings_updated) {
    memcpy(transport_global->settings[GRPC_PEER_SETTINGS],
           transport_parsing->settings, sizeof(transport_parsing->settings));
    transport_parsing->settings_updated = 0;
  }

  /* update settings based on ack if received */
  if (transport_parsing->settings_ack_received) {
    memcpy(transport_global->settings[GRPC_ACKED_SETTINGS],
           transport_global->settings[GRPC_SENT_SETTINGS],
           GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
    transport_parsing->settings_ack_received = 0;
    transport_global->sent_local_settings = 0;
  }

  /* move goaway to the global state if we received one (it will be
     published later */
  if (transport_parsing->goaway_received) {
    grpc_chttp2_add_incoming_goaway(exec_ctx, transport_global,
                                    (uint32_t)transport_parsing->goaway_error,
                                    transport_parsing->goaway_text);
    transport_parsing->goaway_text = gpr_empty_slice();
    transport_parsing->goaway_received = 0;
  }

  /* propagate flow control tokens to global state */
  was_zero = transport_global->outgoing_window <= 0;
  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window,
                                  transport_parsing, outgoing_window);
  is_zero = transport_global->outgoing_window <= 0;
  if (was_zero && !is_zero) {
    while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
                                                     &stream_global)) {
      grpc_chttp2_become_writable(transport_global, stream_global);
    }
  }

  if (transport_parsing->incoming_window <
      transport_global->connection_window_target * 3 / 4) {
    int64_t announce_bytes = transport_global->connection_window_target -
                             transport_parsing->incoming_window;
    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global,
                                      announce_incoming_window, announce_bytes);
    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing,
                                      incoming_window, announce_bytes);
  }

  /* for each stream that saw an update, fixup global state */
  while (grpc_chttp2_list_pop_parsing_seen_stream(
      transport_global, transport_parsing, &stream_global, &stream_parsing)) {
    if (stream_parsing->seen_error) {
      stream_global->seen_error = true;
      stream_global->exceeded_metadata_size =
          stream_parsing->exceeded_metadata_size;
      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
    }

    /* flush stats to global stream state */
    grpc_transport_move_stats(&stream_parsing->stats, &stream_global->stats);

    /* update outgoing flow control window */
    was_zero = stream_global->outgoing_window <= 0;
    GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global,
                                 outgoing_window, stream_parsing,
                                 outgoing_window);
    is_zero = stream_global->outgoing_window <= 0;
    if (was_zero && !is_zero) {
      grpc_chttp2_become_writable(transport_global, stream_global);
    }

    stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(
        stream_global->max_recv_bytes, stream_parsing->received_bytes);
    stream_parsing->received_bytes = 0;

    /* publish incoming stream ops */
    if (stream_global->incoming_frames.tail != NULL) {
      stream_global->incoming_frames.tail->is_tail = 0;
    }
    if (stream_parsing->data_parser.incoming_frames.head != NULL) {
      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
    }
    grpc_chttp2_incoming_frame_queue_merge(
        &stream_global->incoming_frames,
        &stream_parsing->data_parser.incoming_frames);
    if (stream_global->incoming_frames.tail != NULL) {
      stream_global->incoming_frames.tail->is_tail = 1;
    }

    if (!stream_global->published_initial_metadata &&
        stream_parsing->got_metadata_on_parse[0]) {
      stream_parsing->got_metadata_on_parse[0] = 0;
      stream_global->published_initial_metadata = 1;
      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
               stream_parsing->metadata_buffer[0],
               stream_global->received_initial_metadata);
      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
    }
    if (!stream_global->published_trailing_metadata &&
        stream_parsing->got_metadata_on_parse[1]) {
      stream_parsing->got_metadata_on_parse[1] = 0;
      stream_global->published_trailing_metadata = 1;
      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
               stream_parsing->metadata_buffer[1],
               stream_global->received_trailing_metadata);
      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
    }

    if (stream_parsing->forced_close_error != GRPC_ERROR_NONE) {
      intptr_t reason;
      bool has_reason = grpc_error_get_int(stream_parsing->forced_close_error,
                                           GRPC_ERROR_INT_HTTP2_ERROR, &reason);
      if (has_reason && reason != GRPC_CHTTP2_NO_ERROR) {
        grpc_status_code status_code =
            has_reason
                ? grpc_chttp2_http2_error_to_grpc_status(
                      (grpc_chttp2_error_code)reason, stream_global->deadline)
                : GRPC_STATUS_INTERNAL;
        const char *status_details =
            grpc_error_string(stream_parsing->forced_close_error);
        gpr_slice slice_details = gpr_slice_from_copied_string(status_details);
        grpc_error_free_string(status_details);
        grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
                                status_code, &slice_details);
      }
      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
                                     1, 1, stream_parsing->forced_close_error);
    }

    if (stream_parsing->received_close) {
      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
                                     1, 0, GRPC_ERROR_NONE);
    }
  }
}
Esempio n. 11
0
static void perform_stream_op_locked(
    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
  if (op->cancel_with_status != GRPC_STATUS_OK) {
    cancel_from_api(transport_global, stream_global, op->cancel_with_status);
  }

  if (op->close_with_status != GRPC_STATUS_OK) {
    close_from_api(transport_global, stream_global, op->close_with_status,
                   op->optional_close_message);
  }

  if (op->send_ops) {
    GPR_ASSERT(stream_global->outgoing_sopb == NULL);
    stream_global->send_done_closure = op->on_done_send;
    if (!stream_global->cancelled) {
      stream_global->written_anything = 1;
      stream_global->outgoing_sopb = op->send_ops;
      if (op->is_last_send &&
          stream_global->write_state == GRPC_WRITE_STATE_OPEN) {
        stream_global->write_state = GRPC_WRITE_STATE_QUEUED_CLOSE;
      }
      if (stream_global->id == 0) {
        GRPC_CHTTP2_IF_TRACING(gpr_log(
            GPR_DEBUG,
            "HTTP:%s: New grpc_chttp2_stream %p waiting for concurrency",
            transport_global->is_client ? "CLI" : "SVR", stream_global));
        grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
                                                     stream_global);
        maybe_start_some_streams(exec_ctx, transport_global);
      } else if (stream_global->outgoing_window > 0) {
        grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
      }
    } else {
      grpc_sopb_reset(op->send_ops);
      grpc_exec_ctx_enqueue(exec_ctx, stream_global->send_done_closure, 0);
    }
  }

  if (op->recv_ops) {
    GPR_ASSERT(stream_global->publish_sopb == NULL);
    GPR_ASSERT(stream_global->published_state != GRPC_STREAM_CLOSED);
    stream_global->recv_done_closure = op->on_done_recv;
    stream_global->publish_sopb = op->recv_ops;
    stream_global->publish_sopb->nops = 0;
    stream_global->publish_state = op->recv_state;
    /* clamp max recv bytes */
    op->max_recv_bytes = GPR_MIN(op->max_recv_bytes, GPR_UINT32_MAX);
    if (stream_global->max_recv_bytes < op->max_recv_bytes) {
      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
          "op", transport_global, stream_global, max_recv_bytes,
          op->max_recv_bytes - stream_global->max_recv_bytes);
      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
          "op", transport_global, stream_global, unannounced_incoming_window,
          op->max_recv_bytes - stream_global->max_recv_bytes);
      stream_global->unannounced_incoming_window +=
          (gpr_uint32)op->max_recv_bytes - stream_global->max_recv_bytes;
      stream_global->max_recv_bytes = (gpr_uint32)op->max_recv_bytes;
    }
    grpc_chttp2_incoming_metadata_live_op_buffer_end(
        &stream_global->outstanding_metadata);
    grpc_chttp2_list_add_read_write_state_changed(transport_global,
                                                  stream_global);
    if (stream_global->id != 0) {
      grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
    }
  }

  if (op->bind_pollset) {
    add_to_pollset_locked(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
                          op->bind_pollset);
  }

  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1);
}