Added spdylay_session_mem_recv()
spdylay_session_mem_recv() processes input bytes as the received data from the remote endpoint. spdylay_session_recv() uses it internally. The spdylay_inbound_buffer and ibuf member in spdylay_session is removed. The buffer is allocated in the stack when spdylay_session_recv() is called.
This commit is contained in:
parent
425a9558d7
commit
742a8bbac9
|
@ -1144,6 +1144,29 @@ int spdylay_session_send(spdylay_session *session);
|
||||||
*/
|
*/
|
||||||
int spdylay_session_recv(spdylay_session *session);
|
int spdylay_session_recv(spdylay_session *session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes data |in| as an input from the remote endpoint. The
|
||||||
|
* |inlen| indicates the number of bytes in the |in|.
|
||||||
|
*
|
||||||
|
* This function behaves like `spdylay_session_recv()` except that it
|
||||||
|
* does not use :member:`spdylay_session_callbacks.recv_callback` to
|
||||||
|
* receive data; the |in| is the only data for the invocation of this
|
||||||
|
* function. If all bytes are processed, this function returns. The
|
||||||
|
* other callbacks are called in the same way as they are in
|
||||||
|
* `spdylay_session_recv()`.
|
||||||
|
*
|
||||||
|
* In the current implementation, this function always tries to
|
||||||
|
* processes all input data unless an error occurs.
|
||||||
|
*
|
||||||
|
* This function returns the number of processed bytes, or one of the
|
||||||
|
* following negative error codes:
|
||||||
|
*
|
||||||
|
* :enum:`SPDYLAY_ERR_NOMEM`
|
||||||
|
* Out of memory.
|
||||||
|
*/
|
||||||
|
ssize_t spdylay_session_mem_recv(spdylay_session *session,
|
||||||
|
const uint8_t *in, size_t inlen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
|
|
|
@ -104,6 +104,13 @@ static int spdylay_outbound_item_compar(const void *lhsx, const void *rhsx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void spdylay_inbound_frame_reset(spdylay_inbound_frame *iframe)
|
||||||
|
{
|
||||||
|
iframe->state = SPDYLAY_RECV_HEAD;
|
||||||
|
iframe->len = iframe->off = 0;
|
||||||
|
iframe->headbufoff = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int spdylay_session_new(spdylay_session **session_ptr,
|
static int spdylay_session_new(spdylay_session **session_ptr,
|
||||||
uint16_t version,
|
uint16_t version,
|
||||||
const spdylay_session_callbacks *callbacks,
|
const spdylay_session_callbacks *callbacks,
|
||||||
|
@ -190,16 +197,13 @@ static int spdylay_session_new(spdylay_session **session_ptr,
|
||||||
(*session_ptr)->callbacks = *callbacks;
|
(*session_ptr)->callbacks = *callbacks;
|
||||||
(*session_ptr)->user_data = user_data;
|
(*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;
|
|
||||||
(*session_ptr)->iframe.buf = malloc(SPDYLAY_INITIAL_INBOUND_FRAMEBUF_LENGTH);
|
(*session_ptr)->iframe.buf = malloc(SPDYLAY_INITIAL_INBOUND_FRAMEBUF_LENGTH);
|
||||||
if((*session_ptr)->iframe.buf == NULL) {
|
if((*session_ptr)->iframe.buf == NULL) {
|
||||||
r = SPDYLAY_ERR_NOMEM;
|
r = SPDYLAY_ERR_NOMEM;
|
||||||
goto fail_iframe_buf;
|
goto fail_iframe_buf;
|
||||||
}
|
}
|
||||||
(*session_ptr)->iframe.bufmax = SPDYLAY_INITIAL_INBOUND_FRAMEBUF_LENGTH;
|
(*session_ptr)->iframe.bufmax = SPDYLAY_INITIAL_INBOUND_FRAMEBUF_LENGTH;
|
||||||
|
spdylay_inbound_frame_reset(&(*session_ptr)->iframe);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1280,29 +1284,14 @@ int spdylay_session_send(spdylay_session *session)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spdylay_inbound_buffer_shift(spdylay_inbound_buffer *ibuf)
|
static ssize_t spdylay_recv(spdylay_session *session, uint8_t *buf, size_t len)
|
||||||
{
|
|
||||||
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;
|
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
|
r = session->callbacks.recv_callback
|
||||||
(session, session->ibuf.limit, recv_max, 0, session->user_data);
|
(session, buf, len, 0, session->user_data);
|
||||||
if(r > 0) {
|
if(r > 0) {
|
||||||
if(r > recv_max) {
|
if(r > len) {
|
||||||
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||||
} else {
|
|
||||||
session->ibuf.limit += r;
|
|
||||||
}
|
}
|
||||||
} else if(r < 0) {
|
} else if(r < 0) {
|
||||||
if(r != SPDYLAY_ERR_WOULDBLOCK) {
|
if(r != SPDYLAY_ERR_WOULDBLOCK) {
|
||||||
|
@ -1312,18 +1301,6 @@ static ssize_t spdylay_recv(spdylay_session *session)
|
||||||
return r;
|
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;
|
|
||||||
iframe->len = iframe->off = 0;
|
|
||||||
iframe->ign = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void spdylay_session_call_on_request_recv
|
static void spdylay_session_call_on_request_recv
|
||||||
(spdylay_session *session, int32_t stream_id)
|
(spdylay_session *session, int32_t stream_id)
|
||||||
{
|
{
|
||||||
|
@ -2049,49 +2026,50 @@ static int spdylay_session_update_recv_window_size(spdylay_session *session,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spdylay_session_recv(spdylay_session *session)
|
ssize_t spdylay_session_mem_recv(spdylay_session *session,
|
||||||
|
const uint8_t *in, size_t inlen)
|
||||||
{
|
{
|
||||||
|
const uint8_t *inmark, *inlimit;
|
||||||
|
inmark = in;
|
||||||
|
inlimit = in+inlen;
|
||||||
while(1) {
|
while(1) {
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
if(session->iframe.state == SPDYLAY_RECV_HEAD) {
|
if(session->iframe.state == SPDYLAY_RECV_HEAD) {
|
||||||
uint32_t payloadlen;
|
uint32_t payloadlen;
|
||||||
if(spdylay_inbound_buffer_avail(&session->ibuf) < SPDYLAY_HEAD_LEN) {
|
size_t remheadbytes;
|
||||||
r = spdylay_recv(session);
|
size_t readlen;
|
||||||
/* If EOF is reached, r == SPDYLAY_ERR_EOF */
|
size_t bufavail = inlimit-inmark;
|
||||||
if(r < 0) {
|
if(bufavail == 0) {
|
||||||
if(r == SPDYLAY_ERR_WOULDBLOCK) {
|
break;
|
||||||
return 0;
|
|
||||||
} else if(r == SPDYLAY_ERR_EOF) {
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(spdylay_inbound_buffer_avail(&session->ibuf) < SPDYLAY_HEAD_LEN) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
session->iframe.state = SPDYLAY_RECV_PAYLOAD;
|
remheadbytes = SPDYLAY_HEAD_LEN-session->iframe.headbufoff;
|
||||||
payloadlen = spdylay_get_uint32(&session->ibuf.mark[4]) &
|
readlen = spdylay_min(remheadbytes, bufavail);
|
||||||
SPDYLAY_LENGTH_MASK;
|
memcpy(session->iframe.headbuf+session->iframe.headbufoff,
|
||||||
memcpy(session->iframe.headbuf, session->ibuf.mark, SPDYLAY_HEAD_LEN);
|
inmark, readlen);
|
||||||
session->ibuf.mark += SPDYLAY_HEAD_LEN;
|
inmark += readlen;
|
||||||
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
session->iframe.headbufoff += readlen;
|
||||||
/* control frame */
|
if(session->iframe.headbufoff == SPDYLAY_HEAD_LEN) {
|
||||||
session->iframe.len = payloadlen;
|
session->iframe.state = SPDYLAY_RECV_PAYLOAD;
|
||||||
r = spdylay_reserve_buffer(&session->iframe.buf,
|
payloadlen = spdylay_get_uint32(&session->iframe.headbuf[4]) &
|
||||||
&session->iframe.bufmax,
|
SPDYLAY_LENGTH_MASK;
|
||||||
session->iframe.len);
|
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||||
if(r != 0) {
|
/* control frame */
|
||||||
/* FATAL */
|
session->iframe.len = payloadlen;
|
||||||
assert(r < SPDYLAY_ERR_FATAL);
|
r = spdylay_reserve_buffer(&session->iframe.buf,
|
||||||
return r;
|
&session->iframe.bufmax,
|
||||||
|
session->iframe.len);
|
||||||
|
if(r != 0) {
|
||||||
|
/* FATAL */
|
||||||
|
assert(r < SPDYLAY_ERR_FATAL);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
session->iframe.off = 0;
|
||||||
|
} else {
|
||||||
|
session->iframe.len = payloadlen;
|
||||||
|
session->iframe.off = 0;
|
||||||
}
|
}
|
||||||
session->iframe.off = 0;
|
|
||||||
} else {
|
} else {
|
||||||
/* TODO validate stream id here */
|
break;
|
||||||
session->iframe.len = payloadlen;
|
|
||||||
session->iframe.off = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(session->iframe.state == SPDYLAY_RECV_PAYLOAD) {
|
if(session->iframe.state == SPDYLAY_RECV_PAYLOAD) {
|
||||||
|
@ -2099,22 +2077,13 @@ int spdylay_session_recv(spdylay_session *session)
|
||||||
size_t bufavail, readlen;
|
size_t bufavail, readlen;
|
||||||
int32_t data_stream_id = 0;
|
int32_t data_stream_id = 0;
|
||||||
uint8_t data_flags = SPDYLAY_DATA_FLAG_NONE;
|
uint8_t data_flags = SPDYLAY_DATA_FLAG_NONE;
|
||||||
if(spdylay_inbound_buffer_avail(&session->ibuf) == 0 &&
|
bufavail = inlimit-inmark;
|
||||||
rempayloadlen > 0) {
|
if(rempayloadlen > 0 && bufavail == 0) {
|
||||||
r = spdylay_recv(session);
|
break;
|
||||||
if(r == 0 || r == SPDYLAY_ERR_WOULDBLOCK) {
|
|
||||||
return 0;
|
|
||||||
} else if(r == SPDYLAY_ERR_EOF) {
|
|
||||||
return r;
|
|
||||||
} else if(r < 0) {
|
|
||||||
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bufavail = spdylay_inbound_buffer_avail(&session->ibuf);
|
readlen = spdylay_min(bufavail, rempayloadlen);
|
||||||
readlen = bufavail < rempayloadlen ? bufavail : rempayloadlen;
|
|
||||||
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||||
memcpy(session->iframe.buf+session->iframe.off,
|
memcpy(session->iframe.buf+session->iframe.off, inmark, readlen);
|
||||||
session->ibuf.mark, readlen);
|
|
||||||
} else {
|
} else {
|
||||||
/* For data frame, We don't buffer data. Instead, just pass
|
/* For data frame, We don't buffer data. Instead, just pass
|
||||||
received data to callback function. */
|
received data to callback function. */
|
||||||
|
@ -2125,13 +2094,13 @@ int spdylay_session_recv(spdylay_session *session)
|
||||||
session->callbacks.on_data_chunk_recv_callback(session,
|
session->callbacks.on_data_chunk_recv_callback(session,
|
||||||
data_flags,
|
data_flags,
|
||||||
data_stream_id,
|
data_stream_id,
|
||||||
session->ibuf.mark,
|
inmark,
|
||||||
readlen,
|
readlen,
|
||||||
session->user_data);
|
session->user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session->iframe.off += readlen;
|
session->iframe.off += readlen;
|
||||||
session->ibuf.mark += readlen;
|
inmark += readlen;
|
||||||
|
|
||||||
if(session->flow_control &&
|
if(session->flow_control &&
|
||||||
!spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
!spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||||
|
@ -2163,7 +2132,29 @@ int spdylay_session_recv(spdylay_session *session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return inmark-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_recv(spdylay_session *session)
|
||||||
|
{
|
||||||
|
uint8_t buf[SPDYLAY_INBOUND_BUFFER_LENGTH];
|
||||||
|
while(1) {
|
||||||
|
ssize_t readlen;
|
||||||
|
readlen = spdylay_recv(session, buf, sizeof(buf));
|
||||||
|
if(readlen > 0) {
|
||||||
|
ssize_t proclen = spdylay_session_mem_recv(session, buf, readlen);
|
||||||
|
if(proclen < 0) {
|
||||||
|
return proclen;
|
||||||
|
}
|
||||||
|
assert(proclen == readlen);
|
||||||
|
} else if(readlen == 0 || readlen == SPDYLAY_ERR_WOULDBLOCK) {
|
||||||
|
return 0;
|
||||||
|
} else if(readlen == SPDYLAY_ERR_EOF) {
|
||||||
|
return readlen;
|
||||||
|
} else if(readlen < 0) {
|
||||||
|
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int spdylay_session_want_read(spdylay_session *session)
|
int spdylay_session_want_read(spdylay_session *session)
|
||||||
|
|
|
@ -53,8 +53,7 @@ typedef struct {
|
||||||
size_t framebufoff;
|
size_t framebufoff;
|
||||||
} spdylay_active_outbound_item;
|
} spdylay_active_outbound_item;
|
||||||
|
|
||||||
/* Buffer length for inbound SPDY frames. Same value for the size of
|
/* Buffer length for inbound raw byte stream. */
|
||||||
message block of SSLv3/TLSv1 */
|
|
||||||
#define SPDYLAY_INBOUND_BUFFER_LENGTH 16384
|
#define SPDYLAY_INBOUND_BUFFER_LENGTH 16384
|
||||||
|
|
||||||
#define SPDYLAY_INITIAL_OUTBOUND_FRAMEBUF_LENGTH (SPDYLAY_DATA_PAYLOAD_LENGTH+8)
|
#define SPDYLAY_INITIAL_OUTBOUND_FRAMEBUF_LENGTH (SPDYLAY_DATA_PAYLOAD_LENGTH+8)
|
||||||
|
@ -64,12 +63,6 @@ typedef struct {
|
||||||
|
|
||||||
#define SPDYLAY_INITIAL_WINDOW_SIZE 65536
|
#define SPDYLAY_INITIAL_WINDOW_SIZE 65536
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t buf[SPDYLAY_INBOUND_BUFFER_LENGTH];
|
|
||||||
uint8_t *mark;
|
|
||||||
uint8_t *limit;
|
|
||||||
} spdylay_inbound_buffer;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPDYLAY_RECV_HEAD,
|
SPDYLAY_RECV_HEAD,
|
||||||
SPDYLAY_RECV_PAYLOAD
|
SPDYLAY_RECV_PAYLOAD
|
||||||
|
@ -84,14 +77,16 @@ typedef enum {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
spdylay_inbound_state state;
|
spdylay_inbound_state state;
|
||||||
uint8_t headbuf[SPDYLAY_HEAD_LEN];
|
uint8_t headbuf[SPDYLAY_HEAD_LEN];
|
||||||
|
/* How many bytes are filled in headbuf */
|
||||||
|
size_t headbufoff;
|
||||||
/* Payload for control frames. It is not used for DATA frames */
|
/* Payload for control frames. It is not used for DATA frames */
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
/* Capacity of buf */
|
/* Capacity of buf */
|
||||||
size_t bufmax;
|
size_t bufmax;
|
||||||
/* length in Length field */
|
/* length in Length field */
|
||||||
size_t len;
|
size_t len;
|
||||||
|
/* How many bytes are filled in buf */
|
||||||
size_t off;
|
size_t off;
|
||||||
uint8_t ign;
|
|
||||||
} spdylay_inbound_frame;
|
} spdylay_inbound_frame;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -128,7 +123,6 @@ struct spdylay_session {
|
||||||
|
|
||||||
spdylay_active_outbound_item aob;
|
spdylay_active_outbound_item aob;
|
||||||
|
|
||||||
spdylay_inbound_buffer ibuf;
|
|
||||||
spdylay_inbound_frame iframe;
|
spdylay_inbound_frame iframe;
|
||||||
|
|
||||||
/* Buffer used to store inflated name/value pairs in wire format
|
/* Buffer used to store inflated name/value pairs in wire format
|
||||||
|
|
Loading…
Reference in New Issue