connect.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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 <libwebsockets.h>
  25. #include "private-lib-core.h"
  26. struct lws *
  27. lws_client_connect_via_info(const struct lws_client_connect_info *i)
  28. {
  29. const char *local = i->protocol;
  30. struct lws *wsi, *safe = NULL;
  31. const struct lws_protocols *p;
  32. size_t s = sizeof(struct lws);
  33. const char *cisin[CIS_COUNT];
  34. int tid = 0, n, m;
  35. size_t size;
  36. char *pc;
  37. if (i->context->requested_kill)
  38. return NULL;
  39. if (!i->context->protocol_init_done)
  40. if (lws_protocol_init(i->context))
  41. return NULL;
  42. /*
  43. * If we have .local_protocol_name, use it to select the local protocol
  44. * handler to bind to. Otherwise use .protocol if http[s].
  45. */
  46. if (i->local_protocol_name)
  47. local = i->local_protocol_name;
  48. lws_stats_bump(&i->context->pt[tid], LWSSTATS_C_CONNS_CLIENT, 1);
  49. /* PHASE 1: create a bare wsi */
  50. #if defined(LWS_WITH_EVENT_LIBS)
  51. s += i->context->event_loop_ops->evlib_size_wsi;
  52. #endif
  53. wsi = lws_zalloc(s, "client wsi");
  54. if (wsi == NULL)
  55. goto bail;
  56. #if defined(LWS_WITH_EVENT_LIBS)
  57. wsi->evlib_wsi = (uint8_t *)wsi + sizeof(*wsi);
  58. #endif
  59. /*
  60. * Until we exit, we can report connection failure directly to the
  61. * caller without needing to call through to protocol CONNECTION_ERROR.
  62. */
  63. wsi->client_suppress_CONNECTION_ERROR = 1;
  64. if (i->keep_warm_secs)
  65. wsi->keep_warm_secs = i->keep_warm_secs;
  66. else
  67. wsi->keep_warm_secs = 5;
  68. wsi->a.context = i->context;
  69. wsi->desc.sockfd = LWS_SOCK_INVALID;
  70. wsi->seq = i->seq;
  71. wsi->flags = i->ssl_connection;
  72. if (i->retry_and_idle_policy)
  73. wsi->retry_policy = i->retry_and_idle_policy;
  74. else
  75. wsi->retry_policy = &i->context->default_retry;
  76. #if defined(LWS_WITH_DETAILED_LATENCY)
  77. if (i->context->detailed_latency_cb)
  78. wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
  79. #endif
  80. if (i->ssl_connection & LCCSCF_WAKE_SUSPEND__VALIDITY)
  81. wsi->conn_validity_wakesuspend = 1;
  82. wsi->a.vhost = NULL;
  83. if (!i->vhost) {
  84. struct lws_vhost *v = i->context->vhost_list;
  85. if (!v) { /* coverity */
  86. lwsl_err("%s: no vhost\n", __func__);
  87. goto bail;
  88. }
  89. if (!strcmp(v->name, "system"))
  90. v = v->vhost_next;
  91. lws_vhost_bind_wsi(v, wsi);
  92. } else
  93. lws_vhost_bind_wsi(i->vhost, wsi);
  94. if (!wsi->a.vhost) {
  95. lwsl_err("%s: No vhost in the context\n", __func__);
  96. goto bail;
  97. }
  98. #if LWS_MAX_SMP > 1
  99. tid = wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_GET_THREAD_ID,
  100. NULL, NULL, 0);
  101. #endif
  102. /*
  103. * PHASE 2: if SMP, bind the client to whatever tsi the current thread
  104. * represents
  105. */
  106. #if LWS_MAX_SMP > 1
  107. lws_context_lock(i->context, "client find tsi");
  108. for (n = 0; n < i->context->count_threads; n++)
  109. if (i->context->pt[n].service_tid == tid) {
  110. lwsl_info("%s: client binds to caller tsi %d\n",
  111. __func__, n);
  112. wsi->tsi = n;
  113. #if defined(LWS_WITH_DETAILED_LATENCY)
  114. wsi->detlat.tsi = n;
  115. #endif
  116. break;
  117. }
  118. /*
  119. * this binding is sort of provisional, since when we try to insert
  120. * into the pt fds, there may be no space and it will fail
  121. */
  122. lws_context_unlock(i->context);
  123. #endif
  124. /*
  125. * PHASE 3: Choose an initial role for the wsi and do role-specific init
  126. *
  127. * Note the initial role may not reflect the final role, eg,
  128. * we may want ws, but first we have to go through h1 to get that
  129. */
  130. if (lws_role_call_client_bind(wsi, i) < 0) {
  131. lwsl_err("%s: unable to bind to role\n", __func__);
  132. goto bail;
  133. }
  134. lwsl_info("%s: role binding to %s\n", __func__, wsi->role_ops->name);
  135. /*
  136. * PHASE 4: fill up the wsi with stuff from the connect_info as far as
  137. * it can go. It's uncertain because not only is our connection
  138. * going to complete asynchronously, we might have bound to h1 and not
  139. * even be able to get ahold of an ah immediately.
  140. */
  141. wsi->user_space = NULL;
  142. wsi->pending_timeout = NO_PENDING_TIMEOUT;
  143. wsi->position_in_fds_table = LWS_NO_FDS_POS;
  144. wsi->ocport = wsi->c_port = i->port;
  145. wsi->sys_tls_client_cert = i->sys_tls_client_cert;
  146. #if defined(LWS_ROLE_H2)
  147. wsi->txc.manual_initial_tx_credit = (int32_t)i->manual_initial_tx_credit;
  148. #endif
  149. wsi->a.protocol = &wsi->a.vhost->protocols[0];
  150. wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE);
  151. wsi->client_no_follow_redirect = !!(i->ssl_connection &
  152. LCCSCF_HTTP_NO_FOLLOW_REDIRECT);
  153. /*
  154. * PHASE 5: handle external user_space now, generic alloc is done in
  155. * role finalization
  156. */
  157. if (i->userdata) {
  158. wsi->user_space_externally_allocated = 1;
  159. wsi->user_space = i->userdata;
  160. }
  161. if (local) {
  162. lwsl_info("%s: vh %s protocol binding to %s\n", __func__, wsi->a.vhost->name, local);
  163. p = lws_vhost_name_to_protocol(wsi->a.vhost, local);
  164. if (p)
  165. lws_bind_protocol(wsi, p, __func__);
  166. else
  167. lwsl_info("%s: unknown protocol %s\n", __func__, local);
  168. lwsl_info("%s: wsi %p: %s %s entry\n",
  169. __func__, wsi, wsi->role_ops->name,
  170. wsi->a.protocol ? wsi->a.protocol->name : "none");
  171. }
  172. /*
  173. * PHASE 5: handle external user_space now, generic alloc is done in
  174. * role finalization
  175. */
  176. if (!wsi->user_space && i->userdata) {
  177. wsi->user_space_externally_allocated = 1;
  178. wsi->user_space = i->userdata;
  179. }
  180. #if defined(LWS_WITH_TLS)
  181. wsi->tls.use_ssl = i->ssl_connection;
  182. #else
  183. if (i->ssl_connection & LCCSCF_USE_SSL) {
  184. lwsl_err("%s: lws not configured for tls\n", __func__);
  185. goto bail;
  186. }
  187. #endif
  188. /*
  189. * PHASE 6: stash the things from connect_info that we can't process
  190. * right now, eg, if http binding, without an ah. If h1 and no ah, we
  191. * will go on the ah waiting list and process those things later (after
  192. * the connect_info and maybe the things pointed to have gone out of
  193. * scope)
  194. *
  195. * However these things are stashed in a generic way at this point,
  196. * with no relationship to http or ah
  197. */
  198. cisin[CIS_ADDRESS] = i->address;
  199. cisin[CIS_PATH] = i->path;
  200. cisin[CIS_HOST] = i->host;
  201. cisin[CIS_ORIGIN] = i->origin;
  202. cisin[CIS_PROTOCOL] = i->protocol;
  203. cisin[CIS_METHOD] = i->method;
  204. cisin[CIS_IFACE] = i->iface;
  205. cisin[CIS_ALPN] = i->alpn;
  206. size = sizeof(*wsi->stash);
  207. /*
  208. * Let's overallocate the stash object with space for all the args
  209. * in one hit.
  210. */
  211. for (n = 0; n < CIS_COUNT; n++)
  212. if (cisin[n])
  213. size += strlen(cisin[n]) + 1;
  214. wsi->stash = lws_malloc(size, "client stash");
  215. if (!wsi->stash) {
  216. lwsl_err("%s: OOM\n", __func__);
  217. goto bail1;
  218. }
  219. /* all the pointers default to NULL, but no need to zero the args */
  220. memset(wsi->stash, 0, sizeof(*wsi->stash));
  221. wsi->a.opaque_user_data = wsi->stash->opaque_user_data =
  222. i->opaque_user_data;
  223. pc = (char *)&wsi->stash[1];
  224. for (n = 0; n < CIS_COUNT; n++)
  225. if (cisin[n]) {
  226. wsi->stash->cis[n] = pc;
  227. m = (int)strlen(cisin[n]) + 1;
  228. memcpy(pc, cisin[n], m);
  229. pc += m;
  230. }
  231. /*
  232. * at this point user callbacks like
  233. * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER will be interested to
  234. * know the parent... eg for proxying we can grab extra headers from
  235. * the parent's incoming ah and add them to the child client handshake
  236. */
  237. if (i->parent_wsi) {
  238. lwsl_info("%s: created child %p of parent %p\n", __func__,
  239. wsi, i->parent_wsi);
  240. wsi->parent = i->parent_wsi;
  241. safe = wsi->sibling_list = i->parent_wsi->child_list;
  242. i->parent_wsi->child_list = wsi;
  243. }
  244. /*
  245. * PHASE 7: Do any role-specific finalization processing. We can still
  246. * see important info things via wsi->stash
  247. */
  248. if (wsi->role_ops->client_bind) {
  249. int n = wsi->role_ops->client_bind(wsi, NULL);
  250. if (n && i->parent_wsi) {
  251. /* unpick from parent */
  252. i->parent_wsi->child_list = safe;
  253. }
  254. if (n < 0)
  255. /* we didn't survive, wsi is freed */
  256. goto bail2;
  257. if (n)
  258. /* something else failed, wsi needs freeing */
  259. goto bail;
  260. }
  261. /* let the caller's optional wsi storage have the wsi we created */
  262. if (i->pwsi)
  263. *i->pwsi = wsi;
  264. /* PHASE 8: notify protocol with role-specific connected callback */
  265. /* raw socket per se doesn't want this... raw socket proxy wants it... */
  266. if (wsi->role_ops != &role_ops_raw_skt ||
  267. (i->local_protocol_name &&
  268. !strcmp(i->local_protocol_name, "raw-proxy"))) {
  269. lwsl_debug("%s: wsi %p: adoption cb %d to %s %s\n", __func__,
  270. wsi, wsi->role_ops->adoption_cb[0],
  271. wsi->role_ops->name, wsi->a.protocol->name);
  272. wsi->a.protocol->callback(wsi, wsi->role_ops->adoption_cb[0],
  273. wsi->user_space, NULL, 0);
  274. }
  275. #if defined(LWS_WITH_HUBBUB)
  276. if (i->uri_replace_to)
  277. wsi->http.rw = lws_rewrite_create(wsi, html_parser_cb,
  278. i->uri_replace_from,
  279. i->uri_replace_to);
  280. #endif
  281. if (i->method && (!strcmp(i->method, "RAW") // ||
  282. // !strcmp(i->method, "MQTT")
  283. )) {
  284. /*
  285. * Not for MQTT here, since we don't know if we will
  286. * pipeline it or not...
  287. */
  288. #if defined(LWS_WITH_TLS)
  289. wsi->tls.ssl = NULL;
  290. if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
  291. const char *cce = NULL;
  292. switch (
  293. #if !defined(LWS_WITH_SYS_ASYNC_DNS)
  294. lws_client_create_tls(wsi, &cce, 1)
  295. #else
  296. lws_client_create_tls(wsi, &cce, 0)
  297. #endif
  298. ) {
  299. case 1:
  300. return wsi;
  301. case 0:
  302. break;
  303. default:
  304. goto bail3;
  305. }
  306. }
  307. #endif
  308. /* fallthru */
  309. wsi = lws_http_client_connect_via_info2(wsi);
  310. }
  311. if (wsi)
  312. /*
  313. * If it subsequently fails, report CONNECTION_ERROR,
  314. * because we're going to return a non-error return now.
  315. */
  316. wsi->client_suppress_CONNECTION_ERROR = 0;
  317. return wsi;
  318. #if defined(LWS_WITH_TLS)
  319. bail3:
  320. lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "tls start fail");
  321. return NULL;
  322. #endif
  323. bail1:
  324. lws_free_set_NULL(wsi->stash);
  325. bail:
  326. lws_free(wsi);
  327. #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
  328. bail2:
  329. #endif
  330. #if defined(LWS_WITH_TLS)
  331. if (i->ssl_connection & LCCSCF_USE_SSL)
  332. lws_tls_restrict_return(i->context);
  333. #endif
  334. if (i->pwsi)
  335. *i->pwsi = NULL;
  336. lws_stats_bump(&i->context->pt[tid], LWSSTATS_C_CONNS_CLIENT_FAILED, 1);
  337. return NULL;
  338. }