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