• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 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 #include <private-lib-abstract.h>
27 
28 extern const lws_abs_transport_t lws_abs_transport_cli_raw_skt,
29 				 lws_abs_transport_cli_unit_test;
30 #if defined(LWS_WITH_SMTP)
31 extern const lws_abs_protocol_t lws_abs_protocol_smtp;
32 #endif
33 #if defined(LWS_WITH_MQTT)
34 extern const lws_abs_protocol_t lws_abs_protocol_mqttc;
35 #endif
36 
37 static const lws_abs_transport_t * const available_abs_transports[] = {
38 	&lws_abs_transport_cli_raw_skt,
39 	&lws_abs_transport_cli_unit_test,
40 };
41 
42 #if defined(LWS_WITH_ABSTRACT)
43 static const lws_abs_protocol_t * const available_abs_protocols[] = {
44 #if defined(LWS_WITH_SMTP)
45 	&lws_abs_protocol_smtp,
46 #endif
47 #if defined(LWS_WITH_MQTT)
48 	&lws_abs_protocol_mqttc,
49 #endif
50 };
51 #endif
52 
53 const lws_abs_transport_t *
lws_abs_transport_get_by_name(const char * name)54 lws_abs_transport_get_by_name(const char *name)
55 {
56 	int n;
57 
58 	for (n = 0; n < (int)LWS_ARRAY_SIZE(available_abs_transports); n++)
59 		if (!strcmp(name, available_abs_transports[n]->name))
60 			return available_abs_transports[n];
61 
62 	lwsl_err("%s: cannot find '%s'\n", __func__, name);
63 
64 	return NULL;
65 }
66 
67 const lws_abs_protocol_t *
lws_abs_protocol_get_by_name(const char * name)68 lws_abs_protocol_get_by_name(const char *name)
69 {
70 #if defined(LWS_WITH_ABSTRACT)
71 	int n;
72 
73 	for (n = 0; n < (int)LWS_ARRAY_SIZE(available_abs_protocols); n++)
74 		if (!strcmp(name, available_abs_protocols[n]->name))
75 			return available_abs_protocols[n];
76 #endif
77 	lwsl_err("%s: cannot find '%s'\n", __func__, name);
78 
79 	return NULL;
80 }
81 
82 const lws_token_map_t *
lws_abs_get_token(const lws_token_map_t * token_map,short name_index)83 lws_abs_get_token(const lws_token_map_t *token_map, short name_index)
84 {
85 	if (!token_map)
86 		return NULL;
87 
88 	do {
89 		if (token_map->name_index == name_index)
90 			return token_map;
91 		token_map++;
92 	} while (token_map->name_index);
93 
94 	return NULL;
95 }
96 
97 static int
lws_abstract_compare_connection(lws_abs_t * abs1,lws_abs_t * abs2)98 lws_abstract_compare_connection(lws_abs_t *abs1, lws_abs_t *abs2)
99 {
100 	/* it has to be using the same protocol */
101 	if (abs1->ap != abs2->ap)
102 		return 1;
103 
104 	/* protocol has to allow some kind of binding */
105 	if (!abs1->ap->flags)
106 		return 1;
107 
108 	/* it has to be using the same transport */
109 	if (abs1->at != abs2->at)
110 		return 1;
111 
112 	/*
113 	 * The transport must feel the endpoint and conditions in use match the
114 	 * requested endpoint and conditions... and the transport type must be
115 	 * willing to allow it
116 	 */
117 	if (abs1->at->compare(abs1, abs2))
118 		return 1;
119 
120 	/*
121 	 * The protocol must feel they are in compatible modes if any
122 	 * (and the protocol type must be willing to allow it)
123 	 */
124 	if (abs1->ap->compare(abs1, abs2))
125 		return 1;
126 
127 	/*
128 	 * If no objection by now, we can say there's already a comparable
129 	 * connection and both the protocol and transport feel we can make
130 	 * use of it.
131 	 */
132 
133 	return 0;
134 }
135 
136 static int
find_compatible(struct lws_dll2 * d,void * user)137 find_compatible(struct lws_dll2 *d, void *user)
138 {
139 	lws_abs_t *ai1 = (lws_abs_t *)user,
140 		  *ai2 = lws_container_of(d, lws_abs_t, abstract_instances);
141 
142 	if (!lws_abstract_compare_connection(ai1, ai2)) {
143 		/* we can bind to it */
144 		lws_dll2_add_tail(&ai1->bound, &ai2->children_owner);
145 
146 		return 1;
147 	}
148 
149 	return 0;
150 }
151 
152 lws_abs_t *
lws_abs_bind_and_create_instance(const lws_abs_t * abs)153 lws_abs_bind_and_create_instance(const lws_abs_t *abs)
154 {
155 	size_t size = sizeof(lws_abs_t) + abs->ap->alloc + abs->at->alloc;
156 	lws_abs_t *ai;
157 	int n;
158 
159 	/*
160 	 * since we know we will allocate the lws_abs_t, the protocol's
161 	 * instance allocation, and the transport's instance allocation,
162 	 * we merge it into a single heap allocation
163 	 */
164 	ai = lws_malloc(size, "abs inst");
165 	if (!ai)
166 		return NULL;
167 
168 	*ai = *abs;
169 	ai->ati = NULL;
170 
171 	ai->api = (char *)ai + sizeof(lws_abs_t);
172 
173 	if (!ai->ap->flags) /* protocol only understands single connections */
174 		goto fresh;
175 
176 	lws_vhost_lock(ai->vh); /* ----------------------------------- vh { */
177 
178 	/*
179 	 * Let's have a look for any already-connected transport we can use
180 	 */
181 
182 	n = lws_dll2_foreach_safe(&ai->vh->abstract_instances_owner, ai,
183 				  find_compatible);
184 
185 	lws_vhost_unlock(ai->vh); /* } vh --------------------------------- */
186 
187 	if (n)
188 		goto vh_list_add;
189 
190 	/* there's no existing connection doing what we want */
191 
192 fresh:
193 
194 	ai->ati = (char *)ai->api + abs->ap->alloc;
195 	if (ai->at->create(ai)) {
196 		ai->ati = NULL;
197 		goto bail;
198 	}
199 
200 vh_list_add:
201 	/* add us to the vhost's dll2 of instances */
202 
203 	lws_dll2_clear(&ai->abstract_instances);
204 	lws_dll2_add_head(&ai->abstract_instances,
205 			  &ai->vh->abstract_instances_owner);
206 
207 	if (ai->ap->create(ai)) {
208 		ai->api = NULL;
209 		goto bail;
210 	}
211 
212 	if (ai->bound.owner) { /* we are a piggybacker */
213 		lws_abs_t *ai2 = lws_container_of(ai->bound.owner, lws_abs_t,
214 						  children_owner);
215 		/*
216 		 * Provide an 'event' in the parent context to start handling
217 		 * the bind if it's otherwise idle.  We give the parent abs
218 		 * because we don't know if we're "next" or whatever.  Just that
219 		 * a child joined him and he should look into his child
220 		 * situation in case he was waiting for one to appear.
221 		 */
222 		if (ai2->ap->child_bind(ai2)) {
223 			lwsl_info("%s: anticpated child bind fail\n", __func__);
224 			lws_dll2_remove(&ai->bound);
225 
226 			goto bail;
227 		}
228 	}
229 
230 	return ai;
231 
232 bail:
233 	lws_abs_destroy_instance(&ai);
234 
235 	return NULL;
236 }
237 
238 /*
239  * We get called to clean up each child that was still bound to a parent
240  * at the time the parent is getting destroyed.
241  */
242 
243 static void
__lws_abs_destroy_instance2(lws_abs_t ** ai)244 __lws_abs_destroy_instance2(lws_abs_t **ai)
245 {
246 	lws_abs_t *a = *ai;
247 
248 	if (a->api)
249 		a->ap->destroy(&a->api);
250 	if (a->ati)
251 		a->at->destroy(&a->ati);
252 
253 	lws_dll2_remove(&a->abstract_instances);
254 
255 	*ai = NULL;
256 	free(a);
257 }
258 
259 static int
__reap_children(struct lws_dll2 * d,void * user)260 __reap_children(struct lws_dll2 *d, void *user)
261 {
262 	lws_abs_t *ac = lws_container_of(d, lws_abs_t, bound);
263 
264 	lws_dll2_foreach_safe(&ac->children_owner, NULL, __reap_children);
265 
266 	/* then destroy ourselves */
267 
268 	__lws_abs_destroy_instance2(&ac);
269 
270 	return 0;
271 }
272 
273 void
lws_abs_destroy_instance(lws_abs_t ** ai)274 lws_abs_destroy_instance(lws_abs_t **ai)
275 {
276 	lws_abs_t *a = *ai;
277 
278 	/* destroy child instances that are bound to us first... */
279 
280 	lws_vhost_lock(a->vh); /* ----------------------------------- vh { */
281 
282 	lws_dll2_foreach_safe(&a->children_owner, NULL, __reap_children);
283 
284 	/* ...then destroy ourselves */
285 
286 	__lws_abs_destroy_instance2(ai);
287 
288 	lws_vhost_unlock(a->vh); /* } vh --------------------------------- */
289 }
290 
291 lws_abs_t *
lws_abstract_alloc(struct lws_vhost * vhost,void * user,const char * abstract_path,const lws_token_map_t * ap_tokens,const lws_token_map_t * at_tokens,struct lws_sequencer * seq,void * opaque_user_data)292 lws_abstract_alloc(struct lws_vhost *vhost, void *user,
293 		   const char *abstract_path, const lws_token_map_t *ap_tokens,
294 		   const lws_token_map_t *at_tokens, struct lws_sequencer *seq,
295 		   void *opaque_user_data)
296 {
297 	lws_abs_t *abs = lws_zalloc(sizeof(*abs), __func__);
298 	struct lws_tokenize ts;
299 	lws_tokenize_elem e;
300 	char tmp[30];
301 
302 	if (!abs)
303 		return NULL;
304 
305 	lws_tokenize_init(&ts, abstract_path, LWS_TOKENIZE_F_MINUS_NONTERM);
306 
307 	e = lws_tokenize(&ts);
308 	if (e != LWS_TOKZE_TOKEN)
309 		goto abs_path_problem;
310 
311 	if (lws_tokenize_cstr(&ts, tmp, sizeof(tmp)))
312 		goto abs_path_problem;
313 
314 	abs->ap = lws_abs_protocol_get_by_name(tmp);
315 	if (!abs->ap)
316 		goto abs_path_problem;
317 
318 	e = lws_tokenize(&ts);
319 	if (e != LWS_TOKZE_DELIMITER)
320 		goto abs_path_problem;
321 
322 	e = lws_tokenize(&ts);
323 	if (e != LWS_TOKZE_TOKEN)
324 		goto abs_path_problem;
325 
326 	if (lws_tokenize_cstr(&ts, tmp, sizeof(tmp)))
327 		goto abs_path_problem;
328 
329 	abs->at = lws_abs_transport_get_by_name(tmp);
330 	if (!abs->at)
331 		goto abs_path_problem;
332 
333 	abs->vh = vhost;
334 	abs->ap_tokens = ap_tokens;
335 	abs->at_tokens = at_tokens;
336 	abs->seq = seq;
337 	abs->opaque_user_data = opaque_user_data;
338 
339 	lwsl_info("%s: allocated %s\n", __func__, abstract_path);
340 
341 	return abs;
342 
343 abs_path_problem:
344 	lwsl_err("%s: bad abs path '%s'\n", __func__, abstract_path);
345 	lws_free_set_NULL(abs);
346 
347 	return NULL;
348 }
349 
350 void
lws_abstract_free(lws_abs_t ** pabs)351 lws_abstract_free(lws_abs_t **pabs)
352 {
353 	if (*pabs)
354 		lws_free_set_NULL(*pabs);
355 }
356