Implement SPDY WINDOW_UPDATE and SETTINGS.

This commit is contained in:
Joris Vink 2013-07-01 11:30:18 +02:00
parent 6fa881e224
commit 51a9e4db9d
6 changed files with 128 additions and 10 deletions

View File

@ -74,6 +74,7 @@ struct listener {
#define CONN_READ_POSSIBLE 0x01 #define CONN_READ_POSSIBLE 0x01
#define CONN_WRITE_POSSIBLE 0x02 #define CONN_WRITE_POSSIBLE 0x02
#define CONN_WRITE_BLOCK 0x04
struct connection { struct connection {
int fd; int fd;
@ -88,6 +89,7 @@ struct connection {
z_stream z_inflate; z_stream z_inflate;
u_int8_t deflate_started; u_int8_t deflate_started;
z_stream z_deflate; z_stream z_deflate;
u_int32_t wsize_initial;
TAILQ_HEAD(, netbuf) send_queue; TAILQ_HEAD(, netbuf) send_queue;
TAILQ_HEAD(, netbuf) recv_queue; TAILQ_HEAD(, netbuf) recv_queue;
@ -260,6 +262,7 @@ void kore_buf_appendb(struct kore_buf *, struct kore_buf *);
struct spdy_header_block *spdy_header_block_create(int); struct spdy_header_block *spdy_header_block_create(int);
struct spdy_stream *spdy_stream_lookup(struct connection *, u_int32_t); struct spdy_stream *spdy_stream_lookup(struct connection *, u_int32_t);
int spdy_frame_data_done(struct netbuf *);
int spdy_stream_get_header(struct spdy_header_block *, int spdy_stream_get_header(struct spdy_header_block *,
char *, char **); char *, char **);

View File

@ -49,6 +49,7 @@ struct spdy_stream {
u_int32_t stream_id; u_int32_t stream_id;
u_int8_t flags; u_int8_t flags;
u_int8_t prio; u_int8_t prio;
int32_t wsize;
void *httpreq; void *httpreq;
struct spdy_header_block *hblock; struct spdy_header_block *hblock;
@ -65,6 +66,7 @@ extern const unsigned char SPDY_dictionary_txt[];
#define SPDY_SYNFRAME_SIZE 10 #define SPDY_SYNFRAME_SIZE 10
#define SPDY_ZLIB_DICT_SIZE 1423 #define SPDY_ZLIB_DICT_SIZE 1423
#define SPDY_ZLIB_CHUNK 16348 #define SPDY_ZLIB_CHUNK 16348
#define SPDY_INIT_WSIZE 65536
/* control frames */ /* control frames */
#define SPDY_CTRL_FRAME_SYN_STREAM 1 #define SPDY_CTRL_FRAME_SYN_STREAM 1
@ -77,6 +79,17 @@ extern const unsigned char SPDY_dictionary_txt[];
/* flags */ /* flags */
#define FLAG_FIN 0x01 #define FLAG_FIN 0x01
#define FLAG_UNIDIRECTIONAL 0x02 #define FLAG_UNIDIRECTIONAL 0x02
#define SPDY_STREAM_WILLCLOSE 0x04
/* settings */
#define SETTINGS_UPLOAD_BANDWIDTH 1
#define SETTINGS_DOWNLOAD_BANDWIDTH 2
#define SETTINGS_ROUND_TRIP_TIME 3
#define SETTINGS_MAX_CONCURRENT_STREAMS 4
#define SETTINGS_CURRENT_CWND 5
#define SETTINGS_DOWNLOAD_RETRANS_RATE 6
#define SETTINGS_INITIAL_WINDOW_SIZE 7
#define SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE 8
#define SPDY_HBLOCK_NORMAL 0 #define SPDY_HBLOCK_NORMAL 0
#define SPDY_HBLOCK_DELAYED_ALLOC 1 #define SPDY_HBLOCK_DELAYED_ALLOC 1

View File

@ -76,6 +76,7 @@ kore_connection_accept(struct listener *l, struct connection **out)
c->client_stream_id = 0; c->client_stream_id = 0;
c->proto = CONN_PROTO_UNKNOWN; c->proto = CONN_PROTO_UNKNOWN;
c->state = CONN_STATE_SSL_SHAKE; c->state = CONN_STATE_SSL_SHAKE;
c->wsize_initial = SPDY_INIT_WSIZE;
TAILQ_INIT(&(c->send_queue)); TAILQ_INIT(&(c->send_queue));
TAILQ_INIT(&(c->recv_queue)); TAILQ_INIT(&(c->recv_queue));

View File

@ -213,6 +213,7 @@ http_request_free(struct http_request *req)
int int
http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len) http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len)
{ {
struct netbuf *nb;
u_int32_t hlen; u_int32_t hlen;
struct http_header *hdr; struct http_header *hdr;
struct kore_buf *buf; struct kore_buf *buf;
@ -245,7 +246,9 @@ http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len)
if (len > 0) { if (len > 0) {
spdy_frame_send(req->owner, SPDY_DATA_FRAME, spdy_frame_send(req->owner, SPDY_DATA_FRAME,
0, len, req->stream, 0); 0, len, req->stream, 0);
net_send_queue(req->owner, d, len, 0, NULL, NULL); net_send_queue(req->owner, d, len, 0, &nb,
spdy_frame_data_done);
nb->extra = req->stream;
} }
spdy_frame_send(req->owner, SPDY_DATA_FRAME, spdy_frame_send(req->owner, SPDY_DATA_FRAME,

View File

@ -126,7 +126,8 @@ kore_platform_event_wait(void)
c = (struct connection *)events[i].data.ptr; c = (struct connection *)events[i].data.ptr;
if (events[i].events & EPOLLIN) if (events[i].events & EPOLLIN)
c->flags |= CONN_READ_POSSIBLE; c->flags |= CONN_READ_POSSIBLE;
if (events[i].events & EPOLLOUT) if (events[i].events & EPOLLOUT &&
!(c->flags & CONN_WRITE_BLOCK))
c->flags |= CONN_WRITE_POSSIBLE; c->flags |= CONN_WRITE_POSSIBLE;
if (!kore_connection_handle(c)) if (!kore_connection_handle(c))

View File

@ -43,6 +43,9 @@ static int spdy_ctrl_frame_settings(struct netbuf *);
static int spdy_ctrl_frame_ping(struct netbuf *); static int spdy_ctrl_frame_ping(struct netbuf *);
static int spdy_ctrl_frame_window(struct netbuf *); static int spdy_ctrl_frame_window(struct netbuf *);
static int spdy_data_frame_recv(struct netbuf *); static int spdy_data_frame_recv(struct netbuf *);
static int spdy_frame_send_done(struct netbuf *);
static void spdy_update_wsize(struct connection *,
struct spdy_stream *, u_int32_t);
static void spdy_stream_close(struct connection *, static void spdy_stream_close(struct connection *,
struct spdy_stream *); struct spdy_stream *);
@ -134,8 +137,9 @@ void
spdy_frame_send(struct connection *c, u_int16_t type, u_int8_t flags, spdy_frame_send(struct connection *c, u_int16_t type, u_int8_t flags,
u_int32_t len, struct spdy_stream *s, u_int32_t misc) u_int32_t len, struct spdy_stream *s, u_int32_t misc)
{ {
u_int8_t nb[12]; struct netbuf *nnb;
u_int32_t length; u_int8_t nb[12];
u_int32_t length;
kore_debug("spdy_frame_send(%p, %d, %d, %d, %p, %d)", kore_debug("spdy_frame_send(%p, %d, %d, %d, %p, %d)",
c, type, flags, len, s, misc); c, type, flags, len, s, misc);
@ -170,10 +174,17 @@ spdy_frame_send(struct connection *c, u_int16_t type, u_int8_t flags,
break; break;
} }
net_send_queue(c, nb, length, 0, NULL, NULL); if (s != NULL && type == SPDY_DATA_FRAME) {
net_send_queue(c, nb, length, 0, &nnb, spdy_frame_send_done);
nnb->extra = s;
} else {
net_send_queue(c, nb, length, 0, NULL, NULL);
}
if ((flags & FLAG_FIN) && (s->flags & FLAG_FIN)) if (s != NULL) {
spdy_stream_close(c, s); if ((flags & FLAG_FIN) && (s->flags & FLAG_FIN))
s->flags |= SPDY_STREAM_WILLCLOSE;
}
} }
struct spdy_stream * struct spdy_stream *
@ -313,6 +324,16 @@ spdy_stream_get_header(struct spdy_header_block *s, char *header, char **out)
return (KORE_RESULT_ERROR); return (KORE_RESULT_ERROR);
} }
int
spdy_frame_data_done(struct netbuf *nb)
{
struct connection *c = (struct connection *)nb->owner;
struct spdy_stream *s = (struct spdy_stream *)nb->extra;
spdy_update_wsize(c, s, nb->len);
return (KORE_RESULT_OK);
}
static int static int
spdy_ctrl_frame_syn_stream(struct netbuf *nb) spdy_ctrl_frame_syn_stream(struct netbuf *nb)
{ {
@ -359,6 +380,7 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb)
s = (struct spdy_stream *)kore_malloc(sizeof(*s)); s = (struct spdy_stream *)kore_malloc(sizeof(*s));
s->prio = syn.prio; s->prio = syn.prio;
s->flags = ctrl.flags; s->flags = ctrl.flags;
s->wsize = c->wsize_initial;
s->stream_id = syn.stream_id; s->stream_id = syn.stream_id;
s->hblock = spdy_header_block_create(SPDY_HBLOCK_DELAYED_ALLOC); s->hblock = spdy_header_block_create(SPDY_HBLOCK_DELAYED_ALLOC);
@ -415,7 +437,8 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb)
c->client_stream_id = s->stream_id; c->client_stream_id = s->stream_id;
TAILQ_INSERT_TAIL(&(c->spdy_streams), s, list); TAILQ_INSERT_TAIL(&(c->spdy_streams), s, list);
kore_debug("SPDY_SYN_STREAM: %d:%d:%d", s->stream_id, s->flags, s->prio); kore_debug("SPDY_SYN_STREAM: %d:%d:%d", s->stream_id,
s->flags, s->prio);
return (KORE_RESULT_OK); return (KORE_RESULT_OK);
} }
@ -423,7 +446,31 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb)
static int static int
spdy_ctrl_frame_settings(struct netbuf *nb) spdy_ctrl_frame_settings(struct netbuf *nb)
{ {
kore_debug("SPDY_SETTINGS (to be implemented)"); u_int8_t *buf, flags;
u_int32_t ecount, i, id, val;
struct connection *c = (struct connection *)nb->owner;
ecount = net_read32(nb->buf + SPDY_FRAME_SIZE);
kore_debug("SPDY_SETTINGS: %d settings present", ecount);
buf = nb->buf + SPDY_FRAME_SIZE + 4;
for (i = 0; i < ecount; i++) {
flags = *(u_int8_t *)buf;
id = net_read32(buf) & 0xffffff;
val = net_read32(buf + 4);
switch (id) {
case SETTINGS_INITIAL_WINDOW_SIZE:
c->wsize_initial = val;
break;
default:
kore_debug("no handling for setting %d:%d (%d)",
id, val, flags);
break;
}
buf += 8;
}
return (KORE_RESULT_OK); return (KORE_RESULT_OK);
} }
@ -450,12 +497,34 @@ spdy_ctrl_frame_ping(struct netbuf *nb)
static int static int
spdy_ctrl_frame_window(struct netbuf *nb) spdy_ctrl_frame_window(struct netbuf *nb)
{ {
u_int32_t stream_id, window_size; struct spdy_stream *s;
u_int32_t stream_id, window_size;
struct connection *c = (struct connection *)nb->owner;
stream_id = net_read32(nb->buf + SPDY_FRAME_SIZE); stream_id = net_read32(nb->buf + SPDY_FRAME_SIZE);
window_size = net_read32(nb->buf + SPDY_FRAME_SIZE + 4); window_size = net_read32(nb->buf + SPDY_FRAME_SIZE + 4);
if ((s = spdy_stream_lookup(c, stream_id)) == NULL) {
kore_debug("received WINDOW_UPDATE for nonexistant stream");
kore_debug("stream_id: %d", stream_id);
return (KORE_RESULT_ERROR);
}
if (s->flags & SPDY_STREAM_WILLCLOSE) {
kore_debug("received WINDOW_UPDATE for FIN stream");
return (KORE_RESULT_ERROR);
}
kore_debug("SPDY_WINDOW_UPDATE: %d:%d", stream_id, window_size); kore_debug("SPDY_WINDOW_UPDATE: %d:%d", stream_id, window_size);
s->wsize += window_size;
if (s->wsize > 0) {
c->flags &= ~CONN_WRITE_BLOCK;
c->flags |= CONN_WRITE_POSSIBLE;
kore_debug("can now send again (%d wsize)", s->wsize);
return (net_send_flush(c));
}
return (KORE_RESULT_OK); return (KORE_RESULT_OK);
} }
@ -512,6 +581,34 @@ spdy_stream_close(struct connection *c, struct spdy_stream *s)
kore_mem_free(s); kore_mem_free(s);
} }
static int
spdy_frame_send_done(struct netbuf *nb)
{
u_int8_t flags;
struct connection *c = (struct connection *)nb->owner;
struct spdy_stream *s = (struct spdy_stream *)nb->extra;
flags = *(u_int8_t *)(nb->buf + 4);
if ((flags & FLAG_FIN) && (s->flags & FLAG_FIN))
spdy_stream_close(c, s);
return (KORE_RESULT_OK);
}
static void
spdy_update_wsize(struct connection *c, struct spdy_stream *s, u_int32_t len)
{
s->wsize -= len;
kore_debug("spdy_update_wsize(): stream %d, window size %d",
s->stream_id, s->wsize);
if (s->wsize <= 0) {
kore_debug("window size <= 0 for stream %d", s->stream_id);
c->flags &= ~CONN_WRITE_POSSIBLE;
c->flags |= CONN_WRITE_BLOCK;
}
}
static int static int
spdy_zlib_inflate(struct connection *c, u_int8_t *src, size_t len, spdy_zlib_inflate(struct connection *c, u_int8_t *src, size_t len,
u_int8_t **dst, u_int32_t *olen) u_int8_t **dst, u_int32_t *olen)