mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-27 04:09:31 +03:00
-fix (potential) memory leak on certain control flow paths
This commit is contained in:
+348
-346
@@ -37,133 +37,135 @@
|
||||
* the frame is such.
|
||||
* The function waits for the full frame and then changes status
|
||||
* of the session. New stream is created.
|
||||
*
|
||||
*
|
||||
* @param session SPDY_Session whose read buffer is used.
|
||||
*/
|
||||
static void
|
||||
spdyf_handler_read_syn_stream (struct SPDY_Session *session)
|
||||
{
|
||||
size_t name_value_strm_size = 0;
|
||||
unsigned int compressed_data_size;
|
||||
int ret;
|
||||
void *name_value_strm = NULL;
|
||||
struct SPDYF_Control_Frame *frame;
|
||||
struct SPDY_NameValue *headers;
|
||||
|
||||
SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
|
||||
|| SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
|
||||
"the function is called wrong");
|
||||
|
||||
frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
|
||||
|
||||
//handle subheaders
|
||||
if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
|
||||
{
|
||||
if(0 == frame->length)
|
||||
{
|
||||
//protocol error: incomplete frame
|
||||
//we just ignore it since there is no stream id for which to
|
||||
//send RST_STREAM
|
||||
//TODO maybe GOAWAY and closing session is appropriate
|
||||
SPDYF_DEBUG("zero long SYN_STREAM received");
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
free(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
if(SPDY_YES != SPDYF_stream_new(session))
|
||||
{
|
||||
/* waiting for some more fields to create new stream
|
||||
or something went wrong, SPDYF_stream_new has handled the
|
||||
situation */
|
||||
return;
|
||||
}
|
||||
|
||||
session->current_stream_id = session->streams_head->stream_id;
|
||||
if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
|
||||
{
|
||||
//TODO no need to create stream if this happens
|
||||
session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
|
||||
return;
|
||||
}
|
||||
else
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
|
||||
}
|
||||
|
||||
//handle body
|
||||
|
||||
//start reading the compressed name/value pairs (http headers)
|
||||
compressed_data_size = frame->length //everything after length field
|
||||
- 10;//4B stream id, 4B assoc strem id, 2B priority, unused and slot
|
||||
|
||||
if(session->read_buffer_offset - session->read_buffer_beginning < compressed_data_size)
|
||||
{
|
||||
// the full frame is not yet here, try later
|
||||
return;
|
||||
}
|
||||
|
||||
if(compressed_data_size > 0
|
||||
&& SPDY_YES != SPDYF_zlib_inflate(&session->zlib_recv_stream,
|
||||
session->read_buffer + session->read_buffer_beginning,
|
||||
compressed_data_size,
|
||||
&name_value_strm,
|
||||
&name_value_strm_size))
|
||||
{
|
||||
/* something went wrong on inflating,
|
||||
* the state of the stream for decompression is unknown
|
||||
* and we may not be able to read anything more received on
|
||||
* this session,
|
||||
* so it is better to close the session */
|
||||
free(name_value_strm);
|
||||
free(frame);
|
||||
|
||||
/* mark the session for closing and close it, when
|
||||
* everything on the output queue is already written */
|
||||
session->status = SPDY_SESSION_STATUS_FLUSHING;
|
||||
|
||||
SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false);
|
||||
size_t name_value_strm_size = 0;
|
||||
unsigned int compressed_data_size;
|
||||
int ret;
|
||||
void *name_value_strm = NULL;
|
||||
struct SPDYF_Control_Frame *frame;
|
||||
struct SPDY_NameValue *headers;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(0 == name_value_strm_size || 0 == compressed_data_size)
|
||||
{
|
||||
//Protocol error: send RST_STREAM
|
||||
if(SPDY_YES != SPDYF_prepare_rst_stream(session, session->streams_head,
|
||||
SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR))
|
||||
{
|
||||
//no memory, try later to send RST
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = SPDYF_name_value_from_stream(name_value_strm, name_value_strm_size, &headers);
|
||||
if(SPDY_NO == ret)
|
||||
SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
|
||||
|| SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
|
||||
"the function is called wrong");
|
||||
|
||||
frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
|
||||
|
||||
//handle subheaders
|
||||
if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
|
||||
{
|
||||
//memory error, try later
|
||||
free(name_value_strm);
|
||||
if(0 == frame->length)
|
||||
{
|
||||
//protocol error: incomplete frame
|
||||
//we just ignore it since there is no stream id for which to
|
||||
//send RST_STREAM
|
||||
//TODO maybe GOAWAY and closing session is appropriate
|
||||
SPDYF_DEBUG("zero long SYN_STREAM received");
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
free(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
if(SPDY_YES != SPDYF_stream_new(session))
|
||||
{
|
||||
/* waiting for some more fields to create new stream
|
||||
or something went wrong, SPDYF_stream_new has handled the
|
||||
situation */
|
||||
return;
|
||||
}
|
||||
|
||||
session->current_stream_id = session->streams_head->stream_id;
|
||||
if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
|
||||
{
|
||||
//TODO no need to create stream if this happens
|
||||
session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
|
||||
return;
|
||||
}
|
||||
else
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
|
||||
}
|
||||
|
||||
//handle body
|
||||
|
||||
//start reading the compressed name/value pairs (http headers)
|
||||
compressed_data_size = frame->length //everything after length field
|
||||
- 10;//4B stream id, 4B assoc strem id, 2B priority, unused and slot
|
||||
|
||||
if(session->read_buffer_offset - session->read_buffer_beginning < compressed_data_size)
|
||||
{
|
||||
// the full frame is not yet here, try later
|
||||
return;
|
||||
}
|
||||
|
||||
session->streams_head->headers = headers;
|
||||
//inform the application layer for the new stream received
|
||||
if(SPDY_YES != session->daemon->fnew_stream_cb(session->daemon->fcls, session->streams_head))
|
||||
if ( (compressed_data_size > 0) &&
|
||||
(SPDY_YES !=
|
||||
SPDYF_zlib_inflate(&session->zlib_recv_stream,
|
||||
session->read_buffer + session->read_buffer_beginning,
|
||||
compressed_data_size,
|
||||
&name_value_strm,
|
||||
&name_value_strm_size)) )
|
||||
{
|
||||
//memory error, try later
|
||||
/* something went wrong on inflating,
|
||||
* the state of the stream for decompression is unknown
|
||||
* and we may not be able to read anything more received on
|
||||
* this session,
|
||||
* so it is better to close the session */
|
||||
free(name_value_strm);
|
||||
free(frame);
|
||||
|
||||
/* mark the session for closing and close it, when
|
||||
* everything on the output queue is already written */
|
||||
session->status = SPDY_SESSION_STATUS_FLUSHING;
|
||||
|
||||
SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
session->read_buffer_beginning += compressed_data_size;
|
||||
free(name_value_strm);
|
||||
}
|
||||
|
||||
|
||||
if(0 == name_value_strm_size || 0 == compressed_data_size)
|
||||
{
|
||||
//Protocol error: send RST_STREAM
|
||||
if(SPDY_YES != SPDYF_prepare_rst_stream(session, session->streams_head,
|
||||
SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR))
|
||||
{
|
||||
//no memory, try later to send RST
|
||||
free(name_value_strm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = SPDYF_name_value_from_stream(name_value_strm, name_value_strm_size, &headers);
|
||||
if(SPDY_NO == ret)
|
||||
{
|
||||
//memory error, try later
|
||||
free(name_value_strm);
|
||||
return;
|
||||
}
|
||||
|
||||
session->streams_head->headers = headers;
|
||||
//inform the application layer for the new stream received
|
||||
if(SPDY_YES != session->daemon->fnew_stream_cb(session->daemon->fcls, session->streams_head))
|
||||
{
|
||||
//memory error, try later
|
||||
free(name_value_strm);
|
||||
return;
|
||||
}
|
||||
|
||||
session->read_buffer_beginning += compressed_data_size;
|
||||
}
|
||||
|
||||
//SPDYF_DEBUG("syn_stream received: id %i", session->current_stream_id);
|
||||
|
||||
//change state to wait for new frame
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
free(frame);
|
||||
|
||||
//change state to wait for new frame
|
||||
free(name_value_strm);
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
free(frame);
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +174,7 @@ spdyf_handler_read_syn_stream (struct SPDY_Session *session)
|
||||
* the frame is such.
|
||||
* The function waits for the full frame and then changes status
|
||||
* of the session.
|
||||
*
|
||||
*
|
||||
* @param session SPDY_Session whose read buffer is used.
|
||||
*/
|
||||
static void
|
||||
@@ -182,50 +184,50 @@ spdyf_handler_read_goaway (struct SPDY_Session *session)
|
||||
uint32_t last_good_stream_id;
|
||||
uint32_t status_int;
|
||||
enum SPDY_GOAWAY_STATUS status;
|
||||
|
||||
|
||||
SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
|
||||
"the function is called wrong");
|
||||
|
||||
|
||||
frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
|
||||
|
||||
|
||||
if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
|
||||
{
|
||||
//this is a protocol error/attack
|
||||
session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(0 != frame->flags || 8 != frame->length)
|
||||
{
|
||||
//this is a protocol error
|
||||
SPDYF_DEBUG("wrong GOAWAY received");
|
||||
//anyway, it will be handled
|
||||
}
|
||||
|
||||
|
||||
if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length)
|
||||
{
|
||||
//not all fields are received
|
||||
//try later
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//mark that the session is almost closed
|
||||
session->is_goaway_received = true;
|
||||
|
||||
|
||||
if(8 == frame->length)
|
||||
{
|
||||
memcpy(&last_good_stream_id, session->read_buffer + session->read_buffer_beginning, 4);
|
||||
last_good_stream_id = NTOH31(last_good_stream_id);
|
||||
session->read_buffer_beginning += 4;
|
||||
|
||||
|
||||
memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4);
|
||||
status = ntohl(status_int);
|
||||
session->read_buffer_beginning += 4;
|
||||
|
||||
|
||||
//TODO do something with last_good
|
||||
|
||||
|
||||
//SPDYF_DEBUG("Received GOAWAY; status=%i; lastgood=%i",status,last_good_stream_id);
|
||||
|
||||
|
||||
//do something according to the status
|
||||
//TODO
|
||||
switch(status)
|
||||
@@ -237,10 +239,10 @@ spdyf_handler_read_goaway (struct SPDY_Session *session)
|
||||
case SPDY_GOAWAY_STATUS_INTERNAL_ERROR:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//SPDYF_DEBUG("goaway received: status %i", status);
|
||||
}
|
||||
|
||||
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
free(frame);
|
||||
}
|
||||
@@ -251,7 +253,7 @@ spdyf_handler_read_goaway (struct SPDY_Session *session)
|
||||
* the stream moves into closed state and status
|
||||
* of the session is changed. Frames, belonging to this stream, which
|
||||
* are still at the output queue, will be ignored later.
|
||||
*
|
||||
*
|
||||
* @param session SPDY_Session whose read buffer is used.
|
||||
*/
|
||||
static void
|
||||
@@ -262,12 +264,12 @@ spdyf_handler_read_rst_stream (struct SPDY_Session *session)
|
||||
int32_t status_int;
|
||||
//enum SPDY_RST_STREAM_STATUS status; //for debug
|
||||
struct SPDYF_Stream *stream;
|
||||
|
||||
|
||||
SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
|
||||
"the function is called wrong");
|
||||
|
||||
|
||||
frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
|
||||
|
||||
|
||||
if(0 != frame->flags || 8 != frame->length)
|
||||
{
|
||||
//this is a protocol error
|
||||
@@ -276,25 +278,25 @@ spdyf_handler_read_rst_stream (struct SPDY_Session *session)
|
||||
session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length)
|
||||
{
|
||||
//not all fields are received
|
||||
//try later
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4);
|
||||
stream_id = NTOH31(stream_id);
|
||||
session->read_buffer_beginning += 4;
|
||||
|
||||
|
||||
memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4);
|
||||
//status = ntohl(status_int); //for debug
|
||||
session->read_buffer_beginning += 4;
|
||||
|
||||
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
free(frame);
|
||||
|
||||
|
||||
//mark the stream as closed
|
||||
stream = session->streams_head;
|
||||
while(NULL != stream)
|
||||
@@ -307,9 +309,9 @@ spdyf_handler_read_rst_stream (struct SPDY_Session *session)
|
||||
}
|
||||
stream = stream->next;
|
||||
}
|
||||
|
||||
|
||||
//SPDYF_DEBUG("Received RST_STREAM; status=%i; id=%i",status,stream_id);
|
||||
|
||||
|
||||
//do something according to the status
|
||||
//TODO
|
||||
/*switch(status)
|
||||
@@ -323,7 +325,7 @@ spdyf_handler_read_rst_stream (struct SPDY_Session *session)
|
||||
/**
|
||||
* Handler for reading DATA frames. In requests they are used for POST
|
||||
* arguments.
|
||||
*
|
||||
*
|
||||
* @param session SPDY_Session whose read buffer is used.
|
||||
*/
|
||||
static void
|
||||
@@ -332,17 +334,17 @@ spdyf_handler_read_data (struct SPDY_Session *session)
|
||||
int ret;
|
||||
struct SPDYF_Data_Frame * frame;
|
||||
struct SPDYF_Stream * stream;
|
||||
|
||||
|
||||
SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
|
||||
|| SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
|
||||
"the function is called wrong");
|
||||
|
||||
|
||||
//SPDYF_DEBUG("DATA frame received (POST?). Ignoring");
|
||||
|
||||
|
||||
//SPDYF_SIGINT("");
|
||||
|
||||
|
||||
frame = (struct SPDYF_Data_Frame *)session->frame_handler_cls;
|
||||
|
||||
|
||||
//handle subheaders
|
||||
if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
|
||||
{
|
||||
@@ -354,41 +356,41 @@ spdyf_handler_read_data (struct SPDY_Session *session)
|
||||
else
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
|
||||
}
|
||||
|
||||
|
||||
//handle body
|
||||
|
||||
|
||||
if(session->read_buffer_offset - session->read_buffer_beginning
|
||||
>= frame->length)
|
||||
{
|
||||
stream = SPDYF_stream_find(frame->stream_id, session);
|
||||
|
||||
|
||||
if(NULL == stream || stream->is_in_closed || NULL == session->daemon->received_data_cb)
|
||||
{
|
||||
if(NULL == session->daemon->received_data_cb)
|
||||
SPDYF_DEBUG("No callback for DATA frame set; Ignoring DATA frame!");
|
||||
|
||||
|
||||
//TODO send error?
|
||||
|
||||
|
||||
//TODO for now ignore frame
|
||||
session->read_buffer_beginning += frame->length;
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
free(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ret = session->daemon->freceived_data_cb(session->daemon->cls,
|
||||
stream,
|
||||
session->read_buffer + session->read_buffer_beginning,
|
||||
frame->length,
|
||||
0 == (SPDY_DATA_FLAG_FIN & frame->flags));
|
||||
|
||||
|
||||
session->read_buffer_beginning += frame->length;
|
||||
|
||||
stream->window_size -= frame->length;
|
||||
|
||||
|
||||
stream->window_size -= frame->length;
|
||||
|
||||
//TODO close in and send rst maybe
|
||||
SPDYF_ASSERT(SPDY_YES == ret, "Cancel POST data is not yet implemented");
|
||||
|
||||
|
||||
if(SPDY_DATA_FLAG_FIN & frame->flags)
|
||||
{
|
||||
stream->is_in_closed = true;
|
||||
@@ -398,7 +400,7 @@ spdyf_handler_read_data (struct SPDY_Session *session)
|
||||
//very simple implementation of flow control
|
||||
//when the window's size is under the half of the initial value,
|
||||
//increase it again up to the initial value
|
||||
|
||||
|
||||
//prepare WINDOW_UPDATE
|
||||
if(SPDY_YES == SPDYF_prepare_window_update(session, stream,
|
||||
SPDYF_INITIAL_WINDOW_SIZE - stream->window_size))
|
||||
@@ -407,15 +409,15 @@ spdyf_handler_read_data (struct SPDY_Session *session)
|
||||
}
|
||||
//else: do it later
|
||||
}
|
||||
|
||||
|
||||
//SPDYF_DEBUG("data received: id %i", frame->stream_id);
|
||||
|
||||
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
free(frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
SPDYF_handler_write_syn_reply (struct SPDY_Session *session)
|
||||
{
|
||||
@@ -427,9 +429,9 @@ SPDYF_handler_write_syn_reply (struct SPDY_Session *session)
|
||||
size_t used_data=0;
|
||||
size_t total_size;
|
||||
uint32_t stream_id_nbo;
|
||||
|
||||
|
||||
SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
|
||||
|
||||
|
||||
memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
|
||||
|
||||
if(SPDY_YES != SPDYF_zlib_deflate(&session->zlib_send_stream,
|
||||
@@ -445,12 +447,12 @@ SPDYF_handler_write_syn_reply (struct SPDY_Session *session)
|
||||
* this session,
|
||||
* so it is better to close the session right now */
|
||||
session->status = SPDY_SESSION_STATUS_CLOSING;
|
||||
|
||||
|
||||
free(compressed_headers);
|
||||
|
||||
return SPDY_NO;
|
||||
}
|
||||
|
||||
|
||||
//TODO do we need this used_Data
|
||||
SPDYF_ASSERT(used_data == response_queue->data_size, "not everything was used by zlib");
|
||||
|
||||
@@ -461,22 +463,22 @@ SPDYF_handler_write_syn_reply (struct SPDY_Session *session)
|
||||
if(NULL == (session->write_buffer = malloc(total_size)))
|
||||
{
|
||||
/* no memory
|
||||
* since we do not save the compressed data anywhere and
|
||||
* the sending zlib stream is already in new state, we must
|
||||
* close the session */
|
||||
* since we do not save the compressed data anywhere and
|
||||
* the sending zlib stream is already in new state, we must
|
||||
* close the session */
|
||||
session->status = SPDY_SESSION_STATUS_CLOSING;
|
||||
|
||||
|
||||
free(compressed_headers);
|
||||
|
||||
|
||||
return SPDY_NO;
|
||||
}
|
||||
session->write_buffer_beginning = 0;
|
||||
session->write_buffer_offset = 0;
|
||||
session->write_buffer_size = total_size;
|
||||
|
||||
|
||||
control_frame.length = compressed_headers_size + 4; // compressed data + stream_id
|
||||
SPDYF_CONTROL_FRAME_HTON(&control_frame);
|
||||
|
||||
|
||||
//put frame headers to write buffer
|
||||
memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
|
||||
session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
|
||||
@@ -489,7 +491,7 @@ SPDYF_handler_write_syn_reply (struct SPDY_Session *session)
|
||||
//put compressed name/value pairs to write buffer
|
||||
memcpy(session->write_buffer + session->write_buffer_offset, compressed_headers, compressed_headers_size);
|
||||
session->write_buffer_offset += compressed_headers_size;
|
||||
|
||||
|
||||
SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
|
||||
SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
|
||||
|
||||
@@ -502,15 +504,15 @@ SPDYF_handler_write_syn_reply (struct SPDY_Session *session)
|
||||
&compressed_headers_size);
|
||||
*/
|
||||
free(compressed_headers);
|
||||
|
||||
|
||||
session->last_replied_to_stream_id = stream->stream_id;
|
||||
|
||||
|
||||
//SPDYF_DEBUG("syn_reply sent: id %i", stream->stream_id);
|
||||
|
||||
return SPDY_YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
SPDYF_handler_write_goaway (struct SPDY_Session *session)
|
||||
{
|
||||
@@ -518,13 +520,13 @@ SPDYF_handler_write_goaway (struct SPDY_Session *session)
|
||||
struct SPDYF_Control_Frame control_frame;
|
||||
size_t total_size;
|
||||
int last_good_stream_id;
|
||||
|
||||
|
||||
SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
|
||||
|
||||
|
||||
memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
|
||||
|
||||
|
||||
session->is_goaway_sent = true;
|
||||
|
||||
|
||||
total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
|
||||
+ 4 // last good stream id as "subheader"
|
||||
+ 4; // status code as "subheader"
|
||||
@@ -536,10 +538,10 @@ SPDYF_handler_write_goaway (struct SPDY_Session *session)
|
||||
session->write_buffer_beginning = 0;
|
||||
session->write_buffer_offset = 0;
|
||||
session->write_buffer_size = total_size;
|
||||
|
||||
|
||||
control_frame.length = 8; // always for GOAWAY
|
||||
SPDYF_CONTROL_FRAME_HTON(&control_frame);
|
||||
|
||||
|
||||
//put frame headers to write buffer
|
||||
memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
|
||||
session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
|
||||
@@ -548,22 +550,22 @@ SPDYF_handler_write_goaway (struct SPDY_Session *session)
|
||||
last_good_stream_id = HTON31(session->last_replied_to_stream_id);
|
||||
memcpy(session->write_buffer + session->write_buffer_offset, &last_good_stream_id, 4);
|
||||
session->write_buffer_offset += 4;
|
||||
|
||||
|
||||
//put "data" to write buffer. This is the status
|
||||
memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 4);
|
||||
session->write_buffer_offset += 4;
|
||||
//data is not freed by the destroy function so:
|
||||
//free(response_queue->data);
|
||||
|
||||
|
||||
//SPDYF_DEBUG("goaway sent: status %i", NTOH31(*(uint32_t*)(response_queue->data)));
|
||||
|
||||
|
||||
SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
|
||||
SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
|
||||
|
||||
return SPDY_YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
{
|
||||
@@ -573,16 +575,16 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
struct SPDYF_Data_Frame data_frame;
|
||||
ssize_t ret;
|
||||
bool more;
|
||||
|
||||
|
||||
SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
|
||||
|
||||
|
||||
memcpy(&data_frame, response_queue->data_frame, sizeof(data_frame));
|
||||
|
||||
if(NULL == response_queue->response->rcb)
|
||||
{
|
||||
//standard response with data into the struct
|
||||
SPDYF_ASSERT(NULL != response_queue->data, "no data for the response");
|
||||
|
||||
|
||||
total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header
|
||||
+ response_queue->data_size;
|
||||
|
||||
@@ -593,7 +595,7 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
session->write_buffer_beginning = 0;
|
||||
session->write_buffer_offset = 0;
|
||||
session->write_buffer_size = total_size;
|
||||
|
||||
|
||||
data_frame.length = response_queue->data_size;
|
||||
SPDYF_DATA_FRAME_HTON(&data_frame);
|
||||
|
||||
@@ -610,7 +612,7 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
/* response with callbacks. The lib will produce more than 1
|
||||
* data frames
|
||||
*/
|
||||
|
||||
|
||||
total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header
|
||||
+ SPDY_MAX_SUPPORTED_FRAME_SIZE; //max possible size
|
||||
|
||||
@@ -621,17 +623,17 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
session->write_buffer_beginning = 0;
|
||||
session->write_buffer_offset = 0;
|
||||
session->write_buffer_size = total_size;
|
||||
|
||||
|
||||
ret = response_queue->response->rcb(response_queue->response->rcb_cls,
|
||||
session->write_buffer + sizeof(struct SPDYF_Data_Frame),
|
||||
response_queue->response->rcb_block_size,
|
||||
&more);
|
||||
|
||||
|
||||
if(ret < 0 || ret > response_queue->response->rcb_block_size)
|
||||
{
|
||||
free(session->write_buffer);
|
||||
session->write_buffer = NULL;
|
||||
|
||||
|
||||
//send RST_STREAM
|
||||
if(SPDY_YES == (ret = SPDYF_prepare_rst_stream(session,
|
||||
response_queue->stream,
|
||||
@@ -639,12 +641,12 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
{
|
||||
return SPDY_NO;
|
||||
}
|
||||
|
||||
|
||||
//else no memory
|
||||
//for now close session
|
||||
//TODO what?
|
||||
session->status = SPDY_SESSION_STATUS_CLOSING;
|
||||
|
||||
|
||||
return SPDY_NO;
|
||||
}
|
||||
if(0 == ret && more)
|
||||
@@ -653,7 +655,7 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
free(session->write_buffer);
|
||||
session->write_buffer = NULL;
|
||||
session->write_buffer_size = 0;
|
||||
|
||||
|
||||
if(NULL != response_queue->next)
|
||||
{
|
||||
//put the frame at the end of the queue
|
||||
@@ -665,10 +667,10 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
response_queue->next = NULL;
|
||||
session->response_queue_tail = response_queue;
|
||||
}
|
||||
|
||||
|
||||
return SPDY_YES;
|
||||
}
|
||||
|
||||
|
||||
if(more)
|
||||
{
|
||||
//create another response queue object to call the user cb again
|
||||
@@ -686,12 +688,12 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
//TODO send RST_STREAM
|
||||
//for now close session
|
||||
session->status = SPDY_SESSION_STATUS_CLOSING;
|
||||
|
||||
|
||||
free(session->write_buffer);
|
||||
session->write_buffer = NULL;
|
||||
return SPDY_NO;
|
||||
}
|
||||
|
||||
|
||||
//put it at second position on the queue
|
||||
new_response_queue->prev = response_queue;
|
||||
new_response_queue->next = response_queue->next;
|
||||
@@ -704,7 +706,7 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
response_queue->next->prev = new_response_queue;
|
||||
}
|
||||
response_queue->next = new_response_queue;
|
||||
|
||||
|
||||
response_queue->frqcb = NULL;
|
||||
response_queue->frqcb_cls = NULL;
|
||||
response_queue->rrcb = NULL;
|
||||
@@ -714,7 +716,7 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
{
|
||||
data_frame.flags |= SPDY_DATA_FLAG_FIN;
|
||||
}
|
||||
|
||||
|
||||
data_frame.length = ret;
|
||||
SPDYF_DATA_FRAME_HTON(&data_frame);
|
||||
|
||||
@@ -726,27 +728,27 @@ SPDYF_handler_write_data (struct SPDY_Session *session)
|
||||
session->write_buffer_offset += ret;
|
||||
session->write_buffer_size = session->write_buffer_offset;
|
||||
}
|
||||
|
||||
|
||||
//SPDYF_DEBUG("data sent: id %i", NTOH31(data_frame.stream_id));
|
||||
|
||||
SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
|
||||
SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
|
||||
|
||||
|
||||
return SPDY_YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
SPDYF_handler_write_rst_stream (struct SPDY_Session *session)
|
||||
{
|
||||
struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
|
||||
struct SPDYF_Control_Frame control_frame;
|
||||
size_t total_size;
|
||||
|
||||
|
||||
SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
|
||||
|
||||
|
||||
memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
|
||||
|
||||
|
||||
total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
|
||||
+ 4 // stream id as "subheader"
|
||||
+ 4; // status code as "subheader"
|
||||
@@ -758,40 +760,40 @@ SPDYF_handler_write_rst_stream (struct SPDY_Session *session)
|
||||
session->write_buffer_beginning = 0;
|
||||
session->write_buffer_offset = 0;
|
||||
session->write_buffer_size = total_size;
|
||||
|
||||
|
||||
control_frame.length = 8; // always for RST_STREAM
|
||||
SPDYF_CONTROL_FRAME_HTON(&control_frame);
|
||||
|
||||
|
||||
//put frame headers to write buffer
|
||||
memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
|
||||
session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
|
||||
|
||||
|
||||
//put stream id to write buffer. This is the status
|
||||
memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 8);
|
||||
session->write_buffer_offset += 8;
|
||||
//data is not freed by the destroy function so:
|
||||
//free(response_queue->data);
|
||||
|
||||
|
||||
//SPDYF_DEBUG("rst_stream sent: id %i", NTOH31((((uint64_t)response_queue->data) & 0xFFFF0000) >> 32));
|
||||
|
||||
|
||||
SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
|
||||
SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
|
||||
|
||||
return SPDY_YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
SPDYF_handler_write_window_update (struct SPDY_Session *session)
|
||||
{
|
||||
struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
|
||||
struct SPDYF_Control_Frame control_frame;
|
||||
size_t total_size;
|
||||
|
||||
|
||||
SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
|
||||
|
||||
|
||||
memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
|
||||
|
||||
|
||||
total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
|
||||
+ 4 // stream id as "subheader"
|
||||
+ 4; // delta-window-size as "subheader"
|
||||
@@ -803,20 +805,20 @@ SPDYF_handler_write_window_update (struct SPDY_Session *session)
|
||||
session->write_buffer_beginning = 0;
|
||||
session->write_buffer_offset = 0;
|
||||
session->write_buffer_size = total_size;
|
||||
|
||||
|
||||
control_frame.length = 8; // always for WINDOW_UPDATE
|
||||
SPDYF_CONTROL_FRAME_HTON(&control_frame);
|
||||
|
||||
|
||||
//put frame headers to write buffer
|
||||
memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
|
||||
session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
|
||||
|
||||
|
||||
//put stream id and delta-window-size to write buffer
|
||||
memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 8);
|
||||
session->write_buffer_offset += 8;
|
||||
|
||||
|
||||
//SPDYF_DEBUG("window_update sent: id %i", NTOH31((((uint64_t)response_queue->data) & 0xFFFF0000) >> 32));
|
||||
|
||||
|
||||
SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
|
||||
SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
|
||||
|
||||
@@ -828,14 +830,14 @@ void
|
||||
SPDYF_handler_ignore_frame (struct SPDY_Session *session)
|
||||
{
|
||||
struct SPDYF_Control_Frame *frame;
|
||||
|
||||
|
||||
SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
|
||||
|| SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
|
||||
"the function is called wrong");
|
||||
|
||||
|
||||
|
||||
|
||||
frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
|
||||
|
||||
|
||||
//handle subheaders
|
||||
if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
|
||||
{
|
||||
@@ -847,9 +849,9 @@ SPDYF_handler_ignore_frame (struct SPDY_Session *session)
|
||||
else
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
|
||||
}
|
||||
|
||||
|
||||
//handle body
|
||||
|
||||
|
||||
if(session->read_buffer_offset - session->read_buffer_beginning
|
||||
>= frame->length)
|
||||
{
|
||||
@@ -866,7 +868,7 @@ SPDYF_session_read (struct SPDY_Session *session)
|
||||
int bytes_read;
|
||||
bool reallocate;
|
||||
size_t actual_buf_size;
|
||||
|
||||
|
||||
if(SPDY_SESSION_STATUS_CLOSING == session->status
|
||||
|| SPDY_SESSION_STATUS_FLUSHING == session->status)
|
||||
return SPDY_NO;
|
||||
@@ -882,40 +884,40 @@ SPDYF_session_read (struct SPDY_Session *session)
|
||||
switch(session->status)
|
||||
{
|
||||
case SPDY_SESSION_STATUS_WAIT_FOR_HEADER:
|
||||
|
||||
|
||||
case SPDY_SESSION_STATUS_IGNORE_BYTES:
|
||||
//we need space for a whole control frame header
|
||||
if(actual_buf_size < sizeof(struct SPDYF_Control_Frame))
|
||||
reallocate = true;
|
||||
break;
|
||||
|
||||
|
||||
case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER:
|
||||
|
||||
|
||||
case SPDY_SESSION_STATUS_WAIT_FOR_BODY:
|
||||
//we need as many bytes as set in length field of the
|
||||
//header
|
||||
SPDYF_ASSERT(NULL != session->frame_handler_cls,
|
||||
"no frame for session");
|
||||
if(session->frame_handler != &spdyf_handler_read_data)
|
||||
{
|
||||
{
|
||||
if(actual_buf_size
|
||||
< ((struct SPDYF_Control_Frame *)session->frame_handler_cls)->length)
|
||||
reallocate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
if(actual_buf_size
|
||||
< ((struct SPDYF_Data_Frame *)session->frame_handler_cls)->length)
|
||||
reallocate = true;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case SPDY_SESSION_STATUS_CLOSING:
|
||||
case SPDY_SESSION_STATUS_FLUSHING:
|
||||
//nothing needed
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(reallocate)
|
||||
{
|
||||
//reuse the space in the buffer that was already read by the lib
|
||||
@@ -933,24 +935,24 @@ SPDYF_session_read (struct SPDY_Session *session)
|
||||
return SPDY_NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
session->last_activity = SPDYF_monotonic_time();
|
||||
|
||||
//actual read from the TLS socket
|
||||
bytes_read = session->fio_recv(session,
|
||||
session->read_buffer + session->read_buffer_offset,
|
||||
session->read_buffer_size - session->read_buffer_offset);
|
||||
|
||||
|
||||
switch(bytes_read)
|
||||
{
|
||||
case SPDY_IO_ERROR_CLOSED:
|
||||
//The TLS connection was closed by the other party, clean
|
||||
//The TLS connection was closed by the other party, clean
|
||||
//or not
|
||||
shutdown (session->socket_fd, SHUT_RD);
|
||||
session->read_closed = true;
|
||||
session->status = SPDY_SESSION_STATUS_CLOSING;
|
||||
return SPDY_YES;
|
||||
|
||||
|
||||
case SPDY_IO_ERROR_ERROR:
|
||||
//any kind of error in the TLS subsystem
|
||||
//try to prepare GOAWAY frame
|
||||
@@ -958,17 +960,17 @@ SPDYF_session_read (struct SPDY_Session *session)
|
||||
//try to flush the queue when write is called
|
||||
session->status = SPDY_SESSION_STATUS_FLUSHING;
|
||||
return SPDY_YES;
|
||||
|
||||
|
||||
case SPDY_IO_ERROR_AGAIN:
|
||||
//read or write should be called again; leave it for the
|
||||
//next time
|
||||
return SPDY_NO;
|
||||
|
||||
|
||||
//default:
|
||||
//something was really read from the TLS subsystem
|
||||
//just continue
|
||||
}
|
||||
|
||||
|
||||
session->read_buffer_offset += bytes_read;
|
||||
|
||||
return SPDY_YES;
|
||||
@@ -983,13 +985,13 @@ SPDYF_session_write (struct SPDY_Session *session,
|
||||
int bytes_written;
|
||||
struct SPDYF_Response_Queue *queue_head;
|
||||
struct SPDYF_Response_Queue *response_queue;
|
||||
|
||||
|
||||
if(SPDY_SESSION_STATUS_CLOSING == session->status)
|
||||
return SPDY_NO;
|
||||
|
||||
|
||||
if(SPDY_NO == session->fio_before_write(session))
|
||||
return SPDY_NO;
|
||||
|
||||
|
||||
for(i=0;
|
||||
only_one_frame
|
||||
? i < 1
|
||||
@@ -1002,7 +1004,7 @@ SPDYF_session_write (struct SPDY_Session *session,
|
||||
{
|
||||
//discard frames on closed streams
|
||||
response_queue = session->response_queue_head;
|
||||
|
||||
|
||||
while(NULL != response_queue)
|
||||
{
|
||||
//if stream is closed, remove not yet sent frames
|
||||
@@ -1012,21 +1014,21 @@ SPDYF_session_write (struct SPDY_Session *session,
|
||||
if(NULL == response_queue->stream
|
||||
|| !response_queue->stream->is_out_closed)
|
||||
break;
|
||||
|
||||
|
||||
DLL_remove(session->response_queue_head,session->response_queue_tail,response_queue);
|
||||
|
||||
|
||||
if(NULL != response_queue->frqcb)
|
||||
{
|
||||
response_queue->frqcb(response_queue->frqcb_cls, response_queue, SPDY_RESPONSE_RESULT_STREAM_CLOSED);
|
||||
}
|
||||
|
||||
|
||||
SPDYF_response_queue_destroy(response_queue);
|
||||
response_queue = session->response_queue_head;
|
||||
}
|
||||
|
||||
|
||||
if(NULL == session->response_queue_head)
|
||||
break;//nothing on the queue
|
||||
|
||||
|
||||
//get next data from queue and put it to the write buffer
|
||||
// to send it
|
||||
if(SPDY_NO == session->response_queue_head->process_response_handler(session))
|
||||
@@ -1047,15 +1049,15 @@ SPDYF_session_write (struct SPDY_Session *session,
|
||||
}
|
||||
return SPDY_YES;
|
||||
}
|
||||
|
||||
|
||||
//just return from the loop to return from this function
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//check if something was prepared for writing
|
||||
//on respones with callbacks it is possible that their is no
|
||||
//data available
|
||||
//data available
|
||||
if(0 == session->write_buffer_size)//nothing to write
|
||||
{
|
||||
if(response_queue != session->response_queue_head)
|
||||
@@ -1073,41 +1075,41 @@ SPDYF_session_write (struct SPDY_Session *session,
|
||||
}
|
||||
|
||||
session->last_activity = SPDYF_monotonic_time();
|
||||
|
||||
|
||||
//actual write to the IO
|
||||
bytes_written = session->fio_send(session,
|
||||
session->write_buffer + session->write_buffer_beginning,
|
||||
session->write_buffer_offset - session->write_buffer_beginning);
|
||||
|
||||
|
||||
switch(bytes_written)
|
||||
{
|
||||
case SPDY_IO_ERROR_CLOSED:
|
||||
//The TLS connection was closed by the other party, clean
|
||||
//The TLS connection was closed by the other party, clean
|
||||
//or not
|
||||
shutdown (session->socket_fd, SHUT_RD);
|
||||
session->read_closed = true;
|
||||
session->status = SPDY_SESSION_STATUS_CLOSING;
|
||||
return SPDY_YES;
|
||||
|
||||
|
||||
case SPDY_IO_ERROR_ERROR:
|
||||
//any kind of error in the TLS subsystem
|
||||
//forbid more writing
|
||||
session->status = SPDY_SESSION_STATUS_CLOSING;
|
||||
return SPDY_YES;
|
||||
|
||||
|
||||
case SPDY_IO_ERROR_AGAIN:
|
||||
//read or write should be called again; leave it for the
|
||||
//next time; return from the function as we do not now
|
||||
//whether reading or writing is needed
|
||||
return i>0 ? SPDY_YES : SPDY_NO;
|
||||
|
||||
|
||||
//default:
|
||||
//something was really read from the TLS subsystem
|
||||
//just continue
|
||||
}
|
||||
|
||||
|
||||
session->write_buffer_beginning += bytes_written;
|
||||
|
||||
|
||||
//check if the full buffer was written
|
||||
if(session->write_buffer_beginning == session->write_buffer_size)
|
||||
{
|
||||
@@ -1126,16 +1128,16 @@ SPDYF_session_write (struct SPDY_Session *session,
|
||||
session->response_queue_head = queue_head->next;
|
||||
session->response_queue_head->prev = NULL;
|
||||
}
|
||||
|
||||
|
||||
//set stream to closed if the frame's fin flag is set
|
||||
SPDYF_stream_set_flags_on_write(queue_head);
|
||||
|
||||
|
||||
if(NULL != queue_head->frqcb)
|
||||
{
|
||||
//application layer callback to notify sending of the response
|
||||
queue_head->frqcb(queue_head->frqcb_cls, queue_head, SPDY_RESPONSE_RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
SPDYF_response_queue_destroy(queue_head);
|
||||
}
|
||||
}
|
||||
@@ -1143,7 +1145,7 @@ SPDYF_session_write (struct SPDY_Session *session,
|
||||
if(SPDY_SESSION_STATUS_FLUSHING == session->status
|
||||
&& NULL == session->response_queue_head)
|
||||
session->status = SPDY_SESSION_STATUS_CLOSING;
|
||||
|
||||
|
||||
//return i>0 ? SPDY_YES : SPDY_NO;
|
||||
return session->fio_after_write(session, i>0 ? SPDY_YES : SPDY_NO);
|
||||
}
|
||||
@@ -1156,7 +1158,7 @@ SPDYF_session_idle (struct SPDY_Session *session)
|
||||
size_t frame_length;
|
||||
struct SPDYF_Control_Frame* control_frame;
|
||||
struct SPDYF_Data_Frame *data_frame;
|
||||
|
||||
|
||||
//prepare session for closing if timeout is used and already passed
|
||||
if(SPDY_SESSION_STATUS_CLOSING != session->status
|
||||
&& session->daemon->session_timeout
|
||||
@@ -1167,7 +1169,7 @@ SPDYF_session_idle (struct SPDY_Session *session)
|
||||
SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_OK, true);
|
||||
SPDYF_session_write(session,true);
|
||||
}
|
||||
|
||||
|
||||
switch(session->status)
|
||||
{
|
||||
//expect new frame to arrive
|
||||
@@ -1190,14 +1192,14 @@ SPDYF_session_idle (struct SPDY_Session *session)
|
||||
SPDYF_DEBUG("No memory");
|
||||
return SPDY_NO;
|
||||
}
|
||||
|
||||
|
||||
//get frame headers
|
||||
memcpy(control_frame,
|
||||
session->read_buffer + session->read_buffer_beginning,
|
||||
sizeof(struct SPDYF_Control_Frame));
|
||||
session->read_buffer_beginning += sizeof(struct SPDYF_Control_Frame);
|
||||
SPDYF_CONTROL_FRAME_NTOH(control_frame);
|
||||
|
||||
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER;
|
||||
//assign different frame handler according to frame type
|
||||
switch(control_frame->type){
|
||||
@@ -1225,14 +1227,14 @@ SPDYF_session_idle (struct SPDY_Session *session)
|
||||
SPDYF_DEBUG("No memory");
|
||||
return SPDY_NO;
|
||||
}
|
||||
|
||||
|
||||
//get frame headers
|
||||
memcpy(data_frame,
|
||||
session->read_buffer + session->read_buffer_beginning,
|
||||
sizeof(struct SPDYF_Data_Frame));
|
||||
session->read_buffer_beginning += sizeof(struct SPDYF_Data_Frame);
|
||||
SPDYF_DATA_FRAME_NTOH(data_frame);
|
||||
|
||||
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
|
||||
session->frame_handler = &spdyf_handler_read_data;
|
||||
session->frame_handler_cls = data_frame;
|
||||
@@ -1241,15 +1243,15 @@ SPDYF_session_idle (struct SPDY_Session *session)
|
||||
else
|
||||
{
|
||||
SPDYF_DEBUG("another protocol or version received!");
|
||||
|
||||
|
||||
/* According to the draft the lib should send here
|
||||
* RST_STREAM with status UNSUPPORTED_VERSION. I don't
|
||||
* see any sense of keeping the session open since
|
||||
* we don't know how many bytes is the bogus "frame".
|
||||
* And the latter normally will be HTTP request.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
//shutdown(session->socket_fd, SHUT_RD);
|
||||
session->status = SPDY_SESSION_STATUS_FLUSHING;
|
||||
SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_PROTOCOL_ERROR,false);
|
||||
@@ -1259,7 +1261,7 @@ SPDYF_session_idle (struct SPDY_Session *session)
|
||||
//SPDYF_session_close(session);
|
||||
return SPDY_YES;
|
||||
}
|
||||
|
||||
|
||||
//expect specific header fields after the standard header
|
||||
case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER:
|
||||
if(NULL!=session->frame_handler)
|
||||
@@ -1268,52 +1270,52 @@ SPDYF_session_idle (struct SPDY_Session *session)
|
||||
//if everything is ok, the "body" will also be processed
|
||||
//by the handler
|
||||
session->frame_handler(session);
|
||||
|
||||
|
||||
if(SPDY_SESSION_STATUS_IGNORE_BYTES == session->status)
|
||||
{
|
||||
//check for larger than max supported frame
|
||||
if(session->frame_handler != &spdyf_handler_read_data)
|
||||
{
|
||||
{
|
||||
frame_length = ((struct SPDYF_Control_Frame *)session->frame_handler_cls)->length;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
frame_length = ((struct SPDYF_Data_Frame *)session->frame_handler_cls)->length;
|
||||
}
|
||||
|
||||
|
||||
//if(SPDY_MAX_SUPPORTED_FRAME_SIZE < frame_length)
|
||||
{
|
||||
SPDYF_DEBUG("received frame with unsupported size: %zu", frame_length);
|
||||
//the data being received must be ignored and
|
||||
//RST_STREAM sent
|
||||
|
||||
|
||||
//ignore bytes that will arive later
|
||||
session->read_ignore_bytes = frame_length
|
||||
+ read_buffer_beginning
|
||||
- session->read_buffer_offset;
|
||||
//ignore what is already in read buffer
|
||||
session->read_buffer_beginning = session->read_buffer_offset;
|
||||
|
||||
|
||||
SPDYF_prepare_rst_stream(session,
|
||||
session->current_stream_id > 0 ? session->streams_head : NULL, //may be 0 here which is not good
|
||||
SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE);
|
||||
|
||||
//actually the read buffer can be bigger than the
|
||||
|
||||
//actually the read buffer can be bigger than the
|
||||
//max supported size
|
||||
session->status = session->read_ignore_bytes
|
||||
? SPDY_SESSION_STATUS_IGNORE_BYTES
|
||||
: SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
|
||||
|
||||
free(session->frame_handler_cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(SPDY_SESSION_STATUS_IGNORE_BYTES != session->status)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//ignoring data in read buffer
|
||||
case SPDY_SESSION_STATUS_IGNORE_BYTES:
|
||||
SPDYF_ASSERT(session->read_ignore_bytes > 0,
|
||||
@@ -1321,7 +1323,7 @@ SPDYF_session_idle (struct SPDY_Session *session)
|
||||
if(session->read_ignore_bytes
|
||||
> session->read_buffer_offset - session->read_buffer_beginning)
|
||||
{
|
||||
session->read_ignore_bytes -=
|
||||
session->read_ignore_bytes -=
|
||||
session->read_buffer_offset - session->read_buffer_beginning;
|
||||
session->read_buffer_beginning = session->read_buffer_offset;
|
||||
}
|
||||
@@ -1332,24 +1334,24 @@ SPDYF_session_idle (struct SPDY_Session *session)
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
//expect frame body (name/value pairs)
|
||||
case SPDY_SESSION_STATUS_WAIT_FOR_BODY:
|
||||
if(NULL!=session->frame_handler)
|
||||
session->frame_handler(session);
|
||||
break;
|
||||
|
||||
|
||||
case SPDY_SESSION_STATUS_FLUSHING:
|
||||
|
||||
|
||||
return SPDY_NO;
|
||||
|
||||
|
||||
//because of error the session needs to be closed
|
||||
case SPDY_SESSION_STATUS_CLOSING:
|
||||
//error should be already sent to the client
|
||||
SPDYF_session_close(session);
|
||||
return SPDY_YES;
|
||||
}
|
||||
|
||||
|
||||
return SPDY_YES;
|
||||
}
|
||||
|
||||
@@ -1359,10 +1361,10 @@ SPDYF_session_close (struct SPDY_Session *session)
|
||||
{
|
||||
struct SPDY_Daemon *daemon = session->daemon;
|
||||
int by_client = session->read_closed ? SPDY_YES : SPDY_NO;
|
||||
|
||||
|
||||
//shutdown the tls and deinit the tls context
|
||||
session->fio_close_session(session);
|
||||
shutdown (session->socket_fd,
|
||||
shutdown (session->socket_fd,
|
||||
session->read_closed ? SHUT_WR : SHUT_RDWR);
|
||||
session->read_closed = true;
|
||||
|
||||
@@ -1374,7 +1376,7 @@ SPDYF_session_close (struct SPDY_Session *session)
|
||||
DLL_insert (daemon->cleanup_head,
|
||||
daemon->cleanup_tail,
|
||||
session);
|
||||
|
||||
|
||||
//call callback for closed session
|
||||
if(NULL != daemon->session_closed_cb)
|
||||
{
|
||||
@@ -1391,43 +1393,43 @@ SPDYF_session_accept(struct SPDY_Daemon *daemon)
|
||||
struct SPDY_Session *session = NULL;
|
||||
socklen_t addr_len;
|
||||
struct sockaddr *addr;
|
||||
|
||||
|
||||
#if HAVE_INET6
|
||||
struct sockaddr_in6 addr6;
|
||||
|
||||
|
||||
addr = (struct sockaddr *)&addr6;
|
||||
addr_len = sizeof(addr6);
|
||||
#else
|
||||
struct sockaddr_in addr4;
|
||||
|
||||
|
||||
addr = (struct sockaddr *)&addr4;
|
||||
addr_len = sizeof(addr6);
|
||||
#endif
|
||||
|
||||
|
||||
new_socket_fd = accept (daemon->socket_fd, addr, &addr_len);
|
||||
|
||||
|
||||
if(new_socket_fd < 1)
|
||||
return SPDY_NO;
|
||||
|
||||
|
||||
if (NULL == (session = malloc (sizeof (struct SPDY_Session))))
|
||||
{
|
||||
goto free_and_fail;
|
||||
}
|
||||
memset (session, 0, sizeof (struct SPDY_Session));
|
||||
|
||||
|
||||
session->daemon = daemon;
|
||||
session->socket_fd = new_socket_fd;
|
||||
session->max_num_frames = daemon->max_num_frames;
|
||||
|
||||
|
||||
ret = SPDYF_io_set_session(session, daemon->io_subsystem);
|
||||
SPDYF_ASSERT(SPDY_YES == ret, "Somehow daemon->io_subsystem iswrong here");
|
||||
|
||||
|
||||
//init TLS context, handshake will be done
|
||||
if(SPDY_YES != session->fio_new_session(session))
|
||||
{
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
|
||||
//read buffer
|
||||
session->read_buffer_size = SPDYF_BUFFER_SIZE;
|
||||
if (NULL == (session->read_buffer = malloc (session->read_buffer_size)))
|
||||
@@ -1435,7 +1437,7 @@ SPDYF_session_accept(struct SPDY_Daemon *daemon)
|
||||
session->fio_close_session(session);
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
|
||||
//address of the client
|
||||
if (NULL == (session->addr = malloc (addr_len)))
|
||||
{
|
||||
@@ -1443,10 +1445,10 @@ SPDYF_session_accept(struct SPDY_Daemon *daemon)
|
||||
goto free_and_fail;
|
||||
}
|
||||
memcpy (session->addr, addr, addr_len);
|
||||
|
||||
|
||||
session->addr_len = addr_len;
|
||||
session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
|
||||
|
||||
|
||||
//init zlib context for the whole session
|
||||
if(SPDY_YES != SPDYF_zlib_deflate_init(&session->zlib_send_stream))
|
||||
{
|
||||
@@ -1459,23 +1461,23 @@ SPDYF_session_accept(struct SPDY_Daemon *daemon)
|
||||
SPDYF_zlib_deflate_end(&session->zlib_send_stream);
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
|
||||
//add it to daemon's list
|
||||
DLL_insert(daemon->sessions_head,daemon->sessions_tail,session);
|
||||
|
||||
|
||||
session->last_activity = SPDYF_monotonic_time();
|
||||
|
||||
|
||||
if(NULL != daemon->new_session_cb)
|
||||
daemon->new_session_cb(daemon->cls, session);
|
||||
|
||||
|
||||
return SPDY_YES;
|
||||
|
||||
|
||||
//for GOTO
|
||||
free_and_fail:
|
||||
/* something failed, so shutdown, close and free memory */
|
||||
shutdown (new_socket_fd, SHUT_RDWR);
|
||||
(void)close (new_socket_fd);
|
||||
|
||||
|
||||
if(NULL != session)
|
||||
{
|
||||
if(NULL != session->addr)
|
||||
@@ -1487,7 +1489,7 @@ SPDYF_session_accept(struct SPDY_Daemon *daemon)
|
||||
return SPDY_NO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
|
||||
struct SPDY_Session *session,
|
||||
@@ -1496,18 +1498,18 @@ SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
|
||||
struct SPDYF_Response_Queue *pos;
|
||||
struct SPDYF_Response_Queue *last;
|
||||
uint8_t priority;
|
||||
|
||||
|
||||
SPDYF_ASSERT(SPDY_YES != consider_priority || NULL != response_to_queue->stream,
|
||||
"called with consider_priority but no stream provided");
|
||||
|
||||
|
||||
last = response_to_queue;
|
||||
while(NULL != last->next)
|
||||
{
|
||||
last = last->next;
|
||||
}
|
||||
|
||||
|
||||
if(SPDY_NO == consider_priority)
|
||||
{
|
||||
{
|
||||
//put it at the end of the queue
|
||||
response_to_queue->prev = session->response_queue_tail;
|
||||
if (NULL == session->response_queue_head)
|
||||
@@ -1528,14 +1530,14 @@ SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
|
||||
session->response_queue_head = response_to_queue;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(NULL == session->response_queue_tail)
|
||||
{
|
||||
session->response_queue_head = response_to_queue;
|
||||
session->response_queue_tail = last;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//search for the right position to put it
|
||||
pos = session->response_queue_tail;
|
||||
priority = response_to_queue->stream->priority;
|
||||
@@ -1544,7 +1546,7 @@ SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
|
||||
{
|
||||
pos = pos->prev;
|
||||
}
|
||||
|
||||
|
||||
if(NULL == pos)
|
||||
{
|
||||
//put it on the head
|
||||
@@ -1574,18 +1576,18 @@ SPDYF_session_destroy(struct SPDY_Session *session)
|
||||
{
|
||||
struct SPDYF_Stream *stream;
|
||||
struct SPDYF_Response_Queue *response_queue;
|
||||
|
||||
|
||||
(void)close (session->socket_fd);
|
||||
SPDYF_zlib_deflate_end(&session->zlib_send_stream);
|
||||
SPDYF_zlib_inflate_end(&session->zlib_recv_stream);
|
||||
|
||||
|
||||
//clean up unsent data in the output queue
|
||||
while (NULL != (response_queue = session->response_queue_head))
|
||||
{
|
||||
DLL_remove (session->response_queue_head,
|
||||
session->response_queue_tail,
|
||||
response_queue);
|
||||
|
||||
|
||||
if(NULL != response_queue->frqcb)
|
||||
{
|
||||
response_queue->frqcb(response_queue->frqcb_cls, response_queue, SPDY_RESPONSE_RESULT_SESSION_CLOSED);
|
||||
@@ -1600,7 +1602,7 @@ SPDYF_session_destroy(struct SPDY_Session *session)
|
||||
DLL_remove (session->streams_head,
|
||||
session->streams_tail,
|
||||
stream);
|
||||
|
||||
|
||||
SPDYF_stream_destroy(stream);
|
||||
}
|
||||
|
||||
@@ -1619,20 +1621,20 @@ SPDYF_prepare_goaway (struct SPDY_Session *session,
|
||||
struct SPDYF_Response_Queue *response_to_queue;
|
||||
struct SPDYF_Control_Frame *control_frame;
|
||||
uint32_t *data;
|
||||
|
||||
|
||||
if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
|
||||
{
|
||||
return SPDY_NO;
|
||||
}
|
||||
memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
|
||||
|
||||
|
||||
if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
|
||||
{
|
||||
free(response_to_queue);
|
||||
return SPDY_NO;
|
||||
}
|
||||
memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
|
||||
|
||||
|
||||
if(NULL == (data = malloc(4)))
|
||||
{
|
||||
free(control_frame);
|
||||
@@ -1640,17 +1642,17 @@ SPDYF_prepare_goaway (struct SPDY_Session *session,
|
||||
return SPDY_NO;
|
||||
}
|
||||
*(data) = htonl(status);
|
||||
|
||||
|
||||
control_frame->control_bit = 1;
|
||||
control_frame->version = SPDY_VERSION;
|
||||
control_frame->type = SPDY_CONTROL_FRAME_TYPES_GOAWAY;
|
||||
control_frame->flags = 0;
|
||||
|
||||
|
||||
response_to_queue->control_frame = control_frame;
|
||||
response_to_queue->process_response_handler = &SPDYF_handler_write_goaway;
|
||||
response_to_queue->data = data;
|
||||
response_to_queue->data_size = 4;
|
||||
|
||||
|
||||
SPDYF_queue_response (response_to_queue,
|
||||
session,
|
||||
in_front ? -1 : SPDY_NO);
|
||||
@@ -1668,25 +1670,25 @@ SPDYF_prepare_rst_stream (struct SPDY_Session *session,
|
||||
struct SPDYF_Control_Frame *control_frame;
|
||||
uint32_t *data;
|
||||
uint32_t stream_id;
|
||||
|
||||
|
||||
if(NULL == stream)
|
||||
stream_id = 0;
|
||||
else
|
||||
stream_id = stream->stream_id;
|
||||
|
||||
|
||||
if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
|
||||
{
|
||||
return SPDY_NO;
|
||||
}
|
||||
memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
|
||||
|
||||
|
||||
if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
|
||||
{
|
||||
free(response_to_queue);
|
||||
return SPDY_NO;
|
||||
}
|
||||
memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
|
||||
|
||||
|
||||
if(NULL == (data = malloc(8)))
|
||||
{
|
||||
free(control_frame);
|
||||
@@ -1695,18 +1697,18 @@ SPDYF_prepare_rst_stream (struct SPDY_Session *session,
|
||||
}
|
||||
*(data) = HTON31(stream_id);
|
||||
*(data + 1) = htonl(status);
|
||||
|
||||
|
||||
control_frame->control_bit = 1;
|
||||
control_frame->version = SPDY_VERSION;
|
||||
control_frame->type = SPDY_CONTROL_FRAME_TYPES_RST_STREAM;
|
||||
control_frame->flags = 0;
|
||||
|
||||
|
||||
response_to_queue->control_frame = control_frame;
|
||||
response_to_queue->process_response_handler = &SPDYF_handler_write_rst_stream;
|
||||
response_to_queue->data = data;
|
||||
response_to_queue->data_size = 8;
|
||||
response_to_queue->stream = stream;
|
||||
|
||||
|
||||
SPDYF_queue_response (response_to_queue,
|
||||
session,
|
||||
-1);
|
||||
@@ -1723,22 +1725,22 @@ SPDYF_prepare_window_update (struct SPDY_Session *session,
|
||||
struct SPDYF_Response_Queue *response_to_queue;
|
||||
struct SPDYF_Control_Frame *control_frame;
|
||||
uint32_t *data;
|
||||
|
||||
|
||||
SPDYF_ASSERT(NULL != stream, "stream cannot be NULL");
|
||||
|
||||
|
||||
if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
|
||||
{
|
||||
return SPDY_NO;
|
||||
}
|
||||
memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
|
||||
|
||||
|
||||
if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
|
||||
{
|
||||
free(response_to_queue);
|
||||
return SPDY_NO;
|
||||
}
|
||||
memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
|
||||
|
||||
|
||||
if(NULL == (data = malloc(8)))
|
||||
{
|
||||
free(control_frame);
|
||||
@@ -1747,18 +1749,18 @@ SPDYF_prepare_window_update (struct SPDY_Session *session,
|
||||
}
|
||||
*(data) = HTON31(stream->stream_id);
|
||||
*(data + 1) = HTON31(delta_window_size);
|
||||
|
||||
|
||||
control_frame->control_bit = 1;
|
||||
control_frame->version = SPDY_VERSION;
|
||||
control_frame->type = SPDY_CONTROL_FRAME_TYPES_WINDOW_UPDATE;
|
||||
control_frame->flags = 0;
|
||||
|
||||
|
||||
response_to_queue->control_frame = control_frame;
|
||||
response_to_queue->process_response_handler = &SPDYF_handler_write_window_update;
|
||||
response_to_queue->data = data;
|
||||
response_to_queue->data_size = 8;
|
||||
response_to_queue->stream = stream;
|
||||
|
||||
|
||||
SPDYF_queue_response (response_to_queue,
|
||||
session,
|
||||
-1);
|
||||
|
||||
Reference in New Issue
Block a user