Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"en-US,en;q\u003d0.5", "gen_ut":1638109153, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets", "f":3, "items": [ {"schema":"libjg2-1", "cid":"f668f9fdd8bfad12177934e25dfe1a77", "oid":{ "oid": "44dd63a03dbea8dd22ed00824ae1450e9bffa4ae", "alias": [ "refs/heads/main"]},"blobname": "lib/roles/ws/server-ws.c", "blob": "/*\n * libwebsockets - small server side websockets and web server implementation\n *\n * Copyright (C) 2010 - 2019 Andy Green \u003candy@warmcat.com\u003e\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \u0022Software\u0022), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \u0022AS IS\u0022, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n#include \u003cprivate-lib-core.h\u003e\n\n#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr +\u003d strlen(str); }\n\n#if !defined(LWS_WITHOUT_EXTENSIONS)\nstatic int\nlws_extension_server_handshake(struct lws *wsi, char **p, int budget)\n{\n\tstruct lws_context *context \u003d wsi-\u003ea.context;\n\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n\tchar ext_name[64], *args, *end \u003d (*p) + budget - 1;\n\tconst struct lws_ext_options *opts, *po;\n\tconst struct lws_extension *ext;\n\tstruct lws_ext_option_arg oa;\n\tint n, m, more \u003d 1;\n\tint ext_count \u003d 0;\n\tchar ignore;\n\tchar *c;\n\n\t/*\n\t * Figure out which extensions the client has that we want to\n\t * enable on this connection, and give him back the list\n\t */\n\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS))\n\t\treturn 0;\n\n\t/*\n\t * break down the list of client extensions\n\t * and go through them\n\t */\n\n\tif (lws_hdr_copy(wsi, (char *)pt-\u003eserv_buf, (int)context-\u003ept_serv_buf_size,\n\t\t\t WSI_TOKEN_EXTENSIONS) \u003c 0)\n\t\treturn 1;\n\n\tc \u003d (char *)pt-\u003eserv_buf;\n\tlwsl_parser(\u0022WSI_TOKEN_EXTENSIONS \u003d '%s'\u005cn\u0022, c);\n\twsi-\u003ews-\u003ecount_act_ext \u003d 0;\n\tignore \u003d 0;\n\tn \u003d 0;\n\targs \u003d NULL;\n\n\t/*\n\t * We may get a simple request\n\t *\n\t * Sec-WebSocket-Extensions: permessage-deflate\n\t *\n\t * or an elaborated one with requested options\n\t *\n\t * Sec-WebSocket-Extensions: permessage-deflate; \u005c\n\t *\t\t\t server_no_context_takeover; \u005c\n\t *\t\t\t client_no_context_takeover\n\t */\n\n\twhile (more) {\n\n\t\tif (c \u003e\u003d (char *)pt-\u003eserv_buf + 255)\n\t\t\treturn -1;\n\n\t\tif (*c \u0026\u0026 (*c !\u003d ',' \u0026\u0026 *c !\u003d '\u005ct')) {\n\t\t\tif (*c \u003d\u003d ';') {\n\t\t\t\tignore \u003d 1;\n\t\t\t\tif (!args)\n\t\t\t\t\targs \u003d c + 1;\n\t\t\t}\n\t\t\tif (ignore || *c \u003d\u003d ' ') {\n\t\t\t\tc++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\text_name[n] \u003d *c++;\n\t\t\tif (n \u003c (int)sizeof(ext_name) - 1)\n\t\t\t\tn++;\n\t\t\tcontinue;\n\t\t}\n\t\text_name[n] \u003d '\u005c0';\n\n\t\tignore \u003d 0;\n\t\tif (!*c)\n\t\t\tmore \u003d 0;\n\t\telse {\n\t\t\tc++;\n\t\t\tif (!n)\n\t\t\t\tcontinue;\n\t\t}\n\n\t\twhile (args \u0026\u0026 *args \u003d\u003d ' ')\n\t\t\targs++;\n\n\t\t/* check a client's extension against our support */\n\n\t\text \u003d wsi-\u003ea.vhost-\u003ews.extensions;\n\n\t\twhile (ext \u0026\u0026 ext-\u003ecallback) {\n\n\t\t\tif (strcmp(ext_name, ext-\u003ename)) {\n\t\t\t\text++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * oh, we do support this one he asked for... but let's\n\t\t\t * confirm he only gave it once\n\t\t\t */\n\t\t\tfor (m \u003d 0; m \u003c wsi-\u003ews-\u003ecount_act_ext; m++)\n\t\t\t\tif (wsi-\u003ews-\u003eactive_extensions[m] \u003d\u003d ext) {\n\t\t\t\t\tlwsl_info(\u0022ext mentioned twice\u005cn\u0022);\n\t\t\t\t\treturn 1; /* shenanigans */\n\t\t\t\t}\n\n\t\t\t/*\n\t\t\t * ask user code if it's OK to apply it on this\n\t\t\t * particular connection + protocol\n\t\t\t */\n\t\t\tm \u003d (wsi-\u003ea.protocol-\u003ecallback)(wsi,\n\t\t\t\tLWS_CALLBACK_CONFIRM_EXTENSION_OKAY,\n\t\t\t\twsi-\u003euser_space, ext_name, 0);\n\n\t\t\t/*\n\t\t\t * zero return from callback means go ahead and allow\n\t\t\t * the extension, it's what we get if the callback is\n\t\t\t * unhandled\n\t\t\t */\n\t\t\tif (m) {\n\t\t\t\text++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/* apply it */\n\n\t\t\text_count++;\n\n\t\t\t/* instantiate the extension on this conn */\n\n\t\t\twsi-\u003ews-\u003eactive_extensions[wsi-\u003ews-\u003ecount_act_ext] \u003d ext;\n\n\t\t\t/* allow him to construct his context */\n\n\t\t\tif (ext-\u003ecallback(lws_get_context(wsi), ext, wsi,\n\t\t\t\t\t LWS_EXT_CB_CONSTRUCT,\n\t\t\t\t\t (void *)\u0026wsi-\u003ews-\u003eact_ext_user[\n\t\t\t\t\t wsi-\u003ews-\u003ecount_act_ext],\n\t\t\t\t\t (void *)\u0026opts, 0)) {\n\t\t\t\tlwsl_info(\u0022ext %s failed construction\u005cn\u0022,\n\t\t\t\t\t ext_name);\n\t\t\t\text_count--;\n\t\t\t\text++;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (ext_count \u003e 1)\n\t\t\t\t*(*p)++ \u003d ',';\n\t\t\telse\n\t\t\t\tLWS_CPYAPP(*p,\n\t\t\t\t\t \u0022\u005cx0d\u005cx0aSec-WebSocket-Extensions: \u0022);\n\t\t\t*p +\u003d lws_snprintf(*p, lws_ptr_diff_size_t(end, *p), \u0022%s\u0022, ext_name);\n\n\t\t\t/*\n\t\t\t * The client may send a bunch of different option\n\t\t\t * sets for the same extension, we are supposed to\n\t\t\t * pick one we like the look of. The option sets are\n\t\t\t * separated by comma.\n\t\t\t *\n\t\t\t * Actually we just either accept the first one or\n\t\t\t * nothing.\n\t\t\t *\n\t\t\t * Go through the options trying to apply the\n\t\t\t * recognized ones\n\t\t\t */\n\n\t\t\tlwsl_info(\u0022ext args %s\u005cn\u0022, args);\n\n\t\t\twhile (args \u0026\u0026 *args \u0026\u0026 *args !\u003d ',') {\n\t\t\t\twhile (*args \u003d\u003d ' ')\n\t\t\t\t\targs++;\n\t\t\t\tpo \u003d opts;\n\t\t\t\twhile (po-\u003ename) {\n\t\t\t\t\t/* only support arg-less options... */\n\t\t\t\t\tif (po-\u003etype !\u003d EXTARG_NONE ||\n\t\t\t\t\t strncmp(args, po-\u003ename,\n\t\t\t\t\t\t strlen(po-\u003ename))) {\n\t\t\t\t\t\tpo++;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\toa.option_name \u003d NULL;\n\t\t\t\t\toa.option_index \u003d (int)(po - opts);\n\t\t\t\t\toa.start \u003d NULL;\n\t\t\t\t\toa.len \u003d 0;\n\t\t\t\t\tlwsl_info(\u0022setting '%s'\u005cn\u0022, po-\u003ename);\n\t\t\t\t\tif (!ext-\u003ecallback(lws_get_context(wsi),\n\t\t\t\t\t\t\t ext, wsi,\n\t\t\t\t\t\tLWS_EXT_CB_OPTION_SET,\n\t\t\t\t\t\twsi-\u003ews-\u003eact_ext_user[\n\t\t\t\t\t\t\twsi-\u003ews-\u003ecount_act_ext],\n\t\t\t\t\t\t\t \u0026oa, lws_ptr_diff_size_t(end, *p))) {\n\n\t\t\t\t\t\t*p +\u003d lws_snprintf(*p,\n\t\t\t\t\t\t\t\t lws_ptr_diff_size_t(end, *p),\n\t\t\t\t\t\t\t \u0022; %s\u0022, po-\u003ename);\n\t\t\t\t\t\tlwsl_debug(\u0022adding option %s\u005cn\u0022,\n\t\t\t\t\t\t\t po-\u003ename);\n\t\t\t\t\t}\n\t\t\t\t\tpo++;\n\t\t\t\t}\n\t\t\t\twhile (*args \u0026\u0026 *args !\u003d ',' \u0026\u0026 *args !\u003d ';')\n\t\t\t\t\targs++;\n\n\t\t\t\tif (*args \u003d\u003d ';')\n\t\t\t\t\targs++;\n\t\t\t}\n\n\t\t\twsi-\u003ews-\u003ecount_act_ext++;\n\t\t\tlwsl_parser(\u0022cnt_act_ext \u003c- %d\u005cn\u0022,\n\t\t\t\t wsi-\u003ews-\u003ecount_act_ext);\n\n\t\t\tif (args \u0026\u0026 *args \u003d\u003d ',')\n\t\t\t\tmore \u003d 0;\n\n\t\t\text++;\n\t\t}\n\n\t\tn \u003d 0;\n\t\targs \u003d NULL;\n\t}\n\n\treturn 0;\n}\n#endif\n\nint\nlws_process_ws_upgrade2(struct lws *wsi)\n{\n\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003ea.context-\u003ept[(int)wsi-\u003etsi];\n#if defined(LWS_WITH_HTTP_BASIC_AUTH)\n\tconst struct lws_protocol_vhost_options *pvos \u003d NULL;\n\tconst char *ws_prot_basic_auth \u003d NULL;\n\n\n\t/*\n\t * Allow basic auth a look-in now we bound the wsi to the protocol.\n\t *\n\t * For vhost ws basic auth, it is \u0022basic-auth\u0022: \u0022path\u0022 as usual but\n\t * applied to the protocol's entry in the vhost's \u0022ws-protocols\u0022:\n\t * section, as a pvo.\n\t */\n\n\tpvos \u003d lws_vhost_protocol_options(wsi-\u003ea.vhost, wsi-\u003ea.protocol-\u003ename);\n\tif (pvos \u0026\u0026 pvos-\u003eoptions \u0026\u0026\n\t !lws_pvo_get_str((void *)pvos-\u003eoptions, \u0022basic-auth\u0022,\n\t\t\t \u0026ws_prot_basic_auth)) {\n\t\tlwsl_info(\u0022%s: ws upgrade requires basic auth\u005cn\u0022, __func__);\n\t\tswitch (lws_check_basic_auth(wsi, ws_prot_basic_auth, LWSAUTHM_DEFAULT\n\t\t\t\t\t\t/* no callback based auth here */)) {\n\t\tcase LCBA_CONTINUE:\n\t\t\tbreak;\n\t\tcase LCBA_FAILED_AUTH:\n\t\t\treturn lws_unauthorised_basic_auth(wsi);\n\t\tcase LCBA_END_TRANSACTION:\n\t\t\tlws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);\n\t\t\treturn lws_http_transaction_completed(wsi);\n\t\t}\n\t}\n#endif\n\n\t/*\n\t * We are upgrading to ws, so http/1.1 + h2 and keepalive + pipelined\n\t * header considerations about keeping the ah around no longer apply.\n\t *\n\t * However it's common for the first ws protocol data to have been\n\t * coalesced with the browser upgrade request and to already be in the\n\t * ah rx buffer.\n\t */\n\n\tlws_pt_lock(pt, __func__);\n\n\t/*\n\t * Switch roles if we're upgrading away from http\n\t */\n\n\tif (!wsi-\u003eh2_stream_carries_ws) {\n\t\tlws_role_transition(wsi, LWSIFR_SERVER, LRS_ESTABLISHED,\n\t\t\t\t \u0026role_ops_ws);\n\n#if defined(LWS_WITH_SECURE_STREAMS) \u0026\u0026 defined(LWS_WITH_SERVER)\n\n\t\t/*\n\t\t * If we're a SS server object, we have to switch to ss-ws\n\t\t * protocol handler too\n\t\t */\n\t\tif (wsi-\u003ea.vhost-\u003ess_handle) {\n\t\t\tlwsl_info(\u0022%s: %s switching to ws protocol\u005cn\u0022,\n\t\t\t\t __func__, lws_ss_tag(wsi-\u003ea.vhost-\u003ess_handle));\n\t\t\twsi-\u003ea.protocol \u003d \u0026protocol_secstream_ws;\n\n\t\t\t/*\n\t\t\t * inform the SS user code that this has done a one-way\n\t\t\t * upgrade to some other protocol... it will likely\n\t\t\t * want to treat subsequent payloads differently\n\t\t\t */\n\n\t\t\t(void)lws_ss_event_helper(wsi-\u003ea.vhost-\u003ess_handle,\n\t\t\t\t\t\tLWSSSCS_SERVER_UPGRADE);\n\t\t}\n#endif\n\t}\n\n\tlws_pt_unlock(pt);\n\n\t/* allocate the ws struct for the wsi */\n\n\twsi-\u003ews \u003d lws_zalloc(sizeof(*wsi-\u003ews), \u0022ws struct\u0022);\n\tif (!wsi-\u003ews) {\n\t\tlwsl_notice(\u0022OOM\u005cn\u0022);\n\t\treturn 1;\n\t}\n\n\tif (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))\n\t\twsi-\u003ews-\u003eietf_spec_revision \u003d (uint8_t)\n\t\t\t atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));\n\n\t/* allocate wsi-\u003euser storage */\n\tif (lws_ensure_user_space(wsi)) {\n\t\tlwsl_notice(\u0022problem with user space\u005cn\u0022);\n\t\treturn 1;\n\t}\n\n\t/*\n\t * Give the user code a chance to study the request and\n\t * have the opportunity to deny it\n\t */\n\tif ((wsi-\u003ea.protocol-\u003ecallback)(wsi,\n\t\t\tLWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,\n\t\t\twsi-\u003euser_space,\n\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {\n\t\tlwsl_warn(\u0022User code denied connection\u005cn\u0022);\n\t\treturn 1;\n\t}\n\n\t/*\n\t * Perform the handshake according to the protocol version the\n\t * client announced\n\t */\n\n\tswitch (wsi-\u003ews-\u003eietf_spec_revision) {\n\tdefault:\n\t\tlwsl_notice(\u0022Unknown client spec version %d\u005cn\u0022,\n\t\t\t wsi-\u003ews-\u003eietf_spec_revision);\n\t\twsi-\u003ews-\u003eietf_spec_revision \u003d 13;\n\t\t//return 1;\n\t\t/* fallthru */\n\tcase 13:\n#if defined(LWS_WITH_HTTP2)\n\t\tif (wsi-\u003eh2_stream_carries_ws) {\n\t\t\tif (lws_h2_ws_handshake(wsi)) {\n\t\t\t\tlwsl_notice(\u0022h2 ws handshake failed\u005cn\u0022);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tlws_role_transition(wsi,\n\t\t\t\t\t LWSIFR_SERVER | LWSIFR_P_ENCAP_H2,\n\t\t\t\t\t LRS_ESTABLISHED, \u0026role_ops_ws);\n\n\t\t\t/*\n\t\t\t * There should be no validity checking since we\n\t\t\t * are encapsulated in something else with its own\n\t\t\t * validity checking\n\t\t\t */\n\n\t\t\tlws_sul_cancel(\u0026wsi-\u003esul_validity);\n\t\t} else\n#endif\n\t\t{\n\t\t\tlwsl_parser(\u0022lws_parse calling handshake_04\u005cn\u0022);\n\t\t\tif (handshake_0405(wsi-\u003ea.context, wsi)) {\n\t\t\t\tlwsl_notice(\u0022hs0405 has failed the connection\u005cn\u0022);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t}\n\n\tif (lws_server_init_wsi_for_ws(wsi)) {\n\t\tlwsl_notice(\u0022%s: user ESTABLISHED failed connection\u005cn\u0022, __func__);\n\t\treturn 1;\n\t}\n\tlwsl_parser(\u0022accepted v%02d connection\u005cn\u0022, wsi-\u003ews-\u003eietf_spec_revision);\n\n#if defined(LWS_WITH_ACCESS_LOG)\n\t{\n\t\tchar *uptr \u003d \u0022unknown method\u0022, combo[128], dotstar[64];\n\t\tint l \u003d 14, meth \u003d lws_http_get_uri_and_method(wsi, \u0026uptr, \u0026l);\n\n\t\tif (wsi-\u003eh2_stream_carries_ws)\n\t\t\twsi-\u003ehttp.request_version \u003d HTTP_VERSION_2;\n\n\t\twsi-\u003ehttp.access_log.response \u003d 101;\n\n\t\tlws_strnncpy(dotstar, uptr, l, sizeof(dotstar));\n\t\tl \u003d lws_snprintf(combo, sizeof(combo), \u0022%s (%s)\u0022, dotstar,\n\t\t\t\t wsi-\u003ea.protocol-\u003ename);\n\n\t\tif (meth \u003c 0)\n\t\t\tmeth \u003d 0;\n\t\tlws_prepare_access_log_info(wsi, combo, l, meth);\n\t\tlws_access_log(wsi);\n\t}\n#endif\n\n\tlwsl_info(\u0022%s: %s: dropping ah on ws upgrade\u005cn\u0022, __func__, lws_wsi_tag(wsi));\n\tlws_header_table_detach(wsi, 1);\n\n\treturn 0;\n}\n\nint\nlws_process_ws_upgrade(struct lws *wsi)\n{\n\tconst struct lws_protocols *pcol \u003d NULL;\n\tchar buf[128], name[64];\n\tstruct lws_tokenize ts;\n\tlws_tokenize_elem e;\n\tint n;\n\n\tif (!wsi-\u003ea.protocol)\n\t\tlwsl_err(\u0022NULL protocol at lws_read\u005cn\u0022);\n\n\t/*\n\t * It's either websocket or h2-\u003ewebsocket\n\t *\n\t * If we are on h1, confirm we got the required \u0022connection: upgrade\u0022\n\t * header. h2 / ws-over-h2 does not have this.\n\t */\n\n#if defined(LWS_WITH_HTTP2)\n\tif (!wsi-\u003emux_substream) {\n#endif\n\n\t\tlws_tokenize_init(\u0026ts, buf, LWS_TOKENIZE_F_COMMA_SEP_LIST |\n\t\t\t\t\t LWS_TOKENIZE_F_DOT_NONTERM |\n\t\t\t\t\t LWS_TOKENIZE_F_RFC7230_DELIMS |\n\t\t\t\t\t LWS_TOKENIZE_F_MINUS_NONTERM);\n\t\tn \u003d lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_CONNECTION);\n\t\tif (n \u003c\u003d 0)\n\t\t\tgoto bad_conn_format;\n\t\tts.len \u003d (unsigned int)n;\n\n\t\tdo {\n\t\t\te \u003d lws_tokenize(\u0026ts);\n\t\t\tswitch (e) {\n\t\t\tcase LWS_TOKZE_TOKEN:\n\t\t\t\tif (!strncasecmp(ts.token, \u0022upgrade\u0022, ts.token_len))\n\t\t\t\t\te \u003d LWS_TOKZE_ENDED;\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_TOKZE_DELIMITER:\n\t\t\t\tbreak;\n\n\t\t\tdefault: /* includes ENDED */\n\tbad_conn_format:\n\t\t\t\tlwsl_err(\u0022%s: malformed or absent conn hdr\u005cn\u0022,\n\t\t\t\t\t __func__);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t} while (e \u003e 0);\n\n#if defined(LWS_WITH_HTTP2)\n\t}\n#endif\n\n#if defined(LWS_WITH_HTTP_PROXY)\n\t{\n\t\tconst struct lws_http_mount *hit;\n\t\tint uri_len \u003d 0, meth;\n\t\tchar *uri_ptr;\n\n\t\tmeth \u003d lws_http_get_uri_and_method(wsi, \u0026uri_ptr, \u0026uri_len);\n\t\thit \u003d lws_find_mount(wsi, uri_ptr, uri_len);\n\n\t\tif (hit \u0026\u0026 (meth \u003d\u003d LWSHUMETH_GET ||\n\t\t\t meth \u003d\u003d LWSHUMETH_CONNECT ||\n\t\t\t meth \u003d\u003d LWSHUMETH_COLON_PATH) \u0026\u0026\n\t\t (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTPS ||\n\t\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTP))\n\t\t\t/*\n\t\t\t * We are an h1 ws upgrade on a urlpath that corresponds\n\t\t\t * to a proxying mount. Don't try to deal with it\n\t\t\t * locally, eg, we won't even have the right protocol\n\t\t\t * handler since we're not the guy handling it, just a\n\t\t\t * conduit.\n\t\t\t *\n\t\t\t * Instead open the related ongoing h1 connection\n\t\t\t * according to the mount configuration and proxy\n\t\t\t * whatever that has to say from now on.\n\t\t\t */\n\t\t\treturn lws_http_proxy_start(wsi, hit, uri_ptr, 1);\n\t}\n#endif\n\n\t/*\n\t * Select the first protocol we support from the list\n\t * the client sent us.\n\t */\n\n\tlws_tokenize_init(\u0026ts, buf, LWS_TOKENIZE_F_COMMA_SEP_LIST |\n\t\t\t\t LWS_TOKENIZE_F_MINUS_NONTERM |\n\t\t\t\t LWS_TOKENIZE_F_DOT_NONTERM |\n\t\t\t\t LWS_TOKENIZE_F_RFC7230_DELIMS);\n\tn \u003d lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_PROTOCOL);\n\tif (n \u003c 0) {\n\t\tlwsl_err(\u0022%s: protocol list too long\u005cn\u0022, __func__);\n\t\treturn 1;\n\t}\n\tts.len \u003d (unsigned int)n;\n\tif (!ts.len) {\n\t\tint n \u003d wsi-\u003ea.vhost-\u003edefault_protocol_index;\n\t\t/*\n\t\t * Some clients only have one protocol and do not send the\n\t\t * protocol list header... allow it and match to the vhost's\n\t\t * default protocol (which itself defaults to zero).\n\t\t *\n\t\t * Setting the vhost default protocol index to -1 or anything\n\t\t * more than the actual number of protocols on the vhost causes\n\t\t * these \u0022no protocol\u0022 ws connections to be rejected.\n\t\t */\n\n\t\tif (n \u003e\u003d wsi-\u003ea.vhost-\u003ecount_protocols) {\n\t\t\tlwsl_notice(\u0022%s: rejecting ws upg with no protocol\u005cn\u0022,\n\t\t\t\t __func__);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tlwsl_info(\u0022%s: defaulting to prot handler %d\u005cn\u0022, __func__, n);\n\n\t\tlws_bind_protocol(wsi, \u0026wsi-\u003ea.vhost-\u003eprotocols[n],\n\t\t\t\t \u0022ws upgrade default pcol\u0022);\n\n\t\tgoto alloc_ws;\n\t}\n\n#if defined(LWS_WITH_SECURE_STREAMS) \u0026\u0026 defined(LWS_WITH_SERVER)\n\tif (wsi-\u003ea.vhost-\u003ess_handle) {\n\t\tlws_ss_handle_t *sssh \u003d wsi-\u003ea.vhost-\u003ess_handle;\n\n\t\t/*\n\t\t * At the moment, once we see it's a ss ws server, whatever\n\t\t * he asked for we bind him to the ss-ws protocol handler.\n\t\t *\n\t\t * In the response subprotocol header, we need to name\n\t\t *\n\t\t * sssh-\u003epolicy-\u003eu.http.u.ws.subprotocol\n\t\t *\n\t\t * though...\n\t\t */\n\n\t\tif (sssh-\u003epolicy-\u003eu.http.u.ws.subprotocol) {\n\t\t\tpcol \u003d lws_vhost_name_to_protocol(wsi-\u003ea.vhost,\n\t\t\t\t\t\t\t \u0022lws-secstream-ws\u0022);\n\t\t\tif (pcol) {\n\t\t\t\tlws_bind_protocol(wsi, pcol, \u0022ss ws upg pcol\u0022);\n\n\t\t\t\tgoto alloc_ws;\n\t\t\t}\n\t\t}\n\t}\n#endif\n\n\t/* otherwise go through the user-provided protocol list */\n\n\tdo {\n\t\te \u003d lws_tokenize(\u0026ts);\n\t\tswitch (e) {\n\t\tcase LWS_TOKZE_TOKEN:\n\n\t\t\tif (lws_tokenize_cstr(\u0026ts, name, sizeof(name))) {\n\t\t\t\tlwsl_err(\u0022%s: pcol name too long\u005cn\u0022, __func__);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tlwsl_debug(\u0022checking %s\u005cn\u0022, name);\n\t\t\tpcol \u003d lws_vhost_name_to_protocol(wsi-\u003ea.vhost, name);\n\t\t\tif (pcol) {\n\t\t\t\t/* if we know it, bind to it and stop looking */\n\t\t\t\tlws_bind_protocol(wsi, pcol, \u0022ws upg pcol\u0022);\n\t\t\t\te \u003d LWS_TOKZE_ENDED;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase LWS_TOKZE_DELIMITER:\n\t\tcase LWS_TOKZE_ENDED:\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tlwsl_err(\u0022%s: malformatted protocol list\u0022, __func__);\n\n\t\t\treturn 1;\n\t\t}\n\t} while (e \u003e 0);\n\n\t/* we didn't find a protocol he wanted? */\n\n\tif (!pcol) {\n\t\tlwsl_notice(\u0022No supported protocol \u005c\u0022%s\u005c\u0022\u005cn\u0022, buf);\n\n\t\treturn 1;\n\t}\n\nalloc_ws:\n\n\treturn lws_process_ws_upgrade2(wsi);\n}\n\nint\nhandshake_0405(struct lws_context *context, struct lws *wsi)\n{\n\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n\tstruct lws_process_html_args args;\n\tunsigned char hash[20];\n\tint n, accept_len;\n\tchar *response;\n\tchar *p;\n\n\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST) ||\n\t !lws_hdr_total_length(wsi, WSI_TOKEN_KEY)) {\n\t\tlwsl_info(\u0022handshake_04 missing pieces\u005cn\u0022);\n\t\t/* completed header processing, but missing some bits */\n\t\tgoto bail;\n\t}\n\n\tif (lws_hdr_total_length(wsi, WSI_TOKEN_KEY) \u003e\u003d\n\t MAX_WEBSOCKET_04_KEY_LEN) {\n\t\tlwsl_warn(\u0022Client key too long %d\u005cn\u0022, MAX_WEBSOCKET_04_KEY_LEN);\n\t\tgoto bail;\n\t}\n\n\t/*\n\t * since key length is restricted above (currently 128), cannot\n\t * overflow\n\t */\n\tn \u003d sprintf((char *)pt-\u003eserv_buf,\n\t\t \u0022%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11\u0022,\n\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY));\n\n\tlws_SHA1(pt-\u003eserv_buf, (unsigned int)n, hash);\n\n\taccept_len \u003d lws_b64_encode_string((char *)hash, 20,\n\t\t\t(char *)pt-\u003eserv_buf, (int)context-\u003ept_serv_buf_size);\n\tif (accept_len \u003c 0) {\n\t\tlwsl_warn(\u0022Base64 encoded hash too long\u005cn\u0022);\n\t\tgoto bail;\n\t}\n\n\t/* allocate the per-connection user memory (if any) */\n\tif (lws_ensure_user_space(wsi))\n\t\tgoto bail;\n\n\t/* create the response packet */\n\n\t/* make a buffer big enough for everything */\n\n\tresponse \u003d (char *)pt-\u003eserv_buf + MAX_WEBSOCKET_04_KEY_LEN +\n\t\t 256 + LWS_PRE;\n\tp \u003d response;\n\tLWS_CPYAPP(p, \u0022HTTP/1.1 101 Switching Protocols\u005cx0d\u005cx0a\u0022\n\t\t \u0022Upgrade: WebSocket\u005cx0d\u005cx0a\u0022\n\t\t \u0022Connection: Upgrade\u005cx0d\u005cx0a\u0022\n\t\t \u0022Sec-WebSocket-Accept: \u0022);\n\tstrcpy(p, (char *)pt-\u003eserv_buf);\n\tp +\u003d accept_len;\n\n\t/* we can only return the protocol header if:\n\t * - one came in, and ... */\n\tif (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) \u0026\u0026\n\t /* - it is not an empty string */\n\t wsi-\u003ea.protocol-\u003ename \u0026\u0026\n\t wsi-\u003ea.protocol-\u003ename[0]) {\n\t\tconst char *prot \u003d wsi-\u003ea.protocol-\u003ename;\n\n#if defined(LWS_WITH_HTTP_PROXY)\n\t\tif (wsi-\u003eproxied_ws_parent \u0026\u0026 wsi-\u003echild_list)\n\t\t\tprot \u003d wsi-\u003echild_list-\u003ews-\u003eactual_protocol;\n#endif\n\n#if defined(LWS_WITH_SECURE_STREAMS) \u0026\u0026 defined(LWS_WITH_SERVER)\n\t\t{\n\t\t\tlws_ss_handle_t *sssh \u003d wsi-\u003ea.vhost-\u003ess_handle;\n\n\t\t\t/*\n\t\t\t * At the moment, once we see it's a ss ws server, whatever\n\t\t\t * he asked for we bind him to the ss-ws protocol handler.\n\t\t\t *\n\t\t\t * In the response subprotocol header, we need to name\n\t\t\t *\n\t\t\t * sssh-\u003epolicy-\u003eu.http.u.ws.subprotocol\n\t\t\t *\n\t\t\t * though...\n\t\t\t */\n\n\t\t\tif (sssh \u0026\u0026 sssh-\u003epolicy \u0026\u0026\n\t\t\t sssh-\u003epolicy-\u003eu.http.u.ws.subprotocol)\n\t\t\t\tprot \u003d sssh-\u003epolicy-\u003eu.http.u.ws.subprotocol;\n\t\t}\n#endif\n\n\t\tLWS_CPYAPP(p, \u0022\u005cx0d\u005cx0aSec-WebSocket-Protocol: \u0022);\n\t\tp +\u003d lws_snprintf(p, 128, \u0022%s\u0022, prot);\n\t}\n\n#if !defined(LWS_WITHOUT_EXTENSIONS)\n\t/*\n\t * Figure out which extensions the client has that we want to\n\t * enable on this connection, and give him back the list.\n\t *\n\t * Give him a limited write bugdet\n\t */\n\tif (lws_extension_server_handshake(wsi, \u0026p, 192))\n\t\tgoto bail;\n#endif\n\tLWS_CPYAPP(p, \u0022\u005cx0d\u005cx0a\u0022);\n\n\targs.p \u003d p;\n\targs.max_len \u003d lws_ptr_diff((char *)pt-\u003eserv_buf +\n\t\t\t\t context-\u003ept_serv_buf_size, p);\n\tif (user_callback_handle_rxflow(wsi-\u003ea.protocol-\u003ecallback, wsi,\n\t\t\t\t\tLWS_CALLBACK_ADD_HEADERS,\n\t\t\t\t\twsi-\u003euser_space, \u0026args, 0))\n\t\tgoto bail;\n\n\tp \u003d args.p;\n\n\t/* end of response packet */\n\n\tLWS_CPYAPP(p, \u0022\u005cx0d\u005cx0a\u0022);\n\n\t/* okay send the handshake response accepting the connection */\n\n\tlwsl_parser(\u0022issuing resp pkt %d len\u005cn\u0022,\n\t\t lws_ptr_diff(p, response));\n#if defined(DEBUG)\n\tfwrite(response, 1, p - response, stderr);\n#endif\n\tn \u003d lws_write(wsi, (unsigned char *)response, lws_ptr_diff_size_t(p, response),\n\t\t LWS_WRITE_HTTP_HEADERS);\n\tif (n !\u003d lws_ptr_diff(p, response)) {\n\t\tlwsl_info(\u0022%s: ERROR writing to socket %d\u005cn\u0022, __func__, n);\n\t\tgoto bail;\n\t}\n\n\t/* alright clean up and set ourselves into established state */\n\n\tlwsi_set_state(wsi, LRS_ESTABLISHED);\n\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n\n\t{\n\t\tconst char * uri_ptr \u003d\n\t\t\tlws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);\n\t\tint uri_len \u003d lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);\n\t\tconst struct lws_http_mount *hit \u003d\n\t\t\tlws_find_mount(wsi, uri_ptr, uri_len);\n\t\tif (hit \u0026\u0026 hit-\u003ecgienv \u0026\u0026\n\t\t wsi-\u003ea.protocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP_PMO,\n\t\t\twsi-\u003euser_space, (void *)hit-\u003ecgienv, 0))\n\t\t\treturn 1;\n\t}\n\n\treturn 0;\n\nbail:\n\t/* caller will free up his parsing allocations */\n\treturn -1;\n}\n\n\n\n/*\n * Once we reach LWS_RXPS_WS_FRAME_PAYLOAD, we know how much\n * to expect in that state and can deal with it in bulk more efficiently.\n */\n\nstatic int\nlws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)\n{\n\tstruct lws_ext_pm_deflate_rx_ebufs pmdrx;\n\tunsigned int avail \u003d (unsigned int)len;\n\tuint8_t *buffer \u003d *buf, mask[4];\n#if !defined(LWS_WITHOUT_EXTENSIONS)\n\tunsigned int old_packet_length \u003d (unsigned int)wsi-\u003ews-\u003erx_packet_length;\n#endif\n\tint n \u003d 0;\n\n\t/*\n\t * With zlib, we can give it as much input as we like. The pmd\n\t * extension will draw it down in chunks (default 1024).\n\t *\n\t * If we try to restrict how much we give it, because we must go\n\t * back to the event loop each time, we will drop the remainder...\n\t */\n\n#if !defined(LWS_WITHOUT_EXTENSIONS)\n\tif (!wsi-\u003ews-\u003ecount_act_ext)\n#endif\n\t{\n\t\tif (wsi-\u003ea.protocol-\u003erx_buffer_size)\n\t\t\tavail \u003d (unsigned int)wsi-\u003ea.protocol-\u003erx_buffer_size;\n\t\telse\n\t\t\tavail \u003d wsi-\u003ea.context-\u003ept_serv_buf_size;\n\t}\n\n\t/* do not consume more than we should */\n\tif (avail \u003e wsi-\u003ews-\u003erx_packet_length)\n\t\tavail \u003d (unsigned int)wsi-\u003ews-\u003erx_packet_length;\n\n\t/* do not consume more than what is in the buffer */\n\tif (avail \u003e len)\n\t\tavail \u003d (unsigned int)len;\n\n\tif (!avail)\n\t\treturn 0;\n\n\tpmdrx.eb_in.token \u003d buffer;\n\tpmdrx.eb_in.len \u003d (int)avail;\n\tpmdrx.eb_out.token \u003d buffer;\n\tpmdrx.eb_out.len \u003d (int)avail;\n\n\tif (!wsi-\u003ews-\u003eall_zero_nonce) {\n\n\t\tfor (n \u003d 0; n \u003c 4; n++)\n\t\t\tmask[n] \u003d wsi-\u003ews-\u003emask[(wsi-\u003ews-\u003emask_idx + n) \u0026 3];\n\n\t\t/* deal with 4-byte chunks using unwrapped loop */\n\t\tn \u003d (int)(avail \u003e\u003e 2);\n\t\twhile (n--) {\n\t\t\t*(buffer) \u003d *(buffer) ^ mask[0];\n\t\t\tbuffer++;\n\t\t\t*(buffer) \u003d *(buffer) ^ mask[1];\n\t\t\tbuffer++;\n\t\t\t*(buffer) \u003d *(buffer) ^ mask[2];\n\t\t\tbuffer++;\n\t\t\t*(buffer) \u003d *(buffer) ^ mask[3];\n\t\t\tbuffer++;\n\t\t}\n\t\t/* and the remaining bytes bytewise */\n\t\tfor (n \u003d 0; n \u003c (int)(avail \u0026 3); n++) {\n\t\t\t*(buffer) \u003d *(buffer) ^ mask[n];\n\t\t\tbuffer++;\n\t\t}\n\n\t\twsi-\u003ews-\u003emask_idx \u003d (wsi-\u003ews-\u003emask_idx + avail) \u0026 3;\n\t}\n\n\tlwsl_info(\u0022%s: using %d of raw input (total %d on offer)\u005cn\u0022, __func__,\n\t\t avail, (int)len);\n\n\t(*buf) +\u003d avail;\n\tlen -\u003d avail;\n\twsi-\u003ews-\u003erx_packet_length -\u003d avail;\n\n#if !defined(LWS_WITHOUT_EXTENSIONS)\n\tn \u003d lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, \u0026pmdrx, 0);\n\tlwsl_info(\u0022%s: ext says %d / ebuf_out.len %d\u005cn\u0022, __func__, n,\n\t\t\tpmdrx.eb_out.len);\n\n\t/*\n\t * ebuf may be pointing somewhere completely different now,\n\t * it's the output\n\t */\n\n\tif (n \u003c 0) {\n\t\t/*\n\t\t * we may rely on this to get RX, just drop connection\n\t\t */\n\t\tlwsl_notice(\u0022%s: LWS_EXT_CB_PAYLOAD_RX blew out\u005cn\u0022, __func__);\n\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n\n\t\treturn -1;\n\t}\n\n\t/*\n\t * if we had an rx fragment right at the last compressed byte of the\n\t * message, we can get a zero length inflated output, where no prior\n\t * rx inflated output marked themselves with FIN, since there was\n\t * raw ws payload still to drain at that time.\n\t *\n\t * Then we need to generate a zero length ws rx that can be understood\n\t * as the message completion.\n\t */\n\n\tif (!pmdrx.eb_out.len \u0026\u0026\t /* zero-length inflation output */\n\t n \u003d\u003d PMDR_EMPTY_FINAL \u0026\u0026 /* nothing to drain from the inflator */\n\t old_packet_length \u0026\u0026\t /* we gave the inflator new input */\n\t !wsi-\u003ews-\u003erx_packet_length \u0026\u0026 /* raw ws packet payload all gone */\n\t wsi-\u003ews-\u003efinal \u0026\u0026\t\t /* the raw ws packet is a FIN guy */\n\t wsi-\u003ea.protocol-\u003ecallback \u0026\u0026\n\t !wsi-\u003ewsistate_pre_close) {\n\n\t\tlwsl_ext(\u0022%s: issuing zero length FIN pkt\u005cn\u0022, __func__);\n\n\t\tif (user_callback_handle_rxflow(wsi-\u003ea.protocol-\u003ecallback, wsi,\n\t\t\t\t\t\tLWS_CALLBACK_RECEIVE,\n\t\t\t\t\t\twsi-\u003euser_space, NULL, 0))\n\t\t\treturn -1;\n\n\t\treturn (int)avail;\n\t}\n\n\t/*\n\t * If doing permessage-deflate, above was the only way to get a zero\n\t * length receive. Otherwise we're more willing.\n\t */\n\tif (wsi-\u003ews-\u003ecount_act_ext \u0026\u0026 !pmdrx.eb_out.len)\n\t\treturn (int)avail;\n\n\tif (n \u003d\u003d PMDR_HAS_PENDING)\n\t\t/* extension had more... main loop will come back */\n\t\tlws_add_wsi_to_draining_ext_list(wsi);\n\telse\n\t\tlws_remove_wsi_from_draining_ext_list(wsi);\n#endif\n\n\tif (pmdrx.eb_out.len \u0026\u0026\n\t wsi-\u003ews-\u003echeck_utf8 \u0026\u0026 !wsi-\u003ews-\u003edefeat_check_utf8) {\n\t\tif (lws_check_utf8(\u0026wsi-\u003ews-\u003eutf8,\n\t\t\t\t pmdrx.eb_out.token,\n\t\t\t\t (unsigned int)pmdrx.eb_out.len)) {\n\t\t\tlws_close_reason(wsi, LWS_CLOSE_STATUS_INVALID_PAYLOAD,\n\t\t\t\t\t (uint8_t *)\u0022bad utf8\u0022, 8);\n\t\t\tgoto utf8_fail;\n\t\t}\n\n\t\t/* we are ending partway through utf-8 character? */\n\t\tif (!wsi-\u003ews-\u003erx_packet_length \u0026\u0026 wsi-\u003ews-\u003efinal \u0026\u0026\n\t\t wsi-\u003ews-\u003eutf8 \u0026\u0026 !n) {\n\t\t\tlwsl_info(\u0022FINAL utf8 error\u005cn\u0022);\n\t\t\tlws_close_reason(wsi, LWS_CLOSE_STATUS_INVALID_PAYLOAD,\n\t\t\t\t\t (uint8_t *)\u0022partial utf8\u0022, 12);\n\nutf8_fail:\n\t\t\tlwsl_info(\u0022utf8 error\u005cn\u0022);\n\t\t\tlwsl_hexdump_info(pmdrx.eb_out.token, (size_t)pmdrx.eb_out.len);\n\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\tif (wsi-\u003ea.protocol-\u003ecallback \u0026\u0026 !wsi-\u003ewsistate_pre_close)\n\t\tif (user_callback_handle_rxflow(wsi-\u003ea.protocol-\u003ecallback, wsi,\n\t\t\t\t\t\tLWS_CALLBACK_RECEIVE,\n\t\t\t\t\t\twsi-\u003euser_space,\n\t\t\t\t\t\tpmdrx.eb_out.token,\n\t\t\t\t\t\t(unsigned int)pmdrx.eb_out.len))\n\t\t\treturn -1;\n\n\twsi-\u003ews-\u003efirst_fragment \u003d 0;\n\n#if !defined(LWS_WITHOUT_EXTENSIONS)\n\tlwsl_info(\u0022%s: input used %d, output %d, rem len %d, rx_draining_ext %d\u005cn\u0022,\n\t\t __func__, avail, pmdrx.eb_out.len, (int)len,\n\t\t wsi-\u003ews-\u003erx_draining_ext);\n#endif\n\n\treturn (int)avail; /* how much we used from the input */\n}\n\n\nint\nlws_parse_ws(struct lws *wsi, unsigned char **buf, size_t len)\n{\n\tunsigned char *bufin \u003d *buf;\n\tint m, bulk \u003d 0;\n\n\tlwsl_debug(\u0022%s: received %d byte packet\u005cn\u0022, __func__, (int)len);\n\n\t//lwsl_hexdump_notice(*buf, len);\n\n\t/* let the rx protocol state machine have as much as it needs */\n\n\twhile (len) {\n\t\t/*\n\t\t * we were accepting input but now we stopped doing so\n\t\t */\n\t\tif (wsi-\u003erxflow_bitmap) {\n\t\t\tlwsl_info(\u0022%s: doing rxflow, caching %d\u005cn\u0022, __func__,\n\t\t\t\t(int)len);\n\t\t\t/*\n\t\t\t * Since we cached the remaining available input, we\n\t\t\t * can say we \u0022consumed\u0022 it.\n\t\t\t *\n\t\t\t * But what about the case where the available input\n\t\t\t * came out of the rxflow cache already? If we are\n\t\t\t * effectively \u0022putting it back in the cache\u0022, we have\n\t\t\t * leave it where it is, already pointed to by the head.\n\t\t\t */\n\t\t\tif (lws_rxflow_cache(wsi, *buf, 0, len) \u003d\u003d\n\t\t\t\t\t\t\tLWSRXFC_TRIMMED) {\n\t\t\t\t/*\n\t\t\t\t * We dealt with it by trimming the existing\n\t\t\t\t * rxflow cache HEAD to account for what we used.\n\t\t\t\t *\n\t\t\t\t * so he doesn't do any consumed processing\n\t\t\t\t */\n\t\t\t\tlwsl_info(\u0022%s: trimming inside rxflow cache\u005cn\u0022,\n\t\t\t\t\t __func__);\n\t\t\t\t*buf \u003d bufin;\n\t\t\t} else\n\t\t\t\t*buf +\u003d len;\n\n\t\t\treturn 1;\n\t\t}\n#if !defined(LWS_WITHOUT_EXTENSIONS)\n\t\tif (wsi-\u003ews-\u003erx_draining_ext) {\n\t\t\tlwsl_debug(\u0022%s: draining rx ext\u005cn\u0022, __func__);\n\t\t\tm \u003d lws_ws_rx_sm(wsi, ALREADY_PROCESSED_IGNORE_CHAR, 0);\n\t\t\tif (m \u003c 0)\n\t\t\t\treturn -1;\n\t\t\tcontinue;\n\t\t}\n#endif\n\n\t\t/* consume payload bytes efficiently */\n\t\twhile (wsi-\u003elws_rx_parse_state \u003d\u003d LWS_RXPS_WS_FRAME_PAYLOAD \u0026\u0026\n\t\t\t\t(wsi-\u003ews-\u003eopcode \u003d\u003d LWSWSOPC_TEXT_FRAME ||\n\t\t\t\t wsi-\u003ews-\u003eopcode \u003d\u003d LWSWSOPC_BINARY_FRAME ||\n\t\t\t\t wsi-\u003ews-\u003eopcode \u003d\u003d LWSWSOPC_CONTINUATION) \u0026\u0026\n\t\t len) {\n\t\t\tuint8_t *bin \u003d *buf;\n\n\t\t\tbulk \u003d 1;\n\t\t\tm \u003d lws_ws_frame_rest_is_payload(wsi, buf, len);\n\t\t\tassert((int)lws_ptr_diff(*buf, bin) \u003c\u003d (int)len);\n\t\t\tlen -\u003d lws_ptr_diff_size_t(*buf, bin);\n\n\t\t\tif (!m) {\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (m \u003c 0) {\n\t\t\t\tlwsl_info(\u0022%s: rest_is_payload bailed\u005cn\u0022,\n\t\t\t\t\t __func__);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\n\t\tif (!bulk) {\n\t\t\t/* process the byte */\n\t\t\tm \u003d lws_ws_rx_sm(wsi, 0, *(*buf)++);\n\t\t\tlen--;\n\t\t} else {\n\t\t\t/*\n\t\t\t * We already handled this byte in bulk, just deal\n\t\t\t * with the ramifications\n\t\t\t */\n#if !defined(LWS_WITHOUT_EXTENSIONS)\n\t\t\tlwsl_debug(\u0022%s: coming out of bulk with len %d, \u0022\n\t\t\t\t \u0022wsi-\u003ews-\u003erx_draining_ext %d\u005cn\u0022,\n\t\t\t\t __func__, (int)len,\n\t\t\t\t wsi-\u003ews-\u003erx_draining_ext);\n#endif\n\t\t\tm \u003d lws_ws_rx_sm(wsi, ALREADY_PROCESSED_IGNORE_CHAR |\n\t\t\t\t\t ALREADY_PROCESSED_NO_CB, 0);\n\t\t}\n\n\t\tif (m \u003c 0) {\n\t\t\tlwsl_info(\u0022%s: lws_ws_rx_sm bailed %d\u005cn\u0022, __func__,\n\t\t\t\t bulk);\n\n\t\t\treturn -1;\n\t\t}\n\n\t\tbulk \u003d 0;\n\t}\n\n\tlwsl_debug(\u0022%s: exit with %d unused\u005cn\u0022, __func__, (int)len);\n\n\treturn 0;\n}\n","s":{"c":1638109153,"u": 1135}} ],"g": 9918,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 1, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}