Added header deflate/inflate using zlib. Added send/recv frame.
This commit is contained in:
parent
1330d74b73
commit
9c8270436f
|
@ -40,8 +40,13 @@ AM_PROG_LIBTOOL
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
AC_PROG_LN_S
|
AC_PROG_LN_S
|
||||||
AC_PROG_MAKE_SET
|
AC_PROG_MAKE_SET
|
||||||
|
PKG_PROG_PKG_CONFIG([0.20])
|
||||||
|
|
||||||
# Checks for libraries.
|
# Checks for libraries.
|
||||||
|
PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.3])
|
||||||
|
LIBS=$ZLIB_LIBS $LIBS
|
||||||
|
CFLAGS=$CFLAGS $ZLIB_CFLAGS
|
||||||
|
|
||||||
AC_CHECK_LIB([cunit], [CU_initialize_registry],
|
AC_CHECK_LIB([cunit], [CU_initialize_registry],
|
||||||
[have_cunit=yes], [have_cunit=no])
|
[have_cunit=yes], [have_cunit=no])
|
||||||
AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ])
|
AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ])
|
||||||
|
|
|
@ -32,10 +32,12 @@ DISTCLEANFILES = $(pkgconfig_DATA)
|
||||||
lib_LTLIBRARIES = libspdylay.la
|
lib_LTLIBRARIES = libspdylay.la
|
||||||
|
|
||||||
OBJECTS = spdylay_pq.c spdylay_map.c spdylay_queue.c \
|
OBJECTS = spdylay_pq.c spdylay_map.c spdylay_queue.c \
|
||||||
spdylay_buffer.c
|
spdylay_buffer.c spdylay_frame.c spdylay_zlib.c \
|
||||||
|
spdylay_session.c spdylay_helper.c spdylay_stream.c
|
||||||
|
|
||||||
HFILES = spdylay_pq.h spdylay_int.h spdylay_map.h spdylay_queue.h \
|
HFILES = spdylay_pq.h spdylay_int.h spdylay_map.h spdylay_queue.h \
|
||||||
spdylay_buffer.h
|
spdylay_buffer.h spdylay_frame.h spdylay_zlib.h \
|
||||||
|
spdylay_session.h spdylay_helper.h spdylay_stream.h spdylay_int.h
|
||||||
|
|
||||||
libspdylay_la_SOURCES = $(HFILES) $(OBJECTS)
|
libspdylay_la_SOURCES = $(HFILES) $(OBJECTS)
|
||||||
libspdylay_la_LDFLAGS = -no-undefined \
|
libspdylay_la_LDFLAGS = -no-undefined \
|
||||||
|
|
|
@ -32,10 +32,49 @@ extern "C" {
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
enum spdylay_error {
|
typedef enum {
|
||||||
SPDYLAY_ERR_NOMEM = -500,
|
SPDYLAY_ERR_NOMEM = -500,
|
||||||
SPDYLAY_ERR_INVALID_ARGUMENT = -501
|
SPDYLAY_ERR_INVALID_ARGUMENT = -501,
|
||||||
};
|
SPDYLAY_ERR_ZLIB = -502,
|
||||||
|
SPDYLAY_ERR_ZLIB_BUF = -503,
|
||||||
|
SPDYLAY_ERR_WOULDBLOCK = -504,
|
||||||
|
SPDYLAY_ERR_PROTO = -505,
|
||||||
|
SPDYLAY_ERR_CALLBACK_FAILURE = -505,
|
||||||
|
} spdylay_error;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPDYLAY_MSG_MORE
|
||||||
|
} spdylay_io_flag;
|
||||||
|
|
||||||
|
typedef ssize_t (*spdylay_send_callback)
|
||||||
|
(const uint8_t *data, size_t length, int flags, void *user_data);
|
||||||
|
|
||||||
|
typedef ssize_t (*spdylay_recv_callback)
|
||||||
|
(uint8_t *buf, size_t length, int flags, void *user_data);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_send_callback send_callback;
|
||||||
|
spdylay_recv_callback recv_callback;
|
||||||
|
} spdylay_session_callbacks;
|
||||||
|
|
||||||
|
struct spdylay_session;
|
||||||
|
typedef struct spdylay_session spdylay_session;
|
||||||
|
|
||||||
|
int spdylay_session_client_init(spdylay_session **session_ptr,
|
||||||
|
const spdylay_session_callbacks *callbacks,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
void spdylay_session_free(struct spdylay_session *session);
|
||||||
|
|
||||||
|
int spdylay_session_send(spdylay_session *session);
|
||||||
|
|
||||||
|
int spdylay_session_recv(spdylay_session *session);
|
||||||
|
|
||||||
|
int spdylay_session_want_read(spdylay_session *session);
|
||||||
|
|
||||||
|
int spdylay_session_want_write(spdylay_session *session);
|
||||||
|
|
||||||
|
int spdylay_req_submit(spdylay_session *session, const char *path);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,3 +122,18 @@ void spdylay_buffer_pop(spdylay_buffer *buffer)
|
||||||
spdylay_queue_pop(&buffer->q);
|
spdylay_queue_pop(&buffer->q);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t spdylay_buffer_capacity(spdylay_buffer *buffer)
|
||||||
|
{
|
||||||
|
return buffer->capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_buffer_serialize(spdylay_buffer *buffer, uint8_t *buf)
|
||||||
|
{
|
||||||
|
while(spdylay_buffer_length(buffer)) {
|
||||||
|
size_t len = spdylay_buffer_front_length(buffer);
|
||||||
|
memcpy(buf, spdylay_buffer_front_data(buffer), len);
|
||||||
|
buf += len;
|
||||||
|
spdylay_buffer_pop(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -75,4 +75,11 @@ uint8_t* spdylay_buffer_front_data(spdylay_buffer *buffer);
|
||||||
size of poped chunk buffer. */
|
size of poped chunk buffer. */
|
||||||
void spdylay_buffer_pop(spdylay_buffer *buffer);
|
void spdylay_buffer_pop(spdylay_buffer *buffer);
|
||||||
|
|
||||||
|
/* Returns capacity of each fixed chunk buffer */
|
||||||
|
size_t spdylay_buffer_capacity(spdylay_buffer *buffer);
|
||||||
|
|
||||||
|
/* Stores the contents of buffer into buf. buf must be at least
|
||||||
|
spdylay_buffer_length(buffer) bytes long. */
|
||||||
|
void spdylay_buffer_serialize(spdylay_buffer *buffer, uint8_t *buf);
|
||||||
|
|
||||||
#endif /* SPDYLAY_BUFFER_H */
|
#endif /* SPDYLAY_BUFFER_H */
|
||||||
|
|
|
@ -0,0 +1,395 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_frame.h"
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "spdylay_helper.h"
|
||||||
|
|
||||||
|
static uint8_t spdylay_unpack_pri(const uint8_t *data)
|
||||||
|
{
|
||||||
|
return (data[0] >> 6) & 0x3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t* spdylay_pack_str(uint8_t *buf, const char *str, size_t len)
|
||||||
|
{
|
||||||
|
spdylay_put_uint16be(buf, len);
|
||||||
|
buf += 2;
|
||||||
|
memcpy(buf, str, len);
|
||||||
|
return buf+len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spdylay_frame_pack_ctrl_hd(uint8_t* buf, const spdylay_ctrl_hd *hd)
|
||||||
|
{
|
||||||
|
spdylay_put_uint16be(&buf[0], hd->version);
|
||||||
|
buf[0] |= 1 << 7;
|
||||||
|
spdylay_put_uint16be(&buf[2], hd->type);
|
||||||
|
spdylay_put_uint32be(&buf[4], hd->length);
|
||||||
|
printf("hd->length=%d\n", hd->length);
|
||||||
|
buf[4] = hd->flags;
|
||||||
|
printf("hd->flags=%d\n", hd->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spdylay_frame_unpack_ctrl_hd(spdylay_ctrl_hd *hd,
|
||||||
|
const uint8_t* buf)
|
||||||
|
{
|
||||||
|
hd->version = spdylay_get_uint16(buf) & 0x7fff;
|
||||||
|
hd->type = spdylay_get_uint16(buf+2);
|
||||||
|
hd->flags = buf[4];
|
||||||
|
hd->length = spdylay_get_uint32(buf+5) & 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
|
||||||
|
char **nv, size_t nv_offset,
|
||||||
|
spdylay_zlib *deflater)
|
||||||
|
{
|
||||||
|
size_t nvbuflen = spdylay_frame_count_nv_space(nv);
|
||||||
|
uint8_t *nvbuf = malloc(nvbuflen);
|
||||||
|
size_t maxframelen = nv_offset+
|
||||||
|
spdylay_zlib_deflate_hd_bound(deflater, nvbuflen);
|
||||||
|
uint8_t *framebuf = malloc(maxframelen);
|
||||||
|
ssize_t framelen;
|
||||||
|
spdylay_frame_pack_nv(nvbuf, nv);
|
||||||
|
framelen = spdylay_zlib_deflate_hd(deflater, framebuf+18, maxframelen-18,
|
||||||
|
nvbuf, nvbuflen);
|
||||||
|
free(nvbuf);
|
||||||
|
if(framelen < 0) {
|
||||||
|
free(framebuf);
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
framelen += 18;
|
||||||
|
*buf_ptr = framebuf;
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
uint16_t n;
|
||||||
|
size_t off;
|
||||||
|
size_t nv_max = 126;
|
||||||
|
int i, j, k;
|
||||||
|
char *name = NULL, *val = NULL;
|
||||||
|
if(inlen < 2) {
|
||||||
|
return SPDYLAY_ERR_PROTO;
|
||||||
|
}
|
||||||
|
memcpy(&n, in, sizeof(uint16_t));
|
||||||
|
n = ntohs(n);
|
||||||
|
if(n > nv_max) {
|
||||||
|
nv_max = n;
|
||||||
|
}
|
||||||
|
*nv_ptr = malloc(nv_max*sizeof(char*)+1);
|
||||||
|
if(*nv_ptr == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
off = 2;
|
||||||
|
for(i = 0, j = 0; i < n; ++i) {
|
||||||
|
uint16_t nlen, vlen;
|
||||||
|
size_t last, len;
|
||||||
|
if(off+2 > inlen) {
|
||||||
|
r = SPDYLAY_ERR_PROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* For NULL delimited values, they are splitted with each name */
|
||||||
|
memcpy(&nlen, &in[off], sizeof(uint16_t));
|
||||||
|
nlen = ntohs(nlen);
|
||||||
|
off += 2;
|
||||||
|
if(off+nlen > inlen || nlen == 0) {
|
||||||
|
r = SPDYLAY_ERR_PROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
name = malloc(nlen+1);
|
||||||
|
if(name == NULL) {
|
||||||
|
r = SPDYLAY_ERR_NOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(name, &in[off], nlen);
|
||||||
|
name[nlen] = '\0';
|
||||||
|
off += nlen;
|
||||||
|
if(off+2 > inlen) {
|
||||||
|
r = SPDYLAY_ERR_PROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(&vlen, &in[off], sizeof(uint16_t));
|
||||||
|
vlen = ntohs(vlen);
|
||||||
|
off += 2;
|
||||||
|
if(off+vlen > inlen) {
|
||||||
|
r = SPDYLAY_ERR_PROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for(k = 0, last = off; k < vlen; ++k) {
|
||||||
|
size_t len;
|
||||||
|
if(in[off+k] == '\0') {
|
||||||
|
len = off+k-last;
|
||||||
|
if(len == 0) {
|
||||||
|
r = SPDYLAY_ERR_PROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
val = malloc(len+1);
|
||||||
|
if(val == NULL) {
|
||||||
|
r = SPDYLAY_ERR_NOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(val, &in[last], len);
|
||||||
|
val[len] = '\0';
|
||||||
|
if(j >= nv_max) {
|
||||||
|
char **nnv;
|
||||||
|
nv_max *= 2;
|
||||||
|
nnv = realloc(*nv_ptr, nv_max+1);
|
||||||
|
if(nnv == NULL) {
|
||||||
|
r = SPDYLAY_ERR_NOMEM;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
*nv_ptr = nnv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*nv_ptr)[j] = strdup(name);
|
||||||
|
(*nv_ptr)[j+1] = val;
|
||||||
|
val = NULL;
|
||||||
|
last = off+k+1;
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(r != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = vlen-(last-off);
|
||||||
|
if(len == 0) {
|
||||||
|
r = SPDYLAY_ERR_PROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
val = malloc(len+1);
|
||||||
|
if(val == NULL) {
|
||||||
|
free(name);
|
||||||
|
r = SPDYLAY_ERR_NOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(val, &in[last], len);
|
||||||
|
val[len] = '\0';
|
||||||
|
if(j >= nv_max) {
|
||||||
|
char **nnv;
|
||||||
|
nv_max *= 2;
|
||||||
|
nnv = realloc(*nv_ptr, nv_max+1);
|
||||||
|
if(nnv == NULL) {
|
||||||
|
r = SPDYLAY_ERR_NOMEM;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
*nv_ptr = nnv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*nv_ptr)[j] = name;
|
||||||
|
(*nv_ptr)[j+1] = val;
|
||||||
|
name = val = NULL;
|
||||||
|
j += 2;
|
||||||
|
off += vlen;
|
||||||
|
}
|
||||||
|
free(name);
|
||||||
|
free(val);
|
||||||
|
if(r == 0) {
|
||||||
|
(*nv_ptr)[j] = NULL;
|
||||||
|
} else {
|
||||||
|
for(i = 0; i < j; ++i) {
|
||||||
|
free((*nv_ptr)[i]);
|
||||||
|
}
|
||||||
|
free(*nv_ptr);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spdylay_frame_alloc_unpack_nv(char ***nv_ptr,
|
||||||
|
const uint8_t *in, size_t inlen,
|
||||||
|
spdylay_zlib *inflater)
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
spdylay_buffer outbuffer;
|
||||||
|
spdylay_buffer_init(&outbuffer, 4096);
|
||||||
|
r = spdylay_zlib_inflate_hd(inflater, &outbuffer, in, inlen);
|
||||||
|
if(r < 0) {
|
||||||
|
spdylay_buffer_free(&outbuffer);
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
uint8_t *buf = malloc(r);
|
||||||
|
if(buf == NULL) {
|
||||||
|
spdylay_buffer_free(&outbuffer);
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
spdylay_buffer_serialize(&outbuffer, buf);
|
||||||
|
spdylay_buffer_free(&outbuffer);
|
||||||
|
r = spdylay_frame_unpack_nv(nv_ptr, buf, r);
|
||||||
|
free(buf);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t spdylay_frame_count_nv_space(char **nv)
|
||||||
|
{
|
||||||
|
size_t sum = 2;
|
||||||
|
int i;
|
||||||
|
const char *prev = "";
|
||||||
|
size_t prevlen = 0;
|
||||||
|
for(i = 0; nv[i]; i += 2) {
|
||||||
|
const char *key = nv[i];
|
||||||
|
const char *val = nv[i+1];
|
||||||
|
size_t keylen = strlen(key);
|
||||||
|
size_t vallen = strlen(val);
|
||||||
|
if(prevlen == keylen && memcmp(prev, key, keylen) == 0) {
|
||||||
|
/* Join previous value, with NULL character */
|
||||||
|
sum += vallen+1;
|
||||||
|
} else {
|
||||||
|
prev = key;
|
||||||
|
/* SPDY NV header does not include terminating NULL byte */
|
||||||
|
sum += keylen+vallen+4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t *bufp = buf+2;
|
||||||
|
uint16_t num_nv = 0;
|
||||||
|
/* TODO Join values with same keys, using '\0' as a delimiter */
|
||||||
|
const char *prev = "";
|
||||||
|
uint8_t *prev_vallen_buf = NULL;
|
||||||
|
uint16_t prev_vallen = 0;
|
||||||
|
for(i = 0; nv[i]; i += 2) {
|
||||||
|
const char *key = nv[i];
|
||||||
|
const char *val = nv[i+1];
|
||||||
|
size_t keylen = strlen(key);
|
||||||
|
size_t vallen = strlen(val);
|
||||||
|
if(strcmp(prev, key) == 0) {
|
||||||
|
prev_vallen += vallen+1;
|
||||||
|
spdylay_put_uint16be(prev_vallen_buf, prev_vallen);
|
||||||
|
*bufp = '\0';
|
||||||
|
++bufp;
|
||||||
|
memcpy(bufp, val, vallen);
|
||||||
|
bufp += vallen;
|
||||||
|
} else {
|
||||||
|
++num_nv;
|
||||||
|
bufp = spdylay_pack_str(bufp, key, keylen);
|
||||||
|
prev = key;
|
||||||
|
prev_vallen_buf = bufp;
|
||||||
|
prev_vallen = vallen;
|
||||||
|
bufp = spdylay_pack_str(bufp, val, vallen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spdylay_put_uint16be(buf, num_nv);
|
||||||
|
return bufp-buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_frame_is_ctrl_frame(uint8_t first_byte)
|
||||||
|
{
|
||||||
|
return first_byte & 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_nv_free(char **nv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; nv[i]; i += 2) {
|
||||||
|
free(nv[i]);
|
||||||
|
free(nv[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame, uint8_t flags,
|
||||||
|
int32_t stream_id, int32_t assoc_stream_id,
|
||||||
|
uint8_t pri, char **nv)
|
||||||
|
{
|
||||||
|
memset(frame, 0, sizeof(spdylay_syn_stream));
|
||||||
|
frame->hd.version = 2;
|
||||||
|
frame->hd.type = SPDYLAY_SYN_STREAM;
|
||||||
|
frame->hd.flags = flags;
|
||||||
|
frame->stream_id = stream_id;
|
||||||
|
frame->assoc_stream_id = assoc_stream_id;
|
||||||
|
frame->pri = pri;
|
||||||
|
frame->nv = nv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_syn_stream_free(spdylay_syn_stream *frame)
|
||||||
|
{
|
||||||
|
spdylay_frame_nv_free(frame->nv);
|
||||||
|
free(frame->nv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame)
|
||||||
|
{
|
||||||
|
spdylay_frame_nv_free(frame->nv);
|
||||||
|
free(frame->nv);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
|
||||||
|
spdylay_syn_stream *frame,
|
||||||
|
spdylay_zlib *deflater)
|
||||||
|
{
|
||||||
|
uint8_t *framebuf = NULL;
|
||||||
|
size_t framelen;
|
||||||
|
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv, 18, deflater);
|
||||||
|
if(framelen < 0) {
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
frame->hd.length = framelen-8;
|
||||||
|
memset(framebuf, 0, 18);
|
||||||
|
/* pack ctrl header after length is determined */
|
||||||
|
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
|
||||||
|
spdylay_put_uint32be(&framebuf[8], frame->stream_id);
|
||||||
|
spdylay_put_uint32be(&framebuf[12], frame->assoc_stream_id);
|
||||||
|
framebuf[16] = (frame->pri << 6);
|
||||||
|
|
||||||
|
*buf_ptr = framebuf;
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
|
||||||
|
const uint8_t *head, size_t headlen,
|
||||||
|
const uint8_t *payload, size_t payloadlen,
|
||||||
|
spdylay_zlib *inflater)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
||||||
|
frame->stream_id = spdylay_get_uint32(payload);
|
||||||
|
frame->assoc_stream_id = spdylay_get_uint32(payload+4);
|
||||||
|
frame->pri = spdylay_unpack_pri(payload+8);
|
||||||
|
r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+10, payloadlen-10,
|
||||||
|
inflater);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
|
||||||
|
const uint8_t *head, size_t headlen,
|
||||||
|
const uint8_t *payload, size_t payloadlen,
|
||||||
|
spdylay_zlib *inflater)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
||||||
|
frame->stream_id = spdylay_get_uint32(payload);
|
||||||
|
r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+6, payloadlen-6,
|
||||||
|
inflater);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_FRAME_H
|
||||||
|
#define SPDYLAY_FRAME_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include "spdylay_zlib.h"
|
||||||
|
#include "spdylay_buffer.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPDYLAY_SYN_STREAM = 1,
|
||||||
|
SPDYLAY_SYN_REPLY = 2,
|
||||||
|
SPDYLAY_RST_STREAM = 3,
|
||||||
|
SPDYLAY_SETTINGS = 4,
|
||||||
|
SPDYLAY_NOOP = 5,
|
||||||
|
SPDYLAY_PING = 6,
|
||||||
|
SPDYLAY_GOAWAY = 7,
|
||||||
|
} spdylay_frame_type;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPDYLAY_FLAG_FIN = 1
|
||||||
|
} spdylay_flag;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t version;
|
||||||
|
uint16_t type;
|
||||||
|
uint8_t flags;
|
||||||
|
int32_t length;
|
||||||
|
} spdylay_ctrl_hd;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_ctrl_hd hd;
|
||||||
|
int32_t stream_id;
|
||||||
|
int32_t assoc_stream_id;
|
||||||
|
uint8_t pri;
|
||||||
|
char **nv;
|
||||||
|
} spdylay_syn_stream;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_ctrl_hd hd;
|
||||||
|
int32_t stream_id;
|
||||||
|
char **nv;
|
||||||
|
} spdylay_syn_reply;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
spdylay_syn_stream syn_stream;
|
||||||
|
} spdylay_frame;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs SYN_STREAM frame |frame| in wire frame format and store it in
|
||||||
|
* |*buf_ptr|. This function allocates enough memory to store given
|
||||||
|
* frame in |*buf_ptr|. This function returns the size of packed
|
||||||
|
* frame if it succeeds, or returns negative error
|
||||||
|
* code. frame->hd.length is assigned after length is determined
|
||||||
|
* during packing process.
|
||||||
|
*/
|
||||||
|
ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
|
||||||
|
spdylay_syn_stream *frame,
|
||||||
|
spdylay_zlib *deflater);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpacks SYN_STREAM frame byte sequence into |frame|. Header is
|
||||||
|
* given in head and headlen. In spdy/2 spec, headlen is 8
|
||||||
|
* bytes. |payload| is the data after length field of the header.
|
||||||
|
* This function returns 0 if it succeeds or negative error code.
|
||||||
|
*/
|
||||||
|
int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
|
||||||
|
const uint8_t *head, size_t headlen,
|
||||||
|
const uint8_t *payload, size_t payloadlen,
|
||||||
|
spdylay_zlib *inflater);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpacks SYN_REPLY frame byte sequence into |frame|. This function
|
||||||
|
* returns 0 if it succeeds or negative error code.
|
||||||
|
*/
|
||||||
|
int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
|
||||||
|
const uint8_t *head, size_t headlen,
|
||||||
|
const uint8_t *payload, size_t payloadlen,
|
||||||
|
spdylay_zlib *inflater);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns number of bytes to pack name/value pairs |nv|. This
|
||||||
|
* function expects |nv| is sorted in ascending order of key. This
|
||||||
|
* function can handles duplicate keys and concatenation of thier
|
||||||
|
* values with '\0'.
|
||||||
|
*/
|
||||||
|
size_t spdylay_frame_count_nv_space(char **nv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs name/value pairs in |nv| in |buf|. |buf| must have at least
|
||||||
|
* spdylay_frame_count_nv_space(nv) bytes.
|
||||||
|
*/
|
||||||
|
ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpacks name/value pairs in wire format |in| with length |inlen|
|
||||||
|
* and stores them in |*nv_ptr|. Thif function allocates enough
|
||||||
|
* memory to store name/value pairs in |*nv_ptr|. This function
|
||||||
|
* returns 0 if it succeeds, or negative error code.
|
||||||
|
*/
|
||||||
|
int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes SYN_STREAM frame |frame| with given values. |frame|
|
||||||
|
* takes ownership of |nv|, so caller must not free it. If stream_id
|
||||||
|
* is not assigned yet, it must be 0.
|
||||||
|
*/
|
||||||
|
void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame, uint8_t flags,
|
||||||
|
int32_t stream_id, int32_t assoc_stream_id,
|
||||||
|
uint8_t pri, char **nv);
|
||||||
|
|
||||||
|
void spdylay_frame_syn_stream_free(spdylay_syn_stream *frame);
|
||||||
|
|
||||||
|
void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 1 if the first byte of this frame indicates it is a control
|
||||||
|
* frame.
|
||||||
|
*/
|
||||||
|
int spdylay_frame_is_ctrl_frame(uint8_t first_byte);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deallocates memory of key/value pairs in |nv|.
|
||||||
|
*/
|
||||||
|
void spdylay_frame_nv_free(char **nv);
|
||||||
|
|
||||||
|
#endif /* SPDYLAY_FRAME_H */
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_helper.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
void spdylay_put_uint16be(uint8_t *buf, uint16_t n)
|
||||||
|
{
|
||||||
|
uint16_t x = htons(n);
|
||||||
|
memcpy(buf, &x, sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_put_uint32be(uint8_t *buf, uint32_t n)
|
||||||
|
{
|
||||||
|
uint32_t x = htonl(n);
|
||||||
|
memcpy(buf, &x, sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t spdylay_get_uint16(const uint8_t *data)
|
||||||
|
{
|
||||||
|
uint16_t n;
|
||||||
|
memcpy(&n, data, sizeof(uint16_t));
|
||||||
|
return ntohs(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t spdylay_get_uint32(const uint8_t *data)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
memcpy(&n, data, sizeof(uint32_t));
|
||||||
|
return ntohl(n);
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_HELPER_H
|
||||||
|
#define SPDYLAY_HELPER_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include <spdylay/spdylay.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
|
||||||
|
* network byte order.
|
||||||
|
*/
|
||||||
|
void spdylay_put_uint16be(uint8_t *buf, uint16_t n);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copies 4 byte unsigned integer |n| in host byte order to |buf| in
|
||||||
|
* network byte order.
|
||||||
|
*/
|
||||||
|
void spdylay_put_uint32be(uint8_t *buf, uint32_t n);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieves 2 byte unsigned integer stored in |data| in network byte
|
||||||
|
* order and returns it in host byte order.
|
||||||
|
*/
|
||||||
|
uint16_t spdylay_get_uint16(const uint8_t *data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieves 4 byte unsigned integer stored in |data| in network byte
|
||||||
|
* order and returns it in host byte order.
|
||||||
|
*/
|
||||||
|
uint32_t spdylay_get_uint32(const uint8_t *data);
|
||||||
|
|
||||||
|
#endif /* SPDYLAY_HELPER_H */
|
|
@ -115,3 +115,8 @@ void spdylay_pq_pop(spdylay_pq *pq)
|
||||||
bubble_down(pq, 0);
|
bubble_down(pq, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spdylay_pq_empty(spdylay_pq *pq)
|
||||||
|
{
|
||||||
|
return pq->length == 0;
|
||||||
|
}
|
||||||
|
|
|
@ -51,5 +51,6 @@ void* spdylay_pq_top(spdylay_pq *pq);
|
||||||
|
|
||||||
void spdylay_pq_pop(spdylay_pq *pq);
|
void spdylay_pq_pop(spdylay_pq *pq);
|
||||||
|
|
||||||
|
int spdylay_pq_empty(spdylay_pq *pq);
|
||||||
|
|
||||||
#endif /* SPDYLAY_PQ_H */
|
#endif /* SPDYLAY_PQ_H */
|
||||||
|
|
|
@ -0,0 +1,482 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_session.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "spdylay_stream.h"
|
||||||
|
#include "spdylay_helper.h"
|
||||||
|
|
||||||
|
int spdylay_outbound_item_compar(const void *lhsx, const void *rhsx)
|
||||||
|
{
|
||||||
|
const spdylay_outbound_item *lhs, *rhs;
|
||||||
|
lhs = (const spdylay_outbound_item*)lhsx;
|
||||||
|
rhs = (const spdylay_outbound_item*)rhsx;
|
||||||
|
return lhs->pri-rhs->pri;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_client_init(spdylay_session **session_ptr,
|
||||||
|
const spdylay_session_callbacks *callbacks,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
*session_ptr = malloc(sizeof(spdylay_session));
|
||||||
|
if(*session_ptr == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
memset(*session_ptr, 0, sizeof(spdylay_session));
|
||||||
|
(*session_ptr)->next_stream_id = 1;
|
||||||
|
(*session_ptr)->last_accepted_stream_id = 0;
|
||||||
|
|
||||||
|
r = spdylay_zlib_deflate_hd_init(&(*session_ptr)->hd_deflater);
|
||||||
|
if(r != 0) {
|
||||||
|
free(*session_ptr);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = spdylay_zlib_inflate_hd_init(&(*session_ptr)->hd_inflater);
|
||||||
|
if(r != 0) {
|
||||||
|
spdylay_zlib_deflate_free(&(*session_ptr)->hd_deflater);
|
||||||
|
free(*session_ptr);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = spdylay_map_init(&(*session_ptr)->streams);
|
||||||
|
if(r != 0) {
|
||||||
|
spdylay_zlib_inflate_free(&(*session_ptr)->hd_inflater);
|
||||||
|
spdylay_zlib_deflate_free(&(*session_ptr)->hd_deflater);
|
||||||
|
free(*session_ptr);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = spdylay_pq_init(&(*session_ptr)->ob_pq, spdylay_outbound_item_compar);
|
||||||
|
if(r != 0) {
|
||||||
|
spdylay_map_free(&(*session_ptr)->streams);
|
||||||
|
spdylay_zlib_inflate_free(&(*session_ptr)->hd_inflater);
|
||||||
|
spdylay_zlib_deflate_free(&(*session_ptr)->hd_deflater);
|
||||||
|
free(*session_ptr);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
(*session_ptr)->callbacks = *callbacks;
|
||||||
|
(*session_ptr)->user_data = user_data;
|
||||||
|
|
||||||
|
(*session_ptr)->ibuf.mark = (*session_ptr)->ibuf.buf;
|
||||||
|
(*session_ptr)->ibuf.limit = (*session_ptr)->ibuf.buf;
|
||||||
|
|
||||||
|
(*session_ptr)->iframe.state = SPDYLAY_RECV_HEAD;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spdylay_free_streams(key_type key, void *val)
|
||||||
|
{
|
||||||
|
spdylay_stream_free((spdylay_stream*)val);
|
||||||
|
free(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spdylay_outbound_item_free(spdylay_outbound_item *item)
|
||||||
|
{
|
||||||
|
if(item == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch(item->frame_type) {
|
||||||
|
case SPDYLAY_SYN_STREAM:
|
||||||
|
spdylay_frame_syn_stream_free(&item->frame->syn_stream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(item->frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_session_free(spdylay_session *session)
|
||||||
|
{
|
||||||
|
spdylay_map_each(&session->streams, spdylay_free_streams);
|
||||||
|
spdylay_map_free(&session->streams);
|
||||||
|
while(!spdylay_pq_empty(&session->ob_pq)) {
|
||||||
|
spdylay_outbound_item *item = (spdylay_outbound_item*)
|
||||||
|
spdylay_pq_top(&session->ob_pq);
|
||||||
|
spdylay_outbound_item_free(item);
|
||||||
|
free(item);
|
||||||
|
spdylay_pq_pop(&session->ob_pq);
|
||||||
|
}
|
||||||
|
spdylay_pq_free(&session->ob_pq);
|
||||||
|
spdylay_zlib_deflate_free(&session->hd_deflater);
|
||||||
|
spdylay_zlib_inflate_free(&session->hd_inflater);
|
||||||
|
free(session->iframe.buf);
|
||||||
|
free(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_add_frame(spdylay_session *session,
|
||||||
|
spdylay_frame_type frame_type,
|
||||||
|
spdylay_frame *frame)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
spdylay_outbound_item *item;
|
||||||
|
item = malloc(sizeof(spdylay_outbound_item));
|
||||||
|
if(item == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
item->frame_type = frame_type;
|
||||||
|
item->frame = frame;
|
||||||
|
/* TODO Add pri field to SYN_REPLY, DATA frame which copies
|
||||||
|
corresponding SYN_STREAM pri. PING frame always pri = 0
|
||||||
|
(highest) */
|
||||||
|
switch(frame_type) {
|
||||||
|
case SPDYLAY_SYN_STREAM:
|
||||||
|
item->pri = 4-frame->syn_stream.pri;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
item->pri = 4;
|
||||||
|
};
|
||||||
|
r = spdylay_pq_push(&session->ob_pq, item);
|
||||||
|
if(r != 0) {
|
||||||
|
free(item);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
spdylay_stream *stream = malloc(sizeof(spdylay_stream));
|
||||||
|
if(stream == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
spdylay_stream_init(stream, stream_id);
|
||||||
|
r = spdylay_map_insert(&session->streams, stream_id, stream);
|
||||||
|
if(r != 0) {
|
||||||
|
free(stream);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
||||||
|
spdylay_outbound_item *item,
|
||||||
|
uint8_t **framebuf_ptr)
|
||||||
|
{
|
||||||
|
uint8_t *framebuf;
|
||||||
|
ssize_t framebuflen;
|
||||||
|
int r;
|
||||||
|
switch(item->frame_type) {
|
||||||
|
case SPDYLAY_SYN_STREAM: {
|
||||||
|
item->frame->syn_stream.stream_id = session->next_stream_id;
|
||||||
|
session->next_stream_id += 2;
|
||||||
|
framebuflen = spdylay_frame_pack_syn_stream(&framebuf,
|
||||||
|
&item->frame->syn_stream,
|
||||||
|
&session->hd_deflater);
|
||||||
|
if(framebuflen < 0) {
|
||||||
|
return framebuflen;
|
||||||
|
}
|
||||||
|
printf("packed %d bytes\n", framebuflen);
|
||||||
|
r = spdylay_session_open_stream(session, item->frame->syn_stream.stream_id);
|
||||||
|
if(r != 0) {
|
||||||
|
free(framebuf);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
*framebuf_ptr = framebuf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
framebuflen = SPDYLAY_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
return framebuflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spdylay_active_outbound_item_reset
|
||||||
|
(spdylay_active_outbound_item *aob)
|
||||||
|
{
|
||||||
|
spdylay_outbound_item_free(aob->item);
|
||||||
|
free(aob->item);
|
||||||
|
free(aob->framebuf);
|
||||||
|
memset(aob, 0, sizeof(spdylay_active_outbound_item));
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_send(spdylay_session *session)
|
||||||
|
{
|
||||||
|
printf("session_send\n");
|
||||||
|
while(session->aob.item || !spdylay_pq_empty(&session->ob_pq)) {
|
||||||
|
const uint8_t *data;
|
||||||
|
size_t datalen;
|
||||||
|
ssize_t sentlen;
|
||||||
|
if(session->aob.item == NULL) {
|
||||||
|
spdylay_outbound_item *item = spdylay_pq_top(&session->ob_pq);
|
||||||
|
uint8_t *framebuf;
|
||||||
|
ssize_t framebuflen;
|
||||||
|
spdylay_pq_pop(&session->ob_pq);
|
||||||
|
/* TODO Get or validate stream id here */
|
||||||
|
framebuflen = spdylay_session_prep_frame(session, item, &framebuf);
|
||||||
|
if(framebuflen < 0) {
|
||||||
|
/* TODO Call error callback? */
|
||||||
|
spdylay_outbound_item_free(item);
|
||||||
|
free(item);
|
||||||
|
continue;;
|
||||||
|
}
|
||||||
|
session->aob.item = item;
|
||||||
|
session->aob.framebuf = framebuf;
|
||||||
|
session->aob.framebuflen = framebuflen;
|
||||||
|
}
|
||||||
|
data = session->aob.framebuf + session->aob.framebufoff;
|
||||||
|
datalen = session->aob.framebuflen - session->aob.framebufoff;
|
||||||
|
sentlen = session->callbacks.send_callback(data, datalen, 0,
|
||||||
|
session->user_data);
|
||||||
|
if(sentlen < 0) {
|
||||||
|
if(sentlen == SPDYLAY_ERR_WOULDBLOCK) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return sentlen;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("sent %d bytes\n", sentlen);
|
||||||
|
session->aob.framebufoff += sentlen;
|
||||||
|
if(session->aob.framebufoff == session->aob.framebuflen) {
|
||||||
|
/* Frame has completely sent */
|
||||||
|
spdylay_active_outbound_item_reset(&session->aob);
|
||||||
|
/* TODO If frame is data frame, we need to sent all chunk of
|
||||||
|
data.*/
|
||||||
|
} else {
|
||||||
|
/* partial write */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spdylay_inbound_buffer_shift(spdylay_inbound_buffer *ibuf)
|
||||||
|
{
|
||||||
|
ptrdiff_t len = ibuf->limit-ibuf->mark;
|
||||||
|
memmove(ibuf->buf, ibuf->mark, len);
|
||||||
|
ibuf->limit = ibuf->buf+len;
|
||||||
|
ibuf->mark = ibuf->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t spdylay_recv(spdylay_session *session)
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
size_t recv_max;
|
||||||
|
if(session->ibuf.mark != session->ibuf.buf) {
|
||||||
|
spdylay_inbound_buffer_shift(&session->ibuf);
|
||||||
|
}
|
||||||
|
recv_max = session->ibuf.buf+sizeof(session->ibuf.buf)-session->ibuf.limit;
|
||||||
|
r = session->callbacks.recv_callback
|
||||||
|
(session->ibuf.limit, recv_max, 0, session->user_data);
|
||||||
|
if(r > 0) {
|
||||||
|
if(r > recv_max) {
|
||||||
|
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||||
|
} else {
|
||||||
|
session->ibuf.limit += r;
|
||||||
|
}
|
||||||
|
} else if(r < 0) {
|
||||||
|
if(r != SPDYLAY_ERR_WOULDBLOCK) {
|
||||||
|
r = SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t spdylay_inbound_buffer_avail(spdylay_inbound_buffer *ibuf)
|
||||||
|
{
|
||||||
|
return ibuf->limit-ibuf->mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spdylay_inbound_frame_reset(spdylay_inbound_frame *iframe)
|
||||||
|
{
|
||||||
|
iframe->state = SPDYLAY_RECV_HEAD;
|
||||||
|
free(iframe->buf);
|
||||||
|
iframe->buf = NULL;
|
||||||
|
iframe->len = iframe->off = 0;
|
||||||
|
iframe->ign = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spdylay_debug_print_nv(char **nv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; nv[i]; i += 2) {
|
||||||
|
printf("%s: %s\n", nv[i], nv[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_process_ctrl_frame(spdylay_session *session)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
uint16_t type;
|
||||||
|
memcpy(&type, &session->iframe.headbuf[2], sizeof(uint16_t));
|
||||||
|
type = ntohs(type);
|
||||||
|
switch(type) {
|
||||||
|
case SPDYLAY_SYN_STREAM: {
|
||||||
|
spdylay_syn_stream frame;
|
||||||
|
printf("SYN_STREAM\n");
|
||||||
|
r = spdylay_frame_unpack_syn_stream(&frame, session->iframe.headbuf,
|
||||||
|
sizeof(session->iframe.headbuf),
|
||||||
|
session->iframe.buf,
|
||||||
|
session->iframe.len,
|
||||||
|
&session->hd_inflater);
|
||||||
|
if(r == 0) {
|
||||||
|
spdylay_debug_print_nv(frame.nv);
|
||||||
|
spdylay_frame_syn_stream_free(&frame);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SPDYLAY_SYN_REPLY: {
|
||||||
|
spdylay_syn_reply frame;
|
||||||
|
printf("SYN_REPLY\n");
|
||||||
|
r = spdylay_frame_unpack_syn_reply(&frame, session->iframe.headbuf,
|
||||||
|
sizeof(session->iframe.headbuf),
|
||||||
|
session->iframe.buf,
|
||||||
|
session->iframe.len,
|
||||||
|
&session->hd_inflater);
|
||||||
|
if(r == 0) {
|
||||||
|
spdylay_debug_print_nv(frame.nv);
|
||||||
|
spdylay_frame_syn_reply_free(&frame);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
/* ignore */
|
||||||
|
printf("Received control frame type %x\n", type);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_process_data_frame(spdylay_session *session)
|
||||||
|
{
|
||||||
|
printf("Received data frame, stream_id %d, %zu bytes, fin=%d\n",
|
||||||
|
spdylay_get_uint32(session->iframe.headbuf),
|
||||||
|
session->iframe.len,
|
||||||
|
session->iframe.headbuf[4] & SPDYLAY_FLAG_FIN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_recv(spdylay_session *session)
|
||||||
|
{
|
||||||
|
printf("session_recv\n");
|
||||||
|
while(1) {
|
||||||
|
ssize_t r;
|
||||||
|
if(session->iframe.state == SPDYLAY_RECV_HEAD) {
|
||||||
|
uint32_t payloadlen;
|
||||||
|
if(spdylay_inbound_buffer_avail(&session->ibuf) < SPDYLAY_HEAD_LEN) {
|
||||||
|
r = spdylay_recv(session);
|
||||||
|
printf("r=%d\n", r);
|
||||||
|
/* TODO handle EOF */
|
||||||
|
if(r < 0) {
|
||||||
|
if(r == SPDYLAY_ERR_WOULDBLOCK) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("Recved %d bytes\n", r);
|
||||||
|
if(spdylay_inbound_buffer_avail(&session->ibuf) < SPDYLAY_HEAD_LEN) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session->iframe.state = SPDYLAY_RECV_PAYLOAD;
|
||||||
|
payloadlen = spdylay_get_uint32(&session->ibuf.mark[4]) & 0xffffff;
|
||||||
|
memcpy(session->iframe.headbuf, session->ibuf.mark, SPDYLAY_HEAD_LEN);
|
||||||
|
session->ibuf.mark += SPDYLAY_HEAD_LEN;
|
||||||
|
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||||
|
/* control frame */
|
||||||
|
session->iframe.len = payloadlen;
|
||||||
|
session->iframe.buf = malloc(session->iframe.len);
|
||||||
|
if(session->iframe.buf == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
session->iframe.off = 0;
|
||||||
|
} else {
|
||||||
|
int32_t stream_id;
|
||||||
|
/* data frame */
|
||||||
|
/* For data frame, We dont' buffer data. Instead, just pass
|
||||||
|
received data to callback function. */
|
||||||
|
stream_id = spdylay_get_uint32(session->iframe.headbuf) & 0x7fffffff;
|
||||||
|
/* TODO validate stream id here */
|
||||||
|
session->iframe.len = payloadlen;
|
||||||
|
session->iframe.off = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(session->iframe.state == SPDYLAY_RECV_PAYLOAD) {
|
||||||
|
size_t rempayloadlen = session->iframe.len - session->iframe.off;
|
||||||
|
size_t bufavail, readlen;
|
||||||
|
if(spdylay_inbound_buffer_avail(&session->ibuf) == 0 &&
|
||||||
|
rempayloadlen > 0) {
|
||||||
|
r = spdylay_recv(session);
|
||||||
|
if(r <= 0) {
|
||||||
|
if(r == SPDYLAY_ERR_WOULDBLOCK) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bufavail = spdylay_inbound_buffer_avail(&session->ibuf);
|
||||||
|
readlen = bufavail < rempayloadlen ? bufavail : rempayloadlen;
|
||||||
|
if(session->iframe.buf != NULL) {
|
||||||
|
memcpy(session->iframe.buf, session->ibuf.mark, readlen);
|
||||||
|
}
|
||||||
|
session->iframe.off += readlen;
|
||||||
|
session->ibuf.mark += readlen;
|
||||||
|
if(session->iframe.len == session->iframe.off) {
|
||||||
|
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||||
|
spdylay_session_process_ctrl_frame(session);
|
||||||
|
} else {
|
||||||
|
spdylay_session_process_data_frame(session);
|
||||||
|
}
|
||||||
|
spdylay_inbound_frame_reset(&session->iframe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_want_read(spdylay_session *session)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_want_write(spdylay_session *session)
|
||||||
|
{
|
||||||
|
return session->aob.item != NULL || !spdylay_pq_empty(&session->ob_pq);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_req_submit(spdylay_session *session, const char *path)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
spdylay_frame *frame;
|
||||||
|
char **nv;
|
||||||
|
frame = malloc(sizeof(spdylay_frame));
|
||||||
|
nv = malloc(9*sizeof(char*));
|
||||||
|
nv[0] = strdup("method");
|
||||||
|
nv[1] = strdup("GET");
|
||||||
|
nv[2] = strdup("scheme");
|
||||||
|
nv[3] = strdup("https");
|
||||||
|
nv[4] = strdup("url");
|
||||||
|
nv[5] = strdup(path);
|
||||||
|
nv[6] = strdup("version");
|
||||||
|
nv[7] = strdup("HTTP/1.1");
|
||||||
|
nv[8] = NULL;
|
||||||
|
spdylay_frame_syn_stream_init(&frame->syn_stream,
|
||||||
|
SPDYLAY_FLAG_FIN, 0, 0, 0, nv);
|
||||||
|
r = spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame);
|
||||||
|
assert(r == 0);
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_SESSION_H
|
||||||
|
#define SPDYLAY_SESSION_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include <spdylay/spdylay.h>
|
||||||
|
#include "spdylay_pq.h"
|
||||||
|
#include "spdylay_map.h"
|
||||||
|
#include "spdylay_frame.h"
|
||||||
|
#include "spdylay_zlib.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_frame_type frame_type;
|
||||||
|
spdylay_frame *frame;
|
||||||
|
int pri;
|
||||||
|
} spdylay_outbound_item;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_outbound_item *item;
|
||||||
|
uint8_t *framebuf;
|
||||||
|
size_t framebuflen;
|
||||||
|
size_t framebufoff;
|
||||||
|
} spdylay_active_outbound_item;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t buf[4096];
|
||||||
|
uint8_t *mark;
|
||||||
|
uint8_t *limit;
|
||||||
|
} spdylay_inbound_buffer;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPDYLAY_RECV_HEAD,
|
||||||
|
SPDYLAY_RECV_PAYLOAD
|
||||||
|
} spdylay_inbound_state;
|
||||||
|
|
||||||
|
#define SPDYLAY_HEAD_LEN 8
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_inbound_state state;
|
||||||
|
uint8_t headbuf[SPDYLAY_HEAD_LEN];
|
||||||
|
/* NULL if inbound frame is data frame */
|
||||||
|
uint8_t *buf;
|
||||||
|
/* length in Length field */
|
||||||
|
size_t len;
|
||||||
|
size_t off;
|
||||||
|
uint8_t ign;
|
||||||
|
} spdylay_inbound_frame;
|
||||||
|
|
||||||
|
typedef struct spdylay_session {
|
||||||
|
uint8_t server;
|
||||||
|
int32_t next_stream_id;
|
||||||
|
int32_t last_accepted_stream_id;
|
||||||
|
|
||||||
|
spdylay_map /* <spdylay_stream*> */ streams;
|
||||||
|
spdylay_pq /* <spdylay_outbound_item*> */ ob_pq;
|
||||||
|
|
||||||
|
spdylay_active_outbound_item aob;
|
||||||
|
|
||||||
|
spdylay_inbound_buffer ibuf;
|
||||||
|
spdylay_inbound_frame iframe;
|
||||||
|
|
||||||
|
spdylay_zlib hd_deflater;
|
||||||
|
spdylay_zlib hd_inflater;
|
||||||
|
|
||||||
|
spdylay_session_callbacks callbacks;
|
||||||
|
void *user_data;
|
||||||
|
} spdylay_session;
|
||||||
|
|
||||||
|
/* TODO stream timeout etc */
|
||||||
|
|
||||||
|
int spdylay_session_add_frame(spdylay_session *session,
|
||||||
|
spdylay_frame_type frame_type,
|
||||||
|
spdylay_frame *frame);
|
||||||
|
|
||||||
|
int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id);
|
||||||
|
|
||||||
|
int spdylay_session_close_stream(spdylay_session *session, int32_t stream_id);
|
||||||
|
|
||||||
|
#endif /* SPDYLAY_SESSION_H */
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_stream.h"
|
||||||
|
|
||||||
|
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id)
|
||||||
|
{
|
||||||
|
stream->stream_id = stream_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_stream_free(spdylay_stream *stream)
|
||||||
|
{}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_STREAM_H
|
||||||
|
#define SPDYLAY_STREAM_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include <spdylay/spdylay.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t stream_id;
|
||||||
|
} spdylay_stream;
|
||||||
|
|
||||||
|
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id);
|
||||||
|
|
||||||
|
void spdylay_stream_free(spdylay_stream *stream);
|
||||||
|
|
||||||
|
#endif /* SPDYLAY_STREAM */
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_zlib.h"
|
||||||
|
|
||||||
|
#define COMPRESSION_LEVEL 9
|
||||||
|
#define WINDOW_BITS 11
|
||||||
|
#define MEM_LEVEL 1
|
||||||
|
|
||||||
|
static const char hd_dict[] =
|
||||||
|
"optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
|
||||||
|
"languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
|
||||||
|
"f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
|
||||||
|
"-agent10010120020120220320420520630030130230330430530630740040140240340440"
|
||||||
|
"5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
|
||||||
|
"glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
|
||||||
|
"ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
|
||||||
|
"sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
|
||||||
|
"oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
|
||||||
|
"ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
|
||||||
|
"pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
|
||||||
|
"ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
|
||||||
|
".1statusversionurl";
|
||||||
|
|
||||||
|
int spdylay_zlib_deflate_hd_init(spdylay_zlib *deflater)
|
||||||
|
{
|
||||||
|
deflater->zst.next_in = Z_NULL;
|
||||||
|
deflater->zst.zalloc = Z_NULL;
|
||||||
|
deflater->zst.zfree = Z_NULL;
|
||||||
|
deflater->zst.opaque = Z_NULL;
|
||||||
|
if(Z_OK != deflateInit2(&deflater->zst, COMPRESSION_LEVEL, Z_DEFLATED,
|
||||||
|
WINDOW_BITS, MEM_LEVEL, Z_DEFAULT_STRATEGY)) {
|
||||||
|
return SPDYLAY_ERR_ZLIB;
|
||||||
|
}
|
||||||
|
if(Z_OK != deflateSetDictionary(&deflater->zst, (uint8_t*)hd_dict,
|
||||||
|
sizeof(hd_dict))) {
|
||||||
|
return SPDYLAY_ERR_ZLIB;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_zlib_inflate_hd_init(spdylay_zlib *inflater)
|
||||||
|
{
|
||||||
|
inflater->zst.next_in = Z_NULL;
|
||||||
|
inflater->zst.avail_in = 0;
|
||||||
|
inflater->zst.zalloc = Z_NULL;
|
||||||
|
inflater->zst.zfree = Z_NULL;
|
||||||
|
if(Z_OK != inflateInit(&inflater->zst)) {
|
||||||
|
return SPDYLAY_ERR_ZLIB;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_zlib_deflate_free(spdylay_zlib *zlib)
|
||||||
|
{
|
||||||
|
deflateEnd(&zlib->zst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_zlib_inflate_free(spdylay_zlib *zlib)
|
||||||
|
{
|
||||||
|
inflateEnd(&zlib->zst);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_zlib_deflate_hd(spdylay_zlib *deflater,
|
||||||
|
uint8_t *out, size_t outlen,
|
||||||
|
const uint8_t *in, size_t inlen)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
deflater->zst.avail_in = inlen;
|
||||||
|
deflater->zst.next_in = (uint8_t*)in;
|
||||||
|
deflater->zst.avail_out = outlen;
|
||||||
|
deflater->zst.next_out = out;
|
||||||
|
r = deflate(&deflater->zst, Z_SYNC_FLUSH);
|
||||||
|
if(r == Z_OK) {
|
||||||
|
return outlen-deflater->zst.avail_out;
|
||||||
|
} else {
|
||||||
|
return SPDYLAY_ERR_ZLIB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t spdylay_zlib_deflate_hd_bound(spdylay_zlib *deflater, size_t len)
|
||||||
|
{
|
||||||
|
return deflateBound(&deflater->zst, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_zlib_inflate_hd(spdylay_zlib *inflater,
|
||||||
|
spdylay_buffer* buf,
|
||||||
|
const uint8_t *in, size_t inlen)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
inflater->zst.avail_in = inlen;
|
||||||
|
inflater->zst.next_in = (uint8_t*)in;
|
||||||
|
while(1) {
|
||||||
|
if(spdylay_buffer_avail(buf) == 0) {
|
||||||
|
if((r = spdylay_buffer_alloc(buf)) != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inflater->zst.avail_out = spdylay_buffer_avail(buf);
|
||||||
|
inflater->zst.next_out = spdylay_buffer_get(buf);
|
||||||
|
r = inflate(&inflater->zst, Z_NO_FLUSH);
|
||||||
|
if(r == Z_STREAM_ERROR || r == Z_STREAM_END) {
|
||||||
|
return SPDYLAY_ERR_ZLIB;
|
||||||
|
} else if(r == Z_NEED_DICT) {
|
||||||
|
if(Z_OK != inflateSetDictionary(&inflater->zst, (uint8_t*)hd_dict,
|
||||||
|
sizeof(hd_dict))) {
|
||||||
|
return SPDYLAY_ERR_ZLIB;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(r == Z_OK) {
|
||||||
|
size_t adv = spdylay_buffer_avail(buf)-inflater->zst.avail_out;
|
||||||
|
spdylay_buffer_advance(buf, adv);
|
||||||
|
}
|
||||||
|
if(inflater->zst.avail_in == 0 && inflater->zst.avail_out > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spdylay_buffer_length(buf);
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_ZLIB_H
|
||||||
|
#define SPDYLAY_ZLIB_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "spdylay_buffer.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
z_stream zst;
|
||||||
|
} spdylay_zlib;
|
||||||
|
|
||||||
|
int spdylay_zlib_deflate_hd_init(spdylay_zlib *deflater);
|
||||||
|
|
||||||
|
int spdylay_zlib_inflate_hd_init(spdylay_zlib *inflater);
|
||||||
|
|
||||||
|
void spdylay_zlib_deflate_free(spdylay_zlib *zlib);
|
||||||
|
|
||||||
|
void spdylay_zlib_inflate_free(spdylay_zlib *zlib);
|
||||||
|
|
||||||
|
size_t spdylay_zlib_deflate_hd_bound(spdylay_zlib *deflater, size_t len);
|
||||||
|
|
||||||
|
ssize_t spdylay_zlib_deflate_hd(spdylay_zlib *deflater,
|
||||||
|
uint8_t *out, size_t outlen,
|
||||||
|
const uint8_t *in, size_t inlen);
|
||||||
|
|
||||||
|
ssize_t spdylay_zlib_inflate_hd(spdylay_zlib *inflater,
|
||||||
|
spdylay_buffer* buf,
|
||||||
|
const uint8_t *in, size_t inlen);
|
||||||
|
|
||||||
|
#endif /* SPDYLAY_ZLIB_H */
|
|
@ -26,10 +26,12 @@ if HAVE_CUNIT
|
||||||
check_PROGRAMS = main
|
check_PROGRAMS = main
|
||||||
|
|
||||||
OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c spdylay_queue_test.c \
|
OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c spdylay_queue_test.c \
|
||||||
spdylay_buffer_test.c
|
spdylay_buffer_test.c spdylay_zlib_test.c spdylay_session_test.c \
|
||||||
|
spdylay_frame_test.c
|
||||||
|
|
||||||
HFILES = spdylay_pq_test.h spdylay_map_test.h spdylay_queue_test.h \
|
HFILES = spdylay_pq_test.h spdylay_map_test.h spdylay_queue_test.h \
|
||||||
spdylay_buffer_test.h
|
spdylay_buffer_test.h spdylay_zlib_test.h spdylay_session_test.h
|
||||||
|
spdylay_frame_test.h
|
||||||
|
|
||||||
main_SOURCES = $(HFILES) $(OBJECTS)
|
main_SOURCES = $(HFILES) $(OBJECTS)
|
||||||
|
|
||||||
|
|
11
tests/main.c
11
tests/main.c
|
@ -30,6 +30,9 @@
|
||||||
#include "spdylay_map_test.h"
|
#include "spdylay_map_test.h"
|
||||||
#include "spdylay_queue_test.h"
|
#include "spdylay_queue_test.h"
|
||||||
#include "spdylay_buffer_test.h"
|
#include "spdylay_buffer_test.h"
|
||||||
|
#include "spdylay_zlib_test.h"
|
||||||
|
#include "spdylay_session_test.h"
|
||||||
|
#include "spdylay_frame_test.h"
|
||||||
|
|
||||||
int init_suite1(void)
|
int init_suite1(void)
|
||||||
{
|
{
|
||||||
|
@ -61,7 +64,13 @@ int main()
|
||||||
if(!CU_add_test(pSuite, "pq", test_spdylay_pq) ||
|
if(!CU_add_test(pSuite, "pq", test_spdylay_pq) ||
|
||||||
!CU_add_test(pSuite, "map", test_spdylay_map) ||
|
!CU_add_test(pSuite, "map", test_spdylay_map) ||
|
||||||
!CU_add_test(pSuite, "queue", test_spdylay_queue) ||
|
!CU_add_test(pSuite, "queue", test_spdylay_queue) ||
|
||||||
!CU_add_test(pSuite, "buffer", test_spdylay_buffer)) {
|
!CU_add_test(pSuite, "buffer", test_spdylay_buffer) ||
|
||||||
|
!CU_add_test(pSuite, "zlib", test_spdylay_zlib) ||
|
||||||
|
!CU_add_test(pSuite, "session_recv", test_spdylay_session_recv) ||
|
||||||
|
!CU_add_test(pSuite, "session_add_frame",
|
||||||
|
test_spdylay_session_add_frame) ||
|
||||||
|
!CU_add_test(pSuite, "frame_unpack_nv",
|
||||||
|
test_spdylay_frame_unpack_nv)) {
|
||||||
CU_cleanup_registry();
|
CU_cleanup_registry();
|
||||||
return CU_get_error();
|
return CU_get_error();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_frame_test.h"
|
||||||
|
|
||||||
|
#include <CUnit/CUnit.h>
|
||||||
|
|
||||||
|
#include "spdylay_frame.h"
|
||||||
|
|
||||||
|
void test_spdylay_frame_unpack_nv()
|
||||||
|
{
|
||||||
|
const char *headers[] = {
|
||||||
|
"method", "GET",
|
||||||
|
"scheme", "https",
|
||||||
|
"url", "/",
|
||||||
|
"version", "HTTP/1.1",
|
||||||
|
"x-head", "foo",
|
||||||
|
"x-head", "bar",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char in[1024];
|
||||||
|
char **nv;
|
||||||
|
int i;
|
||||||
|
size_t inlen = spdylay_frame_pack_nv(in, (char**)headers);
|
||||||
|
CU_ASSERT(0 == spdylay_frame_unpack_nv(&nv, in, inlen));
|
||||||
|
spdylay_frame_nv_free(nv);
|
||||||
|
free(nv);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_FRAME_TEST_H
|
||||||
|
#define SPDYLAY_FRAME_TEST_H
|
||||||
|
|
||||||
|
void test_spdylay_frame_unpack_nv();
|
||||||
|
|
||||||
|
#endif /* SPDYLAY_FRAME_TEST_H */
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_session_test.h"
|
||||||
|
|
||||||
|
#include <CUnit/CUnit.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "spdylay_session.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t buf[4096];
|
||||||
|
size_t length;
|
||||||
|
} accumulator;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t data[8192];
|
||||||
|
uint8_t* datamark;
|
||||||
|
uint8_t* datalimit;
|
||||||
|
size_t feedseq[8192];
|
||||||
|
size_t seqidx;
|
||||||
|
} scripted_data_feed;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
accumulator *acc;
|
||||||
|
scripted_data_feed *df;
|
||||||
|
} my_user_data;
|
||||||
|
|
||||||
|
static void scripted_data_feed_init(scripted_data_feed *df,
|
||||||
|
uint8_t *data, size_t data_length)
|
||||||
|
{
|
||||||
|
memset(df, 0, sizeof(scripted_data_feed));
|
||||||
|
memcpy(df->data, data, data_length);
|
||||||
|
df->datamark = df->data;
|
||||||
|
df->datalimit = df->data+data_length;
|
||||||
|
df->feedseq[0] = data_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t scripted_recv_callback(uint8_t* data, size_t len, int flags,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
scripted_data_feed *df = ((my_user_data*)user_data)->df;
|
||||||
|
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
|
||||||
|
memcpy(data, df->datamark, wlen);
|
||||||
|
df->datamark += wlen;
|
||||||
|
if(wlen <= len) {
|
||||||
|
++df->seqidx;
|
||||||
|
} else {
|
||||||
|
df->feedseq[df->seqidx] -= wlen;
|
||||||
|
}
|
||||||
|
return wlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t accumulator_send_callback(const uint8_t *buf, size_t len,
|
||||||
|
int flags, void* user_data)
|
||||||
|
{
|
||||||
|
accumulator *acc = ((my_user_data*)user_data)->acc;
|
||||||
|
assert(acc->length+len < sizeof(acc->buf));
|
||||||
|
memcpy(acc->buf+acc->length, buf, len);
|
||||||
|
acc->length += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char** dup_nv(const char **src)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char **dst;
|
||||||
|
for(i = 0; src[i]; ++i);
|
||||||
|
dst = malloc((i+1)*sizeof(char*));
|
||||||
|
for(i = 0; src[i]; ++i) {
|
||||||
|
dst[i] = strdup(src[i]);
|
||||||
|
}
|
||||||
|
dst[i] = NULL;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_spdylay_session_recv()
|
||||||
|
{
|
||||||
|
spdylay_session *session;
|
||||||
|
spdylay_session_callbacks callbacks = {
|
||||||
|
NULL,
|
||||||
|
scripted_recv_callback
|
||||||
|
};
|
||||||
|
scripted_data_feed df;
|
||||||
|
my_user_data user_data;
|
||||||
|
const char *nv[] = {
|
||||||
|
"url", "/", NULL
|
||||||
|
};
|
||||||
|
uint8_t *framedata;
|
||||||
|
size_t framelen;
|
||||||
|
spdylay_frame frame;
|
||||||
|
|
||||||
|
user_data.df = &df;
|
||||||
|
spdylay_session_client_init(&session, &callbacks, &user_data);
|
||||||
|
spdylay_frame_syn_stream_init(&frame.syn_stream, 0, 0, 0, 3, dup_nv(nv));
|
||||||
|
framelen = spdylay_frame_pack_syn_stream(&framedata, &frame.syn_stream,
|
||||||
|
&session->hd_deflater);
|
||||||
|
scripted_data_feed_init(&df, framedata, framelen);
|
||||||
|
free(framedata);
|
||||||
|
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_session_recv(session));
|
||||||
|
spdylay_session_free(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_spdylay_session_add_frame()
|
||||||
|
{
|
||||||
|
spdylay_session *session;
|
||||||
|
spdylay_session_callbacks callbacks = {
|
||||||
|
accumulator_send_callback,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
accumulator acc;
|
||||||
|
my_user_data user_data;
|
||||||
|
const char *nv[] = {
|
||||||
|
"method", "GET",
|
||||||
|
"scheme", "https",
|
||||||
|
"url", "/",
|
||||||
|
"version", "HTTP/1.1",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
spdylay_frame *frame;
|
||||||
|
const uint8_t hd_ans1[] = {
|
||||||
|
0x80, 0x02, 0x00, 0x01
|
||||||
|
};
|
||||||
|
uint32_t temp32;
|
||||||
|
acc.length = 0;
|
||||||
|
user_data.acc = &acc;
|
||||||
|
CU_ASSERT(0 == spdylay_session_client_init(&session, &callbacks, &user_data));
|
||||||
|
|
||||||
|
frame = malloc(sizeof(spdylay_frame));
|
||||||
|
spdylay_frame_syn_stream_init(&frame->syn_stream, 0, 0, 0, 3, dup_nv(nv));
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame));
|
||||||
|
CU_ASSERT(0 == spdylay_pq_empty(&session->ob_pq));
|
||||||
|
CU_ASSERT(0 == spdylay_session_send(session));
|
||||||
|
CU_ASSERT(memcmp(hd_ans1, acc.buf, 4) == 0);
|
||||||
|
/* check stream id */
|
||||||
|
memcpy(&temp32, &acc.buf[8], 4);
|
||||||
|
temp32 = ntohl(temp32);
|
||||||
|
CU_ASSERT(1 == temp32);
|
||||||
|
/* check assoc stream id */
|
||||||
|
memcpy(&temp32, &acc.buf[12], 4);
|
||||||
|
temp32 = ntohl(temp32);
|
||||||
|
CU_ASSERT(0 == temp32);
|
||||||
|
/* check pri */
|
||||||
|
temp32 = (acc.buf[16] >> 6) & 0x3;
|
||||||
|
CU_ASSERT(3 == temp32);
|
||||||
|
|
||||||
|
spdylay_session_free(session);
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_SESSION_TEST_H
|
||||||
|
#define SPDYLAY_SESSION_TEST_H
|
||||||
|
|
||||||
|
void test_spdylay_session_recv();
|
||||||
|
void test_spdylay_session_add_frame();
|
||||||
|
|
||||||
|
#endif // SPDYLAY_SESSION_TEST_H
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_zlib_test.h"
|
||||||
|
|
||||||
|
#include <CUnit/CUnit.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "spdylay_zlib.h"
|
||||||
|
|
||||||
|
void test_spdylay_zlib()
|
||||||
|
{
|
||||||
|
spdylay_zlib deflater, inflater;
|
||||||
|
const char msg[] =
|
||||||
|
"GET /chat HTTP/1.1\r\n"
|
||||||
|
"Host: server.example.com\r\n"
|
||||||
|
"Upgrade: websocket\r\n"
|
||||||
|
"Connection: Upgrade\r\n"
|
||||||
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
|
"Origin: http://example.com\r\n"
|
||||||
|
"Sec-WebSocket-Protocol: chat, superchat\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"\r\n";
|
||||||
|
uint8_t inflatebuf[sizeof(msg)];
|
||||||
|
spdylay_buffer buf;
|
||||||
|
uint8_t *deflatebuf;
|
||||||
|
size_t deflatebuf_max;
|
||||||
|
ssize_t deflatebuf_len;
|
||||||
|
spdylay_buffer_init(&buf, 4096);
|
||||||
|
|
||||||
|
deflatebuf_max = spdylay_zlib_deflate_hd_bound(&deflater, sizeof(msg));
|
||||||
|
deflatebuf = malloc(deflatebuf_max);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_zlib_deflate_hd_init(&deflater));
|
||||||
|
CU_ASSERT(0 == spdylay_zlib_inflate_hd_init(&inflater));
|
||||||
|
|
||||||
|
CU_ASSERT(0 < (deflatebuf_len = spdylay_zlib_deflate_hd
|
||||||
|
(&deflater, deflatebuf, deflatebuf_max,
|
||||||
|
(const uint8_t*)msg, sizeof(msg))));
|
||||||
|
CU_ASSERT(sizeof(msg) == spdylay_zlib_inflate_hd
|
||||||
|
(&inflater, &buf, deflatebuf, deflatebuf_len));
|
||||||
|
free(deflatebuf);
|
||||||
|
spdylay_buffer_serialize(&buf, inflatebuf);
|
||||||
|
|
||||||
|
|
||||||
|
spdylay_zlib_deflate_free(&deflater);
|
||||||
|
spdylay_zlib_inflate_free(&inflater);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_ZLIB_TEST_H
|
||||||
|
#define SPDYLAY_ZLIB_TEST_H
|
||||||
|
|
||||||
|
void test_spdylay_zlib();
|
||||||
|
|
||||||
|
#endif // SPDYLAY_ZLIB_TEST_H
|
Loading…
Reference in New Issue