1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 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
27d4afb5ceSopenharmony_citypedef struct lws_map_hashtable {
28d4afb5ceSopenharmony_ci	struct lws_map			*map_owner; /* so items can find map */
29d4afb5ceSopenharmony_ci	lws_dll2_owner_t		ho;
30d4afb5ceSopenharmony_ci} lws_map_hashtable_t;
31d4afb5ceSopenharmony_ci
32d4afb5ceSopenharmony_citypedef struct lws_map {
33d4afb5ceSopenharmony_ci	lws_map_info_t			info;
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_ci	/* array of info.modulo x lws_map_hashtable_t overallocated */
36d4afb5ceSopenharmony_ci} lws_map_t;
37d4afb5ceSopenharmony_ci
38d4afb5ceSopenharmony_citypedef struct lws_map_item {
39d4afb5ceSopenharmony_ci	lws_dll2_t			list; /* owned by hashtable */
40d4afb5ceSopenharmony_ci
41d4afb5ceSopenharmony_ci	size_t				keylen;
42d4afb5ceSopenharmony_ci	size_t				valuelen;
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ci	/* key then value is overallocated */
45d4afb5ceSopenharmony_ci} lws_map_item_t;
46d4afb5ceSopenharmony_ci
47d4afb5ceSopenharmony_ci/*
48d4afb5ceSopenharmony_ci * lwsac-aware allocator
49d4afb5ceSopenharmony_ci */
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_civoid *
52d4afb5ceSopenharmony_cilws_map_alloc_lwsac(struct lws_map *map, size_t x)
53d4afb5ceSopenharmony_ci{
54d4afb5ceSopenharmony_ci	return lwsac_use((struct lwsac **)map->info.opaque, x,
55d4afb5ceSopenharmony_ci					(size_t)map->info.aux);
56d4afb5ceSopenharmony_ci}
57d4afb5ceSopenharmony_ci
58d4afb5ceSopenharmony_civoid
59d4afb5ceSopenharmony_cilws_map_free_lwsac(void *v)
60d4afb5ceSopenharmony_ci{
61d4afb5ceSopenharmony_ci}
62d4afb5ceSopenharmony_ci
63d4afb5ceSopenharmony_ci/*
64d4afb5ceSopenharmony_ci * Default allocation / free if none given in info
65d4afb5ceSopenharmony_ci */
66d4afb5ceSopenharmony_ci
67d4afb5ceSopenharmony_civoid *
68d4afb5ceSopenharmony_cilws_map_alloc_lws_malloc(struct lws_map *mo, size_t x)
69d4afb5ceSopenharmony_ci{
70d4afb5ceSopenharmony_ci	return lws_malloc(x, __func__);
71d4afb5ceSopenharmony_ci}
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_civoid
74d4afb5ceSopenharmony_cilws_map_free_lws_free(void *v)
75d4afb5ceSopenharmony_ci{
76d4afb5ceSopenharmony_ci	lws_free(v);
77d4afb5ceSopenharmony_ci}
78d4afb5ceSopenharmony_ci
79d4afb5ceSopenharmony_ci/*
80d4afb5ceSopenharmony_ci * This just needs to approximate a flat distribution, it's not related to
81d4afb5ceSopenharmony_ci * security at all.
82d4afb5ceSopenharmony_ci */
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_cilws_map_hash_t
85d4afb5ceSopenharmony_cilws_map_hash_from_key_default(const lws_map_key_t key, size_t kl)
86d4afb5ceSopenharmony_ci{
87d4afb5ceSopenharmony_ci	lws_map_hash_t h = 0x12345678;
88d4afb5ceSopenharmony_ci	const uint8_t *u = (const uint8_t *)key;
89d4afb5ceSopenharmony_ci
90d4afb5ceSopenharmony_ci	while (kl--)
91d4afb5ceSopenharmony_ci		h = ((((h << 7) | (h >> 25)) + 0xa1b2c3d4) ^ (*u++)) ^ h;
92d4afb5ceSopenharmony_ci
93d4afb5ceSopenharmony_ci	return h;
94d4afb5ceSopenharmony_ci}
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ciint
97d4afb5ceSopenharmony_cilws_map_compare_key_default(const lws_map_key_t key1, size_t kl1,
98d4afb5ceSopenharmony_ci			    const lws_map_value_t key2, size_t kl2)
99d4afb5ceSopenharmony_ci{
100d4afb5ceSopenharmony_ci	if (kl1 != kl2)
101d4afb5ceSopenharmony_ci		return 1;
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_ci	return memcmp(key1, key2, kl1);
104d4afb5ceSopenharmony_ci}
105d4afb5ceSopenharmony_ci
106d4afb5ceSopenharmony_cilws_map_t *
107d4afb5ceSopenharmony_cilws_map_create(const lws_map_info_t *info)
108d4afb5ceSopenharmony_ci{
109d4afb5ceSopenharmony_ci	lws_map_t *map;
110d4afb5ceSopenharmony_ci	lws_map_alloc_t a = info->_alloc;
111d4afb5ceSopenharmony_ci	size_t modulo = info->modulo;
112d4afb5ceSopenharmony_ci	lws_map_hashtable_t *ht;
113d4afb5ceSopenharmony_ci	size_t size;
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci	if (!a)
116d4afb5ceSopenharmony_ci		a = lws_map_alloc_lws_malloc;
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci	if (!modulo)
119d4afb5ceSopenharmony_ci		modulo = 8;
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci	size = sizeof(*map) + (modulo * sizeof(lws_map_hashtable_t));
122d4afb5ceSopenharmony_ci	map = lws_malloc(size, __func__);
123d4afb5ceSopenharmony_ci	if (!map)
124d4afb5ceSopenharmony_ci		return NULL;
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci	memset(map, 0, size);
127d4afb5ceSopenharmony_ci
128d4afb5ceSopenharmony_ci	map->info = *info;
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci	map->info._alloc = a;
131d4afb5ceSopenharmony_ci	map->info.modulo = modulo;
132d4afb5ceSopenharmony_ci	if (!info->_free)
133d4afb5ceSopenharmony_ci		map->info._free = lws_map_free_lws_free;
134d4afb5ceSopenharmony_ci	if (!info->_hash)
135d4afb5ceSopenharmony_ci		map->info._hash = lws_map_hash_from_key_default;
136d4afb5ceSopenharmony_ci	if (!info->_compare)
137d4afb5ceSopenharmony_ci		map->info._compare = lws_map_compare_key_default;
138d4afb5ceSopenharmony_ci
139d4afb5ceSopenharmony_ci	ht = (lws_map_hashtable_t *)&map[1];
140d4afb5ceSopenharmony_ci	while (modulo--)
141d4afb5ceSopenharmony_ci		ht[modulo].map_owner = map;
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci	return map;
144d4afb5ceSopenharmony_ci}
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_cistatic int
147d4afb5ceSopenharmony_ciho_free_item(struct lws_dll2 *d, void *user)
148d4afb5ceSopenharmony_ci{
149d4afb5ceSopenharmony_ci	lws_map_item_t *i = lws_container_of(d, lws_map_item_t, list);
150d4afb5ceSopenharmony_ci
151d4afb5ceSopenharmony_ci	lws_map_item_destroy(i);
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	return 0;
154d4afb5ceSopenharmony_ci}
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_civoid
157d4afb5ceSopenharmony_cilws_map_destroy(lws_map_t **pmap)
158d4afb5ceSopenharmony_ci{
159d4afb5ceSopenharmony_ci	lws_map_hashtable_t *ht;
160d4afb5ceSopenharmony_ci	lws_map_t *map = *pmap;
161d4afb5ceSopenharmony_ci
162d4afb5ceSopenharmony_ci	if (!map)
163d4afb5ceSopenharmony_ci		return;
164d4afb5ceSopenharmony_ci
165d4afb5ceSopenharmony_ci	/* empty out all the hashtables */
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci	ht = (lws_map_hashtable_t *)&(map[1]);
168d4afb5ceSopenharmony_ci	while (map->info.modulo--) {
169d4afb5ceSopenharmony_ci		lws_dll2_foreach_safe(&ht->ho, ht, ho_free_item);
170d4afb5ceSopenharmony_ci		ht++;
171d4afb5ceSopenharmony_ci	}
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci	/* free the map itself */
174d4afb5ceSopenharmony_ci
175d4afb5ceSopenharmony_ci	lws_free_set_NULL(*pmap);
176d4afb5ceSopenharmony_ci}
177d4afb5ceSopenharmony_ci
178d4afb5ceSopenharmony_cilws_map_item_t *
179d4afb5ceSopenharmony_cilws_map_item_create(lws_map_t *map,
180d4afb5ceSopenharmony_ci		    const lws_map_key_t key, size_t keylen,
181d4afb5ceSopenharmony_ci		    const lws_map_value_t value, size_t valuelen)
182d4afb5ceSopenharmony_ci{
183d4afb5ceSopenharmony_ci	lws_map_hashtable_t *ht;
184d4afb5ceSopenharmony_ci	lws_map_item_t *item;
185d4afb5ceSopenharmony_ci	lws_map_hash_t h;
186d4afb5ceSopenharmony_ci	size_t hti;
187d4afb5ceSopenharmony_ci	uint8_t *u;
188d4afb5ceSopenharmony_ci
189d4afb5ceSopenharmony_ci	item = lws_map_item_lookup(map, key, keylen);
190d4afb5ceSopenharmony_ci	if (item)
191d4afb5ceSopenharmony_ci		lws_map_item_destroy(item);
192d4afb5ceSopenharmony_ci
193d4afb5ceSopenharmony_ci	item = map->info._alloc(map, sizeof(*item) + keylen + valuelen);
194d4afb5ceSopenharmony_ci	if (!item)
195d4afb5ceSopenharmony_ci		return NULL;
196d4afb5ceSopenharmony_ci
197d4afb5ceSopenharmony_ci	lws_dll2_clear(&item->list);
198d4afb5ceSopenharmony_ci	item->keylen = keylen;
199d4afb5ceSopenharmony_ci	item->valuelen = valuelen;
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci	u = (uint8_t *)&item[1];
202d4afb5ceSopenharmony_ci	memcpy(u, key, keylen);
203d4afb5ceSopenharmony_ci	u += keylen;
204d4afb5ceSopenharmony_ci	if (value)
205d4afb5ceSopenharmony_ci		memcpy(u, value, valuelen);
206d4afb5ceSopenharmony_ci
207d4afb5ceSopenharmony_ci	h = map->info._hash(key, keylen);
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci	hti = h % map->info.modulo;
210d4afb5ceSopenharmony_ci	ht = (lws_map_hashtable_t *)&map[1];
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci	lws_dll2_add_head(&item->list, &ht[hti].ho);
213d4afb5ceSopenharmony_ci
214d4afb5ceSopenharmony_ci	return item;
215d4afb5ceSopenharmony_ci}
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_civoid
218d4afb5ceSopenharmony_cilws_map_item_destroy(lws_map_item_t *item)
219d4afb5ceSopenharmony_ci{
220d4afb5ceSopenharmony_ci	lws_map_hashtable_t *ht = lws_container_of(item->list.owner,
221d4afb5ceSopenharmony_ci						   lws_map_hashtable_t, ho);
222d4afb5ceSopenharmony_ci
223d4afb5ceSopenharmony_ci	lws_dll2_remove(&item->list);
224d4afb5ceSopenharmony_ci	ht->map_owner->info._free(item);
225d4afb5ceSopenharmony_ci}
226d4afb5ceSopenharmony_ci
227d4afb5ceSopenharmony_cilws_map_item_t *
228d4afb5ceSopenharmony_cilws_map_item_lookup(lws_map_t *map, const lws_map_key_t key, size_t keylen)
229d4afb5ceSopenharmony_ci{
230d4afb5ceSopenharmony_ci	lws_map_hash_t h = map->info._hash(key, keylen);
231d4afb5ceSopenharmony_ci	lws_map_hashtable_t *ht = (lws_map_hashtable_t *)&map[1];
232d4afb5ceSopenharmony_ci
233d4afb5ceSopenharmony_ci	lws_start_foreach_dll(struct lws_dll2 *, p,
234d4afb5ceSopenharmony_ci			      ht[h % map->info.modulo].ho.head) {
235d4afb5ceSopenharmony_ci		lws_map_item_t *i = lws_container_of(p, lws_map_item_t, list);
236d4afb5ceSopenharmony_ci
237d4afb5ceSopenharmony_ci		if (!map->info._compare(key, keylen, &i[1], i->keylen))
238d4afb5ceSopenharmony_ci			return i;
239d4afb5ceSopenharmony_ci	} lws_end_foreach_dll(p);
240d4afb5ceSopenharmony_ci
241d4afb5ceSopenharmony_ci	return NULL;
242d4afb5ceSopenharmony_ci}
243d4afb5ceSopenharmony_ci
244d4afb5ceSopenharmony_ciconst void *
245d4afb5ceSopenharmony_cilws_map_item_key(lws_map_item_t *_item)
246d4afb5ceSopenharmony_ci{
247d4afb5ceSopenharmony_ci	return ((void *)&_item[1]);
248d4afb5ceSopenharmony_ci}
249d4afb5ceSopenharmony_ci
250d4afb5ceSopenharmony_ciconst void *
251d4afb5ceSopenharmony_cilws_map_item_value(lws_map_item_t *_item)
252d4afb5ceSopenharmony_ci{
253d4afb5ceSopenharmony_ci	return (void *)(((uint8_t *)&_item[1]) + _item->keylen);
254d4afb5ceSopenharmony_ci}
255d4afb5ceSopenharmony_ci
256d4afb5ceSopenharmony_cisize_t
257d4afb5ceSopenharmony_cilws_map_item_key_len(lws_map_item_t *_item)
258d4afb5ceSopenharmony_ci{
259d4afb5ceSopenharmony_ci	return _item->keylen;
260d4afb5ceSopenharmony_ci}
261d4afb5ceSopenharmony_ci
262d4afb5ceSopenharmony_cisize_t
263d4afb5ceSopenharmony_cilws_map_item_value_len(lws_map_item_t *_item)
264d4afb5ceSopenharmony_ci{
265d4afb5ceSopenharmony_ci	return _item->valuelen;
266d4afb5ceSopenharmony_ci}
267