Reuse buffers when packing frames.

Temporal name/value buffer will be shared by unpacking frame.
This commit is contained in:
Tatsuhiro Tsujikawa 2012-02-16 20:54:30 +09:00
parent e4ad446261
commit 050f33e8f9
8 changed files with 313 additions and 170 deletions

View File

@ -63,27 +63,35 @@ static void spdylay_frame_unpack_ctrl_hd(spdylay_ctrl_hd *hd,
}
static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
size_t *buflen_ptr,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_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);
size_t nvspace;
size_t maxframelen;
ssize_t framelen;
spdylay_frame_pack_nv(nvbuf, nv);
int r;
nvspace = spdylay_frame_count_nv_space(nv);
r = spdylay_reserve_buffer(nvbuf_ptr, nvbuflen_ptr, nvspace);
if(r != 0) {
return SPDYLAY_ERR_NOMEM;
}
maxframelen = nv_offset+spdylay_zlib_deflate_hd_bound(deflater, nvspace);
r = spdylay_reserve_buffer(buf_ptr, buflen_ptr, maxframelen);
if(r != 0) {
return SPDYLAY_ERR_NOMEM;
}
spdylay_frame_pack_nv(*nvbuf_ptr, nv);
framelen = spdylay_zlib_deflate_hd(deflater,
framebuf+nv_offset,
(*buf_ptr)+nv_offset,
maxframelen-nv_offset,
nvbuf, nvbuflen);
free(nvbuf);
*nvbuf_ptr, nvspace);
if(framelen < 0) {
free(framebuf);
return framelen;
}
framelen += nv_offset;
*buf_ptr = framebuf;
return framelen;
}
@ -451,26 +459,28 @@ void spdylay_frame_data_free(spdylay_data *frame)
#define SPDYLAY_SYN_STREAM_NV_OFFSET 18
ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
size_t *buflen_ptr,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
spdylay_syn_stream *frame,
spdylay_zlib *deflater)
{
uint8_t *framebuf = NULL;
ssize_t framelen;
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv,
framelen = spdylay_frame_alloc_pack_nv(buf_ptr, buflen_ptr,
nvbuf_ptr, nvbuflen_ptr,
frame->nv,
SPDYLAY_SYN_STREAM_NV_OFFSET,
deflater);
if(framelen < 0) {
return framelen;
}
frame->hd.length = framelen-SPDYLAY_FRAME_HEAD_LENGTH;
memset(framebuf, 0, SPDYLAY_SYN_STREAM_NV_OFFSET);
memset(*buf_ptr, 0, SPDYLAY_SYN_STREAM_NV_OFFSET);
/* 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;
spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd);
spdylay_put_uint32be(&(*buf_ptr)[8], frame->stream_id);
spdylay_put_uint32be(&(*buf_ptr)[12], frame->assoc_stream_id);
(*buf_ptr)[16] = (frame->pri << 6);
return framelen;
}
@ -496,21 +506,24 @@ int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
#define SPDYLAY_SYN_REPLY_NV_OFFSET 14
ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
size_t *buflen_ptr,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
spdylay_syn_reply *frame,
spdylay_zlib *deflater)
{
uint8_t *framebuf = NULL;
ssize_t framelen;
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv,
framelen = spdylay_frame_alloc_pack_nv(buf_ptr, buflen_ptr,
nvbuf_ptr, nvbuflen_ptr,
frame->nv,
SPDYLAY_SYN_REPLY_NV_OFFSET, deflater);
if(framelen < 0) {
return framelen;
}
frame->hd.length = framelen-SPDYLAY_FRAME_HEAD_LENGTH;
memset(framebuf, 0, SPDYLAY_SYN_REPLY_NV_OFFSET);
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
spdylay_put_uint32be(&framebuf[8], frame->stream_id);
*buf_ptr = framebuf;
memset(*buf_ptr, 0, SPDYLAY_SYN_REPLY_NV_OFFSET);
spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd);
spdylay_put_uint32be(&(*buf_ptr)[8], frame->stream_id);
return framelen;
}
@ -530,18 +543,18 @@ int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
return r;
}
ssize_t spdylay_frame_pack_ping(uint8_t **buf_ptr, spdylay_ping *frame)
ssize_t spdylay_frame_pack_ping(uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_ping *frame)
{
uint8_t *framebuf = NULL;
ssize_t framelen = 12;
framebuf = malloc(framelen);
if(framebuf == NULL) {
return SPDYLAY_ERR_NOMEM;
int r;
r = spdylay_reserve_buffer(buf_ptr, buflen_ptr, framelen);
if(r != 0) {
return r;
}
memset(framebuf, 0, framelen);
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
spdylay_put_uint32be(&framebuf[8], frame->unique_id);
*buf_ptr = framebuf;
memset(*buf_ptr, 0, framelen);
spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd);
spdylay_put_uint32be(&(*buf_ptr)[8], frame->unique_id);
return framelen;
}
@ -557,18 +570,18 @@ int spdylay_frame_unpack_ping(spdylay_ping *frame,
return 0;
}
ssize_t spdylay_frame_pack_goaway(uint8_t **buf_ptr, spdylay_goaway *frame)
ssize_t spdylay_frame_pack_goaway(uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_goaway *frame)
{
uint8_t *framebuf = NULL;
ssize_t framelen = 12;
framebuf = malloc(framelen);
if(framebuf == NULL) {
return SPDYLAY_ERR_NOMEM;
int r;
r = spdylay_reserve_buffer(buf_ptr, buflen_ptr, framelen);
if(r != 0) {
return r;
}
memset(framebuf, 0, framelen);
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
spdylay_put_uint32be(&framebuf[8], frame->last_good_stream_id);
*buf_ptr = framebuf;
memset(*buf_ptr, 0, framelen);
spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd);
spdylay_put_uint32be(&(*buf_ptr)[8], frame->last_good_stream_id);
return framelen;
}
@ -587,22 +600,23 @@ int spdylay_frame_unpack_goaway(spdylay_goaway *frame,
#define SPDYLAY_HEADERS_NV_OFFSET 14
ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr,
ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr,
uint8_t **nvbuf_ptr, size_t *nvbuflen_ptr,
spdylay_headers *frame,
spdylay_zlib *deflater)
{
uint8_t *framebuf = NULL;
ssize_t framelen;
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv,
framelen = spdylay_frame_alloc_pack_nv(buf_ptr, buflen_ptr,
nvbuf_ptr, nvbuflen_ptr,
frame->nv,
SPDYLAY_HEADERS_NV_OFFSET, deflater);
if(framelen < 0) {
return framelen;
}
frame->hd.length = framelen-SPDYLAY_FRAME_HEAD_LENGTH;
memset(framebuf, 0, SPDYLAY_HEADERS_NV_OFFSET);
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
spdylay_put_uint32be(&framebuf[8], frame->stream_id);
*buf_ptr = framebuf;
memset(*buf_ptr, 0, SPDYLAY_HEADERS_NV_OFFSET);
spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd);
spdylay_put_uint32be(&(*buf_ptr)[8], frame->stream_id);
return framelen;
}
@ -622,20 +636,19 @@ int spdylay_frame_unpack_headers(spdylay_headers *frame,
return r;
}
ssize_t spdylay_frame_pack_rst_stream(uint8_t **buf_ptr,
ssize_t spdylay_frame_pack_rst_stream(uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_rst_stream *frame)
{
uint8_t *framebuf;
ssize_t framelen = 16;
framebuf = malloc(framelen);
if(framebuf == NULL) {
return SPDYLAY_ERR_NOMEM;
int r;
r = spdylay_reserve_buffer(buf_ptr, buflen_ptr, framelen);
if(r != 0) {
return r;
}
memset(framebuf, 0, framelen);
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
spdylay_put_uint32be(&framebuf[8], frame->stream_id);
spdylay_put_uint32be(&framebuf[12], frame->status_code);
*buf_ptr = framebuf;
memset(*buf_ptr, 0, framelen);
spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd);
spdylay_put_uint32be(&(*buf_ptr)[8], frame->stream_id);
spdylay_put_uint32be(&(*buf_ptr)[12], frame->status_code);
return framelen;
}
@ -652,34 +665,33 @@ int spdylay_frame_unpack_rst_stream(spdylay_rst_stream *frame,
return 0;
}
ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, spdylay_settings *frame)
ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_settings *frame)
{
uint8_t *framebuf;
ssize_t framelen = SPDYLAY_FRAME_HEAD_LENGTH+frame->hd.length;
int i;
framebuf = malloc(framelen);
if(framebuf == NULL) {
return SPDYLAY_ERR_NOMEM;
int i, r;
r = spdylay_reserve_buffer(buf_ptr, buflen_ptr, framelen);
if(r != 0) {
return r;
}
memset(framebuf, 0, framelen);
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
spdylay_put_uint32be(&framebuf[8], frame->niv);
memset(*buf_ptr, 0, framelen);
spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd);
spdylay_put_uint32be(&(*buf_ptr)[8], frame->niv);
for(i = 0; i < frame->niv; ++i) {
int off = i*8;
/* spdy/2 spec says ID is network byte order, but publicly
deployed server sends little endian host byte order. */
char *id_ptr = (char*)(&frame->iv[i].settings_id);
#ifdef WORDS_BIGENDIAN
framebuf[12+off] = id_ptr[3];
framebuf[12+off+1] = id_ptr[2];
framebuf[12+off+2] = id_ptr[1];
(*buf_ptr)[12+off] = id_ptr[3];
(*buf_ptr)[12+off+1] = id_ptr[2];
(*buf_ptr)[12+off+2] = id_ptr[1];
#else /* !WORDS_BIGENDIAN */
memcpy(&framebuf[12+off], id_ptr, 3);
memcpy(&(*buf_ptr)[12+off], id_ptr, 3);
#endif /* !WORDS_BIGENDIAN */
framebuf[15+off] = frame->iv[i].flags;
spdylay_put_uint32be(&framebuf[16+off], frame->iv[i].value);
(*buf_ptr)[15+off] = frame->iv[i].flags;
spdylay_put_uint32be(&(*buf_ptr)[16+off], frame->iv[i].value);
}
*buf_ptr = framebuf;
return framelen;
}

