int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) { int rv; size_t nwrite; nghttp2_buf *buf; const uint8_t *p; if(bufs_avail(bufs) < (ssize_t)len) { return NGHTTP2_ERR_BUFFER_ERROR; } p = (const uint8_t *)data; while(len) { buf = &bufs->cur->buf; nwrite = nghttp2_min((size_t)nghttp2_buf_avail(buf), len); if(nwrite == 0) { rv = bufs_alloc_chain(bufs); if(rv != 0) { return rv; } continue; } buf->last = nghttp2_cpymem(buf->last, p, nwrite); p += len; len -= nwrite; } return 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; }
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) { int rv; size_t nwrite; nghttp2_buf *buf; const uint8_t *p; // h1994st: if (!bufs->random_enabled && bufs_avail(bufs) < len) { return NGHTTP2_ERR_BUFFER_ERROR; } p = data; while (len) { buf = &bufs->cur->buf; nwrite = nghttp2_min(nghttp2_buf_avail(buf), len); if (nwrite == 0) { rv = bufs_alloc_chain(bufs); if (rv != 0) { return rv; } continue; } buf->last = nghttp2_cpymem(buf->last, p, nwrite); p += nwrite; len -= nwrite; } return 0; }
int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr, int32_t *recv_window_size_ptr, int32_t *recv_reduction_ptr, int32_t *delta_ptr) { int32_t recv_reduction_delta; int32_t delta; delta = *delta_ptr; assert(delta >= 0); /* 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; *recv_window_size_ptr += recv_reduction_delta; /* recv_reduction_delta must be paid from *delta_ptr, since it was added in window size reduction (see below). */ *delta_ptr -= recv_reduction_delta; return 0; }
static ssize_t data_feed_recv_callback(nghttp2_session *session, uint8_t *data, size_t len, int flags, void *user_data) { data_feed *df = ((my_user_data *)user_data)->df; size_t avail = (size_t)(df->datalimit - df->datamark); size_t wlen = nghttp2_min(avail, len); (void)session; (void)flags; memcpy(data, df->datamark, wlen); df->datamark += wlen; return (ssize_t)wlen; }
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; }