C++程序  |  1247行  |  30.05 KB

/*
    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 structures.h
 * @brief  internal and public structures -- most of the structs used by
 * 			the library are defined here
 * @author Andrey Uzunov
 */

#ifndef STRUCTURES_H
#define STRUCTURES_H

#include "platform.h"
#include "microspdy.h"
#include "io.h"


/**
 * All possible SPDY control frame types. The number is used in the header
 * of the control frame.
 */
enum SPDY_CONTROL_FRAME_TYPES
{
	/**
	 * The SYN_STREAM control frame allows the sender to asynchronously
	 * create a stream between the endpoints.
	 */
	SPDY_CONTROL_FRAME_TYPES_SYN_STREAM = 1,
	
	/**
	 * SYN_REPLY indicates the acceptance of a stream creation by
	 * the recipient of a SYN_STREAM frame.
	 */
	SPDY_CONTROL_FRAME_TYPES_SYN_REPLY = 2,
	
	/**
	 * The RST_STREAM frame allows for abnormal termination of a stream.
	 * When sent by the creator of a stream, it indicates the creator
	 * wishes to cancel the stream. When sent by the recipient of a
	 * stream, it indicates an error or that the recipient did not want
	 * to accept the stream, so the stream should be closed.
	 */
	SPDY_CONTROL_FRAME_TYPES_RST_STREAM = 3,
	
	/**
	 * A SETTINGS frame contains a set of id/value pairs for
	 * communicating configuration data about how the two endpoints may
	 * communicate. SETTINGS frames can be sent at any time by either
	 * endpoint, are optionally sent, and are fully asynchronous. When
	 * the server is the sender, the sender can request that
	 * configuration data be persisted by the client across SPDY
	 * sessions and returned to the server in future communications.
	 */
	SPDY_CONTROL_FRAME_TYPES_SETTINGS = 4,
	
	/**
	 * The PING control frame is a mechanism for measuring a minimal
	 * round-trip time from the sender. It can be sent from the client
	 * or the server. Recipients of a PING frame should send an
	 * identical frame to the sender as soon as possible (if there is
	 * other pending data waiting to be sent, PING should take highest
	 * priority). Each ping sent by a sender should use a unique ID.
	 */
	SPDY_CONTROL_FRAME_TYPES_PING = 6,
	
	/**
	 * The GOAWAY control frame is a mechanism to tell the remote side
	 * of the connection to stop creating streams on this session. It
	 * can be sent from the client or the server.
	 */
	SPDY_CONTROL_FRAME_TYPES_GOAWAY = 7,
	
	/**
	 * The HEADERS frame augments a stream with additional headers. It
	 * may be optionally sent on an existing stream at any time.
	 * Specific application of the headers in this frame is
	 * application-dependent. The name/value header block within this
	 * frame is compressed.
	 */
	SPDY_CONTROL_FRAME_TYPES_HEADERS = 8,
	
	/**
	 * The WINDOW_UPDATE control frame is used to implement per stream
	 * flow control in SPDY. Flow control in SPDY is per hop, that is,
	 * only between the two endpoints of a SPDY connection. If there are
	 * one or more intermediaries between the client and the origin
	 * server, flow control signals are not explicitly forwarded by the
	 * intermediaries.
	 */
	SPDY_CONTROL_FRAME_TYPES_WINDOW_UPDATE = 9,
	
	/**
	 * The CREDENTIAL control frame is used by the client to send
	 * additional client certificates to the server. A SPDY client may
	 * decide to send requests for resources from different origins on
	 * the same SPDY session if it decides that that server handles both
	 * origins. For example if the IP address associated with both
	 * hostnames matches and the SSL server certificate presented in the
	 * initial handshake is valid for both hostnames. However, because
	 * the SSL connection can contain at most one client certificate,
	 * the client needs a mechanism to send additional client
	 * certificates to the server.
	 */
	SPDY_CONTROL_FRAME_TYPES_CREDENTIAL = 11
};


/**
 * SPDY_SESSION_STATUS is used to show the current receiving state 
 * of each session, i.e. what is expected to come now, and how it should
 * be handled.
 */