View File

@ -44,14 +44,25 @@
#define SPDYLAY_FRAME_HEAD_LENGTH 8
/*
* 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
* Packs SYN_STREAM frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| bytes.
* The |*nvbuf_ptr| is used to store inflated name/value pairs in wire
* format temporarily. Its length is |*nvbuflen_ptr| bytes. This
* function expands |*buf_ptr| and |*nvbuf_ptr| as necessary to store
* frame and name/value pairs. When expansion occurred, memory
* previously pointed by |*buf_ptr| and |*nvbuf_ptr| is freed.
* |*buf_ptr|, |*buflen_ptr|, |*nvbuf_ptr| and |*nvbuflen_ptr| are
* updated accordingly.
*
* 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,
size_t *buflen_ptr,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
spdylay_syn_stream *frame,
spdylay_zlib *deflater);
@ -68,12 +79,22 @@ int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
/*
* Packs SYN_REPLY 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
* it it succeeds, or returns negative error code. frame->hd.length is
* assigned after length is determined during packing process.
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| bytes.
* The |*nvbuf_ptr| is used to store inflated name/value pairs in wire
* format temporarily. Its length is |*nvbuflen_ptr| bytes. This
* function expands |*buf_ptr| and |*nvbuf_ptr| as necessary to store
* frame and name/value pairs. When expansion occurred, memory
* previously pointed by |*buf_ptr| and |*nvbuf_ptr| is freed.
* |*buf_ptr|, |*buflen_ptr|, |*nvbuf_ptr| and |*nvbuflen_ptr| are
* updated accordingly. This function returns the size of packed
* frame it 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_reply(uint8_t **buf_ptr,
size_t *buflen_ptr,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
spdylay_syn_reply *frame,
spdylay_zlib *deflater);
@ -88,11 +109,13 @@ int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
/*
* Packs PING frame |frame| in wire format and store it in
* |*buf_ptr|. This function allocates enough memory in |*buf_ptr| to
* store given |frame|. This function returns the size of packed frame
* if it succeeds, or negative error code.
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|. This function returns the size of packed frame if it
* succeeds, or negative error code.
*/
ssize_t spdylay_frame_pack_ping(uint8_t **buf_ptr, spdylay_ping *frame);
ssize_t spdylay_frame_pack_ping(uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_ping *frame);
/*
* Unpacks PING wire format into |frame|. This function returns 0 if
@ -104,11 +127,13 @@ int spdylay_frame_unpack_ping(spdylay_ping *frame,
/*
* Packs GOAWAY frame |frame | in wire format and store it in
* |*buf_ptr|. This function allocates enough memory in |*buf_ptr| to
* store given |frame|. This function returns the size of packed frame
* if it succeeds, or negative error code.
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|. This function returns the size of packed frame if it
* succeeds, or negative error code.
*/
ssize_t spdylay_frame_pack_goaway(uint8_t **buf_ptr, spdylay_goaway *frame);
ssize_t spdylay_frame_pack_goaway(uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_goaway *frame);
/*
* Unpacks GOAWAY wire format into |frame|. This function returns 0 if
@ -120,12 +145,20 @@ int spdylay_frame_unpack_goaway(spdylay_goaway *frame,
/*
* Packs HEADERS frame |frame| in wire format and store it in
* |*buf_ptr|. This function allocates enough memory in |*buf_ptr| to
* store given |frame|. This function returns the size of packed frame
* it it succeeds, or returns negative error code. frame->hd.length is
* assigned after length is determined during packing process.
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| bytes.
* The |*nvbuf_ptr| is used to store inflated name/value pairs in wire
* format temporarily. Its length is |*nvbuflen_ptr| bytes. This
* function expands |*buf_ptr| and |*nvbuf_ptr| as necessary to store
* frame and name/value pairs. When expansion occurred, memory
* previously pointed by |*buf_ptr| and |*nvbuf_ptr| is freed.
* |*buf_ptr|, |*buflen_ptr|, |*nvbuf_ptr| and |*nvbuflen_ptr| are
* updated accordingly. This function returns the size of packed
* frame it it succeeds, or returns negative error
* code. frame->hd.length is assigned after length is determined
* during packing process.
*/
ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr,
ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr,
uint8_t **nvbuf_ptr, size_t *nvbuflen_ptr,
spdylay_headers *frame,
spdylay_zlib *deflater);
@ -140,12 +173,13 @@ int spdylay_frame_unpack_headers(spdylay_headers *frame,
/*
* Packs RST_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|. In spdy/2 spc, RST_STREAM wire format is
* always 16 bytes long. This function returns the size of packed
* frame if it succeeds, or negative error code.
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|. In spdy/2 spc, RST_STREAM wire format is always 16
* bytes long. This function returns the size of packed frame if it
* succeeds, or negative error code.
*/
ssize_t spdylay_frame_pack_rst_stream(uint8_t **buf_ptr,
ssize_t spdylay_frame_pack_rst_stream(uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_rst_stream *frame);
/*
@ -158,11 +192,13 @@ int spdylay_frame_unpack_rst_stream(spdylay_rst_stream *frame,
/*
* Packs SETTINGS frame |frame| in wire 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 negative error code.
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|. This function returns the size of packed frame if it
* succeeds, or negative error code.
*/
ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, spdylay_settings *frame);
ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_settings *frame);
/*
* Unpacks SETTINGS wire format into |frame|. This function returns 0

View File

@ -52,3 +52,19 @@ uint32_t spdylay_get_uint32(const uint8_t *data)
memcpy(&n, data, sizeof(uint32_t));
return ntohl(n);
}
int spdylay_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t min_length)
{
if(min_length > *buflen_ptr) {
uint8_t *temp = malloc(min_length);
if(temp == NULL) {
return SPDYLAY_ERR_NOMEM;
} else {
free(*buf_ptr);
*buf_ptr = temp;
*buflen_ptr = min_length;
}
}
return 0;
}

View File

@ -55,4 +55,18 @@ uint16_t spdylay_get_uint16(const uint8_t *data);
*/
uint32_t spdylay_get_uint32(const uint8_t *data);
/*
* Ensures that buffer |*buf_ptr| with |*buflen_ptr| length has at
* least |min_length| bytes. If |min_length| > |*buflen_ptr|,
* allocates new buffer having at least |min_length| bytes and assigns
* its pointer to |*buf_ptr| and allocated number of bytes to
* |*buflen_ptr|. The memory pointed by |*buf_ptr| previously is
* freed. No memory copy is done between old and new buffer. This
* function returns 0 if it succeeds, or negative error code.
* |*buf_ptr| and |*buflen_ptr| are only updated iff this function
* succeeds.
*/
int spdylay_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t min_length);
#endif /* SPDYLAY_HELPER_H */

