Bring back deferred DATA to the outbound queue when SETTINGS with
INITIAL_WINDOW_SIZE is received and the window size becomes positive.
This commit is contained in:
parent
5789f35f5e
commit
9b619e5dd7
|
@ -683,7 +683,8 @@ void spdylay_frame_window_update_free(spdylay_window_update *frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initializes SETTINGS frame |frame| with given values. |frame| takes
|
* Initializes SETTINGS frame |frame| with given values. |frame| takes
|
||||||
* ownership of |iv|, so caller must not free it.
|
* ownership of |iv|, so caller must not free it. The |flags| are
|
||||||
|
* bitwise-OR of one or more of spdylay_settings_flag.
|
||||||
*/
|
*/
|
||||||
void spdylay_frame_settings_init(spdylay_settings *frame,
|
void spdylay_frame_settings_init(spdylay_settings *frame,
|
||||||
uint16_t version, uint8_t flags,
|
uint16_t version, uint8_t flags,
|
||||||
|
|
|
@ -197,20 +197,24 @@ size_t spdylay_map_size(spdylay_map *map)
|
||||||
return map->size;
|
return map->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void for_each(spdylay_map_entry *entry,
|
static int for_each(spdylay_map_entry *entry,
|
||||||
void (*func)(key_type key, void *val, void *ptr),
|
int (*func)(key_type key, void *val, void *ptr),
|
||||||
void *ptr)
|
void *ptr)
|
||||||
{
|
{
|
||||||
if(entry != NULL) {
|
if(entry) {
|
||||||
for_each(entry->left, func, ptr);
|
int rv;
|
||||||
func(entry->key, entry->val, ptr);
|
if((rv = for_each(entry->left, func, ptr)) != 0 ||
|
||||||
for_each(entry->right, func, ptr);
|
(rv = func(entry->key, entry->val, ptr)) != 0 ||
|
||||||
|
(rv = for_each(entry->right, func, ptr)) != 0) {
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spdylay_map_each(spdylay_map *map,
|
int spdylay_map_each(spdylay_map *map,
|
||||||
void (*func)(key_type key, void *val, void *ptr),
|
int (*func)(key_type key, void *val, void *ptr),
|
||||||
void *ptr)
|
void *ptr)
|
||||||
{
|
{
|
||||||
for_each(map->root, func, ptr);
|
return for_each(map->root, func, ptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,9 +102,16 @@ size_t spdylay_map_size(spdylay_map *map);
|
||||||
* Applies the function |func| to each key/item pair in the map |map|
|
* Applies the function |func| to each key/item pair in the map |map|
|
||||||
* with the optional user supplied pointer |ptr|. This function is
|
* with the optional user supplied pointer |ptr|. This function is
|
||||||
* useful to free item in the map.
|
* useful to free item in the map.
|
||||||
|
*
|
||||||
|
* If the |func| returns 0, this function calls the |func| with the
|
||||||
|
* next key and value pair. If the |func| returns nonzero, it will not
|
||||||
|
* call the |func| for further key and value pair and return the
|
||||||
|
* return value of the |func| immediately. Thus, this function
|
||||||
|
* returns 0 if all the invocations of the |func| return 0, or nonzero
|
||||||
|
* value which the last invocation of |func| returns.
|
||||||
*/
|
*/
|
||||||
void spdylay_map_each(spdylay_map *map,
|
int spdylay_map_each(spdylay_map *map,
|
||||||
void (*func)(key_type key, void *val, void *ptr),
|
int (*func)(key_type key, void *val, void *ptr),
|
||||||
void *ptr);
|
void *ptr);
|
||||||
|
|
||||||
#endif /* SPDYLAY_MAP_H */
|
#endif /* SPDYLAY_MAP_H */
|
||||||
|
|
|
@ -274,10 +274,11 @@ int spdylay_session_server_new(spdylay_session **session_ptr,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spdylay_free_streams(key_type key, void *val, void *ptr)
|
static int spdylay_free_streams(key_type key, void *val, void *ptr)
|
||||||
{
|
{
|
||||||
spdylay_stream_free((spdylay_stream*)val);
|
spdylay_stream_free((spdylay_stream*)val);
|
||||||
free(val);
|
free(val);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spdylay_session_ob_pq_free(spdylay_pq *pq)
|
static void spdylay_session_ob_pq_free(spdylay_pq *pq)
|
||||||
|
@ -1783,28 +1784,56 @@ int spdylay_session_on_rst_stream_received(spdylay_session *session,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spdylay_update_initial_window_size_func(key_type key, void *value,
|
static int spdylay_update_initial_window_size_func(key_type key, void *value,
|
||||||
void *ptr)
|
void *ptr)
|
||||||
{
|
{
|
||||||
int32_t *vals;
|
spdylay_update_window_size_arg *arg;
|
||||||
vals = (int32_t*)ptr;
|
spdylay_stream *stream;
|
||||||
spdylay_stream_update_initial_window_size((spdylay_stream*)value,
|
arg = (spdylay_update_window_size_arg*)ptr;
|
||||||
vals[0], vals[1]);
|
stream = (spdylay_stream*)value;
|
||||||
|
spdylay_stream_update_initial_window_size(stream,
|
||||||
|
arg->new_window_size,
|
||||||
|
arg->old_window_size);
|
||||||
|
/* If window size gets positive, push deferred DATA frame to
|
||||||
|
outbound queue. */
|
||||||
|
if(stream->window_size > 0 &&
|
||||||
|
stream->deferred_data &&
|
||||||
|
(stream->deferred_flags & SPDYLAY_DEFERRED_FLOW_CONTROL)) {
|
||||||
|
int rv;
|
||||||
|
rv = spdylay_pq_push(&arg->session->ob_pq, stream->deferred_data);
|
||||||
|
if(rv == 0) {
|
||||||
|
spdylay_stream_detach_deferred_data(stream);
|
||||||
|
} else {
|
||||||
|
/* FATAL */
|
||||||
|
assert(rv < SPDYLAY_ERR_FATAL);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates the initial window size of all active streams.
|
* Updates the initial window size of all active streams.
|
||||||
|
* If error occurs, all streams may not be updated.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
*/
|
*/
|
||||||
static void spdylay_session_update_initial_window_size
|
static int spdylay_session_update_initial_window_size
|
||||||
(spdylay_session *session,
|
(spdylay_session *session,
|
||||||
int32_t new_initial_window_size)
|
int32_t new_initial_window_size)
|
||||||
{
|
{
|
||||||
int32_t vals[2];
|
spdylay_update_window_size_arg arg;
|
||||||
vals[0] = new_initial_window_size;
|
arg.session = session;
|
||||||
vals[1] = session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE];
|
arg.new_window_size = new_initial_window_size;
|
||||||
spdylay_map_each(&session->streams,
|
arg.old_window_size =
|
||||||
|
session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE];
|
||||||
|
return spdylay_map_each(&session->streams,
|
||||||
spdylay_update_initial_window_size_func,
|
spdylay_update_initial_window_size_func,
|
||||||
vals);
|
&arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spdylay_session_update_local_settings(spdylay_session *session,
|
void spdylay_session_update_local_settings(spdylay_session *session,
|
||||||
|
@ -1821,6 +1850,7 @@ void spdylay_session_update_local_settings(spdylay_session *session,
|
||||||
int spdylay_session_on_settings_received(spdylay_session *session,
|
int spdylay_session_on_settings_received(spdylay_session *session,
|
||||||
spdylay_frame *frame)
|
spdylay_frame *frame)
|
||||||
{
|
{
|
||||||
|
int rv;
|
||||||
size_t i;
|
size_t i;
|
||||||
int check[SPDYLAY_SETTINGS_MAX+1];
|
int check[SPDYLAY_SETTINGS_MAX+1];
|
||||||
if(!spdylay_session_check_version(session, frame->settings.hd.version)) {
|
if(!spdylay_session_check_version(session, frame->settings.hd.version)) {
|
||||||
|
@ -1842,12 +1872,14 @@ int spdylay_session_on_settings_received(spdylay_session *session,
|
||||||
/* Update the initial window size of the all active streams */
|
/* Update the initial window size of the all active streams */
|
||||||
/* Check that initial_window_size < (1u << 31) */
|
/* Check that initial_window_size < (1u << 31) */
|
||||||
if(entry->value < (1u << 31)) {
|
if(entry->value < (1u << 31)) {
|
||||||
spdylay_session_update_initial_window_size(session, entry->value);
|
rv = spdylay_session_update_initial_window_size(session, entry->value);
|
||||||
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if(entry->settings_id ==
|
} else if(entry->settings_id ==
|
||||||
SPDYLAY_SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE) {
|
SPDYLAY_SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE) {
|
||||||
if(!session->server) {
|
if(!session->server) {
|
||||||
int rv;
|
|
||||||
/* Limit certificate vector length in the reasonable size. */
|
/* Limit certificate vector length in the reasonable size. */
|
||||||
entry->value = spdylay_min(entry->value,
|
entry->value = spdylay_min(entry->value,
|
||||||
SPDYLAY_MAX_CLIENT_CERT_VECTOR_LENGTH);
|
SPDYLAY_MAX_CLIENT_CERT_VECTOR_LENGTH);
|
||||||
|
|
|
@ -197,6 +197,13 @@ struct spdylay_session {
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Struct used when updating initial window size of each active
|
||||||
|
stream. */
|
||||||
|
typedef struct {
|
||||||
|
spdylay_session *session;
|
||||||
|
int32_t new_window_size, old_window_size;
|
||||||
|
} spdylay_update_window_size_arg;
|
||||||
|
|
||||||
/* TODO stream timeout etc */
|
/* TODO stream timeout etc */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1736,6 +1736,8 @@ void test_spdylay_session_flow_control(void)
|
||||||
spdylay_frame frame;
|
spdylay_frame frame;
|
||||||
spdylay_stream *stream;
|
spdylay_stream *stream;
|
||||||
int32_t new_initial_window_size;
|
int32_t new_initial_window_size;
|
||||||
|
spdylay_settings_entry iv[1];
|
||||||
|
spdylay_frame settings_frame;
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
|
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
|
||||||
callbacks.send_callback = null_send_callback;
|
callbacks.send_callback = null_send_callback;
|
||||||
|
@ -1769,6 +1771,8 @@ void test_spdylay_session_flow_control(void)
|
||||||
stream->window_size = new_initial_window_size-
|
stream->window_size = new_initial_window_size-
|
||||||
(session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE]
|
(session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE]
|
||||||
-stream->window_size);
|
-stream->window_size);
|
||||||
|
session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE] =
|
||||||
|
new_initial_window_size;
|
||||||
CU_ASSERT(-48*1024 == stream->window_size);
|
CU_ASSERT(-48*1024 == stream->window_size);
|
||||||
|
|
||||||
/* Back 48KiB */
|
/* Back 48KiB */
|
||||||
|
@ -1787,9 +1791,15 @@ void test_spdylay_session_flow_control(void)
|
||||||
CU_ASSERT(0 == spdylay_session_send(session));
|
CU_ASSERT(0 == spdylay_session_send(session));
|
||||||
CU_ASSERT(16*1024 == ud.data_source_length);
|
CU_ASSERT(16*1024 == ud.data_source_length);
|
||||||
|
|
||||||
/* Back 16KiB */
|
/* Increase initial window size to 32KiB */
|
||||||
frame.window_update.delta_window_size = 16*1024;
|
iv[0].settings_id = SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||||
spdylay_session_on_window_update_received(session, &frame);
|
iv[0].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
||||||
|
iv[0].value = 32*1024;
|
||||||
|
|
||||||
|
spdylay_frame_settings_init(&settings_frame.settings, SPDYLAY_PROTO_SPDY3,
|
||||||
|
SPDYLAY_FLAG_SETTINGS_NONE, dup_iv(iv, 1), 1);
|
||||||
|
spdylay_session_on_settings_received(session, &settings_frame);
|
||||||
|
spdylay_frame_settings_free(&settings_frame.settings);
|
||||||
|
|
||||||
/* Sends another 16KiB data */
|
/* Sends another 16KiB data */
|
||||||
CU_ASSERT(0 == spdylay_session_send(session));
|
CU_ASSERT(0 == spdylay_session_send(session));
|
||||||
|
|
Loading…
Reference in New Issue