enum SPDY_SESSION_STATUS
{
	/**
	 * The session is in closing state, do not read read anything from
	 * it. Do not write anything to it.
	 */
	SPDY_SESSION_STATUS_CLOSING = 0,
	
	/**
	 * Wait for new SPDY frame to come.
	 */
	SPDY_SESSION_STATUS_WAIT_FOR_HEADER = 1,
	
	/**
	 * The standard 8 byte header of the SPDY frame was received and
	 * handled. Wait for the specific (sub)headers according to the
	 * frame type.
	 */
	SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER = 2,
	
	/**
	 * The specific (sub)headers were received and handled. Wait for the
	 * "body", i.e. wait for the name/value pairs compressed by zlib.
	 */
	SPDY_SESSION_STATUS_WAIT_FOR_BODY = 3,
	
	/**
	 * Ignore all the bytes read from the socket, e.g. larger frames.
	 */
	SPDY_SESSION_STATUS_IGNORE_BYTES= 4,
	
	/**
	 * The session is in pre-closing state, do not read read anything
	 * from it. In this state the output queue will be written to the
	 * socket.
	 */
	SPDY_SESSION_STATUS_FLUSHING = 5,
};


/**
 * Specific flags for the SYN_STREAM control frame.
 */
enum SPDY_SYN_STREAM_FLAG
{
	/**
	 * The sender won't send any more frames on this stream.
	 */
	SPDY_SYN_STREAM_FLAG_FIN = 1,
	
	/**
	 * The sender creates this stream as unidirectional.
	 */
	SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL = 2
};


/**
 * Specific flags for the SYN_REPLY control frame.
 */
enum SPDY_SYN_REPLY_FLAG
{
	/**
	 * The sender won't send any more frames on this stream.
	 */
	SPDY_SYN_REPLY_FLAG_FIN = 1
};


/**
 * Specific flags for the data frame.
 */
enum SPDY_DATA_FLAG
{
	/**
	 * The sender won't send any more frames on this stream.
	 */
	SPDY_DATA_FLAG_FIN = 1,
	
	/**
	 * The data in the frame is compressed. 
	 * This flag appears only in the draft on ietf.org but not on
	 * chromium.org.
	 */
	SPDY_DATA_FLAG_COMPRESS = 2
};

/**
 * Status code within RST_STREAM control frame.
 */
enum SPDY_RST_STREAM_STATUS
{
	/**
	 * This is a generic error, and should only be used if a more
	 * specific error is not available.
	 */
	SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR = 1,
	
	/**
	 * This is returned when a frame is received for a stream which is
	 * not active.
	 */
	SPDY_RST_STREAM_STATUS_INVALID_STREAM = 2,
	
	/**
	 * Indicates that the stream was refused before any processing has
	 * been done on the stream.
	 */
	SPDY_RST_STREAM_STATUS_REFUSED_STREAM = 3,
	
	/**
	 * Indicates that the recipient of a stream does not support the
	 * SPDY version requested.
	 */
	SPDY_RST_STREAM_STATUS_UNSUPPORTED_VERSION = 4,
	
	/**
	 * Used by the creator of a stream to indicate that the stream is
	 * no longer needed.
	 */
	SPDY_RST_STREAM_STATUS_CANCEL = 5,
	
	/**
	 * This is a generic error which can be used when the implementation
	 * has internally failed, not due to anything in the protocol.
	 */
	SPDY_RST_STREAM_STATUS_INTERNAL_ERROR = 6,
	
	/**
	 * The endpoint detected that its peer violated the flow control
	 * protocol.
	 */
	SPDY_RST_STREAM_STATUS_FLOW_CONTROL_ERROR = 7,
	
	/**
	 * The endpoint received a SYN_REPLY for a stream already open.
	 */
	SPDY_RST_STREAM_STATUS_STREAM_IN_USE = 8,
	
	/**
	 * The endpoint received a data or SYN_REPLY frame for a stream
	 * which is half closed.
	 */
	SPDY_RST_STREAM_STATUS_STREAM_ALREADY_CLOSED = 9,
	
	/**
	 * The server received a request for a resource whose origin does
	 * not have valid credentials in the client certificate vector.
	 */
	SPDY_RST_STREAM_STATUS_INVALID_CREDENTIALS = 10,
	
