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