1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2019 - 2020 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 27d4afb5ceSopenharmony_cistatic int 28d4afb5ceSopenharmony_cisecstream_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user, 29d4afb5ceSopenharmony_ci void *in, size_t len) 30d4afb5ceSopenharmony_ci{ 31d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 32d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 33d4afb5ceSopenharmony_ci#endif 34d4afb5ceSopenharmony_ci lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); 35d4afb5ceSopenharmony_ci uint8_t buf[LWS_PRE + 1400]; 36d4afb5ceSopenharmony_ci lws_ss_state_return_t r; 37d4afb5ceSopenharmony_ci int f = 0, f1, n; 38d4afb5ceSopenharmony_ci size_t buflen; 39d4afb5ceSopenharmony_ci 40d4afb5ceSopenharmony_ci switch (reason) { 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_ci /* because we are protocols[0] ... */ 43d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 44d4afb5ceSopenharmony_ci lwsl_info("%s: CLIENT_CONNECTION_ERROR: %s\n", __func__, 45d4afb5ceSopenharmony_ci in ? (char *)in : "(null)"); 46d4afb5ceSopenharmony_ci if (!h) 47d4afb5ceSopenharmony_ci break; 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON) 50d4afb5ceSopenharmony_ci lws_conmon_ss_json(h); 51d4afb5ceSopenharmony_ci#endif 52d4afb5ceSopenharmony_ci 53d4afb5ceSopenharmony_ci r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE); 54d4afb5ceSopenharmony_ci if (r == LWSSSSRET_DESTROY_ME) 55d4afb5ceSopenharmony_ci return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); 56d4afb5ceSopenharmony_ci 57d4afb5ceSopenharmony_ci h->wsi = NULL; 58d4afb5ceSopenharmony_ci r = lws_ss_backoff(h); 59d4afb5ceSopenharmony_ci if (r != LWSSSSRET_OK) 60d4afb5ceSopenharmony_ci return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); 61d4afb5ceSopenharmony_ci break; 62d4afb5ceSopenharmony_ci 63d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED: /* server */ 64d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CLOSED: 65d4afb5ceSopenharmony_ci if (!h) 66d4afb5ceSopenharmony_ci break; 67d4afb5ceSopenharmony_ci lws_sul_cancel(&h->sul_timeout); 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON) 70d4afb5ceSopenharmony_ci lws_conmon_ss_json(h); 71d4afb5ceSopenharmony_ci#endif 72d4afb5ceSopenharmony_ci 73d4afb5ceSopenharmony_ci r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED); 74d4afb5ceSopenharmony_ci if (r == LWSSSSRET_DESTROY_ME) 75d4afb5ceSopenharmony_ci return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); 76d4afb5ceSopenharmony_ci 77d4afb5ceSopenharmony_ci if (h->wsi) 78d4afb5ceSopenharmony_ci lws_set_opaque_user_data(h->wsi, NULL); 79d4afb5ceSopenharmony_ci h->wsi = NULL; 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 82d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 83d4afb5ceSopenharmony_ci lws_dll2_remove(&h->cli_list); 84d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 85d4afb5ceSopenharmony_ci#endif 86d4afb5ceSopenharmony_ci 87d4afb5ceSopenharmony_ci if (reason == LWS_CALLBACK_CLIENT_CLOSED) { 88d4afb5ceSopenharmony_ci if (h->policy && 89d4afb5ceSopenharmony_ci !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) && 90d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 91d4afb5ceSopenharmony_ci !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */ 92d4afb5ceSopenharmony_ci#endif 93d4afb5ceSopenharmony_ci !wsi->a.context->being_destroyed) { 94d4afb5ceSopenharmony_ci r = lws_ss_backoff(h); 95d4afb5ceSopenharmony_ci if (r != LWSSSSRET_OK) 96d4afb5ceSopenharmony_ci return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); 97d4afb5ceSopenharmony_ci break; 98d4afb5ceSopenharmony_ci } 99d4afb5ceSopenharmony_ci 100d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 101d4afb5ceSopenharmony_ci if (h->info.flags & LWSSSINFLAGS_ACCEPTED) { 102d4afb5ceSopenharmony_ci /* 103d4afb5ceSopenharmony_ci * was an accepted client connection to 104d4afb5ceSopenharmony_ci * our server, so the stream is over now 105d4afb5ceSopenharmony_ci */ 106d4afb5ceSopenharmony_ci lws_ss_destroy(&h); 107d4afb5ceSopenharmony_ci return 0; 108d4afb5ceSopenharmony_ci } 109d4afb5ceSopenharmony_ci#endif 110d4afb5ceSopenharmony_ci 111d4afb5ceSopenharmony_ci } 112d4afb5ceSopenharmony_ci break; 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_ci case LWS_CALLBACK_ESTABLISHED: 115d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_ESTABLISHED: 116d4afb5ceSopenharmony_ci h->retry = 0; 117d4afb5ceSopenharmony_ci h->seqstate = SSSEQ_CONNECTED; 118d4afb5ceSopenharmony_ci lws_sul_cancel(&h->sul); 119d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS) 120d4afb5ceSopenharmony_ci /* 121d4afb5ceSopenharmony_ci * If any hanging caliper measurement, dump it, and free any tags 122d4afb5ceSopenharmony_ci */ 123d4afb5ceSopenharmony_ci lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL); 124d4afb5ceSopenharmony_ci#endif 125d4afb5ceSopenharmony_ci r = lws_ss_event_helper(h, LWSSSCS_CONNECTED); 126d4afb5ceSopenharmony_ci if (r != LWSSSSRET_OK) 127d4afb5ceSopenharmony_ci return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); 128d4afb5ceSopenharmony_ci break; 129d4afb5ceSopenharmony_ci 130d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE: 131d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_RECEIVE: 132d4afb5ceSopenharmony_ci // lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE: read %d\n", (int)len); 133d4afb5ceSopenharmony_ci if (!h || !h->info.rx) 134d4afb5ceSopenharmony_ci return 0; 135d4afb5ceSopenharmony_ci if (lws_is_first_fragment(wsi)) 136d4afb5ceSopenharmony_ci f |= LWSSS_FLAG_SOM; 137d4afb5ceSopenharmony_ci if (lws_is_final_fragment(wsi)) 138d4afb5ceSopenharmony_ci f |= LWSSS_FLAG_EOM; 139d4afb5ceSopenharmony_ci // lws_frame_is_binary(wsi); 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci h->subseq = 1; 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_ci r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, f); 144d4afb5ceSopenharmony_ci if (r != LWSSSSRET_OK) 145d4afb5ceSopenharmony_ci return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); 146d4afb5ceSopenharmony_ci 147d4afb5ceSopenharmony_ci return 0; /* don't passthru */ 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_ci case LWS_CALLBACK_SERVER_WRITEABLE: 150d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_WRITEABLE: 151d4afb5ceSopenharmony_ci // lwsl_notice("%s: %s: WRITEABLE\n", __func__, lws_ss_tag(h)); 152d4afb5ceSopenharmony_ci if (!h || !h->info.tx) 153d4afb5ceSopenharmony_ci return 0; 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_ci if (h->seqstate != SSSEQ_CONNECTED) { 156d4afb5ceSopenharmony_ci lwsl_warn("%s: seqstate %d\n", __func__, h->seqstate); 157d4afb5ceSopenharmony_ci break; 158d4afb5ceSopenharmony_ci } 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci buflen = sizeof(buf) - LWS_PRE; 161d4afb5ceSopenharmony_ci r = h->info.tx(ss_to_userobj(h), h->txord++, buf + LWS_PRE, 162d4afb5ceSopenharmony_ci &buflen, &f); 163d4afb5ceSopenharmony_ci if (r == LWSSSSRET_TX_DONT_SEND) 164d4afb5ceSopenharmony_ci return 0; 165d4afb5ceSopenharmony_ci if (r != LWSSSSRET_OK) 166d4afb5ceSopenharmony_ci return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); 167d4afb5ceSopenharmony_ci 168d4afb5ceSopenharmony_ci f1 = lws_write_ws_flags(h->policy->u.http.u.ws.binary ? 169d4afb5ceSopenharmony_ci LWS_WRITE_BINARY : LWS_WRITE_TEXT, 170d4afb5ceSopenharmony_ci !!(f & LWSSS_FLAG_SOM), 171d4afb5ceSopenharmony_ci !!(f & LWSSS_FLAG_EOM)); 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_ci n = lws_write(wsi, buf + LWS_PRE, buflen, (enum lws_write_protocol)f1); 174d4afb5ceSopenharmony_ci if (n < (int)buflen) { 175d4afb5ceSopenharmony_ci lwsl_info("%s: write failed %d %d\n", __func__, 176d4afb5ceSopenharmony_ci n, (int)buflen); 177d4afb5ceSopenharmony_ci 178d4afb5ceSopenharmony_ci return -1; 179d4afb5ceSopenharmony_ci } 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci return 0; 182d4afb5ceSopenharmony_ci 183d4afb5ceSopenharmony_ci default: 184d4afb5ceSopenharmony_ci break; 185d4afb5ceSopenharmony_ci } 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci return lws_callback_http_dummy(wsi, reason, user, in, len); 188d4afb5ceSopenharmony_ci} 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ciconst struct lws_protocols protocol_secstream_ws = { 191d4afb5ceSopenharmony_ci "lws-secstream-ws", 192d4afb5ceSopenharmony_ci secstream_ws, 193d4afb5ceSopenharmony_ci 0, 0, 0, NULL, 0 194d4afb5ceSopenharmony_ci}; 195d4afb5ceSopenharmony_ci/* 196d4afb5ceSopenharmony_ci * Munge connect info according to protocol-specific considerations... this 197d4afb5ceSopenharmony_ci * usually means interpreting aux in a protocol-specific way and using the 198d4afb5ceSopenharmony_ci * pieces at connection setup time, eg, http url pieces. 199d4afb5ceSopenharmony_ci * 200d4afb5ceSopenharmony_ci * len bytes of buf can be used for things with scope until after the actual 201d4afb5ceSopenharmony_ci * connect. 202d4afb5ceSopenharmony_ci * 203d4afb5ceSopenharmony_ci * For ws, protocol aux is <url path>;<ws subprotocol name> 204d4afb5ceSopenharmony_ci */ 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_cistatic int 207d4afb5ceSopenharmony_cisecstream_connect_munge_ws(lws_ss_handle_t *h, char *buf, size_t len, 208d4afb5ceSopenharmony_ci struct lws_client_connect_info *i, 209d4afb5ceSopenharmony_ci union lws_ss_contemp *ct) 210d4afb5ceSopenharmony_ci{ 211d4afb5ceSopenharmony_ci const char *pbasis = h->policy->u.http.url; 212d4afb5ceSopenharmony_ci size_t used_in, used_out; 213d4afb5ceSopenharmony_ci lws_strexp_t exp; 214d4afb5ceSopenharmony_ci 215d4afb5ceSopenharmony_ci /* i.path on entry is used to override the policy urlpath if not "" */ 216d4afb5ceSopenharmony_ci 217d4afb5ceSopenharmony_ci if (i->path[0]) 218d4afb5ceSopenharmony_ci pbasis = i->path; 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci if (!pbasis) 221d4afb5ceSopenharmony_ci return 0; 222d4afb5ceSopenharmony_ci 223d4afb5ceSopenharmony_ci if (h->policy->flags & LWSSSPOLF_HTTP_CACHE_COOKIES) 224d4afb5ceSopenharmony_ci i->ssl_connection |= LCCSCF_CACHE_COOKIES; 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci if (h->policy->flags & LWSSSPOLF_PRIORITIZE_READS) 227d4afb5ceSopenharmony_ci i->ssl_connection |= LCCSCF_PRIORITIZE_READS; 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci /* protocol aux is the path part ; ws subprotocol name */ 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci i->path = buf; 232d4afb5ceSopenharmony_ci buf[0] = '/'; 233d4afb5ceSopenharmony_ci 234d4afb5ceSopenharmony_ci lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1); 235d4afb5ceSopenharmony_ci 236d4afb5ceSopenharmony_ci if (lws_strexp_expand(&exp, pbasis, strlen(pbasis), 237d4afb5ceSopenharmony_ci &used_in, &used_out) != LSTRX_DONE) 238d4afb5ceSopenharmony_ci return 1; 239d4afb5ceSopenharmony_ci 240d4afb5ceSopenharmony_ci i->protocol = h->policy->u.http.u.ws.subprotocol; 241d4afb5ceSopenharmony_ci 242d4afb5ceSopenharmony_ci lwsl_ss_info(h, "url %s, ws subprotocol %s", buf, i->protocol); 243d4afb5ceSopenharmony_ci 244d4afb5ceSopenharmony_ci return 0; 245d4afb5ceSopenharmony_ci} 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ciconst struct ss_pcols ss_pcol_ws = { 248d4afb5ceSopenharmony_ci "ws", "http/1.1", &protocol_secstream_ws, secstream_connect_munge_ws, 0, 0 249d4afb5ceSopenharmony_ci}; 250