	/**
	 * The endpoint received a frame which this implementation could not
	 * support. If FRAME_TOO_LARGE is sent for a SYN_STREAM, HEADERS,
	 * or SYN_REPLY frame without fully processing the compressed
	 * portion of those frames, then the compression state will be
	 * out-of-sync with the other endpoint. In this case, senders of
	 * FRAME_TOO_LARGE MUST close the session.
	 */
	SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE = 11
};


/**
 * Status code within GOAWAY control frame.
 */
enum SPDY_GOAWAY_STATUS
{
	/**
	 * This is a normal session teardown.
	 */
	SPDY_GOAWAY_STATUS_OK = 0,
	
	/**
	 * This is a generic error, and should only be used if a more
	 * specific error is not available.
	 */
	SPDY_GOAWAY_STATUS_PROTOCOL_ERROR = 1,
	
	/**
	 * This is a generic error which can be used when the implementation
	 * has internally failed, not due to anything in the protocol.
	 */
	SPDY_GOAWAY_STATUS_INTERNAL_ERROR = 11
};


struct SPDYF_Stream;

struct SPDYF_Response_Queue;


/**
 * Callback for received new data chunk.
 *
 * @param cls client-defined closure
 * @param stream handler
 * @param buf data chunk from the data
 * @param size the size of the data chunk 'buf' in bytes
 * @param more false if this is the last frame received on this stream. Note:
 *             true does not mean that more data will come, exceptional
 *             situation is possible
 * @return SPDY_YES to continue calling the function,
 *         SPDY_NO to stop calling the function for this stream
 */
typedef int
(*SPDYF_NewDataCallback) (void * cls,
					 struct SPDYF_Stream *stream,
					 const void * buf,
					 size_t size,
					 bool more);
           
           
/**
 * Callback for new stream. To be used in the application layer of the
 * lib.
 *
 * @param cls
 * @param stream the new stream
 * @return SPDY_YES on success,
 *         SPDY_NO if error occurs
 */
typedef int
(*SPDYF_NewStreamCallback) (void *cls,
						struct SPDYF_Stream * stream);


/**
 * Callback to be called when the response queue object was handled and 
 * the data was already sent. 
 *
 * @param cls
 * @param response_queue the SPDYF_Response_Queue structure which will
 * 			be cleaned very soon
 * @param status shows if actually the response was sent or it was
 * 			discarded by the lib for any reason (e.g., closing session,
 * 			closing stream, stopping daemon, etc.). It is possible that
 * 			status indicates an error but part of the response (in one
 * 			or several frames) was sent to the client.
 */
typedef void
(*SPDYF_ResponseQueueResultCallback) (void * cls,
								struct SPDYF_Response_Queue *response_queue,
								enum SPDY_RESPONSE_RESULT status);


/**
 * Representation of the control frame's headers, which are common for
 * all types.
 */
struct __attribute__((__packed__)) SPDYF_Control_Frame
{
	uint16_t version : 15;
	uint16_t control_bit : 1; /* always 1 for control frames */
	uint16_t type;
	uint32_t flags : 8;
	uint32_t length : 24;
};


/**
 * Representation of the data frame's headers.
 */
struct __attribute__((__packed__)) SPDYF_Data_Frame
{
	uint32_t stream_id : 31;
	uint32_t control_bit : 1; /* always 0 for data frames */
	uint32_t flags : 8;
	uint32_t length : 24;
};


/**
 * Queue of the responses, to be handled (e.g. compressed) and sent later.
 */
struct SPDYF_Response_Queue
{
	/**
	 * This is a doubly-linked list.
	 */
	struct SPDYF_Response_Queue *next;

	/**
	 * This is a doubly-linked list.
	 */
	struct SPDYF_Response_Queue *prev;

	/**
	 * Stream (Request) for which is the response.
	 */
	struct SPDYF_Stream *stream;

	/**
	 * Response structure with all the data (uncompressed headers) to be sent.
	 */
	struct SPDY_Response *response;

	/**
	 * Control frame. The length field should be set after compressing
	 * the headers!
	 */
	struct SPDYF_Control_Frame *control_frame;

