Пример #1
0
/**
 * Handler for reading the GOAWAY frame after we know that
 * 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
spdyf_handler_read_goaway (struct SPDY_Session *session)
{
	struct SPDYF_Control_Frame *frame;
	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)
		{
			case SPDY_GOAWAY_STATUS_OK:
				break;
			case SPDY_GOAWAY_STATUS_PROTOCOL_ERROR:
				break;
			case SPDY_GOAWAY_STATUS_INTERNAL_ERROR:
				break;
		}
  
    //SPDYF_DEBUG("goaway received: status %i", status);
	}
	
	session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
	free(frame);
}
Пример #2
0
/**
 * Handler for reading RST_STREAM frames. After receiving the frame
 * 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
spdyf_handler_read_rst_stream (struct SPDY_Session *session)
{
	struct SPDYF_Control_Frame *frame;
	uint32_t stream_id;
	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
		SPDYF_DEBUG("wrong RST_STREAM received");
		//ignore as a large frame
		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)
	{
		if(stream_id == stream->stream_id)
		{
			stream->is_in_closed = true;
			stream->is_out_closed = true;
			break;
		}
		stream = stream->next;
	}
	
	//SPDYF_DEBUG("Received RST_STREAM; status=%i; id=%i",status,stream_id);
	
	//do something according to the status
	//TODO
	/*switch(status)
	{
		case SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR:
			break;
	}*/
}
Пример #3
0
int
SPDYF_stream_new (struct SPDY_Session *session)
{
	uint32_t stream_id;
	uint32_t assoc_stream_id;
	uint8_t priority;
	uint8_t slot;
	size_t buffer_pos = session->read_buffer_beginning;
	struct SPDYF_Stream *stream;
	struct SPDYF_Control_Frame *frame;
	
	if((session->read_buffer_offset - session->read_buffer_beginning) < 10)
	{
		//not all fields are received to create new stream
		return SPDY_NO;
	}
	
	frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
	
	//get stream id of the new stream
    memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4);
	stream_id = NTOH31(stream_id);
	session->read_buffer_beginning += 4;
	if(stream_id <= session->last_in_stream_id || 0==(stream_id % 2))
	{
		//wrong stream id sent by client
		//GOAWAY with PROTOCOL_ERROR MUST be sent
		//TODO
		
		//ignore frame
		session->frame_handler = &SPDYF_handler_ignore_frame;
		return SPDY_NO;
	}
	else if(session->is_goaway_sent)
	{
		//the client is not allowed to create new streams anymore
		//we MUST ignore the frame
		session->frame_handler = &SPDYF_handler_ignore_frame;
		return SPDY_NO;
	}
	
	//set highest stream id for session
	session->last_in_stream_id = stream_id;
	
	//get assoc stream id of the new stream
	//this value is used with SPDY PUSH, thus nothing to do with it here
    memcpy(&assoc_stream_id, session->read_buffer + session->read_buffer_beginning, 4);
	assoc_stream_id = NTOH31(assoc_stream_id);
	session->read_buffer_beginning += 4;

	//get stream priority (3 bits)
	//after it there are 5 bits that are not used
	priority = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning) >> 5;
	session->read_buffer_beginning++;
	
	//get slot (see SPDY draft)
	slot = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning);
	session->read_buffer_beginning++;
	
	if(NULL == (stream = malloc(sizeof(struct SPDYF_Stream))))
	{
		SPDYF_DEBUG("No memory");
		//revert buffer state
		session->read_buffer_beginning = buffer_pos;
		return SPDY_NO;
	}
	memset(stream,0, sizeof(struct SPDYF_Stream));
	stream->session = session;
	stream->stream_id = stream_id;
	stream->assoc_stream_id = assoc_stream_id;
	stream->priority = priority;
	stream->slot = slot;
	stream->is_in_closed = (frame->flags & SPDY_SYN_STREAM_FLAG_FIN) != 0;
	stream->flag_unidirectional = (frame->flags & SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL) != 0;
	stream->is_out_closed = stream->flag_unidirectional;
	stream->is_server_initiator = false;
	stream->window_size = SPDYF_INITIAL_WINDOW_SIZE;
	
	//put the stream to the list of streams for the session
	DLL_insert(session->streams_head, session->streams_tail, stream);
	
	return SPDY_YES;
}