ss-ws.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2019 - 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. static int
  26. secstream_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user,
  27. void *in, size_t len)
  28. {
  29. lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
  30. uint8_t buf[LWS_PRE + 1400];
  31. lws_ss_state_return_t r;
  32. int f = 0, f1, n;
  33. size_t buflen;
  34. switch (reason) {
  35. /* because we are protocols[0] ... */
  36. case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
  37. lwsl_info("%s: CLIENT_CONNECTION_ERROR: %s\n", __func__,
  38. in ? (char *)in : "(null)");
  39. if (!h)
  40. break;
  41. r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
  42. if (r == LWSSSSRET_DESTROY_ME)
  43. return _lws_ss_handle_state_ret(r, wsi, &h);
  44. h->wsi = NULL;
  45. r = lws_ss_backoff(h);
  46. if (r != LWSSSSRET_OK)
  47. return _lws_ss_handle_state_ret(r, wsi, &h);
  48. break;
  49. case LWS_CALLBACK_CLOSED: /* server */
  50. case LWS_CALLBACK_CLIENT_CLOSED:
  51. if (!h)
  52. break;
  53. lws_sul_cancel(&h->sul_timeout);
  54. r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
  55. if (r == LWSSSSRET_DESTROY_ME)
  56. return _lws_ss_handle_state_ret(r, wsi, &h);
  57. if (h->wsi)
  58. lws_set_opaque_user_data(h->wsi, NULL);
  59. h->wsi = NULL;
  60. if (reason == LWS_CALLBACK_CLIENT_CLOSED) {
  61. if (h->policy &&
  62. !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
  63. #if defined(LWS_WITH_SERVER)
  64. !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
  65. #endif
  66. !h->txn_ok && !wsi->a.context->being_destroyed) {
  67. r = lws_ss_backoff(h);
  68. if (r != LWSSSSRET_OK)
  69. return _lws_ss_handle_state_ret(r, wsi, &h);
  70. break;
  71. }
  72. }
  73. break;
  74. case LWS_CALLBACK_ESTABLISHED:
  75. case LWS_CALLBACK_CLIENT_ESTABLISHED:
  76. h->retry = 0;
  77. h->seqstate = SSSEQ_CONNECTED;
  78. lws_sul_cancel(&h->sul);
  79. r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
  80. if (r != LWSSSSRET_OK)
  81. return _lws_ss_handle_state_ret(r, wsi, &h);
  82. break;
  83. case LWS_CALLBACK_RECEIVE:
  84. case LWS_CALLBACK_CLIENT_RECEIVE:
  85. // lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE: read %d\n", (int)len);
  86. if (!h || !h->info.rx)
  87. return 0;
  88. if (lws_is_first_fragment(wsi))
  89. f |= LWSSS_FLAG_SOM;
  90. if (lws_is_final_fragment(wsi))
  91. f |= LWSSS_FLAG_EOM;
  92. // lws_frame_is_binary(wsi);
  93. h->subseq = 1;
  94. r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, f);
  95. if (r != LWSSSSRET_OK)
  96. return _lws_ss_handle_state_ret(r, wsi, &h);
  97. return 0; /* don't passthru */
  98. case LWS_CALLBACK_SERVER_WRITEABLE:
  99. case LWS_CALLBACK_CLIENT_WRITEABLE:
  100. // lwsl_notice("%s: ss %p: WRITEABLE\n", __func__, h);
  101. if (!h || !h->info.tx)
  102. return 0;
  103. if (h->seqstate != SSSEQ_CONNECTED) {
  104. lwsl_warn("%s: seqstate %d\n", __func__, h->seqstate);
  105. break;
  106. }
  107. buflen = sizeof(buf) - LWS_PRE;
  108. r = h->info.tx(ss_to_userobj(h), h->txord++, buf + LWS_PRE,
  109. &buflen, &f);
  110. if (r == LWSSSSRET_TX_DONT_SEND)
  111. return 0;
  112. if (r != LWSSSSRET_OK)
  113. return _lws_ss_handle_state_ret(r, wsi, &h);
  114. f1 = lws_write_ws_flags(h->policy->u.http.u.ws.binary ?
  115. LWS_WRITE_BINARY : LWS_WRITE_TEXT,
  116. !!(f & LWSSS_FLAG_SOM),
  117. !!(f & LWSSS_FLAG_EOM));
  118. n = lws_write(wsi, buf + LWS_PRE, buflen, f1);
  119. if (n < (int)buflen) {
  120. lwsl_info("%s: write failed %d %d\n", __func__,
  121. n, (int)buflen);
  122. return -1;
  123. }
  124. return 0;
  125. default:
  126. break;
  127. }
  128. return lws_callback_http_dummy(wsi, reason, user, in, len);
  129. }
  130. const struct lws_protocols protocol_secstream_ws = {
  131. "lws-secstream-ws",
  132. secstream_ws,
  133. 0,
  134. 0,
  135. };
  136. /*
  137. * Munge connect info according to protocol-specific considerations... this
  138. * usually means interpreting aux in a protocol-specific way and using the
  139. * pieces at connection setup time, eg, http url pieces.
  140. *
  141. * len bytes of buf can be used for things with scope until after the actual
  142. * connect.
  143. *
  144. * For ws, protocol aux is <url path>;<ws subprotocol name>
  145. */
  146. static int
  147. secstream_connect_munge_ws(lws_ss_handle_t *h, char *buf, size_t len,
  148. struct lws_client_connect_info *i,
  149. union lws_ss_contemp *ct)
  150. {
  151. const char *pbasis = h->policy->u.http.url;
  152. size_t used_in, used_out;
  153. lws_strexp_t exp;
  154. lwsl_notice("%s\n", __func__);
  155. /* i.path on entry is used to override the policy urlpath if not "" */
  156. if (i->path[0])
  157. pbasis = i->path;
  158. if (!pbasis)
  159. return 0;
  160. /* protocol aux is the path part ; ws subprotocol name */
  161. i->path = buf;
  162. buf[0] = '/';
  163. lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1);
  164. if (lws_strexp_expand(&exp, pbasis, strlen(pbasis),
  165. &used_in, &used_out) != LSTRX_DONE)
  166. return 1;
  167. i->protocol = h->policy->u.http.u.ws.subprotocol;
  168. lwsl_notice("%s: url %s, ws subprotocol %s\n", __func__, buf, i->protocol);
  169. return 0;
  170. }
  171. const struct ss_pcols ss_pcol_ws = {
  172. "ws", "http/1.1", &protocol_secstream_ws, secstream_connect_munge_ws
  173. };