abstract.c 8.4 KB

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