diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index 87815623..6bf60a95 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -73,6 +73,8 @@ typedef enum { SPDYLAY_PING = 6, SPDYLAY_GOAWAY = 7, SPDYLAY_HEADERS = 8, + /* Since SPDY/3 */ + SPDYLAY_WINDOW_UPDATE = 9, SPDYLAY_DATA = 100, } spdylay_frame_type; @@ -143,7 +145,7 @@ typedef struct { SPDYLAY_SPDY3_LOWEST_PRI (loweset), depending on the protocol version. */ uint8_t pri; - /* Use in spdy/3 only */ + /* Since SPDY/3 */ uint8_t slot; char **nv; } spdylay_syn_stream; @@ -187,10 +189,17 @@ typedef struct { typedef struct { spdylay_ctrl_hd hd; int32_t last_good_stream_id; - /* spdy/3 only */ + /* Since SPDY/3 */ uint32_t status_code; } spdylay_goaway; +/* WINDOW_UPDATE is introduced since SPDY/3 */ +typedef struct { + spdylay_ctrl_hd hd; + int32_t stream_id; + int32_t delta_window_size; +} spdylay_window_update; + typedef union { int fd; void *ptr; @@ -237,6 +246,8 @@ typedef union { spdylay_ping ping; spdylay_goaway goaway; spdylay_headers headers; + /* Since SPDY/3 */ + spdylay_window_update window_update; spdylay_data data; } spdylay_frame; diff --git a/lib/spdylay_frame.c b/lib/spdylay_frame.c index e651d9ba..d29b386f 100644 --- a/lib/spdylay_frame.c +++ b/lib/spdylay_frame.c @@ -495,6 +495,23 @@ void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame, void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame) {} +void spdylay_frame_window_update_init(spdylay_window_update *frame, + uint16_t version, + int32_t stream_id, + int32_t delta_window_size) +{ + memset(frame, 0, sizeof(spdylay_window_update)); + frame->hd.version = version; + frame->hd.type = SPDYLAY_WINDOW_UPDATE; + frame->hd.flags = 0; + frame->hd.length = 8; + frame->stream_id = stream_id; + frame->delta_window_size = delta_window_size; +} + +void spdylay_frame_window_update_free(spdylay_window_update *frame) +{} + void spdylay_frame_settings_init(spdylay_settings *frame, uint16_t version, uint8_t flags, spdylay_settings_entry *iv, size_t niv) @@ -823,6 +840,37 @@ int spdylay_frame_unpack_rst_stream(spdylay_rst_stream *frame, return 0; } +ssize_t spdylay_frame_pack_window_update(uint8_t **buf_ptr, size_t *buflen_ptr, + spdylay_window_update *frame) +{ + ssize_t framelen = 16; + int r; + r = spdylay_reserve_buffer(buf_ptr, buflen_ptr, framelen); + if(r != 0) { + return r; + } + memset(*buf_ptr, 0, framelen); + spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd); + spdylay_put_uint32be(&(*buf_ptr)[8], frame->stream_id); + spdylay_put_uint32be(&(*buf_ptr)[12], frame->delta_window_size); + return framelen; +} + +int spdylay_frame_unpack_window_update(spdylay_window_update *frame, + const uint8_t *head, size_t headlen, + const uint8_t *payload, + size_t payloadlen) +{ + if(payloadlen != 8) { + return SPDYLAY_ERR_INVALID_FRAME; + } + spdylay_frame_unpack_ctrl_hd(&frame->hd, head); + frame->stream_id = spdylay_get_uint32(payload) & SPDYLAY_STREAM_ID_MASK; + frame->delta_window_size = spdylay_get_uint32(&payload[4]) & + SPDYLAY_DELTA_WINDOW_SIZE_MASK; + return 0; +} + ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr, spdylay_settings *frame) { diff --git a/lib/spdylay_frame.h b/lib/spdylay_frame.h index 07418953..71856a1a 100644 --- a/lib/spdylay_frame.h +++ b/lib/spdylay_frame.h @@ -36,6 +36,7 @@ #define SPDYLAY_STREAM_ID_MASK 0x7fffffff #define SPDYLAY_LENGTH_MASK 0xffffff #define SPDYLAY_VERSION_MASK 0x7fff +#define SPDYLAY_DELTA_WINDOW_SIZE_MASK 0x7fffffff /* The length of DATA frame payload. */ #define SPDYLAY_DATA_PAYLOAD_LENGTH 4096 @@ -287,7 +288,7 @@ int spdylay_frame_unpack_headers(spdylay_headers *frame, * Packs RST_STREAM frame |frame| in wire frame format and store it in * |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * length. This function expands |*buf_ptr| as necessary to store - * given |frame|. In spdy/2 spc, RST_STREAM wire format is always 16 + * given |frame|. In spdy/2 spec, RST_STREAM wire format is always 16 * bytes long. * * This function returns the size of packed frame if it succeeds, or @@ -312,6 +313,37 @@ 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 WINDOW_UPDATE frame |frame| in wire frame format and store it + * in |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| + * length. This function expands |*buf_ptr| as necessary to store + * given |frame|. In SPDY/3 spec, WINDOW_UPDATE wire format is always 16 + * bytes long. + * + * This function returns the size of packed frame if it succeeds, or + * returns one of the following negative error codes: + * + * SPDYLAY_ERR_NOMEM + * Out of memory. + */ +ssize_t spdylay_frame_pack_window_update(uint8_t **buf_ptr, size_t *buflen_ptr, + spdylay_window_update *frame); + +/* + * Unpacks WINDOW_UPDATE frame byte sequence into |frame|. + * + * This function returns 0 if it succeeds or one of the following + * negative error codes: + * + * SPDYLAY_ERR_INVALID_FRAME + * The input data are invalid. + */ +int spdylay_frame_unpack_window_update(spdylay_window_update *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|. The capacity of |*buf_ptr| is |*buflen_ptr| @@ -448,6 +480,13 @@ void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame, void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame); +void spdylay_frame_window_update_init(spdylay_window_update *frame, + uint16_t version, + int32_t stream_id, + int32_t delta_window_size); + +void spdylay_frame_window_update_free(spdylay_window_update *frame); + /* * Initializes SETTINGS frame |frame| with given values. |frame| takes * ownership of |iv|, so caller must not free it. diff --git a/tests/main.c b/tests/main.c index 6786cbaf..e8b4cf9a 100644 --- a/tests/main.c +++ b/tests/main.c @@ -145,6 +145,8 @@ int main(int argc, char* argv[]) test_spdylay_frame_pack_syn_reply) || !CU_add_test(pSuite, "frame_pack_headers", test_spdylay_frame_pack_headers) || + !CU_add_test(pSuite, "frame_pack_window_update", + test_spdylay_frame_pack_window_update) || !CU_add_test(pSuite, "frame_pack_settings", test_spdylay_frame_pack_settings) || !CU_add_test(pSuite, "frame_nv_sort", test_spdylay_frame_nv_sort) || diff --git a/tests/spdylay_frame_test.c b/tests/spdylay_frame_test.c index 186137ef..62f2d561 100644 --- a/tests/spdylay_frame_test.c +++ b/tests/spdylay_frame_test.c @@ -384,6 +384,33 @@ void test_spdylay_frame_pack_headers() test_spdylay_frame_pack_headers_with(SPDYLAY_PROTO_SPDY3); } +void test_spdylay_frame_pack_window_update() +{ + spdylay_frame frame, oframe; + uint8_t *buf = NULL; + size_t buflen = 0; + ssize_t framelen; + spdylay_frame_window_update_init(&frame.window_update, SPDYLAY_PROTO_SPDY3, + 1000000007, 4096); + framelen = spdylay_frame_pack_window_update(&buf, &buflen, + &frame.window_update); + CU_ASSERT(0 == spdylay_frame_unpack_window_update + (&oframe.window_update, + &buf[0], SPDYLAY_FRAME_HEAD_LENGTH, + &buf[SPDYLAY_FRAME_HEAD_LENGTH], + framelen-SPDYLAY_FRAME_HEAD_LENGTH)); + CU_ASSERT(1000000007 == oframe.window_update.stream_id); + CU_ASSERT(4096 == oframe.window_update.delta_window_size); + CU_ASSERT(SPDYLAY_PROTO_SPDY3 == oframe.headers.hd.version); + CU_ASSERT(SPDYLAY_WINDOW_UPDATE == oframe.headers.hd.type); + CU_ASSERT(SPDYLAY_CTRL_FLAG_NONE == oframe.headers.hd.flags); + CU_ASSERT(framelen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.ping.hd.length); + free(buf); + spdylay_frame_window_update_free(&oframe.window_update); + spdylay_frame_window_update_free(&frame.window_update); +} + + void test_spdylay_frame_pack_settings() { spdylay_frame frame, oframe; diff --git a/tests/spdylay_frame_test.h b/tests/spdylay_frame_test.h index 3c30e5e8..f567a065 100644 --- a/tests/spdylay_frame_test.h +++ b/tests/spdylay_frame_test.h @@ -34,6 +34,7 @@ void test_spdylay_frame_pack_goaway(); void test_spdylay_frame_pack_syn_stream(); void test_spdylay_frame_pack_syn_reply(); void test_spdylay_frame_pack_headers(); +void test_spdylay_frame_pack_window_update(); void test_spdylay_frame_pack_settings(); void test_spdylay_frame_nv_sort(); void test_spdylay_frame_nv_downcase();