diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index ae2ca10b..e54fe6d2 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -40,12 +40,70 @@ typedef enum { SPDYLAY_ERR_WOULDBLOCK = -504, SPDYLAY_ERR_PROTO = -505, SPDYLAY_ERR_CALLBACK_FAILURE = -505, + SPDYLAY_ERR_INVALID_FRAME = -506, } spdylay_error; typedef enum { SPDYLAY_MSG_MORE } spdylay_io_flag; +typedef enum { + SPDYLAY_SYN_STREAM = 1, + SPDYLAY_SYN_REPLY = 2, + SPDYLAY_RST_STREAM = 3, + SPDYLAY_SETTINGS = 4, + SPDYLAY_NOOP = 5, + SPDYLAY_PING = 6, + SPDYLAY_GOAWAY = 7, +} spdylay_frame_type; + +typedef enum { + SPDYLAY_FLAG_FIN = 1 +} spdylay_flag; + +typedef enum { + SPDYLAY_PROTOCOL_ERROR = 1, + SPDYLAY_INVALID_STREAM = 2, + SPDYLAY_REFUSED_STREAM = 3, + SPDYLAY_UNSUPPORTED_VERSION = 4, + SPDYLAY_CANCEL = 5, + SPDYLAY_INTERNAL_ERROR = 6, + SPDYLAY_FLOW_CONTROL_ERROR = 7 +} spdylay_status_code; + +typedef struct { + uint16_t version; + uint16_t type; + uint8_t flags; + int32_t length; +} spdylay_ctrl_hd; + +typedef struct { + spdylay_ctrl_hd hd; + int32_t stream_id; + int32_t assoc_stream_id; + uint8_t pri; + char **nv; +} spdylay_syn_stream; + +typedef struct { + spdylay_ctrl_hd hd; + int32_t stream_id; + char **nv; +} spdylay_syn_reply; + +typedef struct { + spdylay_ctrl_hd hd; + int32_t stream_id; + uint32_t status_code; +} spdylay_rst_stream; + +typedef union { + spdylay_syn_stream syn_stream; + spdylay_syn_reply syn_reply; + spdylay_rst_stream rst_stream; +} spdylay_frame; + struct spdylay_session; typedef struct spdylay_session spdylay_session; @@ -57,9 +115,28 @@ typedef ssize_t (*spdylay_recv_callback) (spdylay_session *session, uint8_t *buf, size_t length, int flags, void *user_data); +/* + * Callback function invoked by spdylay_session_recv() when a control + * frame is arrived. + */ +typedef void (*spdylay_on_ctrl_recv_callback) +(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame, + void *user_data); + +/* + * Callback function invoked by spdylay_session_recv() when an invalid + * control frame is arrived, which typically the case where RST_STREAM + * will be sent + */ +typedef void (*spdylay_on_invalid_ctrl_recv_callback) +(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame, + void *user_data); + typedef struct { spdylay_send_callback send_callback; spdylay_recv_callback recv_callback; + spdylay_on_ctrl_recv_callback on_ctrl_recv_callback; + spdylay_on_invalid_ctrl_recv_callback on_invalid_ctrl_recv_callback; } spdylay_session_callbacks; int spdylay_session_client_new(spdylay_session **session_ptr, diff --git a/lib/spdylay_frame.c b/lib/spdylay_frame.c index 84c246e6..231c8e57 100644 --- a/lib/spdylay_frame.c +++ b/lib/spdylay_frame.c @@ -75,14 +75,16 @@ static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr, uint8_t *framebuf = malloc(maxframelen); ssize_t framelen; spdylay_frame_pack_nv(nvbuf, nv); - framelen = spdylay_zlib_deflate_hd(deflater, framebuf+18, maxframelen-18, + framelen = spdylay_zlib_deflate_hd(deflater, + framebuf+nv_offset, + maxframelen-nv_offset, nvbuf, nvbuflen); free(nvbuf); if(framelen < 0) { free(framebuf); return framelen; } - framelen += 18; + framelen += nv_offset; *buf_ptr = framebuf; return framelen; } @@ -337,12 +339,38 @@ void spdylay_frame_syn_stream_free(spdylay_syn_stream *frame) free(frame->nv); } +void spdylay_frame_syn_reply_init(spdylay_syn_reply *frame, uint8_t flags, + int32_t stream_id, char **nv) +{ + memset(frame, 0, sizeof(spdylay_syn_reply)); + frame->hd.version = 2; + frame->hd.type = SPDYLAY_SYN_REPLY; + frame->hd.flags = flags; + frame->stream_id = stream_id; + frame->nv = nv; +} + void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame) { spdylay_frame_nv_free(frame->nv); free(frame->nv); } +void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame, + int32_t stream_id, uint32_t status_code) +{ + memset(frame, 0, sizeof(spdylay_rst_stream)); + frame->hd.version = 2; + frame->hd.type = SPDYLAY_RST_STREAM; + frame->hd.flags = 0; + frame->hd.length = 8; + frame->stream_id = stream_id; + frame->status_code = status_code; +} + +void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame) +{} + ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr, spdylay_syn_stream *frame, spdylay_zlib *deflater) @@ -371,15 +399,36 @@ int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame, spdylay_zlib *inflater) { int r; + if(payloadlen < 12) { + return SPDYLAY_ERR_INVALID_FRAME; + } spdylay_frame_unpack_ctrl_hd(&frame->hd, head); - frame->stream_id = spdylay_get_uint32(payload); - frame->assoc_stream_id = spdylay_get_uint32(payload+4); + frame->stream_id = spdylay_get_uint32(payload) & 0x7fffffff; + frame->assoc_stream_id = spdylay_get_uint32(payload+4) & 0x7fffffff; frame->pri = spdylay_unpack_pri(payload+8); r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+10, payloadlen-10, inflater); return r; } +ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr, + spdylay_syn_reply *frame, + spdylay_zlib *deflater) +{ + uint8_t *framebuf = NULL; + size_t framelen; + framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv, 14, deflater); + if(framelen < 0) { + return framelen; + } + frame->hd.length = framelen-8; + memset(framebuf, 0, 14); + spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd); + spdylay_put_uint32be(&framebuf[8], frame->stream_id); + *buf_ptr = framebuf; + return framelen; +} + int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame, const uint8_t *head, size_t headlen, const uint8_t *payload, size_t payloadlen, @@ -387,9 +436,38 @@ int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame, { int r; spdylay_frame_unpack_ctrl_hd(&frame->hd, head); - frame->stream_id = spdylay_get_uint32(payload); + frame->stream_id = spdylay_get_uint32(payload) &0x7fffffff; 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, + spdylay_rst_stream *frame) +{ + uint8_t *framebuf; + size_t framelen = 16; + 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->stream_id); + spdylay_put_uint32be(&framebuf[12], frame->status_code); + *buf_ptr = framebuf; + return framelen; +} + +int spdylay_frame_unpack_rst_stream(spdylay_rst_stream *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) & 0x7fffffff; + frame->status_code = spdylay_get_uint32(payload+4); + return 0; +} diff --git a/lib/spdylay_frame.h b/lib/spdylay_frame.h index 661b7b86..55dae389 100644 --- a/lib/spdylay_frame.h +++ b/lib/spdylay_frame.h @@ -29,48 +29,10 @@ # include #endif /* HAVE_CONFIG_H */ +#include #include "spdylay_zlib.h" #include "spdylay_buffer.h" -typedef enum { - SPDYLAY_SYN_STREAM = 1, - SPDYLAY_SYN_REPLY = 2, - SPDYLAY_RST_STREAM = 3, - SPDYLAY_SETTINGS = 4, - SPDYLAY_NOOP = 5, - SPDYLAY_PING = 6, - SPDYLAY_GOAWAY = 7, -} spdylay_frame_type; - -typedef enum { - SPDYLAY_FLAG_FIN = 1 -} spdylay_flag; - -typedef struct { - uint16_t version; - uint16_t type; - uint8_t flags; - int32_t length; -} spdylay_ctrl_hd; - -typedef struct { - spdylay_ctrl_hd hd; - int32_t stream_id; - int32_t assoc_stream_id; - uint8_t pri; - char **nv; -} spdylay_syn_stream; - -typedef struct { - spdylay_ctrl_hd hd; - int32_t stream_id; - char **nv; -} spdylay_syn_reply; - -typedef union { - spdylay_syn_stream syn_stream; -} spdylay_frame; - /* * Packs SYN_STREAM frame |frame| in wire frame format and store it in * |*buf_ptr|. This function allocates enough memory to store given @@ -94,6 +56,17 @@ int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame, const uint8_t *payload, size_t payloadlen, spdylay_zlib *inflater); +/* + * Packs SYN_REPLY frame |frame| in wire frame 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 + * it it succeeds, or returns negative error code. frame->hd.length is + * assigned after length is determined during packing process. + */ +ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr, + spdylay_syn_reply *frame, + spdylay_zlib *deflater); + /* * Unpacks SYN_REPLY frame byte sequence into |frame|. This function * returns 0 if it succeeds or negative error code. @@ -103,6 +76,24 @@ int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame, 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 + * frame in |*buf_ptr|. In spdy/2 spc, RST_STREAM wire format is + * always 16 bytes long. This function returns the size of packed + * frame if it succeeds, or negative error code. + */ +ssize_t spdylay_frame_pack_rst_stream(uint8_t **buf_ptr, + spdylay_rst_stream *frame); + +/* + * Unpacks RST_STREAM frame byte sequence into |frame|. This function + * returns 0 if it succeeds, or negative error code. + */ +int spdylay_frame_unpack_rst_stream(spdylay_rst_stream *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 @@ -136,8 +127,16 @@ void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame, uint8_t flags, void spdylay_frame_syn_stream_free(spdylay_syn_stream *frame); +void spdylay_frame_syn_reply_init(spdylay_syn_reply *frame, uint8_t flags, + int32_t stream_id, char **nv); + void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame); +void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame, + int32_t stream_id, uint32_t status_code); + +void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame); + /* * Returns 1 if the first byte of this frame indicates it is a control * frame. diff --git a/lib/spdylay_session.c b/lib/spdylay_session.c index e1e755ba..24c49d36 100644 --- a/lib/spdylay_session.c +++ b/lib/spdylay_session.c @@ -52,7 +52,7 @@ int spdylay_session_client_new(spdylay_session **session_ptr, } memset(*session_ptr, 0, sizeof(spdylay_session)); (*session_ptr)->next_stream_id = 1; - (*session_ptr)->last_accepted_stream_id = 0; + (*session_ptr)->last_recv_stream_id = 0; r = spdylay_zlib_deflate_hd_init(&(*session_ptr)->hd_deflater); if(r != 0) { @@ -157,6 +157,25 @@ int spdylay_session_add_frame(spdylay_session *session, return 0; } +int spdylay_session_add_rst_stream(spdylay_session *session, + int32_t stream_id, uint32_t status_code) +{ + int r; + spdylay_frame *frame; + frame = malloc(sizeof(spdylay_frame)); + if(frame == NULL) { + return SPDYLAY_ERR_NOMEM; + } + spdylay_frame_rst_stream_init(&frame->rst_stream, stream_id, status_code); + r = spdylay_session_add_frame(session, SPDYLAY_RST_STREAM, frame); + if(r != 0) { + spdylay_frame_rst_stream_free(&frame->rst_stream); + free(frame); + return r; + } + return 0; +} + int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id) { int r; @@ -318,45 +337,143 @@ static void spdylay_debug_print_nv(char **nv) } } -int spdylay_session_process_ctrl_frame(spdylay_session *session) +static void spdylay_session_call_on_ctrl_frame_received +(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame) +{ + if(session->callbacks.on_ctrl_recv_callback) { + session->callbacks.on_ctrl_recv_callback + (session, type, frame, session->user_data); + } +} + +/* + * Checks whether received stream_id is valid. + * This function returns 1 if it succeeds, or 0. + */ +static int spdylay_session_is_new_peer_stream_id(spdylay_session *session, + int32_t stream_id) +{ + if(stream_id == 0) { + return 0; + } + if(session->server) { + return stream_id % 2 == 1 && session->last_recv_stream_id < stream_id; + } else { + return stream_id % 2 == 0 && session->last_recv_stream_id < stream_id; + } +} + +/* + * Validates SYN_STREAM frame |frame|. This function returns 0 if it + * succeeds, or -1. + */ +static int spdylay_session_validate_syn_stream(spdylay_session *session, + spdylay_syn_stream *frame) +{ + /* TODO Check assoc_stream_id */ + if(spdylay_session_is_new_peer_stream_id(session, frame->stream_id)) { + return 0; + } else { + return -1; + } +} + +static spdylay_stream* spdylay_session_get_stream(spdylay_session *session, + int32_t stream_id) +{ + return (spdylay_stream*)spdylay_map_find(&session->streams, stream_id); +} + +/* + * Validates SYN_REPLY frame |frame|. This function returns 0 if it + * succeeds, or -1. + */ +static int spdylay_session_validate_syn_reply(spdylay_session *session, + spdylay_syn_reply *frame) +{ + spdylay_stream *stream; + stream = spdylay_session_get_stream(session, frame->stream_id); + if(stream && stream->state == SPDYLAY_STREAM_OPENING) { + return 0; + } else { + return -1; + } +} + +static int spdylay_session_handle_invalid_ctrl_frame(spdylay_session *session, + int32_t stream_id, + spdylay_frame_type type, + spdylay_frame *frame) { int r; + r = spdylay_session_add_rst_stream(session, stream_id, + SPDYLAY_PROTOCOL_ERROR); + if(r != 0) { + return r; + } + if(session->callbacks.on_invalid_ctrl_recv_callback) { + session->callbacks.on_invalid_ctrl_recv_callback + (session, type, frame, session->user_data); + } +} + +int spdylay_session_process_ctrl_frame(spdylay_session *session) +{ + int r = 0; uint16_t type; + spdylay_frame frame; memcpy(&type, &session->iframe.headbuf[2], sizeof(uint16_t)); type = ntohs(type); switch(type) { - case SPDYLAY_SYN_STREAM: { - spdylay_syn_stream frame; + case SPDYLAY_SYN_STREAM: printf("SYN_STREAM\n"); - r = spdylay_frame_unpack_syn_stream(&frame, session->iframe.headbuf, + r = spdylay_frame_unpack_syn_stream(&frame.syn_stream, + session->iframe.headbuf, sizeof(session->iframe.headbuf), session->iframe.buf, session->iframe.len, &session->hd_inflater); if(r == 0) { - spdylay_debug_print_nv(frame.nv); - spdylay_frame_syn_stream_free(&frame); + r = spdylay_session_validate_syn_stream(session, &frame.syn_stream); + if(r == 0) { + spdylay_session_call_on_ctrl_frame_received(session, type, &frame); + } else { + r = spdylay_session_handle_invalid_ctrl_frame + (session, frame.syn_stream.stream_id, type, &frame); + } + spdylay_frame_syn_stream_free(&frame.syn_stream); + } else { + /* TODO if r indicates mulformed NV pairs (multiple nulls) or + invalid frame, send RST_STREAM with PROTOCOL_ERROR. Same for + other control frames. */ } break; - } - case SPDYLAY_SYN_REPLY: { - spdylay_syn_reply frame; + case SPDYLAY_SYN_REPLY: printf("SYN_REPLY\n"); - r = spdylay_frame_unpack_syn_reply(&frame, session->iframe.headbuf, + r = spdylay_frame_unpack_syn_reply(&frame.syn_reply, + session->iframe.headbuf, sizeof(session->iframe.headbuf), session->iframe.buf, session->iframe.len, &session->hd_inflater); if(r == 0) { - spdylay_debug_print_nv(frame.nv); - spdylay_frame_syn_reply_free(&frame); + r = spdylay_session_validate_syn_reply(session, &frame.syn_reply); + if(r == 0) { + spdylay_session_call_on_ctrl_frame_received(session, type, &frame); + } else { + r = spdylay_session_handle_invalid_ctrl_frame + (session, frame.syn_reply.stream_id, type, &frame); + } + spdylay_frame_syn_reply_free(&frame.syn_reply); } break; - } default: /* ignore */ printf("Received control frame type %x\n", type); } + if(r != 0) { + return r; + } return 0; } diff --git a/lib/spdylay_session.h b/lib/spdylay_session.h index fa024ccd..aa99c5f5 100644 --- a/lib/spdylay_session.h +++ b/lib/spdylay_session.h @@ -75,7 +75,7 @@ typedef struct { typedef struct spdylay_session { uint8_t server; int32_t next_stream_id; - int32_t last_accepted_stream_id; + int32_t last_recv_stream_id; spdylay_map /* */ streams; spdylay_pq /* */ ob_pq; @@ -98,6 +98,9 @@ int spdylay_session_add_frame(spdylay_session *session, spdylay_frame_type frame_type, spdylay_frame *frame); +int spdylay_session_add_rst_stream(spdylay_session *session, + int32_t stream_id, uint32_t status_code); + int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id); int spdylay_session_close_stream(spdylay_session *session, int32_t stream_id); diff --git a/lib/spdylay_stream.h b/lib/spdylay_stream.h index 68cbe44c..2daf8234 100644 --- a/lib/spdylay_stream.h +++ b/lib/spdylay_stream.h @@ -32,8 +32,15 @@ #include typedef enum { + /* For stream initiator: SYN_STREAM has been sent, but SYN_REPLY is + not received yet. For receiver: SYN_STREAM has been received, + but it does not send SYN_REPLY yet. */ SPDYLAY_STREAM_OPENING, + /* For stream initiator: SYN_REPLY is received. For receiver: + SYN_REPLY is sent. */ SPDYLAY_STREAM_OPENED, + /* RST_STREAM is received, but somehow we need to keep stream in + memory. */ SPDYLAY_STREAM_CLOSING } spdylay_stream_state; diff --git a/lib/spdylay_zlib.c b/lib/spdylay_zlib.c index 006d44de..1600915d 100644 --- a/lib/spdylay_zlib.c +++ b/lib/spdylay_zlib.c @@ -120,7 +120,7 @@ ssize_t spdylay_zlib_inflate_hd(spdylay_zlib *inflater, inflater->zst.avail_out = spdylay_buffer_avail(buf); inflater->zst.next_out = spdylay_buffer_get(buf); r = inflate(&inflater->zst, Z_NO_FLUSH); - if(r == Z_STREAM_ERROR || r == Z_STREAM_END) { + if(r == Z_STREAM_ERROR || r == Z_STREAM_END || r == Z_DATA_ERROR) { return SPDYLAY_ERR_ZLIB; } else if(r == Z_NEED_DICT) { if(Z_OK != inflateSetDictionary(&inflater->zst, (uint8_t*)hd_dict, diff --git a/tests/main.c b/tests/main.c index 82e338bc..a10dbe8f 100644 --- a/tests/main.c +++ b/tests/main.c @@ -67,6 +67,8 @@ int main() !CU_add_test(pSuite, "buffer", test_spdylay_buffer) || !CU_add_test(pSuite, "zlib", test_spdylay_zlib) || !CU_add_test(pSuite, "session_recv", test_spdylay_session_recv) || + !CU_add_test(pSuite, "session_recv_invalid_stream_id", + test_spdylay_session_recv_invalid_stream_id) || !CU_add_test(pSuite, "session_add_frame", test_spdylay_session_add_frame) || !CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) || diff --git a/tests/spdylay_session_test.c b/tests/spdylay_session_test.c index 472e3d3f..aec6991f 100644 --- a/tests/spdylay_session_test.c +++ b/tests/spdylay_session_test.c @@ -48,6 +48,7 @@ typedef struct { typedef struct { accumulator *acc; scripted_data_feed *df; + int flags; } my_user_data; static void scripted_data_feed_init(scripted_data_feed *df, @@ -87,6 +88,15 @@ static ssize_t accumulator_send_callback(spdylay_session *session, return len; } +static void on_invalid_ctrl_recv_callback(spdylay_session *session, + spdylay_frame_type type, + spdylay_frame *frame, + void *user_data) +{ + my_user_data *ud = (my_user_data*)user_data; + ++ud->flags; +} + static char** dup_nv(const char **src) { int i; @@ -175,3 +185,46 @@ void test_spdylay_session_add_frame() spdylay_session_del(session); } + +void test_spdylay_session_recv_invalid_stream_id() +{ + spdylay_session *session; + spdylay_session_callbacks callbacks = { + NULL, + scripted_recv_callback, + NULL, + on_invalid_ctrl_recv_callback + }; + scripted_data_feed df; + my_user_data user_data; + const char *nv[] = { NULL }; + uint8_t *framedata; + size_t framelen; + spdylay_frame frame; + + user_data.df = &df; + user_data.flags = 0; + spdylay_session_client_new(&session, &callbacks, &user_data); + spdylay_frame_syn_stream_init(&frame.syn_stream, 0, 1, 0, 3, dup_nv(nv)); + framelen = spdylay_frame_pack_syn_stream(&framedata, &frame.syn_stream, + &session->hd_deflater); + scripted_data_feed_init(&df, framedata, framelen); + free(framedata); + spdylay_frame_syn_stream_free(&frame.syn_stream); + + CU_ASSERT(0 == spdylay_session_recv(session)); + CU_ASSERT(1 == user_data.flags); + + spdylay_frame_syn_reply_init(&frame.syn_reply, 0, 100, dup_nv(nv)); + framelen = spdylay_frame_pack_syn_reply(&framedata, &frame.syn_reply, + &session->hd_deflater); + scripted_data_feed_init(&df, framedata, framelen); + free(framedata); + spdylay_frame_syn_reply_free(&frame.syn_reply); + + CU_ASSERT(0 == spdylay_session_recv(session)); + CU_ASSERT(2 == user_data.flags); + + spdylay_session_del(session); +} + diff --git a/tests/spdylay_session_test.h b/tests/spdylay_session_test.h index 76e375b3..c0781d53 100644 --- a/tests/spdylay_session_test.h +++ b/tests/spdylay_session_test.h @@ -26,6 +26,7 @@ #define SPDYLAY_SESSION_TEST_H void test_spdylay_session_recv(); +void test_spdylay_session_recv_invalid_stream_id(); void test_spdylay_session_add_frame(); #endif // SPDYLAY_SESSION_TEST_H