2013-04-28 19:11:44 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2013 Joris Vink <joris@coders.se>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/queue.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include <openssl/ssl.h>
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2013-04-29 23:35:36 +02:00
|
|
|
#include <zlib.h>
|
2013-04-28 19:11:44 +02:00
|
|
|
|
|
|
|
#include "spdy.h"
|
|
|
|
#include "kore.h"
|
2013-05-01 00:35:33 +02:00
|
|
|
#include "http.h"
|
2013-04-28 23:42:13 +02:00
|
|
|
|
2013-04-28 19:11:44 +02:00
|
|
|
static int spdy_ctrl_frame_syn_stream(struct netbuf *);
|
|
|
|
static int spdy_ctrl_frame_settings(struct netbuf *);
|
2013-05-01 12:23:21 +02:00
|
|
|
static int spdy_ctrl_frame_ping(struct netbuf *);
|
2013-05-01 00:35:33 +02:00
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
static int spdy_zlib_inflate(struct connection *, u_int8_t *,
|
|
|
|
size_t, u_int8_t **, u_int32_t *);
|
|
|
|
static int spdy_zlib_deflate(struct connection *, u_int8_t *,
|
|
|
|
size_t, u_int8_t **, u_int32_t *);
|
2013-04-28 19:11:44 +02:00
|
|
|
|
|
|
|
int
|
|
|
|
spdy_frame_recv(struct netbuf *nb)
|
|
|
|
{
|
2013-05-01 00:35:33 +02:00
|
|
|
struct spdy_ctrl_frame ctrl;
|
2013-04-28 23:42:13 +02:00
|
|
|
int (*cb)(struct netbuf *), r;
|
2013-04-28 19:11:44 +02:00
|
|
|
struct connection *c = (struct connection *)nb->owner;
|
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
kore_log("spdy_frame_recv(%p)", nb);
|
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
if (SPDY_CONTROL_FRAME(net_read32(nb->buf))) {
|
2013-04-28 19:11:44 +02:00
|
|
|
kore_log("received control frame");
|
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
ctrl.version = net_read16(nb->buf) & 0x7fff;
|
|
|
|
ctrl.type = net_read16(nb->buf + 2);
|
|
|
|
ctrl.flags = *(u_int8_t *)(nb->buf + 4);
|
|
|
|
ctrl.length = net_read32(nb->buf + 4) & 0xffffff;
|
|
|
|
|
|
|
|
kore_log("type is %d", ctrl.type);
|
|
|
|
kore_log("version is %d", ctrl.version);
|
|
|
|
kore_log("length is %d", ctrl.length);
|
|
|
|
kore_log("flags are %d", ctrl.flags);
|
2013-04-28 19:11:44 +02:00
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
if (ctrl.version != 3) {
|
|
|
|
kore_log("protocol mismatch (recv version %d)",
|
|
|
|
ctrl.version);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
switch (ctrl.type) {
|
2013-04-28 19:11:44 +02:00
|
|
|
case SPDY_CTRL_FRAME_SYN_STREAM:
|
|
|
|
cb = spdy_ctrl_frame_syn_stream;
|
|
|
|
break;
|
|
|
|
case SPDY_CTRL_FRAME_SETTINGS:
|
|
|
|
cb = spdy_ctrl_frame_settings;
|
|
|
|
break;
|
2013-05-01 12:23:21 +02:00
|
|
|
case SPDY_CTRL_FRAME_PING:
|
|
|
|
cb = spdy_ctrl_frame_ping;
|
|
|
|
break;
|
2013-04-28 19:11:44 +02:00
|
|
|
default:
|
|
|
|
cb = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cb != NULL) {
|
2013-05-01 00:35:33 +02:00
|
|
|
r = net_recv_expand(c, nb, ctrl.length, cb);
|
2013-04-28 19:11:44 +02:00
|
|
|
} else {
|
2013-05-01 00:35:33 +02:00
|
|
|
kore_log("no callback for type %d", ctrl.type);
|
2013-05-02 05:32:56 +02:00
|
|
|
r = KORE_RESULT_OK;
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
|
|
|
} else {
|
2013-05-01 12:23:21 +02:00
|
|
|
r = KORE_RESULT_ERROR;
|
|
|
|
kore_log("received data frame, can't handle that yet.");
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
|
|
|
|
2013-05-02 00:28:49 +02:00
|
|
|
if (r == KORE_RESULT_OK) {
|
|
|
|
r = net_recv_queue(c, SPDY_FRAME_SIZE,
|
|
|
|
0, NULL, spdy_frame_recv);
|
|
|
|
}
|
2013-05-01 12:23:21 +02:00
|
|
|
|
2013-04-28 23:42:13 +02:00
|
|
|
return (r);
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
|
|
|
|
2013-05-01 08:09:04 +02:00
|
|
|
int
|
|
|
|
spdy_frame_send(struct connection *c, u_int16_t type, u_int8_t flags,
|
2013-05-01 12:23:21 +02:00
|
|
|
u_int32_t len, u_int32_t stream_id)
|
2013-05-01 08:09:04 +02:00
|
|
|
{
|
|
|
|
u_int8_t nb[12];
|
|
|
|
u_int32_t length;
|
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
kore_log("spdy_frame_send(%p, %d, %d, %d, %d)", c, type, flags,
|
|
|
|
len, stream_id);
|
2013-05-01 08:09:04 +02:00
|
|
|
|
|
|
|
length = 0;
|
|
|
|
memset(nb, 0, sizeof(nb));
|
|
|
|
switch (type) {
|
2013-05-01 12:23:21 +02:00
|
|
|
case SPDY_CTRL_FRAME_PING:
|
2013-05-01 08:09:04 +02:00
|
|
|
case SPDY_CTRL_FRAME_SYN_REPLY:
|
|
|
|
net_write16(&nb[0], 3);
|
|
|
|
nb[0] |= (1 << 7);
|
|
|
|
net_write16(&nb[2], type);
|
2013-05-01 12:23:21 +02:00
|
|
|
|
|
|
|
if (type != SPDY_CTRL_FRAME_PING)
|
|
|
|
net_write32(&nb[4], len + 4);
|
|
|
|
else
|
|
|
|
net_write32(&nb[4], len);
|
|
|
|
|
2013-05-01 08:09:04 +02:00
|
|
|
nb[4] = flags;
|
|
|
|
net_write32(&nb[8], stream_id);
|
|
|
|
length = 12;
|
|
|
|
break;
|
|
|
|
case SPDY_DATA_FRAME:
|
2013-05-01 12:23:21 +02:00
|
|
|
net_write32(&nb[0], stream_id);
|
|
|
|
nb[0] &= ~(1 << 7);
|
|
|
|
net_write32(&nb[4], len);
|
|
|
|
nb[4] = flags;
|
|
|
|
length = 8;
|
2013-05-01 08:09:04 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-05-02 00:28:49 +02:00
|
|
|
return (net_send_queue(c, nb, length, 0, NULL, NULL));
|
2013-05-01 08:09:04 +02:00
|
|
|
}
|
|
|
|
|
2013-04-29 23:35:36 +02:00
|
|
|
struct spdy_stream *
|
|
|
|
spdy_stream_lookup(struct connection *c, u_int32_t id)
|
|
|
|
{
|
|
|
|
struct spdy_stream *s;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(s, &(c->spdy_streams), list) {
|
|
|
|
if (s->stream_id == id)
|
|
|
|
return (s);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2013-05-01 08:09:04 +02:00
|
|
|
struct spdy_header_block *
|
|
|
|
spdy_header_block_create(int delayed_alloc)
|
|
|
|
{
|
|
|
|
struct spdy_header_block *hblock;
|
|
|
|
|
|
|
|
kore_log("spdy_header_block_create()");
|
|
|
|
|
|
|
|
hblock = (struct spdy_header_block *)kore_malloc(sizeof(*hblock));
|
|
|
|
if (delayed_alloc == SPDY_HBLOCK_NORMAL) {
|
|
|
|
hblock->header_block = (u_int8_t *)kore_malloc(128);
|
|
|
|
hblock->header_block_len = 128;
|
2013-05-01 12:23:21 +02:00
|
|
|
hblock->header_offset = 4;
|
2013-05-01 08:09:04 +02:00
|
|
|
} else {
|
|
|
|
hblock->header_block = NULL;
|
|
|
|
hblock->header_block_len = 0;
|
2013-05-01 12:23:21 +02:00
|
|
|
hblock->header_offset = 0;
|
2013-05-01 08:09:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
hblock->header_pairs = 0;
|
|
|
|
|
|
|
|
return (hblock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
spdy_header_block_add(struct spdy_header_block *hblock, char *name, char *value)
|
|
|
|
{
|
|
|
|
u_int8_t *p;
|
|
|
|
u_int32_t nlen, vlen;
|
|
|
|
|
|
|
|
kore_log("spdy_header_block_add(%p, %s, %s)", hblock, name, value);
|
|
|
|
|
|
|
|
nlen = strlen(name);
|
|
|
|
vlen = strlen(value);
|
|
|
|
if ((nlen + vlen + hblock->header_offset) > hblock->header_block_len) {
|
|
|
|
hblock->header_block_len += nlen + vlen + 128;
|
|
|
|
hblock->header_block =
|
|
|
|
(u_int8_t *)kore_realloc(hblock->header_block,
|
|
|
|
hblock->header_block_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
p = hblock->header_block + hblock->header_offset;
|
|
|
|
net_write32(p, nlen);
|
|
|
|
memcpy((p + 4), (u_int8_t *)name, nlen);
|
|
|
|
hblock->header_offset += 4 + nlen;
|
|
|
|
|
|
|
|
p = hblock->header_block + hblock->header_offset;
|
|
|
|
net_write32(p, vlen);
|
|
|
|
memcpy((p + 4), (u_int8_t *)value, vlen);
|
|
|
|
hblock->header_offset += 4 + vlen;
|
|
|
|
|
|
|
|
hblock->header_pairs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int8_t *
|
2013-05-01 12:23:21 +02:00
|
|
|
spdy_header_block_release(struct connection *c,
|
|
|
|
struct spdy_header_block *hblock, u_int32_t *len)
|
2013-05-01 08:09:04 +02:00
|
|
|
{
|
|
|
|
u_int8_t *deflated;
|
|
|
|
|
|
|
|
kore_log("spdy_header_block_release(%p, %p)", hblock, len);
|
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
net_write32(hblock->header_block, hblock->header_pairs);
|
|
|
|
if (!spdy_zlib_deflate(c, hblock->header_block, hblock->header_offset,
|
2013-05-01 08:09:04 +02:00
|
|
|
&deflated, len)) {
|
|
|
|
free(hblock->header_block);
|
|
|
|
free(hblock);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(hblock->header_block);
|
|
|
|
free(hblock);
|
|
|
|
|
|
|
|
return (deflated);
|
|
|
|
}
|
|
|
|
|
2013-05-01 21:16:09 +02:00
|
|
|
int
|
|
|
|
spdy_stream_get_header(struct spdy_header_block *s, char *header, char **out)
|
|
|
|
{
|
2013-05-02 00:28:49 +02:00
|
|
|
char *cmp;
|
2013-05-01 21:16:09 +02:00
|
|
|
u_int8_t *p, *end;
|
|
|
|
u_int32_t i, nlen, vlen;
|
|
|
|
|
|
|
|
kore_log("spdy_stream_get_header(%p, %s) <%d>", s, header,
|
|
|
|
s->header_pairs);
|
|
|
|
|
|
|
|
p = s->header_block + 4;
|
|
|
|
end = s->header_block + s->header_block_len;
|
|
|
|
|
|
|
|
if (p >= end) {
|
|
|
|
kore_log("p >= end when looking for headers");
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < s->header_pairs; i++) {
|
|
|
|
nlen = net_read32(p);
|
|
|
|
if ((p + nlen + 4) > end) {
|
|
|
|
kore_log("nlen out of bounds on %d (%d)", i, nlen);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
vlen = net_read32(p + nlen + 4);
|
|
|
|
if ((p + nlen + vlen + 8) > end) {
|
|
|
|
kore_log("vlen out of bounds on %d (%d)", i, vlen);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
cmp = (char *)(p + 4);
|
|
|
|
if (!strncasecmp(cmp, header, nlen)) {
|
|
|
|
kore_log("found %s header", header);
|
|
|
|
|
|
|
|
cmp = (char *)(p + nlen + 8);
|
|
|
|
*out = (char *)kore_malloc(vlen + 1);
|
|
|
|
kore_strlcpy(*out, cmp, vlen + 1);
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
kore_log("pair name %d bytes, value %d bytes", nlen, vlen);
|
|
|
|
|
|
|
|
p += nlen + vlen + 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2013-04-28 19:11:44 +02:00
|
|
|
static int
|
|
|
|
spdy_ctrl_frame_syn_stream(struct netbuf *nb)
|
|
|
|
{
|
2013-04-29 23:35:36 +02:00
|
|
|
struct spdy_stream *s;
|
2013-05-01 00:35:33 +02:00
|
|
|
struct spdy_syn_stream syn;
|
|
|
|
struct spdy_ctrl_frame ctrl;
|
|
|
|
u_int8_t *src;
|
|
|
|
char *host, *method, *path;
|
2013-04-29 23:35:36 +02:00
|
|
|
struct connection *c = (struct connection *)nb->owner;
|
2013-04-28 23:42:13 +02:00
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
ctrl.version = net_read16(nb->buf) & 0x7fff;
|
|
|
|
ctrl.type = net_read16(nb->buf + 2);
|
|
|
|
ctrl.flags = *(u_int8_t *)(nb->buf + 4);
|
|
|
|
ctrl.length = net_read32(nb->buf + 4) & 0xffffff;
|
2013-04-28 23:42:13 +02:00
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
syn.stream_id = net_read32(nb->buf + 8);
|
|
|
|
syn.assoc_stream_id = net_read32(nb->buf + 12);
|
|
|
|
syn.prio = net_read16(nb->buf + 16) & 0xe000;
|
|
|
|
syn.slot = net_read16(nb->buf + 16) & 0x7;
|
2013-04-28 23:42:13 +02:00
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
kore_log("spdy_ctrl_frame_syn_stream()");
|
|
|
|
kore_log("stream_id: %d", syn.stream_id);
|
|
|
|
kore_log("length : %d", ctrl.length);
|
|
|
|
|
2013-05-01 08:09:04 +02:00
|
|
|
/* XXX need to send protocol error. */
|
2013-05-01 00:35:33 +02:00
|
|
|
if ((syn.stream_id % 2) == 0 || syn.stream_id == 0) {
|
2013-04-29 23:35:36 +02:00
|
|
|
kore_log("client sent incorrect id for SPDY_SYN_STREAM (%d)",
|
2013-05-01 00:35:33 +02:00
|
|
|
syn.stream_id);
|
2013-04-29 23:35:36 +02:00
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2013-05-01 08:09:04 +02:00
|
|
|
/* XXX need to send protocol error. */
|
|
|
|
if (syn.stream_id < c->client_stream_id) {
|
|
|
|
kore_log("client sent incorrect id SPDY_SYN_STREAM (%d < %d)",
|
|
|
|
syn.stream_id, c->client_stream_id);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
if ((s = spdy_stream_lookup(c, syn.stream_id)) != NULL) {
|
|
|
|
kore_log("duplicate SPDY_SYN_STREAM (%d)", syn.stream_id);
|
2013-04-29 23:35:36 +02:00
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
s = (struct spdy_stream *)kore_malloc(sizeof(*s));
|
|
|
|
s->prio = syn.prio;
|
|
|
|
s->flags = ctrl.flags;
|
|
|
|
s->stream_id = syn.stream_id;
|
2013-05-01 08:09:04 +02:00
|
|
|
s->hblock = spdy_header_block_create(SPDY_HBLOCK_DELAYED_ALLOC);
|
2013-05-01 00:35:33 +02:00
|
|
|
|
|
|
|
src = (nb->buf + SPDY_FRAME_SIZE + SPDY_SYNFRAME_SIZE);
|
|
|
|
kore_log("compressed headers are %d bytes long", ctrl.length - 10);
|
2013-05-01 12:23:21 +02:00
|
|
|
if (!spdy_zlib_inflate(c, src, (ctrl.length - SPDY_SYNFRAME_SIZE),
|
2013-05-01 08:09:04 +02:00
|
|
|
&(s->hblock->header_block), &(s->hblock->header_block_len))) {
|
|
|
|
free(s->hblock->header_block);
|
|
|
|
free(s->hblock);
|
2013-05-01 00:35:33 +02:00
|
|
|
free(s);
|
2013-04-29 23:35:36 +02:00
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2013-05-01 08:09:04 +02:00
|
|
|
s->hblock->header_pairs = net_read32(s->hblock->header_block);
|
|
|
|
kore_log("got %d headers", s->hblock->header_pairs);
|
2013-04-29 23:35:36 +02:00
|
|
|
|
2013-05-01 01:23:46 +02:00
|
|
|
path = NULL;
|
|
|
|
host = NULL;
|
|
|
|
method = NULL;
|
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
#define GET_HEADER(n, r) \
|
2013-05-01 08:09:04 +02:00
|
|
|
if (!spdy_stream_get_header(s->hblock, n, r)) { \
|
|
|
|
free(s->hblock->header_block); \
|
|
|
|
free(s->hblock); \
|
2013-05-01 00:35:33 +02:00
|
|
|
free(s); \
|
|
|
|
kore_log("no such header: %s", n); \
|
2013-05-01 01:23:46 +02:00
|
|
|
if (path != NULL) \
|
|
|
|
free(path); \
|
|
|
|
if (host != NULL) \
|
|
|
|
free(host); \
|
|
|
|
if (method != NULL) \
|
|
|
|
free(method); \
|
2013-05-01 00:35:33 +02:00
|
|
|
return (KORE_RESULT_ERROR); \
|
|
|
|
}
|
2013-04-29 23:35:36 +02:00
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
GET_HEADER(":path", &path);
|
|
|
|
GET_HEADER(":method", &method);
|
|
|
|
GET_HEADER(":host", &host);
|
2013-05-02 03:51:04 +02:00
|
|
|
if (!http_request_new(c, s, host, method, path, NULL)) {
|
2013-05-01 08:09:04 +02:00
|
|
|
free(s->hblock->header_block);
|
|
|
|
free(s->hblock);
|
2013-05-01 00:35:33 +02:00
|
|
|
free(s);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
2013-04-29 23:35:36 +02:00
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
free(path);
|
|
|
|
free(method);
|
|
|
|
free(host);
|
2013-04-29 23:35:36 +02:00
|
|
|
|
2013-05-01 08:09:04 +02:00
|
|
|
c->client_stream_id = s->stream_id;
|
2013-04-29 23:35:36 +02:00
|
|
|
TAILQ_INSERT_TAIL(&(c->spdy_streams), s, list);
|
|
|
|
kore_log("SPDY_SYN_STREAM: %d:%d:%d", s->stream_id, s->flags, s->prio);
|
2013-05-01 00:35:33 +02:00
|
|
|
|
2013-04-28 19:11:44 +02:00
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
spdy_ctrl_frame_settings(struct netbuf *nb)
|
|
|
|
{
|
2013-05-01 12:23:21 +02:00
|
|
|
kore_log("SPDY_SETTINGS (to be implemented)");
|
|
|
|
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
spdy_ctrl_frame_ping(struct netbuf *nb)
|
|
|
|
{
|
|
|
|
u_int32_t id;
|
2013-04-28 19:11:44 +02:00
|
|
|
struct connection *c = (struct connection *)nb->owner;
|
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
id = ntohl(*(u_int32_t *)(nb->buf + SPDY_FRAME_SIZE));
|
|
|
|
kore_log("SPDY_PING: %d", id);
|
2013-04-28 19:11:44 +02:00
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
/* XXX todo - check if we sent the ping. */
|
|
|
|
if ((id % 2) == 0) {
|
|
|
|
kore_log("received malformed client PING (%d)", id);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (spdy_frame_send(c, SPDY_CTRL_FRAME_PING, 0, 4, id));
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
2013-05-01 00:35:33 +02:00
|
|
|
|
|
|
|
static int
|
2013-05-01 12:23:21 +02:00
|
|
|
spdy_zlib_inflate(struct connection *c, u_int8_t *src, size_t len,
|
|
|
|
u_int8_t **dst, u_int32_t *olen)
|
2013-05-01 00:35:33 +02:00
|
|
|
{
|
|
|
|
size_t have;
|
|
|
|
int r, ret;
|
|
|
|
u_char inflate_buffer[SPDY_ZLIB_CHUNK];
|
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
kore_log("spdy_zlib_inflate(%p, %p, %d)", c, src, len);
|
2013-05-01 00:35:33 +02:00
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
if (c->inflate_started == 0) {
|
|
|
|
c->z_inflate.avail_in = 0;
|
|
|
|
c->z_inflate.next_in = Z_NULL;
|
|
|
|
c->z_inflate.zalloc = Z_NULL;
|
|
|
|
c->z_inflate.zfree = Z_NULL;
|
|
|
|
if ((r = inflateInit(&(c->z_inflate))) != Z_OK) {
|
|
|
|
kore_log("inflateInit() failed: %d", r);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
c->inflate_started = 1;
|
2013-05-01 00:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
*olen = 0;
|
|
|
|
*dst = NULL;
|
|
|
|
|
|
|
|
ret = -1;
|
2013-05-01 12:23:21 +02:00
|
|
|
c->z_inflate.avail_in = len;
|
|
|
|
c->z_inflate.next_in = src;
|
2013-05-01 00:35:33 +02:00
|
|
|
while (ret == -1) {
|
2013-05-01 12:23:21 +02:00
|
|
|
c->z_inflate.avail_out = SPDY_ZLIB_CHUNK;
|
|
|
|
c->z_inflate.next_out = inflate_buffer;
|
2013-05-01 00:35:33 +02:00
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
r = inflate(&(c->z_inflate), Z_SYNC_FLUSH);
|
2013-05-01 00:35:33 +02:00
|
|
|
switch (r) {
|
|
|
|
case Z_NEED_DICT:
|
2013-05-01 12:23:21 +02:00
|
|
|
r = inflateSetDictionary(&(c->z_inflate),
|
|
|
|
SPDY_dictionary_txt, SPDY_ZLIB_DICT_SIZE);
|
2013-05-01 00:35:33 +02:00
|
|
|
if (r != Z_OK) {
|
2013-05-01 12:23:21 +02:00
|
|
|
inflateEnd(&(c->z_inflate));
|
2013-05-01 00:35:33 +02:00
|
|
|
kore_log("inflateSetDictionary(): %d", r);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
case Z_BUF_ERROR:
|
|
|
|
case Z_DATA_ERROR:
|
|
|
|
case Z_MEM_ERROR:
|
|
|
|
ret = KORE_RESULT_ERROR;
|
|
|
|
kore_log("inflate(): %d", r);
|
|
|
|
break;
|
|
|
|
case Z_OK:
|
2013-05-01 12:23:21 +02:00
|
|
|
have = SPDY_ZLIB_CHUNK - c->z_inflate.avail_out;
|
2013-05-01 00:35:33 +02:00
|
|
|
*olen += have;
|
|
|
|
*dst = (u_int8_t *)kore_realloc(*dst, *olen);
|
|
|
|
memcpy((*dst) + (*olen - have), inflate_buffer, have);
|
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
if (c->z_inflate.avail_in != 0 ||
|
|
|
|
c->z_inflate.avail_out == 0)
|
2013-05-01 00:35:33 +02:00
|
|
|
break;
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case Z_STREAM_END:
|
|
|
|
ret = KORE_RESULT_OK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2013-05-01 12:23:21 +02:00
|
|
|
spdy_zlib_deflate(struct connection *c, u_int8_t *src, size_t len,
|
|
|
|
u_int8_t **dst, u_int32_t *olen)
|
2013-05-01 00:35:33 +02:00
|
|
|
{
|
|
|
|
size_t have;
|
|
|
|
int r, ret;
|
|
|
|
u_char deflate_buffer[SPDY_ZLIB_CHUNK];
|
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
kore_log("spdy_zlib_deflate(%p, %p, %d)", c, src, len);
|
2013-05-01 00:35:33 +02:00
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
if (c->deflate_started == 0) {
|
|
|
|
c->z_deflate.avail_in = 0;
|
|
|
|
c->z_deflate.next_in = Z_NULL;
|
|
|
|
c->z_deflate.zalloc = Z_NULL;
|
|
|
|
c->z_deflate.zfree = Z_NULL;
|
|
|
|
if ((r = deflateInit(&(c->z_deflate), -1)) != Z_OK) {
|
|
|
|
kore_log("deflateInit() failed: %d", r);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
2013-05-01 00:35:33 +02:00
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
r = deflateSetDictionary(&(c->z_deflate), SPDY_dictionary_txt,
|
|
|
|
SPDY_ZLIB_DICT_SIZE);
|
|
|
|
if (r != Z_OK) {
|
|
|
|
deflateEnd(&(c->z_deflate));
|
|
|
|
kore_log("delfateSetDictionary(): %d", r);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
c->deflate_started = 1;
|
2013-05-01 00:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
*olen = 0;
|
|
|
|
*dst = NULL;
|
|
|
|
|
|
|
|
ret = -1;
|
2013-05-01 12:23:21 +02:00
|
|
|
c->z_deflate.avail_in = len;
|
|
|
|
c->z_deflate.next_in = src;
|
2013-05-01 00:35:33 +02:00
|
|
|
while (ret == -1) {
|
2013-05-01 12:23:21 +02:00
|
|
|
c->z_deflate.avail_out = SPDY_ZLIB_CHUNK;
|
|
|
|
c->z_deflate.next_out = deflate_buffer;
|
2013-05-01 00:35:33 +02:00
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
r = deflate(&(c->z_deflate), Z_SYNC_FLUSH);
|
2013-05-01 00:35:33 +02:00
|
|
|
switch (r) {
|
|
|
|
case Z_BUF_ERROR:
|
|
|
|
case Z_DATA_ERROR:
|
|
|
|
case Z_MEM_ERROR:
|
|
|
|
ret = KORE_RESULT_ERROR;
|
|
|
|
kore_log("deflate(): %d", r);
|
|
|
|
break;
|
|
|
|
case Z_OK:
|
2013-05-01 12:23:21 +02:00
|
|
|
have = SPDY_ZLIB_CHUNK - c->z_deflate.avail_out;
|
2013-05-01 00:35:33 +02:00
|
|
|
*olen += have;
|
|
|
|
*dst = (u_int8_t *)kore_realloc(*dst, *olen);
|
|
|
|
memcpy((*dst) + (*olen - have), deflate_buffer, have);
|
|
|
|
|
2013-05-01 12:23:21 +02:00
|
|
|
if (c->z_deflate.avail_in == 0 &&
|
|
|
|
c->z_deflate.avail_out != 0)
|
2013-05-01 00:35:33 +02:00
|
|
|
ret = KORE_RESULT_OK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|