Added SPDY/3 flow control.

This commit is contained in:
Tatsuhiro Tsujikawa 2012-02-26 00:12:32 +09:00
parent 4e62c75b02
commit 8693874340
12 changed files with 522 additions and 93 deletions

View File

@ -173,7 +173,7 @@ SpdyEventHandler::SpdyEventHandler(const Config* config,
: EventHandler(config), : EventHandler(config),
fd_(fd), ssl_(ssl), session_id_(session_id), want_write_(false) fd_(fd), ssl_(ssl), session_id_(session_id), want_write_(false)
{ {
spdylay_session_server_new(&session_, callbacks, this); spdylay_session_server_new(&session_, SPDYLAY_PROTO_SPDY2, callbacks, this);
} }
SpdyEventHandler::~SpdyEventHandler() SpdyEventHandler::~SpdyEventHandler()

View File

@ -51,7 +51,7 @@ bool ssl_debug = false;
Spdylay::Spdylay(int fd, SSL *ssl, const spdylay_session_callbacks *callbacks) Spdylay::Spdylay(int fd, SSL *ssl, const spdylay_session_callbacks *callbacks)
: fd_(fd), ssl_(ssl), want_write_(false) : fd_(fd), ssl_(ssl), want_write_(false)
{ {
spdylay_session_client_new(&session_, callbacks, this); spdylay_session_client_new(&session_, SPDYLAY_PROTO_SPDY2, callbacks, this);
} }
Spdylay::~Spdylay() Spdylay::~Spdylay()
@ -286,7 +286,8 @@ const char *ctrl_names[] = {
"NOOP", "NOOP",
"PING", "PING",
"GOAWAY", "GOAWAY",
"HEADERS" "HEADERS",
"WINDOW_UPDATE"
}; };
} // namespace } // namespace
@ -367,6 +368,12 @@ void print_frame(spdylay_frame_type type, spdylay_frame *frame)
printf("(stream_id=%d)\n", frame->headers.stream_id); printf("(stream_id=%d)\n", frame->headers.stream_id);
print_nv(frame->headers.nv); print_nv(frame->headers.nv);
break; break;
case SPDYLAY_WINDOW_UPDATE:
print_frame_attr_indent();
printf("(stream_id=%d, delta_window_size=%d)\n",
frame->window_update.stream_id,
frame->window_update.delta_window_size);
break;
default: default:
printf("\n"); printf("\n");
break; break;

View File

