diff options
Diffstat (limited to 'src/microspdy/stream.c')
-rw-r--r-- | src/microspdy/stream.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/microspdy/stream.c b/src/microspdy/stream.c new file mode 100644 index 00000000..9b6dc08d --- /dev/null +++ b/src/microspdy/stream.c @@ -0,0 +1,169 @@ +/* + 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; +} |