diff --git a/lib/nghttp2_buf.c b/lib/nghttp2_buf.c index f4bfb54e..e7b73924 100644 --- a/lib/nghttp2_buf.c +++ b/lib/nghttp2_buf.c @@ -131,11 +131,17 @@ int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk, size_t offset) +{ + return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset); +} + +int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length, + size_t max_chunk, size_t chunk_keep, size_t offset) { int rv; nghttp2_buf_chain *chain; - if(max_chunk == 0 || chunk_length < offset) { + if(chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) { return NGHTTP2_ERR_INVALID_ARGUMENT; } @@ -152,7 +158,9 @@ int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length, nghttp2_buf_shift_right(&bufs->cur->buf, offset); bufs->chunk_length = chunk_length; - bufs->chunk_left = max_chunk - 1; + bufs->chunk_used = 1; + bufs->max_chunk = max_chunk; + bufs->chunk_keep = chunk_keep; return 0; } @@ -199,7 +207,7 @@ ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs) static int nghttp2_bufs_avail(nghttp2_bufs *bufs) { return nghttp2_buf_avail(&bufs->cur->buf) + - (bufs->chunk_length - bufs->offset) * bufs->chunk_left; + (bufs->chunk_length - bufs->offset) * (bufs->max_chunk - bufs->chunk_used); } static int nghttp2_bufs_alloc_chain(nghttp2_bufs *bufs) @@ -213,7 +221,7 @@ static int nghttp2_bufs_alloc_chain(nghttp2_bufs *bufs) return 0; } - if(bufs->chunk_left == 0) { + if(bufs->max_chunk == bufs->chunk_used) { return NGHTTP2_ERR_BUFFER_ERROR; } @@ -226,7 +234,7 @@ static int nghttp2_bufs_alloc_chain(nghttp2_bufs *bufs) "new buffer %zu bytes allocated for bufs %p, left %zu\n", bufs->chunk_length, bufs, bufs->chunk_left)); - --bufs->chunk_left; + ++bufs->chunk_used; bufs->cur->next = chain; bufs->cur = chain; @@ -382,11 +390,33 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) void nghttp2_bufs_reset(nghttp2_bufs *bufs) { - nghttp2_buf_chain *chain; + nghttp2_buf_chain *chain, *ci; + size_t k; - for(chain = bufs->head; chain; chain = chain->next) { - nghttp2_buf_reset(&chain->buf); - nghttp2_buf_shift_right(&chain->buf, bufs->offset); + k = bufs->chunk_keep; + + for(ci = bufs->head; ci; ci = ci->next) { + nghttp2_buf_reset(&ci->buf); + nghttp2_buf_shift_right(&ci->buf, bufs->offset); + + if(--k == 0) { + break; + } + } + + if(ci) { + chain = ci->next; + ci->next = NULL; + + for(ci = chain; ci;) { + chain = ci->next; + + nghttp2_buf_chain_del(ci); + + ci = chain; + } + + bufs->chunk_used = bufs->chunk_keep; } bufs->cur = bufs->head; diff --git a/lib/nghttp2_buf.h b/lib/nghttp2_buf.h index f6629a75..f5e4ecf4 100644 --- a/lib/nghttp2_buf.h +++ b/lib/nghttp2_buf.h @@ -154,7 +154,11 @@ typedef struct { /* The buffer capacity of each buf */ size_t chunk_length; /* The maximum number of nghttp2_buf_chain */ - size_t chunk_left; + size_t max_chunk; + /* The number of nghttp2_buf_chain allocated */ + size_t chunk_used; + /* The number of nghttp2_buf_chain to keep on reset */ + size_t chunk_keep; /* pos offset from begin in each buffers. On initialization and reset, buf->pos and buf->last are positioned at buf->begin + offset. */ @@ -168,11 +172,19 @@ typedef struct { int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk); +/* + * This is the same as calling nghttp2_bufs_init3 with the given + * arguments and chunk_keep = max_chunk. + */ +int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length, + size_t max_chunk, size_t offset); + /* * Initializes |bufs|. Each buffer size is given in the * |chunk_length|. The maximum number of buffers is given in the - * |max_chunk|. Each buffer will have bufs->pos and bufs->last shifted - * to left by |offset| bytes on creation and reset. + * |max_chunk|. On reset, first |chunk_keep| buffers are kept and + * remaining buffers are deleted. Each buffer will have bufs->pos and + * bufs->last shifted to left by |offset| bytes on creation and reset. * * This function allocates first buffer. bufs->head and bufs->cur * will point to the first buffer after this call. @@ -183,10 +195,11 @@ int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, * NGHTTP2_ERR_NOMEM * Out of memory. * NGHTTP2_ERR_INVALID_ARGUMENT - * max_chunk is 0 + * chunk_keep is 0; or max_chunk < chunk_keep; or offset is too + * long. */ -int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length, - size_t max_chunk, size_t offset); +int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length, + size_t max_chunk, size_t chunk_keep, size_t offset); /* * Frees any related resources to the |bufs|. diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 42d05b54..96a4b55a 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -291,9 +291,10 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, /* 2 for PAD_HIGH and PAD_LOW. We have maximum 64KB of frame serialization buffer for transmission */ - rv = nghttp2_bufs_init2(&(*session_ptr)->aob.framebufs, + rv = nghttp2_bufs_init3(&(*session_ptr)->aob.framebufs, NGHTTP2_MAX_FRAMELEN, - 65536 / NGHTTP2_MAX_FRAMELEN, + (1 << 17) / NGHTTP2_MAX_FRAMELEN, + (1 << 13) / NGHTTP2_MAX_FRAMELEN, NGHTTP2_FRAME_HDLEN + 2); if(rv != 0) { goto fail_aob_framebuf; diff --git a/tests/nghttp2_buf_test.c b/tests/nghttp2_buf_test.c index 862fafba..3fb292d0 100644 --- a/tests/nghttp2_buf_test.c +++ b/tests/nghttp2_buf_test.c @@ -203,7 +203,7 @@ void test_nghttp2_bufs_reset(void) nghttp2_buf_chain *ci; ssize_t offset = 9; - rv = nghttp2_bufs_init2(&bufs, 250, 3, offset); + rv = nghttp2_bufs_init3(&bufs, 250, 3, 1, offset); CU_ASSERT(0 == rv); rv = nghttp2_bufs_add(&bufs, "foo", 3); @@ -227,6 +227,8 @@ void test_nghttp2_bufs_reset(void) CU_ASSERT(ci->buf.pos == ci->buf.last); } + CU_ASSERT(bufs.head->next == NULL); + nghttp2_bufs_free(&bufs); } diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index f7473369..e4e46d0d 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -1996,7 +1996,7 @@ void test_nghttp2_session_send_headers_header_comp_error(void) nghttp2_nv *nva; ssize_t nvlen; size_t vallen = NGHTTP2_HD_MAX_VALUE; - nghttp2_nv nv[16]; + nghttp2_nv nv[28]; size_t nnv = ARRLEN(nv); size_t i;