	/**
	 * Data frame. The length field should be set after compressing
	 * the body!
	 */
	struct SPDYF_Data_Frame *data_frame;

	/**
	 * Data to be sent: name/value pairs in control frames or body in data frames.
	 */
	void *data;

	/**
	 * Specific handler for different frame types.
	 */
	int (* process_response_handler)(struct SPDY_Session *session);

	/**
	 * Callback to be called when the last bytes from the response was sent
	 * to the client.
	 */
	SPDYF_ResponseQueueResultCallback frqcb;
	
	/**
	 * Closure for frqcb.
	 */
	void *frqcb_cls;

	/**
	 * Callback to be used by the application layer.
	 */
	SPDY_ResponseResultCallback rrcb;
	
	/**
	 * Closure for rcb.
	 */
	void *rrcb_cls;

	/**
	 * Data size.
	 */
	size_t data_size;

	/**
	 * True if data frame should be sent. False if control frame should
	 * be sent.
	 */
	bool is_data;
};



/**
 * Collection of HTTP headers used in requests and responses.
 */
struct SPDY_NameValue
{
	/**
	* This is a doubly-linked list.
	*/
	struct SPDY_NameValue *next;

	/**
	* This is a doubly-linked list.
	*/
	struct SPDY_NameValue *prev;

	/**
	* Null terminated string for name.
	*/
    char *name;

	/**
	* Array of Null terminated strings for value. num_values is the
	* length of the array.
	*/
	char **value;

	/**
	* Number of values, this is >= 0.
	*/
	unsigned int num_values;
};


/**
 * Represents a SPDY stream
 */ 
struct SPDYF_Stream
{
	/**
	 * This is a doubly-linked list.
	 */
	struct SPDYF_Stream *next;

	/**
	 * This is a doubly-linked list.
	 */
	struct SPDYF_Stream *prev;

	/**
	 * Reference to the SPDY_Session struct.
	 */
	struct SPDY_Session *session;
	
	/**
	 * Name value pairs, sent within the frame which created the stream.
	 */
	struct SPDY_NameValue *headers;
	
	/**
	 * Any object to be used by the application layer.
	 */
	void *cls;
  
	/**
	 * This stream's ID.
	 */
	uint32_t stream_id;
	
	/**
	 * Stream to which this one is associated.
	 */
	uint32_t assoc_stream_id;
	
	/**
	 * The window of the data within data frames.
	 */
	uint32_t window_size;
	
	/**
	 * Stream priority. 0 is the highest, 7 is the lowest.
	 */
	uint8_t priority;
	
	/**
	 * Integer specifying the index in the server's CREDENTIAL vector of
	 * the client certificate to be used for this request The value 0
	 * means no client certificate should be associated with this stream.
	 */
	uint8_t slot;
	
	/**
	 * If initially the stream was created as unidirectional.
	 */
	bool flag_unidirectional;
	
	/**
	 * If the stream won't be used for receiving frames anymore. The 
	 * client has sent FLAG_FIN or the stream was terminated with
	 * RST_STREAM.
	 */
	bool is_in_closed;
	
	/**
	 * If the stream won't be used for sending out frames anymore. The 
	 * server has sent FLAG_FIN or the stream was terminated with
	 * RST_STREAM.
	 */
	bool is_out_closed;
	
	/**
	 * Which entity (server/client) has created the stream.
	 */
	bool is_server_initiator;
};


/**
 * Represents a SPDY session which is just a TCP connection
 */ 
struct SPDY_Session
{
	/**
	 * zlib stream for decompressing all the name/pair values from the
	 * received frames. All the received compressed data must be
	 * decompressed within one context: this stream. Thus, it should be
	 * unique for the session and initialized at its creation.
	 */
	z_stream zlib_recv_stream;

	/**
	 * zlib stream for compressing all the name/pair values from the
	 * frames to be sent. All the sent compressed data must be
	 * compressed within one context: this stream. Thus, it should be
	 * unique for the session and initialized at its creation.
	 */
	z_stream zlib_send_stream;
	
	/**
	 * This is a doubly-linked list.
	 */
	struct SPDY_Session *next;

