00001 /* 00002 This file is part of libmicrospdy 00003 Copyright (C) 2012 Andrey Uzunov 00004 00005 This program is free software: you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation, either version 3 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00025 #include "platform.h" 00026 #include "structures.h" 00027 #include "internal.h" 00028 #include "session.h" 00029 00030 00031 int 00032 SPDYF_stream_new (struct SPDY_Session *session) 00033 { 00034 uint32_t stream_id; 00035 uint32_t assoc_stream_id; 00036 uint8_t priority; 00037 uint8_t slot; 00038 size_t buffer_pos = session->read_buffer_beginning; 00039 struct SPDYF_Stream *stream; 00040 struct SPDYF_Control_Frame *frame; 00041 00042 if((session->read_buffer_offset - session->read_buffer_beginning) < 10) 00043 { 00044 //not all fields are received to create new stream 00045 return SPDY_NO; 00046 } 00047 00048 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls; 00049 00050 //get stream id of the new stream 00051 memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4); 00052 stream_id = NTOH31(stream_id); 00053 session->read_buffer_beginning += 4; 00054 if(stream_id <= session->last_in_stream_id || 0==(stream_id % 2)) 00055 { 00056 //wrong stream id sent by client 00057 //GOAWAY with PROTOCOL_ERROR MUST be sent 00058 //TODO 00059 00060 //ignore frame 00061 session->frame_handler = &SPDYF_handler_ignore_frame; 00062 return SPDY_NO; 00063 } 00064 else if(session->is_goaway_sent) 00065 { 00066 //the client is not allowed to create new streams anymore 00067 //we MUST ignore the frame 00068 session->frame_handler = &SPDYF_handler_ignore_frame; 00069 return SPDY_NO; 00070 } 00071 00072 //set highest stream id for session 00073 session->last_in_stream_id = stream_id; 00074 00075 //get assoc stream id of the new stream 00076 //this value is used with SPDY PUSH, thus nothing to do with it here 00077 memcpy(&assoc_stream_id, session->read_buffer + session->read_buffer_beginning, 4); 00078 assoc_stream_id = NTOH31(assoc_stream_id); 00079 session->read_buffer_beginning += 4; 00080 00081 //get stream priority (3 bits) 00082 //after it there are 5 bits that are not used 00083 priority = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning) >> 5; 00084 session->read_buffer_beginning++; 00085 00086 //get slot (see SPDY draft) 00087 slot = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning); 00088 session->read_buffer_beginning++; 00089 00090 if(NULL == (stream = malloc(sizeof(struct SPDYF_Stream)))) 00091 { 00092 SPDYF_DEBUG("No memory"); 00093 //revert buffer state 00094 session->read_buffer_beginning = buffer_pos; 00095 return SPDY_NO; 00096 } 00097 memset(stream,0, sizeof(struct SPDYF_Stream)); 00098 stream->session = session; 00099 stream->stream_id = stream_id; 00100 stream->assoc_stream_id = assoc_stream_id; 00101 stream->priority = priority; 00102 stream->slot = slot; 00103 stream->is_in_closed = (frame->flags & SPDY_SYN_STREAM_FLAG_FIN) != 0; 00104 stream->flag_unidirectional = (frame->flags & SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL) != 0; 00105 stream->is_out_closed = stream->flag_unidirectional; 00106 stream->is_server_initiator = false; 00107 stream->window_size = SPDYF_INITIAL_WINDOW_SIZE; 00108 00109 //put the stream to the list of streams for the session 00110 DLL_insert(session->streams_head, session->streams_tail, stream); 00111 00112 return SPDY_YES; 00113 } 00114 00115 00116 void 00117 SPDYF_stream_destroy(struct SPDYF_Stream *stream) 00118 { 00119 SPDY_name_value_destroy(stream->headers); 00120 free(stream); 00121 stream = NULL; 00122 } 00123 00124 00125 void 00126 SPDYF_stream_set_flags_on_write(struct SPDYF_Response_Queue *response_queue) 00127 { 00128 struct SPDYF_Stream * stream = response_queue->stream; 00129 00130 if(NULL != response_queue->data_frame) 00131 { 00132 stream->is_out_closed = (bool)(response_queue->data_frame->flags & SPDY_DATA_FLAG_FIN); 00133 } 00134 else if(NULL != response_queue->control_frame) 00135 { 00136 switch(response_queue->control_frame->type) 00137 { 00138 case SPDY_CONTROL_FRAME_TYPES_SYN_REPLY: 00139 stream->is_out_closed = (bool)(response_queue->control_frame->flags & SPDY_SYN_REPLY_FLAG_FIN); 00140 break; 00141 00142 case SPDY_CONTROL_FRAME_TYPES_RST_STREAM: 00143 if(NULL != stream) 00144 { 00145 stream->is_out_closed = true; 00146 stream->is_in_closed = true; 00147 } 00148 break; 00149 00150 } 00151 } 00152 } 00153 00154 00155 //TODO add function *on_read 00156 00157 00158 struct SPDYF_Stream * 00159 SPDYF_stream_find(uint32_t stream_id, struct SPDY_Session * session) 00160 { 00161 struct SPDYF_Stream * stream = session->streams_head; 00162 00163 while(NULL != stream && stream_id != stream->stream_id) 00164 { 00165 stream = stream->next; 00166 } 00167 00168 return stream; 00169 }