aboutsummaryrefslogtreecommitdiff
path: root/src/microspdy/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microspdy/stream.c')
-rw-r--r--src/microspdy/stream.c169
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;
+}