Having the number of server and client streams be limited separately
using SETTINGS_MAX_CONCURRENT_STREAMS
This commit is contained in:
parent
67eca8d078
commit
02e4440e4a
|
@ -33,18 +33,27 @@
|
||||||
#include "spdylay_net.h"
|
#include "spdylay_net.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns non-zero if the number of opened streams is larger than or
|
* Returns non-zero if the number of outgoing opened streams is larger
|
||||||
* equal to SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS value.
|
* than or equal to
|
||||||
|
* remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS].
|
||||||
*/
|
*/
|
||||||
static int spdylay_session_get_max_concurrent_streams_reached
|
static int spdylay_session_is_outgoing_concurrent_streams_max
|
||||||
(spdylay_session *session)
|
(spdylay_session *session)
|
||||||
{
|
{
|
||||||
uint32_t local_max, remote_max;
|
return session->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS]
|
||||||
local_max = session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS];
|
<= session->num_outgoing_streams;
|
||||||
remote_max =
|
}
|
||||||
session->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS];
|
|
||||||
return spdylay_min(local_max, remote_max)
|
/*
|
||||||
<= spdylay_map_size(&session->streams);
|
* Returns non-zero if the number of incoming opened streams is larger
|
||||||
|
* than or equal to
|
||||||
|
* local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS].
|
||||||
|
*/
|
||||||
|
static int spdylay_session_is_incoming_concurrent_streams_max
|
||||||
|
(spdylay_session *session)
|
||||||
|
{
|
||||||
|
return session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS]
|
||||||
|
<= session->num_incoming_streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -451,6 +460,11 @@ spdylay_stream* spdylay_session_open_stream(spdylay_session *session,
|
||||||
free(stream);
|
free(stream);
|
||||||
stream = NULL;
|
stream = NULL;
|
||||||
}
|
}
|
||||||
|
if(spdylay_session_is_my_stream_id(session, stream_id)) {
|
||||||
|
++session->num_outgoing_streams;
|
||||||
|
} else {
|
||||||
|
++session->num_incoming_streams;
|
||||||
|
}
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,6 +479,11 @@ int spdylay_session_close_stream(spdylay_session *session, int32_t stream_id,
|
||||||
status_code,
|
status_code,
|
||||||
session->user_data);
|
session->user_data);
|
||||||
}
|
}
|
||||||
|
if(spdylay_session_is_my_stream_id(session, stream_id)) {
|
||||||
|
--session->num_outgoing_streams;
|
||||||
|
} else {
|
||||||
|
--session->num_incoming_streams;
|
||||||
|
}
|
||||||
spdylay_map_erase(&session->streams, stream_id);
|
spdylay_map_erase(&session->streams, stream_id);
|
||||||
spdylay_stream_free(stream);
|
spdylay_stream_free(stream);
|
||||||
free(stream);
|
free(stream);
|
||||||
|
@ -1128,7 +1147,7 @@ spdylay_outbound_item* spdylay_session_get_next_ob_item
|
||||||
} else {
|
} else {
|
||||||
/* Return item only when concurrent connection limit is not
|
/* Return item only when concurrent connection limit is not
|
||||||
reached */
|
reached */
|
||||||
if(spdylay_session_get_max_concurrent_streams_reached(session)) {
|
if(spdylay_session_is_outgoing_concurrent_streams_max(session)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
return spdylay_pq_top(&session->ob_ss_pq);
|
return spdylay_pq_top(&session->ob_ss_pq);
|
||||||
|
@ -1141,7 +1160,7 @@ spdylay_outbound_item* spdylay_session_get_next_ob_item
|
||||||
spdylay_outbound_item *item, *syn_stream_item;
|
spdylay_outbound_item *item, *syn_stream_item;
|
||||||
item = spdylay_pq_top(&session->ob_pq);
|
item = spdylay_pq_top(&session->ob_pq);
|
||||||
syn_stream_item = spdylay_pq_top(&session->ob_ss_pq);
|
syn_stream_item = spdylay_pq_top(&session->ob_ss_pq);
|
||||||
if(spdylay_session_get_max_concurrent_streams_reached(session) ||
|
if(spdylay_session_is_outgoing_concurrent_streams_max(session) ||
|
||||||
item->pri < syn_stream_item->pri ||
|
item->pri < syn_stream_item->pri ||
|
||||||
(item->pri == syn_stream_item->pri &&
|
(item->pri == syn_stream_item->pri &&
|
||||||
item->seq < syn_stream_item->seq)) {
|
item->seq < syn_stream_item->seq)) {
|
||||||
|
@ -1162,7 +1181,7 @@ spdylay_outbound_item* spdylay_session_pop_next_ob_item
|
||||||
} else {
|
} else {
|
||||||
/* Pop item only when concurrent connection limit is not
|
/* Pop item only when concurrent connection limit is not
|
||||||
reached */
|
reached */
|
||||||
if(spdylay_session_get_max_concurrent_streams_reached(session)) {
|
if(spdylay_session_is_outgoing_concurrent_streams_max(session)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
spdylay_outbound_item *item;
|
spdylay_outbound_item *item;
|
||||||
|
@ -1181,7 +1200,7 @@ spdylay_outbound_item* spdylay_session_pop_next_ob_item
|
||||||
spdylay_outbound_item *item, *syn_stream_item;
|
spdylay_outbound_item *item, *syn_stream_item;
|
||||||
item = spdylay_pq_top(&session->ob_pq);
|
item = spdylay_pq_top(&session->ob_pq);
|
||||||
syn_stream_item = spdylay_pq_top(&session->ob_ss_pq);
|
syn_stream_item = spdylay_pq_top(&session->ob_ss_pq);
|
||||||
if(spdylay_session_get_max_concurrent_streams_reached(session) ||
|
if(spdylay_session_is_outgoing_concurrent_streams_max(session) ||
|
||||||
item->pri < syn_stream_item->pri ||
|
item->pri < syn_stream_item->pri ||
|
||||||
(item->pri == syn_stream_item->pri &&
|
(item->pri == syn_stream_item->pri &&
|
||||||
item->seq < syn_stream_item->seq)) {
|
item->seq < syn_stream_item->seq)) {
|
||||||
|
@ -1558,8 +1577,8 @@ static int spdylay_session_check_version(spdylay_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validates SYN_STREAM frame |frame|. This function returns 0 if it
|
* Validates received SYN_STREAM frame |frame|. This function returns
|
||||||
* succeeds, or non-zero spdylay_status_code.
|
* 0 if it succeeds, or non-zero spdylay_status_code.
|
||||||
*/
|
*/
|
||||||
static int spdylay_session_validate_syn_stream(spdylay_session *session,
|
static int spdylay_session_validate_syn_stream(spdylay_session *session,
|
||||||
spdylay_syn_stream *frame)
|
spdylay_syn_stream *frame)
|
||||||
|
@ -1586,7 +1605,7 @@ static int spdylay_session_validate_syn_stream(spdylay_session *session,
|
||||||
return SPDYLAY_PROTOCOL_ERROR;
|
return SPDYLAY_PROTOCOL_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(spdylay_session_get_max_concurrent_streams_reached(session)) {
|
if(spdylay_session_is_incoming_concurrent_streams_max(session)) {
|
||||||
/* spdy/2 spec does not clearly say what to do when max concurrent
|
/* spdy/2 spec does not clearly say what to do when max concurrent
|
||||||
streams number is reached. The mod_spdy sends
|
streams number is reached. The mod_spdy sends
|
||||||
SPDYLAY_REFUSED_STREAM and we think it is reasonable. So we
|
SPDYLAY_REFUSED_STREAM and we think it is reasonable. So we
|
||||||
|
@ -2432,7 +2451,7 @@ int spdylay_session_want_write(spdylay_session *session)
|
||||||
*/
|
*/
|
||||||
return (session->aob.item != NULL || !spdylay_pq_empty(&session->ob_pq) ||
|
return (session->aob.item != NULL || !spdylay_pq_empty(&session->ob_pq) ||
|
||||||
(!spdylay_pq_empty(&session->ob_ss_pq) &&
|
(!spdylay_pq_empty(&session->ob_ss_pq) &&
|
||||||
!spdylay_session_get_max_concurrent_streams_reached(session))) &&
|
!spdylay_session_is_outgoing_concurrent_streams_max(session))) &&
|
||||||
(!session->goaway_flags || spdylay_map_size(&session->streams) > 0);
|
(!session->goaway_flags || spdylay_map_size(&session->streams) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,13 @@ struct spdylay_session {
|
||||||
int64_t next_seq;
|
int64_t next_seq;
|
||||||
|
|
||||||
spdylay_map /* <spdylay_stream*> */ streams;
|
spdylay_map /* <spdylay_stream*> */ streams;
|
||||||
|
/* The number of outgoing streams. This will be capped by
|
||||||
|
remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS]. */
|
||||||
|
size_t num_outgoing_streams;
|
||||||
|
/* The number of incoming streams. This will be capped by
|
||||||
|
local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS]. */
|
||||||
|
size_t num_incoming_streams;
|
||||||
|
|
||||||
/* Queue for outbound frames other than SYN_STREAM */
|
/* Queue for outbound frames other than SYN_STREAM */
|
||||||
spdylay_pq /* <spdylay_outbound_item*> */ ob_pq;
|
spdylay_pq /* <spdylay_outbound_item*> */ ob_pq;
|
||||||
/* Queue for outbound SYN_STREAM frame */
|
/* Queue for outbound SYN_STREAM frame */
|
||||||
|
|
|
@ -457,6 +457,20 @@ void test_spdylay_session_on_syn_stream_received(void)
|
||||||
|
|
||||||
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||||
|
|
||||||
|
|
||||||
|
/* More than max concurrent streams leads REFUSED_STREAM */
|
||||||
|
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 1;
|
||||||
|
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
|
||||||
|
SPDYLAY_CTRL_FLAG_NONE,
|
||||||
|
5, 0, 3, dup_nv(nv));
|
||||||
|
user_data.invalid_ctrl_recv_cb_called = 0;
|
||||||
|
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
|
||||||
|
CU_ASSERT(1 == user_data.invalid_ctrl_recv_cb_called);
|
||||||
|
|
||||||
|
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||||
|
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] =
|
||||||
|
SPDYLAY_INITIAL_MAX_CONCURRENT_STREAMS;
|
||||||
|
|
||||||
/* Stream ID less than previouly received SYN_STREAM leads session
|
/* Stream ID less than previouly received SYN_STREAM leads session
|
||||||
error */
|
error */
|
||||||
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
|
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
|
||||||
|
@ -468,6 +482,7 @@ void test_spdylay_session_on_syn_stream_received(void)
|
||||||
CU_ASSERT(session->goaway_flags & SPDYLAY_GOAWAY_FAIL_ON_SEND);
|
CU_ASSERT(session->goaway_flags & SPDYLAY_GOAWAY_FAIL_ON_SEND);
|
||||||
|
|
||||||
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||||
|
|
||||||
spdylay_session_del(session);
|
spdylay_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1236,7 +1251,7 @@ void test_spdylay_session_get_next_ob_item(void)
|
||||||
callbacks.send_callback = null_send_callback;
|
callbacks.send_callback = null_send_callback;
|
||||||
|
|
||||||
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
|
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
|
||||||
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 2;
|
session->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 2;
|
||||||
|
|
||||||
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
|
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
|
||||||
spdylay_submit_ping(session);
|
spdylay_submit_ping(session);
|
||||||
|
@ -1250,17 +1265,20 @@ void test_spdylay_session_get_next_ob_item(void)
|
||||||
CU_ASSERT(0 == spdylay_session_send(session));
|
CU_ASSERT(0 == spdylay_session_send(session));
|
||||||
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
|
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
|
||||||
|
|
||||||
|
/* Incoming stream does not affect the number of outgoing max
|
||||||
|
concurrent streams. */
|
||||||
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
|
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
|
||||||
3, SPDYLAY_STREAM_OPENING, NULL);
|
3, SPDYLAY_STREAM_OPENING, NULL);
|
||||||
|
|
||||||
|
spdylay_submit_request(session, 0, nv, NULL, NULL);
|
||||||
|
CU_ASSERT(SPDYLAY_SYN_STREAM ==
|
||||||
|
OB_CTRL_TYPE(spdylay_session_get_next_ob_item(session)));
|
||||||
|
CU_ASSERT(0 == spdylay_session_send(session));
|
||||||
|
|
||||||
spdylay_submit_request(session, 0, nv, NULL, NULL);
|
spdylay_submit_request(session, 0, nv, NULL, NULL);
|
||||||
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
|
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
|
||||||
|
|
||||||
spdylay_submit_response(session, 1, nv, NULL);
|
session->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 3;
|
||||||
CU_ASSERT(SPDYLAY_SYN_REPLY ==
|
|
||||||
OB_CTRL_TYPE(spdylay_session_get_next_ob_item(session)));
|
|
||||||
|
|
||||||
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 3;
|
|
||||||
|
|
||||||
CU_ASSERT(SPDYLAY_SYN_STREAM ==
|
CU_ASSERT(SPDYLAY_SYN_STREAM ==
|
||||||
OB_CTRL_TYPE(spdylay_session_get_next_ob_item(session)));
|
OB_CTRL_TYPE(spdylay_session_get_next_ob_item(session)));
|
||||||
|
@ -1278,11 +1296,11 @@ void test_spdylay_session_pop_next_ob_item(void)
|
||||||
callbacks.send_callback = null_send_callback;
|
callbacks.send_callback = null_send_callback;
|
||||||
|
|
||||||
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
|
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
|
||||||
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 1;
|
session->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 1;
|
||||||
|
|
||||||
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
|
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
|
||||||
spdylay_submit_ping(session);
|
spdylay_submit_ping(session);
|
||||||
spdylay_submit_request(session, 0, nv, NULL, NULL);
|
spdylay_submit_request(session, 1, nv, NULL, NULL);
|
||||||
|
|
||||||
item = spdylay_session_pop_next_ob_item(session);
|
item = spdylay_session_pop_next_ob_item(session);
|
||||||
CU_ASSERT(SPDYLAY_PING == OB_CTRL_TYPE(item));
|
CU_ASSERT(SPDYLAY_PING == OB_CTRL_TYPE(item));
|
||||||
|
@ -1296,9 +1314,15 @@ void test_spdylay_session_pop_next_ob_item(void)
|
||||||
|
|
||||||
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
|
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
|
||||||
|
|
||||||
|
/* Incoming stream does not affect the number of outgoing max
|
||||||
|
concurrent streams. */
|
||||||
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
|
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
|
||||||
3, SPDYLAY_STREAM_OPENING, NULL);
|
3, SPDYLAY_STREAM_OPENING, NULL);
|
||||||
|
|
||||||
|
/* In-flight outgoing stream */
|
||||||
|
spdylay_session_open_stream(session, 4, SPDYLAY_CTRL_FLAG_NONE,
|
||||||
|
3, SPDYLAY_STREAM_OPENING, NULL);
|
||||||
|
|
||||||
spdylay_submit_request(session, 0, nv, NULL, NULL);
|
spdylay_submit_request(session, 0, nv, NULL, NULL);
|
||||||
spdylay_submit_response(session, 1, nv, NULL);
|
spdylay_submit_response(session, 1, nv, NULL);
|
||||||
|
|
||||||
|
@ -1309,8 +1333,7 @@ void test_spdylay_session_pop_next_ob_item(void)
|
||||||
|
|
||||||
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
|
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
|
||||||
|
|
||||||
spdylay_submit_response(session, 1, nv, NULL);
|
session->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 2;
|
||||||
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 2;
|
|
||||||
|
|
||||||
item = spdylay_session_pop_next_ob_item(session);
|
item = spdylay_session_pop_next_ob_item(session);
|
||||||
CU_ASSERT(SPDYLAY_SYN_STREAM == OB_CTRL_TYPE(item));
|
CU_ASSERT(SPDYLAY_SYN_STREAM == OB_CTRL_TYPE(item));
|
||||||
|
|
Loading…
Reference in New Issue