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 31int 32SPDYF_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 116void 117SPDYF_stream_destroy(struct SPDYF_Stream *stream) 118{ 119 SPDY_name_value_destroy(stream->headers); 120 free(stream); 121 stream = NULL; 122} 123 124 125void 126SPDYF_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 158struct SPDYF_Stream * 159SPDYF_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