Commit 92a56d03 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

Fix bug that idle/closed stream may be destroyed while it is referenced

parent 5de2c7a8
This diff is collapsed.
......@@ -73,6 +73,10 @@ typedef struct {
/* The default maximum number of incoming reserved streams */
#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200
/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this
number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */
#define NGHTTP2_MIN_IDLE_STREAMS 16
/* The maximum number of items in outbound queue, which is considered
as flooding caused by peer. All frames are not considered here.
We only consider PING + ACK and SETTINGS + ACK. This is because
......@@ -443,6 +447,11 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
*
* This function returns a pointer to created new stream object, or
* NULL.
*
* This function adjusts neither the number of closed streams or idle
* streams. The caller should manually call
* nghttp2_session_adjust_closed_stream() or
* nghttp2_session_adjust_idle_stream() respectively.
*/
nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
int32_t stream_id, uint8_t flags,
......@@ -491,29 +500,17 @@ int nghttp2_session_destroy_stream(nghttp2_session *session,
* limitation of maximum number of streams in memory, |stream| is not
* closed and just deleted from memory (see
* nghttp2_session_destroy_stream).
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_keep_closed_stream(nghttp2_session *session,
nghttp2_stream *stream);
void nghttp2_session_keep_closed_stream(nghttp2_session *session,
nghttp2_stream *stream);
/*
* Appends |stream| to linked list |session->idle_stream_head|. We
* apply fixed limit for list size. To fit into that limit, one or
* more oldest streams are removed from list as necessary.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_keep_idle_stream(nghttp2_session *session,
nghttp2_stream *stream);
void nghttp2_session_keep_idle_stream(nghttp2_session *session,
nghttp2_stream *stream);
/*
* Detaches |stream| from idle streams linked list.
......@@ -524,9 +521,7 @@ void nghttp2_session_detach_idle_stream(nghttp2_session *session,
/*
* Deletes closed stream to ensure that number of incoming streams
* including active and closed is in the maximum number of allowed
* stream. If |offset| is nonzero, it is decreased from the maximum
* number of allowed stream when comparing number of active and closed
* stream and the maximum number.
* stream.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
......@@ -534,8 +529,7 @@ void nghttp2_session_detach_idle_stream(nghttp2_session *session,
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_adjust_closed_stream(nghttp2_session *session,
size_t offset);
int nghttp2_session_adjust_closed_stream(nghttp2_session *session);
/*
* Deletes idle stream to ensure that number of idle streams is in
......@@ -807,6 +801,9 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
* |pri_spec|. Caller must ensure that stream->hd.stream_id !=
* pri_spec->stream_id.
*
* This function does not adjust the number of idle streams. The
* caller should call nghttp2_session_adjust_idle_stream() later.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
......
......@@ -7669,6 +7669,7 @@ void test_nghttp2_session_keep_closed_stream(void) {
CU_ASSERT(NULL == session->closed_stream_head->closed_prev);
open_stream(session, 11);
nghttp2_session_adjust_closed_stream(session);
CU_ASSERT(1 == session->num_closed_streams);
CU_ASSERT(5 == session->closed_stream_tail->stream_id);
......@@ -7677,6 +7678,7 @@ void test_nghttp2_session_keep_closed_stream(void) {
CU_ASSERT(NULL == session->closed_stream_head->closed_next);
open_stream(session, 13);
nghttp2_session_adjust_closed_stream(session);
CU_ASSERT(0 == session->num_closed_streams);
CU_ASSERT(NULL == session->closed_stream_tail);
......@@ -7689,6 +7691,7 @@ void test_nghttp2_session_keep_closed_stream(void) {
/* server initiated stream is not counted to max concurrent limit */
open_stream(session, 2);
nghttp2_session_adjust_closed_stream(session);
CU_ASSERT(1 == session->num_closed_streams);
CU_ASSERT(3 == session->closed_stream_head->stream_id);
......@@ -7708,6 +7711,7 @@ void test_nghttp2_session_keep_idle_stream(void) {
nghttp2_settings_entry iv = {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
max_concurrent_streams};
int i;
int32_t stream_id;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = null_send_callback;
......@@ -7716,25 +7720,29 @@ void test_nghttp2_session_keep_idle_stream(void) {
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1);
/* We at least allow 2 idle streams even if max concurrent streams
is very low. */
for (i = 0; i < 2; ++i) {
/* We at least allow NGHTTP2_MIN_IDLE_STREAM idle streams even if
max concurrent streams is very low. */
for (i = 0; i < NGHTTP2_MIN_IDLE_STREAMS; ++i) {
nghttp2_session_open_stream(session, i * 2 + 1, NGHTTP2_STREAM_FLAG_NONE,
&pri_spec_default, NGHTTP2_STREAM_IDLE, NULL);
nghttp2_session_adjust_idle_stream(session);
}
CU_ASSERT(2 == session->num_idle_streams);
CU_ASSERT(NGHTTP2_MIN_IDLE_STREAMS == session->num_idle_streams);
stream_id = (NGHTTP2_MIN_IDLE_STREAMS - 1) * 2 + 1;
CU_ASSERT(1 == session->idle_stream_head->stream_id);
CU_ASSERT(3 == session->idle_stream_tail->stream_id);
CU_ASSERT(stream_id == session->idle_stream_tail->stream_id);
nghttp2_session_open_stream(session, 5, NGHTTP2_FLAG_NONE, &pri_spec_default,
NGHTTP2_STREAM_IDLE, NULL);
stream_id += 2;
CU_ASSERT(2 == session->num_idle_streams);
nghttp2_session_open_stream(session, stream_id, NGHTTP2_FLAG_NONE,
&pri_spec_default, NGHTTP2_STREAM_IDLE, NULL);
nghttp2_session_adjust_idle_stream(session);
CU_ASSERT(NGHTTP2_MIN_IDLE_STREAMS == session->num_idle_streams);
CU_ASSERT(3 == session->idle_stream_head->stream_id);
CU_ASSERT(5 == session->idle_stream_tail->stream_id);
CU_ASSERT(stream_id == session->idle_stream_tail->stream_id);
nghttp2_session_del(session);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment