Пример #1
0
int
SPDYF_openssl_new_session(struct SPDY_Session *session)
{
	int ret;

	if(NULL == (session->io_context = SSL_new(session->daemon->io_context)))
    {
		SPDYF_DEBUG("Couldn't create ssl structure");
		return SPDY_NO;
	}
	if(1 != (ret = SSL_set_fd(session->io_context, session->socket_fd)))
    {
		SPDYF_DEBUG("SSL_set_fd %i",ret);
		SSL_free(session->io_context);
		session->io_context = NULL;
		return SPDY_NO;
	}

	//for non-blocking I/O SSL_accept may return -1
	//and this function won't work
	if(1 != (ret = SSL_accept(session->io_context)))
    {
		SPDYF_DEBUG("SSL_accept %i",ret);
		SSL_free(session->io_context);
		session->io_context = NULL;
		return SPDY_NO;
	}
	/* alternatively
	SSL_set_accept_state(session->io_context);
	* may be called and then the negotiation will be done on reading
	*/

	return SPDY_YES;
}
Пример #2
0
int
SPDYF_openssl_init(struct SPDY_Daemon *daemon)
{
    int options;
    //create ssl context. TLSv1 used
    if(NULL == (daemon->io_context = SSL_CTX_new(TLSv1_server_method())))
    {
		SPDYF_DEBUG("Couldn't create ssl context");
		return SPDY_NO;
        }
	//set options for tls
	//TODO DH is not enabled for easier debugging
    //SSL_CTX_set_options(daemon->io_context, SSL_OP_SINGLE_DH_USE);
    
    //TODO here session tickets are disabled for easier debuging with 
    //wireshark when using Chrome
    // SSL_OP_NO_COMPRESSION disables TLS compression to avoid CRIME attack
    options = SSL_OP_NO_TICKET;
#ifdef SSL_OP_NO_COMPRESSION
    options |= SSL_OP_NO_COMPRESSION;
#elif OPENSSL_VERSION_NUMBER >= 0x00908000L /* workaround for OpenSSL 0.9.8 */
    sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
#endif

    SSL_CTX_set_options(daemon->io_context, options);
    if(1 != SSL_CTX_use_certificate_file(daemon->io_context, daemon->certfile , SSL_FILETYPE_PEM))
    {
		SPDYF_DEBUG("Couldn't load the cert file");
		SSL_CTX_free(daemon->io_context);
		return SPDY_NO;
	}
    if(1 != SSL_CTX_use_PrivateKey_file(daemon->io_context, daemon->keyfile, SSL_FILETYPE_PEM))
    {
		SPDYF_DEBUG("Couldn't load the name file");
		SSL_CTX_free(daemon->io_context);
		return SPDY_NO;
	}
    SSL_CTX_set_next_protos_advertised_cb(daemon->io_context, &spdyf_next_protos_advertised_cb, NULL);
	//TODO only RC4-SHA is used to make it easy to debug with wireshark
    if (1 != SSL_CTX_set_cipher_list(daemon->io_context, "RC4-SHA"))
    {
		SPDYF_DEBUG("Couldn't set the desired cipher list");
		SSL_CTX_free(daemon->io_context);
		return SPDY_NO;
	}
	
	return SPDY_YES;
}
Пример #3
0
void
SPDY_destroy_request (struct SPDY_Request *request)
{
	if(NULL == request)
	{
		SPDYF_DEBUG("request is NULL");
		return;
	}
	//strings into request struct are just references to strings in
	//headers, so no need to free them twice
	SPDY_name_value_destroy(request->headers);
	free(request);
}
Пример #4
0
int
SPDYF_raw_new_session(struct SPDY_Session *session)
{
    int fd_flags;
    int val = 1;
    int ret;

    //setting the socket to be non-blocking
    fd_flags = fcntl (session->socket_fd, F_GETFL);
    if ( -1 == fd_flags
            || 0 != fcntl (session->socket_fd, F_SETFL, fd_flags | O_NONBLOCK))
        SPDYF_DEBUG("WARNING: Couldn't set the new connection to be non-blocking");

    if(SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags)
    {
        ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
        if(-1 == ret)
            SPDYF_DEBUG("WARNING: Couldn't set the new connection to TCP_NODELAY");
    }

    return SPDY_YES;
}
Пример #5
0
int
SPDYF_raw_after_write(struct SPDY_Session *session, int was_written)
{
#if HAVE_DECL_TCP_CORK
    if(SPDY_YES == was_written && 0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags))
    {
        int val = 0;
        int ret;

        ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_CORK, &val, (socklen_t)sizeof(val));
        if(-1 == ret)
            SPDYF_DEBUG("WARNING: Couldn't unset the new connection to TCP_CORK");
    }

#endif
    return was_written;
}
Пример #6
0
/**
 * Handler for reading the full SYN_STREAM frame after we know that
 * the frame is such.
 * The function waits for the full frame and then changes status
 * of the session. New stream is created.
 * 
 * @param session SPDY_Session whose read buffer is used.
 */
static void
spdyf_handler_read_syn_stream (struct SPDY_Session *session)
{
	size_t name_value_strm_size = 0;
	unsigned int compressed_data_size;
	int ret;
	void *name_value_strm = NULL;
	struct SPDYF_Control_Frame *frame;
	struct SPDY_NameValue *headers;
	
	SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
		|| SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
		"the function is called wrong");
	
	frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
	
	//handle subheaders
	if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
	{
		if(0 == frame->length)
		{
			//protocol error: incomplete frame
			//we just ignore it since there is no stream id for which to
			//send RST_STREAM
			//TODO maybe GOAWAY and closing session is appropriate
			SPDYF_DEBUG("zero long SYN_STREAM received");
			session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
			free(frame);
			return;
		}
		
		if(SPDY_YES != SPDYF_stream_new(session))
		{
			/* waiting for some more fields to create new stream
			or something went wrong, SPDYF_stream_new has handled the
			situation */
			return;
		}
		
		session->current_stream_id = session->streams_head->stream_id;
		if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
		{
			//TODO no need to create stream if this happens
			session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
			return;
		}
		else
			session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
	}
	
	//handle body
	
	//start reading the compressed name/value pairs (http headers)
	compressed_data_size = frame->length //everything after length field
		- 10;//4B stream id, 4B assoc strem id, 2B priority, unused and slot
	
	if(session->read_buffer_offset - session->read_buffer_beginning < compressed_data_size)
	{
		// the full frame is not yet here, try later
		return;
	}
	
	if(compressed_data_size > 0
		&& SPDY_YES != SPDYF_zlib_inflate(&session->zlib_recv_stream,
						session->read_buffer + session->read_buffer_beginning,
						compressed_data_size,
						&name_value_strm,
						&name_value_strm_size))
	{
		/* something went wrong on inflating,
		* the state of the stream for decompression is unknown
		* and we may not be able to read anything more received on
		* this session,
		* so it is better to close the session */ 
		free(name_value_strm);
		free(frame);
		
		/* mark the session for closing and close it, when 
		 * everything on the output queue is already written */
		session->status = SPDY_SESSION_STATUS_FLUSHING;
		
		SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false);

		return;
	}
	
	if(0 == name_value_strm_size || 0 == compressed_data_size)
	{
		//Protocol error: send RST_STREAM
		if(SPDY_YES != SPDYF_prepare_rst_stream(session, session->streams_head,
						SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR))
		{
			//no memory, try later to send RST
			return;
		}
	}
	else
  {
    ret = SPDYF_name_value_from_stream(name_value_strm, name_value_strm_size, &headers);
    if(SPDY_NO == ret)
    {
      //memory error, try later
      free(name_value_strm);
      return;
    }

    session->streams_head->headers = headers;
    //inform the application layer for the new stream received
    if(SPDY_YES != session->daemon->fnew_stream_cb(session->daemon->fcls, session->streams_head))
    {
      //memory error, try later
      free(name_value_strm);
      return;
    }
      
    session->read_buffer_beginning += compressed_data_size;
    free(name_value_strm);
  }
  
  //SPDYF_DEBUG("syn_stream received: id %i", session->current_stream_id);
  
	//change state to wait for new frame
	session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
	free(frame);
}
Пример #7
0
/**
 * Handler for reading DATA frames. In requests they are used for POST
 * arguments.
 * 
 * @param session SPDY_Session whose read buffer is used.
 */
static void
spdyf_handler_read_data (struct SPDY_Session *session)
{
  int ret;
  struct SPDYF_Data_Frame * frame;
  struct SPDYF_Stream * stream;
  
	SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
		|| SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
		"the function is called wrong");
    
  //SPDYF_DEBUG("DATA frame received (POST?). Ignoring");
	
  //SPDYF_SIGINT("");
  
	frame = (struct SPDYF_Data_Frame *)session->frame_handler_cls;
	
	//handle subheaders
	if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
	{
		if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
		{
			session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
			return;
		}
		else
			session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
	}
	
	//handle body
	
	if(session->read_buffer_offset - session->read_buffer_beginning
		>= frame->length)
	{
    stream = SPDYF_stream_find(frame->stream_id, session);
    
    if(NULL == stream || stream->is_in_closed || NULL == session->daemon->received_data_cb)
    {
      if(NULL == session->daemon->received_data_cb)
      SPDYF_DEBUG("No callback for DATA frame set; Ignoring DATA frame!");
      
      //TODO send error?
      
      //TODO for now ignore frame
      session->read_buffer_beginning += frame->length;
      session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
      free(frame);
      return;
    }
    
    ret = session->daemon->freceived_data_cb(session->daemon->cls,
                                      stream,
                                      session->read_buffer + session->read_buffer_beginning,
                                      frame->length,
                                      0 == (SPDY_DATA_FLAG_FIN & frame->flags));
        
    session->read_buffer_beginning += frame->length;
    
    stream->window_size -= frame->length;  
         
    //TODO close in and send rst maybe
    SPDYF_ASSERT(SPDY_YES == ret, "Cancel POST data is not yet implemented");
    
    if(SPDY_DATA_FLAG_FIN & frame->flags)
    {
      stream->is_in_closed = true;
    }
    else if(stream->window_size < SPDYF_INITIAL_WINDOW_SIZE / 2)
    {
      //very simple implementation of flow control
      //when the window's size is under the half of the initial value,
      //increase it again up to the initial value
      
      //prepare WINDOW_UPDATE
      if(SPDY_YES == SPDYF_prepare_window_update(session, stream,
            SPDYF_INITIAL_WINDOW_SIZE - stream->window_size))
      {
        stream->window_size = SPDYF_INITIAL_WINDOW_SIZE;
      }
      //else: do it later
    }
  
    //SPDYF_DEBUG("data received: id %i", frame->stream_id);
  
    session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
    free(frame);
	}
}
Пример #8
0
/**
 * Handler for reading RST_STREAM frames. After receiving the frame
 * the stream moves into closed state and status
 * of the session is changed. Frames, belonging to this stream, which
 * are still at the output queue, will be ignored later.
 * 
 * @param session SPDY_Session whose read buffer is used.
 */
static void
spdyf_handler_read_rst_stream (struct SPDY_Session *session)
{
	struct SPDYF_Control_Frame *frame;
	uint32_t stream_id;
	int32_t status_int;
	//enum SPDY_RST_STREAM_STATUS status; //for debug
	struct SPDYF_Stream *stream;
	
	SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
		"the function is called wrong");
		
	frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
	
	if(0 != frame->flags || 8 != frame->length)
	{
		//this is a protocol error
		SPDYF_DEBUG("wrong RST_STREAM received");
		//ignore as a large frame
		session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
		return;
	}
	
	if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length)
	{
		//not all fields are received
		//try later
		return;
	}
	
    memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4);
	stream_id = NTOH31(stream_id);
	session->read_buffer_beginning += 4;
	
    memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4);
	//status = ntohl(status_int); //for debug
	session->read_buffer_beginning += 4;
	
	session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
	free(frame);
	
	//mark the stream as closed
	stream = session->streams_head;
	while(NULL != stream)
	{
		if(stream_id == stream->stream_id)
		{
			stream->is_in_closed = true;
			stream->is_out_closed = true;
			break;
		}
		stream = stream->next;
	}
	
	//SPDYF_DEBUG("Received RST_STREAM; status=%i; id=%i",status,stream_id);
	
	//do something according to the status
	//TODO
	/*switch(status)
	{
		case SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR:
			break;
	}*/
}
Пример #9
0
/**
 * Handler for reading the GOAWAY frame after we know that
 * the frame is such.
 * The function waits for the full frame and then changes status
 * of the session.
 * 
 * @param session SPDY_Session whose read buffer is used.
 */
