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_UNIDIRECTIONAL = 2
|
||||||
} spdylay_flag;
|
} 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 {
|
typedef enum {
|
||||||
SPDYLAY_OK = 0,
|
SPDYLAY_OK = 0,
|
||||||
SPDYLAY_PROTOCOL_ERROR = 1,
|
SPDYLAY_PROTOCOL_ERROR = 1,
|
||||||
|
@ -123,6 +144,19 @@ typedef struct {
|
||||||
uint32_t status_code;
|
uint32_t status_code;
|
||||||
} spdylay_rst_stream;
|
} 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 {
|
typedef struct {
|
||||||
spdylay_ctrl_hd hd;
|
spdylay_ctrl_hd hd;
|
||||||
uint32_t unique_id;
|
uint32_t unique_id;
|
||||||
|
@ -158,6 +192,7 @@ typedef union {
|
||||||
spdylay_syn_stream syn_stream;
|
spdylay_syn_stream syn_stream;
|
||||||
spdylay_syn_reply syn_reply;
|
spdylay_syn_reply syn_reply;
|
||||||
spdylay_rst_stream rst_stream;
|
spdylay_rst_stream rst_stream;
|
||||||
|
spdylay_settings settings;
|
||||||
spdylay_ping ping;
|
spdylay_ping ping;
|
||||||
spdylay_goaway goaway;
|
spdylay_goaway goaway;
|
||||||
spdylay_headers headers;
|
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_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,
|
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
||||||
spdylay_data_provider *data_prd)
|
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);
|
frame->status_code = spdylay_get_uint32(payload+4);
|
||||||
return 0;
|
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 *head, size_t headlen,
|
||||||
const uint8_t *payload, size_t payloadlen);
|
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
|
* Returns number of bytes to pack name/value pairs |nv|. This
|
||||||
* function expects |nv| is sorted in ascending order of key. 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);
|
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,
|
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
||||||
spdylay_data_provider *data_prd);
|
spdylay_data_provider *data_prd);
|
||||||
|
|
||||||
|
@ -239,4 +264,12 @@ char** spdylay_frame_nv_copy(const char **nv);
|
||||||
*/
|
*/
|
||||||
void spdylay_frame_nv_sort(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 */
|
#endif /* SPDYLAY_FRAME_H */
|
||||||
|
|
|
@ -100,6 +100,8 @@ int main()
|
||||||
test_spdylay_frame_pack_goaway) ||
|
test_spdylay_frame_pack_goaway) ||
|
||||||
!CU_add_test(pSuite, "frame_pack_headers",
|
!CU_add_test(pSuite, "frame_pack_headers",
|
||||||
test_spdylay_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_add_test(pSuite, "frame_nv_sort", test_spdylay_frame_nv_sort)) {
|
||||||
CU_cleanup_registry();
|
CU_cleanup_registry();
|
||||||
return CU_get_error();
|
return CU_get_error();
|
||||||
|
|
|
@ -125,6 +125,54 @@ void test_spdylay_frame_pack_headers()
|
||||||
spdylay_zlib_deflate_free(&deflater);
|
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()
|
void test_spdylay_frame_nv_sort()
|
||||||
{
|
{
|
||||||
char *nv[7];
|
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_ping();
|
||||||
void test_spdylay_frame_pack_goaway();
|
void test_spdylay_frame_pack_goaway();
|
||||||
void test_spdylay_frame_pack_headers();
|
void test_spdylay_frame_pack_headers();
|
||||||
|
void test_spdylay_frame_pack_settings();
|
||||||
void test_spdylay_frame_nv_sort();
|
void test_spdylay_frame_nv_sort();
|
||||||
|
|
||||||
#endif /* SPDYLAY_FRAME_TEST_H */
|
#endif /* SPDYLAY_FRAME_TEST_H */
|
||||||
|
|
Loading…
Reference in New Issue