	/**
	 * This is a doubly-linked list.
	 */
	struct SPDY_Session *prev;

	/**
	 * Reference to the SPDY_Daemon struct.
	 */
	struct SPDY_Daemon *daemon;

	/**
	 * Foreign address (of length addr_len).
	 */
	struct sockaddr *addr;

	/**
	 * Head of doubly-linked list of the SPDY streams belonging to the
	 * session.
	 */
	struct SPDYF_Stream *streams_head;

	/**
	 * Tail of doubly-linked list of the streams.
	 */
	struct SPDYF_Stream *streams_tail;

	/**
	 * Unique IO context for the session. Initialized on each creation
	 * (actually when the TCP connection is established).
	 */
	void *io_context;
	
	/**
	 * Head of doubly-linked list of the responses.
	 */
	struct SPDYF_Response_Queue *response_queue_head;
	
	/**
	 * Tail of doubly-linked list of the responses.
	 */
	struct SPDYF_Response_Queue *response_queue_tail;

	/**
	 * Buffer for reading requests.
	 */
	void *read_buffer;

	/**
	 * Buffer for writing responses.
	 */
	void *write_buffer;

	/**
	 * Specific handler for the frame that is currently being received.
	 */
	void (*frame_handler) (struct SPDY_Session * session);

	/**
	 * Closure for frame_handler.
	 */
	void *frame_handler_cls;

	/**
	 * Extra field to be used by the user with set/get func for whatever
	 * purpose he wants.
	 */
	void *user_cls;

	/**
	 * Function to initialize the IO context for a new session.
	 */
	SPDYF_IONewSession fio_new_session;

	/**
	 * Function to deinitialize the IO context for a session.
	 */
	SPDYF_IOCloseSession fio_close_session;

	/**
	 * Function to read data from socket.
	 */
	SPDYF_IORecv fio_recv;

	/**
	 * Function to write data to socket.
	 */
	SPDYF_IOSend fio_send;

	/**
	 * Function to check for pending data in IO buffers.
	 */
	SPDYF_IOIsPending fio_is_pending;

	/**
	 * Function to call before writing set of frames.
	 */
	SPDYF_IOBeforeWrite fio_before_write;

	/**
	 * Function to call after writing set of frames.
	 */
	SPDYF_IOAfterWrite fio_after_write;

	/**
	 * Number of bytes that the lib must ignore immediately after they 
	 * are read from the TLS socket without adding them to the read buf.
	 * This is needed, for instance, when receiving frame bigger than
	 * the buffer to avoid deadlock situations.
	 */
	size_t read_ignore_bytes;

	/**
	 * Size of read_buffer (in bytes).  This value indicates
	 * how many bytes we're willing to read into the buffer;
	 * the real buffer is one byte longer to allow for
	 * adding zero-termination (when needed).
	 */
	size_t read_buffer_size;

	/**
	 * Position where we currently append data in
	 * read_buffer (last valid position).
	 */
	size_t read_buffer_offset;

	/**
	 * Position until where everything was already read
	 */
	size_t read_buffer_beginning;

	/**
	 * Size of write_buffer (in bytes).  This value indicates
	 * how many bytes we're willing to prepare for writing.
	 */
	size_t write_buffer_size;

	/**
	 * Position where we currently append data in
	 * write_buffer (last valid position).
	 */
	size_t write_buffer_offset;

	/**
	 * Position until where everything was already written to the socket
	 */
	size_t write_buffer_beginning;
	
	/**
	 * Last time this connection had any activity
	 * (reading or writing). In milliseconds.
	 */
	unsigned long long last_activity;

	/**
	 * Socket for this connection.  Set to -1 if
	 * this connection has died (daemon should clean
	 * up in that case).
	 */
	int socket_fd;

	/**
	 * Length of the foreign address.
	 */
	socklen_t addr_len;
	
	/**
	 * The biggest stream ID for this session for streams initiated
	 * by the client.
	 */
	uint32_t last_in_stream_id;
	
	/**
	 * The biggest stream ID for this session for streams initiated
	 * by the server.
	 */
	uint32_t last_out_stream_id;
	
