/*1* nghttp2 - HTTP/2 C Library2*3* Copyright (c) 2014 Tatsuhiro Tsujikawa4*5* Permission is hereby granted, free of charge, to any person obtaining6* a copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sublicense, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice shall be14* included in all copies or substantial portions of the Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,17* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF18* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND19* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE20* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION21* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION22* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.23*/24#ifndef NGHTTP2_BUF_H25#define NGHTTP2_BUF_H2627#ifdef HAVE_CONFIG_H28# include <config.h>29#endif /* HAVE_CONFIG_H */3031#include <nghttp2/nghttp2.h>3233#include "nghttp2_int.h"34#include "nghttp2_mem.h"3536typedef struct {37/* This points to the beginning of the buffer. The effective range38of buffer is [begin, end). */39uint8_t *begin;40/* This points to the memory one byte beyond the end of the41buffer. */42uint8_t *end;43/* The position indicator for effective start of the buffer. pos <=44last must be hold. */45uint8_t *pos;46/* The position indicator for effective one beyond of the end of the47buffer. last <= end must be hold. */48uint8_t *last;49/* Mark arbitrary position in buffer [begin, end) */50uint8_t *mark;51} nghttp2_buf;5253#define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos))54#define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last))55#define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last))56#define nghttp2_buf_cap(BUF) ((size_t)((BUF)->end - (BUF)->begin))5758#define nghttp2_buf_pos_offset(BUF) ((size_t)((BUF)->pos - (BUF)->begin))59#define nghttp2_buf_last_offset(BUF) ((size_t)((BUF)->last - (BUF)->begin))6061#define nghttp2_buf_shift_right(BUF, AMT) \62do { \63(BUF)->pos += AMT; \64(BUF)->last += AMT; \65} while (0)6667#define nghttp2_buf_shift_left(BUF, AMT) \68do { \69(BUF)->pos -= AMT; \70(BUF)->last -= AMT; \71} while (0)7273/*74* Initializes the |buf|. No memory is allocated in this function. Use75* nghttp2_buf_reserve() to allocate memory.76*/77void nghttp2_buf_init(nghttp2_buf *buf);7879/*80* Initializes the |buf| and allocates at least |initial| bytes of81* memory.82*83* This function returns 0 if it succeeds, or one of the following84* negative error codes:85*86* NGHTTP2_ERR_NOMEM87* Out of memory88*/89int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem);9091/*92* Frees buffer in |buf|.93*/94void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);9596/*97* Extends buffer so that nghttp2_buf_cap() returns at least98* |new_cap|. If extensions took place, buffer pointers in |buf| will99* change.100*101* This function returns 0 if it succeeds, or one of the following102* negative error codes:103*104* NGHTTP2_ERR_NOMEM105* Out of memory106*/107int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem);108109/*110* Resets pos, last, mark member of |buf| to buf->begin.111*/112void nghttp2_buf_reset(nghttp2_buf *buf);113114/*115* Initializes |buf| using supplied buffer |begin| of length116* |len|. Semantically, the application should not call *_reserve() or117* nghttp2_free() functions for |buf|.118*/119void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len);120121struct nghttp2_buf_chain;122123typedef struct nghttp2_buf_chain nghttp2_buf_chain;124125/* Chains 2 buffers */126struct nghttp2_buf_chain {127/* Points to the subsequent buffer. NULL if there is no such128buffer. */129nghttp2_buf_chain *next;130nghttp2_buf buf;131};132133typedef struct {134/* Points to the first buffer */135nghttp2_buf_chain *head;136/* Buffer pointer where write occurs. */137nghttp2_buf_chain *cur;138/* Memory allocator */139nghttp2_mem *mem;140/* The buffer capacity of each buf. This field may be 0 if141nghttp2_bufs is initialized by nghttp2_bufs_wrap_init* family142functions. */143size_t chunk_length;144/* The maximum number of nghttp2_buf_chain */145size_t max_chunk;146/* The number of nghttp2_buf_chain allocated */147size_t chunk_used;148/* The number of nghttp2_buf_chain to keep on reset */149size_t chunk_keep;150/* pos offset from begin in each buffers. On initialization and151reset, buf->pos and buf->last are positioned at buf->begin +152offset. */153size_t offset;154} nghttp2_bufs;155156/*157* This is the same as calling nghttp2_bufs_init2 with the given158* arguments and offset = 0.159*/160int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,161nghttp2_mem *mem);162163/*164* This is the same as calling nghttp2_bufs_init3 with the given165* arguments and chunk_keep = max_chunk.166*/167int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,168size_t max_chunk, size_t offset, nghttp2_mem *mem);169170/*171* Initializes |bufs|. Each buffer size is given in the172* |chunk_length|. The maximum number of buffers is given in the173* |max_chunk|. On reset, first |chunk_keep| buffers are kept and174* remaining buffers are deleted. Each buffer will have bufs->pos and175* bufs->last shifted to left by |offset| bytes on creation and reset.176*177* This function allocates first buffer. bufs->head and bufs->cur178* will point to the first buffer after this call.179*180* This function returns 0 if it succeeds, or one of the following181* negative error codes:182*183* NGHTTP2_ERR_NOMEM184* Out of memory.185* NGHTTP2_ERR_INVALID_ARGUMENT186* chunk_keep is 0; or max_chunk < chunk_keep; or offset is too187* long.188*/189int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,190size_t max_chunk, size_t chunk_keep, size_t offset,191nghttp2_mem *mem);192193/*194* Frees any related resources to the |bufs|.195*/196void nghttp2_bufs_free(nghttp2_bufs *bufs);197198/*199* Initializes |bufs| using supplied buffer |begin| of length |len|.200* The first buffer bufs->head uses buffer |begin|. The buffer size201* is fixed and no extra chunk buffer is allocated. In other202* words, max_chunk = chunk_keep = 1. To free the resource allocated203* for |bufs|, use nghttp2_bufs_wrap_free().204*205* Don't use the function which performs allocation, such as206* nghttp2_bufs_realloc().207*208* This function returns 0 if it succeeds, or one of the following209* negative error codes:210*211* NGHTTP2_ERR_NOMEM212* Out of memory.213*/214int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,215nghttp2_mem *mem);216217/*218* Initializes |bufs| using supplied |veclen| size of buf vector219* |vec|. The number of buffers is fixed and no extra chunk buffer is220* allocated. In other words, max_chunk = chunk_keep = |in_len|. To221* free the resource allocated for |bufs|, use222* nghttp2_bufs_wrap_free().223*224* Don't use the function which performs allocation, such as225* nghttp2_bufs_realloc().226*227* This function returns 0 if it succeeds, or one of the following228* negative error codes:229*230* NGHTTP2_ERR_NOMEM231* Out of memory.232*/233int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec,234size_t veclen, nghttp2_mem *mem);235236/*237* Frees any related resource to the |bufs|. This function does not238* free supplied buffer provided in nghttp2_bufs_wrap_init().239*/240void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs);241242/*243* Reallocates internal buffer using |chunk_length|. The max_chunk,244* chunk_keep and offset do not change. After successful allocation245* of new buffer, previous buffers are deallocated without copying246* anything into new buffers. chunk_used is reset to 1.247*248* This function returns 0 if it succeeds, or one of the following249* negative error codes:250*251* NGHTTP2_ERR_NOMEM252* Out of memory.253* NGHTTP2_ERR_INVALID_ARGUMENT254* chunk_length < offset255*/256int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length);257258/*259* Appends the |data| of length |len| to the |bufs|. The write starts260* at bufs->cur->buf.last. A new buffers will be allocated to store261* all data.262*263* This function returns 0 if it succeeds, or one of the following264* negative error codes:265*266* NGHTTP2_ERR_NOMEM267* Out of memory.268* NGHTTP2_ERR_BUFFER_ERROR269* Out of buffer space.270*/271int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len);272273/*274* Appends a single byte |b| to the |bufs|. The write starts at275* bufs->cur->buf.last. A new buffers will be allocated to store all276* data.277*278* This function returns 0 if it succeeds, or one of the following279* negative error codes:280*281* NGHTTP2_ERR_NOMEM282* Out of memory.283* NGHTTP2_ERR_BUFFER_ERROR284* Out of buffer space.285*/286int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b);287288/*289* Behaves like nghttp2_bufs_addb(), but this does not update290* buf->last pointer.291*/292int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b);293294#define nghttp2_bufs_fast_addb(BUFS, B) \295do { \296*(BUFS)->cur->buf.last++ = B; \297} while (0)298299#define nghttp2_bufs_fast_addb_hold(BUFS, B) \300do { \301*(BUFS)->cur->buf.last = B; \302} while (0)303304/*305* Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers306* will be allocated if necessary.307*308* This function returns 0 if it succeeds, or one of the following309* negative error codes:310*311* NGHTTP2_ERR_NOMEM312* Out of memory.313* NGHTTP2_ERR_BUFFER_ERROR314* Out of buffer space.315*/316int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b);317318/*319* Behaves like nghttp2_bufs_orb(), but does not update buf->last320* pointer.321*/322int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);323324#define nghttp2_bufs_fast_orb(BUFS, B) \325do { \326uint8_t **p = &(BUFS)->cur->buf.last; \327**p = (uint8_t)(**p | (B)); \328++(*p); \329} while (0)330331#define nghttp2_bufs_fast_orb_hold(BUFS, B) \332do { \333uint8_t *p = (BUFS)->cur->buf.last; \334*p = (uint8_t)(*p | (B)); \335} while (0)336337/*338* Copies all data stored in |bufs| to the contiguous buffer. This339* function allocates the contiguous memory to store all data in340* |bufs| and assigns it to |*out|.341*342* The contents of |bufs| is left unchanged.343*344* This function returns the length of copied data and assigns the345* pointer to copied data to |*out| if it succeeds, or one of the346* following negative error codes:347*348* NGHTTP2_ERR_NOMEM349* Out of memory350*/351ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);352353/*354* Copies all data stored in |bufs| to |out|. This function assumes355* that the buffer space pointed by |out| has at least356* nghttp2_bufs(bufs) bytes.357*358* The contents of |bufs| is left unchanged.359*360* This function returns the length of copied data.361*/362size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out);363364/*365* Resets |bufs| and makes the buffers empty.366*/367void nghttp2_bufs_reset(nghttp2_bufs *bufs);368369/*370* Moves bufs->cur to bufs->cur->next. If resulting bufs->cur is371* NULL, this function allocates new buffers and bufs->cur points to372* it.373*374* This function returns 0 if it succeeds, or one of the following375* negative error codes:376*377* NGHTTP2_ERR_NOMEM378* Out of memory379* NGHTTP2_ERR_BUFFER_ERROR380* Out of buffer space.381*/382int nghttp2_bufs_advance(nghttp2_bufs *bufs);383384/* Sets bufs->cur to bufs->head */385#define nghttp2_bufs_rewind(BUFS) \386do { \387(BUFS)->cur = (BUFS)->head; \388} while (0)389390/*391* Move bufs->cur, from the current position, using next member, to392* the last buf which has nghttp2_buf_len(buf) > 0 without seeing buf393* which satisfies nghttp2_buf_len(buf) == 0. If394* nghttp2_buf_len(&bufs->cur->buf) == 0 or bufs->cur->next is NULL,395* bufs->cur is unchanged.396*/397void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs);398399/*400* Returns nonzero if bufs->cur->next is not empty.401*/402int nghttp2_bufs_next_present(nghttp2_bufs *bufs);403404#define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf)405406/*407* Returns the total buffer length of |bufs|.408*/409size_t nghttp2_bufs_len(nghttp2_bufs *bufs);410411#endif /* NGHTTP2_BUF_H */412413414