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, ...@@ -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()
......
...@@ -51,7 +51,7 @@ bool ssl_debug = false; ...@@ -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[] = { ...@@ -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) ...@@ -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;
......
...@@ -127,8 +127,8 @@ typedef enum { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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);
......
This diff is collapsed.
...@@ -62,6 +62,8 @@ typedef struct { ...@@ -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 { ...@@ -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); ...@@ -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, ...@@ -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 ...@@ -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 */
...@@ -29,6 +29,7 @@ ...@@ -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, ...@@ -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) ...@@ -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;
} }
...@@ -69,6 +69,12 @@ typedef enum { ...@@ -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 { ...@@ -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); ...@@ -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
......
...@@ -42,7 +42,7 @@ static int spdylay_submit_syn_stream_shared ...@@ -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) {
......
...@@ -99,6 +99,8 @@ int main(int argc, char* argv[]) ...@@ -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[]) ...@@ -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) ||
......
This diff is collapsed.
...@@ -31,6 +31,7 @@ void test_spdylay_session_add_frame(); ...@@ -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(); ...@@ -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
...@@ -32,7 +32,7 @@ void test_spdylay_stream_add_pushed_stream() ...@@ -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) {
......
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