	/**
	 * This value is updated whenever SYN_REPLY or RST_STREAM are sent
	 * and is used later in GOAWAY frame.
	 * TODO it is not clear in the draft what happens when streams are
	 * not answered in the order of their IDs. Moreover, why should we
	 * send GOAWAY with the ID of received bogus SYN_STREAM with huge ID?
	 */
	uint32_t last_replied_to_stream_id;
	
	/**
	 * Shows the stream id of the currently handled frame. This value is
	 * to be used when sending RST_STREAM in answer to a problematic
	 * frame, e.g. larger than supported.
	 */
	uint32_t current_stream_id;
	
	/**
	 * Maximum number of frames to be written to the socket at once. The
   * library tries to send max_num_frames in a single call to SPDY_run
   * for a single session. This means no requests can be received nor
   * other sessions can send data as long the current one has enough
   * frames to send and there is no error on writing.
	 */
	uint32_t max_num_frames;

	/**
	 * Shows the current receiving state the session, i.e. what is
	 * expected to come now, and how it shold be handled.
	 */
	enum SPDY_SESSION_STATUS status;

	/**
	 * Has this socket been closed for reading (i.e.
	 * other side closed the connection)?  If so,
	 * we must completely close the connection once
	 * we are done sending our response (and stop
	 * trying to read from this socket).
	 */
	bool read_closed;

	/**
	 * If the server sends GOAWAY, it must ignore all SYN_STREAMS for
	 * this session. Normally the server will soon close the TCP session.
	 */
	bool is_goaway_sent;

	/**
	 * If the server receives GOAWAY, it must not send new SYN_STREAMS 
	 * on this session. Normally the client will soon close the TCP
	 * session.
	 */
	bool is_goaway_received;
};


/**
 * State and settings kept for each SPDY daemon.
 */
struct SPDY_Daemon
{

	/**
	 * Tail of doubly-linked list of our current, active sessions.
	 */
	struct SPDY_Session *sessions_head;

	/**
	 * Tail of doubly-linked list of our current, active sessions.
	 */
	struct SPDY_Session *sessions_tail;
	
	/**
	 * Tail of doubly-linked list of connections to clean up.
	 */
	struct SPDY_Session *cleanup_head;

	/**
	 * Tail of doubly-linked list of connections to clean up.
	 */
	struct SPDY_Session *cleanup_tail;

	/**
	 * Unique IO context for the daemon. Initialized on daemon start.
	 */
	void *io_context;

	/**
	 * Certificate file of the server. File path is kept here.
	 */
	char *certfile;

	/**
	 * Key file for the certificate of the server. File path is
	 * kept here.
	 */
	char *keyfile;
	

	/**
	 * The address to which the listening socket is bound.
	 */
	struct sockaddr *address;
	
	/**
	 * Callback called when a new SPDY session is
	 * established by a client
	 */
	SPDY_NewSessionCallback new_session_cb;

	/**
	 * Callback called when a client closes the session
	 */
	SPDY_SessionClosedCallback session_closed_cb;

	/**
	 * Callback called when a client sends request
	 */
	SPDY_NewRequestCallback new_request_cb;

	/**
	* Callback called when HTTP POST params are received
	* after request. To be used by the application layer
	*/
	SPDY_NewDataCallback received_data_cb;

	/**
	* Callback called when DATA frame is received.
	*/
	SPDYF_NewDataCallback freceived_data_cb;

	/**
	 * Closure argument for all the callbacks that can be used by the client.
	 */
	void *cls;

	/**
	 * Callback called when new stream is created.
	 */
	SPDYF_NewStreamCallback fnew_stream_cb;

	/**
	 * Closure argument for all the callbacks defined in the framing layer.
	 */
	void *fcls;

	/**
	 * Function to initialize the IO context for the daemon.
	 */
	SPDYF_IOInit fio_init;

	/**
	 * Function to deinitialize the IO context for the daemon.
	 */
	SPDYF_IODeinit fio_deinit;

	/**
	 * After how many milliseconds of inactivity should
	 * connections time out? Zero for no timeout.
	 */
	unsigned long long session_timeout;

	/**
	 * Listen socket.
	 */
	int socket_fd;
	
