Added SETTINGS frame and its pack/unpack functions.
This commit is contained in:
parent
49096387c3
commit
0b75800c23
|
@ -78,6 +78,27 @@ typedef enum {
|
|||
SPDYLAY_FLAG_UNIDIRECTIONAL = 2
|
||||
} spdylay_flag;
|
||||
|
||||
typedef enum {
|
||||
SPDYLAY_FLAG_SETTINGS_NONE = 0,
|
||||
SPDYLAY_FLAG_SETTINGS_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 1
|
||||
} spdylay_settings_flag;
|
||||
|
||||
typedef enum {
|
||||
SPDYLAY_ID_FLAG_SETTINGS_NONE = 0,
|
||||
SPDYLAY_ID_FLAG_SETTINGS_PERSIST_VALUE = 1,
|
||||
SPDYLAY_ID_FLAG_SETTINGS_PERSISTED = 2
|
||||
} spdylay_settings_id_flag;
|
||||
|
||||
typedef enum {
|
||||
SPDYLAY_SETTINGS_UPLOAD_BANDWIDTH = 1,
|
||||
SPDYLAY_SETTINGS_DOWNLOAD_BANDWIDTH = 2,
|
||||
SPDYLAY_SETTINGS_ROUND_TRIP_TIME = 3,
|
||||
SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS = 4,
|
||||
SPDYLAY_SETTINGS_CURRENT_CWND = 5,
|
||||
SPDYLAY_SETTINGS_DOWNLOAD_RETRANS_RATE = 6,
|
||||
SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE = 7
|
||||
} spdylay_settings_id;
|
||||
|
||||
typedef enum {
|
||||
SPDYLAY_OK = 0,
|
||||
SPDYLAY_PROTOCOL_ERROR = 1,
|
||||
|
@ -123,6 +144,19 @@ typedef struct {
|
|||
uint32_t status_code;
|
||||
} spdylay_rst_stream;
|
||||
|
||||
typedef struct {
|
||||
int32_t settings_id;
|
||||
uint8_t flags;
|
||||
uint32_t value;
|
||||
} spdylay_settings_entry;
|
||||
|
||||
typedef struct {
|
||||
spdylay_ctrl_hd hd;
|
||||
/* Number of entries in |iv| */
|
||||
size_t niv;
|
||||
spdylay_settings_entry *iv;
|
||||
} spdylay_settings;
|
||||
|
||||
typedef struct {
|
||||
spdylay_ctrl_hd hd;
|
||||
uint32_t unique_id;
|
||||
|
@ -158,6 +192,7 @@ typedef union {
|
|||
spdylay_syn_stream syn_stream;
|
||||
spdylay_syn_reply syn_reply;
|
||||
spdylay_rst_stream rst_stream;
|
||||
spdylay_settings settings;
|
||||
spdylay_ping ping;
|
||||
spdylay_goaway goaway;
|
||||
spdylay_headers headers;
|
||||
|
|
|
@ -444,6 +444,23 @@ void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame,
|
|||
void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame)
|
||||
{}
|
||||
|
||||
void spdylay_frame_settings_init(spdylay_settings *frame, uint8_t flags,
|
||||
spdylay_settings_entry *iv, size_t niv)
|
||||
{
|
||||
memset(frame, 0, sizeof(spdylay_settings));
|
||||
frame->hd.version = SPDYLAY_PROTO_VERSION;
|
||||
frame->hd.type = SPDYLAY_SETTINGS;
|
||||
frame->hd.flags = flags;
|
||||
frame->hd.length = 4+niv*8;
|
||||
frame->niv = niv;
|
||||
frame->iv = iv;
|
||||
}
|
||||
|
||||
void spdylay_frame_settings_free(spdylay_settings *frame)
|
||||
{
|
||||
free(frame->iv);
|
||||
}
|
||||
|
||||
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
||||
spdylay_data_provider *data_prd)
|
||||
{
|
||||
|
@ -658,3 +675,64 @@ int spdylay_frame_unpack_rst_stream(spdylay_rst_stream *frame,
|
|||
frame->status_code = spdylay_get_uint32(payload+4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, spdylay_settings *frame)
|
||||
{
|
||||
uint8_t *framebuf;
|
||||
ssize_t framelen = SPDYLAY_FRAME_HEAD_LENGTH+frame->hd.length;
|
||||
int i;
|
||||
framebuf = malloc(framelen);
|
||||
if(framebuf == NULL) {
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
memset(framebuf, 0, framelen);
|
||||
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
|
||||
spdylay_put_uint32be(&framebuf[8], frame->niv);
|
||||
for(i = 0; i < frame->niv; ++i) {
|
||||
int off = i*8;
|
||||
spdylay_put_uint32be(&framebuf[12+off], frame->iv[i].settings_id << 8);
|
||||
framebuf[15+off] = frame->iv[i].flags;
|
||||
spdylay_put_uint32be(&framebuf[16+off], frame->iv[i].value);
|
||||
}
|
||||
*buf_ptr = framebuf;
|
||||
return framelen;
|
||||
}
|
||||
|
||||
int spdylay_frame_unpack_settings(spdylay_settings *frame,
|
||||
const uint8_t *head, size_t headlen,
|
||||
const uint8_t *payload, size_t payloadlen)
|
||||
{
|
||||
int i;
|
||||
if(payloadlen < 4) {
|
||||
return SPDYLAY_ERR_INVALID_FRAME;
|
||||
}
|
||||
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
||||
frame->niv = spdylay_get_uint32(payload);
|
||||
if(payloadlen != 4+frame->niv*8) {
|
||||
return SPDYLAY_ERR_INVALID_FRAME;
|
||||
}
|
||||
frame->iv = malloc(frame->niv*sizeof(spdylay_settings_entry));
|
||||
if(frame->iv == NULL) {
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
for(i = 0; i < frame->niv; ++i) {
|
||||
int off = i*8;
|
||||
frame->iv[i].settings_id = (spdylay_get_uint32(&payload[4+off]) >> 8);
|
||||
frame->iv[i].flags = payload[7+off];
|
||||
frame->iv[i].value = spdylay_get_uint32(&payload[8+off]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
spdylay_settings_entry* spdylay_frame_iv_copy(const spdylay_settings_entry *iv,
|
||||
size_t niv)
|
||||
{
|
||||
spdylay_settings_entry *iv_copy;
|
||||
size_t len = niv*sizeof(spdylay_settings_entry);
|
||||
iv_copy = malloc(len);
|
||||
if(iv_copy == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(iv_copy, iv, len);
|
||||
return iv_copy;
|
||||
}
|
||||
|
|
|
@ -155,6 +155,22 @@ int spdylay_frame_unpack_rst_stream(spdylay_rst_stream *frame,
|
|||
const uint8_t *head, size_t headlen,
|
||||
const uint8_t *payload, size_t payloadlen);
|
||||
|
||||
/*
|
||||
* Packs SETTINGS frame |frame| in wire format and store it in
|
||||
* |*buf_ptr|. This function allocates enough memory to store given
|
||||
* frame in |*buf_ptr|. This function returns the size of packed frame
|
||||
* if it succeeds, or negative error code.
|
||||
*/
|
||||
ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, spdylay_settings *frame);
|
||||
|
||||
/*
|
||||
* Unpacks SETTINGS wire format into |frame|. This function returns 0
|
||||
* if it succeeds, or negative error code.
|
||||
*/
|
||||
int spdylay_frame_unpack_settings(spdylay_settings *frame,
|
||||
const uint8_t *head, size_t headlen,
|
||||
const uint8_t *payload, size_t payloadlen);
|
||||
|
||||
/*
|
||||
* Returns number of bytes to pack name/value pairs |nv|. This
|
||||
* function expects |nv| is sorted in ascending order of key. This
|
||||
|
@ -212,6 +228,15 @@ void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame,
|
|||
|
||||
void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame);
|
||||
|
||||
/*
|
||||
* Initializes SETTINGS frame |frame| with given values. |frame| takes
|
||||
* ownership of |iv|, so caller must not free it.
|
||||
*/
|
||||
void spdylay_frame_settings_init(spdylay_settings *frame, uint8_t flags,
|
||||
spdylay_settings_entry *iv, size_t niv);
|
||||
|
||||
void spdylay_frame_settings_free(spdylay_settings *frame);
|
||||
|
||||
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
||||
spdylay_data_provider *data_prd);
|
||||
|
||||
|
@ -239,4 +264,12 @@ char** spdylay_frame_nv_copy(const char **nv);
|
|||
*/
|
||||
void spdylay_frame_nv_sort(char **nv);
|
||||
|
||||
/*
|
||||
* Makes copy of |iv| and return the copy. The |niv| is the number of
|
||||
* entries in |iv|. This function returns the pointer to the copy if
|
||||
* it succeeds, or NULL.
|
||||
*/
|
||||
spdylay_settings_entry* spdylay_frame_iv_copy(const spdylay_settings_entry *iv,
|
||||
size_t niv);
|
||||
|
||||
#endif /* SPDYLAY_FRAME_H */
|
||||
|
|
|
@ -100,6 +100,8 @@ int main()
|
|||
test_spdylay_frame_pack_goaway) ||
|
||||
!CU_add_test(pSuite, "frame_pack_headers",
|
||||
test_spdylay_frame_pack_headers) ||
|
||||
!CU_add_test(pSuite, "frame_pack_settings",
|
||||
test_spdylay_frame_pack_settings) ||
|
||||
!CU_add_test(pSuite, "frame_nv_sort", test_spdylay_frame_nv_sort)) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
|
|
|
@ -125,6 +125,54 @@ void test_spdylay_frame_pack_headers()
|
|||
spdylay_zlib_deflate_free(&deflater);
|
||||
}
|
||||
|
||||
void test_spdylay_frame_pack_settings()
|
||||
{
|
||||
spdylay_frame frame, oframe;
|
||||
uint8_t *buf;
|
||||
ssize_t buflen;
|
||||
int i;
|
||||
spdylay_settings_entry iv[3];
|
||||
iv[0].settings_id = SPDYLAY_SETTINGS_UPLOAD_BANDWIDTH;
|
||||
iv[0].flags = SPDYLAY_ID_FLAG_SETTINGS_PERSIST_VALUE;
|
||||
iv[0].value = 256;
|
||||
iv[1].settings_id = SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||
iv[1].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
||||
iv[1].value = 100;
|
||||
iv[2].settings_id = SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||
iv[2].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
||||
iv[2].value = 65536;
|
||||
|
||||
spdylay_frame_settings_init
|
||||
(&frame.settings,
|
||||
SPDYLAY_FLAG_SETTINGS_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS,
|
||||
spdylay_frame_iv_copy(iv, 3), 3);
|
||||
buflen = spdylay_frame_pack_settings(&buf, &frame.settings);
|
||||
CU_ASSERT(8+4+3*8 == buflen);
|
||||
|
||||
CU_ASSERT(0 == spdylay_frame_unpack_settings
|
||||
(&oframe.settings,
|
||||
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
|
||||
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
|
||||
buflen-SPDYLAY_FRAME_HEAD_LENGTH));
|
||||
|
||||
CU_ASSERT(SPDYLAY_PROTO_VERSION == oframe.settings.hd.version);
|
||||
CU_ASSERT(SPDYLAY_SETTINGS == oframe.settings.hd.type);
|
||||
CU_ASSERT(SPDYLAY_FLAG_SETTINGS_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS ==
|
||||
oframe.settings.hd.flags);
|
||||
CU_ASSERT(buflen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.settings.hd.length);
|
||||
|
||||
CU_ASSERT(3 == oframe.settings.niv);
|
||||
for(i = 0; i < 3; ++i) {
|
||||
CU_ASSERT(iv[i].settings_id == oframe.settings.iv[i].settings_id);
|
||||
CU_ASSERT(iv[i].flags == oframe.settings.iv[i].flags);
|
||||
CU_ASSERT(iv[i].value == oframe.settings.iv[i].value);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
spdylay_frame_settings_free(&frame.settings);
|
||||
spdylay_frame_settings_free(&oframe.settings);
|
||||
}
|
||||
|
||||
void test_spdylay_frame_nv_sort()
|
||||
{
|
||||
char *nv[7];
|
||||
|
|
|
@ -30,6 +30,7 @@ void test_spdylay_frame_count_nv_space();
|
|||
void test_spdylay_frame_pack_ping();
|
||||
void test_spdylay_frame_pack_goaway();
|
||||
void test_spdylay_frame_pack_headers();
|
||||
void test_spdylay_frame_pack_settings();
|
||||
void test_spdylay_frame_nv_sort();
|
||||
|
||||
#endif /* SPDYLAY_FRAME_TEST_H */
|
||||
|
|
Loading…
Reference in New Issue