C++程序  |  170行  |  4.63 KB

/*
    This file is part of libmicrospdy
    Copyright Copyright (C) 2012 Andrey Uzunov

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @file stream.c
 * @brief  SPDY streams handling
 * @author Andrey Uzunov
 */

#include "platform.h"
#include "structures.h"
#include "internal.h"
#include "session.h"


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;
}


void
SPDYF_stream_destroy(struct SPDYF_Stream *stream)
{
	SPDY_name_value_destroy(stream->headers);
	free(stream);
	stream = NULL;
}


void
SPDYF_stream_set_flags_on_write(struct SPDYF_Response_Queue *response_queue)
{
	struct SPDYF_Stream * stream = response_queue->stream;
	
	if(NULL != response_queue->data_frame)
	{
		stream->is_out_closed = (bool)(response_queue->data_frame->flags & SPDY_DATA_FLAG_FIN);
	}
	else if(NULL != response_queue->control_frame)
	{
		switch(response_queue->control_frame->type)
		{
			case SPDY_CONTROL_FRAME_TYPES_SYN_REPLY:
				stream->is_out_closed = (bool)(response_queue->control_frame->flags & SPDY_SYN_REPLY_FLAG_FIN);
				break;
				
			case SPDY_CONTROL_FRAME_TYPES_RST_STREAM:
				if(NULL != stream)
				{
					stream->is_out_closed = true;
					stream->is_in_closed = true;
				}
				break;
				
		}
	}
}


//TODO add function *on_read


struct SPDYF_Stream * 
SPDYF_stream_find(uint32_t stream_id, struct SPDY_Session * session)
{
  struct SPDYF_Stream * stream = session->streams_head;
  
  while(NULL != stream && stream_id != stream->stream_id)
  {
    stream = stream->next;
  }
  
  return stream;
}