static void
spdyf_handler_read_goaway (struct SPDY_Session *session)
{
	struct SPDYF_Control_Frame *frame;
	uint32_t last_good_stream_id;
	uint32_t status_int;
	enum SPDY_GOAWAY_STATUS status;
	
	SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
		"the function is called wrong");
		
	frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
	
	if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
	{
		//this is a protocol error/attack
		session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
		return;
	}
			
	if(0 != frame->flags || 8 != frame->length)
	{
		//this is a protocol error
		SPDYF_DEBUG("wrong GOAWAY received");
		//anyway, it will be handled
	}
	
	if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length)
	{
		//not all fields are received
		//try later
		return;
	}
	
	//mark that the session is almost closed
	session->is_goaway_received = true;
	
	if(8 == frame->length)
	{
		memcpy(&last_good_stream_id, session->read_buffer + session->read_buffer_beginning, 4);
		last_good_stream_id = NTOH31(last_good_stream_id);
		session->read_buffer_beginning += 4;
		
		memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4);
		status = ntohl(status_int);
		session->read_buffer_beginning += 4;
	
		//TODO do something with last_good
		
		//SPDYF_DEBUG("Received GOAWAY; status=%i; lastgood=%i",status,last_good_stream_id);
		
		//do something according to the status
		//TODO
		switch(status)
		{
			case SPDY_GOAWAY_STATUS_OK:
				break;
			case SPDY_GOAWAY_STATUS_PROTOCOL_ERROR:
				break;
			case SPDY_GOAWAY_STATUS_INTERNAL_ERROR:
				break;
		}
  
    //SPDYF_DEBUG("goaway received: status %i", status);
	}
	
	session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
	free(frame);
}
Пример #10
0
int
SPDYF_session_idle (struct SPDY_Session *session)
{
	size_t read_buffer_beginning;
	size_t frame_length;
	struct SPDYF_Control_Frame* control_frame;
	struct SPDYF_Data_Frame *data_frame;
	
	//prepare session for closing if timeout is used and already passed
	if(SPDY_SESSION_STATUS_CLOSING != session->status
		&& session->daemon->session_timeout
		&& (session->last_activity + session->daemon->session_timeout < SPDYF_monotonic_time()))
	{
		session->status = SPDY_SESSION_STATUS_CLOSING;
		//best effort for sending GOAWAY
		SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_OK, true);
		SPDYF_session_write(session,true);
	}
	
	switch(session->status)
	{
		//expect new frame to arrive
		case SPDY_SESSION_STATUS_WAIT_FOR_HEADER:
			session->current_stream_id = 0;
			//check if the whole frame header is already here
			//both frame types have the same length
			if(session->read_buffer_offset - session->read_buffer_beginning
				< sizeof(struct SPDYF_Control_Frame))
				return SPDY_NO;

			/* check the first bit to see if it is data or control frame
			 * and also if the version is supported */
			if(0x80 == *(uint8_t *)(session->read_buffer + session->read_buffer_beginning)
				&& SPDY_VERSION == *((uint8_t *)session->read_buffer + session->read_buffer_beginning + 1))
			{
				//control frame
				if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
				{
					SPDYF_DEBUG("No memory");
					return SPDY_NO;
				}
				
				//get frame headers
				memcpy(control_frame,
					session->read_buffer + session->read_buffer_beginning,
					sizeof(struct SPDYF_Control_Frame));
				session->read_buffer_beginning += sizeof(struct SPDYF_Control_Frame);
				SPDYF_CONTROL_FRAME_NTOH(control_frame);
		
				session->status = SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER;
				//assign different frame handler according to frame type
				switch(control_frame->type){
					case SPDY_CONTROL_FRAME_TYPES_SYN_STREAM:
						session->frame_handler = &spdyf_handler_read_syn_stream;
						break;
					case SPDY_CONTROL_FRAME_TYPES_GOAWAY:
						session->frame_handler = &spdyf_handler_read_goaway;
						break;
					case SPDY_CONTROL_FRAME_TYPES_RST_STREAM:
						session->frame_handler = &spdyf_handler_read_rst_stream;
						break;
					default:
						session->frame_handler = &SPDYF_handler_ignore_frame;
				}
				session->frame_handler_cls = control_frame;
				//DO NOT break the outer case
			}
			else if(0 == *(uint8_t *)(session->read_buffer + session->read_buffer_beginning))
			{
				//needed for POST
				//data frame
				if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
				{
					SPDYF_DEBUG("No memory");
					return SPDY_NO;
				}
				
				//get frame headers
				memcpy(data_frame,
					session->read_buffer + session->read_buffer_beginning,
					sizeof(struct SPDYF_Data_Frame));
				session->read_buffer_beginning += sizeof(struct SPDYF_Data_Frame);
				SPDYF_DATA_FRAME_NTOH(data_frame);
				
				session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
				session->frame_handler = &spdyf_handler_read_data;
				session->frame_handler_cls = data_frame;
				//DO NOT brake the outer case
			}
			else
			{
				SPDYF_DEBUG("another protocol or version received!");
				
				/* According to the draft the lib should send here
				 * RST_STREAM with status UNSUPPORTED_VERSION. I don't
				 * see any sense of keeping the session open since
				 * we don't know how many bytes is the bogus "frame".
				 * And the latter normally will be HTTP request.
				 * 
				 */
				
				//shutdown(session->socket_fd, SHUT_RD);
				session->status = SPDY_SESSION_STATUS_FLUSHING;
				SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_PROTOCOL_ERROR,false);
				//SPDYF_session_write(session,false);
				/* close connection since the client expects another
				protocol from us */
				//SPDYF_session_close(session);
				return SPDY_YES;
			}
			
		//expect specific header fields after the standard header
		case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER:
			if(NULL!=session->frame_handler)
			{
				read_buffer_beginning = session->read_buffer_beginning;
				//if everything is ok, the "body" will also be processed
				//by the handler
				session->frame_handler(session);
				
				if(SPDY_SESSION_STATUS_IGNORE_BYTES == session->status)
				{
					//check for larger than max supported frame
					if(session->frame_handler != &spdyf_handler_read_data)
					{	
						frame_length = ((struct SPDYF_Control_Frame *)session->frame_handler_cls)->length;
					}
					else
					{	
						frame_length = ((struct SPDYF_Data_Frame *)session->frame_handler_cls)->length;
					}
					
					//if(SPDY_MAX_SUPPORTED_FRAME_SIZE < frame_length)
					{
						SPDYF_DEBUG("received frame with unsupported size: %zu", frame_length);
						//the data being received must be ignored and
						//RST_STREAM sent
						
						//ignore bytes that will arive later
						session->read_ignore_bytes = frame_length
							+ read_buffer_beginning
							- session->read_buffer_offset;
						//ignore what is already in read buffer
						session->read_buffer_beginning = session->read_buffer_offset;
						
						SPDYF_prepare_rst_stream(session,
							session->current_stream_id > 0 ? session->streams_head : NULL, //may be 0 here which is not good
							SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE);
						
						//actually the read buffer can be bigger than the 
						//max supported size
						session->status = session->read_ignore_bytes
							? SPDY_SESSION_STATUS_IGNORE_BYTES
							: SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
							
						free(session->frame_handler_cls);
					}
				}
			}
			
			if(SPDY_SESSION_STATUS_IGNORE_BYTES != session->status)
			{
				break;
			}
			
		//ignoring data in read buffer
		case SPDY_SESSION_STATUS_IGNORE_BYTES:
			SPDYF_ASSERT(session->read_ignore_bytes > 0,
				"Session is in wrong state");
			if(session->read_ignore_bytes
				> session->read_buffer_offset - session->read_buffer_beginning)
			{
				session->read_ignore_bytes -= 
					session->read_buffer_offset - session->read_buffer_beginning;
				session->read_buffer_beginning = session->read_buffer_offset;
			}
			else
			{
				session->read_buffer_beginning += session->read_ignore_bytes;
				session->read_ignore_bytes = 0;
				session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
			}
			break;
			
		//expect frame body (name/value pairs)
		case SPDY_SESSION_STATUS_WAIT_FOR_BODY:
			if(NULL!=session->frame_handler)
				session->frame_handler(session);
			break;
			
		case SPDY_SESSION_STATUS_FLUSHING:
		
			return SPDY_NO;
			
		//because of error the session needs to be closed
		case SPDY_SESSION_STATUS_CLOSING:
			//error should be already sent to the client
			SPDYF_session_close(session);
			return SPDY_YES;
	}
	
	return SPDY_YES;
}
Пример #11
0
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;
}