Commit 86938743 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

Added SPDY/3 flow control.

parent 4e62c75b
......@@ -173,7 +173,7 @@ SpdyEventHandler::SpdyEventHandler(const Config* config,
: EventHandler(config),
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()
......
......@@ -51,7 +51,7 @@ bool ssl_debug = false;
Spdylay::Spdylay(int fd, SSL *ssl, const spdylay_session_callbacks *callbacks)
: 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()
......@@ -286,7 +286,8 @@ const char *ctrl_names[] = {
"NOOP",
"PING",
"GOAWAY",
"HEADERS"
"HEADERS",
"WINDOW_UPDATE"
};
} // namespace
......@@ -367,6 +368,12 @@ void print_frame(spdylay_frame_type type, spdylay_frame *frame)
printf("(stream_id=%d)\n", frame->headers.stream_id);
print_nv(frame->headers.nv);
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:
printf("\n");
break;
......
......@@ -127,8 +127,8 @@ typedef enum {
SPDYLAY_FLOW_CONTROL_ERROR = 7
} spdylay_status_code;
#define SPDYLAY_SPDY2_LOWEST_PRI 3
#define SPDYLAY_SPDY3_LOWEST_PRI 7
#define SPDYLAY_SPDY2_PRI_LOWEST 3
#define SPDYLAY_SPDY3_PRI_LOWEST 7
typedef struct {
uint16_t version;
......@@ -141,8 +141,8 @@ typedef struct {
spdylay_ctrl_hd hd;
int32_t stream_id;
int32_t assoc_stream_id;
/* 0 (Highest) to SPDYLAY_SPDY2_LOWEST_PRI or
SPDYLAY_SPDY3_LOWEST_PRI (loweset), depending on the protocol
/* 0 (Highest) to SPDYLAY_SPDY2_PRI_LOWEST or
SPDYLAY_SPDY3_PRI_LOWEST (loweset), depending on the protocol
version. */
uint8_t pri;
/* Since SPDY/3 */
......@@ -372,10 +372,11 @@ typedef struct {
} spdylay_session_callbacks;
/*
* Initializes |*session_ptr| for client use. The all members of
* |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr|
* does not store |callbacks|. |user_data| is an arbitrary user
* supplied data, which will be passed to the callback functions.
* Initializes |*session_ptr| for client use, using the protocol
* version |version|. The all members of |callbacks| are copied to
* |*session_ptr|. Therefore |*session_ptr| does not store
* |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
* negative error codes:
......@@ -388,14 +389,16 @@ typedef struct {
* The version is not supported.
*/
int spdylay_session_client_new(spdylay_session **session_ptr,
uint16_t version,
const spdylay_session_callbacks *callbacks,
void *user_data);
/*
* Initializes |*session_ptr| for server use. The all members of
* |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr|
* does not store |callbacks|. |user_data| is an arbitrary user
* supplied data, which will be passed to the callback functions.
* Initializes |*session_ptr| for server use, using the protocol
* version |version|. The all members of |callbacks| are copied to
* |*session_ptr|. Therefore |*session_ptr| does not store
* |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
* negative error codes:
......@@ -408,6 +411,7 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
* The version is not supported.
*/
int spdylay_session_server_new(spdylay_session **session_ptr,
uint16_t version,
const spdylay_session_callbacks *callbacks,
void *user_data);
......
This diff is collapsed.
......@@ -62,6 +62,8 @@ typedef struct {
SPDYLAY_INITIAL_OUTBOUND_FRAMEBUF_LENGTH
#define SPDYLAY_INITIAL_NV_BUFFER_LENGTH 4096
#define SPDYLAY_INITIAL_WINDOW_SIZE 65536
typedef struct {
uint8_t buf[SPDYLAY_INBOUND_BUFFER_LENGTH];
uint8_t *mark;
......@@ -149,6 +151,10 @@ struct spdylay_session {
/* This is the value in GOAWAY frame sent by remote endpoint. */
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
unused. */
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,
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|,
* 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,
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.
*
......@@ -437,4 +472,9 @@ spdylay_outbound_item* spdylay_session_pop_next_ob_item
spdylay_outbound_item* spdylay_session_get_next_ob_item
(spdylay_session *session);
/*
* Returns lowest priority value.
*/
uint8_t spdylay_session_get_pri_lowest(spdylay_session *session);
#endif /* SPDYLAY_SESSION_H */
......@@ -29,6 +29,7 @@
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id,
uint8_t flags, uint8_t pri,
spdylay_stream_state initial_state,
int32_t initial_window_size,
void *stream_user_data)
{
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->stream_user_data = stream_user_data;
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)
......@@ -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,
spdylay_outbound_item *data)
spdylay_outbound_item *data,
uint8_t flags)
{
assert(stream->deferred_data == NULL);
stream->deferred_data = data;
stream->deferred_flags = flags;
}
void spdylay_stream_detach_deferred_data(spdylay_stream *stream)
{
stream->deferred_data = NULL;
stream->deferred_flags = SPDYLAY_DEFERRED_NONE;
}
......@@ -69,6 +69,12 @@ typedef enum {
SPDYLAY_SHUT_RDWR = SPDYLAY_SHUT_RD | SPDYLAY_SHUT_WR
} 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 {
int32_t stream_id;
spdylay_stream_state state;
......@@ -90,11 +96,27 @@ typedef struct {
void *stream_user_data;
/* Deferred DATA frame */
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;
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id,
uint8_t flags, uint8_t pri,
spdylay_stream_state initial_state,
int32_t initial_window_size,
void *stream_user_data);
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
* 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,
spdylay_outbound_item *data);
spdylay_outbound_item *data,
uint8_t flags);
/*
* Detaches deferred data from this stream. This function does not
......
......@@ -42,7 +42,7 @@ static int spdylay_submit_syn_stream_shared
uint8_t flags_copy;
spdylay_data_provider *data_prd_copy = NULL;
spdylay_syn_stream_aux_data *aux_data;
if(pri > 3) {
if(pri > spdylay_session_get_pri_lowest(session)) {
return SPDYLAY_ERR_INVALID_ARGUMENT;
}
if(session->server == 0) {
......
......@@ -99,6 +99,8 @@ int main(int argc, char* argv[])
test_spdylay_session_reply_fail) ||
!CU_add_test(pSuite, "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",
test_spdylay_session_on_ping_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) ||
!CU_add_test(pSuite, "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_count_nv_space",
test_spdylay_frame_count_nv_space) ||
......
This diff is collapsed.
......@@ -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_with_push();
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_reply();
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_recv_invalid_frame();
void test_spdylay_session_defer_data();
void test_spdylay_session_flow_control();
#endif // SPDYLAY_SESSION_TEST_H
......@@ -32,7 +32,7 @@ void test_spdylay_stream_add_pushed_stream()
{
spdylay_stream stream;
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);
n = 26;
for(i = 2; i < n; i += 2) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment