/* 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