• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
SPDYF_stream_new(struct SPDY_Session * session)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
SPDYF_stream_destroy(struct SPDYF_Stream * stream)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
SPDYF_stream_set_flags_on_write(struct SPDYF_Response_Queue * response_queue)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 *
SPDYF_stream_find(uint32_t stream_id,struct SPDY_Session * session)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