View File

@ -130,6 +130,31 @@ static int spdylay_session_new(spdylay_session **session_ptr,
return r;
}
(*session_ptr)->aob.framebuf = malloc(SPDYLAY_INITIAL_OUTBOUND_BUFFER_LENGTH);
if((*session_ptr)->aob.framebuf == NULL) {
spdylay_pq_free(&(*session_ptr)->ob_ss_pq);
spdylay_pq_free(&(*session_ptr)->ob_pq);
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)->aob.framebufmax = SPDYLAY_INITIAL_OUTBOUND_BUFFER_LENGTH;
(*session_ptr)->nvbuf = malloc(SPDYLAY_INITIAL_NV_BUFFER_LENGTH);
if((*session_ptr)->nvbuf == NULL) {
free((*session_ptr)->aob.framebuf);
spdylay_pq_free(&(*session_ptr)->ob_ss_pq);
spdylay_pq_free(&(*session_ptr)->ob_pq);
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)->nvbuflen = SPDYLAY_INITIAL_NV_BUFFER_LENGTH;
memset((*session_ptr)->settings, 0, sizeof((*session_ptr)->settings));
(*session_ptr)->settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] =
SPDYLAY_CONCURRENT_STREAMS_MAX;
@ -244,6 +269,8 @@ void spdylay_session_del(spdylay_session *session)
spdylay_zlib_deflate_free(&session->hd_deflater);
spdylay_zlib_inflate_free(&session->hd_inflater);
free(session->iframe.buf);
free(session->aob.framebuf);
free(session->nvbuf);
free(session);
}
@ -454,12 +481,10 @@ static int spdylay_session_is_data_allowed(spdylay_session *session,
}
ssize_t spdylay_session_prep_frame(spdylay_session *session,
spdylay_outbound_item *item,
uint8_t **framebuf_ptr)
spdylay_outbound_item *item)
{
/* TODO Get or validate stream ID here */
/* TODO Validate assoc_stream_id here */
uint8_t *framebuf;
ssize_t framebuflen;
switch(item->frame_type) {
case SPDYLAY_SYN_STREAM: {
@ -473,7 +498,10 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
stream_id = session->next_stream_id;
item->frame->syn_stream.stream_id = stream_id;
session->next_stream_id += 2;
framebuflen = spdylay_frame_pack_syn_stream(&framebuf,
framebuflen = spdylay_frame_pack_syn_stream(&session->aob.framebuf,
&session->aob.framebufmax,
&session->nvbuf,
&session->nvbuflen,
&item->frame->syn_stream,
&session->hd_deflater);
if(framebuflen < 0) {
@ -485,7 +513,6 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
item->frame->syn_stream.pri,
SPDYLAY_STREAM_INITIAL,
aux_data->stream_user_data) == NULL) {
free(framebuf);
return SPDYLAY_ERR_NOMEM;
}
break;
@ -495,7 +522,10 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
item->frame->syn_reply.stream_id)) {
return SPDYLAY_ERR_INVALID_FRAME;
}
framebuflen = spdylay_frame_pack_syn_reply(&framebuf,
framebuflen = spdylay_frame_pack_syn_reply(&session->aob.framebuf,
&session->aob.framebufmax,
&session->nvbuf,
&session->nvbuflen,
&item->frame->syn_reply,
&session->hd_deflater);
if(framebuflen < 0) {
@ -504,14 +534,16 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
break;
}
case SPDYLAY_RST_STREAM:
framebuflen = spdylay_frame_pack_rst_stream(&framebuf,
framebuflen = spdylay_frame_pack_rst_stream(&session->aob.framebuf,
&session->aob.framebufmax,
&item->frame->rst_stream);
if(framebuflen < 0) {
return framebuflen;
}
break;
case SPDYLAY_SETTINGS:
framebuflen = spdylay_frame_pack_settings(&framebuf,
framebuflen = spdylay_frame_pack_settings(&session->aob.framebuf,
&session->aob.framebufmax,
&item->frame->settings);
if(framebuflen < 0) {
return framebuflen;
@ -522,7 +554,9 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
unreachable. */
abort();
case SPDYLAY_PING:
framebuflen = spdylay_frame_pack_ping(&framebuf, &item->frame->ping);
framebuflen = spdylay_frame_pack_ping(&session->aob.framebuf,
&session->aob.framebufmax,
&item->frame->ping);
if(framebuflen < 0) {
return framebuflen;
}
@ -539,7 +573,9 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
last-good-stream-id. */
return SPDYLAY_ERR_INVALID_FRAME;
}
framebuflen = spdylay_frame_pack_goaway(&framebuf, &item->frame->goaway);
framebuflen = spdylay_frame_pack_goaway(&session->aob.framebuf,
&session->aob.framebufmax,
&item->frame->goaway);
if(framebuflen < 0) {
return framebuflen;
}
@ -548,7 +584,9 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
if(!spdylay_session_is_data_allowed(session, item->frame->data.stream_id)) {
return SPDYLAY_ERR_INVALID_FRAME;
}
framebuflen = spdylay_session_pack_data(session, &framebuf,
framebuflen = spdylay_session_pack_data(session,
&session->aob.framebuf,
&session->aob.framebufmax,
&item->frame->data);
if(framebuflen < 0) {
return framebuflen;
@ -558,7 +596,6 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
default:
framebuflen = SPDYLAY_ERR_INVALID_ARGUMENT;
}
*framebuf_ptr = framebuf;
return framebuflen;
}
@ -567,8 +604,8 @@ static void spdylay_active_outbound_item_reset
{
spdylay_outbound_item_free(aob->item);
free(aob->item);
free(aob->framebuf);
memset(aob, 0, sizeof(spdylay_active_outbound_item));
aob->item = NULL;
aob->framebuflen = aob->framebufoff = 0;
}
spdylay_outbound_item* spdylay_session_get_ob_pq_top
@ -815,13 +852,12 @@ int spdylay_session_send(spdylay_session *session)
ssize_t sentlen;
if(session->aob.item == NULL) {
spdylay_outbound_item *item;
uint8_t *framebuf;
ssize_t framebuflen;
item = spdylay_session_pop_next_ob_item(session);
if(item == NULL) {
break;
}
framebuflen = spdylay_session_prep_frame(session, item, &framebuf);
framebuflen = spdylay_session_prep_frame(session, item);
if(framebuflen < 0) {
/* TODO Call error callback? */
spdylay_outbound_item_free(item);
@ -833,7 +869,6 @@ int spdylay_session_send(spdylay_session *session)
}
}
session->aob.item = item;
session->aob.framebuf = framebuf;
session->aob.framebuflen = framebuflen;
/* Call before_send callback */
if(item->frame_type != SPDYLAY_DATA &&
@ -1582,21 +1617,17 @@ int spdylay_session_add_goaway(spdylay_session *session,
}
ssize_t spdylay_session_pack_data(spdylay_session *session,
uint8_t **buf_ptr, spdylay_data *frame)
uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_data *frame)
{
uint8_t *framebuf;
ssize_t framelen = SPDYLAY_DATA_FRAME_LENGTH;
framebuf = malloc(framelen);
if(framebuf == NULL) {
return SPDYLAY_ERR_NOMEM;
int r;
r = spdylay_reserve_buffer(buf_ptr, buflen_ptr, framelen);
if(r != 0) {
return r;
}
framelen = spdylay_session_pack_data_overwrite(session, framebuf, framelen,
framelen = spdylay_session_pack_data_overwrite(session, *buf_ptr, framelen,
frame);
if(framelen < 0) {
free(framebuf);
} else {
*buf_ptr = framebuf;
}
return framelen;
}

View File

@ -46,8 +46,16 @@ typedef struct {
typedef struct {
spdylay_outbound_item *item;
/* Buffer for outbound frames. Used to pack one frame. The memory
pointed by framebuf is initially allocated by
spdylay_session_{client,server}_new() and deallocated by
spdylay_session_del() */
uint8_t *framebuf;
/* The capacity of framebuf in bytes */
size_t framebufmax;
/* The length of the frame stored in framebuf */
size_t framebuflen;
/* The number of bytes has been sent */
size_t framebufoff;
} spdylay_active_outbound_item;
@ -55,6 +63,9 @@ typedef struct {
message block of SSLv3/TLSv1 */
#define SPDYLAY_INBOUND_BUFFER_LENGTH 16384
#define SPDYLAY_INITIAL_OUTBOUND_BUFFER_LENGTH SPDYLAY_DATA_FRAME_LENGTH
#define SPDYLAY_INITIAL_NV_BUFFER_LENGTH 4096
typedef struct {
uint8_t buf[SPDYLAY_INBOUND_BUFFER_LENGTH];
uint8_t *mark;
@ -114,6 +125,12 @@ struct spdylay_session {
spdylay_inbound_buffer ibuf;
spdylay_inbound_frame iframe;
/* Buffer used to store inflated name/value pairs in wire format
temporarily on pack/unpack. */
uint8_t *nvbuf;
/* The number of bytes allocated for nvbuf */
size_t nvbuflen;
spdylay_zlib hd_deflater;
spdylay_zlib hd_inflater;
@ -274,14 +291,15 @@ spdylay_stream* spdylay_session_get_stream(spdylay_session *session,
/*
* Packs DATA frame |frame| in wire frame format and store it in
* |*buf_ptr|. This function always allocates
* 8+SPDYLAY_DATA_CHUNK_LENGTH bytes. It packs header in first 8
* bytes. Remaining bytes are filled using frame->data_prd. This
* function returns the size of packed frame if it succeeds, or
* negative error code.
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|. It packs header in first 8 bytes. Remaining bytes
* are filled using frame->data_prd. This function returns the size
* of packed frame if it succeeds, or negative error code.
*/
ssize_t spdylay_session_pack_data(spdylay_session *session,
uint8_t **buf_ptr, spdylay_data *frame);
uint8_t **buf_ptr, size_t *buflen_ptr,
spdylay_data *frame);
/*
* Packs DATA frame |frame| in wire frame format and store it in

View File

@ -95,15 +95,16 @@ void test_spdylay_frame_count_unpack_nv_space()
void test_spdylay_frame_pack_ping()
{
spdylay_frame frame, oframe;
uint8_t *buf;
ssize_t buflen;
uint8_t *buf = NULL;
size_t buflen = 0;
ssize_t framelen;
spdylay_frame_ping_init(&frame.ping, 1);
buflen = spdylay_frame_pack_ping(&buf, &frame.ping);
framelen = spdylay_frame_pack_ping(&buf, &buflen, &frame.ping);
CU_ASSERT(0 == spdylay_frame_unpack_ping
(&oframe.ping,
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
buflen-SPDYLAY_FRAME_HEAD_LENGTH));
framelen-SPDYLAY_FRAME_HEAD_LENGTH));
CU_ASSERT(1 == oframe.ping.unique_id);
free(buf);
spdylay_frame_ping_free(&oframe.ping);
@ -113,20 +114,21 @@ void test_spdylay_frame_pack_ping()
void test_spdylay_frame_pack_goaway()
{
spdylay_frame frame, oframe;
uint8_t *buf;
ssize_t buflen;
uint8_t *buf = NULL;
size_t buflen = 0;
ssize_t framelen;
spdylay_frame_goaway_init(&frame.goaway, 1000000007);
buflen = spdylay_frame_pack_goaway(&buf, &frame.goaway);
framelen = spdylay_frame_pack_goaway(&buf, &buflen, &frame.goaway);
CU_ASSERT(0 == spdylay_frame_unpack_goaway
(&oframe.goaway,
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
buflen-SPDYLAY_FRAME_HEAD_LENGTH));
framelen-SPDYLAY_FRAME_HEAD_LENGTH));
CU_ASSERT(1000000007 == oframe.goaway.last_good_stream_id);
CU_ASSERT(SPDYLAY_PROTO_VERSION == oframe.headers.hd.version);
CU_ASSERT(SPDYLAY_GOAWAY == oframe.headers.hd.type);
CU_ASSERT(SPDYLAY_FLAG_NONE == oframe.headers.hd.flags);
CU_ASSERT(buflen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.ping.hd.length);
CU_ASSERT(framelen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.ping.hd.length);
free(buf);
spdylay_frame_goaway_free(&oframe.goaway);
spdylay_frame_goaway_free(&frame.goaway);
@ -136,28 +138,32 @@ void test_spdylay_frame_pack_headers()
{
spdylay_zlib deflater, inflater;
spdylay_frame frame, oframe;
uint8_t *buf;
ssize_t buflen;
uint8_t *buf = NULL, *nvbuf = NULL;
size_t buflen = 0, nvbuflen = 0;
ssize_t framelen;
spdylay_zlib_deflate_hd_init(&deflater);
spdylay_zlib_inflate_hd_init(&inflater);
spdylay_frame_headers_init(&frame.headers, SPDYLAY_FLAG_FIN, 3,
spdylay_frame_nv_copy(headers));
buflen = spdylay_frame_pack_headers(&buf, &frame.headers, &deflater);
framelen = spdylay_frame_pack_headers(&buf, &buflen,
&nvbuf, &nvbuflen,
&frame.headers, &deflater);
CU_ASSERT(0 == spdylay_frame_unpack_headers
(&oframe.headers,
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
buflen-SPDYLAY_FRAME_HEAD_LENGTH,
framelen-SPDYLAY_FRAME_HEAD_LENGTH,
&inflater));
CU_ASSERT(3 == oframe.headers.stream_id);
CU_ASSERT(SPDYLAY_PROTO_VERSION == oframe.headers.hd.version);
CU_ASSERT(SPDYLAY_HEADERS == oframe.headers.hd.type);
CU_ASSERT(SPDYLAY_FLAG_FIN == oframe.headers.hd.flags);
CU_ASSERT(buflen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.ping.hd.length);
CU_ASSERT(framelen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.ping.hd.length);
CU_ASSERT(strcmp("method", oframe.headers.nv[0]) == 0);
CU_ASSERT(strcmp("GET", oframe.headers.nv[1]) == 0);
CU_ASSERT(NULL == oframe.headers.nv[12]);
free(buf);
free(nvbuf);
spdylay_frame_headers_free(&oframe.headers);
spdylay_frame_headers_free(&frame.headers);
spdylay_zlib_inflate_free(&inflater);
@ -167,8 +173,9 @@ void test_spdylay_frame_pack_headers()
void test_spdylay_frame_pack_settings()
{
spdylay_frame frame, oframe;
uint8_t *buf;
ssize_t buflen;
uint8_t *buf = NULL;
size_t buflen = 0;
ssize_t framelen;
int i;
spdylay_settings_entry iv[3];
iv[0].settings_id = SPDYLAY_SETTINGS_UPLOAD_BANDWIDTH;
@ -185,20 +192,20 @@ void test_spdylay_frame_pack_settings()
(&frame.settings,
SPDYLAY_FLAG_SETTINGS_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS,
spdylay_frame_iv_copy(iv, 3), 3);
buflen = spdylay_frame_pack_settings(&buf, &frame.settings);
CU_ASSERT(8+4+3*8 == buflen);
framelen = spdylay_frame_pack_settings(&buf, &buflen, &frame.settings);
CU_ASSERT(8+4+3*8 == framelen);
CU_ASSERT(0 == spdylay_frame_unpack_settings
(&oframe.settings,
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
buflen-SPDYLAY_FRAME_HEAD_LENGTH));
framelen-SPDYLAY_FRAME_HEAD_LENGTH));
CU_ASSERT(SPDYLAY_PROTO_VERSION == oframe.settings.hd.version);
CU_ASSERT(SPDYLAY_SETTINGS == oframe.settings.hd.type);
CU_ASSERT(SPDYLAY_FLAG_SETTINGS_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS ==
oframe.settings.hd.flags);
CU_ASSERT(buflen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.settings.hd.length);
CU_ASSERT(framelen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.settings.hd.length);
CU_ASSERT(3 == oframe.settings.niv);
for(i = 0; i < 3; ++i) {

View File

@ -190,18 +190,22 @@ void test_spdylay_session_recv()
const char *nv[] = {
"url", "/", NULL
};
uint8_t *framedata;
size_t framelen;
uint8_t *framedata = NULL, *nvbuf = NULL;
size_t framedatalen = 0, nvbuflen = 0;
ssize_t framelen;
spdylay_frame frame;
user_data.df = &df;
spdylay_session_client_new(&session, &callbacks, &user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_FLAG_NONE, 0, 0, 3,
dup_nv(nv));
framelen = spdylay_frame_pack_syn_stream(&framedata, &frame.syn_stream,
framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen,
&nvbuf, &nvbuflen,
&frame.syn_stream,
&session->hd_deflater);
scripted_data_feed_init(&df, framedata, framelen);
free(framedata);
free(nvbuf);
spdylay_frame_syn_stream_free(&frame.syn_stream);
CU_ASSERT(0 == spdylay_session_recv(session));
@ -272,8 +276,9 @@ void test_spdylay_session_recv_invalid_stream_id()
scripted_data_feed df;
my_user_data user_data;
const char *nv[] = { NULL };
uint8_t *framedata;
size_t framelen;
uint8_t *framedata = NULL, *nvbuf = NULL;
size_t framedatalen = 0, nvbuflen = 0;
ssize_t framelen;
spdylay_frame frame;
user_data.df = &df;
@ -281,10 +286,11 @@ void test_spdylay_session_recv_invalid_stream_id()
spdylay_session_client_new(&session, &callbacks, &user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_FLAG_NONE, 1, 0, 3,
dup_nv(nv));
framelen = spdylay_frame_pack_syn_stream(&framedata, &frame.syn_stream,
framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen,
&nvbuf, &nvbuflen,
&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));
@ -292,15 +298,18 @@ void test_spdylay_session_recv_invalid_stream_id()
spdylay_frame_syn_reply_init(&frame.syn_reply, SPDYLAY_FLAG_NONE, 100,
dup_nv(nv));
framelen = spdylay_frame_pack_syn_reply(&framedata, &frame.syn_reply,
framelen = spdylay_frame_pack_syn_reply(&framedata, &framedatalen,
&nvbuf, &nvbuflen,
&frame.syn_reply,
&session->hd_deflater);
scripted_data_feed_init(&df, framedata, framelen);
free(framedata);
spdylay_frame_syn_reply_free(&frame.syn_reply);
CU_ASSERT(0 == spdylay_session_recv(session));
CU_ASSERT(2 == user_data.invalid_ctrl_recv_cb_called);
free(framedata);
free(nvbuf);
spdylay_session_del(session);
}