Example #1
0
/*
 *   local_window_size
 *   ^  *
 *   |  *    recv_window_size
 *   |  *  * ^
 *   |  *  * |
 *  0+++++++++
 *   |  *  *   \
 *   |  *  *   | This rage is hidden in flow control.  But it must be
 *   v  *  *   / kept in order to restore it when window size is enlarged.
 *   recv_reduction
 *   (+ for negative direction)
 *
 *   recv_window_size could be negative if we decrease
 *   local_window_size more than recv_window_size:
 *
 *   local_window_size
 *   ^  *
 *   |  *
 *   |  *
 *   0++++++++
 *   |  *    ^ recv_window_size (negative)
 *   |  *    |
 *   v  *  *
 *   recv_reduction
 */
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
                                     int32_t *recv_window_size_ptr,
                                     int32_t *recv_reduction_ptr,
                                     int32_t *delta_ptr) {
  if (*delta_ptr > 0) {
    int32_t recv_reduction_delta;
    int32_t delta;
    int32_t new_recv_window_size =
        nghttp2_max(0, *recv_window_size_ptr) - *delta_ptr;

    if (new_recv_window_size >= 0) {
      *recv_window_size_ptr = new_recv_window_size;
      return 0;
    }

    delta = -new_recv_window_size;

    /* The delta size is strictly more than received bytes. Increase
       local_window_size by that difference |delta|. */
    if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) {
      return NGHTTP2_ERR_FLOW_CONTROL;
    }
    *local_window_size_ptr += delta;
    /* If there is recv_reduction due to earlier window_size
       reduction, we have to adjust it too. */
    recv_reduction_delta = nghttp2_min(*recv_reduction_ptr, delta);
    *recv_reduction_ptr -= recv_reduction_delta;
    if (*recv_window_size_ptr < 0) {
      *recv_window_size_ptr += recv_reduction_delta;
    } else {
      /* If *recv_window_size_ptr > 0, then those bytes are going to
         be returned to the remote peer (by WINDOW_UPDATE with the
         adjusted *delta_ptr), so it is effectively 0 now.  We set to
         *recv_reduction_delta, because caller does not take into
         account it in *delta_ptr. */
      *recv_window_size_ptr = recv_reduction_delta;
    }
    /* recv_reduction_delta must be paied from *delta_ptr, since it
       was added in window size reduction (see below). */
    *delta_ptr -= recv_reduction_delta;

    return 0;
  }

  if (*local_window_size_ptr + *delta_ptr < 0 ||
      *recv_window_size_ptr < INT32_MIN - *delta_ptr ||
      *recv_reduction_ptr > INT32_MAX + *delta_ptr) {
    return NGHTTP2_ERR_FLOW_CONTROL;
  }
  /* Decreasing local window size. Note that we achieve this without
     noticing to the remote peer. To do this, we cut
     recv_window_size by -delta. This means that we don't send
     WINDOW_UPDATE for -delta bytes. */
  *local_window_size_ptr += *delta_ptr;
  *recv_window_size_ptr += *delta_ptr;
  *recv_reduction_ptr -= *delta_ptr;
  *delta_ptr = 0;

  return 0;
}
Example #2
0
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
{
  uint8_t *ptr;
  size_t cap;

  cap = nghttp2_buf_cap(buf);

  if(cap >= new_cap) {
    return 0;
  }

  new_cap = nghttp2_max(new_cap, cap * 2);

  ptr = (uint8_t *)realloc(buf->begin, new_cap);
  if(ptr == NULL) {
    return NGHTTP2_ERR_NOMEM;
  }

  buf->pos = ptr + (buf->pos - buf->begin);
  buf->last = ptr + (buf->last - buf->begin);
  buf->mark = ptr + (buf->mark - buf->begin);
  buf->begin = ptr;
  buf->end = ptr + new_cap;

  return 0;
}
Example #3
0
void nghttp2_stream_reschedule(nghttp2_stream *stream) {
  nghttp2_stream *dep_stream;

  assert(stream->queued);

  dep_stream = stream->dep_prev;

  for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
    if (nghttp2_pq_size(&dep_stream->obq) == 1) {
      dep_stream->descendant_last_cycle = 0;
      stream->cycle = 0;
    } else {
      dep_stream->descendant_last_cycle =
          nghttp2_max(dep_stream->descendant_last_cycle, stream->cycle);

      stream->cycle =
          stream_next_cycle(stream, dep_stream->descendant_last_cycle);

      nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
      nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
    }

    DEBUGF(fprintf(stderr, "stream: stream=%d obq resched cycle=%ld\n",
                   stream->stream_id, stream->cycle));

    dep_stream->last_writelen = stream->last_writelen;
  }
}
Example #4
0
int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
                                 int32_t stream_id,
                                 int32_t window_size_increment) {
  int rv;
  nghttp2_stream *stream = 0;
  if (window_size_increment == 0) {
    return 0;
  }
  flags = 0;
  if (stream_id == 0) {
    rv = nghttp2_adjust_local_window_size(
        &session->local_window_size, &session->recv_window_size,
        &session->recv_reduction, &window_size_increment);
    if (rv != 0) {
      return rv;
    }
  } else {
    stream = nghttp2_session_get_stream(session, stream_id);
    if (!stream) {
      return 0;
    }

    rv = nghttp2_adjust_local_window_size(
        &stream->local_window_size, &stream->recv_window_size,
        &stream->recv_reduction, &window_size_increment);
    if (rv != 0) {
      return rv;
    }
  }

  if (window_size_increment > 0) {
    if (stream_id == 0) {
      session->consumed_size =
          nghttp2_max(0, session->consumed_size - window_size_increment);
    } else {
      stream->consumed_size =
          nghttp2_max(0, stream->consumed_size - window_size_increment);
    }

    return nghttp2_session_add_window_update(session, flags, stream_id,
                                             window_size_increment);
  }
  return 0;
}
Example #5
0
int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
                                                        int32_t weight) {
  if (stream->sum_norest_weight == 0) {
    return stream->effective_weight;
  }

  weight = stream->effective_weight * weight / stream->sum_norest_weight;

  return nghttp2_max(1, weight);
}
Example #6
0
int nghttp2_buffer_reserve(nghttp2_buffer *buffer, size_t len)
{
  if(len > buffer->max_capacity) {
    return NGHTTP2_ERR_BUFFER_ERROR;
  }
  if(buffer->capacity < len) {
    uint8_t *new_buf;
    size_t new_cap = buffer->capacity == 0 ? 8 : buffer->capacity * 3 / 2;
    new_cap = nghttp2_min(buffer->max_capacity, nghttp2_max(new_cap, len));
    new_buf = realloc(buffer->buf, new_cap);
    if(new_buf == NULL) {
      return NGHTTP2_ERR_NOMEM;
    }
    buffer->buf = new_buf;
    buffer->capacity = new_cap;
  }
  return 0;
}
Example #7
0
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
                                              int32_t weight) {
  weight = stream->weight * weight / stream->sum_dep_weight;

  return nghttp2_max(1, weight);
}