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