@ -127,8 +127,8 @@ typedef enum {
SPDYLAY_FLOW_CONTROL_ERROR = 7 SPDYLAY_FLOW_CONTROL_ERROR = 7
} spdylay_status_code; } spdylay_status_code;
#define SPDYLAY_SPDY2_LOWEST_PRI 3 #define SPDYLAY_SPDY2_PRI_LOWEST 3
#define SPDYLAY_SPDY3_LOWEST_PRI 7 #define SPDYLAY_SPDY3_PRI_LOWEST 7
typedef struct { typedef struct {
uint16_t version; uint16_t version;
@ -141,8 +141,8 @@ typedef struct {
spdylay_ctrl_hd hd; spdylay_ctrl_hd hd;
int32_t stream_id; int32_t stream_id;
int32_t assoc_stream_id; int32_t assoc_stream_id;
/* 0 (Highest) to SPDYLAY_SPDY2_LOWEST_PRI or /* 0 (Highest) to SPDYLAY_SPDY2_PRI_LOWEST or
SPDYLAY_SPDY3_LOWEST_PRI (loweset), depending on the protocol SPDYLAY_SPDY3_PRI_LOWEST (loweset), depending on the protocol
version. */ version. */
uint8_t pri; uint8_t pri;
/* Since SPDY/3 */ /* Since SPDY/3 */
@ -372,10 +372,11 @@ typedef struct {
} spdylay_session_callbacks; } spdylay_session_callbacks;
/* /*
* Initializes |*session_ptr| for client use. The all members of * Initializes |*session_ptr| for client use, using the protocol
* |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| * version |version|. The all members of |callbacks| are copied to
* does not store |callbacks|. |user_data| is an arbitrary user * |*session_ptr|. Therefore |*session_ptr| does not store
* supplied data, which will be passed to the callback functions. * |callbacks|. |user_data| is an arbitrary user supplied data, which
* will be passed to the callback functions.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@ -388,14 +389,16 @@ typedef struct {
* The version is not supported. * The version is not supported.
*/ */
int spdylay_session_client_new(spdylay_session **session_ptr, int spdylay_session_client_new(spdylay_session **session_ptr,
uint16_t version,
const spdylay_session_callbacks *callbacks, const spdylay_session_callbacks *callbacks,
void *user_data); void *user_data);
/* /*
* Initializes |*session_ptr| for server use. The all members of * Initializes |*session_ptr| for server use, using the protocol
* |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| * version |version|. The all members of |callbacks| are copied to
* does not store |callbacks|. |user_data| is an arbitrary user * |*session_ptr|. Therefore |*session_ptr| does not store
* supplied data, which will be passed to the callback functions. * |callbacks|. |user_data| is an arbitrary user supplied data, which
* will be passed to the callback functions.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@ -408,6 +411,7 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
* The version is not supported. * The version is not supported.
*/ */
int spdylay_session_server_new(spdylay_session **session_ptr, int spdylay_session_server_new(spdylay_session **session_ptr,
uint16_t version,
const spdylay_session_callbacks *callbacks, const spdylay_session_callbacks *callbacks,
void *user_data); void *user_data);

View File

@ -73,10 +73,14 @@ static int spdylay_outbound_item_compar(const void *lhsx, const void *rhsx)
} }
static int spdylay_session_new(spdylay_session **session_ptr, static int spdylay_session_new(spdylay_session **session_ptr,
uint16_t version,
const spdylay_session_callbacks *callbacks, const spdylay_session_callbacks *callbacks,
void *user_data) void *user_data)
{ {
int r; int r;
if(version != SPDYLAY_PROTO_SPDY2 && version != SPDYLAY_PROTO_SPDY3) {
return SPDYLAY_ERR_UNSUPPORTED_VERSION;
}
*session_ptr = malloc(sizeof(spdylay_session)); *session_ptr = malloc(sizeof(spdylay_session));
if(*session_ptr == NULL) { if(*session_ptr == NULL) {
r = SPDYLAY_ERR_NOMEM; r = SPDYLAY_ERR_NOMEM;
@ -84,11 +88,15 @@ static int spdylay_session_new(spdylay_session **session_ptr,
} }
memset(*session_ptr, 0, sizeof(spdylay_session)); memset(*session_ptr, 0, sizeof(spdylay_session));
(*session_ptr)->version = version;
/* next_stream_id, last_recv_stream_id and next_unique_id are /* next_stream_id, last_recv_stream_id and next_unique_id are
initialized in either spdylay_session_client_new or initialized in either spdylay_session_client_new or
spdylay_session_server_new */ spdylay_session_server_new */
(*session_ptr)->version = SPDYLAY_PROTO_SPDY2; (*session_ptr)->flow_control =
(*session_ptr)->version == SPDYLAY_PROTO_SPDY3;
(*session_ptr)->last_ping_unique_id = 0; (*session_ptr)->last_ping_unique_id = 0;
(*session_ptr)->next_seq = 0; (*session_ptr)->next_seq = 0;
@ -137,6 +145,9 @@ static int spdylay_session_new(spdylay_session **session_ptr,
(*session_ptr)->settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = (*session_ptr)->settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] =
SPDYLAY_CONCURRENT_STREAMS_MAX; SPDYLAY_CONCURRENT_STREAMS_MAX;
(*session_ptr)->settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE] =
SPDYLAY_INITIAL_WINDOW_SIZE;
(*session_ptr)->callbacks = *callbacks; (*session_ptr)->callbacks = *callbacks;
(*session_ptr)->user_data = user_data; (*session_ptr)->user_data = user_data;
@ -173,11 +184,12 @@ static int spdylay_session_new(spdylay_session **session_ptr,
} }
int spdylay_session_client_new(spdylay_session **session_ptr, int spdylay_session_client_new(spdylay_session **session_ptr,
uint16_t version,
const spdylay_session_callbacks *callbacks, const spdylay_session_callbacks *callbacks,
void *user_data) void *user_data)
{ {
int r; int r;
r = spdylay_session_new(session_ptr, callbacks, user_data); r = spdylay_session_new(session_ptr, version, callbacks, user_data);
if(r == 0) { if(r == 0) {
/* IDs for use in client */ /* IDs for use in client */
(*session_ptr)->next_stream_id = 1; (*session_ptr)->next_stream_id = 1;
@ -188,11 +200,12 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
} }
int spdylay_session_server_new(spdylay_session **session_ptr, int spdylay_session_server_new(spdylay_session **session_ptr,
uint16_t version,
const spdylay_session_callbacks *callbacks, const spdylay_session_callbacks *callbacks,
void *user_data) void *user_data)
{ {
int r; int r;
r = spdylay_session_new(session_ptr, callbacks, user_data); r = spdylay_session_new(session_ptr, version, callbacks, user_data);
if(r == 0) { if(r == 0) {
(*session_ptr)->server = 1; (*session_ptr)->server = 1;
/* IDs for use in client */ /* IDs for use in client */
@ -264,7 +277,7 @@ int spdylay_session_add_frame(spdylay_session *session,
item->aux_data = aux_data; item->aux_data = aux_data;
item->seq = session->next_seq++; item->seq = session->next_seq++;
/* Set priority lowest at the moment. */ /* Set priority lowest at the moment. */
item->pri = 3; item->pri = spdylay_session_get_pri_lowest(session);
switch(frame_type) { switch(frame_type) {
case SPDYLAY_SYN_STREAM: case SPDYLAY_SYN_STREAM:
item->pri = frame->syn_stream.pri; item->pri = frame->syn_stream.pri;
@ -308,6 +321,14 @@ int spdylay_session_add_frame(spdylay_session *session,
} }
break; break;
} }
case SPDYLAY_WINDOW_UPDATE: {
spdylay_stream *stream = spdylay_session_get_stream
(session, frame->window_update.stream_id);
if(stream) {
item->pri = stream->pri;
}
break;
}
case SPDYLAY_DATA: { case SPDYLAY_DATA: {
spdylay_stream *stream = spdylay_session_get_stream spdylay_stream *stream = spdylay_session_get_stream
(session, frame->data.stream_id); (session, frame->data.stream_id);
@ -361,6 +382,7 @@ spdylay_stream* spdylay_session_open_stream(spdylay_session *session,
return NULL; return NULL;
} }
spdylay_stream_init(stream, stream_id, flags, pri, initial_state, spdylay_stream_init(stream, stream_id, flags, pri, initial_state,
session->settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE],
stream_user_data); stream_user_data);
r = spdylay_map_insert(&session->streams, stream_id, stream); r = spdylay_map_insert(&session->streams, stream_id, stream);
if(r != 0) { if(r != 0) {
@ -452,6 +474,38 @@ static int spdylay_session_is_headers_allowed(spdylay_session *session,
} }
} }
/*
* Returns nonzero value if local endpoint can send WINDOW_UPDATE with
* stream ID |stream_id| at the moment.
*/
static int spdylay_session_is_window_update_allowed(spdylay_session *session,
int32_t stream_id)
{
spdylay_stream *stream = spdylay_session_get_stream(session, stream_id);
if(stream == NULL) {
return 0;
}
return stream->state != SPDYLAY_STREAM_CLOSING;
}
/*
* Returns the available window size.
*/
static size_t spdylay_session_avail_window(spdylay_session *session,
spdylay_stream *stream)
{
if(session->flow_control == 0) {
return SPDYLAY_DATA_PAYLOAD_LENGTH;
} else {
if(stream->window_size >= SPDYLAY_DATA_PAYLOAD_LENGTH ||
stream->initial_window_size < stream->window_size*2) {
return stream->window_size;
} else {
return 0;
}
}
}
static int spdylay_session_is_data_allowed(spdylay_session *session, static int spdylay_session_is_data_allowed(spdylay_session *session,
int32_t stream_id) int32_t stream_id)
{ {
@ -577,6 +631,19 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
} }
break; break;
} }
case SPDYLAY_WINDOW_UPDATE: {
if(!spdylay_session_is_window_update_allowed
(session, item->frame->window_update.stream_id)) {
return SPDYLAY_ERR_INVALID_FRAME;
}
framebuflen = spdylay_frame_pack_window_update(&session->aob.framebuf,
&session->aob.framebufmax,
&item->frame->window_update);
if(framebuflen < 0) {
return framebuflen;
}
break;
}
case SPDYLAY_GOAWAY: case SPDYLAY_GOAWAY:
if(session->goaway_flags & SPDYLAY_GOAWAY_SEND) { if(session->goaway_flags & SPDYLAY_GOAWAY_SEND) {
/* TODO The spec does not mandate that both endpoints have to /* TODO The spec does not mandate that both endpoints have to
@ -593,20 +660,28 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
} }
break; break;
case SPDYLAY_DATA: { case SPDYLAY_DATA: {
size_t avail_window;
spdylay_stream *stream;
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;
} }
framebuflen = spdylay_session_pack_data(session, stream = spdylay_session_get_stream(session, item->frame->data.stream_id);
&session->aob.framebuf,
&session->aob.framebufmax,
SPDYLAY_DATA_PAYLOAD_LENGTH,
&item->frame->data);
if(framebuflen == SPDYLAY_ERR_DEFERRED) {
spdylay_stream *stream = spdylay_session_get_stream
(session, item->frame->data.stream_id);
/* Assuming stream is not NULL */ /* Assuming stream is not NULL */
assert(stream); assert(stream);
spdylay_stream_defer_data(stream, item); avail_window = spdylay_session_avail_window(session, stream);
if(avail_window == 0) {
spdylay_stream_defer_data(stream, item, SPDYLAY_DEFERRED_FLOW_CONTROL);
return SPDYLAY_ERR_DEFERRED;
}
framebuflen = spdylay_session_pack_data
(session,
&session->aob.framebuf,
&session->aob.framebufmax,
(avail_window < SPDYLAY_DATA_PAYLOAD_LENGTH) ?
avail_window : SPDYLAY_DATA_PAYLOAD_LENGTH,
&item->frame->data);
if(framebuflen == SPDYLAY_ERR_DEFERRED) {
spdylay_stream_defer_data(stream, item, SPDYLAY_DEFERRED_NONE);
return SPDYLAY_ERR_DEFERRED; return SPDYLAY_ERR_DEFERRED;
} else if(framebuflen < 0) { } else if(framebuflen < 0) {
return framebuflen; return framebuflen;
@ -826,6 +901,8 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
} }
break; break;
} }
case SPDYLAY_WINDOW_UPDATE:
break;
case SPDYLAY_DATA: case SPDYLAY_DATA:
if(frame->data.eof && (frame->data.flags & SPDYLAY_DATA_FLAG_FIN)) { if(frame->data.eof && (frame->data.flags & SPDYLAY_DATA_FLAG_FIN)) {
spdylay_stream *stream = spdylay_stream *stream =
@ -846,21 +923,33 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
spdylay_active_outbound_item_reset(&session->aob); spdylay_active_outbound_item_reset(&session->aob);
} else { } else {
spdylay_outbound_item* item = spdylay_session_get_next_ob_item(session); spdylay_outbound_item* item = spdylay_session_get_next_ob_item(session);
if(item == NULL || session->aob.item->pri <= item->pri) {
/* If priority of this stream is higher or equal to other stream /* If priority of this stream is higher or equal to other stream
waiting at the top of the queue, we continue to send this waiting at the top of the queue, we continue to send this
data. */ data. */
r = spdylay_session_pack_data(session, if(item == NULL || session->aob.item->pri <= item->pri) {
&session->aob.framebuf, size_t avail_window;
&session->aob.framebufmax, spdylay_stream *stream;
SPDYLAY_DATA_PAYLOAD_LENGTH, stream = spdylay_session_get_stream(session, frame->data.stream_id);
&frame->data);
if(r == SPDYLAY_ERR_DEFERRED) {
spdylay_stream *stream =
spdylay_session_get_stream(session, frame->data.stream_id);
/* Assuming stream is not NULL */ /* Assuming stream is not NULL */
assert(stream); assert(stream);
spdylay_stream_defer_data(stream, session->aob.item); avail_window = spdylay_session_avail_window(session, stream);
if(avail_window == 0) {
spdylay_stream_defer_data(stream, session->aob.item,
SPDYLAY_DEFERRED_FLOW_CONTROL);
session->aob.item = NULL;
spdylay_active_outbound_item_reset(&session->aob);
return 0;
}
r = spdylay_session_pack_data
(session,
&session->aob.framebuf,
&session->aob.framebufmax,
(avail_window < SPDYLAY_DATA_PAYLOAD_LENGTH ?
avail_window : SPDYLAY_DATA_PAYLOAD_LENGTH),
&frame->data);
if(r == SPDYLAY_ERR_DEFERRED) {
spdylay_stream_defer_data(stream, session->aob.item,
SPDYLAY_DEFERRED_NONE);
session->aob.item = NULL; session->aob.item = NULL;
spdylay_active_outbound_item_reset(&session->aob); spdylay_active_outbound_item_reset(&session->aob);
} else if(r < 0) { } else if(r < 0) {
@ -939,6 +1028,16 @@ int spdylay_session_send(spdylay_session *session)
} }
} else { } else {
session->aob.framebufoff += sentlen; session->aob.framebufoff += sentlen;
if(session->flow_control &&
session->aob.item->frame_type == SPDYLAY_DATA) {
spdylay_frame *frame;
spdylay_stream *stream;
frame = session->aob.item->frame;
stream = spdylay_session_get_stream(session, frame->data.stream_id);
if(stream) {
stream->window_size -= spdylay_get_uint32(&session->aob.framebuf[4]);
}
}
if(session->aob.framebufoff == session->aob.framebuflen) { if(session->aob.framebufoff == session->aob.framebuflen) {
/* Frame has completely sent */ /* Frame has completely sent */
r = spdylay_session_after_frame_sent(session); r = spdylay_session_after_frame_sent(session);
@ -1295,6 +1394,45 @@ int spdylay_session_on_goaway_received(spdylay_session *session,
return 0; return 0;
} }
int spdylay_session_on_window_update_received(spdylay_session *session,
spdylay_frame *frame)
{
spdylay_stream *stream;
if(!spdylay_session_check_version(session, frame->window_update.hd.version)) {
return 0;
}
if(!session->flow_control) {
return 0;
}
stream = spdylay_session_get_stream(session, frame->window_update.stream_id);
if(stream) {
if(INT32_MAX-frame->window_update.delta_window_size < stream->window_size) {
int r;
r = spdylay_session_handle_invalid_stream
(session, frame->window_update.stream_id, SPDYLAY_WINDOW_UPDATE, frame,
SPDYLAY_FLOW_CONTROL_ERROR);
return r;
} else {
stream->window_size += frame->window_update.delta_window_size;
if(stream->deferred_data != NULL &&
(stream->deferred_flags & SPDYLAY_DEFERRED_FLOW_CONTROL)) {
int r;
r = spdylay_pq_push(&session->ob_pq, stream->deferred_data);
if(r == 0) {
spdylay_stream_detach_deferred_data(stream);
} else if(r < 0) {
/* FATAL */
assert(r < SPDYLAY_ERR_FATAL);
return r;
}
}
spdylay_session_call_on_ctrl_frame_received(session,
SPDYLAY_WINDOW_UPDATE, 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)
{ {
@ -1488,6 +1626,19 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
r = spdylay_session_fail_session(session); r = spdylay_session_fail_session(session);
} }
break; break;
case SPDYLAY_WINDOW_UPDATE:
r = spdylay_frame_unpack_window_update(&frame.window_update,
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len);
if(r == 0) {
r = spdylay_session_on_window_update_received(session, &frame);
spdylay_frame_window_update_free(&frame.window_update);
} else if(spdylay_is_non_fatal(r)) {
r = spdylay_session_fail_session(session);
}
break;
} }
if(r < SPDYLAY_ERR_FATAL) { if(r < SPDYLAY_ERR_FATAL) {
return r; return r;
@ -1568,6 +1719,40 @@ static int spdylay_session_process_data_frame(spdylay_session *session)
} }
} }
/*
* Accumulates received bytes |delta_size| and decides whether to send
* WINDOW_UPDATE.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
static int spdylay_session_update_recv_window_size(spdylay_session *session,
int32_t stream_id,
int32_t delta_size)
{
spdylay_stream *stream;
stream = spdylay_session_get_stream(session, stream_id);
if(stream) {
stream->recv_window_size += delta_size;
/* This is just a heuristics. */
if(stream->recv_window_size*2 >=
session->settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE]) {
int r;
r = spdylay_session_add_window_update(session, stream_id,
stream->recv_window_size);
if(r == 0) {
stream->recv_window_size = 0;
} else {
return r;
}
}
}
return 0;
}
int spdylay_session_recv(spdylay_session *session) int spdylay_session_recv(spdylay_session *session)
{ {
while(1) { while(1) {
@ -1616,6 +1801,8 @@ int spdylay_session_recv(spdylay_session *session)
if(session->iframe.state == SPDYLAY_RECV_PAYLOAD) { if(session->iframe.state == SPDYLAY_RECV_PAYLOAD) {
size_t rempayloadlen = session->iframe.len - session->iframe.off; size_t rempayloadlen = session->iframe.len - session->iframe.off;
size_t bufavail, readlen; size_t bufavail, readlen;
int32_t data_stream_id = 0;
uint8_t data_flags = SPDYLAY_DATA_FLAG_NONE;
if(spdylay_inbound_buffer_avail(&session->ibuf) == 0 && if(spdylay_inbound_buffer_avail(&session->ibuf) == 0 &&
rempayloadlen > 0) { rempayloadlen > 0) {
r = spdylay_recv(session); r = spdylay_recv(session);
@ -1632,23 +1819,39 @@ int spdylay_session_recv(spdylay_session *session)
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) { if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
memcpy(session->iframe.buf+session->iframe.off, memcpy(session->iframe.buf+session->iframe.off,
session->ibuf.mark, readlen); session->ibuf.mark, readlen);
} else if(session->callbacks.on_data_chunk_recv_callback) { } else {
int32_t stream_id;
uint8_t flags;
/* For data frame, We don't buffer data. Instead, just pass /* For data frame, We don't buffer data. Instead, just pass
received data to callback function. */ received data to callback function. */
stream_id = spdylay_get_uint32(session->iframe.headbuf) & data_stream_id = spdylay_get_uint32(session->iframe.headbuf) &
SPDYLAY_STREAM_ID_MASK; SPDYLAY_STREAM_ID_MASK;
flags = session->iframe.headbuf[4]; data_flags = session->iframe.headbuf[4];
if(session->callbacks.on_data_chunk_recv_callback) {
session->callbacks.on_data_chunk_recv_callback(session, session->callbacks.on_data_chunk_recv_callback(session,
flags, data_flags,
stream_id, data_stream_id,
session->ibuf.mark, session->ibuf.mark,
readlen, readlen,
session->user_data); session->user_data);
} }
}
session->iframe.off += readlen; session->iframe.off += readlen;
session->ibuf.mark += readlen; session->ibuf.mark += readlen;
if(session->flow_control &&
!spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
if(readlen > 0 &&
(session->iframe.len != session->iframe.off ||
(data_flags & SPDYLAY_DATA_FLAG_FIN) == 0)) {
r = spdylay_session_update_recv_window_size(session,
data_stream_id,
readlen);
if(r < 0) {
/* FATAL */
assert(r < SPDYLAY_ERR_FATAL);
return r;
}
}
}
if(session->iframe.len == session->iframe.off) { if(session->iframe.len == session->iframe.off) {
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) { if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
r = spdylay_session_process_ctrl_frame(session); r = spdylay_session_process_ctrl_frame(session);
@ -1738,6 +1941,26 @@ int spdylay_session_add_goaway(spdylay_session *session,
return r; return r;
} }
int spdylay_session_add_window_update(spdylay_session *session,
int32_t stream_id,
int32_t delta_window_size)
{
int r;
spdylay_frame *frame;
frame = malloc(sizeof(spdylay_frame));
if(frame == NULL) {
return SPDYLAY_ERR_NOMEM;
}
spdylay_frame_window_update_init(&frame->window_update, session->version,
stream_id, delta_window_size);
r = spdylay_session_add_frame(session, SPDYLAY_WINDOW_UPDATE, frame, NULL);
if(r != 0) {
spdylay_frame_window_update_free(&frame->window_update);
free(frame);
}
return r;
}
ssize_t spdylay_session_pack_data(spdylay_session *session, ssize_t spdylay_session_pack_data(spdylay_session *session,
uint8_t **buf_ptr, size_t *buflen_ptr, uint8_t **buf_ptr, size_t *buflen_ptr,
size_t datamax, size_t datamax,
@ -1805,7 +2028,8 @@ int spdylay_session_resume_data(spdylay_session *session, int32_t stream_id)
int r; int r;
spdylay_stream *stream; spdylay_stream *stream;
stream = spdylay_session_get_stream(session, stream_id); stream = spdylay_session_get_stream(session, stream_id);
if(stream == NULL || stream->deferred_data == NULL) { if(stream == NULL || stream->deferred_data == NULL ||
(stream->deferred_flags & SPDYLAY_DEFERRED_FLOW_CONTROL)) {
return SPDYLAY_ERR_INVALID_ARGUMENT; return SPDYLAY_ERR_INVALID_ARGUMENT;
} }
r = spdylay_pq_push(&session->ob_pq, stream->deferred_data); r = spdylay_pq_push(&session->ob_pq, stream->deferred_data);
@ -1814,3 +2038,14 @@ int spdylay_session_resume_data(spdylay_session *session, int32_t stream_id)
} }
return r; return r;
} }
uint8_t spdylay_session_get_pri_lowest(spdylay_session *session)
{
if(session->version == SPDYLAY_PROTO_SPDY2) {
return SPDYLAY_SPDY2_PRI_LOWEST;
} else if(session->version == SPDYLAY_PROTO_SPDY3) {
return SPDYLAY_SPDY3_PRI_LOWEST;
} else {
return 0;
}
}

View File

@ -62,6 +62,8 @@ typedef struct {
SPDYLAY_INITIAL_OUTBOUND_FRAMEBUF_LENGTH SPDYLAY_INITIAL_OUTBOUND_FRAMEBUF_LENGTH
#define SPDYLAY_INITIAL_NV_BUFFER_LENGTH 4096 #define SPDYLAY_INITIAL_NV_BUFFER_LENGTH 4096
#define SPDYLAY_INITIAL_WINDOW_SIZE 65536
typedef struct { typedef struct {
uint8_t buf[SPDYLAY_INBOUND_BUFFER_LENGTH]; uint8_t buf[SPDYLAY_INBOUND_BUFFER_LENGTH];
uint8_t *mark; uint8_t *mark;
@ -149,6 +151,10 @@ struct spdylay_session {
/* This is the value in GOAWAY frame sent by remote endpoint. */ /* This is the value in GOAWAY frame sent by remote endpoint. */
int32_t last_good_stream_id; int32_t last_good_stream_id;
/* Flag to indicate whether this session enforces flow
control. Nonzero for flow control enabled. */
uint8_t flow_control;
/* Settings value store. We just use ID as index. The index = 0 is /* Settings value store. We just use ID as index. The index = 0 is
unused. */ unused. */
uint32_t settings[SPDYLAY_SETTINGS_MAX+1]; uint32_t settings[SPDYLAY_SETTINGS_MAX+1];
@ -225,6 +231,22 @@ int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id);
int spdylay_session_add_goaway(spdylay_session *session, int spdylay_session_add_goaway(spdylay_session *session,
int32_t last_good_stream_id); int32_t last_good_stream_id);
/*
* Adds WINDOW_UPDATE frame with stream ID |stream_id| and
* delta-window-size |delta_window_size|. This is a convenient
* function built on top of spdylay_session_add_frame() to add
* WINDOW_UPDATE easily.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_session_add_window_update(spdylay_session *session,
int32_t stream_id,
int32_t delta_window_size);
/* /*
* 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|. SPDYLAY_CTRL_FLAG_UNIDIRECTIONAL * priority |pri| and flags |flags|. SPDYLAY_CTRL_FLAG_UNIDIRECTIONAL
@ -363,6 +385,19 @@ int spdylay_session_on_goaway_received(spdylay_session *session,
int spdylay_session_on_headers_received(spdylay_session *session, int spdylay_session_on_headers_received(spdylay_session *session,
spdylay_frame *frame); spdylay_frame *frame);
/*
* Called when WINDOW_UPDATE is recieved, assuming
* |frame.window_update| is properly initialized.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_session_on_window_update_received(spdylay_session *session,
spdylay_frame *frame);
/* /*
* Called when DATA is received. * Called when DATA is received.
* *
@ -437,4 +472,9 @@ spdylay_outbound_item* spdylay_session_pop_next_ob_item
spdylay_outbound_item* spdylay_session_get_next_ob_item spdylay_outbound_item* spdylay_session_get_next_ob_item
(spdylay_session *session); (spdylay_session *session);
/*
* Returns lowest priority value.
*/
uint8_t spdylay_session_get_pri_lowest(spdylay_session *session);
#endif /* SPDYLAY_SESSION_H */ #endif /* SPDYLAY_SESSION_H */

View File

@ -29,6 +29,7 @@
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id, void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id,
uint8_t flags, uint8_t pri, uint8_t flags, uint8_t pri,
spdylay_stream_state initial_state, spdylay_stream_state initial_state,
int32_t initial_window_size,
void *stream_user_data) void *stream_user_data)
{ {
stream->stream_id = stream_id; stream->stream_id = stream_id;
@ -41,6 +42,9 @@ void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id,
stream->pushed_streams_capacity = 0; stream->pushed_streams_capacity = 0;
stream->stream_user_data = stream_user_data; stream->stream_user_data = stream_user_data;
stream->deferred_data = NULL; stream->deferred_data = NULL;
stream->deferred_flags = SPDYLAY_DEFERRED_NONE;
stream->initial_window_size = stream->window_size = initial_window_size;
stream->recv_window_size = 0;
} }
void spdylay_stream_free(spdylay_stream *stream) void spdylay_stream_free(spdylay_stream *stream)
@ -73,13 +77,16 @@ int spdylay_stream_add_pushed_stream(spdylay_stream *stream, int32_t stream_id)
} }
void spdylay_stream_defer_data(spdylay_stream *stream, void spdylay_stream_defer_data(spdylay_stream *stream,
spdylay_outbound_item *data) spdylay_outbound_item *data,
uint8_t flags)
{ {
assert(stream->deferred_data == NULL); assert(stream->deferred_data == NULL);
stream->deferred_data = data; stream->deferred_data = data;
stream->deferred_flags = flags;
} }
void spdylay_stream_detach_deferred_data(spdylay_stream *stream) void spdylay_stream_detach_deferred_data(spdylay_stream *stream)
{ {
stream->deferred_data = NULL; stream->deferred_data = NULL;
stream->deferred_flags = SPDYLAY_DEFERRED_NONE;
} }

View File

@ -69,6 +69,12 @@ typedef enum {
SPDYLAY_SHUT_RDWR = SPDYLAY_SHUT_RD | SPDYLAY_SHUT_WR SPDYLAY_SHUT_RDWR = SPDYLAY_SHUT_RD | SPDYLAY_SHUT_WR
} spdylay_shut_flag; } spdylay_shut_flag;
typedef enum {
SPDYLAY_DEFERRED_NONE = 0,
/* Indicates the DATA is deferred due to flow control. */
SPDYLAY_DEFERRED_FLOW_CONTROL = 0x01
} spdylay_deferred_flag;
typedef struct { typedef struct {
int32_t stream_id; int32_t stream_id;
spdylay_stream_state state; spdylay_stream_state state;
@ -90,11 +96,27 @@ typedef struct {
void *stream_user_data; void *stream_user_data;
/* Deferred DATA frame */ /* Deferred DATA frame */
spdylay_outbound_item *deferred_data; spdylay_outbound_item *deferred_data;
/* The flags for defered DATA. Bitwise OR of zero or more
spdylay_deferred_flag values */
uint8_t deferred_flags;
/* Initial window size where window_size is compuated
against. Initially, window_size = initial_window_size. When N
bytes are sent, window_size -= N. After that, when the initial
window size is changed, say, new_initial_window_size, then
window_size becomes
new_initial_window_size-(initial_window_size-window_size) */
int32_t initial_window_size;
/* Current sender window size */
int32_t window_size;
/* Keep track of the number of bytes received without
WINDOW_UPDATE. */
int32_t recv_window_size;
} spdylay_stream; } spdylay_stream;
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id, void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id,
uint8_t flags, uint8_t pri, uint8_t flags, uint8_t pri,
spdylay_stream_state initial_state, spdylay_stream_state initial_state,
int32_t initial_window_size,
void *stream_user_data); void *stream_user_data);
void spdylay_stream_free(spdylay_stream *stream); void spdylay_stream_free(spdylay_stream *stream);
@ -120,10 +142,12 @@ int spdylay_stream_add_pushed_stream(spdylay_stream *stream, int32_t stream_id);
/* /*
* Defer DATA frame |data|. We won't call this function in the * Defer DATA frame |data|. We won't call this function in the
* situation where stream->deferred_data != NULL. * situation where stream->deferred_data != NULL. If |flags| is
* bitwise OR of zero or more spdylay_deferred_flag values.
*/ */
void spdylay_stream_defer_data(spdylay_stream *stream, void spdylay_stream_defer_data(spdylay_stream *stream,
spdylay_outbound_item *data); spdylay_outbound_item *data,
uint8_t flags);
/* /*
* Detaches deferred data from this stream. This function does not * Detaches deferred data from this stream. This function does not

View File

@ -42,7 +42,7 @@ static int spdylay_submit_syn_stream_shared
uint8_t flags_copy; uint8_t flags_copy;
spdylay_data_provider *data_prd_copy = NULL; spdylay_data_provider *data_prd_copy = NULL;
spdylay_syn_stream_aux_data *aux_data; spdylay_syn_stream_aux_data *aux_data;
if(pri > 3) { if(pri > spdylay_session_get_pri_lowest(session)) {
return SPDYLAY_ERR_INVALID_ARGUMENT; return SPDYLAY_ERR_INVALID_ARGUMENT;
} }
if(session->server == 0) { if(session->server == 0) {

View File

@ -99,6 +99,8 @@ int main(int argc, char* argv[])
test_spdylay_session_reply_fail) || test_spdylay_session_reply_fail) ||
!CU_add_test(pSuite, "session_on_headers_received", !CU_add_test(pSuite, "session_on_headers_received",
test_spdylay_session_on_headers_received) || test_spdylay_session_on_headers_received) ||
!CU_add_test(pSuite, "session_on_window_update_received",
test_spdylay_session_on_window_update_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", !CU_add_test(pSuite, "session_on_goaway_received",
@ -131,6 +133,8 @@ int main(int argc, char* argv[])
test_spdylay_session_recv_invalid_frame) || test_spdylay_session_recv_invalid_frame) ||
!CU_add_test(pSuite, "session_defer_data", !CU_add_test(pSuite, "session_defer_data",
test_spdylay_session_defer_data) || test_spdylay_session_defer_data) ||
!CU_add_test(pSuite, "session_flow_control",
test_spdylay_session_flow_control) ||
!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) ||

View File

@ -198,7 +198,8 @@ void test_spdylay_session_recv()
callbacks.recv_callback = scripted_recv_callback; callbacks.recv_callback = scripted_recv_callback;
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback; callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
user_data.df = &df; user_data.df = &df;
spdylay_session_server_new(&session, &callbacks, &user_data); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, SPDYLAY_CTRL_FLAG_NONE,
1, 0, 3, dup_nv(nv)); 1, 0, 3, dup_nv(nv));
@ -249,7 +250,8 @@ void test_spdylay_session_add_frame()
memset(aux_data, 0, sizeof(spdylay_syn_stream_aux_data)); memset(aux_data, 0, sizeof(spdylay_syn_stream_aux_data));
acc.length = 0; acc.length = 0;
user_data.acc = &acc; user_data.acc = &acc;
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, &user_data)); CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &user_data));
frame = malloc(sizeof(spdylay_frame)); frame = malloc(sizeof(spdylay_frame));
spdylay_frame_syn_stream_init(&frame->syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame->syn_stream, SPDYLAY_PROTO_SPDY2,
@ -294,7 +296,8 @@ void test_spdylay_session_recv_invalid_stream_id()
user_data.df = &df; user_data.df = &df;
user_data.invalid_ctrl_recv_cb_called = 0; user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, &callbacks, &user_data); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 1, 0, 3, dup_nv(nv)); SPDYLAY_CTRL_FLAG_NONE, 1, 0, 3, dup_nv(nv));
framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen, framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen,
@ -341,7 +344,8 @@ void test_spdylay_session_on_syn_stream_received()
user_data.ctrl_recv_cb_called = 0; user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0; user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_server_new(&session, &callbacks, &user_data); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, SPDYLAY_CTRL_FLAG_NONE,
stream_id, 0, pri, dup_nv(nv)); stream_id, 0, pri, dup_nv(nv));
@ -393,7 +397,8 @@ void test_spdylay_session_on_syn_stream_received_with_push()
user_data.ctrl_recv_cb_called = 0; user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0; user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, &callbacks, &user_data); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_session_open_stream(session, assoc_stream_id, SPDYLAY_CTRL_FLAG_NONE, spdylay_session_open_stream(session, assoc_stream_id, SPDYLAY_CTRL_FLAG_NONE,
pri, SPDYLAY_STREAM_OPENED, NULL); pri, SPDYLAY_STREAM_OPENED, NULL);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
@ -446,7 +451,8 @@ void test_spdylay_session_on_syn_reply_received()
user_data.ctrl_recv_cb_called = 0; user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0; user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, &callbacks, &user_data); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0, spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENING, NULL); SPDYLAY_STREAM_OPENING, NULL);
spdylay_frame_syn_reply_init(&frame.syn_reply, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_reply_init(&frame.syn_reply, SPDYLAY_PROTO_SPDY2,
@ -503,7 +509,7 @@ void test_spdylay_session_send_syn_stream()
malloc(sizeof(spdylay_syn_stream_aux_data)); malloc(sizeof(spdylay_syn_stream_aux_data));
memset(aux_data, 0, sizeof(spdylay_syn_stream_aux_data)); memset(aux_data, 0, sizeof(spdylay_syn_stream_aux_data));
spdylay_session_client_new(&session, &callbacks, NULL); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
spdylay_frame_syn_stream_init(&frame->syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame->syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 0, 0, 3, dup_nv(nv)); SPDYLAY_CTRL_FLAG_NONE, 0, 0, 3, dup_nv(nv));
spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame, aux_data); spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame, aux_data);
@ -527,7 +533,8 @@ void test_spdylay_session_send_syn_reply()
spdylay_frame *frame = malloc(sizeof(spdylay_frame)); spdylay_frame *frame = malloc(sizeof(spdylay_frame));
spdylay_stream *stream; spdylay_stream *stream;
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, NULL)); CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
spdylay_session_open_stream(session, 2, SPDYLAY_CTRL_FLAG_NONE, 3, spdylay_session_open_stream(session, 2, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL); SPDYLAY_STREAM_OPENING, NULL);
spdylay_frame_syn_reply_init(&frame->syn_reply, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_reply_init(&frame->syn_reply, SPDYLAY_PROTO_SPDY2,
@ -557,7 +564,8 @@ void test_spdylay_submit_response()
data_prd.read_callback = fixed_length_data_source_read_callback; data_prd.read_callback = fixed_length_data_source_read_callback;
ud.data_source_length = 64*1024; ud.data_source_length = 64*1024;
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, &ud)); CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
spdylay_session_open_stream(session, stream_id, SPDYLAY_CTRL_FLAG_NONE, 3, spdylay_session_open_stream(session, stream_id, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL); SPDYLAY_STREAM_OPENING, NULL);
CU_ASSERT(0 == spdylay_submit_response(session, stream_id, nv, &data_prd)); CU_ASSERT(0 == spdylay_submit_response(session, stream_id, nv, &data_prd));
@ -577,7 +585,8 @@ void test_spdylay_submit_response_with_null_data_read_callback()
memset(&callbacks, 0, sizeof(callbacks)); memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = null_send_callback; callbacks.send_callback = null_send_callback;
CU_ASSERT(0 == spdylay_session_server_new(&session, &callbacks, NULL)); CU_ASSERT(0 == spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_FIN, 3, spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_FIN, 3,
SPDYLAY_STREAM_OPENING, NULL); SPDYLAY_STREAM_OPENING, NULL);
CU_ASSERT(0 == spdylay_submit_response(session, 1, nv, &data_prd)); CU_ASSERT(0 == spdylay_submit_response(session, 1, nv, &data_prd));
@ -604,7 +613,8 @@ void test_spdylay_submit_request_with_data()
data_prd.read_callback = fixed_length_data_source_read_callback; data_prd.read_callback = fixed_length_data_source_read_callback;
ud.data_source_length = 64*1024; ud.data_source_length = 64*1024;
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, &ud)); CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_request(session, 3, nv, &data_prd, NULL)); CU_ASSERT(0 == spdylay_submit_request(session, 3, nv, &data_prd, NULL));
item = spdylay_session_get_next_ob_item(session); item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->syn_stream.nv[0])); CU_ASSERT(0 == strcmp("version", item->frame->syn_stream.nv[0]));
@ -627,7 +637,8 @@ void test_spdylay_submit_request_with_null_data_read_callback()
spdylay_data_provider data_prd = {{-1}, NULL}; spdylay_data_provider data_prd = {{-1}, NULL};
spdylay_outbound_item *item; spdylay_outbound_item *item;
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, NULL)); CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
CU_ASSERT(0 == spdylay_submit_request(session, 3, nv, &data_prd, NULL)); CU_ASSERT(0 == spdylay_submit_request(session, 3, nv, &data_prd, NULL));
item = spdylay_session_get_next_ob_item(session); item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->syn_stream.nv[0])); CU_ASSERT(0 == strcmp("version", item->frame->syn_stream.nv[0]));
@ -644,7 +655,8 @@ void test_spdylay_submit_syn_stream()
spdylay_outbound_item *item; spdylay_outbound_item *item;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks)); memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, NULL)); CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
CU_ASSERT(0 == spdylay_submit_syn_stream(session, SPDYLAY_CTRL_FLAG_FIN, 1, 3, CU_ASSERT(0 == spdylay_submit_syn_stream(session, SPDYLAY_CTRL_FLAG_FIN, 1, 3,
nv, NULL)); nv, NULL));
item = spdylay_session_get_next_ob_item(session); item = spdylay_session_get_next_ob_item(session);
@ -656,7 +668,8 @@ void test_spdylay_submit_syn_stream()
spdylay_session_del(session); spdylay_session_del(session);
CU_ASSERT(0 == spdylay_session_server_new(&session, &callbacks, NULL)); CU_ASSERT(0 == spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
CU_ASSERT(0 == spdylay_submit_syn_stream(session, SPDYLAY_CTRL_FLAG_FIN, 1, 3, CU_ASSERT(0 == spdylay_submit_syn_stream(session, SPDYLAY_CTRL_FLAG_FIN, 1, 3,
nv, NULL)); nv, NULL));
item = spdylay_session_get_next_ob_item(session); item = spdylay_session_get_next_ob_item(session);
@ -681,7 +694,8 @@ void test_spdylay_submit_headers()
callbacks.send_callback = null_send_callback; callbacks.send_callback = null_send_callback;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback; callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, &ud)); CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_headers(session, SPDYLAY_CTRL_FLAG_FIN, 1, nv)); CU_ASSERT(0 == spdylay_submit_headers(session, SPDYLAY_CTRL_FLAG_FIN, 1, nv));
item = spdylay_session_get_next_ob_item(session); item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->headers.nv[0])); CU_ASSERT(0 == strcmp("version", item->frame->headers.nv[0]));
@ -720,7 +734,8 @@ void test_spdylay_session_reply_fail()
data_prd.read_callback = fixed_length_data_source_read_callback; data_prd.read_callback = fixed_length_data_source_read_callback;
ud.data_source_length = 4*1024; ud.data_source_length = 4*1024;
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, &ud)); CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_response(session, stream_id, nv, &data_prd)); CU_ASSERT(0 == spdylay_submit_response(session, stream_id, nv, &data_prd));
CU_ASSERT(0 == spdylay_session_send(session)); CU_ASSERT(0 == spdylay_session_send(session));
spdylay_session_del(session); spdylay_session_del(session);
@ -740,7 +755,8 @@ void test_spdylay_session_on_headers_received()
user_data.ctrl_recv_cb_called = 0; user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0; user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, &callbacks, &user_data); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0, spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENED, NULL); SPDYLAY_STREAM_OPENED, NULL);
spdylay_stream_shutdown(spdylay_session_get_stream(session, 1), spdylay_stream_shutdown(spdylay_session_get_stream(session, 1),
@ -805,6 +821,44 @@ void test_spdylay_session_on_headers_received()
spdylay_session_del(session); spdylay_session_del(session);
} }
void test_spdylay_session_on_window_update_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
spdylay_frame frame;
spdylay_stream *stream;
spdylay_outbound_item *data_item;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks,
&user_data);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENED, NULL);
spdylay_frame_window_update_init(&frame.window_update, SPDYLAY_PROTO_SPDY3,
1, 16*1024);
CU_ASSERT(0 == spdylay_session_on_window_update_received(session, &frame));
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);
CU_ASSERT(64*1024+16*1024 == stream->window_size);
data_item = malloc(sizeof(spdylay_outbound_item));
memset(data_item, 0, sizeof(spdylay_outbound_item));
spdylay_stream_defer_data(stream, data_item, SPDYLAY_DEFERRED_FLOW_CONTROL);
CU_ASSERT(0 == spdylay_session_on_window_update_received(session, &frame));
CU_ASSERT(2 == user_data.ctrl_recv_cb_called);
CU_ASSERT(64*1024+16*1024*2 == stream->window_size);
CU_ASSERT(NULL == stream->deferred_data);
spdylay_frame_window_update_free(&frame.window_update);
spdylay_session_del(session);
}
void test_spdylay_session_on_ping_received() void test_spdylay_session_on_ping_received()
{ {
spdylay_session *session; spdylay_session *session;
@ -821,7 +875,8 @@ void test_spdylay_session_on_ping_received()
user_data.ctrl_recv_cb_called = 0; user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0; user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, &callbacks, &user_data); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
unique_id = 2; unique_id = 2;
spdylay_frame_ping_init(&frame.ping, SPDYLAY_PROTO_SPDY2, unique_id); spdylay_frame_ping_init(&frame.ping, SPDYLAY_PROTO_SPDY2, unique_id);
@ -856,7 +911,8 @@ void test_spdylay_session_on_goaway_received()
user_data.ctrl_recv_cb_called = 0; user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0; user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, &callbacks, &user_data); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_goaway_init(&frame.goaway, SPDYLAY_PROTO_SPDY2, stream_id); spdylay_frame_goaway_init(&frame.goaway, SPDYLAY_PROTO_SPDY2, stream_id);
CU_ASSERT(0 == spdylay_session_on_goaway_received(session, &frame)); CU_ASSERT(0 == spdylay_session_on_goaway_received(session, &frame));
@ -877,7 +933,8 @@ void test_spdylay_session_on_data_received()
int32_t stream_id = 2; int32_t stream_id = 2;
spdylay_stream *stream; spdylay_stream *stream;
spdylay_session_client_new(&session, &callbacks, &user_data); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
stream = spdylay_session_open_stream(session, stream_id, stream = spdylay_session_open_stream(session, stream_id,
SPDYLAY_CTRL_FLAG_NONE, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL); 3, SPDYLAY_STREAM_OPENING, NULL);
@ -920,7 +977,7 @@ void test_spdylay_session_is_my_stream_id()
spdylay_session *session; spdylay_session *session;
spdylay_session_callbacks callbacks; spdylay_session_callbacks callbacks;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks)); memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
spdylay_session_server_new(&session, &callbacks, NULL); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 0)); CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 0));
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 1)); CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 1));
@ -928,7 +985,7 @@ void test_spdylay_session_is_my_stream_id()
spdylay_session_del(session); spdylay_session_del(session);
spdylay_session_client_new(&session, &callbacks, NULL); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 0)); CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 0));
CU_ASSERT(1 == spdylay_session_is_my_stream_id(session, 1)); CU_ASSERT(1 == spdylay_session_is_my_stream_id(session, 1));
@ -945,7 +1002,8 @@ void test_spdylay_session_on_rst_received()
spdylay_stream *stream; spdylay_stream *stream;
spdylay_frame frame; spdylay_frame frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks)); memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
spdylay_session_server_new(&session, &callbacks, &user_data); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL); 3, SPDYLAY_STREAM_OPENING, NULL);
/* server push */ /* server push */
@ -978,7 +1036,8 @@ void test_spdylay_session_send_rst_stream()
spdylay_frame *frame; spdylay_frame *frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks)); memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback; callbacks.send_callback = null_send_callback;
spdylay_session_client_new(&session, &callbacks, &user_data); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL); 3, SPDYLAY_STREAM_OPENING, NULL);
/* server push */ /* server push */
@ -1010,7 +1069,7 @@ void test_spdylay_session_get_next_ob_item()
memset(&callbacks, 0, sizeof(spdylay_session_callbacks)); memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback; callbacks.send_callback = null_send_callback;
spdylay_session_server_new(&session, &callbacks, NULL); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
session->settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 2; session->settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 2;
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session)); CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
@ -1052,7 +1111,7 @@ void test_spdylay_session_pop_next_ob_item()
memset(&callbacks, 0, sizeof(spdylay_session_callbacks)); memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback; callbacks.send_callback = null_send_callback;
spdylay_session_server_new(&session, &callbacks, NULL); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
session->settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 1; session->settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 1;
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session)); CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
@ -1106,7 +1165,8 @@ void test_spdylay_session_on_request_recv_callback()
callbacks.on_request_recv_callback = on_request_recv_callback; callbacks.on_request_recv_callback = on_request_recv_callback;
user_data.stream_id = 0; user_data.stream_id = 0;
spdylay_session_server_new(&session, &callbacks, &user_data); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 1, 0, 3, dup_nv(nv)); SPDYLAY_CTRL_FLAG_NONE, 1, 0, 3, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame)); CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
@ -1174,7 +1234,8 @@ void test_spdylay_session_on_stream_close()
callbacks.on_stream_close_callback = stream_close_callback; callbacks.on_stream_close_callback = stream_close_callback;
user_data.stream_close_cb_called = 0; user_data.stream_close_cb_called = 0;
CU_ASSERT(spdylay_session_client_new(&session, &callbacks, &user_data) == 0); CU_ASSERT(spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &user_data) == 0);
stream = spdylay_session_open_stream(session, stream_id, stream = spdylay_session_open_stream(session, stream_id,
SPDYLAY_CTRL_FLAG_NONE, SPDYLAY_CTRL_FLAG_NONE,
pri, SPDYLAY_STREAM_OPENED, &user_data); pri, SPDYLAY_STREAM_OPENED, &user_data);
@ -1193,7 +1254,7 @@ void test_spdylay_session_max_concurrent_streams()
spdylay_outbound_item *item; spdylay_outbound_item *item;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks)); memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
spdylay_session_server_new(&session, &callbacks, NULL); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3, spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENED, NULL); SPDYLAY_STREAM_OPENED, NULL);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
@ -1244,7 +1305,7 @@ void test_spdylay_session_data_backoff_by_high_pri_frame()
ud.ctrl_send_cb_called = 0; ud.ctrl_send_cb_called = 0;
ud.data_source_length = 16*1024; ud.data_source_length = 16*1024;
spdylay_session_client_new(&session, &callbacks, &ud); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, &ud);
spdylay_submit_request(session, 3, nv, &data_prd, NULL); spdylay_submit_request(session, 3, nv, &data_prd, NULL);
ud.block_count = 2; ud.block_count = 2;
@ -1289,7 +1350,7 @@ void test_spdylay_session_stop_data_with_rst_stream()
ud.ctrl_send_cb_called = 0; ud.ctrl_send_cb_called = 0;
ud.data_source_length = 16*1024; ud.data_source_length = 16*1024;
spdylay_session_server_new(&session, &callbacks, &ud); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, &ud);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3, spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL); SPDYLAY_STREAM_OPENING, NULL);
spdylay_submit_response(session, 1, nv, &data_prd); spdylay_submit_response(session, 1, nv, &data_prd);
@ -1336,7 +1397,7 @@ void test_spdylay_session_stream_close_on_syn_stream()
no_stream_user_data_stream_close_callback; no_stream_user_data_stream_close_callback;
ud.stream_close_cb_called = 0; ud.stream_close_cb_called = 0;
spdylay_session_client_new(&session, &callbacks, &ud); spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, &ud);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3, spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL); SPDYLAY_STREAM_OPENING, NULL);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
@ -1371,7 +1432,8 @@ void test_spdylay_session_recv_invalid_frame()
user_data.df = &df; user_data.df = &df;
user_data.ctrl_send_cb_called = 0; user_data.ctrl_send_cb_called = 0;
spdylay_session_server_new(&session, &callbacks, &user_data); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2, spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 1, 0, 3, dup_nv(nv)); SPDYLAY_CTRL_FLAG_NONE, 1, 0, 3, dup_nv(nv));
framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen, framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen,
@ -1424,7 +1486,7 @@ void test_spdylay_session_defer_data()
ud.ctrl_send_cb_called = 0; ud.ctrl_send_cb_called = 0;
ud.data_source_length = 16*1024; ud.data_source_length = 16*1024;
spdylay_session_server_new(&session, &callbacks, &ud); spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, &ud);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3, spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL); SPDYLAY_STREAM_OPENING, NULL);
spdylay_submit_response(session, 1, nv, &data_prd); spdylay_submit_response(session, 1, nv, &data_prd);
@ -1473,3 +1535,47 @@ void test_spdylay_session_defer_data()
spdylay_session_del(session); spdylay_session_del(session);
} }
void test_spdylay_session_flow_control()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { NULL };
my_user_data ud;
spdylay_data_provider data_prd;
spdylay_frame frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
data_prd.read_callback = fixed_length_data_source_read_callback;
ud.ctrl_send_cb_called = 0;
ud.data_source_length = 128*1024;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks, &ud);
spdylay_submit_request(session, 3, nv, &data_prd, NULL);
/* Sends 64KiB data */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(64*1024 == ud.data_source_length);
spdylay_frame_window_update_init(&frame.window_update, SPDYLAY_PROTO_SPDY3,
1, 32*1024);
spdylay_session_on_window_update_received(session, &frame);
/* Sends another 32KiB data */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(32*1024 == ud.data_source_length);
spdylay_session_on_window_update_received(session, &frame);
/* Sends another 32KiB data */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == ud.data_source_length);
CU_ASSERT(spdylay_session_get_stream(session, 1)->shut_flags &
SPDYLAY_SHUT_WR);
spdylay_frame_window_update_free(&frame.window_update);
spdylay_session_del(session);
}

