Added GOAWAY handling
This commit is contained in:
parent
cb58e6e893
commit
aed626bfa5
|
@ -125,6 +125,12 @@ typedef struct {
|
||||||
uint32_t unique_id;
|
uint32_t unique_id;
|
||||||
} spdylay_ping;
|
} spdylay_ping;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_ctrl_hd hd;
|
||||||
|
int32_t last_good_stream_id;
|
||||||
|
uint32_t status_code;
|
||||||
|
} spdylay_goaway;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
int fd;
|
int fd;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
|
@ -150,6 +156,7 @@ typedef union {
|
||||||
spdylay_syn_reply syn_reply;
|
spdylay_syn_reply syn_reply;
|
||||||
spdylay_rst_stream rst_stream;
|
spdylay_rst_stream rst_stream;
|
||||||
spdylay_ping ping;
|
spdylay_ping ping;
|
||||||
|
spdylay_goaway goaway;
|
||||||
spdylay_headers headers;
|
spdylay_headers headers;
|
||||||
spdylay_data data;
|
spdylay_data data;
|
||||||
} spdylay_frame;
|
} spdylay_frame;
|
||||||
|
|
|
@ -399,6 +399,19 @@ void spdylay_frame_ping_init(spdylay_ping *frame, uint32_t unique_id)
|
||||||
void spdylay_frame_ping_free(spdylay_ping *frame)
|
void spdylay_frame_ping_free(spdylay_ping *frame)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void spdylay_frame_goaway_init(spdylay_goaway *frame,
|
||||||
|
int32_t last_good_stream_id)
|
||||||
|
{
|
||||||
|
memset(frame, 0, sizeof(spdylay_goaway));
|
||||||
|
frame->hd.version = SPDYLAY_PROTO_VERSION;
|
||||||
|
frame->hd.type = SPDYLAY_GOAWAY;
|
||||||
|
frame->hd.length = 4;
|
||||||
|
frame->last_good_stream_id = last_good_stream_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_goaway_free(spdylay_goaway *frame)
|
||||||
|
{}
|
||||||
|
|
||||||
void spdylay_frame_headers_init(spdylay_headers *frame, uint8_t flags,
|
void spdylay_frame_headers_init(spdylay_headers *frame, uint8_t flags,
|
||||||
int32_t stream_id, char **nv)
|
int32_t stream_id, char **nv)
|
||||||
{
|
{
|
||||||
|
@ -551,6 +564,34 @@ int spdylay_frame_unpack_ping(spdylay_ping *frame,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_frame_pack_goaway(uint8_t **buf_ptr, spdylay_goaway *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->last_good_stream_id);
|
||||||
|
*buf_ptr = framebuf;
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_frame_unpack_goaway(spdylay_goaway *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->last_good_stream_id = spdylay_get_uint32(payload) &
|
||||||
|
SPDYLAY_STREAM_ID_MASK;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define SPDYLAY_HEADERS_NV_OFFSET 14
|
#define SPDYLAY_HEADERS_NV_OFFSET 14
|
||||||
|
|
||||||
ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr,
|
ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr,
|
||||||
|
|
|
@ -101,6 +101,22 @@ int spdylay_frame_unpack_ping(spdylay_ping *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 GOAWAY 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_goaway(uint8_t **buf_ptr, spdylay_goaway *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpacks GOAWAY wire format into |frame|. This function returns 0 if
|
||||||
|
* it succeeds, or negative error code.
|
||||||
|
*/
|
||||||
|
int spdylay_frame_unpack_goaway(spdylay_goaway *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
|
* Packs HEADERS frame |frame| in wire format and store it in
|
||||||
* |*buf_ptr|. This function allocates enough memory in |*buf_ptr| to
|
* |*buf_ptr|. This function allocates enough memory in |*buf_ptr| to
|
||||||
|
@ -181,6 +197,11 @@ void spdylay_frame_ping_init(spdylay_ping *frame, uint32_t unique_id);
|
||||||
|
|
||||||
void spdylay_frame_ping_free(spdylay_ping *frame);
|
void spdylay_frame_ping_free(spdylay_ping *frame);
|
||||||
|
|
||||||
|
void spdylay_frame_goaway_init(spdylay_goaway *frame,
|
||||||
|
int32_t last_good_stream_id);
|
||||||
|
|
||||||
|
void spdylay_frame_goaway_free(spdylay_goaway *frame);
|
||||||
|
|
||||||
void spdylay_frame_headers_init(spdylay_headers *frame, uint8_t flags,
|
void spdylay_frame_headers_init(spdylay_headers *frame, uint8_t flags,
|
||||||
int32_t stream_id, char **nv);
|
int32_t stream_id, char **nv);
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,9 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
|
||||||
(*session_ptr)->last_ping_unique_id = 0;
|
(*session_ptr)->last_ping_unique_id = 0;
|
||||||
memset(&(*session_ptr)->last_ping_time, 0, sizeof(struct timespec));
|
memset(&(*session_ptr)->last_ping_time, 0, sizeof(struct timespec));
|
||||||
|
|
||||||
|
(*session_ptr)->goaway_flags = SPDYLAY_GOAWAY_NONE;
|
||||||
|
(*session_ptr)->last_good_stream_id = 0;
|
||||||
|
|
||||||
r = spdylay_zlib_deflate_hd_init(&(*session_ptr)->hd_deflater);
|
r = spdylay_zlib_deflate_hd_init(&(*session_ptr)->hd_deflater);
|
||||||
if(r != 0) {
|
if(r != 0) {
|
||||||
free(*session_ptr);
|
free(*session_ptr);
|
||||||
|
@ -144,6 +147,9 @@ static void spdylay_outbound_item_free(spdylay_outbound_item *item)
|
||||||
case SPDYLAY_PING:
|
case SPDYLAY_PING:
|
||||||
spdylay_frame_ping_free(&item->frame->ping);
|
spdylay_frame_ping_free(&item->frame->ping);
|
||||||
break;
|
break;
|
||||||
|
case SPDYLAY_GOAWAY:
|
||||||
|
spdylay_frame_goaway_free(&item->frame->goaway);
|
||||||
|
break;
|
||||||
case SPDYLAY_HEADERS:
|
case SPDYLAY_HEADERS:
|
||||||
spdylay_frame_headers_free(&item->frame->headers);
|
spdylay_frame_headers_free(&item->frame->headers);
|
||||||
break;
|
break;
|
||||||
|
@ -215,6 +221,9 @@ int spdylay_session_add_frame(spdylay_session *session,
|
||||||
/* Ping has "height" priority. Give it -1. */
|
/* Ping has "height" priority. Give it -1. */
|
||||||
item->pri = -1;
|
item->pri = -1;
|
||||||
break;
|
break;
|
||||||
|
case SPDYLAY_GOAWAY:
|
||||||
|
/* Should GOAWAY have higher priority? */
|
||||||
|
break;
|
||||||
case SPDYLAY_HEADERS:
|
case SPDYLAY_HEADERS:
|
||||||
/* Currently we don't have any API to send HEADERS frame, so this
|
/* Currently we don't have any API to send HEADERS frame, so this
|
||||||
is unreachable. */
|
is unreachable. */
|
||||||
|
@ -328,6 +337,11 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
||||||
int r;
|
int r;
|
||||||
switch(item->frame_type) {
|
switch(item->frame_type) {
|
||||||
case SPDYLAY_SYN_STREAM: {
|
case SPDYLAY_SYN_STREAM: {
|
||||||
|
if(session->goaway_flags) {
|
||||||
|
/* When GOAWAY is sent or received, peer must not send new
|
||||||
|
SYN_STREAM. */
|
||||||
|
return SPDYLAY_ERR_INVALID_FRAME;
|
||||||
|
}
|
||||||
item->frame->syn_stream.stream_id = session->next_stream_id;
|
item->frame->syn_stream.stream_id = session->next_stream_id;
|
||||||
session->next_stream_id += 2;
|
session->next_stream_id += 2;
|
||||||
framebuflen = spdylay_frame_pack_syn_stream(&framebuf,
|
framebuflen = spdylay_frame_pack_syn_stream(&framebuf,
|
||||||
|
@ -373,6 +387,19 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
||||||
/* Currently we don't have any API to send HEADERS frame, so this
|
/* Currently we don't have any API to send HEADERS frame, so this
|
||||||
is unreachable. */
|
is unreachable. */
|
||||||
abort();
|
abort();
|
||||||
|
case SPDYLAY_GOAWAY:
|
||||||
|
if(session->goaway_flags & SPDYLAY_GOAWAY_SEND) {
|
||||||
|
/* TODO The spec does not mandate that both endpoints have to
|
||||||
|
exchange GOAWAY. This implementation allows receiver of first
|
||||||
|
GOAWAY can sent its own GOAWAY to tell the remote peer that
|
||||||
|
last-good-stream-id. */
|
||||||
|
return SPDYLAY_ERR_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
framebuflen = spdylay_frame_pack_goaway(&framebuf, &item->frame->goaway);
|
||||||
|
if(framebuflen < 0) {
|
||||||
|
return framebuflen;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SPDYLAY_DATA: {
|
case SPDYLAY_DATA: {
|
||||||
if(!spdylay_session_is_data_allowed(session, item->frame->data.stream_id)) {
|
if(!spdylay_session_is_data_allowed(session, item->frame->data.stream_id)) {
|
||||||
return SPDYLAY_ERR_INVALID_FRAME;
|
return SPDYLAY_ERR_INVALID_FRAME;
|
||||||
|
@ -454,6 +481,9 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
|
||||||
/* TODO If clock_gettime() fails, what should we do? */
|
/* TODO If clock_gettime() fails, what should we do? */
|
||||||
clock_gettime(CLOCK_MONOTONIC, &session->last_ping_time);
|
clock_gettime(CLOCK_MONOTONIC, &session->last_ping_time);
|
||||||
break;
|
break;
|
||||||
|
case SPDYLAY_GOAWAY:
|
||||||
|
session->goaway_flags |= SPDYLAY_GOAWAY_SEND;
|
||||||
|
break;
|
||||||
case SPDYLAY_HEADERS:
|
case SPDYLAY_HEADERS:
|
||||||
/* Currently we don't have any API to send HEADERS frame, so this
|
/* Currently we don't have any API to send HEADERS frame, so this
|
||||||
is unreachable. */
|
is unreachable. */
|
||||||
|
@ -530,8 +560,12 @@ int spdylay_session_send(spdylay_session *session)
|
||||||
/* TODO Call error callback? */
|
/* TODO Call error callback? */
|
||||||
spdylay_outbound_item_free(item);
|
spdylay_outbound_item_free(item);
|
||||||
free(item);
|
free(item);
|
||||||
|
if(framebuflen <= SPDYLAY_ERR_FATAL) {
|
||||||
|
return framebuflen;
|
||||||
|
} else {
|
||||||
continue;;
|
continue;;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
session->aob.item = item;
|
session->aob.item = item;
|
||||||
session->aob.framebuf = framebuf;
|
session->aob.framebuf = framebuf;
|
||||||
session->aob.framebuflen = framebuflen;
|
session->aob.framebuflen = framebuflen;
|
||||||
|
@ -686,6 +720,10 @@ int spdylay_session_on_syn_stream_received(spdylay_session *session,
|
||||||
spdylay_frame *frame)
|
spdylay_frame *frame)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
if(session->goaway_flags) {
|
||||||
|
/* We don't accept SYN_STREAM after GOAWAY is sent or received. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if(spdylay_session_validate_syn_stream(session, &frame->syn_stream) == 0) {
|
if(spdylay_session_validate_syn_stream(session, &frame->syn_stream) == 0) {
|
||||||
uint8_t flags = frame->syn_stream.hd.flags;
|
uint8_t flags = frame->syn_stream.hd.flags;
|
||||||
if((flags & SPDYLAY_FLAG_FIN) && (flags & SPDYLAY_FLAG_UNIDIRECTIONAL)) {
|
if((flags & SPDYLAY_FLAG_FIN) && (flags & SPDYLAY_FLAG_UNIDIRECTIONAL)) {
|
||||||
|
@ -786,6 +824,25 @@ int spdylay_session_on_ping_received(spdylay_session *session,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spdylay_session_on_goaway_received(spdylay_session *session,
|
||||||
|
spdylay_frame *frame)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
session->last_good_stream_id = frame->goaway.last_good_stream_id;
|
||||||
|
session->goaway_flags |= SPDYLAY_GOAWAY_RECV;
|
||||||
|
if(!(session->goaway_flags & SPDYLAY_GOAWAY_SEND)) {
|
||||||
|
/* TODO The spec does not mandate to send back GOAWAY. I think the
|
||||||
|
remote endpoint does not expect this, but sending GOAWAY does
|
||||||
|
not harm. */
|
||||||
|
r = spdylay_session_add_goaway(session, session->last_recv_stream_id);
|
||||||
|
if(r != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spdylay_session_call_on_ctrl_frame_received(session, SPDYLAY_GOAWAY, frame);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int spdylay_session_on_headers_received(spdylay_session *session,
|
int spdylay_session_on_headers_received(spdylay_session *session,
|
||||||
spdylay_frame *frame)
|
spdylay_frame *frame)
|
||||||
{
|
{
|
||||||
|
@ -895,6 +952,17 @@ int spdylay_session_process_ctrl_frame(spdylay_session *session)
|
||||||
spdylay_frame_ping_free(&frame.ping);
|
spdylay_frame_ping_free(&frame.ping);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SPDYLAY_GOAWAY:
|
||||||
|
r = spdylay_frame_unpack_goaway(&frame.goaway,
|
||||||
|
session->iframe.headbuf,
|
||||||
|
sizeof(session->iframe.headbuf),
|
||||||
|
session->iframe.buf,
|
||||||
|
session->iframe.len);
|
||||||
|
if(r == 0) {
|
||||||
|
r = spdylay_session_on_goaway_received(session, &frame);
|
||||||
|
spdylay_frame_goaway_free(&frame.goaway);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SPDYLAY_HEADERS:
|
case SPDYLAY_HEADERS:
|
||||||
r = spdylay_frame_unpack_headers(&frame.headers,
|
r = spdylay_frame_unpack_headers(&frame.headers,
|
||||||
session->iframe.headbuf,
|
session->iframe.headbuf,
|
||||||
|
@ -1025,12 +1093,19 @@ int spdylay_session_recv(spdylay_session *session)
|
||||||
|
|
||||||
int spdylay_session_want_read(spdylay_session *session)
|
int spdylay_session_want_read(spdylay_session *session)
|
||||||
{
|
{
|
||||||
return 1;
|
/* If GOAWAY is not sent or received, we always want to read
|
||||||
|
incoming frames. After GOAWAY is sent or received, we are only
|
||||||
|
interested in existing streams. */
|
||||||
|
return !(session->goaway_flags & SPDYLAY_GOAWAY_SEND) ||
|
||||||
|
spdylay_map_size(&session->streams) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spdylay_session_want_write(spdylay_session *session)
|
int spdylay_session_want_write(spdylay_session *session)
|
||||||
{
|
{
|
||||||
return session->aob.item != NULL || !spdylay_pq_empty(&session->ob_pq);
|
uint8_t goaway_sent = session->goaway_flags & SPDYLAY_GOAWAY_SEND;
|
||||||
|
return (!goaway_sent &&
|
||||||
|
(session->aob.item != NULL || !spdylay_pq_empty(&session->ob_pq))) ||
|
||||||
|
(goaway_sent && spdylay_map_size(&session->streams) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id)
|
int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id)
|
||||||
|
@ -1050,6 +1125,24 @@ int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spdylay_session_add_goaway(spdylay_session *session,
|
||||||
|
int32_t last_good_stream_id)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
spdylay_frame *frame;
|
||||||
|
frame = malloc(sizeof(spdylay_frame));
|
||||||
|
if(frame == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
spdylay_frame_goaway_init(&frame->goaway, last_good_stream_id);
|
||||||
|
r = spdylay_session_add_frame(session, SPDYLAY_GOAWAY, frame);
|
||||||
|
if(r != 0) {
|
||||||
|
spdylay_frame_goaway_free(&frame->goaway);
|
||||||
|
free(frame);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
int spdylay_submit_ping(spdylay_session *session)
|
int spdylay_submit_ping(spdylay_session *session)
|
||||||
{
|
{
|
||||||
return spdylay_session_add_ping(session,
|
return spdylay_session_add_ping(session,
|
||||||
|
|
|
@ -79,6 +79,14 @@ typedef struct {
|
||||||
uint8_t ign;
|
uint8_t ign;
|
||||||
} spdylay_inbound_frame;
|
} spdylay_inbound_frame;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPDYLAY_GOAWAY_NONE = 0,
|
||||||
|
/* Flag means GOAWAY frame is sent to the remote peer. */
|
||||||
|
SPDYLAY_GOAWAY_SEND = 0x1,
|
||||||
|
/* Flag means GOAWAY frame is received from the remote peer. */
|
||||||
|
SPDYLAY_GOAWAY_RECV = 0x2
|
||||||
|
} spdylay_goaway_flag;
|
||||||
|
|
||||||
typedef struct spdylay_session {
|
typedef struct spdylay_session {
|
||||||
uint8_t server;
|
uint8_t server;
|
||||||
int32_t next_stream_id;
|
int32_t next_stream_id;
|
||||||
|
@ -103,6 +111,12 @@ typedef struct spdylay_session {
|
||||||
/* Time stamp when last ping is sent. */
|
/* Time stamp when last ping is sent. */
|
||||||
struct timespec last_ping_time;
|
struct timespec last_ping_time;
|
||||||
|
|
||||||
|
/* Flags indicating GOAWAY is sent and/or recieved. The flags are
|
||||||
|
composed by bitwise OR-ing spdylay_goaway_flag. */
|
||||||
|
uint8_t goaway_flags;
|
||||||
|
/* This is the value in GOAWAY frame sent by remote endpoint. */
|
||||||
|
int32_t last_good_stream_id;
|
||||||
|
|
||||||
spdylay_session_callbacks callbacks;
|
spdylay_session_callbacks callbacks;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
} spdylay_session;
|
} spdylay_session;
|
||||||
|
@ -118,6 +132,9 @@ int spdylay_session_add_rst_stream(spdylay_session *session,
|
||||||
|
|
||||||
int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id);
|
int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id);
|
||||||
|
|
||||||
|
int spdylay_session_add_goaway(spdylay_session *session,
|
||||||
|
int32_t last_good_stream_id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates new stream in |session| with stream ID |stream_id|,
|
* Creates new stream in |session| with stream ID |stream_id|,
|
||||||
* priority |pri| and flags |flags|. Currently, |flags| &
|
* priority |pri| and flags |flags|. Currently, |flags| &
|
||||||
|
@ -167,6 +184,12 @@ int spdylay_session_on_rst_stream_received(spdylay_session *session,
|
||||||
int spdylay_session_on_ping_received(spdylay_session *session,
|
int spdylay_session_on_ping_received(spdylay_session *session,
|
||||||
spdylay_frame *frame);
|
spdylay_frame *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when GOAWAY is received. Received frame is |frame|.
|
||||||
|
*/
|
||||||
|
int spdylay_session_on_goaway_received(spdylay_session *session,
|
||||||
|
spdylay_frame *frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when HEADERS is recieved. Received frame is |frame|.
|
* Called when HEADERS is recieved. Received frame is |frame|.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -86,10 +86,14 @@ int main()
|
||||||
test_spdylay_session_on_headers_received) ||
|
test_spdylay_session_on_headers_received) ||
|
||||||
!CU_add_test(pSuite, "session_on_ping_received",
|
!CU_add_test(pSuite, "session_on_ping_received",
|
||||||
test_spdylay_session_on_ping_received) ||
|
test_spdylay_session_on_ping_received) ||
|
||||||
|
!CU_add_test(pSuite, "session_on_goaway_received",
|
||||||
|
test_spdylay_session_on_goaway_received) ||
|
||||||
!CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) ||
|
!CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) ||
|
||||||
!CU_add_test(pSuite, "frame_count_nv_space",
|
!CU_add_test(pSuite, "frame_count_nv_space",
|
||||||
test_spdylay_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_ping", test_spdylay_frame_pack_ping) ||
|
||||||
|
!CU_add_test(pSuite, "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_nv_sort", test_spdylay_frame_nv_sort)) {
|
!CU_add_test(pSuite, "frame_nv_sort", test_spdylay_frame_nv_sort)) {
|
||||||
|
|
|
@ -71,6 +71,28 @@ void test_spdylay_frame_pack_ping()
|
||||||
spdylay_frame_ping_free(&frame.ping);
|
spdylay_frame_ping_free(&frame.ping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_spdylay_frame_pack_goaway()
|
||||||
|
{
|
||||||
|
spdylay_frame frame, oframe;
|
||||||
|
uint8_t *buf;
|
||||||
|
ssize_t buflen;
|
||||||
|
spdylay_frame_goaway_init(&frame.goaway, 1000000007);
|
||||||
|
buflen = spdylay_frame_pack_goaway(&buf, &frame.goaway);
|
||||||
|
CU_ASSERT(0 == spdylay_frame_unpack_goaway
|
||||||
|
(&oframe.goaway,
|
||||||
|
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
|
||||||
|
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
|
||||||
|
buflen-SPDYLAY_FRAME_HEAD_LENGTH));
|
||||||
|
CU_ASSERT(1000000007 == oframe.goaway.last_good_stream_id);
|
||||||
|
CU_ASSERT(SPDYLAY_PROTO_VERSION == oframe.headers.hd.version);
|
||||||
|
CU_ASSERT(SPDYLAY_GOAWAY == oframe.headers.hd.type);
|
||||||
|
CU_ASSERT(SPDYLAY_FLAG_NONE == oframe.headers.hd.flags);
|
||||||
|
CU_ASSERT(buflen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.ping.hd.length);
|
||||||
|
free(buf);
|
||||||
|
spdylay_frame_goaway_free(&oframe.goaway);
|
||||||
|
spdylay_frame_goaway_free(&frame.goaway);
|
||||||
|
}
|
||||||
|
|
||||||
void test_spdylay_frame_pack_headers()
|
void test_spdylay_frame_pack_headers()
|
||||||
{
|
{
|
||||||
spdylay_zlib deflater, inflater;
|
spdylay_zlib deflater, inflater;
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
void test_spdylay_frame_unpack_nv();
|
void test_spdylay_frame_unpack_nv();
|
||||||
void test_spdylay_frame_count_nv_space();
|
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_headers();
|
void test_spdylay_frame_pack_headers();
|
||||||
void test_spdylay_frame_nv_sort();
|
void test_spdylay_frame_nv_sort();
|
||||||
|
|
||||||
|
|
|
@ -579,3 +579,34 @@ void test_spdylay_session_on_ping_received()
|
||||||
spdylay_frame_ping_free(&frame.ping);
|
spdylay_frame_ping_free(&frame.ping);
|
||||||
spdylay_session_del(session);
|
spdylay_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_spdylay_session_on_goaway_received()
|
||||||
|
{
|
||||||
|
spdylay_session *session;
|
||||||
|
spdylay_session_callbacks callbacks = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
on_ctrl_recv_callback,
|
||||||
|
on_invalid_ctrl_recv_callback,
|
||||||
|
};
|
||||||
|
my_user_data user_data;
|
||||||
|
spdylay_frame frame;
|
||||||
|
spdylay_outbound_item *top;
|
||||||
|
int32_t stream_id = 1000000007;
|
||||||
|
user_data.valid = 0;
|
||||||
|
user_data.invalid = 0;
|
||||||
|
|
||||||
|
spdylay_session_client_new(&session, &callbacks, &user_data);
|
||||||
|
spdylay_frame_goaway_init(&frame.goaway, stream_id);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_session_on_goaway_received(session, &frame));
|
||||||
|
CU_ASSERT(1 == user_data.valid);
|
||||||
|
CU_ASSERT(session->goaway_flags == SPDYLAY_GOAWAY_RECV);
|
||||||
|
|
||||||
|
top = spdylay_session_get_ob_pq_top(session);
|
||||||
|
CU_ASSERT(SPDYLAY_GOAWAY == top->frame_type);
|
||||||
|
CU_ASSERT(0 == top->frame->goaway.last_good_stream_id);
|
||||||
|
|
||||||
|
spdylay_frame_goaway_free(&frame.goaway);
|
||||||
|
spdylay_session_del(session);
|
||||||
|
}
|
||||||
|
|
|
@ -36,5 +36,6 @@ void test_spdylay_submit_response();
|
||||||
void test_spdylay_session_reply_fail();
|
void test_spdylay_session_reply_fail();
|
||||||
void test_spdylay_session_on_headers_received();
|
void test_spdylay_session_on_headers_received();
|
||||||
void test_spdylay_session_on_ping_received();
|
void test_spdylay_session_on_ping_received();
|
||||||
|
void test_spdylay_session_on_goaway_received();
|
||||||
|
|
||||||
#endif // SPDYLAY_SESSION_TEST_H
|
#endif // SPDYLAY_SESSION_TEST_H
|
||||||
|
|
Loading…
Reference in New Issue