Home | History | Annotate | Download | only in microspdy
      1 /*
      2     This file is part of libmicrospdy
      3     Copyright Copyright (C) 2012 Andrey Uzunov
      4 
      5     This program is free software: you can redistribute it and/or modify
      6     it under the terms of the GNU General Public License as published by
      7     the Free Software Foundation, either version 3 of the License, or
      8     (at your option) any later version.
      9 
     10     This program is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13     GNU General Public License for more details.
     14 
     15     You should have received a copy of the GNU General Public License
     16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 */
     18 
     19 /**
     20  * @file stream.c
     21  * @brief  SPDY streams handling
     22  * @author Andrey Uzunov
     23  */
     24 
     25 #include "platform.h"
     26 #include "structures.h"
     27 #include "internal.h"
     28 #include "session.h"
     29 
     30 
     31 int
     32 SPDYF_stream_new (struct SPDY_Session *session)
     33 {
     34 	uint32_t stream_id;
     35 	uint32_t assoc_stream_id;
     36 	uint8_t priority;
     37 	uint8_t slot;
     38 	size_t buffer_pos = session->read_buffer_beginning;
     39 	struct SPDYF_Stream *stream;
     40 	struct SPDYF_Control_Frame *frame;
     41 
     42 	if((session->read_buffer_offset - session->read_buffer_beginning) < 10)
     43 	{
     44 		//not all fields are received to create new stream
     45 		return SPDY_NO;
     46 	}
     47 
     48 	frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
     49 
     50 	//get stream id of the new stream
     51     memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4);
     52 	stream_id = NTOH31(stream_id);
     53 	session->read_buffer_beginning += 4;
     54 	if(stream_id <= session->last_in_stream_id || 0==(stream_id % 2))
     55 	{
     56 		//wrong stream id sent by client
     57 		//GOAWAY with PROTOCOL_ERROR MUST be sent
     58 		//TODO
     59 
     60 		//ignore frame
     61 		session->frame_handler = &SPDYF_handler_ignore_frame;
     62 		return SPDY_NO;
     63 	}
     64 	else if(session->is_goaway_sent)
     65 	{
     66 		//the client is not allowed to create new streams anymore
     67 		//we MUST ignore the frame
     68 		session->frame_handler = &SPDYF_handler_ignore_frame;
     69 		return SPDY_NO;
     70 	}
     71 
     72 	//set highest stream id for session
     73 	session->last_in_stream_id = stream_id;
     74 
     75 	//get assoc stream id of the new stream
     76 	//this value is used with SPDY PUSH, thus nothing to do with it here
     77     memcpy(&assoc_stream_id, session->read_buffer + session->read_buffer_beginning, 4);
     78 	assoc_stream_id = NTOH31(assoc_stream_id);
     79 	session->read_buffer_beginning += 4;
     80 
     81 	//get stream priority (3 bits)
     82 	//after it there are 5 bits that are not used
     83 	priority = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning) >> 5;
     84 	session->read_buffer_beginning++;
     85 
     86 	//get slot (see SPDY draft)
     87 	slot = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning);
     88 	session->read_buffer_beginning++;
     89 
     90 	if(NULL == (stream = malloc(sizeof(struct SPDYF_Stream))))
     91 	{
     92 		SPDYF_DEBUG("No memory");
     93 		//revert buffer state
     94 		session->read_buffer_beginning = buffer_pos;
     95 		return SPDY_NO;
     96 	}
     97 	memset(stream,0, sizeof(struct SPDYF_Stream));
     98 	stream->session = session;
     99 	stream->stream_id = stream_id;
    100 	stream->assoc_stream_id = assoc_stream_id;
    101 	stream->priority = priority;
    102 	stream->slot = slot;
    103 	stream->is_in_closed = (frame->flags & SPDY_SYN_STREAM_FLAG_FIN) != 0;
    104 	stream->flag_unidirectional = (frame->flags & SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL) != 0;
    105 	stream->is_out_closed = stream->flag_unidirectional;
    106 	stream->is_server_initiator = false;
    107 	stream->window_size = SPDYF_INITIAL_WINDOW_SIZE;
    108 
    109 	//put the stream to the list of streams for the session
    110 	DLL_insert(session->streams_head, session->streams_tail, stream);
    111 
    112 	return SPDY_YES;
    113 }
    114 
    115 
    116 void
    117 SPDYF_stream_destroy(struct SPDYF_Stream *stream)
    118 {
    119 	SPDY_name_value_destroy(stream->headers);
    120 	free(stream);
    121 	stream = NULL;
    122 }
    123 
    124 
    125 void
    126 SPDYF_stream_set_flags_on_write(struct SPDYF_Response_Queue *response_queue)
    127 {
    128 	struct SPDYF_Stream * stream = response_queue->stream;
    129 
    130 	if(NULL != response_queue->data_frame)
    131 	{
    132 		stream->is_out_closed = (bool)(response_queue->data_frame->flags & SPDY_DATA_FLAG_FIN);
    133 	}
    134 	else if(NULL != response_queue->control_frame)
    135 	{
    136 		switch(response_queue->control_frame->type)
    137 		{
    138 			case SPDY_CONTROL_FRAME_TYPES_SYN_REPLY:
    139 				stream->is_out_closed = (bool)(response_queue->control_frame->flags & SPDY_SYN_REPLY_FLAG_FIN);
    140 				break;
    141 
    142 			case SPDY_CONTROL_FRAME_TYPES_RST_STREAM:
    143 				if(NULL != stream)
    144 				{
    145 					stream->is_out_closed = true;
    146 					stream->is_in_closed = true;
    147 				}
    148 				break;
    149 
    150 		}
    151 	}
    152 }
    153 
    154 
    155 //TODO add function *on_read
    156 
    157 
    158 struct SPDYF_Stream *
    159 SPDYF_stream_find(uint32_t stream_id, struct SPDY_Session * session)
    160 {
    161   struct SPDYF_Stream * stream = session->streams_head;
    162 
    163   while(NULL != stream && stream_id != stream->stream_id)
    164   {
    165     stream = stream->next;
    166   }
    167 
    168   return stream;
    169 }
    170