1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "private-lib-core.h" 26d4afb5ceSopenharmony_ci#include "private-lib-misc-lwsac.h" 27d4afb5ceSopenharmony_ci 28d4afb5ceSopenharmony_civoid 29d4afb5ceSopenharmony_cilws_list_ptr_insert(lws_list_ptr *head, lws_list_ptr *add, 30d4afb5ceSopenharmony_ci lws_list_ptr_sort_func_t sort_func) 31d4afb5ceSopenharmony_ci{ 32d4afb5ceSopenharmony_ci while (sort_func && *head) { 33d4afb5ceSopenharmony_ci if (sort_func(add, *head) <= 0) 34d4afb5ceSopenharmony_ci break; 35d4afb5ceSopenharmony_ci 36d4afb5ceSopenharmony_ci head = *head; 37d4afb5ceSopenharmony_ci } 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_ci *add = *head; 40d4afb5ceSopenharmony_ci *head = add; 41d4afb5ceSopenharmony_ci} 42d4afb5ceSopenharmony_ci 43d4afb5ceSopenharmony_cisize_t 44d4afb5ceSopenharmony_cilwsac_align(size_t length) 45d4afb5ceSopenharmony_ci{ 46d4afb5ceSopenharmony_ci size_t align = sizeof(int *); 47d4afb5ceSopenharmony_ci 48d4afb5ceSopenharmony_ci if (length & (align - 1)) 49d4afb5ceSopenharmony_ci length += align - (length & (align - 1)); 50d4afb5ceSopenharmony_ci 51d4afb5ceSopenharmony_ci return length; 52d4afb5ceSopenharmony_ci} 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_cisize_t 55d4afb5ceSopenharmony_cilwsac_sizeof(int first) 56d4afb5ceSopenharmony_ci{ 57d4afb5ceSopenharmony_ci return sizeof(struct lwsac) + (first ? sizeof(struct lwsac_head) : 0); 58d4afb5ceSopenharmony_ci} 59d4afb5ceSopenharmony_ci 60d4afb5ceSopenharmony_cisize_t 61d4afb5ceSopenharmony_cilwsac_get_tail_pos(struct lwsac *lac) 62d4afb5ceSopenharmony_ci{ 63d4afb5ceSopenharmony_ci return lac->ofs; 64d4afb5ceSopenharmony_ci} 65d4afb5ceSopenharmony_ci 66d4afb5ceSopenharmony_cistruct lwsac * 67d4afb5ceSopenharmony_cilwsac_get_next(struct lwsac *lac) 68d4afb5ceSopenharmony_ci{ 69d4afb5ceSopenharmony_ci return lac->next; 70d4afb5ceSopenharmony_ci} 71d4afb5ceSopenharmony_ci 72d4afb5ceSopenharmony_ciint 73d4afb5ceSopenharmony_cilwsac_extend(struct lwsac *head, size_t amount) 74d4afb5ceSopenharmony_ci{ 75d4afb5ceSopenharmony_ci struct lwsac_head *lachead; 76d4afb5ceSopenharmony_ci struct lwsac *bf; 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci assert(head); 79d4afb5ceSopenharmony_ci lachead = (struct lwsac_head *)&head[1]; 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci bf = lachead->curr; 82d4afb5ceSopenharmony_ci assert(bf); 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ci if (bf->alloc_size - bf->ofs < lwsac_align(amount)) 85d4afb5ceSopenharmony_ci return 1; 86d4afb5ceSopenharmony_ci 87d4afb5ceSopenharmony_ci /* memset so constant folding never sees uninitialized data */ 88d4afb5ceSopenharmony_ci 89d4afb5ceSopenharmony_ci memset(((uint8_t *)bf) + bf->ofs, 0, lwsac_align(amount)); 90d4afb5ceSopenharmony_ci bf->ofs += lwsac_align(amount); 91d4afb5ceSopenharmony_ci 92d4afb5ceSopenharmony_ci return 0; 93d4afb5ceSopenharmony_ci} 94d4afb5ceSopenharmony_ci 95d4afb5ceSopenharmony_cistatic void * 96d4afb5ceSopenharmony_ci_lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size, char backfill) 97d4afb5ceSopenharmony_ci{ 98d4afb5ceSopenharmony_ci struct lwsac_head *lachead = NULL; 99d4afb5ceSopenharmony_ci size_t ofs, alloc, al, hp; 100d4afb5ceSopenharmony_ci struct lwsac *bf = *head; 101d4afb5ceSopenharmony_ci 102d4afb5ceSopenharmony_ci if (bf) 103d4afb5ceSopenharmony_ci lachead = (struct lwsac_head *)&bf[1]; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci al = lwsac_align(ensure); 106d4afb5ceSopenharmony_ci 107d4afb5ceSopenharmony_ci /* backfill into earlier chunks if that is allowed */ 108d4afb5ceSopenharmony_ci 109d4afb5ceSopenharmony_ci if (backfill) 110d4afb5ceSopenharmony_ci /* 111d4afb5ceSopenharmony_ci * check if anything can take it, from the start 112d4afb5ceSopenharmony_ci */ 113d4afb5ceSopenharmony_ci while (bf) { 114d4afb5ceSopenharmony_ci if (bf->alloc_size - bf->ofs >= ensure) 115d4afb5ceSopenharmony_ci goto do_use; 116d4afb5ceSopenharmony_ci 117d4afb5ceSopenharmony_ci bf = bf->next; 118d4afb5ceSopenharmony_ci } 119d4afb5ceSopenharmony_ci else { 120d4afb5ceSopenharmony_ci /* 121d4afb5ceSopenharmony_ci * If there's a current chunk, just check if he can take it 122d4afb5ceSopenharmony_ci */ 123d4afb5ceSopenharmony_ci if (lachead && lachead->curr) { 124d4afb5ceSopenharmony_ci bf = lachead->curr; 125d4afb5ceSopenharmony_ci if (bf->alloc_size - bf->ofs >= ensure) 126d4afb5ceSopenharmony_ci goto do_use; 127d4afb5ceSopenharmony_ci } 128d4afb5ceSopenharmony_ci } 129d4afb5ceSopenharmony_ci 130d4afb5ceSopenharmony_ci /* nothing can currently take it... so we must allocate */ 131d4afb5ceSopenharmony_ci 132d4afb5ceSopenharmony_ci hp = sizeof(*bf); /* always need the normal header part... */ 133d4afb5ceSopenharmony_ci if (!*head) 134d4afb5ceSopenharmony_ci hp += sizeof(struct lwsac_head); 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci if (!chunk_size) 137d4afb5ceSopenharmony_ci alloc = LWSAC_CHUNK_SIZE + hp; 138d4afb5ceSopenharmony_ci else 139d4afb5ceSopenharmony_ci alloc = chunk_size + hp; 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci /* 142d4afb5ceSopenharmony_ci * If we get asked for something outside our expectation, 143d4afb5ceSopenharmony_ci * increase the allocation to meet it 144d4afb5ceSopenharmony_ci */ 145d4afb5ceSopenharmony_ci 146d4afb5ceSopenharmony_ci if (al >= alloc - hp) 147d4afb5ceSopenharmony_ci alloc = al + hp; 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_ci lwsl_debug("%s: alloc %d for %d\n", __func__, (int)alloc, (int)ensure); 150d4afb5ceSopenharmony_ci bf = malloc(alloc); 151d4afb5ceSopenharmony_ci if (!bf) { 152d4afb5ceSopenharmony_ci lwsl_err("%s: OOM trying to alloc %llud\n", __func__, 153d4afb5ceSopenharmony_ci (unsigned long long)alloc); 154d4afb5ceSopenharmony_ci return NULL; 155d4afb5ceSopenharmony_ci } 156d4afb5ceSopenharmony_ci 157d4afb5ceSopenharmony_ci /* 158d4afb5ceSopenharmony_ci * belabouring the point... ofs is aligned to the platform's 159d4afb5ceSopenharmony_ci * generic struct alignment at the start then 160d4afb5ceSopenharmony_ci */ 161d4afb5ceSopenharmony_ci bf->ofs = sizeof(*bf); 162d4afb5ceSopenharmony_ci 163d4afb5ceSopenharmony_ci if (!*head) { 164d4afb5ceSopenharmony_ci /* 165d4afb5ceSopenharmony_ci * We are the first, head, entry... 166d4afb5ceSopenharmony_ci */ 167d4afb5ceSopenharmony_ci *head = bf; 168d4afb5ceSopenharmony_ci /* 169d4afb5ceSopenharmony_ci * ... allocate for the special head block 170d4afb5ceSopenharmony_ci */ 171d4afb5ceSopenharmony_ci bf->ofs += sizeof(*lachead); 172d4afb5ceSopenharmony_ci lachead = (struct lwsac_head *)&bf[1]; 173d4afb5ceSopenharmony_ci memset(lachead, 0, sizeof(*lachead)); 174d4afb5ceSopenharmony_ci } else 175d4afb5ceSopenharmony_ci if (lachead->curr) 176d4afb5ceSopenharmony_ci lachead->curr->next = bf; 177d4afb5ceSopenharmony_ci 178d4afb5ceSopenharmony_ci lachead->curr = bf; 179d4afb5ceSopenharmony_ci bf->head = *head; 180d4afb5ceSopenharmony_ci bf->next = NULL; 181d4afb5ceSopenharmony_ci bf->alloc_size = alloc; 182d4afb5ceSopenharmony_ci 183d4afb5ceSopenharmony_ci lachead->total_alloc_size += alloc; 184d4afb5ceSopenharmony_ci lachead->total_blocks++; 185d4afb5ceSopenharmony_ci 186d4afb5ceSopenharmony_cido_use: 187d4afb5ceSopenharmony_ci 188d4afb5ceSopenharmony_ci ofs = bf->ofs; 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci if (al > ensure) 191d4afb5ceSopenharmony_ci /* zero down the alignment padding part */ 192d4afb5ceSopenharmony_ci memset((char *)bf + ofs + ensure, 0, al - ensure); 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci bf->ofs += al; 195d4afb5ceSopenharmony_ci if (bf->ofs >= bf->alloc_size) 196d4afb5ceSopenharmony_ci bf->ofs = bf->alloc_size; 197d4afb5ceSopenharmony_ci 198d4afb5ceSopenharmony_ci return (char *)bf + ofs; 199d4afb5ceSopenharmony_ci} 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_civoid * 202d4afb5ceSopenharmony_cilwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size) 203d4afb5ceSopenharmony_ci{ 204d4afb5ceSopenharmony_ci return _lwsac_use(head, ensure, chunk_size, 0); 205d4afb5ceSopenharmony_ci} 206d4afb5ceSopenharmony_ci 207d4afb5ceSopenharmony_civoid * 208d4afb5ceSopenharmony_cilwsac_use_backfill(struct lwsac **head, size_t ensure, size_t chunk_size) 209d4afb5ceSopenharmony_ci{ 210d4afb5ceSopenharmony_ci return _lwsac_use(head, ensure, chunk_size, 1); 211d4afb5ceSopenharmony_ci} 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_ciuint8_t * 214d4afb5ceSopenharmony_cilwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul) 215d4afb5ceSopenharmony_ci{ 216d4afb5ceSopenharmony_ci while (head) { 217d4afb5ceSopenharmony_ci uint8_t *pos = (uint8_t *)&head[1], 218d4afb5ceSopenharmony_ci *end = ((uint8_t *)head) + head->ofs - len; 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci if (head->ofs - sizeof(*head) >= len) 221d4afb5ceSopenharmony_ci while (pos < end) { 222d4afb5ceSopenharmony_ci if (*pos == *find && (!nul || !pos[len]) && 223d4afb5ceSopenharmony_ci pos[len - 1] == find[len - 1] && 224d4afb5ceSopenharmony_ci !memcmp(pos, find, len)) 225d4afb5ceSopenharmony_ci /* found the blob */ 226d4afb5ceSopenharmony_ci return pos; 227d4afb5ceSopenharmony_ci pos++; 228d4afb5ceSopenharmony_ci } 229d4afb5ceSopenharmony_ci 230d4afb5ceSopenharmony_ci head = head->next; 231d4afb5ceSopenharmony_ci } 232d4afb5ceSopenharmony_ci 233d4afb5ceSopenharmony_ci return NULL; 234d4afb5ceSopenharmony_ci} 235d4afb5ceSopenharmony_ci 236d4afb5ceSopenharmony_ciuint64_t 237d4afb5ceSopenharmony_cilwsac_total_overhead(struct lwsac *head) 238d4afb5ceSopenharmony_ci{ 239d4afb5ceSopenharmony_ci uint64_t overhead = 0; 240d4afb5ceSopenharmony_ci 241d4afb5ceSopenharmony_ci while (head) { 242d4afb5ceSopenharmony_ci overhead += (head->alloc_size - head->ofs) + sizeof(*head); 243d4afb5ceSopenharmony_ci 244d4afb5ceSopenharmony_ci head = head->next; 245d4afb5ceSopenharmony_ci } 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci return overhead; 248d4afb5ceSopenharmony_ci} 249d4afb5ceSopenharmony_ci 250d4afb5ceSopenharmony_civoid * 251d4afb5ceSopenharmony_cilwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size) 252d4afb5ceSopenharmony_ci{ 253d4afb5ceSopenharmony_ci void *p = lwsac_use(head, ensure, chunk_size); 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci if (p) 256d4afb5ceSopenharmony_ci memset(p, 0, ensure); 257d4afb5ceSopenharmony_ci 258d4afb5ceSopenharmony_ci return p; 259d4afb5ceSopenharmony_ci} 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_civoid 262d4afb5ceSopenharmony_cilwsac_free(struct lwsac **head) 263d4afb5ceSopenharmony_ci{ 264d4afb5ceSopenharmony_ci struct lwsac *it = *head; 265d4afb5ceSopenharmony_ci 266d4afb5ceSopenharmony_ci *head = NULL; 267d4afb5ceSopenharmony_ci lwsl_debug("%s: head %p\n", __func__, *head); 268d4afb5ceSopenharmony_ci 269d4afb5ceSopenharmony_ci while (it) { 270d4afb5ceSopenharmony_ci struct lwsac *tmp = it->next; 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_ci free(it); 273d4afb5ceSopenharmony_ci it = tmp; 274d4afb5ceSopenharmony_ci } 275d4afb5ceSopenharmony_ci} 276d4afb5ceSopenharmony_ci 277d4afb5ceSopenharmony_civoid 278d4afb5ceSopenharmony_cilwsac_info(struct lwsac *head) 279d4afb5ceSopenharmony_ci{ 280d4afb5ceSopenharmony_ci#if _LWS_ENABLED_LOGS & LLL_DEBUG 281d4afb5ceSopenharmony_ci struct lwsac_head *lachead; 282d4afb5ceSopenharmony_ci 283d4afb5ceSopenharmony_ci if (!head) { 284d4afb5ceSopenharmony_ci lwsl_debug("%s: empty\n", __func__); 285d4afb5ceSopenharmony_ci return; 286d4afb5ceSopenharmony_ci } 287d4afb5ceSopenharmony_ci 288d4afb5ceSopenharmony_ci lachead = (struct lwsac_head *)&head[1]; 289d4afb5ceSopenharmony_ci 290d4afb5ceSopenharmony_ci lwsl_debug("%s: lac %p: %dKiB in %d blocks\n", __func__, head, 291d4afb5ceSopenharmony_ci (int)(lachead->total_alloc_size >> 10), lachead->total_blocks); 292d4afb5ceSopenharmony_ci#endif 293d4afb5ceSopenharmony_ci} 294d4afb5ceSopenharmony_ci 295d4afb5ceSopenharmony_ciuint64_t 296d4afb5ceSopenharmony_cilwsac_total_alloc(struct lwsac *head) 297d4afb5ceSopenharmony_ci{ 298d4afb5ceSopenharmony_ci struct lwsac_head *lachead; 299d4afb5ceSopenharmony_ci 300d4afb5ceSopenharmony_ci if (!head) 301d4afb5ceSopenharmony_ci return 0; 302d4afb5ceSopenharmony_ci 303d4afb5ceSopenharmony_ci lachead = (struct lwsac_head *)&head[1]; 304d4afb5ceSopenharmony_ci return lachead->total_alloc_size; 305d4afb5ceSopenharmony_ci} 306d4afb5ceSopenharmony_ci 307d4afb5ceSopenharmony_civoid 308d4afb5ceSopenharmony_cilwsac_reference(struct lwsac *head) 309d4afb5ceSopenharmony_ci{ 310d4afb5ceSopenharmony_ci struct lwsac_head *lachead = (struct lwsac_head *)&head[1]; 311d4afb5ceSopenharmony_ci 312d4afb5ceSopenharmony_ci lachead->refcount++; 313d4afb5ceSopenharmony_ci lwsl_debug("%s: head %p: (det %d) refcount -> %d\n", 314d4afb5ceSopenharmony_ci __func__, head, lachead->detached, lachead->refcount); 315d4afb5ceSopenharmony_ci} 316d4afb5ceSopenharmony_ci 317d4afb5ceSopenharmony_civoid 318d4afb5ceSopenharmony_cilwsac_unreference(struct lwsac **head) 319d4afb5ceSopenharmony_ci{ 320d4afb5ceSopenharmony_ci struct lwsac_head *lachead; 321d4afb5ceSopenharmony_ci 322d4afb5ceSopenharmony_ci if (!(*head)) 323d4afb5ceSopenharmony_ci return; 324d4afb5ceSopenharmony_ci 325d4afb5ceSopenharmony_ci lachead = (struct lwsac_head *)&(*head)[1]; 326d4afb5ceSopenharmony_ci 327d4afb5ceSopenharmony_ci if (!lachead->refcount) 328d4afb5ceSopenharmony_ci lwsl_warn("%s: refcount going below zero\n", __func__); 329d4afb5ceSopenharmony_ci 330d4afb5ceSopenharmony_ci lachead->refcount--; 331d4afb5ceSopenharmony_ci 332d4afb5ceSopenharmony_ci lwsl_debug("%s: head %p: (det %d) refcount -> %d\n", 333d4afb5ceSopenharmony_ci __func__, *head, lachead->detached, lachead->refcount); 334d4afb5ceSopenharmony_ci 335d4afb5ceSopenharmony_ci if (lachead->detached && !lachead->refcount) { 336d4afb5ceSopenharmony_ci lwsl_debug("%s: head %p: FREED\n", __func__, *head); 337d4afb5ceSopenharmony_ci lwsac_free(head); 338d4afb5ceSopenharmony_ci } 339d4afb5ceSopenharmony_ci} 340d4afb5ceSopenharmony_ci 341d4afb5ceSopenharmony_civoid 342d4afb5ceSopenharmony_cilwsac_detach(struct lwsac **head) 343d4afb5ceSopenharmony_ci{ 344d4afb5ceSopenharmony_ci struct lwsac_head *lachead; 345d4afb5ceSopenharmony_ci 346d4afb5ceSopenharmony_ci if (!(*head)) 347d4afb5ceSopenharmony_ci return; 348d4afb5ceSopenharmony_ci 349d4afb5ceSopenharmony_ci lachead = (struct lwsac_head *)&(*head)[1]; 350d4afb5ceSopenharmony_ci 351d4afb5ceSopenharmony_ci lachead->detached = 1; 352d4afb5ceSopenharmony_ci if (!lachead->refcount) { 353d4afb5ceSopenharmony_ci lwsl_debug("%s: head %p: FREED\n", __func__, *head); 354d4afb5ceSopenharmony_ci lwsac_free(head); 355d4afb5ceSopenharmony_ci } else 356d4afb5ceSopenharmony_ci lwsl_debug("%s: head %p: refcount %d: Marked as detached\n", 357d4afb5ceSopenharmony_ci __func__, *head, lachead->refcount); 358d4afb5ceSopenharmony_ci} 359