connect4.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010 - 2020 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. struct lws *
  26. lws_client_connect_4_established(struct lws *wsi, struct lws *wsi_piggyback,
  27. ssize_t plen)
  28. {
  29. #if defined(LWS_CLIENT_HTTP_PROXYING)
  30. struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
  31. #endif
  32. const char *meth;
  33. struct lws_pollfd pfd;
  34. const char *cce = "";
  35. int n, m, rawish = 0;
  36. meth = lws_wsi_client_stash_item(wsi, CIS_METHOD,
  37. _WSI_TOKEN_CLIENT_METHOD);
  38. if (meth && (!strcmp(meth, "RAW")
  39. #if defined(LWS_ROLE_MQTT)
  40. || !strcmp(meth, "MQTT")
  41. #endif
  42. ))
  43. rawish = 1;
  44. if (wsi_piggyback)
  45. goto send_hs;
  46. #if defined(LWS_CLIENT_HTTP_PROXYING)
  47. #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
  48. /* we are connected to server, or proxy */
  49. /* http proxy */
  50. if (wsi->a.vhost->http.http_proxy_port) {
  51. const char *cpa;
  52. cpa = lws_wsi_client_stash_item(wsi, CIS_ADDRESS,
  53. _WSI_TOKEN_CLIENT_PEER_ADDRESS);
  54. if (!cpa)
  55. goto failed;
  56. lwsl_info("%s: going via proxy\n", __func__);
  57. plen = lws_snprintf((char *)pt->serv_buf, 256,
  58. "CONNECT %s:%u HTTP/1.1\x0d\x0a"
  59. "Host: %s:%u\x0d\x0a"
  60. "User-agent: lws\x0d\x0a", cpa, wsi->ocport,
  61. cpa, wsi->ocport);
  62. #if defined(LWS_WITH_HTTP_BASIC_AUTH)
  63. if (wsi->a.vhost->proxy_basic_auth_token[0])
  64. plen += lws_snprintf((char *)pt->serv_buf + plen, 256,
  65. "Proxy-authorization: basic %s\x0d\x0a",
  66. wsi->a.vhost->proxy_basic_auth_token);
  67. #endif
  68. plen += lws_snprintf((char *)pt->serv_buf + plen, 5,
  69. "\x0d\x0a");
  70. /* lwsl_hexdump_notice(pt->serv_buf, plen); */
  71. /*
  72. * OK from now on we talk via the proxy, so connect to that
  73. */
  74. if (wsi->stash)
  75. wsi->stash->cis[CIS_ADDRESS] =
  76. wsi->a.vhost->http.http_proxy_address;
  77. else
  78. if (lws_hdr_simple_create(wsi,
  79. _WSI_TOKEN_CLIENT_PEER_ADDRESS,
  80. wsi->a.vhost->http.http_proxy_address))
  81. goto failed;
  82. wsi->c_port = wsi->a.vhost->http.http_proxy_port;
  83. n = send(wsi->desc.sockfd, (char *)pt->serv_buf, (int)plen,
  84. MSG_NOSIGNAL);
  85. if (n < 0) {
  86. lwsl_debug("ERROR writing to proxy socket\n");
  87. cce = "proxy write failed";
  88. goto failed;
  89. }
  90. lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
  91. wsi->a.context->timeout_secs);
  92. lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY);
  93. return wsi;
  94. }
  95. #endif
  96. #endif
  97. /* coverity */
  98. if (!wsi->a.protocol)
  99. return NULL;
  100. #if defined(LWS_WITH_SOCKS5)
  101. if (lwsi_state(wsi) != LRS_ESTABLISHED)
  102. switch (lws_socks5c_greet(wsi, &cce)) {
  103. case -1:
  104. goto failed;
  105. case 1:
  106. return wsi;
  107. default:
  108. break;
  109. }
  110. #endif
  111. #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
  112. send_hs:
  113. if (wsi_piggyback &&
  114. !lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
  115. /*
  116. * We are pipelining on an already-established connection...
  117. * we can skip tls establishment.
  118. *
  119. * Set these queued guys to a state where they won't actually
  120. * send their headers until we decide later.
  121. */
  122. lwsi_set_state(wsi, LRS_H2_WAITING_TO_SEND_HEADERS);
  123. /*
  124. * we can't send our headers directly, because they have to
  125. * be sent when the parent is writeable. The parent will check
  126. * for anybody on his client transaction queue that is in
  127. * LRS_H1C_ISSUE_HANDSHAKE2, and let them write.
  128. *
  129. * If we are trying to do this too early, before the master
  130. * connection has written his own headers, then it will just
  131. * wait in the queue until it's possible to send them.
  132. */
  133. lws_callback_on_writable(wsi_piggyback);
  134. #if defined(LWS_WITH_DETAILED_LATENCY)
  135. wsi->detlat.earliest_write_req =
  136. wsi->detlat.earliest_write_req_pre_write =
  137. lws_now_usecs();
  138. #endif
  139. lwsl_info("%s: wsi %p: waiting to send hdrs (par state 0x%x)\n",
  140. __func__, wsi, lwsi_state(wsi_piggyback));
  141. } else {
  142. lwsl_info("%s: wsi %p: %s %s client created own conn "
  143. "(raw %d) vh %sm st 0x%x\n",
  144. __func__, wsi, wsi->role_ops->name,
  145. wsi->a.protocol->name, rawish, wsi->a.vhost->name,
  146. lwsi_state(wsi));
  147. /* we are making our own connection */
  148. if (!rawish) {
  149. if (lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2)
  150. lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);
  151. } else {
  152. /* for a method = "RAW" connection, this makes us
  153. * established */
  154. #if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
  155. /* we have connected if we got here */
  156. if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
  157. (wsi->tls.use_ssl & LCCSCF_USE_SSL)) {
  158. int result;
  159. /*
  160. * We can retry this... just cook the SSL BIO
  161. * the first time
  162. */
  163. result = lws_client_create_tls(wsi, &cce, 1);
  164. lwsl_debug("%s: create_tls said %d\n",
  165. __func__, result);
  166. switch (result) {
  167. case CCTLS_RETURN_DONE:
  168. break;
  169. case CCTLS_RETURN_RETRY:
  170. return wsi;
  171. default:
  172. goto failed;
  173. }
  174. /*
  175. * We succeeded to negotiate a new client tls
  176. * tunnel. If it's h2 alpn, we have arranged
  177. * to send the h2 prefix and set our state to
  178. * LRS_H2_WAITING_TO_SEND_HEADERS already.
  179. */
  180. lwsl_notice("%s: wsi %p: "
  181. "tls established st 0x%x\n",
  182. __func__, wsi, lwsi_state(wsi));
  183. if (lwsi_state(wsi) !=
  184. LRS_H2_WAITING_TO_SEND_HEADERS)
  185. lwsi_set_state(wsi,
  186. LRS_H1C_ISSUE_HANDSHAKE2);
  187. lws_set_timeout(wsi,
  188. PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
  189. wsi->a.context->timeout_secs);
  190. goto provoke_service;
  191. }
  192. #endif
  193. /* clear his established timeout */
  194. lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
  195. m = wsi->role_ops->adoption_cb[0];
  196. if (m) {
  197. n = user_callback_handle_rxflow(
  198. wsi->a.protocol->callback, wsi,
  199. m, wsi->user_space, NULL, 0);
  200. if (n < 0) {
  201. lwsl_info("RAW_PROXY_CLI_ADOPT err\n");
  202. goto failed;
  203. }
  204. }
  205. /* service.c pollout processing wants this */
  206. wsi->hdr_parsing_completed = 1;
  207. #if defined(LWS_ROLE_MQTT)
  208. if (!strcmp(meth, "MQTT")) {
  209. #if defined(LWS_WITH_TLS)
  210. if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
  211. lwsi_set_state(wsi, LRS_WAITING_SSL);
  212. return wsi;
  213. }
  214. #endif
  215. lwsl_info("%s: settings LRS_MQTTC_IDLE\n",
  216. __func__);
  217. lwsi_set_state(wsi, LRS_MQTTC_IDLE);
  218. /*
  219. * provoke service to issue the CONNECT
  220. * directly.
  221. */
  222. lws_set_timeout(wsi,
  223. PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
  224. wsi->a.context->timeout_secs);
  225. assert(lws_socket_is_valid(wsi->desc.sockfd));
  226. pfd.fd = wsi->desc.sockfd;
  227. pfd.events = LWS_POLLIN;
  228. pfd.revents = LWS_POLLOUT;
  229. lwsl_info("%s: going to service fd\n",
  230. __func__);
  231. n = lws_service_fd(wsi->a.context, &pfd);
  232. if (n < 0) {
  233. cce = "first service failed";
  234. goto failed;
  235. }
  236. if (n)
  237. /* returns 1 on fail after close wsi */
  238. return NULL;
  239. return wsi;
  240. }
  241. #endif
  242. lwsl_info("%s: setting ESTABLISHED\n", __func__);
  243. lwsi_set_state(wsi, LRS_ESTABLISHED);
  244. return wsi;
  245. }
  246. /*
  247. * provoke service to issue the handshake directly.
  248. *
  249. * we need to do it this way because in the proxy case, this is
  250. * the next state and executed only if and when we get a good
  251. * proxy response inside the state machine... but notice in
  252. * SSL case this may not have sent anything yet with 0 return,
  253. * and won't until many retries from main loop. To stop that
  254. * becoming endless, cover with a timeout.
  255. */
  256. #if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
  257. provoke_service:
  258. #endif
  259. lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
  260. wsi->a.context->timeout_secs);
  261. assert(lws_socket_is_valid(wsi->desc.sockfd));
  262. pfd.fd = wsi->desc.sockfd;
  263. pfd.events = LWS_POLLIN;
  264. pfd.revents = LWS_POLLIN;
  265. n = lws_service_fd(wsi->a.context, &pfd);
  266. if (n < 0) {
  267. cce = "first service failed";
  268. goto failed;
  269. }
  270. if (n) /* returns 1 on failure after closing wsi */
  271. return NULL;
  272. }
  273. #endif
  274. return wsi;
  275. failed:
  276. lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
  277. lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
  278. return NULL;
  279. }