• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 typedef struct lws_map_hashtable {
28 	struct lws_map			*map_owner; /* so items can find map */
29 	lws_dll2_owner_t		ho;
30 } lws_map_hashtable_t;
31 
32 typedef struct lws_map {
33 	lws_map_info_t			info;
34 
35 	/* array of info.modulo x lws_map_hashtable_t overallocated */
36 } lws_map_t;
37 
38 typedef struct lws_map_item {
39 	lws_dll2_t			list; /* owned by hashtable */
40 
41 	size_t				keylen;
42 	size_t				valuelen;
43 
44 	/* key then value is overallocated */
45 } lws_map_item_t;
46 
47 /*
48  * lwsac-aware allocator
49  */
50 
51 void *
lws_map_alloc_lwsac(struct lws_map * map,size_t x)52 lws_map_alloc_lwsac(struct lws_map *map, size_t x)
53 {
54 	return lwsac_use((struct lwsac **)map->info.opaque, x,
55 					(size_t)map->info.aux);
56 }
57 
58 void
lws_map_free_lwsac(void * v)59 lws_map_free_lwsac(void *v)
60 {
61 }
62 
63 /*
64  * Default allocation / free if none given in info
65  */
66 
67 void *
lws_map_alloc_lws_malloc(struct lws_map * mo,size_t x)68 lws_map_alloc_lws_malloc(struct lws_map *mo, size_t x)
69 {
70 	return lws_malloc(x, __func__);
71 }
72 
73 void
lws_map_free_lws_free(void * v)74 lws_map_free_lws_free(void *v)
75 {
76 	lws_free(v);
77 }
78 
79 /*
80  * This just needs to approximate a flat distribution, it's not related to
81  * security at all.
82  */
83 
84 lws_map_hash_t
lws_map_hash_from_key_default(const lws_map_key_t key,size_t kl)85 lws_map_hash_from_key_default(const lws_map_key_t key, size_t kl)
86 {
87 	lws_map_hash_t h = 0x12345678;
88 	const uint8_t *u = (const uint8_t *)key;
89 
90 	while (kl--)
91 	h = ((
92 		(((h & 0x1fffffff /* coverity */ ) << 7) |
93 		 (h >> 25)) +
94 		   0xa1b2c3d4) ^ (*u++)) ^ h;
95 
96 	return h;
97 }
98 
99 int
lws_map_compare_key_default(const lws_map_key_t key1,size_t kl1,const lws_map_value_t key2,size_t kl2)100 lws_map_compare_key_default(const lws_map_key_t key1, size_t kl1,
101 			    const lws_map_value_t key2, size_t kl2)
102 {
103 	if (kl1 != kl2)
104 		return 1;
105 
106 	return memcmp(key1, key2, kl1);
107 }
108 
109 lws_map_t *
lws_map_create(const lws_map_info_t * info)110 lws_map_create(const lws_map_info_t *info)
111 {
112 	lws_map_t *map;
113 	lws_map_alloc_t a = info->_alloc;
114 	size_t modulo = info->modulo;
115 	lws_map_hashtable_t *ht;
116 	size_t size;
117 
118 	if (!a)
119 		a = lws_map_alloc_lws_malloc;
120 
121 	if (!modulo)
122 		modulo = 8;
123 
124 	size = sizeof(*map) + (modulo * sizeof(lws_map_hashtable_t));
125 	map = lws_malloc(size, __func__);
126 	if (!map)
127 		return NULL;
128 
129 	memset(map, 0, size);
130 
131 	map->info = *info;
132 
133 	map->info._alloc = a;
134 	map->info.modulo = modulo;
135 	if (!info->_free)
136 		map->info._free = lws_map_free_lws_free;
137 	if (!info->_hash)
138 		map->info._hash = lws_map_hash_from_key_default;
139 	if (!info->_compare)
140 		map->info._compare = lws_map_compare_key_default;
141 
142 	ht = (lws_map_hashtable_t *)&map[1];
143 	while (modulo--)
144 		ht[modulo].map_owner = map;
145 
146 	return map;
147 }
148 
149 static int
ho_free_item(struct lws_dll2 * d,void * user)150 ho_free_item(struct lws_dll2 *d, void *user)
151 {
152 	lws_map_item_t *i = lws_container_of(d, lws_map_item_t, list);
153 
154 	lws_map_item_destroy(i);
155 
156 	return 0;
157 }
158 
159 void
lws_map_destroy(lws_map_t ** pmap)160 lws_map_destroy(lws_map_t **pmap)
161 {
162 	lws_map_hashtable_t *ht;
163 	lws_map_t *map = *pmap;
164 
165 	if (!map)
166 		return;
167 
168 	/* empty out all the hashtables */
169 
170 	ht = (lws_map_hashtable_t *)&(map[1]);
171 	while (map->info.modulo--) {
172 		lws_dll2_foreach_safe(&ht->ho, ht, ho_free_item);
173 		ht++;
174 	}
175 
176 	/* free the map itself */
177 
178 	lws_free_set_NULL(*pmap);
179 }
180 
181 lws_map_item_t *
lws_map_item_create(lws_map_t * map,const lws_map_key_t key,size_t keylen,const lws_map_value_t value,size_t valuelen)182 lws_map_item_create(lws_map_t *map,
183 		    const lws_map_key_t key, size_t keylen,
184 		    const lws_map_value_t value, size_t valuelen)
185 {
186 	lws_map_hashtable_t *ht;
187 	lws_map_item_t *item;
188 	lws_map_hash_t h;
189 	size_t hti;
190 	uint8_t *u;
191 
192 	item = lws_map_item_lookup(map, key, keylen);
193 	if (item)
194 		lws_map_item_destroy(item);
195 
196 	item = map->info._alloc(map, sizeof(*item) + keylen + valuelen);
197 	if (!item)
198 		return NULL;
199 
200 	lws_dll2_clear(&item->list);
201 	item->keylen = keylen;
202 	item->valuelen = valuelen;
203 
204 	u = (uint8_t *)&item[1];
205 	memcpy(u, key, keylen);
206 	u += keylen;
207 	if (value)
208 		memcpy(u, value, valuelen);
209 
210 	h = map->info._hash(key, keylen);
211 
212 	hti = h % map->info.modulo;
213 	ht = (lws_map_hashtable_t *)&map[1];
214 
215 	lws_dll2_add_head(&item->list, &ht[hti].ho);
216 
217 	return item;
218 }
219 
220 void
lws_map_item_destroy(lws_map_item_t * item)221 lws_map_item_destroy(lws_map_item_t *item)
222 {
223 	lws_map_hashtable_t *ht = lws_container_of(item->list.owner,
224 						   lws_map_hashtable_t, ho);
225 
226 	lws_dll2_remove(&item->list);
227 	ht->map_owner->info._free(item);
228 }
229 
230 lws_map_item_t *
lws_map_item_lookup(lws_map_t * map,const lws_map_key_t key,size_t keylen)231 lws_map_item_lookup(lws_map_t *map, const lws_map_key_t key, size_t keylen)
232 {
233 	lws_map_hash_t h = map->info._hash(key, keylen);
234 	lws_map_hashtable_t *ht = (lws_map_hashtable_t *)&map[1];
235 
236 	lws_start_foreach_dll(struct lws_dll2 *, p,
237 			      ht[h % map->info.modulo].ho.head) {
238 		lws_map_item_t *i = lws_container_of(p, lws_map_item_t, list);
239 
240 		if (!map->info._compare(key, keylen, &i[1], i->keylen))
241 			return i;
242 	} lws_end_foreach_dll(p);
243 
244 	return NULL;
245 }
246 
247 const void *
lws_map_item_key(lws_map_item_t * _item)248 lws_map_item_key(lws_map_item_t *_item)
249 {
250 	return ((void *)&_item[1]);
251 }
252 
253 const void *
lws_map_item_value(lws_map_item_t * _item)254 lws_map_item_value(lws_map_item_t *_item)
255 {
256 	return (void *)(((uint8_t *)&_item[1]) + _item->keylen);
257 }
258 
259 size_t
lws_map_item_key_len(lws_map_item_t * _item)260 lws_map_item_key_len(lws_map_item_t *_item)
261 {
262 	return _item->keylen;
263 }
264 
265 size_t
lws_map_item_value_len(lws_map_item_t * _item)266 lws_map_item_value_len(lws_map_item_t *_item)
267 {
268 	return _item->valuelen;
269 }
270