	/**
   * This value is inherited by all sessions of the daemon.
	 * Maximum number of frames to be written to the socket at once. The
   * library tries to send max_num_frames in a single call to SPDY_run
   * for a single session. This means no requests can be received nor
   * other sessions can send data as long the current one has enough
   * frames to send and there is no error on writing.
	 */
	uint32_t max_num_frames;

	/**
	 * Daemon's options.
	 */
	enum SPDY_DAEMON_OPTION options;

	/**
	 * Daemon's flags.
	 */
	enum SPDY_DAEMON_FLAG flags;

	/**
	 * IO subsystem type used by daemon and all its sessions.
	 */
	enum SPDY_IO_SUBSYSTEM io_subsystem;

	/**
	 * Listen port.
	 */
	uint16_t port;
};


/**
 * Represents a SPDY response.
 */
struct SPDY_Response
{
	/**
	 * Raw uncompressed stream of the name/value pairs in SPDY frame
	 * used for the HTTP headers.
	 */
    void *headers;
	
	/**
	 * Raw stream of the data to be sent. Equivalent to the body in HTTP
	 * response.
	 */
	void *data;
	
	/**
	 * Callback function to be used when the response data is provided
	 * with callbacks. In this case data must be NULL and data_size must
	 * be 0.
	 */
	SPDY_ResponseCallback rcb;
	
	/**
	 * Extra argument to rcb.
	 */
	void *rcb_cls;
	
	/**
	 * Length of headers.
	 */
	size_t headers_size;
	
	/**
	 * Length of data.
	 */
	size_t data_size;
	
	/**
	 * The callback func will be called to get that amount of bytes to
	 * put them into a DATA frame. It is either user preffered or
	 * the maximum supported by the lib value.
	 */
	uint32_t rcb_block_size;
};


/* Macros for handling data and structures */


/**
 * Insert an element at the head of a DLL. Assumes that head, tail and
 * element are structs with prev and next fields.
 *
 * @param head pointer to the head of the DLL (struct ? *)
 * @param tail pointer to the tail of the DLL (struct ? *)
 * @param element element to insert (struct ? *)
 */
#define DLL_insert(head,tail,element) do { \
	(element)->next = (head); \
	(element)->prev = NULL; \
	if ((tail) == NULL) \
		(tail) = element; \
	else \
		(head)->prev = element; \
	(head) = (element); } while (0)


/**
 * Remove an element from a DLL. Assumes
 * that head, tail and element are structs
 * with prev and next fields.
 *
 * @param head pointer to the head of the DLL (struct ? *)
 * @param tail pointer to the tail of the DLL (struct ? *)
 * @param element element to remove (struct ? *)
 */
#define DLL_remove(head,tail,element) do { \
	if ((element)->prev == NULL) \
		(head) = (element)->next;  \
	else \
		(element)->prev->next = (element)->next; \
	if ((element)->next == NULL) \
		(tail) = (element)->prev;  \
	else \
		(element)->next->prev = (element)->prev; \
	(element)->next = NULL; \
	(element)->prev = NULL; } while (0)


/**
 * Convert all integers in a SPDY control frame headers structure from
 * host byte order to network byte order.
 *
 * @param frame input and output structure (struct SPDY_Control_Frame *)
 */
#if HAVE_BIG_ENDIAN
#define SPDYF_CONTROL_FRAME_HTON(frame)
#else
#define SPDYF_CONTROL_FRAME_HTON(frame) do { \
	(*((uint16_t *) frame  )) = (*((uint8_t *) (frame) +1 )) | ((*((uint8_t *) frame  ))<<8);\
	(frame)->type = htons((frame)->type); \
	(frame)->length = HTON24((frame)->length); \
	} while (0)
#endif


/**
 * Convert all integers in a SPDY control frame headers structure from
 * network byte order to host byte order.
 *
 * @param frame input and output structure (struct SPDY_Control_Frame *)
 */	
#if HAVE_BIG_ENDIAN
#define SPDYF_CONTROL_FRAME_NTOH(frame)
#else
#define SPDYF_CONTROL_FRAME_NTOH(frame) do { \
	(*((uint16_t *) frame  )) = (*((uint8_t *) (frame) +1 )) | ((*((uint8_t *) frame  ))<<8);\
	(frame)->type = ntohs((frame)->type); \
	(frame)->length = NTOH24((frame)->length); \
	} while (0)
