blob: e1f8797a5849d6ef65d922674c130b6a85fa4c99 [file] [log] [blame]
/*
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