diff --git a/include/libwebsockets/lws-lwsac.h b/include/libwebsockets/lws-lwsac.h index 9e2af0e9b..cfa8c7dd7 100644 --- a/include/libwebsockets/lws-lwsac.h +++ b/include/libwebsockets/lws-lwsac.h @@ -100,27 +100,6 @@ lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add, LWS_VISIBLE LWS_EXTERN void * lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size); -/** - * lwsac_use_zero - allocate / use some memory from a lwsac and zero it - * - * \param head: pointer to the lwsac list object - * \param ensure: the number of bytes we want to use - * \param chunk_size: 0, or the size of the chunk to (over)allocate if - * what we want won't fit in the current tail chunk. If - * 0, the default value of 4000 is used. If ensure is - * larger, it is used instead. - * - * This also serves to init the lwsac if *head is NULL. Basically it does - * whatever is necessary to return you a pointer to ensure bytes of memory - * reserved for the caller. - * - * \p ensure bytes at the return address are zeroed if the allocation succeeded. - * - * Returns NULL if OOM. - */ -LWS_VISIBLE LWS_EXTERN void * -lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size); - /** * lwsac_use - allocate / use some memory from a lwsac * @@ -137,7 +116,9 @@ lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size); * Returns NULL if OOM. */ LWS_VISIBLE LWS_EXTERN void * -lwsac_use_zeroed(struct lwsac **head, size_t ensure, size_t chunk_size); +lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size); + +#define lwsac_use_zeroed lwsac_use_zero /** * lwsac_free - deallocate all chunks in the lwsac and set head NULL @@ -228,4 +209,21 @@ lwsac_info(struct lwsac *head); LWS_VISIBLE LWS_EXTERN uint64_t lwsac_total_alloc(struct lwsac *head); +/** + * lwsac_scan_extant() - returns existing copy of blob, or NULL + * + * \param head: the lwsac to scan + * \param find: the blob to look for + * \param len: the length of the blob to look for + * \param nul: nonzero if the next byte must be NUL + * + * Helper that looks through a whole lwsac for a given binary blob already + * present. Used in the case that lwsac contents are const once written, and + * strings or blobs may be repeated in the input: this allows the earlier + * copy to be pointed to by subsequent references without repeating the string + * or blob redundantly. + */ +LWS_VISIBLE LWS_EXTERN uint8_t * +lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul); + ///@} diff --git a/lib/misc/lwsac/README.md b/lib/misc/lwsac/README.md index e33bc8e9a..3aca6c41c 100644 --- a/lib/misc/lwsac/README.md +++ b/lib/misc/lwsac/README.md @@ -90,7 +90,7 @@ lwsac if they need to, avoiding any need to visit them during destroy. It's like clearing up after a kids' party by gathering up a disposable tablecloth: no matter what was left on the table, it's all gone in one step. -## lws_list_ptr helpers +## `lws_list_ptr` helpers ``` /* sort may be NULL if you don't care about order */ @@ -100,7 +100,24 @@ lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add, ``` A common pattern needed with sub-allocated structs is they are on one or more -linked-list. To make that simple to do cleanly, lws_list... apis are provided +linked-list. To make that simple to do cleanly, `lws_list...` apis are provided along with a generic insertion function that can take a sort callback. These allow a struct to participate on multiple linked-lists simultaneously. +## common const string and blob folding + +In some cases the input to be stored in the lwsac may repeat the same tokens +multiple times... if the pattern is to store the string or blob in the lwsac +and then point to it, you can make use of a helper api + +``` +uint8_t * +lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul); +``` + +This lets you check in all previous used parts of the lwsac for the same +string or blob, plus optionally a terminal NUL afterwards. If not found, +it returns `NULL` and you can copy it into the lwsac as usual. If it is +found, a pointer is returned, and you can use this directly without copying +the string or blob in again. + diff --git a/lib/misc/lwsac/lwsac.c b/lib/misc/lwsac/lwsac.c index c560269f9..43baacb75 100644 --- a/lib/misc/lwsac/lwsac.c +++ b/lib/misc/lwsac/lwsac.c @@ -72,8 +72,8 @@ lwsac_get_next(struct lwsac *lac) void * lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size) { + size_t ofs, alloc, al; struct lwsac *chunk; - size_t ofs, alloc; /* ensure there's a chunk and enough space in it for this name */ @@ -127,13 +127,42 @@ lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size) ofs = (*head)->curr->ofs; - (*head)->curr->ofs += lwsac_align(ensure); + al = lwsac_align(ensure); + if (al > ensure) { + /* zero down the alignment padding part */ + + memset((char *)(*head)->curr + ofs + ensure, 0, al - ensure); + } + (*head)->curr->ofs += al; if ((*head)->curr->ofs >= (*head)->curr->alloc_size) (*head)->curr->ofs = (*head)->curr->alloc_size; return (char *)(*head)->curr + ofs; } +uint8_t * +lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul) +{ + while (head) { + uint8_t *pos = (uint8_t *)&head[1], + *end = ((uint8_t *)head) + head->ofs - len; + + if (head->ofs - sizeof(*head) >= len) + while (pos < end) { + if (*pos == *find && (!nul || !pos[len]) && + pos[len - 1] == find[len - 1] && + !memcmp(pos, find, len)) + /* found the blob */ + return pos; + pos++; + } + + head = head->next; + } + + return NULL; +} + void * lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size) { @@ -145,17 +174,6 @@ lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size) return p; } -void * -lwsac_use_zeroed(struct lwsac **head, size_t ensure, size_t chunk_size) -{ - void *r = lwsac_use(head, ensure, chunk_size); - - if (r) - memset(r, 0, ensure); - - return r; -} - void lwsac_free(struct lwsac **head) {