diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index b6544497..73b628c1 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -120,6 +120,11 @@ typedef struct { uint32_t status_code; } spdylay_rst_stream; +typedef struct { + spdylay_ctrl_hd hd; + uint32_t unique_id; +} spdylay_ping; + typedef union { int fd; void *ptr; @@ -144,6 +149,7 @@ typedef union { spdylay_syn_stream syn_stream; spdylay_syn_reply syn_reply; spdylay_rst_stream rst_stream; + spdylay_ping ping; spdylay_headers headers; spdylay_data data; } spdylay_frame; diff --git a/lib/spdylay_frame.c b/lib/spdylay_frame.c index c83a3193..e418baca 100644 --- a/lib/spdylay_frame.c +++ b/lib/spdylay_frame.c @@ -328,7 +328,7 @@ char** spdylay_frame_nv_copy(const char **nv) for(i = 0; i < n; ++i) { nnv[i] = strdup(nv[i]); if(nnv[i] == NULL) { - spdylay_frame_nv_free(nnv[i]); + spdylay_frame_nv_free(nnv); free(nnv); return NULL; } @@ -374,6 +374,19 @@ void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame) free(frame->nv); } +void spdylay_frame_ping_init(spdylay_ping *frame, uint32_t unique_id) +{ + memset(frame, 0, sizeof(spdylay_ping)); + frame->hd.version = SPDYLAY_PROTO_VERSION; + frame->hd.type = SPDYLAY_PING; + frame->hd.flags = SPDYLAY_FLAG_NONE; + frame->hd.length = 4; + frame->unique_id = unique_id; +} + +void spdylay_frame_ping_free(spdylay_ping *frame) +{} + void spdylay_frame_headers_init(spdylay_headers *frame, uint8_t flags, int32_t stream_id, char **nv) { @@ -499,6 +512,33 @@ int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame, return r; } +ssize_t spdylay_frame_pack_ping(uint8_t **buf_ptr, spdylay_ping *frame) +{ + uint8_t *framebuf = NULL; + ssize_t framelen = 12; + 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->unique_id); + *buf_ptr = framebuf; + return framelen; +} + +int spdylay_frame_unpack_ping(spdylay_ping *frame, + const uint8_t *head, size_t headlen, + const uint8_t *payload, size_t payloadlen) +{ + if(payloadlen < 4) { + return SPDYLAY_ERR_INVALID_FRAME; + } + spdylay_frame_unpack_ctrl_hd(&frame->hd, head); + frame->unique_id = spdylay_get_uint32(payload); + return 0; +} + #define SPDYLAY_HEADERS_NV_OFFSET 14 ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr, @@ -533,6 +573,7 @@ int spdylay_frame_unpack_headers(spdylay_headers *frame, frame->stream_id = spdylay_get_uint32(payload) & SPDYLAY_STREAM_ID_MASK; r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+6, payloadlen-6, inflater); + return r; } ssize_t spdylay_frame_pack_rst_stream(uint8_t **buf_ptr, diff --git a/lib/spdylay_frame.h b/lib/spdylay_frame.h index fef58790..6a3e6198 100644 --- a/lib/spdylay_frame.h +++ b/lib/spdylay_frame.h @@ -85,6 +85,22 @@ int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame, const uint8_t *payload, size_t payloadlen, spdylay_zlib *inflater); +/* + * Packs PING frame |frame| in wire format and store it in + * |*buf_ptr|. This function allocates enough memory in |*buf_ptr| to + * store given |frame|. This function returns the size of packed frame + * if it succeeds, or negative error code. + */ +ssize_t spdylay_frame_pack_ping(uint8_t **buf_ptr, spdylay_ping *frame); + +/* + * Unpacks PING wire format into |frame|. This function returns 0 if + * it succeeds, or negative error code. + */ +int spdylay_frame_unpack_ping(spdylay_ping *frame, + const uint8_t *head, size_t headlen, + const uint8_t *payload, size_t payloadlen); + /* * Packs HEADERS frame |frame| in wire format and store it in * |*buf_ptr|. This function allocates enough memory in |*buf_ptr| to @@ -104,6 +120,7 @@ int spdylay_frame_unpack_headers(spdylay_headers *frame, const uint8_t *head, size_t headlen, const uint8_t *payload, size_t payloadlen, spdylay_zlib *inflater); + /* * Packs RST_STREAM frame |frame| in wire frame format and store it in * |*buf_ptr|. This function allocates enough memory to store given @@ -160,6 +177,10 @@ void spdylay_frame_syn_reply_init(spdylay_syn_reply *frame, uint8_t flags, void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame); +void spdylay_frame_ping_init(spdylay_ping *frame, uint32_t unique_id); + +void spdylay_frame_ping_free(spdylay_ping *frame); + void spdylay_frame_headers_init(spdylay_headers *frame, uint8_t flags, int32_t stream_id, char **nv); diff --git a/tests/main.c b/tests/main.c index 411ceebb..531c7372 100644 --- a/tests/main.c +++ b/tests/main.c @@ -87,6 +87,7 @@ int main() !CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) || !CU_add_test(pSuite, "frame_count_nv_space", test_spdylay_frame_count_nv_space) || + !CU_add_test(pSuite, "frame_pack_ping", test_spdylay_frame_pack_ping) || !CU_add_test(pSuite, "frame_pack_headers", test_spdylay_frame_pack_headers)) { CU_cleanup_registry(); diff --git a/tests/spdylay_frame_test.c b/tests/spdylay_frame_test.c index f24c42e8..b5d9f504 100644 --- a/tests/spdylay_frame_test.c +++ b/tests/spdylay_frame_test.c @@ -53,6 +53,24 @@ void test_spdylay_frame_count_nv_space() CU_ASSERT(83 == spdylay_frame_count_nv_space((char**)headers)); } +void test_spdylay_frame_pack_ping() +{ + spdylay_frame frame, oframe; + uint8_t *buf; + ssize_t buflen; + spdylay_frame_ping_init(&frame.ping, 1); + buflen = spdylay_frame_pack_ping(&buf, &frame.ping); + CU_ASSERT(0 == spdylay_frame_unpack_ping + (&oframe.ping, + &buf[0], SPDYLAY_FRAME_HEAD_LENGTH, + &buf[SPDYLAY_FRAME_HEAD_LENGTH], + buflen-SPDYLAY_FRAME_HEAD_LENGTH)); + CU_ASSERT(1 == oframe.ping.unique_id); + free(buf); + spdylay_frame_ping_free(&oframe.ping); + spdylay_frame_ping_free(&frame.ping); +} + void test_spdylay_frame_pack_headers() { spdylay_zlib deflater, inflater; @@ -70,6 +88,11 @@ void test_spdylay_frame_pack_headers() &buf[SPDYLAY_FRAME_HEAD_LENGTH], buflen-SPDYLAY_FRAME_HEAD_LENGTH, &inflater)); + CU_ASSERT(3 == oframe.headers.stream_id); + CU_ASSERT(SPDYLAY_FLAG_FIN == oframe.headers.hd.flags); + CU_ASSERT(strcmp("method", oframe.headers.nv[0]) == 0); + CU_ASSERT(strcmp("GET", oframe.headers.nv[1]) == 0); + CU_ASSERT(NULL == oframe.headers.nv[12]); free(buf); spdylay_frame_headers_free(&oframe.headers); spdylay_frame_headers_free(&frame.headers); diff --git a/tests/spdylay_frame_test.h b/tests/spdylay_frame_test.h index 51097891..81db459a 100644 --- a/tests/spdylay_frame_test.h +++ b/tests/spdylay_frame_test.h @@ -27,6 +27,7 @@ void test_spdylay_frame_unpack_nv(); void test_spdylay_frame_count_nv_space(); +void test_spdylay_frame_pack_ping(); void test_spdylay_frame_pack_headers(); #endif /* SPDYLAY_FRAME_TEST_H */