View File

@ -31,6 +31,7 @@ void test_spdylay_session_add_frame();
void test_spdylay_session_on_syn_stream_received(); void test_spdylay_session_on_syn_stream_received();
void test_spdylay_session_on_syn_stream_received_with_push(); void test_spdylay_session_on_syn_stream_received_with_push();
void test_spdylay_session_on_syn_reply_received(); void test_spdylay_session_on_syn_reply_received();
void test_spdylay_session_on_window_update_received();
void test_spdylay_session_send_syn_stream(); void test_spdylay_session_send_syn_stream();
void test_spdylay_session_send_syn_reply(); void test_spdylay_session_send_syn_reply();
void test_spdylay_submit_response(); void test_spdylay_submit_response();
@ -57,5 +58,6 @@ void test_spdylay_session_stop_data_with_rst_stream();
void test_spdylay_session_stream_close_on_syn_stream(); void test_spdylay_session_stream_close_on_syn_stream();
void test_spdylay_session_recv_invalid_frame(); void test_spdylay_session_recv_invalid_frame();
void test_spdylay_session_defer_data(); void test_spdylay_session_defer_data();
void test_spdylay_session_flow_control();
#endif // SPDYLAY_SESSION_TEST_H #endif // SPDYLAY_SESSION_TEST_H

View File

@ -32,7 +32,7 @@ void test_spdylay_stream_add_pushed_stream()
{ {
spdylay_stream stream; spdylay_stream stream;
int i, n; int i, n;
spdylay_stream_init(&stream, 1, SPDYLAY_CTRL_FLAG_NONE, 3, spdylay_stream_init(&stream, 1, SPDYLAY_CTRL_FLAG_NONE, 3, 65536,
SPDYLAY_STREAM_OPENING, NULL); SPDYLAY_STREAM_OPENING, NULL);
n = 26; n = 26;
for(i = 2; i < n; i += 2) { for(i = 2; i < n; i += 2) {