#endif


/**
 * Convert all integers in a SPDY data frame headers structure from
 * host byte order to network byte order.
 *
 * @param frame input and output structure (struct SPDY_Data_Frame *)
 */
#if HAVE_BIG_ENDIAN
#define SPDYF_DATA_FRAME_HTON(frame)
#else
#define SPDYF_DATA_FRAME_HTON(frame) do { \
	*((uint32_t *) frame  ) = htonl(*((uint32_t *) frame  ));\
	(frame)->length = HTON24((frame)->length); \
	} while (0)
#endif


/**
 * Convert all integers in a SPDY data frame headers structure from
 * network byte order to host byte order.
 *
 * @param frame input and output structure (struct SPDY_Data_Frame *)
 */	
#if HAVE_BIG_ENDIAN
#define SPDYF_DATA_FRAME_NTOH(frame)
#else
#define SPDYF_DATA_FRAME_NTOH(frame) do { \
	*((uint32_t *) frame  ) = ntohl(*((uint32_t *) frame  ));\
	(frame)->length = NTOH24((frame)->length); \
	} while (0)
#endif


/**
 * Creates one or more new SPDYF_Response_Queue object to be put on the
 * response queue.
 *
 * @param is_data whether new data frame or new control frame will be
 *                crerated
 * @param data the row stream which will be used as the body of the frame
 * @param data_size length of data
 * @param response object, part of which is the frame
 * @param stream on which data is to be sent 
 * @param closestream TRUE if the frame must close the stream (with flag) 
 * @param frqcb callback to notify application layer when the frame
 *              has been sent or discarded 
 * @param frqcb_cls closure for frqcb
 * @param rrcb callback used by the application layer to notify the
 *             application when the frame has been sent or discarded.
 *             frqcb will call it 
 * @param rrcb_cls closure for rrcb
 * @return double linked list of SPDYF_Response_Queue structures: one or
 *         more frames are returned based on the size of the data
 */
struct SPDYF_Response_Queue *
SPDYF_response_queue_create(bool is_data,
						void *data,
						size_t data_size,
						struct SPDY_Response *response,
						struct SPDYF_Stream *stream,
						bool closestream,
						SPDYF_ResponseQueueResultCallback frqcb,
						void *frqcb_cls,
						SPDY_ResponseResultCallback rrcb,
						void *rrcb_cls);


/**
 * Destroys SPDYF_Response_Queue structure and whatever is in it.
 *
 * @param response_queue to destroy
 */
void
SPDYF_response_queue_destroy(struct SPDYF_Response_Queue *response_queue);


/**
 * Checks if the container is empty, i.e. created but no values were
 * added to it.
 *
 * @param container
 * @return SPDY_YES if empty
 *         SPDY_NO if not
 */
int
SPDYF_name_value_is_empty(struct SPDY_NameValue *container);


/**
 * Transforms raw binary decomressed stream of headers
 * into SPDY_NameValue, containing all of the headers and values.
 *
 * @param stream that is to be transformed
 * @param size length of the stream
 * @param container will contain the newly created SPDY_NameValue
 *        container. Should point to NULL.
 * @return SPDY_YES on success
 *         SPDY_NO on memory error
 *         SPDY_INPUT_ERROR if the provided stream is not valid
 */
int
SPDYF_name_value_from_stream(void *stream,
							size_t size,
							struct SPDY_NameValue ** container);


/**
 * Transforms array of objects of name/values tuples, containing HTTP
 * headers, into raw binary stream. The resulting stream is ready to
 * be compressed and sent.
 *
 * @param container one or more SPDY_NameValue objects. Each object
 *        contains multiple number of name/value tuples.
 * @param num_containers length of the array
 * @param stream will contain the resulting stream. Should point to NULL.
 * @return length of stream or value less than 0 indicating error
 */
ssize_t
SPDYF_name_value_to_stream(struct SPDY_NameValue * container[],
							int num_containers,
							void **stream);

#endif