Added spdylay_submit_settings

This commit is contained in:
Tatsuhiro Tsujikawa 2012-03-10 18:41:01 +09:00
parent 82e20192d8
commit 02924b6dd0
9 changed files with 176 additions and 2 deletions

View File

@ -662,7 +662,7 @@ void* spdylay_session_get_stream_user_data(spdylay_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* SPDYLAY_ERR_INVALID_FRAME
* SPDYLAY_ERR_INVALID_ARGUMENT
* |pri| is invalid.
* SPDYLAY_ERR_NOMEM
* Out of memory.
@ -728,7 +728,7 @@ int spdylay_submit_response(spdylay_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* SPDYLAY_ERR_INVALID_FRAME
* SPDYLAY_ERR_INVALID_ARGUMENT
* |pri| is invalid.
* SPDYLAY_ERR_NOMEM
* Out of memory.
@ -830,6 +830,23 @@ int spdylay_submit_ping(spdylay_session *session);
*/
int spdylay_submit_goaway(spdylay_session *session, uint32_t status_code);
/*
* Stores local settings and submits SETTINGS frame. The |iv| is the
* pointer to the array of spdylay_settings_entry. The |niv| indicates
* the number of spdylay_settings_entry. The |flags| is bitwise-OR of
* one or more values from spdylay_settings_flag.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* SPDYLAY_ERR_INVALID_ARGUMENT
* The |iv| contains duplicate settings ID or invalid value.
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_submit_settings(spdylay_session *session, uint8_t flags,
const spdylay_settings_entry *iv, size_t niv);
/*
* A helper function for dealing with NPN in client side.
* |in| contains server's protocol in preferable order.

View File

@ -1000,3 +1000,14 @@ spdylay_settings_entry* spdylay_frame_iv_copy(const spdylay_settings_entry *iv,
memcpy(iv_copy, iv, len);
return iv_copy;
}
static int spdylay_settings_entry_compar(const void *lhs, const void *rhs)
{
return ((spdylay_settings_entry *)lhs)->settings_id
-((spdylay_settings_entry *)rhs)->settings_id;
}
void spdylay_frame_iv_sort(spdylay_settings_entry *iv, size_t niv)
{
qsort(iv, niv, sizeof(spdylay_settings_entry), spdylay_settings_entry_compar);
}

View File

@ -618,4 +618,11 @@ void spdylay_frame_nv_2to3(char **nv);
spdylay_settings_entry* spdylay_frame_iv_copy(const spdylay_settings_entry *iv,
size_t niv);
/*
* Sorts the |iv| with the ascending order of the settings_id member.
* The number of the element in the array pointed by the |iv| is given
* by the |niv|.
*/
void spdylay_frame_iv_sort(spdylay_settings_entry *iv, size_t niv);
#endif /* SPDYLAY_FRAME_H */

View File

@ -328,6 +328,7 @@ int spdylay_session_add_frame(spdylay_session *session,
}
case SPDYLAY_SETTINGS:
/* Should SPDYLAY_SETTINGS have higher priority? */
item->pri = -1;
break;
case SPDYLAY_NOOP:
/* We don't have any public API to add NOOP, so here is
@ -1542,6 +1543,17 @@ static void spdylay_session_update_initial_window_size
vals);
}
void spdylay_session_update_local_settings(spdylay_session *session,
spdylay_settings_entry *iv,
size_t niv)
{
int i;
for(i = 0; i < niv; ++i) {
assert(iv[i].settings_id > 0 && iv[i].settings_id <= SPDYLAY_SETTINGS_MAX);
session->local_settings[iv[i].settings_id] = iv[i].value;
}
}
int spdylay_session_on_settings_received(spdylay_session *session,
spdylay_frame *frame)
{

View File

@ -483,4 +483,14 @@ spdylay_outbound_item* spdylay_session_get_next_ob_item
*/
uint8_t spdylay_session_get_pri_lowest(spdylay_session *session);
/*
* Updates local settings with the |iv|. The number of elements in the
* array pointed by the |iv| is given by the |niv|. This function
* assumes that the all settings_id member in |iv| are in range 1 to
* SPDYLAY_SETTINGS_MAX, inclusive.
*/
void spdylay_session_update_local_settings(spdylay_session *session,
spdylay_settings_entry *iv,
size_t niv);
#endif /* SPDYLAY_SESSION_H */

View File

@ -24,6 +24,8 @@
*/
#include "spdylay_submit.h"
#include <string.h>
#include "spdylay_session.h"
#include "spdylay_frame.h"
@ -183,6 +185,44 @@ int spdylay_submit_goaway(spdylay_session *session, uint32_t status_code)
status_code);
}
int spdylay_submit_settings(spdylay_session *session, uint8_t flags,
const spdylay_settings_entry *iv, size_t niv)
{
spdylay_frame *frame;
spdylay_settings_entry *iv_copy;
int check[SPDYLAY_SETTINGS_MAX+1];
int i, r;
memset(check, 0, sizeof(check));
for(i = 0; i < niv; ++i) {
if(iv[i].settings_id > SPDYLAY_SETTINGS_MAX || iv[i].settings_id == 0 ||
check[iv[i].settings_id] == 1) {
return SPDYLAY_ERR_INVALID_ARGUMENT;
} else {
check[iv[i].settings_id] = 1;
}
}
frame = malloc(sizeof(spdylay_frame));
if(frame == NULL) {
return SPDYLAY_ERR_NOMEM;
}
iv_copy = spdylay_frame_iv_copy(iv, niv);
if(iv_copy == NULL) {
free(frame);
return SPDYLAY_ERR_NOMEM;
}
spdylay_frame_iv_sort(iv_copy, niv);
spdylay_frame_settings_init(&frame->settings, session->version,
flags, iv_copy, niv);
r = spdylay_session_add_frame(session, SPDYLAY_SETTINGS, frame, NULL);
if(r == 0) {
spdylay_session_update_local_settings(session, iv_copy, niv);
} else {
spdylay_frame_settings_free(&frame->settings);
free(frame);
}
return r;
}
int spdylay_submit_request(spdylay_session *session, uint8_t pri,
const char **nv,
const spdylay_data_provider *data_prd,

View File

@ -140,6 +140,8 @@ int main(int argc, char* argv[])
test_spdylay_session_on_ctrl_not_send) ||
!CU_add_test(pSuite, "session_on_settings_received",
test_spdylay_session_on_settings_received) ||
!CU_add_test(pSuite, "session_submit_settings",
test_spdylay_submit_settings) ||
!CU_add_test(pSuite, "frame_unpack_nv_spdy2",
test_spdylay_frame_unpack_nv_spdy2) ||
!CU_add_test(pSuite, "frame_unpack_nv_spdy3",

View File

@ -1898,3 +1898,77 @@ void test_spdylay_session_on_settings_received()
spdylay_session_del(session);
}
void test_spdylay_submit_settings()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data ud;
spdylay_outbound_item *item;
spdylay_frame *frame;
spdylay_settings_entry iv[3];
iv[0].settings_id = SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[0].value = 50;
iv[0].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
iv[1].settings_id = SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE;
iv[1].value = 16*1024;
iv[1].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
/* This is duplicate entry */
iv[2].settings_id = SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[2].value = 150;
iv[2].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks, &ud);
CU_ASSERT(SPDYLAY_ERR_INVALID_ARGUMENT ==
spdylay_submit_settings(session, SPDYLAY_FLAG_SETTINGS_NONE,
iv, 3));
/* Make sure that local settings are not changed */
CU_ASSERT(SPDYLAY_CONCURRENT_STREAMS_MAX ==
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS]);
CU_ASSERT(SPDYLAY_INITIAL_WINDOW_SIZE ==
session->local_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE]);
CU_ASSERT(0 == spdylay_submit_settings(session,
SPDYLAY_FLAG_SETTINGS_CLEAR_SETTINGS,
iv, 2));
/* Make sure that local settings are changed */
CU_ASSERT(50 ==
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS]);
CU_ASSERT(16*1024 ==
session->local_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE]);
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(SPDYLAY_SETTINGS == item->frame_type);
frame = item->frame;
CU_ASSERT(2 == frame->settings.niv);
CU_ASSERT(SPDYLAY_FLAG_SETTINGS_CLEAR_SETTINGS == frame->settings.hd.flags);
CU_ASSERT(50 == frame->settings.iv[0].value);
CU_ASSERT(SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS ==
frame->settings.iv[0].settings_id);
CU_ASSERT(SPDYLAY_FLAG_SETTINGS_NONE ==
frame->settings.iv[0].flags);
CU_ASSERT(16*1024 == frame->settings.iv[1].value);
CU_ASSERT(SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE ==
frame->settings.iv[1].settings_id);
CU_ASSERT(SPDYLAY_FLAG_SETTINGS_NONE ==
frame->settings.iv[1].flags);
ud.ctrl_send_cb_called = 0;
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == ud.ctrl_send_cb_called);
spdylay_session_del(session);
}

View File

@ -62,5 +62,6 @@ void test_spdylay_session_defer_data();
void test_spdylay_session_flow_control();
void test_spdylay_session_on_ctrl_not_send();
void test_spdylay_session_on_settings_received();
void test_spdylay_submit_settings();
#endif // SPDYLAY_SESSION_TEST_H