{"schema":"libjg2-1",
"vpath":"/git/",
"avatar":"/git/avatar/",
"alang":"",
"gen_ut":1745914215,
"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":"5ae0b5590374f9ad89b556fed2b9e772",
"commit": {"type":"commit",
"time": 1508146117,
"time_ofs": 480,
"oid_tree": { "oid": "454ea5734f53b1e899eb34372901762a837da0ae", "alias": []},
"oid":{ "oid": "c83afc66e69937b989ab285d71949ac9f7bab61a", "alias": []},
"msg": "refactor: subdirs for source in lib",
"sig_commit": { "git_time": { "time": 1508146117, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },
"sig_author": { "git_time": { "time": 1508129552, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" }},
"body": "refactor: subdirs for source in lib\n\nSplit out some optional code into own sources to\nshrink down libwebsockets.c and server.c a bit"
,
"diff": "diff --git a/CMakeLists.txt b/CMakeLists.txt\nindex 89372d9..b44449f 100644\n--- a/CMakeLists.txt\n+++ b/CMakeLists.txt\n@@ -250,7 +250,7 @@ set(LWS_OPENSSL_LIBRARIES CACHE PATH \u0022Path to the OpenSSL library\u0022)\n set(LWS_OPENSSL_INCLUDE_DIRS CACHE PATH \u0022Path to the OpenSSL include directory\u0022)\n set(LWS_WOLFSSL_LIBRARIES CACHE PATH \u0022Path to the wolfSSL library\u0022)\n set(LWS_WOLFSSL_INCLUDE_DIRS CACHE PATH \u0022Path to the wolfSSL include directory\u0022)\n-set( CACHE PATH \u0022Path to the libev library\u0022)\n+set(LWS_LIBEV_LIBRARIES CACHE PATH \u0022Path to the libev library\u0022)\n set(LWS_LIBEV_INCLUDE_DIRS CACHE PATH \u0022Path to the libev include directory\u0022)\n set(LWS_LIBUV_LIBRARIES CACHE PATH \u0022Path to the libuv library\u0022)\n set(LWS_LIBUV_INCLUDE_DIRS CACHE PATH \u0022Path to the libuv include directory\u0022)\n@@ -610,22 +610,38 @@ set(HDR_PUBLIC\n \t)\n \n set(SOURCES\n-\tlib/base64-decode.c\n+\tlib/misc/base64-decode.c\n \tlib/handshake.c\n \tlib/libwebsockets.c\n \tlib/service.c\n \tlib/pollfd.c\n \tlib/output.c\n-\tlib/parsers.c\n+\tlib/server/parsers.c\n \tlib/context.c\n \tlib/alloc.c\n-\tlib/header.c)\n+\tlib/header.c\n+\tlib/misc/lws-ring.c)\n+\n+if (LWS_WITH_CGI)\n+\tlist(APPEND SOURCES\n+\t\tlib/server/cgi.c)\n+endif()\n+\n+if (LWS_WITH_ACCESS_LOG)\n+\tlist(APPEND SOURCES\n+\t\tlib/server/access-log.c)\n+endif()\n+\n+if (LWS_WITH_PEER_LIMITS)\n+\tlist(APPEND SOURCES\n+\t\tlib/server/peer-limits.c)\n+endif()\n \n if (NOT LWS_WITHOUT_CLIENT)\n \tlist(APPEND SOURCES\n-\t\tlib/client.c\n-\t\tlib/client-handshake.c\n-\t\tlib/client-parser.c)\n+\t\tlib/client/client.c\n+\t\tlib/client/client-handshake.c\n+\t\tlib/client/client-parser.c)\n endif()\n \n if (LWS_WITH_MBEDTLS)\n@@ -673,51 +689,51 @@ endif()\n if (LWS_WITH_SSL)\n \tlist(APPEND SOURCES\n \t\tlib/ssl.c\n-\t\tlib/lws-genhash.c)\n+\t\tlib/misc/lws-genhash.c)\n \t\t\n \tif (NOT LWS_WITHOUT_SERVER)\n \t\tlist(APPEND SOURCES\n-\t\tlib/ssl-server.c)\n+\t\tlib/server/ssl-server.c)\n \tendif()\n \tif (NOT LWS_WITHOUT_CLIENT)\n \t\tlist(APPEND SOURCES\n-\t\tlib/ssl-client.c)\n+\t\tlib/client/ssl-client.c)\n \tendif()\n endif()\n \n if (NOT LWS_WITHOUT_BUILTIN_SHA1)\n \tlist(APPEND SOURCES\n-\t\tlib/sha-1.c)\n+\t\tlib/misc/sha-1.c)\n endif()\n \n if (LWS_WITH_HTTP2)\n \tlist(APPEND SOURCES\n-\t\tlib/http2.c\n-\t\tlib/hpack.c\n-\t\tlib/ssl-http2.c)\n+\t\tlib/http2/http2.c\n+\t\tlib/http2/hpack.c\n+\t\tlib/http2/ssl-http2.c)\n endif()\n # select the active platform files\n \n if (WIN32)\n \tlist(APPEND SOURCES\n-\t\tlib/lws-plat-win.c)\n+\t\tlib/plat/lws-plat-win.c)\n else()\n \n \tif (LWS_WITH_ESP8266)\n \t\tlist(APPEND SOURCES\n-\t\t\tlib/lws-plat-esp8266.c)\n+\t\t\tlib/plat/lws-plat-esp8266.c)\n \telse()\n \t\tif (LWS_PLAT_OPTEE)\n \t\t\tlist(APPEND SOURCES\n-\t\t\t\tlib/lws-plat-optee.c)\n+\t\t\t\tlib/plat/lws-plat-optee.c)\n \t\telse()\n \t\t\tif (LWS_WITH_ESP32)\n \t\t\t\tlist(APPEND SOURCES\n-\t\t\t\t\tlib/lws-plat-esp32.c\n-\t\t\t\t\tlib/romfs.c)\n+\t\t\t\t\tlib/plat/lws-plat-esp32.c\n+\t\t\t\t\tlib/misc/romfs.c)\n \t\t\telse()\n \t\t\t\tlist(APPEND SOURCES\n-\t\t\t\t\tlib/lws-plat-unix.c)\n+\t\t\t\t\tlib/plat/lws-plat-unix.c)\n \t\t\tendif()\n \t\tendif()\n \tendif()\n@@ -725,64 +741,65 @@ endif()\n \n if (NOT LWS_WITHOUT_SERVER)\n \tlist(APPEND SOURCES\n-\t\tlib/server.c\n-\t\tlib/server-handshake.c)\n+\t\tlib/server/server.c\n+\t\tlib/server/lws-spa.c\n+\t\tlib/server/server-handshake.c)\n endif()\n \n if (NOT LWS_WITHOUT_EXTENSIONS)\n \tlist(APPEND HDR_PRIVATE\n-\t\tlib/extension-permessage-deflate.h)\n+\t\tlib/ext/extension-permessage-deflate.h)\n \tlist(APPEND SOURCES\n-\t\tlib/extension.c\n-\t\tlib/extension-permessage-deflate.c)\n+\t\tlib/ext/extension.c\n+\t\tlib/ext/extension-permessage-deflate.c)\n endif()\n \n if (LWS_WITH_HTTP_PROXY)\n \tlist(APPEND SOURCES\n-\t\tlib/rewrite.c)\n+\t\tlib/server/rewrite.c)\n endif()\n \n if (LWS_WITH_LIBEV)\n \tlist(APPEND SOURCES\n-\t\tlib/libev.c)\n+\t\tlib/event-libs/libev.c)\n endif()\n \n if (LWS_WITH_LIBUV)\n \tlist(APPEND SOURCES\n-\t\tlib/libuv.c)\n+\t\tlib/event-libs/libuv.c)\n endif()\n \n if (LWS_WITH_LIBEVENT)\n \tlist(APPEND SOURCES\n-\t\tlib/libevent.c)\n+\t\tlib/event-libs/libevent.c)\n endif()\n \n if (LWS_WITH_LEJP)\n \tlist(APPEND SOURCES\n-\t\tlib/lejp.c)\n+\t\tlib/misc/lejp.c)\n \tlist(APPEND HDR_PUBLIC\n-\t\tlib/lejp.h)\n+\t\tlib/misc/lejp.h)\n endif()\t\n if (LWS_WITH_LEJP_CONF)\n \t\tlist(APPEND SOURCES\n-\t\t\t\u0022lib/lejp-conf.c\u0022\n+\t\t\t\u0022lib/server/lejp-conf.c\u0022\n \t\t)\n endif()\n \n if (LWS_WITH_SMTP)\n \tlist(APPEND SOURCES\n-\t\tlib/smtp.c)\n+\t\tlib/misc/smtp.c)\n endif()\n \n if (LWS_WITH_RANGES)\n \tlist(APPEND SOURCES\n-\t\tlib/ranges.c)\n+\t\tlib/server/ranges.c)\n endif()\n \n if (LWS_WITH_ZIP_FOPS)\n if (LWS_WITH_ZLIB)\n list(APPEND SOURCES\n- lib/fops-zip.c)\n+ lib/server/fops-zip.c)\n else()\n message(FATAL_ERROR \u0022Pre-zipped file support (LWS_WITH_ZIP_FOPS) requires ZLIB (LWS_WITH_ZLIB)\u0022)\n endif()\n@@ -807,14 +824,14 @@ else()\n \t# Unix.\n \tif (NOT LWS_WITHOUT_DAEMONIZE)\n \t\tlist(APPEND SOURCES\n-\t\t\tlib/daemonize.c)\n+\t\t\tlib/server/daemonize.c)\n \tendif()\n endif()\n \n if (UNIX)\n \tif (NOT LWS_HAVE_GETIFADDRS)\n-\t\tlist(APPEND HDR_PRIVATE lib/getifaddrs.h)\n-\t\tlist(APPEND SOURCES lib/getifaddrs.c)\n+\t\tlist(APPEND HDR_PRIVATE lib/misc/getifaddrs.h)\n+\t\tlist(APPEND SOURCES lib/misc/getifaddrs.c)\n \tendif()\n endif()\n \ndiff --git a/READMEs/README.coding.md b/READMEs/README.coding.md\nindex 7e934ba..18bdaf8 100644\n--- a/READMEs/README.coding.md\n+++ b/READMEs/README.coding.md\n@@ -4,20 +4,81 @@ Notes about coding with lws\n @section era Old lws and lws v2.0\n \n Originally lws only supported the \u0022manual\u0022 method of handling everything in the\n-user callback found in test-server.c.\n+user callback found in test-server.c / test-server-http.c.\n \n-Since v2.0, the need for most or all of this manual boilerplate has been eliminated:\n-the protocols[0] http stuff is provided by a lib export `lws_callback_http_dummy()`.\n-You can serve parts of your filesystem at part of the URL space using mounts.\n+Since v2.0, the need for most or all of this manual boilerplate has been\n+eliminated: the protocols[0] http stuff is provided by a generic lib export\n+`lws_callback_http_dummy()`. You can serve parts of your filesystem at part of\n+the URL space using mounts, the dummy http callback will do the right thing.\n \n It's much preferred to use the \u0022automated\u0022 v2.0 type scheme, because it's less\n code and it's easier to support.\n \n You can see an example of the new way in test-server-v2.0.c.\n \n-If you just need generic serving capability, consider not writing any server code\n-and instead use lwsws and writing your user code in a standalone plugin. The\n-server is configured for mounts etc using JSON, see README.lwsws.md.\n+If you just need generic serving capability, without the need to integrate lws\n+to some other app, consider not writing any server code at all, and instead use\n+the generic server `lwsws`, and writing your special user code in a standalone\n+\u0022plugin\u0022. The server is configured for mounts etc using JSON, see\n+./READMEs/README.lwsws.md.\n+\n+Although the \u0022plugins\u0022 are dynamically loaded if you use lwsws or lws built\n+with libuv, actually they may perfectly well be statically included if that\n+suits your situation better, eg, ESP32 test server, where the platform does\n+not support processes or dynamic loading, just #includes the plugins\n+one after the other and gets the same benefit from the same code.\n+\n+Isolating and collating the protocol code in one place also makes it very easy\n+to maintain and understand.\n+\n+So it if highly recommended you put your protocol-specific code into the\n+form of a \u0022plugin\u0022 at the source level, even if you have no immediate plan to\n+use it dynamically-loaded.\n+\n+@section writeable Only send data when socket writeable\n+\n+You should only send data on a websocket connection from the user callback\n+`LWS_CALLBACK_SERVER_WRITEABLE` (or `LWS_CALLBACK_CLIENT_WRITEABLE` for\n+clients).\n+\n+If you want to send something, do NOT just send it but request a callback\n+when the socket is writeable using\n+\n+ - `lws_callback_on_writable(context, wsi)` for a specific `wsi`, or\n+ \n+ - `lws_callback_on_writable_all_protocol(protocol)` for all connections\n+using that protocol to get a callback when next writeable.\n+\n+Usually you will get called back immediately next time around the service\n+loop, but if your peer is slow or temporarily inactive the callback will be\n+delayed accordingly. Generating what to write and sending it should be done\n+in the ...WRITEABLE callback.\n+\n+See the test server code for an example of how to do this.\n+\n+Otherwise evolved libs like libuv get this wrong, they will allow you to \u0022send\u0022\n+anything you want but it only uses up your local memory (and costs you\n+memcpys) until the socket can actually accept it. It is much better to regulate\n+your send action by the downstream peer readiness to take new data in the first\n+place, avoiding all the wasted buffering.\n+\n+Libwebsockets' concept is that the downstream peer is truly the boss, if he,\n+or our connection to him, cannot handle anything new, we should not generate\n+anything new for him. This is how unix shell piping works, you may have\n+`cat a.txt | grep xyz \u003e remote\u0022, but actually that does not cat anything from\n+a.txt while remote cannot accept anything new. \n+\n+@section otherwr Do not rely on only your own WRITEABLE requests appearing\n+\n+Libwebsockets may generate additional `LWS_CALLBACK_CLIENT_WRITEABLE` events\n+if it met network conditions where it had to buffer your send data internally.\n+\n+So your code for `LWS_CALLBACK_CLIENT_WRITEABLE` needs to own the decision\n+about what to send, it can't assume that just because the writeable callback\n+came it really is time to send something.\n+\n+It's quite possible you get an 'extra' writeable callback at any time and\n+just need to `return 0` and wait for the expected callback later.\n \n @section dae Daemonization\n \n@@ -28,8 +89,7 @@ headless background process and exit the starting process.\n \n Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your\n daemon is headless, so you'll need to sort out alternative logging, by, eg,\n-syslog.\n-\n+syslog via `lws_set_log_level(..., lwsl_emit_syslog)`.\n \n @section conns Maximum number of connections\n \n@@ -81,7 +141,9 @@ repeat that in other words:\n There is another network-programming truism that surprises some people which\n is if the sink for the data cannot accept more:\n \n-***YOU MUST PERFORM RX FLOW CONTROL***\n+***YOU MUST PERFORM RX FLOW CONTROL*** to stop taking new input. TCP will make\n+this situation known to the upstream sender by making it impossible for him to\n+send anything more on the connection until we start accepting things again.\n \n See the mirror protocol implementations for example code.\n \n@@ -99,42 +161,6 @@ you might simultaneously create more than one context from different threads.\n SSL_library_init() is called from the context create api and it also is not\n reentrant. So at least create the contexts sequentially.\n \n-\n-@section writeable Only send data when socket writeable\n-\n-You should only send data on a websocket connection from the user callback\n-`LWS_CALLBACK_SERVER_WRITEABLE` (or `LWS_CALLBACK_CLIENT_WRITEABLE` for\n-clients).\n-\n-If you want to send something, do not just send it but request a callback\n-when the socket is writeable using\n-\n- - `lws_callback_on_writable(context, wsi)` for a specific `wsi`, or\n- \n- - `lws_callback_on_writable_all_protocol(protocol)` for all connections\n-using that protocol to get a callback when next writeable.\n-\n-Usually you will get called back immediately next time around the service\n-loop, but if your peer is slow or temporarily inactive the callback will be\n-delayed accordingly. Generating what to write and sending it should be done\n-in the ...WRITEABLE callback.\n-\n-See the test server code for an example of how to do this.\n-\n-\n-@section otherwr Do not rely on only your own WRITEABLE requests appearing\n-\n-Libwebsockets may generate additional `LWS_CALLBACK_CLIENT_WRITEABLE` events\n-if it met network conditions where it had to buffer your send data internally.\n-\n-So your code for `LWS_CALLBACK_CLIENT_WRITEABLE` needs to own the decision\n-about what to send, it can't assume that just because the writeable callback\n-came it really is time to send something.\n-\n-It's quite possible you get an 'extra' writeable callback at any time and\n-just need to `return 0` and wait for the expected callback later.\n-\n-\n @section closing Closing connections from the user side\n \n When you want to close a connection, you do it by returning `-1` from a\ndiff --git a/lib/.gitignore b/lib/.gitignore\ndeleted file mode 100644\nindex dbed3ff..0000000\n--- a/lib/.gitignore\n+++ /dev/null\n@@ -1,8 +0,0 @@\n-#Ignore build files\n-Makefile\n-*.o\n-*.lo\n-*.la\n-.libs\n-.deps\n-\ndiff --git a/lib/base64-decode.c b/lib/base64-decode.c\ndeleted file mode 100644\nindex c8f11d2..0000000\n--- a/lib/base64-decode.c\n+++ /dev/null\n@@ -1,206 +0,0 @@\n-/*\n- * This code originally came from here\n- *\n- * http://base64.sourceforge.net/b64.c\n- *\n- * with the following license:\n- *\n- * LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.\n- *\n- * Permission is hereby granted, free of charge, to any person\n- * obtaining a copy of this software and associated\n- * documentation files (the \u0022Software\u0022), to deal in the\n- * Software without restriction, including without limitation\n- * the rights to use, copy, modify, merge, publish, distribute,\n- * sublicense, and/or sell copies of the Software, and to\n- * permit persons to whom the Software is furnished to do so,\n- * subject to the following conditions:\n- *\n- * The above copyright notice and this permission notice shall\n- * be included in all copies or substantial portions of the\n- * Software.\n- *\n- * THE SOFTWARE IS PROVIDED \u0022AS IS\u0022, WITHOUT WARRANTY OF ANY\n- * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n- * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n- * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n- *\n- * VERSION HISTORY:\n- * Bob Trower 08/04/01 -- Create Version 0.00.00B\n- *\n- * I cleaned it up quite a bit to match the (linux kernel) style of the rest\n- * of libwebsockets; this version is under LGPL2.1 + SLE like the rest of lws\n- * since he explicitly allows sublicensing, but I give the URL above so you can\n- * get the original with Bob's super-liberal terms directly if you prefer.\n- */\n-\n-#include \u003cstdio.h\u003e\n-#include \u003cstring.h\u003e\n-#include \u0022private-libwebsockets.h\u0022\n-\n-static const char encode[] \u003d \u0022ABCDEFGHIJKLMNOPQRSTUVWXYZ\u0022\n-\t\t\t \u0022abcdefghijklmnopqrstuvwxyz0123456789+/\u0022;\n-static const char decode[] \u003d \u0022|$$$}rstuvwxyz{$$$$$$$\u003e?@ABCDEFGHIJKLMNOPQRSTUVW\u0022\n-\t\t\t \u0022$$$$$$XYZ[\u005c\u005c]^_`abcdefghijklmnopq\u0022;\n-\n-LWS_VISIBLE int\n-lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)\n-{\n-\tunsigned char triple[3];\n-\tint i;\n-\tint len;\n-\tint line \u003d 0;\n-\tint done \u003d 0;\n-\n-\twhile (in_len) {\n-\t\tlen \u003d 0;\n-\t\tfor (i \u003d 0; i \u003c 3; i++) {\n-\t\t\tif (in_len) {\n-\t\t\t\ttriple[i] \u003d *in++;\n-\t\t\t\tlen++;\n-\t\t\t\tin_len--;\n-\t\t\t} else\n-\t\t\t\ttriple[i] \u003d 0;\n-\t\t}\n-\n-\t\tif (done + 4 \u003e\u003d out_size)\n-\t\t\treturn -1;\n-\n-\t\t*out++ \u003d encode[triple[0] \u003e\u003e 2];\n-\t\t*out++ \u003d encode[((triple[0] \u0026 0x03) \u003c\u003c 4) |\n-\t\t\t\t\t ((triple[1] \u0026 0xf0) \u003e\u003e 4)];\n-\t\t*out++ \u003d (len \u003e 1 ? encode[((triple[1] \u0026 0x0f) \u003c\u003c 2) |\n-\t\t\t\t\t ((triple[2] \u0026 0xc0) \u003e\u003e 6)] : '\u003d');\n-\t\t*out++ \u003d (len \u003e 2 ? encode[triple[2] \u0026 0x3f] : '\u003d');\n-\n-\t\tdone +\u003d 4;\n-\t\tline +\u003d 4;\n-\t}\n-\n-\tif (done + 1 \u003e\u003d out_size)\n-\t\treturn -1;\n-\n-\t*out++ \u003d '\u005c0';\n-\n-\treturn done;\n-}\n-\n-/*\n- * returns length of decoded string in out, or -1 if out was too small\n- * according to out_size\n- */\n-\n-LWS_VISIBLE int\n-lws_b64_decode_string(const char *in, char *out, int out_size)\n-{\n-\tint len, i, c \u003d 0, done \u003d 0;\n-\tunsigned char v, quad[4];\n-\n-\twhile (*in) {\n-\n-\t\tlen \u003d 0;\n-\t\tfor (i \u003d 0; i \u003c 4 \u0026\u0026 *in; i++) {\n-\n-\t\t\tv \u003d 0;\n-\t\t\tc \u003d 0;\n-\t\t\twhile (*in \u0026\u0026 !v) {\n-\t\t\t\tc \u003d v \u003d *in++;\n-\t\t\t\tv \u003d (v \u003c 43 || v \u003e 122) ? 0 : decode[v - 43];\n-\t\t\t\tif (v)\n-\t\t\t\t\tv \u003d (v \u003d\u003d '$') ? 0 : v - 61;\n-\t\t\t}\n-\t\t\tif (c) {\n-\t\t\t\tlen++;\n-\t\t\t\tif (v)\n-\t\t\t\t\tquad[i] \u003d v - 1;\n-\t\t\t} else\n-\t\t\t\tquad[i] \u003d 0;\n-\t\t}\n-\n-\t\tif (out_size \u003c (done + len - 1))\n-\t\t\t/* out buffer is too small */\n-\t\t\treturn -1;\n-\n-\t\t/*\n-\t\t * \u0022The '\u003d\u003d' sequence indicates that the last group contained\n-\t\t * only one byte, and '\u003d' indicates that it contained two\n-\t\t * bytes.\u0022 (wikipedia)\n-\t\t */\n-\n-\t\tif (!*in \u0026\u0026 c \u003d\u003d '\u003d')\n-\t\t\tlen--;\n-\n-\t\tif (len \u003e\u003d 2)\n-\t\t\t*out++ \u003d quad[0] \u003c\u003c 2 | quad[1] \u003e\u003e 4;\n-\t\tif (len \u003e\u003d 3)\n-\t\t\t*out++ \u003d quad[1] \u003c\u003c 4 | quad[2] \u003e\u003e 2;\n-\t\tif (len \u003e\u003d 4)\n-\t\t\t*out++ \u003d ((quad[2] \u003c\u003c 6) \u0026 0xc0) | quad[3];\n-\n-\t\tdone +\u003d len - 1;\n-\t}\n-\n-\tif (done + 1 \u003e\u003d out_size)\n-\t\treturn -1;\n-\n-\t*out \u003d '\u005c0';\n-\n-\treturn done;\n-}\n-\n-#if 0\n-int\n-lws_b64_selftest(void)\n-{\n-\tchar buf[64];\n-\tunsigned int n, r \u003d 0;\n-\tunsigned int test;\n-\t/* examples from https://en.wikipedia.org/wiki/Base64 */\n-\tstatic const char * const plaintext[] \u003d {\n-\t\t\u0022any carnal pleasure.\u0022,\n-\t\t\u0022any carnal pleasure\u0022,\n-\t\t\u0022any carnal pleasur\u0022,\n-\t\t\u0022any carnal pleasu\u0022,\n-\t\t\u0022any carnal pleas\u0022,\n-\t\t\u0022Admin:kloikloi\u0022\n-\t};\n-\tstatic const char * const coded[] \u003d {\n-\t\t\u0022YW55IGNhcm5hbCBwbGVhc3VyZS4\u003d\u0022,\n-\t\t\u0022YW55IGNhcm5hbCBwbGVhc3VyZQ\u003d\u003d\u0022,\n-\t\t\u0022YW55IGNhcm5hbCBwbGVhc3Vy\u0022,\n-\t\t\u0022YW55IGNhcm5hbCBwbGVhc3U\u003d\u0022,\n-\t\t\u0022YW55IGNhcm5hbCBwbGVhcw\u003d\u003d\u0022,\n-\t\t\u0022QWRtaW46a2xvaWtsb2k\u003d\u0022\n-\t};\n-\n-\tfor (test \u003d 0; test \u003c sizeof plaintext / sizeof(plaintext[0]); test++) {\n-\n-\t\tbuf[sizeof(buf) - 1] \u003d '\u005c0';\n-\t\tn \u003d lws_b64_encode_string(plaintext[test],\n-\t\t\t\t strlen(plaintext[test]), buf, sizeof buf);\n-\t\tif (n !\u003d strlen(coded[test]) || strcmp(buf, coded[test])) {\n-\t\t\tlwsl_err(\u0022Failed lws_b64 encode selftest \u0022\n-\t\t\t\t\t \u0022%d result '%s' %d\u005cn\u0022, test, buf, n);\n-\t\t\tr \u003d -1;\n-\t\t}\n-\n-\t\tbuf[sizeof(buf) - 1] \u003d '\u005c0';\n-\t\tn \u003d lws_b64_decode_string(coded[test], buf, sizeof buf);\n-\t\tif (n !\u003d strlen(plaintext[test]) ||\n-\t\t\t\t\t\t strcmp(buf, plaintext[test])) {\n-\t\t\tlwsl_err(\u0022Failed lws_b64 decode selftest \u0022\n-\t\t\t\t \u0022%d result '%s' / '%s', %d / %d\u005cn\u0022,\n-\t\t\t\t test, buf, plaintext[test], n, strlen(plaintext[test]));\n-\t\t\tr \u003d -1;\n-\t\t}\n-\t}\n-\n-\tlwsl_notice(\u0022Base 64 selftests passed\u005cn\u0022);\n-\n-\treturn r;\n-}\n-#endif\ndiff --git a/lib/client-handshake.c b/lib/client-handshake.c\ndeleted file mode 100644\nindex c2720d9..0000000\n--- a/lib/client-handshake.c\n+++ /dev/null\n@@ -1,1051 +0,0 @@\n-#include \u0022private-libwebsockets.h\u0022\n-\n-static int\n-lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)\n-{\n-\tstruct addrinfo hints;\n-\n-\tmemset(\u0026hints, 0, sizeof(hints));\n-\t*result \u003d NULL;\n-\n-#ifdef LWS_WITH_IPV6\n-\tif (wsi-\u003eipv6) {\n-\n-#if !defined(__ANDROID__)\n-\t\thints.ai_family \u003d AF_INET6;\n-\t\thints.ai_flags \u003d AI_V4MAPPED;\n-#endif\n-\t} else\n-#endif\n-\t{\n-\t\thints.ai_family \u003d PF_UNSPEC;\n-\t\thints.ai_socktype \u003d SOCK_STREAM;\n-\t\thints.ai_flags \u003d AI_CANONNAME;\n-\t}\n-\n-\treturn getaddrinfo(ads, NULL, \u0026hints, result);\n-}\n-\n-struct lws *\n-lws_client_connect_2(struct lws *wsi)\n-{\n-\tsockaddr46 sa46;\n-\tstruct addrinfo *result;\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tstruct lws_pollfd pfd;\n-\tconst char *cce \u003d \u0022\u0022, *iface;\n-\tint n, port;\n-\tssize_t plen \u003d 0;\n-\tconst char *ads;\n-#ifdef LWS_WITH_IPV6\n-\tchar ipv6only \u003d lws_check_opt(wsi-\u003evhost-\u003eoptions,\n-\t\t\tLWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |\n-\t\t\tLWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);\n-\n-#if defined(__ANDROID__)\n-\tipv6only \u003d 0;\n-#endif\n-#endif\n-\n-\tlwsl_client(\u0022%s\u005cn\u0022, __func__);\n-\n-\tif (!wsi-\u003eu.hdr.ah) {\n-\t\tcce \u003d \u0022ah was NULL at cc2\u0022;\n-\t\tlwsl_err(\u0022%s\u005cn\u0022, cce);\n-\t\tgoto oom4;\n-\t}\n-\n-\t/*\n-\t * start off allowing ipv6 on connection if vhost allows it\n-\t */\n-\twsi-\u003eipv6 \u003d LWS_IPV6_ENABLED(wsi-\u003evhost);\n-\n-\t/* Decide what it is we need to connect to:\n-\t *\n-\t * Priority 1: connect to http proxy */\n-\n-\tif (wsi-\u003evhost-\u003ehttp_proxy_port) {\n-\t\tplen \u003d sprintf((char *)pt-\u003eserv_buf,\n-\t\t\t\u0022CONNECT %s:%u HTTP/1.0\u005cx0d\u005cx0a\u0022\n-\t\t\t\u0022User-agent: libwebsockets\u005cx0d\u005cx0a\u0022,\n-\t\t\tlws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),\n-\t\t\twsi-\u003ec_port);\n-\n-\t\tif (wsi-\u003evhost-\u003eproxy_basic_auth_token[0])\n-\t\t\tplen +\u003d sprintf((char *)pt-\u003eserv_buf + plen,\n-\t\t\t\t\t\u0022Proxy-authorization: basic %s\u005cx0d\u005cx0a\u0022,\n-\t\t\t\t\twsi-\u003evhost-\u003eproxy_basic_auth_token);\n-\n-\t\tplen +\u003d sprintf((char *)pt-\u003eserv_buf + plen, \u0022\u005cx0d\u005cx0a\u0022);\n-\t\tads \u003d wsi-\u003evhost-\u003ehttp_proxy_address;\n-\t\tport \u003d wsi-\u003evhost-\u003ehttp_proxy_port;\n-\n-#if defined(LWS_WITH_SOCKS5)\n-\n-\t/* Priority 2: Connect to SOCK5 Proxy */\n-\n-\t} else if (wsi-\u003evhost-\u003esocks_proxy_port) {\n-\t\tsocks_generate_msg(wsi, SOCKS_MSG_GREETING, \u0026plen);\n-\t\tlwsl_client(\u0022Sending SOCKS Greeting\u005cn\u0022);\n-\t\tads \u003d wsi-\u003evhost-\u003esocks_proxy_address;\n-\t\tport \u003d wsi-\u003evhost-\u003esocks_proxy_port;\n-#endif\n-\t} else {\n-\n-\t\t/* Priority 3: Connect directly */\n-\n-\t\tads \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);\n-\t\tport \u003d wsi-\u003ec_port;\n-\t}\n-\n-\t/*\n-\t * prepare the actual connection\n-\t * to whatever we decided to connect to\n-\t */\n-\n- lwsl_notice(\u0022%s: %p: address %s\u005cn\u0022, __func__, wsi, ads);\n-\n- n \u003d lws_getaddrinfo46(wsi, ads, \u0026result);\n-\n-#ifdef LWS_WITH_IPV6\n-\tif (wsi-\u003eipv6) {\n-\n-\t\tif (n) {\n-\t\t\t/* lws_getaddrinfo46 failed, there is no usable result */\n-\t\t\tlwsl_notice(\u0022%s: lws_getaddrinfo46 failed %d\u005cn\u0022,\n-\t\t\t\t\t__func__, n);\n-\t\t\tcce \u003d \u0022ipv6 lws_getaddrinfo46 failed\u0022;\n-\t\t\tgoto oom4;\n-\t\t}\n-\n-\t\tmemset(\u0026sa46, 0, sizeof(sa46));\n-\n-\t\tsa46.sa6.sin6_family \u003d AF_INET6;\n-\t\tswitch (result-\u003eai_family) {\n-\t\tcase AF_INET:\n-\t\t\tif (ipv6only)\n-\t\t\t\tbreak;\n-\t\t\t/* map IPv4 to IPv6 */\n-\t\t\tbzero((char *)\u0026sa46.sa6.sin6_addr,\n-\t\t\t\t\t\tsizeof(sa46.sa6.sin6_addr));\n-\t\t\tsa46.sa6.sin6_addr.s6_addr[10] \u003d 0xff;\n-\t\t\tsa46.sa6.sin6_addr.s6_addr[11] \u003d 0xff;\n-\t\t\tmemcpy(\u0026sa46.sa6.sin6_addr.s6_addr[12],\n-\t\t\t\t\u0026((struct sockaddr_in *)result-\u003eai_addr)-\u003esin_addr,\n-\t\t\t\t\t\t\tsizeof(struct in_addr));\n-\t\t\tlwsl_notice(\u0022uplevelling AF_INET to AF_INET6\u005cn\u0022);\n-\t\t\tbreak;\n-\n-\t\tcase AF_INET6:\n-\t\t\tmemcpy(\u0026sa46.sa6.sin6_addr,\n-\t\t\t \u0026((struct sockaddr_in6 *)result-\u003eai_addr)-\u003esin6_addr,\n-\t\t\t\t\t\tsizeof(struct in6_addr));\n-\t\t\tsa46.sa6.sin6_scope_id \u003d ((struct sockaddr_in6 *)result-\u003eai_addr)-\u003esin6_scope_id;\n-\t\t\tsa46.sa6.sin6_flowinfo \u003d ((struct sockaddr_in6 *)result-\u003eai_addr)-\u003esin6_flowinfo;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tlwsl_err(\u0022Unknown address family\u005cn\u0022);\n-\t\t\tfreeaddrinfo(result);\n-\t\t\tcce \u003d \u0022unknown address family\u0022;\n-\t\t\tgoto oom4;\n-\t\t}\n-\t} else\n-#endif /* use ipv6 */\n-\n-\t/* use ipv4 */\n-\t{\n-\t\tvoid *p \u003d NULL;\n-\n-\t\tif (!n) {\n-\t\t\tstruct addrinfo *res \u003d result;\n-\n-\t\t\t/* pick the first AF_INET (IPv4) result */\n-\n-\t\t\twhile (!p \u0026\u0026 res) {\n-\t\t\t\tswitch (res-\u003eai_family) {\n-\t\t\t\tcase AF_INET:\n-\t\t\t\t\tp \u003d \u0026((struct sockaddr_in *)res-\u003eai_addr)-\u003esin_addr;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\n-\t\t\t\tres \u003d res-\u003eai_next;\n-\t\t\t}\n-#if defined(LWS_FALLBACK_GETHOSTBYNAME)\n-\t\t} else if (n \u003d\u003d EAI_SYSTEM) {\n-\t\t\tstruct hostent *host;\n-\n-\t\t\tlwsl_info(\u0022getaddrinfo (ipv4) failed, trying gethostbyname\u005cn\u0022);\n-\t\t\thost \u003d gethostbyname(ads);\n-\t\t\tif (host) {\n-\t\t\t\tp \u003d host-\u003eh_addr;\n-\t\t\t} else {\n-\t\t\t\tlwsl_err(\u0022gethostbyname failed\u005cn\u0022);\n-\t\t\t\tcce \u003d \u0022gethostbyname (ipv4) failed\u0022;\n-\t\t\t\tgoto oom4;\n-\t\t\t}\n-#endif\n-\t\t} else {\n-\t\t\tlwsl_err(\u0022getaddrinfo failed\u005cn\u0022);\n-\t\t\tcce \u003d \u0022getaddrinfo failed\u0022;\n-\t\t\tgoto oom4;\n-\t\t}\n-\n-\t\tif (!p) {\n-\t\t\tif (result)\n-\t\t\t\tfreeaddrinfo(result);\n-\t\t\tlwsl_err(\u0022Couldn't identify address\u005cn\u0022);\n-\t\t\tcce \u003d \u0022unable to lookup address\u0022;\n-\t\t\tgoto oom4;\n-\t\t}\n-\n-\t\tsa46.sa4.sin_family \u003d AF_INET;\n-\t\tsa46.sa4.sin_addr \u003d *((struct in_addr *)p);\n-\t\tbzero(\u0026sa46.sa4.sin_zero, 8);\n-\t}\n-\n-\tif (result)\n-\t\tfreeaddrinfo(result);\n-\n-\t/* now we decided on ipv4 or ipv6, set the port */\n-\n-\tif (!lws_socket_is_valid(wsi-\u003edesc.sockfd)) {\n-\n-#if defined(LWS_WITH_LIBUV)\n-\t\tif (LWS_LIBUV_ENABLED(context))\n-\t\t\tif (lws_libuv_check_watcher_active(wsi)) {\n-\t\t\t\tlwsl_warn(\u0022Waiting for libuv watcher to close\u005cn\u0022);\n-\t\t\t\tcce \u003d \u0022waiting for libuv watcher to close\u0022;\n-\t\t\t\tgoto oom4;\n-\t\t\t}\n-#endif\n-\n-#ifdef LWS_WITH_IPV6\n-\t\tif (wsi-\u003eipv6)\n-\t\t\twsi-\u003edesc.sockfd \u003d socket(AF_INET6, SOCK_STREAM, 0);\n-\t\telse\n-#endif\n-\t\t\twsi-\u003edesc.sockfd \u003d socket(AF_INET, SOCK_STREAM, 0);\n-\n-\t\tif (!lws_socket_is_valid(wsi-\u003edesc.sockfd)) {\n-\t\t\tlwsl_warn(\u0022Unable to open socket\u005cn\u0022);\n-\t\t\tcce \u003d \u0022unable to open socket\u0022;\n-\t\t\tgoto oom4;\n-\t\t}\n-\n-\t\tif (lws_plat_set_socket_options(wsi-\u003evhost, wsi-\u003edesc.sockfd)) {\n-\t\t\tlwsl_err(\u0022Failed to set wsi socket options\u005cn\u0022);\n-\t\t\tcompatible_close(wsi-\u003edesc.sockfd);\n-\t\t\tcce \u003d \u0022set socket opts failed\u0022;\n-\t\t\tgoto oom4;\n-\t\t}\n-\n-\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_CONNECT;\n-\n-\t\tlws_libev_accept(wsi, wsi-\u003edesc);\n-\t\tlws_libuv_accept(wsi, wsi-\u003edesc);\n-\t\tlws_libevent_accept(wsi, wsi-\u003edesc);\n-\n-\t\tif (insert_wsi_socket_into_fds(context, wsi)) {\n-\t\t\tcompatible_close(wsi-\u003edesc.sockfd);\n-\t\t\tcce \u003d \u0022insert wsi failed\u0022;\n-\t\t\tgoto oom4;\n-\t\t}\n-\n-\t\tlws_change_pollfd(wsi, 0, LWS_POLLIN);\n-\n-\t\t/*\n-\t\t * past here, we can't simply free the structs as error\n-\t\t * handling as oom4 does. We have to run the whole close flow.\n-\t\t */\n-\n-\t\tif (!wsi-\u003eprotocol)\n-\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[0];\n-\n-\t\twsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_WSI_CREATE,\n-\t\t\t\t\twsi-\u003euser_space, NULL, 0);\n-\n-\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,\n-\t\t\t\tAWAITING_TIMEOUT);\n-\n-\t\tiface \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);\n-\n-\t\tif (iface) {\n-\t\t\tn \u003d lws_socket_bind(wsi-\u003evhost, wsi-\u003edesc.sockfd, 0, iface);\n-\t\t\tif (n \u003c 0) {\n-\t\t\t\tcce \u003d \u0022unable to bind socket\u0022;\n-\t\t\t\tgoto failed;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-#ifdef LWS_WITH_IPV6\n-\tif (wsi-\u003eipv6) {\n-\t\tsa46.sa6.sin6_port \u003d htons(port);\n-\t\tn \u003d sizeof(struct sockaddr_in6);\n-\t} else\n-#endif\n-\t{\n-\t\tsa46.sa4.sin_port \u003d htons(port);\n-\t\tn \u003d sizeof(struct sockaddr);\n-\t}\n-\n-\tif (connect(wsi-\u003edesc.sockfd, (const struct sockaddr *)\u0026sa46, n) \u003d\u003d -1 ||\n-\t LWS_ERRNO \u003d\u003d LWS_EISCONN) {\n-\t\tif (LWS_ERRNO \u003d\u003d LWS_EALREADY ||\n-\t\t LWS_ERRNO \u003d\u003d LWS_EINPROGRESS ||\n-\t\t LWS_ERRNO \u003d\u003d LWS_EWOULDBLOCK\n-#ifdef _WIN32\n-\t\t\t|| LWS_ERRNO \u003d\u003d WSAEINVAL\n-#endif\n-\t\t) {\n-\t\t\tlwsl_client(\u0022nonblocking connect retry (errno \u003d %d)\u005cn\u0022,\n-\t\t\t\t LWS_ERRNO);\n-\n-\t\t\tif (lws_plat_check_connection_error(wsi)) {\n-\t\t\t\tcce \u003d \u0022socket connect failed\u0022;\n-\t\t\t\tgoto failed;\n-\t\t\t}\n-\n-\t\t\t/*\n-\t\t\t * must do specifically a POLLOUT poll to hear\n-\t\t\t * about the connect completion\n-\t\t\t */\n-\t\t\tif (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {\n-\t\t\t\tcce \u003d \u0022POLLOUT set failed\u0022;\n-\t\t\t\tgoto failed;\n-\t\t\t}\n-\n-\t\t\treturn wsi;\n-\t\t}\n-\n-\t\tif (LWS_ERRNO !\u003d LWS_EISCONN) {\n-\t\t\tlwsl_notice(\u0022Connect failed errno\u003d%d\u005cn\u0022, LWS_ERRNO);\n-\t\t\tcce \u003d \u0022connect failed\u0022;\n-\t\t\tgoto failed;\n-\t\t}\n-\t}\n-\n-\tlwsl_client(\u0022connected\u005cn\u0022);\n-\n-\t/* we are connected to server, or proxy */\n-\n-\t/* http proxy */\n-\tif (wsi-\u003evhost-\u003ehttp_proxy_port) {\n-\n-\t\t/*\n-\t\t * OK from now on we talk via the proxy, so connect to that\n-\t\t *\n-\t\t * (will overwrite existing pointer,\n-\t\t * leaving old string/frag there but unreferenced)\n-\t\t */\n-\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,\n-\t\t\t\t\t wsi-\u003evhost-\u003ehttp_proxy_address))\n-\t\t\tgoto failed;\n-\t\twsi-\u003ec_port \u003d wsi-\u003evhost-\u003ehttp_proxy_port;\n-\n-\t\tn \u003d send(wsi-\u003edesc.sockfd, (char *)pt-\u003eserv_buf, plen,\n-\t\t\t MSG_NOSIGNAL);\n-\t\tif (n \u003c 0) {\n-\t\t\tlwsl_debug(\u0022ERROR writing to proxy socket\u005cn\u0022);\n-\t\t\tcce \u003d \u0022proxy write failed\u0022;\n-\t\t\tgoto failed;\n-\t\t}\n-\n-\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,\n-\t\t\t\tAWAITING_TIMEOUT);\n-\n-\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_PROXY_REPLY;\n-\n-\t\treturn wsi;\n-\t}\n-#if defined(LWS_WITH_SOCKS5)\n-\t/* socks proxy */\n-\telse if (wsi-\u003evhost-\u003esocks_proxy_port) {\n-\t\tn \u003d send(wsi-\u003edesc.sockfd, (char *)pt-\u003eserv_buf, plen,\n-\t\t\t MSG_NOSIGNAL);\n-\t\tif (n \u003c 0) {\n-\t\t\tlwsl_debug(\u0022ERROR writing socks greeting\u005cn\u0022);\n-\t\t\tcce \u003d \u0022socks write failed\u0022;\n-\t\t\tgoto failed;\n-\t\t}\n-\n-\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,\n-\t\t\t\tAWAITING_TIMEOUT);\n-\n-\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY;\n-\n-\t\treturn wsi;\n-\t}\n-#endif\n-\n-\t/*\n-\t * provoke service to issue the handshake directly\n-\t * we need to do it this way because in the proxy case, this is the\n-\t * next state and executed only if and when we get a good proxy\n-\t * response inside the state machine... but notice in SSL case this\n-\t * may not have sent anything yet with 0 return, and won't until some\n-\t * many retries from main loop. To stop that becoming endless,\n-\t * cover with a timeout.\n-\t */\n-\n-\tlws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,\n-\t\t\tAWAITING_TIMEOUT);\n-\n-\twsi-\u003emode \u003d LWSCM_WSCL_ISSUE_HANDSHAKE;\n-\tpfd.fd \u003d wsi-\u003edesc.sockfd;\n-\tpfd.events \u003d LWS_POLLIN;\n-\tpfd.revents \u003d LWS_POLLIN;\n-\n-\tn \u003d lws_service_fd(context, \u0026pfd);\n-\tif (n \u003c 0) {\n-\t\tcce \u003d \u0022first service failed\u0022;\n-\t\tgoto failed;\n-\t}\n-\tif (n) /* returns 1 on failure after closing wsi */\n-\t\treturn NULL;\n-\n-\treturn wsi;\n-\n-oom4:\n-\t/* we're closing, losing some rx is OK */\n-\tlws_header_table_force_to_detachable_state(wsi);\n-\n-\tif (wsi-\u003emode \u003d\u003d LWSCM_HTTP_CLIENT ||\n-\t wsi-\u003emode \u003d\u003d LWSCM_HTTP_CLIENT_ACCEPTED ||\n-\t wsi-\u003emode \u003d\u003d LWSCM_WSCL_WAITING_CONNECT) {\n-\t\twsi-\u003evhost-\u003eprotocols[0].callback(wsi,\n-\t\t\tLWS_CALLBACK_CLIENT_CONNECTION_ERROR,\n-\t\t\twsi-\u003euser_space, (void *)cce, strlen(cce));\n-\t\twsi-\u003ealready_did_cce \u003d 1;\n-\t}\n-\t/* take care that we might be inserted in fds already */\n-\tif (wsi-\u003eposition_in_fds_table !\u003d -1)\n-\t\tgoto failed1;\n-\tlws_remove_from_timeout_list(wsi);\n-\tlws_header_table_detach(wsi, 0);\n-\tlws_free(wsi);\n-\n-\treturn NULL;\n-\n-failed:\n-\twsi-\u003evhost-\u003eprotocols[0].callback(wsi,\n-\t\tLWS_CALLBACK_CLIENT_CONNECTION_ERROR,\n-\t\twsi-\u003euser_space, (void *)cce, strlen(cce));\n-\twsi-\u003ealready_did_cce \u003d 1;\n-failed1:\n-\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\n-\treturn NULL;\n-}\n-\n-/**\n- * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)\n- *\t\t\tthis only works if still in HTTP, ie, not upgraded yet\n- * wsi:\t\tconnection to reset\n- * address:\tnetwork address of the new server\n- * port:\tport to connect to\n- * path:\turi path to connect to on the new server\n- * host:\thost header to send to the new server\n- */\n-LWS_VISIBLE struct lws *\n-lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,\n-\t\t const char *path, const char *host)\n-{\n-\tchar origin[300] \u003d \u0022\u0022, protocol[300] \u003d \u0022\u0022, method[32] \u003d \u0022\u0022, iface[16] \u003d \u0022\u0022, *p;\n-\tstruct lws *wsi \u003d *pwsi;\n-\n-\tif (wsi-\u003eredirects \u003d\u003d 3) {\n-\t\tlwsl_err(\u0022%s: Too many redirects\u005cn\u0022, __func__);\n-\t\treturn NULL;\n-\t}\n-\twsi-\u003eredirects++;\n-\n-\tp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);\n-\tif (p)\n-\t\tstrncpy(origin, p, sizeof(origin) - 1);\n-\n-\tp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);\n-\tif (p)\n-\t\tstrncpy(protocol, p, sizeof(protocol) - 1);\n-\n-\tp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);\n-\tif (p)\n-\t\tstrncpy(method, p, sizeof(method) - 1);\n-\n-\tp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);\n-\tif (p)\n-\t\tstrncpy(method, p, sizeof(iface) - 1);\n-\n-\tlwsl_info(\u0022redirect ads\u003d'%s', port\u003d%d, path\u003d'%s', ssl \u003d %d\u005cn\u0022,\n-\t\t address, port, path, ssl);\n-\n-\t/* close the connection by hand */\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\tlws_ssl_close(wsi);\n-#endif\n-\n-#ifdef LWS_WITH_LIBUV\n-\tif (LWS_LIBUV_ENABLED(wsi-\u003econtext)) {\n-\t\tlwsl_debug(\u0022%s: lws_libuv_closehandle: wsi %p\u005cn\u0022, __func__, wsi);\n-\t\t/*\n-\t\t * libuv has to do his own close handle processing asynchronously\n-\t\t * but once it starts we can do everything else synchronously,\n-\t\t * including trash wsi-\u003edesc.sockfd since it took a copy.\n-\t\t *\n-\t\t * When it completes it will call compatible_close()\n-\t\t */\n-\t\tlws_libuv_closehandle_manually(wsi);\n-\t} else\n-#else\n-\tcompatible_close(wsi-\u003edesc.sockfd);\n-#endif\n-\n-\tremove_wsi_socket_from_fds(wsi);\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\twsi-\u003euse_ssl \u003d ssl;\n-#else\n-\tif (ssl) {\n-\t\tlwsl_err(\u0022%s: not configured for ssl\u005cn\u0022, __func__);\n-\t\treturn NULL;\n-\t}\n-#endif\n-\n-\twsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n-\twsi-\u003estate \u003d LWSS_CLIENT_UNCONNECTED;\n-\twsi-\u003eprotocol \u003d NULL;\n-\twsi-\u003epending_timeout \u003d NO_PENDING_TIMEOUT;\n-\twsi-\u003ec_port \u003d port;\n-\twsi-\u003ehdr_parsing_completed \u003d 0;\n-\t_lws_header_table_reset(wsi-\u003eu.hdr.ah);\n-\n-\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))\n-\t\treturn NULL;\n-\n-\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))\n-\t\treturn NULL;\n-\n-\tif (origin[0])\n-\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,\n-\t\t\t\t\t origin))\n-\t\t\treturn NULL;\n-\tif (protocol[0])\n-\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,\n-\t\t\t\t\t protocol))\n-\t\t\treturn NULL;\n-\tif (method[0])\n-\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,\n-\t\t\t\t\t method))\n-\t\t\treturn NULL;\n-\n-\tif (iface[0])\n-\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,\n-\t\t\t\t\t iface))\n-\t\t\treturn NULL;\n-\n-\torigin[0] \u003d '/';\n-\tstrncpy(\u0026origin[1], path, sizeof(origin) - 2);\n-\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))\n-\t\treturn NULL;\n-\n-\t*pwsi \u003d lws_client_connect_2(wsi);\n-\n-\treturn *pwsi;\n-}\n-\n-#ifdef LWS_WITH_HTTP_PROXY\n-static hubbub_error\n-html_parser_cb(const hubbub_token *token, void *pw)\n-{\n-\tstruct lws_rewrite *r \u003d (struct lws_rewrite *)pw;\n-\tchar buf[1024], *start \u003d buf + LWS_PRE, *p \u003d start,\n-\t *end \u003d \u0026buf[sizeof(buf) - 1];\n-\tsize_t i;\n-\n-\tswitch (token-\u003etype) {\n-\tcase HUBBUB_TOKEN_DOCTYPE:\n-\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003c!DOCTYPE %.*s %s \u0022,\n-\t\t\t\t(int) token-\u003edata.doctype.name.len,\n-\t\t\t\ttoken-\u003edata.doctype.name.ptr,\n-\t\t\t\ttoken-\u003edata.doctype.force_quirks ?\n-\t\t\t\t\t\t\u0022(force-quirks) \u0022 : \u0022\u0022);\n-\n-\t\tif (token-\u003edata.doctype.public_missing)\n-\t\t\tlwsl_debug(\u0022\u005ctpublic: missing\u005cn\u0022);\n-\t\telse\n-\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022PUBLIC \u005c\u0022%.*s\u005c\u0022\u005cn\u0022,\n-\t\t\t\t(int) token-\u003edata.doctype.public_id.len,\n-\t\t\t\ttoken-\u003edata.doctype.public_id.ptr);\n-\n-\t\tif (token-\u003edata.doctype.system_missing)\n-\t\t\tlwsl_debug(\u0022\u005ctsystem: missing\u005cn\u0022);\n-\t\telse\n-\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022 \u005c\u0022%.*s\u005c\u0022\u003e\u005cn\u0022,\n-\t\t\t\t(int) token-\u003edata.doctype.system_id.len,\n-\t\t\t\ttoken-\u003edata.doctype.system_id.ptr);\n-\n-\t\tbreak;\n-\tcase HUBBUB_TOKEN_START_TAG:\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003c%.*s\u0022, (int)token-\u003edata.tag.name.len,\n-\t\t\t\ttoken-\u003edata.tag.name.ptr);\n-\n-/*\t\t\t\t(token-\u003edata.tag.self_closing) ?\n-\t\t\t\t\t\t\u0022(self-closing) \u0022 : \u0022\u0022,\n-\t\t\t\t(token-\u003edata.tag.n_attributes \u003e 0) ?\n-\t\t\t\t\t\t\u0022attributes:\u0022 : \u0022\u0022);\n-*/\n-\t\tfor (i \u003d 0; i \u003c token-\u003edata.tag.n_attributes; i++) {\n-\t\t\tif (!hstrcmp(\u0026token-\u003edata.tag.attributes[i].name, \u0022href\u0022, 4) ||\n-\t\t\t !hstrcmp(\u0026token-\u003edata.tag.attributes[i].name, \u0022action\u0022, 6) ||\n-\t\t\t !hstrcmp(\u0026token-\u003edata.tag.attributes[i].name, \u0022src\u0022, 3)) {\n-\t\t\t\tconst char *pp \u003d (const char *)token-\u003edata.tag.attributes[i].value.ptr;\n-\t\t\t\tint plen \u003d (int) token-\u003edata.tag.attributes[i].value.len;\n-\n-\t\t\t\tif (strncmp(pp, \u0022http:\u0022, 5) \u0026\u0026 strncmp(pp, \u0022https:\u0022, 6)) {\n-\n-\t\t\t\t\tif (!hstrcmp(\u0026token-\u003edata.tag.attributes[i].value,\n-\t\t\t\t\t\t r-\u003efrom, r-\u003efrom_len)) {\n-\t\t\t\t\t\tpp +\u003d r-\u003efrom_len;\n-\t\t\t\t\t\tplen -\u003d r-\u003efrom_len;\n-\t\t\t\t\t}\n-\t\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022 %.*s\u003d\u005c\u0022%s/%.*s\u005c\u0022\u0022,\n-\t\t\t\t\t (int) token-\u003edata.tag.attributes[i].name.len,\n-\t\t\t\t\t token-\u003edata.tag.attributes[i].name.ptr,\n-\t\t\t\t\t r-\u003eto, plen, pp);\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\t\t\t}\n-\n-\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022 %.*s\u003d\u005c\u0022%.*s\u005c\u0022\u0022,\n-\t\t\t\t(int) token-\u003edata.tag.attributes[i].name.len,\n-\t\t\t\ttoken-\u003edata.tag.attributes[i].name.ptr,\n-\t\t\t\t(int) token-\u003edata.tag.attributes[i].value.len,\n-\t\t\t\ttoken-\u003edata.tag.attributes[i].value.ptr);\n-\t\t}\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003e\u0022);\n-\t\tbreak;\n-\tcase HUBBUB_TOKEN_END_TAG:\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003c/%.*s\u0022, (int) token-\u003edata.tag.name.len,\n-\t\t\t\ttoken-\u003edata.tag.name.ptr);\n-/*\n-\t\t\t\t(token-\u003edata.tag.self_closing) ?\n-\t\t\t\t\t\t\u0022(self-closing) \u0022 : \u0022\u0022,\n-\t\t\t\t(token-\u003edata.tag.n_attributes \u003e 0) ?\n-\t\t\t\t\t\t\u0022attributes:\u0022 : \u0022\u0022);\n-*/\n-\t\tfor (i \u003d 0; i \u003c token-\u003edata.tag.n_attributes; i++) {\n-\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022 %.*s\u003d'%.*s'\u005cn\u0022,\n-\t\t\t\t(int) token-\u003edata.tag.attributes[i].name.len,\n-\t\t\t\ttoken-\u003edata.tag.attributes[i].name.ptr,\n-\t\t\t\t(int) token-\u003edata.tag.attributes[i].value.len,\n-\t\t\t\ttoken-\u003edata.tag.attributes[i].value.ptr);\n-\t\t}\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003e\u0022);\n-\t\tbreak;\n-\tcase HUBBUB_TOKEN_COMMENT:\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003c!-- %.*s --\u003e\u005cn\u0022,\n-\t\t\t\t(int) token-\u003edata.comment.len,\n-\t\t\t\ttoken-\u003edata.comment.ptr);\n-\t\tbreak;\n-\tcase HUBBUB_TOKEN_CHARACTER:\n-\t\tif (token-\u003edata.character.len \u003d\u003d 1) {\n-\t\t\tif (*token-\u003edata.character.ptr \u003d\u003d '\u003c') {\n-\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u0026lt;\u0022);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (*token-\u003edata.character.ptr \u003d\u003d '\u003e') {\n-\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u0026gt;\u0022);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (*token-\u003edata.character.ptr \u003d\u003d '\u0026') {\n-\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u0026amp;\u0022);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022%.*s\u0022, (int) token-\u003edata.character.len,\n-\t\t\t\ttoken-\u003edata.character.ptr);\n-\t\tbreak;\n-\tcase HUBBUB_TOKEN_EOF:\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005cn\u0022);\n-\t\tbreak;\n-\t}\n-\n-\tif (user_callback_handle_rxflow(r-\u003ewsi-\u003eprotocol-\u003ecallback,\n-\t\t\tr-\u003ewsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,\n-\t\t\tr-\u003ewsi-\u003euser_space, start, p - start))\n-\t\treturn -1;\n-\n-\treturn HUBBUB_OK;\n-}\n-#endif\n-\n-LWS_VISIBLE struct lws *\n-lws_client_connect_via_info(struct lws_client_connect_info *i)\n-{\n-\tstruct lws *wsi;\n-\tint v \u003d SPEC_LATEST_SUPPORTED;\n-\tconst struct lws_protocols *p;\n-\n-\tif (i-\u003econtext-\u003erequested_kill)\n-\t\treturn NULL;\n-\n-\tif (!i-\u003econtext-\u003eprotocol_init_done)\n-\t\tlws_protocol_init(i-\u003econtext);\n-\n-\twsi \u003d lws_zalloc(sizeof(struct lws), \u0022client wsi\u0022);\n-\tif (wsi \u003d\u003d NULL)\n-\t\tgoto bail;\n-\n-\twsi-\u003econtext \u003d i-\u003econtext;\n-\t/* assert the mode and union status (hdr) clearly */\n-\tlws_union_transition(wsi, LWSCM_HTTP_CLIENT);\n-\twsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n-\n-\t/* 1) fill up the wsi with stuff from the connect_info as far as it\n-\t * can go. It's because not only is our connection async, we might\n-\t * not even be able to get ahold of an ah at this point.\n-\t */\n-\n-\t/* -1 means just use latest supported */\n-\tif (i-\u003eietf_version_or_minus_one !\u003d -1 \u0026\u0026 i-\u003eietf_version_or_minus_one)\n-\t\tv \u003d i-\u003eietf_version_or_minus_one;\n-\n-\twsi-\u003eietf_spec_revision \u003d v;\n-\twsi-\u003euser_space \u003d NULL;\n-\twsi-\u003estate \u003d LWSS_CLIENT_UNCONNECTED;\n-\twsi-\u003epending_timeout \u003d NO_PENDING_TIMEOUT;\n-\twsi-\u003eposition_in_fds_table \u003d -1;\n-\twsi-\u003ec_port \u003d i-\u003eport;\n-\twsi-\u003evhost \u003d i-\u003evhost;\n-\tif (!wsi-\u003evhost)\n-\t\twsi-\u003evhost \u003d i-\u003econtext-\u003evhost_list;\n-\n-\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[0];\n-\n-\t/* for http[s] connection, allow protocol selection by name */\n-\n-\tif (i-\u003emethod \u0026\u0026 i-\u003evhost \u0026\u0026 i-\u003eprotocol) {\n-\t\tp \u003d lws_vhost_name_to_protocol(i-\u003evhost, i-\u003eprotocol);\n-\t\tif (p)\n-\t\t\twsi-\u003eprotocol \u003d p;\n-\t}\n-\n-\tif (wsi \u0026\u0026 !wsi-\u003euser_space \u0026\u0026 i-\u003euserdata) {\n-\t\twsi-\u003euser_space_externally_allocated \u003d 1;\n-\t\twsi-\u003euser_space \u003d i-\u003euserdata;\n-\t} else\n-\t\t/* if we stay in http, we can assign the user space now,\n-\t\t * otherwise do it after the protocol negotiated\n-\t\t */\n-\t\tif (i-\u003emethod)\n-\t\t\tif (lws_ensure_user_space(wsi))\n-\t\t\t\tgoto bail;\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\twsi-\u003euse_ssl \u003d i-\u003essl_connection;\n-#else\n-\tif (i-\u003essl_connection) {\n-\t\tlwsl_err(\u0022libwebsockets not configured for ssl\u005cn\u0022);\n-\t\tgoto bail;\n-\t}\n-#endif\n-\n-\t/* 2) stash the things from connect_info that we can't process without\n-\t * an ah. Because if no ah, we will go on the ah waiting list and\n-\t * process those things later (after the connect_info and maybe the\n-\t * things pointed to have gone out of scope.\n-\t */\n-\n-\twsi-\u003eu.hdr.stash \u003d lws_malloc(sizeof(*wsi-\u003eu.hdr.stash), \u0022client stash\u0022);\n-\tif (!wsi-\u003eu.hdr.stash) {\n-\t\tlwsl_err(\u0022%s: OOM\u005cn\u0022, __func__);\n-\t\tgoto bail;\n-\t}\n-\n-\twsi-\u003eu.hdr.stash-\u003eorigin[0] \u003d '\u005c0';\n-\twsi-\u003eu.hdr.stash-\u003eprotocol[0] \u003d '\u005c0';\n-\twsi-\u003eu.hdr.stash-\u003emethod[0] \u003d '\u005c0';\n-\twsi-\u003eu.hdr.stash-\u003eiface[0] \u003d '\u005c0';\n-\n-\tstrncpy(wsi-\u003eu.hdr.stash-\u003eaddress, i-\u003eaddress,\n-\t\tsizeof(wsi-\u003eu.hdr.stash-\u003eaddress) - 1);\n-\tstrncpy(wsi-\u003eu.hdr.stash-\u003epath, i-\u003epath,\n-\t\tsizeof(wsi-\u003eu.hdr.stash-\u003epath) - 1);\n-\tstrncpy(wsi-\u003eu.hdr.stash-\u003ehost, i-\u003ehost,\n-\t\tsizeof(wsi-\u003eu.hdr.stash-\u003ehost) - 1);\n-\tif (i-\u003eorigin)\n-\t\tstrncpy(wsi-\u003eu.hdr.stash-\u003eorigin, i-\u003eorigin,\n-\t\t\tsizeof(wsi-\u003eu.hdr.stash-\u003eorigin) - 1);\n-\tif (i-\u003eprotocol)\n-\t\tstrncpy(wsi-\u003eu.hdr.stash-\u003eprotocol, i-\u003eprotocol,\n-\t\t\tsizeof(wsi-\u003eu.hdr.stash-\u003eprotocol) - 1);\n-\tif (i-\u003emethod)\n-\t\tstrncpy(wsi-\u003eu.hdr.stash-\u003emethod, i-\u003emethod,\n-\t\t\tsizeof(wsi-\u003eu.hdr.stash-\u003emethod) - 1);\n-\tif (i-\u003eiface)\n-\t\tstrncpy(wsi-\u003eu.hdr.stash-\u003eiface, i-\u003eiface,\n-\t\t\tsizeof(wsi-\u003eu.hdr.stash-\u003eiface) - 1);\n-\n-\twsi-\u003eu.hdr.stash-\u003eaddress[sizeof(wsi-\u003eu.hdr.stash-\u003eaddress) - 1] \u003d '\u005c0';\n-\twsi-\u003eu.hdr.stash-\u003epath[sizeof(wsi-\u003eu.hdr.stash-\u003epath) - 1] \u003d '\u005c0';\n-\twsi-\u003eu.hdr.stash-\u003ehost[sizeof(wsi-\u003eu.hdr.stash-\u003ehost) - 1] \u003d '\u005c0';\n-\twsi-\u003eu.hdr.stash-\u003eorigin[sizeof(wsi-\u003eu.hdr.stash-\u003eorigin) - 1] \u003d '\u005c0';\n-\twsi-\u003eu.hdr.stash-\u003eprotocol[sizeof(wsi-\u003eu.hdr.stash-\u003eprotocol) - 1] \u003d '\u005c0';\n-\twsi-\u003eu.hdr.stash-\u003emethod[sizeof(wsi-\u003eu.hdr.stash-\u003emethod) - 1] \u003d '\u005c0';\n-\twsi-\u003eu.hdr.stash-\u003eiface[sizeof(wsi-\u003eu.hdr.stash-\u003eiface) - 1] \u003d '\u005c0';\n-\n-\tif (i-\u003epwsi)\n-\t\t*i-\u003epwsi \u003d wsi;\n-\n-\t/* if we went on the waiting list, no probs just return the wsi\n-\t * when we get the ah, now or later, he will call\n-\t * lws_client_connect_via_info2() below.\n-\t */\n-\tif (lws_header_table_attach(wsi, 0) \u003c 0) {\n-\t\t/*\n-\t\t * if we failed here, the connection is already closed\n-\t\t * and freed.\n-\t\t */\n-\t\tgoto bail1;\n-\t}\n-\n-\tif (i-\u003eparent_wsi) {\n-\t\tlwsl_info(\u0022%s: created child %p of parent %p\u005cn\u0022, __func__,\n-\t\t\t\twsi, i-\u003eparent_wsi);\n-\t\twsi-\u003eparent \u003d i-\u003eparent_wsi;\n-\t\twsi-\u003esibling_list \u003d i-\u003eparent_wsi-\u003echild_list;\n-\t\ti-\u003eparent_wsi-\u003echild_list \u003d wsi;\n-\t}\n-#ifdef LWS_WITH_HTTP_PROXY\n-\tif (i-\u003euri_replace_to)\n-\t\twsi-\u003erw \u003d lws_rewrite_create(wsi, html_parser_cb,\n-\t\t\t\t\t i-\u003euri_replace_from,\n-\t\t\t\t\t i-\u003euri_replace_to);\n-#endif\n-\n-\treturn wsi;\n-\n-bail:\n-\tlws_free(wsi);\n-\n-bail1:\n-\tif (i-\u003epwsi)\n-\t\t*i-\u003epwsi \u003d NULL;\n-\n-\treturn NULL;\n-}\n-\n-struct lws *\n-lws_client_connect_via_info2(struct lws *wsi)\n-{\n-\tstruct client_info_stash *stash \u003d wsi-\u003eu.hdr.stash;\n-\n-\tif (!stash)\n-\t\treturn wsi;\n-\n-\t/*\n-\t * we're not necessarily in a position to action these right away,\n-\t * stash them... we only need during connect phase so u.hdr is fine\n-\t */\n-\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,\n-\t\t\t\t stash-\u003eaddress))\n-\t\tgoto bail1;\n-\n-\t/* these only need u.hdr lifetime as well */\n-\n-\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash-\u003epath))\n-\t\tgoto bail1;\n-\n-\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash-\u003ehost))\n-\t\tgoto bail1;\n-\n-\tif (stash-\u003eorigin[0])\n-\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,\n-\t\t\t\t\t stash-\u003eorigin))\n-\t\t\tgoto bail1;\n-\t/*\n-\t * this is a list of protocols we tell the server we're okay with\n-\t * stash it for later when we compare server response with it\n-\t */\n-\tif (stash-\u003eprotocol[0])\n-\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,\n-\t\t\t\t\t stash-\u003eprotocol))\n-\t\t\tgoto bail1;\n-\tif (stash-\u003emethod[0])\n-\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,\n-\t\t\t\t\t stash-\u003emethod))\n-\t\t\tgoto bail1;\n-\tif (stash-\u003eiface[0])\n-\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,\n-\t\t\t\t\t stash-\u003eiface))\n-\t\t\tgoto bail1;\n-\n-#if defined(LWS_WITH_SOCKS5)\n-\tif (!wsi-\u003evhost-\u003esocks_proxy_port)\n-\t\tlws_free_set_NULL(wsi-\u003eu.hdr.stash);\n-#endif\n-\n-\t/*\n-\t * Check with each extension if it is able to route and proxy this\n-\t * connection for us. For example, an extension like x-google-mux\n-\t * can handle this and then we don't need an actual socket for this\n-\t * connection.\n-\t */\n-\n-\tif (lws_ext_cb_all_exts(wsi-\u003econtext, wsi,\n-\t\t\t\tLWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,\n-\t\t\t\t(void *)stash-\u003eaddress,\n-\t\t\t\twsi-\u003ec_port) \u003e 0) {\n-\t\tlwsl_client(\u0022lws_client_connect: ext handling conn\u005cn\u0022);\n-\n-\t\tlws_set_timeout(wsi,\n-\t\t\tPENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,\n-\t\t\t AWAITING_TIMEOUT);\n-\n-\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_EXTENSION_CONNECT;\n-\t\treturn wsi;\n-\t}\n-\tlwsl_client(\u0022lws_client_connect: direct conn\u005cn\u0022);\n-\twsi-\u003econtext-\u003ecount_wsi_allocated++;\n-\n-\treturn lws_client_connect_2(wsi);\n-\n-bail1:\n-#if defined(LWS_WITH_SOCKS5)\n-\tif (!wsi-\u003evhost-\u003esocks_proxy_port)\n-\t\tlws_free_set_NULL(wsi-\u003eu.hdr.stash);\n-#endif\n-\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE struct lws *\n-lws_client_connect_extended(struct lws_context *context, const char *address,\n-\t\t\t int port, int ssl_connection, const char *path,\n-\t\t\t const char *host, const char *origin,\n-\t\t\t const char *protocol, int ietf_version_or_minus_one,\n-\t\t\t void *userdata)\n-{\n-\tstruct lws_client_connect_info i;\n-\n-\tmemset(\u0026i, 0, sizeof(i));\n-\n-\ti.context \u003d context;\n-\ti.address \u003d address;\n-\ti.port \u003d port;\n-\ti.ssl_connection \u003d ssl_connection;\n-\ti.path \u003d path;\n-\ti.host \u003d host;\n-\ti.origin \u003d origin;\n-\ti.protocol \u003d protocol;\n-\ti.ietf_version_or_minus_one \u003d ietf_version_or_minus_one;\n-\ti.userdata \u003d userdata;\n-\n-\treturn lws_client_connect_via_info(\u0026i);\n-}\n-\n-LWS_VISIBLE struct lws *\n-lws_client_connect(struct lws_context *context, const char *address,\n-\t\t\t int port, int ssl_connection, const char *path,\n-\t\t\t const char *host, const char *origin,\n-\t\t\t const char *protocol, int ietf_version_or_minus_one)\n-{\n-\tstruct lws_client_connect_info i;\n-\n-\tmemset(\u0026i, 0, sizeof(i));\n-\n-\ti.context \u003d context;\n-\ti.address \u003d address;\n-\ti.port \u003d port;\n-\ti.ssl_connection \u003d ssl_connection;\n-\ti.path \u003d path;\n-\ti.host \u003d host;\n-\ti.origin \u003d origin;\n-\ti.protocol \u003d protocol;\n-\ti.ietf_version_or_minus_one \u003d ietf_version_or_minus_one;\n-\ti.userdata \u003d NULL;\n-\n-\treturn lws_client_connect_via_info(\u0026i);\n-}\n-\n-#if defined(LWS_WITH_SOCKS5)\n-void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,\n-\t\t\tssize_t *msg_len)\n-{\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tssize_t len \u003d 0, n, passwd_len;\n-\tshort net_num;\n-\tchar *p;\n-\n-\tswitch (type) {\n-\tcase SOCKS_MSG_GREETING:\n-\t\t/* socks version, version 5 only */\n-\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_VERSION_5;\n-\t\t/* number of methods */\n-\t\tpt-\u003eserv_buf[len++] \u003d 2;\n-\t\t/* username password method */\n-\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_AUTH_USERNAME_PASSWORD;\n-\t\t/* no authentication method */\n-\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_AUTH_NO_AUTH;\n-\t\tbreak;\n-\n-\tcase SOCKS_MSG_USERNAME_PASSWORD:\n-\t\tn \u003d strlen(wsi-\u003evhost-\u003esocks_user);\n-\t\tpasswd_len \u003d strlen(wsi-\u003evhost-\u003esocks_password);\n-\n-\t\t/* the subnegotiation version */\n-\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_SUBNEGOTIATION_VERSION_1;\n-\t\t/* length of the user name */\n-\t\tpt-\u003eserv_buf[len++] \u003d n;\n-\t\t/* user name */\n-\t\tstrncpy((char *)\u0026pt-\u003eserv_buf[len], wsi-\u003evhost-\u003esocks_user,\n-\t\t\tcontext-\u003ept_serv_buf_size - len);\n-\t\tlen +\u003d n;\n-\t\t/* length of the password */\n-\t\tpt-\u003eserv_buf[len++] \u003d passwd_len;\n-\t\t/* password */\n-\t\tstrncpy((char *)\u0026pt-\u003eserv_buf[len], wsi-\u003evhost-\u003esocks_password,\n-\t\t\tcontext-\u003ept_serv_buf_size - len);\n-\t\tlen +\u003d passwd_len;\n-\t\tbreak;\n-\n-\tcase SOCKS_MSG_CONNECT:\n-\t\tp \u003d (char*)\u0026net_num;\n-\n-\t\t/* socks version */\n-\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_VERSION_5;\n-\t\t/* socks command */\n-\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_COMMAND_CONNECT;\n-\t\t/* reserved */\n-\t\tpt-\u003eserv_buf[len++] \u003d 0;\n-\t\t/* address type */\n-\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_ATYP_DOMAINNAME;\n-\t\t/* skip length, we fill it in at the end */\n-\t\tn \u003d len++;\n-\n-\t\t/* the address we tell SOCKS proxy to connect to */\n-\t\tstrncpy((char *)\u0026(pt-\u003eserv_buf[len]), wsi-\u003eu.hdr.stash-\u003eaddress,\n-\t\t\tcontext-\u003ept_serv_buf_size - len);\n-\t\tlen +\u003d strlen(wsi-\u003eu.hdr.stash-\u003eaddress);\n-\t\tnet_num \u003d htons(wsi-\u003ec_port);\n-\n-\t\t/* the port we tell SOCKS proxy to connect to */\n-\t\tpt-\u003eserv_buf[len++] \u003d p[0];\n-\t\tpt-\u003eserv_buf[len++] \u003d p[1];\n-\n-\t\t/* the length of the address, excluding port */\n-\t\tpt-\u003eserv_buf[n] \u003d strlen(wsi-\u003eu.hdr.stash-\u003eaddress);\n-\t\tbreak;\n-\t\t\n-\tdefault:\n-\t\treturn;\n-\t}\n-\n-\t*msg_len \u003d len;\n-}\n-#endif\ndiff --git a/lib/client-parser.c b/lib/client-parser.c\ndeleted file mode 100644\nindex 0e42dac..0000000\n--- a/lib/client-parser.c\n+++ /dev/null\n@@ -1,598 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-/*\n- * parsers.c: lws_rx_sm() needs to be roughly kept in\n- * sync with changes here, esp related to ext draining\n- */\n-\n-int lws_client_rx_sm(struct lws *wsi, unsigned char c)\n-{\n-\tint callback_action \u003d LWS_CALLBACK_CLIENT_RECEIVE;\n-\tint handled, n, m, rx_draining_ext \u003d 0;\n-\tunsigned short close_code;\n-\tstruct lws_tokens eff_buf;\n-\tunsigned char *pp;\n-\n-\tif (wsi-\u003eu.ws.rx_draining_ext) {\n-\t\tassert(!c);\n-\t\teff_buf.token \u003d NULL;\n-\t\teff_buf.token_len \u003d 0;\n-\t\tlws_remove_wsi_from_draining_ext_list(wsi);\n-\t\trx_draining_ext \u003d 1;\n-\t\tlwsl_debug(\u0022%s: doing draining flow\u005cn\u0022, __func__);\n-\n-\t\tgoto drain_extension;\n-\t}\n-\n-\tif (wsi-\u003esocket_is_permanently_unusable)\n-\t\treturn -1;\n-\n-\tswitch (wsi-\u003elws_rx_parse_state) {\n-\tcase LWS_RXPS_NEW:\n-\t\t/* control frames (PING) may interrupt checkable sequences */\n-\t\twsi-\u003eu.ws.defeat_check_utf8 \u003d 0;\n-\n-\t\tswitch (wsi-\u003eietf_spec_revision) {\n-\t\tcase 13:\n-\t\t\twsi-\u003eu.ws.opcode \u003d c \u0026 0xf;\n-\t\t\t/* revisit if an extension wants them... */\n-\t\t\tswitch (wsi-\u003eu.ws.opcode) {\n-\t\t\tcase LWSWSOPC_TEXT_FRAME:\n-\t\t\t\twsi-\u003eu.ws.rsv_first_msg \u003d (c \u0026 0x70);\n-\t\t\t\twsi-\u003eu.ws.continuation_possible \u003d 1;\n-\t\t\t\twsi-\u003eu.ws.check_utf8 \u003d lws_check_opt(\n-\t\t\t\t\twsi-\u003econtext-\u003eoptions,\n-\t\t\t\t\tLWS_SERVER_OPTION_VALIDATE_UTF8);\n-\t\t\t\twsi-\u003eu.ws.utf8 \u003d 0;\n-\t\t\t\tbreak;\n-\t\t\tcase LWSWSOPC_BINARY_FRAME:\n-\t\t\t\twsi-\u003eu.ws.rsv_first_msg \u003d (c \u0026 0x70);\n-\t\t\t\twsi-\u003eu.ws.check_utf8 \u003d 0;\n-\t\t\t\twsi-\u003eu.ws.continuation_possible \u003d 1;\n-\t\t\t\tbreak;\n-\t\t\tcase LWSWSOPC_CONTINUATION:\n-\t\t\t\tif (!wsi-\u003eu.ws.continuation_possible) {\n-\t\t\t\t\tlwsl_info(\u0022disordered continuation\u005cn\u0022);\n-\t\t\t\t\treturn -1;\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\tcase LWSWSOPC_CLOSE:\n-\t\t\t\twsi-\u003eu.ws.check_utf8 \u003d 0;\n-\t\t\t\twsi-\u003eu.ws.utf8 \u003d 0;\n-\t\t\t\tbreak;\n-\t\t\tcase 3:\n-\t\t\tcase 4:\n-\t\t\tcase 5:\n-\t\t\tcase 6:\n-\t\t\tcase 7:\n-\t\t\tcase 0xb:\n-\t\t\tcase 0xc:\n-\t\t\tcase 0xd:\n-\t\t\tcase 0xe:\n-\t\t\tcase 0xf:\n-\t\t\t\tlwsl_info(\u0022illegal opcode\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\tdefault:\n-\t\t\t\twsi-\u003eu.ws.defeat_check_utf8 \u003d 1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\twsi-\u003eu.ws.rsv \u003d (c \u0026 0x70);\n-\t\t\t/* revisit if an extension wants them... */\n-\t\t\tif (\n-#ifndef LWS_NO_EXTENSIONS\n-\t\t\t\t!wsi-\u003ecount_act_ext \u0026\u0026\n-#endif\n-\t\t\t\twsi-\u003eu.ws.rsv) {\n-\t\t\t\tlwsl_info(\u0022illegal rsv bits set\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\twsi-\u003eu.ws.final \u003d !!((c \u003e\u003e 7) \u0026 1);\n-\t\t\tlwsl_ext(\u0022%s: This RX frame Final %d\u005cn\u0022, __func__,\n-\t\t\t\t wsi-\u003eu.ws.final);\n-\n-\t\t\tif (wsi-\u003eu.ws.owed_a_fin \u0026\u0026\n-\t\t\t (wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_TEXT_FRAME ||\n-\t\t\t wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_BINARY_FRAME)) {\n-\t\t\t\tlwsl_info(\u0022hey you owed us a FIN\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\tif ((!(wsi-\u003eu.ws.opcode \u0026 8)) \u0026\u0026 wsi-\u003eu.ws.final) {\n-\t\t\t\twsi-\u003eu.ws.continuation_possible \u003d 0;\n-\t\t\t\twsi-\u003eu.ws.owed_a_fin \u003d 0;\n-\t\t\t}\n-\n-\t\t\tif ((wsi-\u003eu.ws.opcode \u0026 8) \u0026\u0026 !wsi-\u003eu.ws.final) {\n-\t\t\t\tlwsl_info(\u0022control msg can't be fragmented\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\tif (!wsi-\u003eu.ws.final)\n-\t\t\t\twsi-\u003eu.ws.owed_a_fin \u003d 1;\n-\n-\t\t\tswitch (wsi-\u003eu.ws.opcode) {\n-\t\t\tcase LWSWSOPC_TEXT_FRAME:\n-\t\t\tcase LWSWSOPC_BINARY_FRAME:\n-\t\t\t\twsi-\u003eu.ws.frame_is_binary \u003d wsi-\u003eu.ws.opcode \u003d\u003d\n-\t\t\t\t\t\t LWSWSOPC_BINARY_FRAME;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN;\n-\t\t\tbreak;\n-\n-\t\tdefault:\n-\t\t\tlwsl_err(\u0022unknown spec version %02d\u005cn\u0022,\n-\t\t\t\t wsi-\u003eietf_spec_revision);\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN:\n-\n-\t\twsi-\u003eu.ws.this_frame_masked \u003d !!(c \u0026 0x80);\n-\n-\t\tswitch (c \u0026 0x7f) {\n-\t\tcase 126:\n-\t\t\t/* control frames are not allowed to have big lengths */\n-\t\t\tif (wsi-\u003eu.ws.opcode \u0026 8)\n-\t\t\t\tgoto illegal_ctl_length;\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN16_2;\n-\t\t\tbreak;\n-\t\tcase 127:\n-\t\t\t/* control frames are not allowed to have big lengths */\n-\t\t\tif (wsi-\u003eu.ws.opcode \u0026 8)\n-\t\t\t\tgoto illegal_ctl_length;\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_8;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\twsi-\u003eu.ws.rx_packet_length \u003d c;\n-\t\t\tif (wsi-\u003eu.ws.this_frame_masked)\n-\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n-\t\t\telse {\n-\t\t\t\tif (c)\n-\t\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n-\t\t\t\telse {\n-\t\t\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n-\t\t\t\t\tgoto spill;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN16_2:\n-\t\twsi-\u003eu.ws.rx_packet_length \u003d c \u003c\u003c 8;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN16_1;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN16_1:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d c;\n-\t\tif (wsi-\u003eu.ws.this_frame_masked)\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_1;\n-\t\telse {\n-\t\t\tif (wsi-\u003eu.ws.rx_packet_length)\n-\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n-\t\t\telse {\n-\t\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n-\t\t\t\tgoto spill;\n-\t\t\t}\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_8:\n-\t\tif (c \u0026 0x80) {\n-\t\t\tlwsl_warn(\u0022b63 of length must be zero\u005cn\u0022);\n-\t\t\t/* kill the connection */\n-\t\t\treturn -1;\n-\t\t}\n-#if defined __LP64__\n-\t\twsi-\u003eu.ws.rx_packet_length \u003d ((size_t)c) \u003c\u003c 56;\n-#else\n-\t\twsi-\u003eu.ws.rx_packet_length \u003d 0;\n-#endif\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_7;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_7:\n-#if defined __LP64__\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 48;\n-#endif\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_6;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_6:\n-#if defined __LP64__\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 40;\n-#endif\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_5;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_5:\n-#if defined __LP64__\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 32;\n-#endif\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_4;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_4:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 24;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_3;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_3:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 16;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_2;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_2:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 8;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_1;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_1:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d (size_t)c;\n-\t\tif (wsi-\u003eu.ws.this_frame_masked)\n-\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n-\t\telse {\n-\t\t\tif (wsi-\u003eu.ws.rx_packet_length)\n-\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n-\t\t\telse {\n-\t\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n-\t\t\t\tgoto spill;\n-\t\t\t}\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_1:\n-\t\twsi-\u003eu.ws.mask[0] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_2;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_2:\n-\t\twsi-\u003eu.ws.mask[1] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_3;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_3:\n-\t\twsi-\u003eu.ws.mask[2] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_4;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_4:\n-\t\twsi-\u003eu.ws.mask[3] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\n-\t\tif (wsi-\u003eu.ws.rx_packet_length)\n-\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n-\t\telse {\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n-\t\t\tgoto spill;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:\n-\n-\t\tassert(wsi-\u003eu.ws.rx_ubuf);\n-\n-\t\tif (wsi-\u003eu.ws.rx_draining_ext)\n-\t\t\tgoto drain_extension;\n-\n-\t\tif (wsi-\u003eu.ws.this_frame_masked \u0026\u0026 !wsi-\u003eu.ws.all_zero_nonce)\n-\t\t\tc ^\u003d wsi-\u003eu.ws.mask[(wsi-\u003eu.ws.mask_idx++) \u0026 3];\n-\n-\t\twsi-\u003eu.ws.rx_ubuf[LWS_PRE + (wsi-\u003eu.ws.rx_ubuf_head++)] \u003d c;\n-\n-\t\tif (--wsi-\u003eu.ws.rx_packet_length \u003d\u003d 0) {\n-\t\t\t/* spill because we have the whole frame */\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n-\t\t\tgoto spill;\n-\t\t}\n-\n-\t\t/*\n-\t\t * if there's no protocol max frame size given, we are\n-\t\t * supposed to default to context-\u003ept_serv_buf_size\n-\t\t */\n-\t\tif (!wsi-\u003eprotocol-\u003erx_buffer_size \u0026\u0026\n-\t\t wsi-\u003eu.ws.rx_ubuf_head !\u003d wsi-\u003econtext-\u003ept_serv_buf_size)\n-\t\t\tbreak;\n-\n-\t\tif (wsi-\u003eprotocol-\u003erx_buffer_size \u0026\u0026\n-\t\t wsi-\u003eu.ws.rx_ubuf_head !\u003d wsi-\u003eprotocol-\u003erx_buffer_size)\n-\t\t\tbreak;\n-\n-\t\t/* spill because we filled our rx buffer */\n-spill:\n-\n-\t\thandled \u003d 0;\n-\n-\t\t/*\n-\t\t * is this frame a control packet we should take care of at this\n-\t\t * layer? If so service it and hide it from the user callback\n-\t\t */\n-\n-\t\tswitch (wsi-\u003eu.ws.opcode) {\n-\t\tcase LWSWSOPC_CLOSE:\n-\t\t\tpp \u003d (unsigned char *)\u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n-\t\t\tif (lws_check_opt(wsi-\u003econtext-\u003eoptions,\n-\t\t\t\t\t LWS_SERVER_OPTION_VALIDATE_UTF8) \u0026\u0026\n-\t\t\t wsi-\u003eu.ws.rx_ubuf_head \u003e 2 \u0026\u0026\n-\t\t\t lws_check_utf8(\u0026wsi-\u003eu.ws.utf8, pp + 2,\n-\t\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head - 2))\n-\t\t\t\tgoto utf8_fail;\n-\n-\t\t\t/* is this an acknowledgement of our close? */\n-\t\t\tif (wsi-\u003estate \u003d\u003d LWSS_AWAITING_CLOSE_ACK) {\n-\t\t\t\t/*\n-\t\t\t\t * fine he has told us he is closing too, let's\n-\t\t\t\t * finish our close\n-\t\t\t\t */\n-\t\t\t\tlwsl_parser(\u0022seen server's close ack\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t\tlwsl_parser(\u0022client sees server close len \u003d %d\u005cn\u0022,\n-\t\t\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n-\t\t\tif (wsi-\u003eu.ws.rx_ubuf_head \u003e\u003d 2) {\n-\t\t\t\tclose_code \u003d (pp[0] \u003c\u003c 8) | pp[1];\n-\t\t\t\tif (close_code \u003c 1000 ||\n-\t\t\t\t close_code \u003d\u003d 1004 ||\n-\t\t\t\t close_code \u003d\u003d 1005 ||\n-\t\t\t\t close_code \u003d\u003d 1006 ||\n-\t\t\t\t close_code \u003d\u003d 1012 ||\n-\t\t\t\t close_code \u003d\u003d 1013 ||\n-\t\t\t\t close_code \u003d\u003d 1014 ||\n-\t\t\t\t close_code \u003d\u003d 1015 ||\n-\t\t\t\t (close_code \u003e\u003d 1016 \u0026\u0026 close_code \u003c 3000)\n-\t\t\t\t) {\n-\t\t\t\t\tpp[0] \u003d (LWS_CLOSE_STATUS_PROTOCOL_ERR \u003e\u003e 8) \u0026 0xff;\n-\t\t\t\t\tpp[1] \u003d LWS_CLOSE_STATUS_PROTOCOL_ERR \u0026 0xff;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif (user_callback_handle_rxflow(\n-\t\t\t\t\twsi-\u003eprotocol-\u003ecallback, wsi,\n-\t\t\t\t\tLWS_CALLBACK_WS_PEER_INITIATED_CLOSE,\n-\t\t\t\t\twsi-\u003euser_space, pp,\n-\t\t\t\t\twsi-\u003eu.ws.rx_ubuf_head))\n-\t\t\t\treturn -1;\n-\n-\t\t\tif (lws_partial_buffered(wsi))\n-\t\t\t\t/*\n-\t\t\t\t * if we're in the middle of something,\n-\t\t\t\t * we can't do a normal close response and\n-\t\t\t\t * have to just close our end.\n-\t\t\t\t */\n-\t\t\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n-\t\t\telse\n-\t\t\t\t/*\n-\t\t\t\t * parrot the close packet payload back\n-\t\t\t\t * we do not care about how it went, we are closing\n-\t\t\t\t * immediately afterwards\n-\t\t\t\t */\n-\t\t\t\tlws_write(wsi, (unsigned char *)\n-\t\t\t\t\t \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n-\t\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head,\n-\t\t\t\t\t LWS_WRITE_CLOSE);\n-\t\t\twsi-\u003estate \u003d LWSS_RETURNED_CLOSE_ALREADY;\n-\t\t\t/* close the connection */\n-\t\t\treturn -1;\n-\n-\t\tcase LWSWSOPC_PING:\n-\t\t\tlwsl_info(\u0022received %d byte ping, sending pong\u005cn\u0022,\n-\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n-\n-\t\t\t/* he set a close reason on this guy, ignore PING */\n-\t\t\tif (wsi-\u003eu.ws.close_in_ping_buffer_len)\n-\t\t\t\tgoto ping_drop;\n-\n-\t\t\tif (wsi-\u003eu.ws.ping_pending_flag) {\n-\t\t\t\t/*\n-\t\t\t\t * there is already a pending ping payload\n-\t\t\t\t * we should just log and drop\n-\t\t\t\t */\n-\t\t\t\tlwsl_parser(\u0022DROP PING since one pending\u005cn\u0022);\n-\t\t\t\tgoto ping_drop;\n-\t\t\t}\n-\n-\t\t\t/* control packets can only be \u003c 128 bytes long */\n-\t\t\tif (wsi-\u003eu.ws.rx_ubuf_head \u003e 128 - 3) {\n-\t\t\t\tlwsl_parser(\u0022DROP PING payload too large\u005cn\u0022);\n-\t\t\t\tgoto ping_drop;\n-\t\t\t}\n-\n-\t\t\t/* stash the pong payload */\n-\t\t\tmemcpy(wsi-\u003eu.ws.ping_payload_buf + LWS_PRE,\n-\t\t\t \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n-\t\t\t\twsi-\u003eu.ws.rx_ubuf_head);\n-\n-\t\t\twsi-\u003eu.ws.ping_payload_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n-\t\t\twsi-\u003eu.ws.ping_pending_flag \u003d 1;\n-\n-\t\t\t/* get it sent as soon as possible */\n-\t\t\tlws_callback_on_writable(wsi);\n-ping_drop:\n-\t\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n-\t\t\thandled \u003d 1;\n-\t\t\tbreak;\n-\n-\t\tcase LWSWSOPC_PONG:\n-\t\t\tlwsl_info(\u0022client receied pong\u005cn\u0022);\n-\t\t\tlwsl_hexdump(\u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n-\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n-\n-\t\t\tif (wsi-\u003epending_timeout \u003d\u003d\n-\t\t\t\t PENDING_TIMEOUT_WS_PONG_CHECK_GET_PONG) {\n-\t\t\t\tlwsl_info(\u0022%p: received expected PONG\u005cn\u0022, wsi);\n-\t\t\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\t\t\t}\n-\n-\t\t\t/* issue it */\n-\t\t\tcallback_action \u003d LWS_CALLBACK_CLIENT_RECEIVE_PONG;\n-\t\t\tbreak;\n-\n-\t\tcase LWSWSOPC_CONTINUATION:\n-\t\tcase LWSWSOPC_TEXT_FRAME:\n-\t\tcase LWSWSOPC_BINARY_FRAME:\n-\t\t\tbreak;\n-\n-\t\tdefault:\n-\n-\t\t\tlwsl_parser(\u0022Reserved opc 0x%2X\u005cn\u0022, wsi-\u003eu.ws.opcode);\n-\n-\t\t\t/*\n-\t\t\t * It's something special we can't understand here.\n-\t\t\t * Pass the payload up to the extension's parsing\n-\t\t\t * state machine.\n-\t\t\t */\n-\n-\t\t\teff_buf.token \u003d \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n-\t\t\teff_buf.token_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n-\n-\t\t\tif (lws_ext_cb_active(wsi,\n-\t\t\t\tLWS_EXT_CB_EXTENDED_PAYLOAD_RX,\n-\t\t\t\t\t\u0026eff_buf, 0) \u003c\u003d 0) {\n-\t\t\t\t/* not handled or failed */\n-\t\t\t\tlwsl_ext(\u0022Unhandled ext opc 0x%x\u005cn\u0022,\n-\t\t\t\t\t wsi-\u003eu.ws.opcode);\n-\t\t\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n-\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t\thandled \u003d 1;\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\t/*\n-\t\t * No it's real payload, pass it up to the user callback.\n-\t\t * It's nicely buffered with the pre-padding taken care of\n-\t\t * so it can be sent straight out again using lws_write\n-\t\t */\n-\t\tif (handled)\n-\t\t\tgoto already_done;\n-\n-\t\teff_buf.token \u003d \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n-\t\teff_buf.token_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n-\n-\t\tif (wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_PONG \u0026\u0026 !eff_buf.token_len)\n-\t\t\tgoto already_done;\n-\n-drain_extension:\n-\t\tlwsl_ext(\u0022%s: passing %d to ext\u005cn\u0022, __func__, eff_buf.token_len);\n-\n-\t\tn \u003d lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, \u0026eff_buf, 0);\n-\t\tlwsl_ext(\u0022Ext RX returned %d\u005cn\u0022, n);\n-\t\tif (n \u003c 0) {\n-\t\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tlwsl_ext(\u0022post inflate eff_buf len %d\u005cn\u0022, eff_buf.token_len);\n-\n-\t\tif (rx_draining_ext \u0026\u0026 !eff_buf.token_len) {\n-\t\t\tlwsl_debug(\u0022 --- ending drain on 0 read result\u005cn\u0022);\n-\t\t\tgoto already_done;\n-\t\t}\n-\n-\t\tif (wsi-\u003eu.ws.check_utf8 \u0026\u0026 !wsi-\u003eu.ws.defeat_check_utf8) {\n-\t\t\tif (lws_check_utf8(\u0026wsi-\u003eu.ws.utf8,\n-\t\t\t\t\t (unsigned char *)eff_buf.token,\n-\t\t\t\t\t eff_buf.token_len))\n-\t\t\t\tgoto utf8_fail;\n-\n-\t\t\t/* we are ending partway through utf-8 character? */\n-\t\t\tif (!wsi-\u003eu.ws.rx_packet_length \u0026\u0026 wsi-\u003eu.ws.final \u0026\u0026\n-\t\t\t wsi-\u003eu.ws.utf8 \u0026\u0026 !n) {\n-\t\t\t\tlwsl_info(\u0022FINAL utf8 error\u005cn\u0022);\n-utf8_fail:\n-\t\t\t\tlwsl_info(\u0022utf8 error\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (eff_buf.token_len \u003c 0 \u0026\u0026\n-\t\t callback_action !\u003d LWS_CALLBACK_CLIENT_RECEIVE_PONG)\n-\t\t\tgoto already_done;\n-\n-\t\tif (!eff_buf.token)\n-\t\t\tgoto already_done;\n-\n-\t\teff_buf.token[eff_buf.token_len] \u003d '\u005c0';\n-\n-\t\tif (!wsi-\u003eprotocol-\u003ecallback)\n-\t\t\tgoto already_done;\n-\n-\t\tif (callback_action \u003d\u003d LWS_CALLBACK_CLIENT_RECEIVE_PONG)\n-\t\t\tlwsl_info(\u0022Client doing pong callback\u005cn\u0022);\n-\n-\t\tif (n \u0026\u0026 eff_buf.token_len)\n-\t\t\t/* extension had more... main loop will come back\n-\t\t\t * we want callback to be done with this set, if so,\n-\t\t\t * because lws_is_final() hides it was final until the\n-\t\t\t * last chunk\n-\t\t\t */\n-\t\t\tlws_add_wsi_to_draining_ext_list(wsi);\n-\t\telse\n-\t\t\tlws_remove_wsi_from_draining_ext_list(wsi);\n-\n-\t\tif (wsi-\u003estate \u003d\u003d LWSS_RETURNED_CLOSE_ALREADY ||\n-\t\t wsi-\u003estate \u003d\u003d LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION ||\n-\t\t wsi-\u003estate \u003d\u003d LWSS_AWAITING_CLOSE_ACK)\n-\t\t\tgoto already_done;\n-\n-\t\tm \u003d wsi-\u003eprotocol-\u003ecallback(wsi,\n-\t\t\t(enum lws_callback_reasons)callback_action,\n-\t\t\twsi-\u003euser_space, eff_buf.token, eff_buf.token_len);\n-\n-\t\t/* if user code wants to close, let caller know */\n-\t\tif (m)\n-\t\t\treturn 1;\n-\n-already_done:\n-\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n-\t\tbreak;\n-\tdefault:\n-\t\tlwsl_err(\u0022client rx illegal state\u005cn\u0022);\n-\t\treturn 1;\n-\t}\n-\n-\treturn 0;\n-\n-illegal_ctl_length:\n-\tlwsl_warn(\u0022Control frame asking for extended length is illegal\u005cn\u0022);\n-\n-\t/* kill the connection */\n-\treturn -1;\n-}\n-\n-\ndiff --git a/lib/client.c b/lib/client.c\ndeleted file mode 100755\nindex b2a4c12..0000000\n--- a/lib/client.c\n+++ /dev/null\n@@ -1,1301 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2014 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-int\n-lws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)\n-{\n-\tint m;\n-\n-\tswitch (wsi-\u003emode) {\n-\tcase LWSCM_WSCL_WAITING_PROXY_REPLY:\n-\tcase LWSCM_WSCL_ISSUE_HANDSHAKE:\n-\tcase LWSCM_WSCL_WAITING_SERVER_REPLY:\n-\tcase LWSCM_WSCL_WAITING_EXTENSION_CONNECT:\n-\tcase LWSCM_WS_CLIENT:\n-\t\twhile (len) {\n-\t\t\t/*\n-\t\t\t * we were accepting input but now we stopped doing so\n-\t\t\t */\n-\t\t\tif (lws_is_flowcontrolled(wsi)) {\n-\t\t\t\tlwsl_debug(\u0022%s: caching %ld\u005cn\u0022, __func__, (long)len);\n-\t\t\t\tlws_rxflow_cache(wsi, *buf, 0, len);\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t\tif (wsi-\u003eu.ws.rx_draining_ext) {\n-#if !defined(LWS_NO_CLIENT)\n-\t\t\t\tif (wsi-\u003emode \u003d\u003d LWSCM_WS_CLIENT)\n-\t\t\t\t\tm \u003d lws_client_rx_sm(wsi, 0);\n-\t\t\t\telse\n-#endif\n-\t\t\t\t\tm \u003d lws_rx_sm(wsi, 0);\n-\t\t\t\tif (m \u003c 0)\n-\t\t\t\t\treturn -1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\t/* account for what we're using in rxflow buffer */\n-\t\t\tif (wsi-\u003erxflow_buffer)\n-\t\t\t\twsi-\u003erxflow_pos++;\n-\n-\t\t\tif (lws_client_rx_sm(wsi, *(*buf)++)) {\n-\t\t\t\tlwsl_debug(\u0022client_rx_sm exited\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\tlen--;\n-\t\t}\n-\t\tlwsl_debug(\u0022%s: finished with %ld\u005cn\u0022, __func__, (long)len);\n-\t\treturn 0;\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN void\n-lws_client_http_body_pending(struct lws *wsi, int something_left_to_send)\n-{\n-\twsi-\u003eclient_http_body_pending \u003d !!something_left_to_send;\n-}\n-\n-int\n-lws_client_socket_service(struct lws_context *context, struct lws *wsi,\n-\t\t\t struct lws_pollfd *pollfd)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tchar *p \u003d (char *)\u0026pt-\u003eserv_buf[0];\n-\tconst char *cce \u003d NULL;\n-\tunsigned char c;\n-\tchar *sb \u003d p;\n-\tint n \u003d 0;\n-\tssize_t len \u003d 0;\n-#if defined(LWS_WITH_SOCKS5)\n-\tchar conn_mode \u003d 0, pending_timeout \u003d 0;\n-#endif\n-\n-\tswitch (wsi-\u003emode) {\n-\n-\tcase LWSCM_WSCL_WAITING_CONNECT:\n-\n-\t\t/*\n-\t\t * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE\n-\t\t * timeout protection set in client-handshake.c\n-\t\t */\n-\n-\t\tif (!lws_client_connect_2(wsi)) {\n-\t\t\t/* closed */\n-\t\t\tlwsl_client(\u0022closed\u005cn\u0022);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\t/* either still pending connection, or changed mode */\n-\t\treturn 0;\n-\n-#if defined(LWS_WITH_SOCKS5)\n-\t/* SOCKS Greeting Reply */\n-\tcase LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY:\n-\tcase LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY:\n-\tcase LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY:\n-\n-\t\t/* handle proxy hung up on us */\n-\n-\t\tif (pollfd-\u003erevents \u0026 LWS_POLLHUP) {\n-\t\t\tlwsl_warn(\u0022SOCKS connection %p (fd\u003d%d) dead\u005cn\u0022,\n-\t\t\t\t (void *)wsi, pollfd-\u003efd);\n-\t\t\tgoto bail3;\n-\t\t}\n-\n-\t\tn \u003d recv(wsi-\u003edesc.sockfd, sb, context-\u003ept_serv_buf_size, 0);\n-\t\tif (n \u003c 0) {\n-\t\t\tif (LWS_ERRNO \u003d\u003d LWS_EAGAIN) {\n-\t\t\t\tlwsl_debug(\u0022SOCKS read EAGAIN, retrying\u005cn\u0022);\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t\tlwsl_err(\u0022ERROR reading from SOCKS socket\u005cn\u0022);\n-\t\t\tgoto bail3;\n-\t\t}\n-\n-\t\tswitch (wsi-\u003emode) {\n-\n-\t\tcase LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY:\n-\t\t\tif (pt-\u003eserv_buf[0] !\u003d SOCKS_VERSION_5)\n-\t\t\t\tgoto socks_reply_fail;\n-\n-\t\t\tif (pt-\u003eserv_buf[1] \u003d\u003d SOCKS_AUTH_NO_AUTH) {\n-\t\t\t\tlwsl_client(\u0022SOCKS greeting reply: No Auth Method\u005cn\u0022);\n-\t\t\t\tsocks_generate_msg(wsi, SOCKS_MSG_CONNECT, \u0026len);\n-\t\t\t\tconn_mode \u003d LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;\n-\t\t\t\tpending_timeout \u003d PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;\n-\t\t\t\tgoto socks_send;\n-\t\t\t}\n-\n-\t\t\tif (pt-\u003eserv_buf[1] \u003d\u003d SOCKS_AUTH_USERNAME_PASSWORD) {\n-\t\t\t\tlwsl_client(\u0022SOCKS greeting reply: User/Pw Method\u005cn\u0022);\n-\t\t\t\tsocks_generate_msg(wsi, SOCKS_MSG_USERNAME_PASSWORD, \u0026len);\n-\t\t\t\tconn_mode \u003d LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY;\n-\t\t\t\tpending_timeout \u003d PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY;\n-\t\t\t\tgoto socks_send;\n-\t\t\t}\n-\t\t\tgoto socks_reply_fail;\n-\n-\t\tcase LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY:\n-\t\t\tif (pt-\u003eserv_buf[0] !\u003d SOCKS_SUBNEGOTIATION_VERSION_1 ||\n-\t\t\t pt-\u003eserv_buf[1] !\u003d SOCKS_SUBNEGOTIATION_STATUS_SUCCESS)\n-\t\t\t\tgoto socks_reply_fail;\n-\n-\t\t\tlwsl_client(\u0022SOCKS password OK, sending connect\u005cn\u0022);\n-\t\t\tsocks_generate_msg(wsi, SOCKS_MSG_CONNECT, \u0026len);\n-\t\t\tconn_mode \u003d LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;\n-\t\t\tpending_timeout \u003d PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;\n-socks_send:\n-\t\t\tn \u003d send(wsi-\u003edesc.sockfd, (char *)pt-\u003eserv_buf, len,\n-\t\t\t\t MSG_NOSIGNAL);\n-\t\t\tif (n \u003c 0) {\n-\t\t\t\tlwsl_debug(\u0022ERROR writing to socks proxy\u005cn\u0022);\n-\t\t\t\tgoto bail3;\n-\t\t\t}\n-\n-\t\t\tlws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);\n-\t\t\twsi-\u003emode \u003d conn_mode;\n-\t\t\tbreak;\n-\n-socks_reply_fail:\n-\t\t\tlwsl_notice(\u0022socks reply: v%d, err %d\u005cn\u0022,\n-\t\t\t\t pt-\u003eserv_buf[0], pt-\u003eserv_buf[1]);\n-\t\t\tgoto bail3;\n-\n-\t\tcase LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY:\n-\t\t\tif (pt-\u003eserv_buf[0] !\u003d SOCKS_VERSION_5 ||\n-\t\t\t pt-\u003eserv_buf[1] !\u003d SOCKS_REQUEST_REPLY_SUCCESS)\n-\t\t\t\tgoto socks_reply_fail;\n-\n-\t\t\tlwsl_client(\u0022socks connect OK\u005cn\u0022);\n-\n-\t\t\t/* free stash since we are done with it */\n-\t\t\tlws_free_set_NULL(wsi-\u003eu.hdr.stash);\n-\t\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,\n-\t\t\t\t\t\t wsi-\u003evhost-\u003esocks_proxy_address))\n-\t\t\t\tgoto bail3;\n-\n-\t\t\twsi-\u003ec_port \u003d wsi-\u003evhost-\u003esocks_proxy_port;\n-\n-\t\t\t/* clear his proxy connection timeout */\n-\t\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\t\t\tgoto start_ws_handshake;\n-\t\t}\n-\t\tbreak;\n-#endif\n-\n-\tcase LWSCM_WSCL_WAITING_PROXY_REPLY:\n-\n-\t\t/* handle proxy hung up on us */\n-\n-\t\tif (pollfd-\u003erevents \u0026 LWS_POLLHUP) {\n-\n-\t\t\tlwsl_warn(\u0022Proxy connection %p (fd\u003d%d) dead\u005cn\u0022,\n-\t\t\t\t (void *)wsi, pollfd-\u003efd);\n-\n-\t\t\tgoto bail3;\n-\t\t}\n-\n-\t\tn \u003d recv(wsi-\u003edesc.sockfd, sb, context-\u003ept_serv_buf_size, 0);\n-\t\tif (n \u003c 0) {\n-\t\t\tif (LWS_ERRNO \u003d\u003d LWS_EAGAIN) {\n-\t\t\t\tlwsl_debug(\u0022Proxy read returned EAGAIN... retrying\u005cn\u0022);\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t\tlwsl_err(\u0022ERROR reading from proxy socket\u005cn\u0022);\n-\t\t\tgoto bail3;\n-\t\t}\n-\n-\t\tpt-\u003eserv_buf[13] \u003d '\u005c0';\n-\t\tif (strcmp(sb, \u0022HTTP/1.0 200 \u0022) \u0026\u0026\n-\t\t strcmp(sb, \u0022HTTP/1.1 200 \u0022)) {\n-\t\t\tlwsl_err(\u0022ERROR proxy: %s\u005cn\u0022, sb);\n-\t\t\tgoto bail3;\n-\t\t}\n-\n-\t\t/* clear his proxy connection timeout */\n-\n-\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\n-\t\t/* fallthru */\n-\n-\tcase LWSCM_WSCL_ISSUE_HANDSHAKE:\n-\n-\t\t/*\n-\t\t * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE\n-\t\t * timeout protection set in client-handshake.c\n-\t\t *\n-\t\t * take care of our lws_callback_on_writable\n-\t\t * happening at a time when there's no real connection yet\n-\t\t */\n-#if defined(LWS_WITH_SOCKS5)\n-start_ws_handshake:\n-#endif\n-\t\tif (lws_change_pollfd(wsi, LWS_POLLOUT, 0))\n-\t\t\treturn -1;\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\t\t/* we can retry this... just cook the SSL BIO the first time */\n-\n-\t\tif (wsi-\u003euse_ssl \u0026\u0026 !wsi-\u003essl) {\n-\t\t\tif (lws_ssl_client_bio_create(wsi))\n-\t\t\t\treturn -1;\n-\t\t}\n-\n-\t\tif (wsi-\u003euse_ssl) {\n-\t\t\tn \u003d lws_ssl_client_connect1(wsi);\n-\t\t\tif (!n)\n-\t\t\t\treturn 0;\n-\t\t\tif (n \u003c 0) {\n-\t\t\t\tcce \u003d \u0022lws_ssl_client_connect1 failed\u0022;\n-\t\t\t\tgoto bail3;\n-\t\t\t}\n-\t\t} else\n-\t\t\twsi-\u003essl \u003d NULL;\n-\n-\t\t/* fallthru */\n-\n-\tcase LWSCM_WSCL_WAITING_SSL:\n-\n-\t\tif (wsi-\u003euse_ssl) {\n-\t\t\tn \u003d lws_ssl_client_connect2(wsi);\n-\t\t\tif (!n)\n-\t\t\t\treturn 0;\n-\t\t\tif (n \u003c 0) {\n-\t\t\t\tcce \u003d \u0022lws_ssl_client_connect2 failed\u0022;\n-\t\t\t\tgoto bail3;\n-\t\t\t}\n-\t\t} else\n-\t\t\twsi-\u003essl \u003d NULL;\n-#endif\n-\n-\t\twsi-\u003emode \u003d LWSCM_WSCL_ISSUE_HANDSHAKE2;\n-\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,\n-\t\t\t\tcontext-\u003etimeout_secs);\n-\n-\t\t/* fallthru */\n-\n-\tcase LWSCM_WSCL_ISSUE_HANDSHAKE2:\n-\t\tp \u003d lws_generate_client_handshake(wsi, p);\n-\t\tif (p \u003d\u003d NULL) {\n-\t\t\tif (wsi-\u003emode \u003d\u003d LWSCM_RAW)\n-\t\t\t\treturn 0;\n-\n-\t\t\tlwsl_err(\u0022Failed to generate handshake for client\u005cn\u0022);\n-\t\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\t\t\treturn 0;\n-\t\t}\n-\n-\t\t/* send our request to the server */\n-\t\tlws_latency_pre(context, wsi);\n-\n-\t\tn \u003d lws_ssl_capable_write(wsi, (unsigned char *)sb, p - sb);\n-\t\tlws_latency(context, wsi, \u0022send lws_issue_raw\u0022, n,\n-\t\t\t n \u003d\u003d p - sb);\n-\t\tswitch (n) {\n-\t\tcase LWS_SSL_CAPABLE_ERROR:\n-\t\t\tlwsl_debug(\u0022ERROR writing to client socket\u005cn\u0022);\n-\t\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\t\t\treturn 0;\n-\t\tcase LWS_SSL_CAPABLE_MORE_SERVICE:\n-\t\t\tlws_callback_on_writable(wsi);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (wsi-\u003eclient_http_body_pending) {\n-\t\t\twsi-\u003emode \u003d LWSCM_WSCL_ISSUE_HTTP_BODY;\n-\t\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,\n-\t\t\t\t\tcontext-\u003etimeout_secs);\n-\t\t\t/* user code must ask for writable callback */\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tgoto client_http_body_sent;\n-\n-\tcase LWSCM_WSCL_ISSUE_HTTP_BODY:\n-\t\tif (wsi-\u003eclient_http_body_pending) {\n-\t\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,\n-\t\t\t\t\tcontext-\u003etimeout_secs);\n-\t\t\t/* user code must ask for writable callback */\n-\t\t\tbreak;\n-\t\t}\n-client_http_body_sent:\n-\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_NAME_PART;\n-\t\twsi-\u003eu.hdr.lextable_pos \u003d 0;\n-\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SERVER_REPLY;\n-\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,\n-\t\t\t\tcontext-\u003etimeout_secs);\n-\t\tbreak;\n-\n-\tcase LWSCM_WSCL_WAITING_SERVER_REPLY:\n-\t\t/*\n-\t\t * handle server hanging up on us...\n-\t\t * but if there is POLLIN waiting, handle that first\n-\t\t */\n-\t\tif ((pollfd-\u003erevents \u0026 (LWS_POLLIN | LWS_POLLHUP)) \u003d\u003d\n-\t\t\t\t\t\t\t\tLWS_POLLHUP) {\n-\n-\t\t\tlwsl_debug(\u0022Server connection %p (fd\u003d%d) dead\u005cn\u0022,\n-\t\t\t\t(void *)wsi, pollfd-\u003efd);\n-\t\t\tcce \u003d \u0022Peer hung up\u0022;\n-\t\t\tgoto bail3;\n-\t\t}\n-\n-\t\tif (!(pollfd-\u003erevents \u0026 LWS_POLLIN))\n-\t\t\tbreak;\n-\n-\t\t/* interpret the server response\n-\t\t *\n-\t\t * HTTP/1.1 101 Switching Protocols\n-\t\t * Upgrade: websocket\n-\t\t * Connection: Upgrade\n-\t\t * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo\u003d\n-\t\t * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC\u003d\u003d\n-\t\t * Sec-WebSocket-Protocol: chat\n-\t\t *\n-\t\t * we have to take some care here to only take from the\n-\t\t * socket bytewise. The browser may (and has been seen to\n-\t\t * in the case that onopen() performs websocket traffic)\n-\t\t * coalesce both handshake response and websocket traffic\n-\t\t * in one packet, since at that point the connection is\n-\t\t * definitively ready from browser pov.\n-\t\t */\n-\t\tlen \u003d 1;\n-\t\twhile (wsi-\u003eu.hdr.parser_state !\u003d WSI_PARSING_COMPLETE \u0026\u0026\n-\t\t len \u003e 0) {\n-\t\t\tn \u003d lws_ssl_capable_read(wsi, \u0026c, 1);\n-\t\t\tlws_latency(context, wsi, \u0022send lws_issue_raw\u0022, n,\n-\t\t\t\t n \u003d\u003d 1);\n-\t\t\tswitch (n) {\n-\t\t\tcase 0:\n-\t\t\tcase LWS_SSL_CAPABLE_ERROR:\n-\t\t\t\tcce \u003d \u0022read failed\u0022;\n-\t\t\t\tgoto bail3;\n-\t\t\tcase LWS_SSL_CAPABLE_MORE_SERVICE:\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\n-\t\t\tif (lws_parse(wsi, c)) {\n-\t\t\t\tlwsl_warn(\u0022problems parsing header\u005cn\u0022);\n-\t\t\t\tgoto bail3;\n-\t\t\t}\n-\t\t}\n-\n-\t\t/*\n-\t\t * hs may also be coming in multiple packets, there is a 5-sec\n-\t\t * libwebsocket timeout still active here too, so if parsing did\n-\t\t * not complete just wait for next packet coming in this state\n-\t\t */\n-\t\tif (wsi-\u003eu.hdr.parser_state !\u003d WSI_PARSING_COMPLETE)\n-\t\t\tbreak;\n-\n-\t\t/*\n-\t\t * otherwise deal with the handshake. If there's any\n-\t\t * packet traffic already arrived we'll trigger poll() again\n-\t\t * right away and deal with it that way\n-\t\t */\n-\t\treturn lws_client_interpret_server_handshake(wsi);\n-\n-bail3:\n-\t\tlwsl_info(\u0022closing conn at LWS_CONNMODE...SERVER_REPLY\u005cn\u0022);\n-\t\tif (cce)\n-\t\t\tlwsl_info(\u0022reason: %s\u005cn\u0022, cce);\n-\t\twsi-\u003eprotocol-\u003ecallback(wsi,\n-\t\t\tLWS_CALLBACK_CLIENT_CONNECTION_ERROR,\n-\t\t\twsi-\u003euser_space, (void *)cce, cce ? strlen(cce) : 0);\n-\t\twsi-\u003ealready_did_cce \u003d 1;\n-\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\t\treturn -1;\n-\n-\tcase LWSCM_WSCL_WAITING_EXTENSION_CONNECT:\n-\t\tlwsl_ext(\u0022LWSCM_WSCL_WAITING_EXTENSION_CONNECT\u005cn\u0022);\n-\t\tbreak;\n-\n-\tcase LWSCM_WSCL_PENDING_CANDIDATE_CHILD:\n-\t\tlwsl_ext(\u0022LWSCM_WSCL_PENDING_CANDIDATE_CHILD\u005cn\u0022);\n-\t\tbreak;\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-/*\n- * In-place str to lower case\n- */\n-\n-static void\n-strtolower(char *s)\n-{\n-\twhile (*s) {\n-#ifdef LWS_PLAT_OPTEE\n-\t\tint tolower_optee(int c);\n-\t\t*s \u003d tolower_optee((int)*s);\n-#else\n-\t\t*s \u003d tolower((int)*s);\n-#endif\n-\t\ts++;\n-\t}\n-}\n-\n-int LWS_WARN_UNUSED_RESULT\n-lws_http_transaction_completed_client(struct lws *wsi)\n-{\n-\tlwsl_debug(\u0022%s: wsi %p\u005cn\u0022, __func__, wsi);\n-\t/* if we can't go back to accept new headers, drop the connection */\n-\tif (wsi-\u003eu.http.connection_type !\u003d HTTP_CONNECTION_KEEP_ALIVE) {\n-\t\tlwsl_info(\u0022%s: %p: close connection\u005cn\u0022, __func__, wsi);\n-\t\treturn 1;\n-\t}\n-\n-\t/* we don't support chained client connections yet */\n-\treturn 1;\n-#if 0\n-\t/* otherwise set ourselves up ready to go again */\n-\twsi-\u003estate \u003d LWSS_CLIENT_HTTP_ESTABLISHED;\n-\twsi-\u003emode \u003d LWSCM_HTTP_CLIENT_ACCEPTED;\n-\twsi-\u003eu.http.rx_content_length \u003d 0;\n-\twsi-\u003ehdr_parsing_completed \u003d 0;\n-\n-\t/* He asked for it to stay alive indefinitely */\n-\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\n-\t/*\n-\t * As client, nothing new is going to come until we ask for it\n-\t * we can drop the ah, if any\n-\t */\n-\tif (wsi-\u003eu.hdr.ah) {\n-\t\tlws_header_table_force_to_detachable_state(wsi);\n-\t\tlws_header_table_detach(wsi, 0);\n-\t}\n-\n-\t/* If we're (re)starting on headers, need other implied init */\n-\twsi-\u003eu.hdr.ues \u003d URIES_IDLE;\n-\n-\tlwsl_info(\u0022%s: %p: keep-alive await new transaction\u005cn\u0022, __func__, wsi);\n-\n-\treturn 0;\n-#endif\n-}\n-\n-LWS_VISIBLE LWS_EXTERN unsigned int\n-lws_http_client_http_response(struct lws *wsi)\n-{\n-\tif (!wsi-\u003eu.http.ah)\n-\t\treturn 0;\n-\n-\treturn wsi-\u003eu.http.ah-\u003ehttp_response;\n-}\n-\n-int\n-lws_client_interpret_server_handshake(struct lws *wsi)\n-{\n-\tint n, len, okay \u003d 0, port \u003d 0, ssl \u003d 0;\n-\tint close_reason \u003d LWS_CLOSE_STATUS_PROTOCOL_ERR;\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tconst char *pc, *prot, *ads \u003d NULL, *path, *cce \u003d NULL;\n-\tstruct allocated_headers *ah \u003d NULL;\n-\tchar *p, *q;\n-\tchar new_path[300];\n-#ifndef LWS_NO_EXTENSIONS\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tchar *sb \u003d (char *)\u0026pt-\u003eserv_buf[0];\n-\tconst struct lws_ext_options *opts;\n-\tconst struct lws_extension *ext;\n-\tchar ext_name[128];\n-\tconst char *c, *a;\n-\tchar ignore;\n-\tint more \u003d 1;\n-\tvoid *v;\n-#endif\n-\tif (wsi-\u003eu.hdr.stash)\n-\t\tlws_free_set_NULL(wsi-\u003eu.hdr.stash);\n-\n-\tah \u003d wsi-\u003eu.hdr.ah;\n-\tif (!wsi-\u003edo_ws) {\n-\t\t/* we are being an http client...\n-\t\t */\n-\t\tlws_union_transition(wsi, LWSCM_HTTP_CLIENT_ACCEPTED);\n-\t\twsi-\u003estate \u003d LWSS_CLIENT_HTTP_ESTABLISHED;\n-\t\twsi-\u003eu.http.ah \u003d ah;\n-\t\tah-\u003ehttp_response \u003d 0;\n-\t}\n-\n-\t/*\n-\t * well, what the server sent looked reasonable for syntax.\n-\t * Now let's confirm it sent all the necessary headers\n-\t *\n-\t * http (non-ws) client will expect something like this\n-\t *\n-\t * HTTP/1.0.200\n-\t * server:.libwebsockets\n-\t * content-type:.text/html\n-\t * content-length:.17703\n-\t * set-cookie:.test\u003dLWS_1456736240_336776_COOKIE;Max-Age\u003d360000\n-\t *\n-\t *\n-\t *\n-\t */\n-\n-\twsi-\u003eu.http.connection_type \u003d HTTP_CONNECTION_KEEP_ALIVE;\n-\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);\n-\tif (wsi-\u003edo_ws \u0026\u0026 !p) {\n-\t\tlwsl_info(\u0022no URI\u005cn\u0022);\n-\t\tcce \u003d \u0022HS: URI missing\u0022;\n-\t\tgoto bail3;\n-\t}\n-\tif (!p) {\n-\t\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP1_0);\n-\t\twsi-\u003eu.http.connection_type \u003d HTTP_CONNECTION_CLOSE;\n-\t}\n-\tif (!p) {\n-\t\tcce \u003d \u0022HS: URI missing\u0022;\n-\t\tlwsl_info(\u0022no URI\u005cn\u0022);\n-\t\tgoto bail3;\n-\t}\n-\tn \u003d atoi(p);\n-\tif (ah)\n-\t\tah-\u003ehttp_response \u003d n;\n-\n-\tif (n \u003d\u003d 301 || n \u003d\u003d 302 || n \u003d\u003d 303 || n \u003d\u003d 307 || n \u003d\u003d 308) {\n-\t\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);\n-\t\tif (!p) {\n-\t\t\tcce \u003d \u0022HS: Redirect code but no Location\u0022;\n-\t\t\tgoto bail3;\n-\t\t}\n-\n-\t\t/* Relative reference absolute path */\n-\t\tif (p[0] \u003d\u003d '/')\n-\t\t{\n-#ifdef LWS_OPENSSL_SUPPORT\n-\t\t\tssl \u003d wsi-\u003euse_ssl;\n-#endif\n-\t\t\tads \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);\n-\t\t\tport \u003d wsi-\u003ec_port;\n-\t\t\tpath \u003d p + 1; /* +1 as lws_client_reset expects leading / to be omitted */\n-\t\t}\n-\t\t/* Absolute (Full) URI */\n-\t\telse if (strchr(p, ':'))\n-\t\t{\n-\t\t\tif (lws_parse_uri(p, \u0026prot, \u0026ads, \u0026port, \u0026path)) {\n-\t\t\t\tcce \u003d \u0022HS: URI did not parse\u0022;\n-\t\t\t\tgoto bail3;\n-\t\t\t}\n-\n-\t\t\tif (!strcmp(prot, \u0022wss\u0022) || !strcmp(prot, \u0022https\u0022))\n-\t\t\t\tssl \u003d 1;\n-\t\t}\n-\t\t/* Relative reference relative path */\n-\t\telse\n-\t\t{\n-\t\t\t/* This doesn't try to calculate an absolute path, that will be left to the server */\n-#ifdef LWS_OPENSSL_SUPPORT\n-\t\t\tssl \u003d wsi-\u003euse_ssl;\n-#endif\n-\t\t\tads \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);\n-\t\t\tport \u003d wsi-\u003ec_port;\n-\t\t\tpath \u003d new_path + 1; /* +1 as lws_client_reset expects leading / to be omitted */\n-\t\t\tstrncpy(new_path, lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI), sizeof(new_path));\n-\t\t\tnew_path[sizeof(new_path) - 1] \u003d '\u005c0';\n-\t\t\tq \u003d strrchr(new_path, '/');\n-\t\t\tif (q)\n-\t\t\t{\n-\t\t\t\tstrncpy(q + 1, p, sizeof(new_path) - (q - new_path) - 1);\n-\t\t\t\tnew_path[sizeof(new_path) - 1] \u003d '\u005c0';\n-\t\t\t}\n-\t\t\telse\n-\t\t\t{\n-\t\t\t\tpath \u003d p;\n-\t\t\t}\n-\t\t}\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\t\tif (wsi-\u003euse_ssl \u0026\u0026 !ssl) {\n-\t\t\tcce \u003d \u0022HS: Redirect attempted SSL downgrade\u0022;\n-\t\t\tgoto bail3;\n-\t\t}\n-#endif\n-\n-\t\tif (!lws_client_reset(\u0026wsi, ssl, ads, port, path, ads)) {\n-\t\t\t/* there are two ways to fail out with NULL return...\n-\t\t\t * simple, early problem where the wsi is intact, or\n-\t\t\t * we went through with the reconnect attempt and the\n-\t\t\t * wsi is already closed. In the latter case, the wsi\n-\t\t\t * has beet set to NULL additionally.\n-\t\t\t */\n-\t\t\tlwsl_err(\u0022Redirect failed\u005cn\u0022);\n-\t\t\tcce \u003d \u0022HS: Redirect failed\u0022;\n-\t\t\tif (wsi)\n-\t\t\t\tgoto bail3;\n-\n-\t\t\treturn 1;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\n-\tif (!wsi-\u003edo_ws) {\n-\t\tif (n !\u003d 200 \u0026\u0026 n !\u003d 201 \u0026\u0026 n !\u003d 304 \u0026\u0026 n !\u003d 401) {\n-\t\t\tlwsl_notice(\u0022Connection failed with code %d\u005cn\u0022, n);\n-\t\t\tcce \u003d \u0022HS: Server unrecognized response code\u0022;\n-\t\t\tgoto bail2;\n-\t\t}\n-\n-#ifdef LWS_WITH_HTTP_PROXY\n-\t\twsi-\u003eperform_rewrite \u003d 0;\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {\n-\t\t\tif (!strncmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE),\n-\t\t\t\t \u0022text/html\u0022, 9))\n-\t\t\t\twsi-\u003eperform_rewrite \u003d 1;\n-\t\t}\n-#endif\n-\n-\t\t/* allocate the per-connection user memory (if any) */\n-\t\tif (lws_ensure_user_space(wsi)) {\n-\t\t\tlwsl_err(\u0022Problem allocating wsi user mem\u005cn\u0022);\n-\t\t\tcce \u003d \u0022HS: OOM\u0022;\n-\t\t\tgoto bail2;\n-\t\t}\n-\n-\t\t/* he may choose to send us stuff in chunked transfer-coding */\n-\t\twsi-\u003echunked \u003d 0;\n-\t\twsi-\u003echunk_remaining \u003d 0; /* ie, next thing is chunk size */\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING)) {\n-\t\t\twsi-\u003echunked \u003d !strcmp(lws_hdr_simple_ptr(wsi,\n-\t\t\t\t\t WSI_TOKEN_HTTP_TRANSFER_ENCODING),\n-\t\t\t\t\t\u0022chunked\u0022);\n-\t\t\t/* first thing is hex, after payload there is crlf */\n-\t\t\twsi-\u003echunk_parser \u003d ELCP_HEX;\n-\t\t}\n-\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n-\t\t\twsi-\u003eu.http.rx_content_length \u003d\n-\t\t\t\t\tatoll(lws_hdr_simple_ptr(wsi,\n-\t\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_LENGTH));\n-\t\t\tlwsl_notice(\u0022%s: incoming content length %llu\u005cn\u0022, __func__,\n-\t\t\t\t\t(unsigned long long)wsi-\u003eu.http.rx_content_length);\n-\t\t\twsi-\u003eu.http.rx_content_remain \u003d wsi-\u003eu.http.rx_content_length;\n-\t\t} else /* can't do 1.1 without a content length or chunked */\n-\t\t\tif (!wsi-\u003echunked)\n-\t\t\t\twsi-\u003eu.http.connection_type \u003d HTTP_CONNECTION_CLOSE;\n-\n-\t\t/*\n-\t\t * we seem to be good to go, give client last chance to check\n-\t\t * headers and OK it\n-\t\t */\n-\t\tif (wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,\n-\t\t\t\t\t wsi-\u003euser_space, NULL, 0)) {\n-\n-\t\t\tcce \u003d \u0022HS: disallowed by client filter\u0022;\n-\t\t\tgoto bail2;\n-\t\t}\n-\n-\t\t/* clear his proxy connection timeout */\n-\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\n-\t\twsi-\u003erxflow_change_to \u003d LWS_RXFLOW_ALLOW;\n-\n-\t\t/* call him back to inform him he is up */\n-\t\tif (wsi-\u003eprotocol-\u003ecallback(wsi,\n-\t\t\t\t\t LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,\n-\t\t\t\t\t wsi-\u003euser_space, NULL, 0)) {\n-\t\t\tcce \u003d \u0022HS: disallowed at ESTABLISHED\u0022;\n-\t\t\tgoto bail3;\n-\t\t}\n-\n-\t\t/* free up his parsing allocations */\n-\t\tlws_header_table_detach(wsi, 0);\n-\n-\t\tlwsl_notice(\u0022%s: client connection up\u005cn\u0022, __func__);\n-\n-\t\treturn 0;\n-\t}\n-\n-\tif (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) \u003d\u003d 0) {\n-\t\tlwsl_info(\u0022no ACCEPT\u005cn\u0022);\n-\t\tcce \u003d \u0022HS: ACCEPT missing\u0022;\n-\t\tgoto bail3;\n-\t}\n-\n-\tif (p \u0026\u0026 strncmp(p, \u0022101\u0022, 3)) {\n-\t\tlwsl_warn(\n-\t\t \u0022lws_client_handshake: got bad HTTP response '%s'\u005cn\u0022, p);\n-\t\tcce \u003d \u0022HS: ws upgrade response not 101\u0022;\n-\t\tgoto bail3;\n-\t}\n-\n-\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE);\n-\tif (!p) {\n-\t\tlwsl_info(\u0022no UPGRADE\u005cn\u0022);\n-\t\tcce \u003d \u0022HS: UPGRADE missing\u0022;\n-\t\tgoto bail3;\n-\t}\n-\tstrtolower(p);\n-\tif (strcmp(p, \u0022websocket\u0022)) {\n-\t\tlwsl_warn(\n-\t\t \u0022lws_client_handshake: got bad Upgrade header '%s'\u005cn\u0022, p);\n-\t\tcce \u003d \u0022HS: Upgrade to something other than websocket\u0022;\n-\t\tgoto bail3;\n-\t}\n-\n-\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_CONNECTION);\n-\tif (!p) {\n-\t\tlwsl_info(\u0022no Connection hdr\u005cn\u0022);\n-\t\tcce \u003d \u0022HS: CONNECTION missing\u0022;\n-\t\tgoto bail3;\n-\t}\n-\tstrtolower(p);\n-\tif (strcmp(p, \u0022upgrade\u0022)) {\n-\t\tlwsl_warn(\u0022lws_client_int_s_hs: bad header %s\u005cn\u0022, p);\n-\t\tcce \u003d \u0022HS: UPGRADE malformed\u0022;\n-\t\tgoto bail3;\n-\t}\n-\n-\tpc \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);\n-\tif (!pc) {\n-\t\tlwsl_parser(\u0022lws_client_int_s_hs: no protocol list\u005cn\u0022);\n-\t} else\n-\t\tlwsl_parser(\u0022lws_client_int_s_hs: protocol list '%s'\u005cn\u0022, pc);\n-\n-\t/*\n-\t * confirm the protocol the server wants to talk was in the list\n-\t * of protocols we offered\n-\t */\n-\n-\tlen \u003d lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);\n-\tif (!len) {\n-\t\tlwsl_info(\u0022lws_client_int_s_hs: WSI_TOKEN_PROTOCOL is null\u005cn\u0022);\n-\t\t/*\n-\t\t * no protocol name to work from,\n-\t\t * default to first protocol\n-\t\t */\n-\t\tn \u003d 0;\n-\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[0];\n-\t\tgoto check_extensions;\n-\t}\n-\n-\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);\n-\tlen \u003d strlen(p);\n-\n-\twhile (pc \u0026\u0026 *pc \u0026\u0026 !okay) {\n-\t\tif (!strncmp(pc, p, len) \u0026\u0026\n-\t\t (pc[len] \u003d\u003d ',' || pc[len] \u003d\u003d '\u005c0')) {\n-\t\t\tokay \u003d 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\twhile (*pc \u0026\u0026 *pc++ !\u003d ',')\n-\t\t\t;\n-\t\twhile (*pc \u0026\u0026 *pc \u003d\u003d ' ')\n-\t\t\tpc++;\n-\t}\n-\n-\tif (!okay) {\n-\t\tlwsl_err(\u0022lws_client_int_s_hs: got bad protocol %s\u005cn\u0022, p);\n-\t\tcce \u003d \u0022HS: PROTOCOL malformed\u0022;\n-\t\tgoto bail2;\n-\t}\n-\n-\t/*\n-\t * identify the selected protocol struct and set it\n-\t */\n-\tn \u003d 0;\n-\twsi-\u003eprotocol \u003d NULL;\n-\twhile (wsi-\u003evhost-\u003eprotocols[n].callback \u0026\u0026 !wsi-\u003eprotocol) {\n-\t\tif (strcmp(p, wsi-\u003evhost-\u003eprotocols[n].name) \u003d\u003d 0) {\n-\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[n];\n-\t\t\tbreak;\n-\t\t}\n-\t\tn++;\n-\t}\n-\n-\tif (wsi-\u003eprotocol \u003d\u003d NULL) {\n-\t\tlwsl_err(\u0022lws_client_int_s_hs: fail protocol %s\u005cn\u0022, p);\n-\t\tcce \u003d \u0022HS: Cannot match protocol\u0022;\n-\t\tgoto bail2;\n-\t}\n-\n-check_extensions:\n-\t/*\n-\t * stitch protocol choice into the vh protocol linked list\n-\t * We always insert ourselves at the start of the list\n-\t *\n-\t * X \u003c-\u003e B\n-\t * X \u003c-\u003e pAn \u003c-\u003e pB\n-\t */\n-\t//lwsl_err(\u0022%s: pre insert vhost start wsi %p, that wsi prev \u003d\u003d %p\u005cn\u0022,\n-\t//\t\t__func__,\n-\t//\t\twsi-\u003evhost-\u003esame_vh_protocol_list[n],\n-\t//\t\twsi-\u003esame_vh_protocol_prev);\n-\twsi-\u003esame_vh_protocol_prev \u003d /* guy who points to us */\n-\t\t\u0026wsi-\u003evhost-\u003esame_vh_protocol_list[n];\n-\twsi-\u003esame_vh_protocol_next \u003d /* old first guy is our next */\n-\t\t\twsi-\u003evhost-\u003esame_vh_protocol_list[n];\n-\t/* we become the new first guy */\n-\twsi-\u003evhost-\u003esame_vh_protocol_list[n] \u003d wsi;\n-\n-\tif (wsi-\u003esame_vh_protocol_next)\n-\t\t/* old first guy points back to us now */\n-\t\twsi-\u003esame_vh_protocol_next-\u003esame_vh_protocol_prev \u003d\n-\t\t\t\t\u0026wsi-\u003esame_vh_protocol_next;\n-\n-#ifndef LWS_NO_EXTENSIONS\n-\t/* instantiate the accepted extensions */\n-\n-\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {\n-\t\tlwsl_ext(\u0022no client extensions allowed by server\u005cn\u0022);\n-\t\tgoto check_accept;\n-\t}\n-\n-\t/*\n-\t * break down the list of server accepted extensions\n-\t * and go through matching them or identifying bogons\n-\t */\n-\n-\tif (lws_hdr_copy(wsi, sb, context-\u003ept_serv_buf_size, WSI_TOKEN_EXTENSIONS) \u003c 0) {\n-\t\tlwsl_warn(\u0022ext list from server failed to copy\u005cn\u0022);\n-\t\tcce \u003d \u0022HS: EXT: list too big\u0022;\n-\t\tgoto bail2;\n-\t}\n-\n-\tc \u003d sb;\n-\tn \u003d 0;\n-\tignore \u003d 0;\n-\ta \u003d NULL;\n-\twhile (more) {\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 (!a)\n-\t\t\t\t\ta \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-\n-\t\t\text_name[n] \u003d *c++;\n-\t\t\tif (n \u003c sizeof(ext_name) - 1)\n-\t\t\t\tn++;\n-\t\t\tcontinue;\n-\t\t}\n-\t\text_name[n] \u003d '\u005c0';\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\t/* check we actually support it */\n-\n-\t\tlwsl_notice(\u0022checking client ext %s\u005cn\u0022, ext_name);\n-\n-\t\tn \u003d 0;\n-\t\text \u003d wsi-\u003evhost-\u003eextensions;\n-\t\twhile (ext \u0026\u0026 ext-\u003ecallback) {\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\tn \u003d 1;\n-\t\t\tlwsl_notice(\u0022instantiating client ext %s\u005cn\u0022, ext_name);\n-\n-\t\t\t/* instantiate the extension on this conn */\n-\n-\t\t\twsi-\u003eactive_extensions[wsi-\u003ecount_act_ext] \u003d ext;\n-\n-\t\t\t/* allow him to construct his ext instance */\n-\n-\t\t\tif (ext-\u003ecallback(lws_get_context(wsi), ext, wsi,\n-\t\t\t\t LWS_EXT_CB_CLIENT_CONSTRUCT,\n-\t\t\t\t (void *)\u0026wsi-\u003eact_ext_user[wsi-\u003ecount_act_ext],\n-\t\t\t\t (void *)\u0026opts, 0)) {\n-\t\t\t\tlwsl_info(\u0022 ext %s failed construction\u005cn\u0022, ext_name);\n-\t\t\t\text++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\n-\t\t\t/*\n-\t\t\t * allow the user code to override ext defaults if it\n-\t\t\t * wants to\n-\t\t\t */\n-\t\t\text_name[0] \u003d '\u005c0';\n-\t\t\tif (user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback,\n-\t\t\t\t\twsi, LWS_CALLBACK_WS_EXT_DEFAULTS,\n-\t\t\t\t\t(char *)ext-\u003ename, ext_name,\n-\t\t\t\t\tsizeof(ext_name))) {\n-\t\t\t\tcce \u003d \u0022HS: EXT: failed setting defaults\u0022;\n-\t\t\t\tgoto bail2;\n-\t\t\t}\n-\n-\t\t\tif (ext_name[0] \u0026\u0026\n-\t\t\t lws_ext_parse_options(ext, wsi, wsi-\u003eact_ext_user[\n-\t\t\t\t\t\t wsi-\u003ecount_act_ext], opts, ext_name,\n-\t\t\t\t\t\t strlen(ext_name))) {\n-\t\t\t\tlwsl_err(\u0022%s: unable to parse user defaults '%s'\u0022,\n-\t\t\t\t\t __func__, ext_name);\n-\t\t\t\tcce \u003d \u0022HS: EXT: failed parsing defaults\u0022;\n-\t\t\t\tgoto bail2;\n-\t\t\t}\n-\n-\t\t\t/*\n-\t\t\t * give the extension the server options\n-\t\t\t */\n-\t\t\tif (a \u0026\u0026 lws_ext_parse_options(ext, wsi,\n-\t\t\t\t\twsi-\u003eact_ext_user[wsi-\u003ecount_act_ext],\n-\t\t\t\t\topts, a, c - a)) {\n-\t\t\t\tlwsl_err(\u0022%s: unable to parse remote def '%s'\u0022,\n-\t\t\t\t\t __func__, a);\n-\t\t\t\tcce \u003d \u0022HS: EXT: failed parsing options\u0022;\n-\t\t\t\tgoto bail2;\n-\t\t\t}\n-\n-\t\t\tif (ext-\u003ecallback(lws_get_context(wsi), ext, wsi,\n-\t\t\t\t\tLWS_EXT_CB_OPTION_CONFIRM,\n-\t\t\t\t wsi-\u003eact_ext_user[wsi-\u003ecount_act_ext],\n-\t\t\t\t NULL, 0)) {\n-\t\t\t\tlwsl_err(\u0022%s: ext %s rejects server options %s\u0022,\n-\t\t\t\t\t __func__, ext-\u003ename, a);\n-\t\t\t\tcce \u003d \u0022HS: EXT: Rejects server options\u0022;\n-\t\t\t\tgoto bail2;\n-\t\t\t}\n-\n-\t\t\twsi-\u003ecount_act_ext++;\n-\n-\t\t\text++;\n-\t\t}\n-\n-\t\tif (n \u003d\u003d 0) {\n-\t\t\tlwsl_warn(\u0022Unknown ext '%s'!\u005cn\u0022, ext_name);\n-\t\t\tcce \u003d \u0022HS: EXT: unknown ext\u0022;\n-\t\t\tgoto bail2;\n-\t\t}\n-\n-\t\ta \u003d NULL;\n-\t\tn \u003d 0;\n-\t}\n-\n-check_accept:\n-#endif\n-\n-\t/*\n-\t * Confirm his accept token is the one we precomputed\n-\t */\n-\n-\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT);\n-\tif (strcmp(p, wsi-\u003eu.hdr.ah-\u003einitial_handshake_hash_base64)) {\n-\t\tlwsl_warn(\u0022lws_client_int_s_hs: accept '%s' wrong vs '%s'\u005cn\u0022, p,\n-\t\t\t\t wsi-\u003eu.hdr.ah-\u003einitial_handshake_hash_base64);\n-\t\tcce \u003d \u0022HS: Accept hash wrong\u0022;\n-\t\tgoto bail2;\n-\t}\n-\n-\t/* allocate the per-connection user memory (if any) */\n-\tif (lws_ensure_user_space(wsi)) {\n-\t\tlwsl_err(\u0022Problem allocating wsi user mem\u005cn\u0022);\n-\t\tcce \u003d \u0022HS: OOM\u0022;\n-\t\tgoto bail2;\n-\t}\n-\n-\t/*\n-\t * we seem to be good to go, give client last chance to check\n-\t * headers and OK it\n-\t */\n-\tif (wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,\n-\t\t\t\t wsi-\u003euser_space, NULL, 0)) {\n-\t\tcce \u003d \u0022HS: Rejected by filter cb\u0022;\n-\t\tgoto bail2;\n-\t}\n-\n-\t/* clear his proxy connection timeout */\n-\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\n-\t/* free up his parsing allocations */\n-\tlws_header_table_detach(wsi, 0);\n-\n-\tlws_union_transition(wsi, LWSCM_WS_CLIENT);\n-\twsi-\u003estate \u003d LWSS_ESTABLISHED;\n-\tlws_restart_ws_ping_pong_timer(wsi);\n-\n-\twsi-\u003erxflow_change_to \u003d LWS_RXFLOW_ALLOW;\n-\n-\t/*\n-\t * create the frame buffer for this connection according to the\n-\t * size mentioned in the protocol definition. If 0 there, then\n-\t * use a big default for compatibility\n-\t */\n-\tn \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n-\tif (!n)\n-\t\tn \u003d context-\u003ept_serv_buf_size;\n-\tn +\u003d LWS_PRE;\n-\twsi-\u003eu.ws.rx_ubuf \u003d lws_malloc(n + 4 /* 0x0000ffff zlib */, \u0022client frame buffer\u0022);\n-\tif (!wsi-\u003eu.ws.rx_ubuf) {\n-\t\tlwsl_err(\u0022Out of Mem allocating rx buffer %d\u005cn\u0022, n);\n-\t\tcce \u003d \u0022HS: OOM\u0022;\n-\t\tgoto bail2;\n-\t}\n- wsi-\u003eu.ws.rx_ubuf_alloc \u003d n;\n-\tlwsl_info(\u0022Allocating client RX buffer %d\u005cn\u0022, n);\n-\n-#if !defined(LWS_WITH_ESP32)\n-\tif (setsockopt(wsi-\u003edesc.sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)\u0026n,\n-\t\t sizeof n)) {\n-\t\tlwsl_warn(\u0022Failed to set SNDBUF to %d\u0022, n);\n-\t\tcce \u003d \u0022HS: SO_SNDBUF failed\u0022;\n-\t\tgoto bail3;\n-\t}\n-#endif\n-\n-\tlwsl_debug(\u0022handshake OK for protocol %s\u005cn\u0022, wsi-\u003eprotocol-\u003ename);\n-\n-\t/* call him back to inform him he is up */\n-\n-\tif (wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_ESTABLISHED,\n-\t\t\t\t wsi-\u003euser_space, NULL, 0)) {\n-\t\tcce \u003d \u0022HS: Rejected at CLIENT_ESTABLISHED\u0022;\n-\t\tgoto bail3;\n-\t}\n-#ifndef LWS_NO_EXTENSIONS\n-\t/*\n-\t * inform all extensions, not just active ones since they\n-\t * already know\n-\t */\n-\text \u003d wsi-\u003evhost-\u003eextensions;\n-\n-\twhile (ext \u0026\u0026 ext-\u003ecallback) {\n-\t\tv \u003d NULL;\n-\t\tfor (n \u003d 0; n \u003c wsi-\u003ecount_act_ext; n++)\n-\t\t\tif (wsi-\u003eactive_extensions[n] \u003d\u003d ext)\n-\t\t\t\tv \u003d wsi-\u003eact_ext_user[n];\n-\n-\t\text-\u003ecallback(context, ext, wsi,\n-\t\t\t LWS_EXT_CB_ANY_WSI_ESTABLISHED, v, NULL, 0);\n-\t\text++;\n-\t}\n-#endif\n-\n-\treturn 0;\n-\n-bail3:\n-\tclose_reason \u003d LWS_CLOSE_STATUS_NOSTATUS;\n-\n-bail2:\n-\tif (wsi-\u003eprotocol)\n-\t\twsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR,\n-\t\t\t\twsi-\u003euser_space, (void *)cce,\n-\t\t\t\t(unsigned int)strlen(cce));\n-\twsi-\u003ealready_did_cce \u003d 1;\n-\n-\tlwsl_info(\u0022closing connection due to bail2 connection error\u005cn\u0022);\n-\n-\t/* closing will free up his parsing allocations */\n-\tlws_close_free_wsi(wsi, close_reason);\n-\n-\treturn 1;\n-}\n-\n-\n-char *\n-lws_generate_client_handshake(struct lws *wsi, char *pkt)\n-{\n-\tchar buf[128], hash[20], key_b64[40], *p \u003d pkt;\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tconst char *meth;\n-\tint n;\n-#ifndef LWS_NO_EXTENSIONS\n-\tconst struct lws_extension *ext;\n-\tint ext_count \u003d 0;\n-#endif\n-\tconst char *pp \u003d lws_hdr_simple_ptr(wsi,\n-\t\t\t\t_WSI_TOKEN_CLIENT_SENT_PROTOCOLS);\n-\n-\tmeth \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);\n-\tif (!meth) {\n-\t\tmeth \u003d \u0022GET\u0022;\n-\t\twsi-\u003edo_ws \u003d 1;\n-\t} else {\n-\t\twsi-\u003edo_ws \u003d 0;\n-\t}\n-\n-\tif (!strcmp(meth, \u0022RAW\u0022)) {\n-\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\t\tlwsl_notice(\u0022client transition to raw\u005cn\u0022);\n-\n-\t\tif (pp) {\n-\t\t\tconst struct lws_protocols *pr;\n-\n-\t\t\tpr \u003d lws_vhost_name_to_protocol(wsi-\u003evhost, pp);\n-\n-\t\t\tif (!pr) {\n-\t\t\t\tlwsl_err(\u0022protocol %s not enabled on vhost\u005cn\u0022,\n-\t\t\t\t\t pp);\n-\t\t\t\treturn NULL;\n-\t\t\t}\n-\n-\t\t\tlws_bind_protocol(wsi, pr);\n-\t\t}\n-\n-\t\tif ((wsi-\u003eprotocol-\u003ecallback)(wsi,\n-\t\t\t\tLWS_CALLBACK_RAW_ADOPT,\n-\t\t\t\twsi-\u003euser_space, NULL, 0))\n-\t\t\treturn NULL;\n-\n-\t\tlws_header_table_force_to_detachable_state(wsi);\n-\t\tlws_union_transition(wsi, LWSCM_RAW);\n-\t\tlws_header_table_detach(wsi, 1);\n-\n-\t\treturn NULL;\n-\t}\n-\n-\tif (wsi-\u003edo_ws) {\n-\t\t/*\n-\t\t * create the random key\n-\t\t */\n-\t\tn \u003d lws_get_random(context, hash, 16);\n-\t\tif (n !\u003d 16) {\n-\t\t\tlwsl_err(\u0022Unable to read from random dev %s\u005cn\u0022,\n-\t\t\t\t SYSTEM_RANDOM_FILEPATH);\n-\t\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\t\t\treturn NULL;\n-\t\t}\n-\n-\t\tlws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));\n-\t}\n-\n-\t/*\n-\t * 04 example client handshake\n-\t *\n-\t * GET /chat HTTP/1.1\n-\t * Host: server.example.com\n-\t * Upgrade: websocket\n-\t * Connection: Upgrade\n-\t * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ\u003d\u003d\n-\t * Sec-WebSocket-Origin: http://example.com\n-\t * Sec-WebSocket-Protocol: chat, superchat\n-\t * Sec-WebSocket-Version: 4\n-\t */\n-\n-\tp +\u003d sprintf(p, \u0022%s %s HTTP/1.1\u005cx0d\u005cx0a\u0022, meth,\n-\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));\n-\n-\tp +\u003d sprintf(p, \u0022Pragma: no-cache\u005cx0d\u005cx0a\u0022\n-\t\t\t\u0022Cache-Control: no-cache\u005cx0d\u005cx0a\u0022);\n-\n-\tp +\u003d sprintf(p, \u0022Host: %s\u005cx0d\u005cx0a\u0022,\n-\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));\n-\n-\tif (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) {\n-\t\tif (lws_check_opt(context-\u003eoptions, LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN))\n-\t\t\tp +\u003d sprintf(p, \u0022Origin: %s\u005cx0d\u005cx0a\u0022,\n-\t\t\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));\n-\t\telse\n-\t\t\tp +\u003d sprintf(p, \u0022Origin: http://%s\u005cx0d\u005cx0a\u0022,\n-\t\t\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));\n-\t}\n-\n-\tif (wsi-\u003edo_ws) {\n-\t\tp +\u003d sprintf(p, \u0022Upgrade: websocket\u005cx0d\u005cx0a\u0022\n-\t\t\t\t\u0022Connection: Upgrade\u005cx0d\u005cx0a\u0022\n-\t\t\t\t\u0022Sec-WebSocket-Key: \u0022);\n-\t\tstrcpy(p, key_b64);\n-\t\tp +\u003d strlen(key_b64);\n-\t\tp +\u003d sprintf(p, \u0022\u005cx0d\u005cx0a\u0022);\n-\t\tif (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))\n-\t\t\tp +\u003d sprintf(p, \u0022Sec-WebSocket-Protocol: %s\u005cx0d\u005cx0a\u0022,\n-\t\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));\n-\n-\t\t/* tell the server what extensions we could support */\n-\n-#ifndef LWS_NO_EXTENSIONS\n-\t\text \u003d wsi-\u003evhost-\u003eextensions;\n-\t\twhile (ext \u0026\u0026 ext-\u003ecallback) {\n-\t\t\tn \u003d lws_ext_cb_all_exts(context, wsi,\n-\t\t\t\t LWS_EXT_CB_CHECK_OK_TO_PROPOSE_EXTENSION,\n-\t\t\t\t (char *)ext-\u003ename, 0);\n-\t\t\tif (n) { /* an extension vetos us */\n-\t\t\t\tlwsl_ext(\u0022ext %s vetoed\u005cn\u0022, (char *)ext-\u003ename);\n-\t\t\t\text++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tn \u003d wsi-\u003evhost-\u003eprotocols[0].callback(wsi,\n-\t\t\t\tLWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,\n-\t\t\t\t\twsi-\u003euser_space, (char *)ext-\u003ename, 0);\n-\n-\t\t\t/*\n-\t\t\t * zero return from callback means\n-\t\t\t * go ahead and allow the extension,\n-\t\t\t * it's what we get if the callback is\n-\t\t\t * unhandled\n-\t\t\t */\n-\n-\t\t\tif (n) {\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\tif (ext_count)\n-\t\t\t\t*p++ \u003d ',';\n-\t\t\telse\n-\t\t\t\tp +\u003d sprintf(p, \u0022Sec-WebSocket-Extensions: \u0022);\n-\t\t\tp +\u003d sprintf(p, \u0022%s\u0022, ext-\u003eclient_offer);\n-\t\t\text_count++;\n-\n-\t\t\text++;\n-\t\t}\n-\t\tif (ext_count)\n-\t\t\tp +\u003d sprintf(p, \u0022\u005cx0d\u005cx0a\u0022);\n-#endif\n-\n-\t\tif (wsi-\u003eietf_spec_revision)\n-\t\t\tp +\u003d sprintf(p, \u0022Sec-WebSocket-Version: %d\u005cx0d\u005cx0a\u0022,\n-\t\t\t\t wsi-\u003eietf_spec_revision);\n-\n-\t\t/* prepare the expected server accept response */\n-\n-\t\tkey_b64[39] \u003d '\u005c0'; /* enforce composed length below buf sizeof */\n-\t\tn \u003d sprintf(buf, \u0022%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11\u0022, key_b64);\n-\n-\t\tlws_SHA1((unsigned char *)buf, n, (unsigned char *)hash);\n-\n-\t\tlws_b64_encode_string(hash, 20,\n-\t\t\t\t wsi-\u003eu.hdr.ah-\u003einitial_handshake_hash_base64,\n-\t\t\t\t sizeof(wsi-\u003eu.hdr.ah-\u003einitial_handshake_hash_base64));\n-\t}\n-\n-\t/* give userland a chance to append, eg, cookies */\n-\n-\twsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,\n-\t\t\t\twsi-\u003euser_space, \u0026p, (pkt + context-\u003ept_serv_buf_size) - p - 12);\n-\n-\tp +\u003d sprintf(p, \u0022\u005cx0d\u005cx0a\u0022);\n-\n-\treturn p;\n-}\n-\ndiff --git a/lib/client/client-handshake.c b/lib/client/client-handshake.c\nnew file mode 100644\nindex 0000000..c2720d9\n--- /dev/null\n+++ b/lib/client/client-handshake.c\n@@ -0,0 +1,1051 @@\n+#include \u0022private-libwebsockets.h\u0022\n+\n+static int\n+lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)\n+{\n+\tstruct addrinfo hints;\n+\n+\tmemset(\u0026hints, 0, sizeof(hints));\n+\t*result \u003d NULL;\n+\n+#ifdef LWS_WITH_IPV6\n+\tif (wsi-\u003eipv6) {\n+\n+#if !defined(__ANDROID__)\n+\t\thints.ai_family \u003d AF_INET6;\n+\t\thints.ai_flags \u003d AI_V4MAPPED;\n+#endif\n+\t} else\n+#endif\n+\t{\n+\t\thints.ai_family \u003d PF_UNSPEC;\n+\t\thints.ai_socktype \u003d SOCK_STREAM;\n+\t\thints.ai_flags \u003d AI_CANONNAME;\n+\t}\n+\n+\treturn getaddrinfo(ads, NULL, \u0026hints, result);\n+}\n+\n+struct lws *\n+lws_client_connect_2(struct lws *wsi)\n+{\n+\tsockaddr46 sa46;\n+\tstruct addrinfo *result;\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tstruct lws_pollfd pfd;\n+\tconst char *cce \u003d \u0022\u0022, *iface;\n+\tint n, port;\n+\tssize_t plen \u003d 0;\n+\tconst char *ads;\n+#ifdef LWS_WITH_IPV6\n+\tchar ipv6only \u003d lws_check_opt(wsi-\u003evhost-\u003eoptions,\n+\t\t\tLWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |\n+\t\t\tLWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);\n+\n+#if defined(__ANDROID__)\n+\tipv6only \u003d 0;\n+#endif\n+#endif\n+\n+\tlwsl_client(\u0022%s\u005cn\u0022, __func__);\n+\n+\tif (!wsi-\u003eu.hdr.ah) {\n+\t\tcce \u003d \u0022ah was NULL at cc2\u0022;\n+\t\tlwsl_err(\u0022%s\u005cn\u0022, cce);\n+\t\tgoto oom4;\n+\t}\n+\n+\t/*\n+\t * start off allowing ipv6 on connection if vhost allows it\n+\t */\n+\twsi-\u003eipv6 \u003d LWS_IPV6_ENABLED(wsi-\u003evhost);\n+\n+\t/* Decide what it is we need to connect to:\n+\t *\n+\t * Priority 1: connect to http proxy */\n+\n+\tif (wsi-\u003evhost-\u003ehttp_proxy_port) {\n+\t\tplen \u003d sprintf((char *)pt-\u003eserv_buf,\n+\t\t\t\u0022CONNECT %s:%u HTTP/1.0\u005cx0d\u005cx0a\u0022\n+\t\t\t\u0022User-agent: libwebsockets\u005cx0d\u005cx0a\u0022,\n+\t\t\tlws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),\n+\t\t\twsi-\u003ec_port);\n+\n+\t\tif (wsi-\u003evhost-\u003eproxy_basic_auth_token[0])\n+\t\t\tplen +\u003d sprintf((char *)pt-\u003eserv_buf + plen,\n+\t\t\t\t\t\u0022Proxy-authorization: basic %s\u005cx0d\u005cx0a\u0022,\n+\t\t\t\t\twsi-\u003evhost-\u003eproxy_basic_auth_token);\n+\n+\t\tplen +\u003d sprintf((char *)pt-\u003eserv_buf + plen, \u0022\u005cx0d\u005cx0a\u0022);\n+\t\tads \u003d wsi-\u003evhost-\u003ehttp_proxy_address;\n+\t\tport \u003d wsi-\u003evhost-\u003ehttp_proxy_port;\n+\n+#if defined(LWS_WITH_SOCKS5)\n+\n+\t/* Priority 2: Connect to SOCK5 Proxy */\n+\n+\t} else if (wsi-\u003evhost-\u003esocks_proxy_port) {\n+\t\tsocks_generate_msg(wsi, SOCKS_MSG_GREETING, \u0026plen);\n+\t\tlwsl_client(\u0022Sending SOCKS Greeting\u005cn\u0022);\n+\t\tads \u003d wsi-\u003evhost-\u003esocks_proxy_address;\n+\t\tport \u003d wsi-\u003evhost-\u003esocks_proxy_port;\n+#endif\n+\t} else {\n+\n+\t\t/* Priority 3: Connect directly */\n+\n+\t\tads \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);\n+\t\tport \u003d wsi-\u003ec_port;\n+\t}\n+\n+\t/*\n+\t * prepare the actual connection\n+\t * to whatever we decided to connect to\n+\t */\n+\n+ lwsl_notice(\u0022%s: %p: address %s\u005cn\u0022, __func__, wsi, ads);\n+\n+ n \u003d lws_getaddrinfo46(wsi, ads, \u0026result);\n+\n+#ifdef LWS_WITH_IPV6\n+\tif (wsi-\u003eipv6) {\n+\n+\t\tif (n) {\n+\t\t\t/* lws_getaddrinfo46 failed, there is no usable result */\n+\t\t\tlwsl_notice(\u0022%s: lws_getaddrinfo46 failed %d\u005cn\u0022,\n+\t\t\t\t\t__func__, n);\n+\t\t\tcce \u003d \u0022ipv6 lws_getaddrinfo46 failed\u0022;\n+\t\t\tgoto oom4;\n+\t\t}\n+\n+\t\tmemset(\u0026sa46, 0, sizeof(sa46));\n+\n+\t\tsa46.sa6.sin6_family \u003d AF_INET6;\n+\t\tswitch (result-\u003eai_family) {\n+\t\tcase AF_INET:\n+\t\t\tif (ipv6only)\n+\t\t\t\tbreak;\n+\t\t\t/* map IPv4 to IPv6 */\n+\t\t\tbzero((char *)\u0026sa46.sa6.sin6_addr,\n+\t\t\t\t\t\tsizeof(sa46.sa6.sin6_addr));\n+\t\t\tsa46.sa6.sin6_addr.s6_addr[10] \u003d 0xff;\n+\t\t\tsa46.sa6.sin6_addr.s6_addr[11] \u003d 0xff;\n+\t\t\tmemcpy(\u0026sa46.sa6.sin6_addr.s6_addr[12],\n+\t\t\t\t\u0026((struct sockaddr_in *)result-\u003eai_addr)-\u003esin_addr,\n+\t\t\t\t\t\t\tsizeof(struct in_addr));\n+\t\t\tlwsl_notice(\u0022uplevelling AF_INET to AF_INET6\u005cn\u0022);\n+\t\t\tbreak;\n+\n+\t\tcase AF_INET6:\n+\t\t\tmemcpy(\u0026sa46.sa6.sin6_addr,\n+\t\t\t \u0026((struct sockaddr_in6 *)result-\u003eai_addr)-\u003esin6_addr,\n+\t\t\t\t\t\tsizeof(struct in6_addr));\n+\t\t\tsa46.sa6.sin6_scope_id \u003d ((struct sockaddr_in6 *)result-\u003eai_addr)-\u003esin6_scope_id;\n+\t\t\tsa46.sa6.sin6_flowinfo \u003d ((struct sockaddr_in6 *)result-\u003eai_addr)-\u003esin6_flowinfo;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tlwsl_err(\u0022Unknown address family\u005cn\u0022);\n+\t\t\tfreeaddrinfo(result);\n+\t\t\tcce \u003d \u0022unknown address family\u0022;\n+\t\t\tgoto oom4;\n+\t\t}\n+\t} else\n+#endif /* use ipv6 */\n+\n+\t/* use ipv4 */\n+\t{\n+\t\tvoid *p \u003d NULL;\n+\n+\t\tif (!n) {\n+\t\t\tstruct addrinfo *res \u003d result;\n+\n+\t\t\t/* pick the first AF_INET (IPv4) result */\n+\n+\t\t\twhile (!p \u0026\u0026 res) {\n+\t\t\t\tswitch (res-\u003eai_family) {\n+\t\t\t\tcase AF_INET:\n+\t\t\t\t\tp \u003d \u0026((struct sockaddr_in *)res-\u003eai_addr)-\u003esin_addr;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\n+\t\t\t\tres \u003d res-\u003eai_next;\n+\t\t\t}\n+#if defined(LWS_FALLBACK_GETHOSTBYNAME)\n+\t\t} else if (n \u003d\u003d EAI_SYSTEM) {\n+\t\t\tstruct hostent *host;\n+\n+\t\t\tlwsl_info(\u0022getaddrinfo (ipv4) failed, trying gethostbyname\u005cn\u0022);\n+\t\t\thost \u003d gethostbyname(ads);\n+\t\t\tif (host) {\n+\t\t\t\tp \u003d host-\u003eh_addr;\n+\t\t\t} else {\n+\t\t\t\tlwsl_err(\u0022gethostbyname failed\u005cn\u0022);\n+\t\t\t\tcce \u003d \u0022gethostbyname (ipv4) failed\u0022;\n+\t\t\t\tgoto oom4;\n+\t\t\t}\n+#endif\n+\t\t} else {\n+\t\t\tlwsl_err(\u0022getaddrinfo failed\u005cn\u0022);\n+\t\t\tcce \u003d \u0022getaddrinfo failed\u0022;\n+\t\t\tgoto oom4;\n+\t\t}\n+\n+\t\tif (!p) {\n+\t\t\tif (result)\n+\t\t\t\tfreeaddrinfo(result);\n+\t\t\tlwsl_err(\u0022Couldn't identify address\u005cn\u0022);\n+\t\t\tcce \u003d \u0022unable to lookup address\u0022;\n+\t\t\tgoto oom4;\n+\t\t}\n+\n+\t\tsa46.sa4.sin_family \u003d AF_INET;\n+\t\tsa46.sa4.sin_addr \u003d *((struct in_addr *)p);\n+\t\tbzero(\u0026sa46.sa4.sin_zero, 8);\n+\t}\n+\n+\tif (result)\n+\t\tfreeaddrinfo(result);\n+\n+\t/* now we decided on ipv4 or ipv6, set the port */\n+\n+\tif (!lws_socket_is_valid(wsi-\u003edesc.sockfd)) {\n+\n+#if defined(LWS_WITH_LIBUV)\n+\t\tif (LWS_LIBUV_ENABLED(context))\n+\t\t\tif (lws_libuv_check_watcher_active(wsi)) {\n+\t\t\t\tlwsl_warn(\u0022Waiting for libuv watcher to close\u005cn\u0022);\n+\t\t\t\tcce \u003d \u0022waiting for libuv watcher to close\u0022;\n+\t\t\t\tgoto oom4;\n+\t\t\t}\n+#endif\n+\n+#ifdef LWS_WITH_IPV6\n+\t\tif (wsi-\u003eipv6)\n+\t\t\twsi-\u003edesc.sockfd \u003d socket(AF_INET6, SOCK_STREAM, 0);\n+\t\telse\n+#endif\n+\t\t\twsi-\u003edesc.sockfd \u003d socket(AF_INET, SOCK_STREAM, 0);\n+\n+\t\tif (!lws_socket_is_valid(wsi-\u003edesc.sockfd)) {\n+\t\t\tlwsl_warn(\u0022Unable to open socket\u005cn\u0022);\n+\t\t\tcce \u003d \u0022unable to open socket\u0022;\n+\t\t\tgoto oom4;\n+\t\t}\n+\n+\t\tif (lws_plat_set_socket_options(wsi-\u003evhost, wsi-\u003edesc.sockfd)) {\n+\t\t\tlwsl_err(\u0022Failed to set wsi socket options\u005cn\u0022);\n+\t\t\tcompatible_close(wsi-\u003edesc.sockfd);\n+\t\t\tcce \u003d \u0022set socket opts failed\u0022;\n+\t\t\tgoto oom4;\n+\t\t}\n+\n+\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_CONNECT;\n+\n+\t\tlws_libev_accept(wsi, wsi-\u003edesc);\n+\t\tlws_libuv_accept(wsi, wsi-\u003edesc);\n+\t\tlws_libevent_accept(wsi, wsi-\u003edesc);\n+\n+\t\tif (insert_wsi_socket_into_fds(context, wsi)) {\n+\t\t\tcompatible_close(wsi-\u003edesc.sockfd);\n+\t\t\tcce \u003d \u0022insert wsi failed\u0022;\n+\t\t\tgoto oom4;\n+\t\t}\n+\n+\t\tlws_change_pollfd(wsi, 0, LWS_POLLIN);\n+\n+\t\t/*\n+\t\t * past here, we can't simply free the structs as error\n+\t\t * handling as oom4 does. We have to run the whole close flow.\n+\t\t */\n+\n+\t\tif (!wsi-\u003eprotocol)\n+\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[0];\n+\n+\t\twsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_WSI_CREATE,\n+\t\t\t\t\twsi-\u003euser_space, NULL, 0);\n+\n+\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,\n+\t\t\t\tAWAITING_TIMEOUT);\n+\n+\t\tiface \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);\n+\n+\t\tif (iface) {\n+\t\t\tn \u003d lws_socket_bind(wsi-\u003evhost, wsi-\u003edesc.sockfd, 0, iface);\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tcce \u003d \u0022unable to bind socket\u0022;\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+#ifdef LWS_WITH_IPV6\n+\tif (wsi-\u003eipv6) {\n+\t\tsa46.sa6.sin6_port \u003d htons(port);\n+\t\tn \u003d sizeof(struct sockaddr_in6);\n+\t} else\n+#endif\n+\t{\n+\t\tsa46.sa4.sin_port \u003d htons(port);\n+\t\tn \u003d sizeof(struct sockaddr);\n+\t}\n+\n+\tif (connect(wsi-\u003edesc.sockfd, (const struct sockaddr *)\u0026sa46, n) \u003d\u003d -1 ||\n+\t LWS_ERRNO \u003d\u003d LWS_EISCONN) {\n+\t\tif (LWS_ERRNO \u003d\u003d LWS_EALREADY ||\n+\t\t LWS_ERRNO \u003d\u003d LWS_EINPROGRESS ||\n+\t\t LWS_ERRNO \u003d\u003d LWS_EWOULDBLOCK\n+#ifdef _WIN32\n+\t\t\t|| LWS_ERRNO \u003d\u003d WSAEINVAL\n+#endif\n+\t\t) {\n+\t\t\tlwsl_client(\u0022nonblocking connect retry (errno \u003d %d)\u005cn\u0022,\n+\t\t\t\t LWS_ERRNO);\n+\n+\t\t\tif (lws_plat_check_connection_error(wsi)) {\n+\t\t\t\tcce \u003d \u0022socket connect failed\u0022;\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\t/*\n+\t\t\t * must do specifically a POLLOUT poll to hear\n+\t\t\t * about the connect completion\n+\t\t\t */\n+\t\t\tif (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {\n+\t\t\t\tcce \u003d \u0022POLLOUT set failed\u0022;\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\treturn wsi;\n+\t\t}\n+\n+\t\tif (LWS_ERRNO !\u003d LWS_EISCONN) {\n+\t\t\tlwsl_notice(\u0022Connect failed errno\u003d%d\u005cn\u0022, LWS_ERRNO);\n+\t\t\tcce \u003d \u0022connect failed\u0022;\n+\t\t\tgoto failed;\n+\t\t}\n+\t}\n+\n+\tlwsl_client(\u0022connected\u005cn\u0022);\n+\n+\t/* we are connected to server, or proxy */\n+\n+\t/* http proxy */\n+\tif (wsi-\u003evhost-\u003ehttp_proxy_port) {\n+\n+\t\t/*\n+\t\t * OK from now on we talk via the proxy, so connect to that\n+\t\t *\n+\t\t * (will overwrite existing pointer,\n+\t\t * leaving old string/frag there but unreferenced)\n+\t\t */\n+\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,\n+\t\t\t\t\t wsi-\u003evhost-\u003ehttp_proxy_address))\n+\t\t\tgoto failed;\n+\t\twsi-\u003ec_port \u003d wsi-\u003evhost-\u003ehttp_proxy_port;\n+\n+\t\tn \u003d send(wsi-\u003edesc.sockfd, (char *)pt-\u003eserv_buf, plen,\n+\t\t\t MSG_NOSIGNAL);\n+\t\tif (n \u003c 0) {\n+\t\t\tlwsl_debug(\u0022ERROR writing to proxy socket\u005cn\u0022);\n+\t\t\tcce \u003d \u0022proxy write failed\u0022;\n+\t\t\tgoto failed;\n+\t\t}\n+\n+\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,\n+\t\t\t\tAWAITING_TIMEOUT);\n+\n+\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_PROXY_REPLY;\n+\n+\t\treturn wsi;\n+\t}\n+#if defined(LWS_WITH_SOCKS5)\n+\t/* socks proxy */\n+\telse if (wsi-\u003evhost-\u003esocks_proxy_port) {\n+\t\tn \u003d send(wsi-\u003edesc.sockfd, (char *)pt-\u003eserv_buf, plen,\n+\t\t\t MSG_NOSIGNAL);\n+\t\tif (n \u003c 0) {\n+\t\t\tlwsl_debug(\u0022ERROR writing socks greeting\u005cn\u0022);\n+\t\t\tcce \u003d \u0022socks write failed\u0022;\n+\t\t\tgoto failed;\n+\t\t}\n+\n+\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,\n+\t\t\t\tAWAITING_TIMEOUT);\n+\n+\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY;\n+\n+\t\treturn wsi;\n+\t}\n+#endif\n+\n+\t/*\n+\t * provoke service to issue the handshake directly\n+\t * we need to do it this way because in the proxy case, this is the\n+\t * next state and executed only if and when we get a good proxy\n+\t * response inside the state machine... but notice in SSL case this\n+\t * may not have sent anything yet with 0 return, and won't until some\n+\t * many retries from main loop. To stop that becoming endless,\n+\t * cover with a timeout.\n+\t */\n+\n+\tlws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,\n+\t\t\tAWAITING_TIMEOUT);\n+\n+\twsi-\u003emode \u003d LWSCM_WSCL_ISSUE_HANDSHAKE;\n+\tpfd.fd \u003d wsi-\u003edesc.sockfd;\n+\tpfd.events \u003d LWS_POLLIN;\n+\tpfd.revents \u003d LWS_POLLIN;\n+\n+\tn \u003d lws_service_fd(context, \u0026pfd);\n+\tif (n \u003c 0) {\n+\t\tcce \u003d \u0022first service failed\u0022;\n+\t\tgoto failed;\n+\t}\n+\tif (n) /* returns 1 on failure after closing wsi */\n+\t\treturn NULL;\n+\n+\treturn wsi;\n+\n+oom4:\n+\t/* we're closing, losing some rx is OK */\n+\tlws_header_table_force_to_detachable_state(wsi);\n+\n+\tif (wsi-\u003emode \u003d\u003d LWSCM_HTTP_CLIENT ||\n+\t wsi-\u003emode \u003d\u003d LWSCM_HTTP_CLIENT_ACCEPTED ||\n+\t wsi-\u003emode \u003d\u003d LWSCM_WSCL_WAITING_CONNECT) {\n+\t\twsi-\u003evhost-\u003eprotocols[0].callback(wsi,\n+\t\t\tLWS_CALLBACK_CLIENT_CONNECTION_ERROR,\n+\t\t\twsi-\u003euser_space, (void *)cce, strlen(cce));\n+\t\twsi-\u003ealready_did_cce \u003d 1;\n+\t}\n+\t/* take care that we might be inserted in fds already */\n+\tif (wsi-\u003eposition_in_fds_table !\u003d -1)\n+\t\tgoto failed1;\n+\tlws_remove_from_timeout_list(wsi);\n+\tlws_header_table_detach(wsi, 0);\n+\tlws_free(wsi);\n+\n+\treturn NULL;\n+\n+failed:\n+\twsi-\u003evhost-\u003eprotocols[0].callback(wsi,\n+\t\tLWS_CALLBACK_CLIENT_CONNECTION_ERROR,\n+\t\twsi-\u003euser_space, (void *)cce, strlen(cce));\n+\twsi-\u003ealready_did_cce \u003d 1;\n+failed1:\n+\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\n+\treturn NULL;\n+}\n+\n+/**\n+ * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)\n+ *\t\t\tthis only works if still in HTTP, ie, not upgraded yet\n+ * wsi:\t\tconnection to reset\n+ * address:\tnetwork address of the new server\n+ * port:\tport to connect to\n+ * path:\turi path to connect to on the new server\n+ * host:\thost header to send to the new server\n+ */\n+LWS_VISIBLE struct lws *\n+lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,\n+\t\t const char *path, const char *host)\n+{\n+\tchar origin[300] \u003d \u0022\u0022, protocol[300] \u003d \u0022\u0022, method[32] \u003d \u0022\u0022, iface[16] \u003d \u0022\u0022, *p;\n+\tstruct lws *wsi \u003d *pwsi;\n+\n+\tif (wsi-\u003eredirects \u003d\u003d 3) {\n+\t\tlwsl_err(\u0022%s: Too many redirects\u005cn\u0022, __func__);\n+\t\treturn NULL;\n+\t}\n+\twsi-\u003eredirects++;\n+\n+\tp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);\n+\tif (p)\n+\t\tstrncpy(origin, p, sizeof(origin) - 1);\n+\n+\tp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);\n+\tif (p)\n+\t\tstrncpy(protocol, p, sizeof(protocol) - 1);\n+\n+\tp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);\n+\tif (p)\n+\t\tstrncpy(method, p, sizeof(method) - 1);\n+\n+\tp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);\n+\tif (p)\n+\t\tstrncpy(method, p, sizeof(iface) - 1);\n+\n+\tlwsl_info(\u0022redirect ads\u003d'%s', port\u003d%d, path\u003d'%s', ssl \u003d %d\u005cn\u0022,\n+\t\t address, port, path, ssl);\n+\n+\t/* close the connection by hand */\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\tlws_ssl_close(wsi);\n+#endif\n+\n+#ifdef LWS_WITH_LIBUV\n+\tif (LWS_LIBUV_ENABLED(wsi-\u003econtext)) {\n+\t\tlwsl_debug(\u0022%s: lws_libuv_closehandle: wsi %p\u005cn\u0022, __func__, wsi);\n+\t\t/*\n+\t\t * libuv has to do his own close handle processing asynchronously\n+\t\t * but once it starts we can do everything else synchronously,\n+\t\t * including trash wsi-\u003edesc.sockfd since it took a copy.\n+\t\t *\n+\t\t * When it completes it will call compatible_close()\n+\t\t */\n+\t\tlws_libuv_closehandle_manually(wsi);\n+\t} else\n+#else\n+\tcompatible_close(wsi-\u003edesc.sockfd);\n+#endif\n+\n+\tremove_wsi_socket_from_fds(wsi);\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\twsi-\u003euse_ssl \u003d ssl;\n+#else\n+\tif (ssl) {\n+\t\tlwsl_err(\u0022%s: not configured for ssl\u005cn\u0022, __func__);\n+\t\treturn NULL;\n+\t}\n+#endif\n+\n+\twsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n+\twsi-\u003estate \u003d LWSS_CLIENT_UNCONNECTED;\n+\twsi-\u003eprotocol \u003d NULL;\n+\twsi-\u003epending_timeout \u003d NO_PENDING_TIMEOUT;\n+\twsi-\u003ec_port \u003d port;\n+\twsi-\u003ehdr_parsing_completed \u003d 0;\n+\t_lws_header_table_reset(wsi-\u003eu.hdr.ah);\n+\n+\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))\n+\t\treturn NULL;\n+\n+\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))\n+\t\treturn NULL;\n+\n+\tif (origin[0])\n+\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,\n+\t\t\t\t\t origin))\n+\t\t\treturn NULL;\n+\tif (protocol[0])\n+\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,\n+\t\t\t\t\t protocol))\n+\t\t\treturn NULL;\n+\tif (method[0])\n+\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,\n+\t\t\t\t\t method))\n+\t\t\treturn NULL;\n+\n+\tif (iface[0])\n+\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,\n+\t\t\t\t\t iface))\n+\t\t\treturn NULL;\n+\n+\torigin[0] \u003d '/';\n+\tstrncpy(\u0026origin[1], path, sizeof(origin) - 2);\n+\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))\n+\t\treturn NULL;\n+\n+\t*pwsi \u003d lws_client_connect_2(wsi);\n+\n+\treturn *pwsi;\n+}\n+\n+#ifdef LWS_WITH_HTTP_PROXY\n+static hubbub_error\n+html_parser_cb(const hubbub_token *token, void *pw)\n+{\n+\tstruct lws_rewrite *r \u003d (struct lws_rewrite *)pw;\n+\tchar buf[1024], *start \u003d buf + LWS_PRE, *p \u003d start,\n+\t *end \u003d \u0026buf[sizeof(buf) - 1];\n+\tsize_t i;\n+\n+\tswitch (token-\u003etype) {\n+\tcase HUBBUB_TOKEN_DOCTYPE:\n+\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003c!DOCTYPE %.*s %s \u0022,\n+\t\t\t\t(int) token-\u003edata.doctype.name.len,\n+\t\t\t\ttoken-\u003edata.doctype.name.ptr,\n+\t\t\t\ttoken-\u003edata.doctype.force_quirks ?\n+\t\t\t\t\t\t\u0022(force-quirks) \u0022 : \u0022\u0022);\n+\n+\t\tif (token-\u003edata.doctype.public_missing)\n+\t\t\tlwsl_debug(\u0022\u005ctpublic: missing\u005cn\u0022);\n+\t\telse\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022PUBLIC \u005c\u0022%.*s\u005c\u0022\u005cn\u0022,\n+\t\t\t\t(int) token-\u003edata.doctype.public_id.len,\n+\t\t\t\ttoken-\u003edata.doctype.public_id.ptr);\n+\n+\t\tif (token-\u003edata.doctype.system_missing)\n+\t\t\tlwsl_debug(\u0022\u005ctsystem: missing\u005cn\u0022);\n+\t\telse\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022 \u005c\u0022%.*s\u005c\u0022\u003e\u005cn\u0022,\n+\t\t\t\t(int) token-\u003edata.doctype.system_id.len,\n+\t\t\t\ttoken-\u003edata.doctype.system_id.ptr);\n+\n+\t\tbreak;\n+\tcase HUBBUB_TOKEN_START_TAG:\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003c%.*s\u0022, (int)token-\u003edata.tag.name.len,\n+\t\t\t\ttoken-\u003edata.tag.name.ptr);\n+\n+/*\t\t\t\t(token-\u003edata.tag.self_closing) ?\n+\t\t\t\t\t\t\u0022(self-closing) \u0022 : \u0022\u0022,\n+\t\t\t\t(token-\u003edata.tag.n_attributes \u003e 0) ?\n+\t\t\t\t\t\t\u0022attributes:\u0022 : \u0022\u0022);\n+*/\n+\t\tfor (i \u003d 0; i \u003c token-\u003edata.tag.n_attributes; i++) {\n+\t\t\tif (!hstrcmp(\u0026token-\u003edata.tag.attributes[i].name, \u0022href\u0022, 4) ||\n+\t\t\t !hstrcmp(\u0026token-\u003edata.tag.attributes[i].name, \u0022action\u0022, 6) ||\n+\t\t\t !hstrcmp(\u0026token-\u003edata.tag.attributes[i].name, \u0022src\u0022, 3)) {\n+\t\t\t\tconst char *pp \u003d (const char *)token-\u003edata.tag.attributes[i].value.ptr;\n+\t\t\t\tint plen \u003d (int) token-\u003edata.tag.attributes[i].value.len;\n+\n+\t\t\t\tif (strncmp(pp, \u0022http:\u0022, 5) \u0026\u0026 strncmp(pp, \u0022https:\u0022, 6)) {\n+\n+\t\t\t\t\tif (!hstrcmp(\u0026token-\u003edata.tag.attributes[i].value,\n+\t\t\t\t\t\t r-\u003efrom, r-\u003efrom_len)) {\n+\t\t\t\t\t\tpp +\u003d r-\u003efrom_len;\n+\t\t\t\t\t\tplen -\u003d r-\u003efrom_len;\n+\t\t\t\t\t}\n+\t\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022 %.*s\u003d\u005c\u0022%s/%.*s\u005c\u0022\u0022,\n+\t\t\t\t\t (int) token-\u003edata.tag.attributes[i].name.len,\n+\t\t\t\t\t token-\u003edata.tag.attributes[i].name.ptr,\n+\t\t\t\t\t r-\u003eto, plen, pp);\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022 %.*s\u003d\u005c\u0022%.*s\u005c\u0022\u0022,\n+\t\t\t\t(int) token-\u003edata.tag.attributes[i].name.len,\n+\t\t\t\ttoken-\u003edata.tag.attributes[i].name.ptr,\n+\t\t\t\t(int) token-\u003edata.tag.attributes[i].value.len,\n+\t\t\t\ttoken-\u003edata.tag.attributes[i].value.ptr);\n+\t\t}\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003e\u0022);\n+\t\tbreak;\n+\tcase HUBBUB_TOKEN_END_TAG:\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003c/%.*s\u0022, (int) token-\u003edata.tag.name.len,\n+\t\t\t\ttoken-\u003edata.tag.name.ptr);\n+/*\n+\t\t\t\t(token-\u003edata.tag.self_closing) ?\n+\t\t\t\t\t\t\u0022(self-closing) \u0022 : \u0022\u0022,\n+\t\t\t\t(token-\u003edata.tag.n_attributes \u003e 0) ?\n+\t\t\t\t\t\t\u0022attributes:\u0022 : \u0022\u0022);\n+*/\n+\t\tfor (i \u003d 0; i \u003c token-\u003edata.tag.n_attributes; i++) {\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022 %.*s\u003d'%.*s'\u005cn\u0022,\n+\t\t\t\t(int) token-\u003edata.tag.attributes[i].name.len,\n+\t\t\t\ttoken-\u003edata.tag.attributes[i].name.ptr,\n+\t\t\t\t(int) token-\u003edata.tag.attributes[i].value.len,\n+\t\t\t\ttoken-\u003edata.tag.attributes[i].value.ptr);\n+\t\t}\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003e\u0022);\n+\t\tbreak;\n+\tcase HUBBUB_TOKEN_COMMENT:\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u003c!-- %.*s --\u003e\u005cn\u0022,\n+\t\t\t\t(int) token-\u003edata.comment.len,\n+\t\t\t\ttoken-\u003edata.comment.ptr);\n+\t\tbreak;\n+\tcase HUBBUB_TOKEN_CHARACTER:\n+\t\tif (token-\u003edata.character.len \u003d\u003d 1) {\n+\t\t\tif (*token-\u003edata.character.ptr \u003d\u003d '\u003c') {\n+\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u0026lt;\u0022);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (*token-\u003edata.character.ptr \u003d\u003d '\u003e') {\n+\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u0026gt;\u0022);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (*token-\u003edata.character.ptr \u003d\u003d '\u0026') {\n+\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u0026amp;\u0022);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022%.*s\u0022, (int) token-\u003edata.character.len,\n+\t\t\t\ttoken-\u003edata.character.ptr);\n+\t\tbreak;\n+\tcase HUBBUB_TOKEN_EOF:\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005cn\u0022);\n+\t\tbreak;\n+\t}\n+\n+\tif (user_callback_handle_rxflow(r-\u003ewsi-\u003eprotocol-\u003ecallback,\n+\t\t\tr-\u003ewsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,\n+\t\t\tr-\u003ewsi-\u003euser_space, start, p - start))\n+\t\treturn -1;\n+\n+\treturn HUBBUB_OK;\n+}\n+#endif\n+\n+LWS_VISIBLE struct lws *\n+lws_client_connect_via_info(struct lws_client_connect_info *i)\n+{\n+\tstruct lws *wsi;\n+\tint v \u003d SPEC_LATEST_SUPPORTED;\n+\tconst struct lws_protocols *p;\n+\n+\tif (i-\u003econtext-\u003erequested_kill)\n+\t\treturn NULL;\n+\n+\tif (!i-\u003econtext-\u003eprotocol_init_done)\n+\t\tlws_protocol_init(i-\u003econtext);\n+\n+\twsi \u003d lws_zalloc(sizeof(struct lws), \u0022client wsi\u0022);\n+\tif (wsi \u003d\u003d NULL)\n+\t\tgoto bail;\n+\n+\twsi-\u003econtext \u003d i-\u003econtext;\n+\t/* assert the mode and union status (hdr) clearly */\n+\tlws_union_transition(wsi, LWSCM_HTTP_CLIENT);\n+\twsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n+\n+\t/* 1) fill up the wsi with stuff from the connect_info as far as it\n+\t * can go. It's because not only is our connection async, we might\n+\t * not even be able to get ahold of an ah at this point.\n+\t */\n+\n+\t/* -1 means just use latest supported */\n+\tif (i-\u003eietf_version_or_minus_one !\u003d -1 \u0026\u0026 i-\u003eietf_version_or_minus_one)\n+\t\tv \u003d i-\u003eietf_version_or_minus_one;\n+\n+\twsi-\u003eietf_spec_revision \u003d v;\n+\twsi-\u003euser_space \u003d NULL;\n+\twsi-\u003estate \u003d LWSS_CLIENT_UNCONNECTED;\n+\twsi-\u003epending_timeout \u003d NO_PENDING_TIMEOUT;\n+\twsi-\u003eposition_in_fds_table \u003d -1;\n+\twsi-\u003ec_port \u003d i-\u003eport;\n+\twsi-\u003evhost \u003d i-\u003evhost;\n+\tif (!wsi-\u003evhost)\n+\t\twsi-\u003evhost \u003d i-\u003econtext-\u003evhost_list;\n+\n+\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[0];\n+\n+\t/* for http[s] connection, allow protocol selection by name */\n+\n+\tif (i-\u003emethod \u0026\u0026 i-\u003evhost \u0026\u0026 i-\u003eprotocol) {\n+\t\tp \u003d lws_vhost_name_to_protocol(i-\u003evhost, i-\u003eprotocol);\n+\t\tif (p)\n+\t\t\twsi-\u003eprotocol \u003d p;\n+\t}\n+\n+\tif (wsi \u0026\u0026 !wsi-\u003euser_space \u0026\u0026 i-\u003euserdata) {\n+\t\twsi-\u003euser_space_externally_allocated \u003d 1;\n+\t\twsi-\u003euser_space \u003d i-\u003euserdata;\n+\t} else\n+\t\t/* if we stay in http, we can assign the user space now,\n+\t\t * otherwise do it after the protocol negotiated\n+\t\t */\n+\t\tif (i-\u003emethod)\n+\t\t\tif (lws_ensure_user_space(wsi))\n+\t\t\t\tgoto bail;\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\twsi-\u003euse_ssl \u003d i-\u003essl_connection;\n+#else\n+\tif (i-\u003essl_connection) {\n+\t\tlwsl_err(\u0022libwebsockets not configured for ssl\u005cn\u0022);\n+\t\tgoto bail;\n+\t}\n+#endif\n+\n+\t/* 2) stash the things from connect_info that we can't process without\n+\t * an ah. Because if no ah, we will go on the ah waiting list and\n+\t * process those things later (after the connect_info and maybe the\n+\t * things pointed to have gone out of scope.\n+\t */\n+\n+\twsi-\u003eu.hdr.stash \u003d lws_malloc(sizeof(*wsi-\u003eu.hdr.stash), \u0022client stash\u0022);\n+\tif (!wsi-\u003eu.hdr.stash) {\n+\t\tlwsl_err(\u0022%s: OOM\u005cn\u0022, __func__);\n+\t\tgoto bail;\n+\t}\n+\n+\twsi-\u003eu.hdr.stash-\u003eorigin[0] \u003d '\u005c0';\n+\twsi-\u003eu.hdr.stash-\u003eprotocol[0] \u003d '\u005c0';\n+\twsi-\u003eu.hdr.stash-\u003emethod[0] \u003d '\u005c0';\n+\twsi-\u003eu.hdr.stash-\u003eiface[0] \u003d '\u005c0';\n+\n+\tstrncpy(wsi-\u003eu.hdr.stash-\u003eaddress, i-\u003eaddress,\n+\t\tsizeof(wsi-\u003eu.hdr.stash-\u003eaddress) - 1);\n+\tstrncpy(wsi-\u003eu.hdr.stash-\u003epath, i-\u003epath,\n+\t\tsizeof(wsi-\u003eu.hdr.stash-\u003epath) - 1);\n+\tstrncpy(wsi-\u003eu.hdr.stash-\u003ehost, i-\u003ehost,\n+\t\tsizeof(wsi-\u003eu.hdr.stash-\u003ehost) - 1);\n+\tif (i-\u003eorigin)\n+\t\tstrncpy(wsi-\u003eu.hdr.stash-\u003eorigin, i-\u003eorigin,\n+\t\t\tsizeof(wsi-\u003eu.hdr.stash-\u003eorigin) - 1);\n+\tif (i-\u003eprotocol)\n+\t\tstrncpy(wsi-\u003eu.hdr.stash-\u003eprotocol, i-\u003eprotocol,\n+\t\t\tsizeof(wsi-\u003eu.hdr.stash-\u003eprotocol) - 1);\n+\tif (i-\u003emethod)\n+\t\tstrncpy(wsi-\u003eu.hdr.stash-\u003emethod, i-\u003emethod,\n+\t\t\tsizeof(wsi-\u003eu.hdr.stash-\u003emethod) - 1);\n+\tif (i-\u003eiface)\n+\t\tstrncpy(wsi-\u003eu.hdr.stash-\u003eiface, i-\u003eiface,\n+\t\t\tsizeof(wsi-\u003eu.hdr.stash-\u003eiface) - 1);\n+\n+\twsi-\u003eu.hdr.stash-\u003eaddress[sizeof(wsi-\u003eu.hdr.stash-\u003eaddress) - 1] \u003d '\u005c0';\n+\twsi-\u003eu.hdr.stash-\u003epath[sizeof(wsi-\u003eu.hdr.stash-\u003epath) - 1] \u003d '\u005c0';\n+\twsi-\u003eu.hdr.stash-\u003ehost[sizeof(wsi-\u003eu.hdr.stash-\u003ehost) - 1] \u003d '\u005c0';\n+\twsi-\u003eu.hdr.stash-\u003eorigin[sizeof(wsi-\u003eu.hdr.stash-\u003eorigin) - 1] \u003d '\u005c0';\n+\twsi-\u003eu.hdr.stash-\u003eprotocol[sizeof(wsi-\u003eu.hdr.stash-\u003eprotocol) - 1] \u003d '\u005c0';\n+\twsi-\u003eu.hdr.stash-\u003emethod[sizeof(wsi-\u003eu.hdr.stash-\u003emethod) - 1] \u003d '\u005c0';\n+\twsi-\u003eu.hdr.stash-\u003eiface[sizeof(wsi-\u003eu.hdr.stash-\u003eiface) - 1] \u003d '\u005c0';\n+\n+\tif (i-\u003epwsi)\n+\t\t*i-\u003epwsi \u003d wsi;\n+\n+\t/* if we went on the waiting list, no probs just return the wsi\n+\t * when we get the ah, now or later, he will call\n+\t * lws_client_connect_via_info2() below.\n+\t */\n+\tif (lws_header_table_attach(wsi, 0) \u003c 0) {\n+\t\t/*\n+\t\t * if we failed here, the connection is already closed\n+\t\t * and freed.\n+\t\t */\n+\t\tgoto bail1;\n+\t}\n+\n+\tif (i-\u003eparent_wsi) {\n+\t\tlwsl_info(\u0022%s: created child %p of parent %p\u005cn\u0022, __func__,\n+\t\t\t\twsi, i-\u003eparent_wsi);\n+\t\twsi-\u003eparent \u003d i-\u003eparent_wsi;\n+\t\twsi-\u003esibling_list \u003d i-\u003eparent_wsi-\u003echild_list;\n+\t\ti-\u003eparent_wsi-\u003echild_list \u003d wsi;\n+\t}\n+#ifdef LWS_WITH_HTTP_PROXY\n+\tif (i-\u003euri_replace_to)\n+\t\twsi-\u003erw \u003d lws_rewrite_create(wsi, html_parser_cb,\n+\t\t\t\t\t i-\u003euri_replace_from,\n+\t\t\t\t\t i-\u003euri_replace_to);\n+#endif\n+\n+\treturn wsi;\n+\n+bail:\n+\tlws_free(wsi);\n+\n+bail1:\n+\tif (i-\u003epwsi)\n+\t\t*i-\u003epwsi \u003d NULL;\n+\n+\treturn NULL;\n+}\n+\n+struct lws *\n+lws_client_connect_via_info2(struct lws *wsi)\n+{\n+\tstruct client_info_stash *stash \u003d wsi-\u003eu.hdr.stash;\n+\n+\tif (!stash)\n+\t\treturn wsi;\n+\n+\t/*\n+\t * we're not necessarily in a position to action these right away,\n+\t * stash them... we only need during connect phase so u.hdr is fine\n+\t */\n+\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,\n+\t\t\t\t stash-\u003eaddress))\n+\t\tgoto bail1;\n+\n+\t/* these only need u.hdr lifetime as well */\n+\n+\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash-\u003epath))\n+\t\tgoto bail1;\n+\n+\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash-\u003ehost))\n+\t\tgoto bail1;\n+\n+\tif (stash-\u003eorigin[0])\n+\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,\n+\t\t\t\t\t stash-\u003eorigin))\n+\t\t\tgoto bail1;\n+\t/*\n+\t * this is a list of protocols we tell the server we're okay with\n+\t * stash it for later when we compare server response with it\n+\t */\n+\tif (stash-\u003eprotocol[0])\n+\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,\n+\t\t\t\t\t stash-\u003eprotocol))\n+\t\t\tgoto bail1;\n+\tif (stash-\u003emethod[0])\n+\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,\n+\t\t\t\t\t stash-\u003emethod))\n+\t\t\tgoto bail1;\n+\tif (stash-\u003eiface[0])\n+\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,\n+\t\t\t\t\t stash-\u003eiface))\n+\t\t\tgoto bail1;\n+\n+#if defined(LWS_WITH_SOCKS5)\n+\tif (!wsi-\u003evhost-\u003esocks_proxy_port)\n+\t\tlws_free_set_NULL(wsi-\u003eu.hdr.stash);\n+#endif\n+\n+\t/*\n+\t * Check with each extension if it is able to route and proxy this\n+\t * connection for us. For example, an extension like x-google-mux\n+\t * can handle this and then we don't need an actual socket for this\n+\t * connection.\n+\t */\n+\n+\tif (lws_ext_cb_all_exts(wsi-\u003econtext, wsi,\n+\t\t\t\tLWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,\n+\t\t\t\t(void *)stash-\u003eaddress,\n+\t\t\t\twsi-\u003ec_port) \u003e 0) {\n+\t\tlwsl_client(\u0022lws_client_connect: ext handling conn\u005cn\u0022);\n+\n+\t\tlws_set_timeout(wsi,\n+\t\t\tPENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,\n+\t\t\t AWAITING_TIMEOUT);\n+\n+\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_EXTENSION_CONNECT;\n+\t\treturn wsi;\n+\t}\n+\tlwsl_client(\u0022lws_client_connect: direct conn\u005cn\u0022);\n+\twsi-\u003econtext-\u003ecount_wsi_allocated++;\n+\n+\treturn lws_client_connect_2(wsi);\n+\n+bail1:\n+#if defined(LWS_WITH_SOCKS5)\n+\tif (!wsi-\u003evhost-\u003esocks_proxy_port)\n+\t\tlws_free_set_NULL(wsi-\u003eu.hdr.stash);\n+#endif\n+\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE struct lws *\n+lws_client_connect_extended(struct lws_context *context, const char *address,\n+\t\t\t int port, int ssl_connection, const char *path,\n+\t\t\t const char *host, const char *origin,\n+\t\t\t const char *protocol, int ietf_version_or_minus_one,\n+\t\t\t void *userdata)\n+{\n+\tstruct lws_client_connect_info i;\n+\n+\tmemset(\u0026i, 0, sizeof(i));\n+\n+\ti.context \u003d context;\n+\ti.address \u003d address;\n+\ti.port \u003d port;\n+\ti.ssl_connection \u003d ssl_connection;\n+\ti.path \u003d path;\n+\ti.host \u003d host;\n+\ti.origin \u003d origin;\n+\ti.protocol \u003d protocol;\n+\ti.ietf_version_or_minus_one \u003d ietf_version_or_minus_one;\n+\ti.userdata \u003d userdata;\n+\n+\treturn lws_client_connect_via_info(\u0026i);\n+}\n+\n+LWS_VISIBLE struct lws *\n+lws_client_connect(struct lws_context *context, const char *address,\n+\t\t\t int port, int ssl_connection, const char *path,\n+\t\t\t const char *host, const char *origin,\n+\t\t\t const char *protocol, int ietf_version_or_minus_one)\n+{\n+\tstruct lws_client_connect_info i;\n+\n+\tmemset(\u0026i, 0, sizeof(i));\n+\n+\ti.context \u003d context;\n+\ti.address \u003d address;\n+\ti.port \u003d port;\n+\ti.ssl_connection \u003d ssl_connection;\n+\ti.path \u003d path;\n+\ti.host \u003d host;\n+\ti.origin \u003d origin;\n+\ti.protocol \u003d protocol;\n+\ti.ietf_version_or_minus_one \u003d ietf_version_or_minus_one;\n+\ti.userdata \u003d NULL;\n+\n+\treturn lws_client_connect_via_info(\u0026i);\n+}\n+\n+#if defined(LWS_WITH_SOCKS5)\n+void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,\n+\t\t\tssize_t *msg_len)\n+{\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tssize_t len \u003d 0, n, passwd_len;\n+\tshort net_num;\n+\tchar *p;\n+\n+\tswitch (type) {\n+\tcase SOCKS_MSG_GREETING:\n+\t\t/* socks version, version 5 only */\n+\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_VERSION_5;\n+\t\t/* number of methods */\n+\t\tpt-\u003eserv_buf[len++] \u003d 2;\n+\t\t/* username password method */\n+\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_AUTH_USERNAME_PASSWORD;\n+\t\t/* no authentication method */\n+\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_AUTH_NO_AUTH;\n+\t\tbreak;\n+\n+\tcase SOCKS_MSG_USERNAME_PASSWORD:\n+\t\tn \u003d strlen(wsi-\u003evhost-\u003esocks_user);\n+\t\tpasswd_len \u003d strlen(wsi-\u003evhost-\u003esocks_password);\n+\n+\t\t/* the subnegotiation version */\n+\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_SUBNEGOTIATION_VERSION_1;\n+\t\t/* length of the user name */\n+\t\tpt-\u003eserv_buf[len++] \u003d n;\n+\t\t/* user name */\n+\t\tstrncpy((char *)\u0026pt-\u003eserv_buf[len], wsi-\u003evhost-\u003esocks_user,\n+\t\t\tcontext-\u003ept_serv_buf_size - len);\n+\t\tlen +\u003d n;\n+\t\t/* length of the password */\n+\t\tpt-\u003eserv_buf[len++] \u003d passwd_len;\n+\t\t/* password */\n+\t\tstrncpy((char *)\u0026pt-\u003eserv_buf[len], wsi-\u003evhost-\u003esocks_password,\n+\t\t\tcontext-\u003ept_serv_buf_size - len);\n+\t\tlen +\u003d passwd_len;\n+\t\tbreak;\n+\n+\tcase SOCKS_MSG_CONNECT:\n+\t\tp \u003d (char*)\u0026net_num;\n+\n+\t\t/* socks version */\n+\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_VERSION_5;\n+\t\t/* socks command */\n+\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_COMMAND_CONNECT;\n+\t\t/* reserved */\n+\t\tpt-\u003eserv_buf[len++] \u003d 0;\n+\t\t/* address type */\n+\t\tpt-\u003eserv_buf[len++] \u003d SOCKS_ATYP_DOMAINNAME;\n+\t\t/* skip length, we fill it in at the end */\n+\t\tn \u003d len++;\n+\n+\t\t/* the address we tell SOCKS proxy to connect to */\n+\t\tstrncpy((char *)\u0026(pt-\u003eserv_buf[len]), wsi-\u003eu.hdr.stash-\u003eaddress,\n+\t\t\tcontext-\u003ept_serv_buf_size - len);\n+\t\tlen +\u003d strlen(wsi-\u003eu.hdr.stash-\u003eaddress);\n+\t\tnet_num \u003d htons(wsi-\u003ec_port);\n+\n+\t\t/* the port we tell SOCKS proxy to connect to */\n+\t\tpt-\u003eserv_buf[len++] \u003d p[0];\n+\t\tpt-\u003eserv_buf[len++] \u003d p[1];\n+\n+\t\t/* the length of the address, excluding port */\n+\t\tpt-\u003eserv_buf[n] \u003d strlen(wsi-\u003eu.hdr.stash-\u003eaddress);\n+\t\tbreak;\n+\t\t\n+\tdefault:\n+\t\treturn;\n+\t}\n+\n+\t*msg_len \u003d len;\n+}\n+#endif\ndiff --git a/lib/client/client-parser.c b/lib/client/client-parser.c\nnew file mode 100644\nindex 0000000..0e42dac\n--- /dev/null\n+++ b/lib/client/client-parser.c\n@@ -0,0 +1,598 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+/*\n+ * parsers.c: lws_rx_sm() needs to be roughly kept in\n+ * sync with changes here, esp related to ext draining\n+ */\n+\n+int lws_client_rx_sm(struct lws *wsi, unsigned char c)\n+{\n+\tint callback_action \u003d LWS_CALLBACK_CLIENT_RECEIVE;\n+\tint handled, n, m, rx_draining_ext \u003d 0;\n+\tunsigned short close_code;\n+\tstruct lws_tokens eff_buf;\n+\tunsigned char *pp;\n+\n+\tif (wsi-\u003eu.ws.rx_draining_ext) {\n+\t\tassert(!c);\n+\t\teff_buf.token \u003d NULL;\n+\t\teff_buf.token_len \u003d 0;\n+\t\tlws_remove_wsi_from_draining_ext_list(wsi);\n+\t\trx_draining_ext \u003d 1;\n+\t\tlwsl_debug(\u0022%s: doing draining flow\u005cn\u0022, __func__);\n+\n+\t\tgoto drain_extension;\n+\t}\n+\n+\tif (wsi-\u003esocket_is_permanently_unusable)\n+\t\treturn -1;\n+\n+\tswitch (wsi-\u003elws_rx_parse_state) {\n+\tcase LWS_RXPS_NEW:\n+\t\t/* control frames (PING) may interrupt checkable sequences */\n+\t\twsi-\u003eu.ws.defeat_check_utf8 \u003d 0;\n+\n+\t\tswitch (wsi-\u003eietf_spec_revision) {\n+\t\tcase 13:\n+\t\t\twsi-\u003eu.ws.opcode \u003d c \u0026 0xf;\n+\t\t\t/* revisit if an extension wants them... */\n+\t\t\tswitch (wsi-\u003eu.ws.opcode) {\n+\t\t\tcase LWSWSOPC_TEXT_FRAME:\n+\t\t\t\twsi-\u003eu.ws.rsv_first_msg \u003d (c \u0026 0x70);\n+\t\t\t\twsi-\u003eu.ws.continuation_possible \u003d 1;\n+\t\t\t\twsi-\u003eu.ws.check_utf8 \u003d lws_check_opt(\n+\t\t\t\t\twsi-\u003econtext-\u003eoptions,\n+\t\t\t\t\tLWS_SERVER_OPTION_VALIDATE_UTF8);\n+\t\t\t\twsi-\u003eu.ws.utf8 \u003d 0;\n+\t\t\t\tbreak;\n+\t\t\tcase LWSWSOPC_BINARY_FRAME:\n+\t\t\t\twsi-\u003eu.ws.rsv_first_msg \u003d (c \u0026 0x70);\n+\t\t\t\twsi-\u003eu.ws.check_utf8 \u003d 0;\n+\t\t\t\twsi-\u003eu.ws.continuation_possible \u003d 1;\n+\t\t\t\tbreak;\n+\t\t\tcase LWSWSOPC_CONTINUATION:\n+\t\t\t\tif (!wsi-\u003eu.ws.continuation_possible) {\n+\t\t\t\t\tlwsl_info(\u0022disordered continuation\u005cn\u0022);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\tcase LWSWSOPC_CLOSE:\n+\t\t\t\twsi-\u003eu.ws.check_utf8 \u003d 0;\n+\t\t\t\twsi-\u003eu.ws.utf8 \u003d 0;\n+\t\t\t\tbreak;\n+\t\t\tcase 3:\n+\t\t\tcase 4:\n+\t\t\tcase 5:\n+\t\t\tcase 6:\n+\t\t\tcase 7:\n+\t\t\tcase 0xb:\n+\t\t\tcase 0xc:\n+\t\t\tcase 0xd:\n+\t\t\tcase 0xe:\n+\t\t\tcase 0xf:\n+\t\t\t\tlwsl_info(\u0022illegal opcode\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\tdefault:\n+\t\t\t\twsi-\u003eu.ws.defeat_check_utf8 \u003d 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\twsi-\u003eu.ws.rsv \u003d (c \u0026 0x70);\n+\t\t\t/* revisit if an extension wants them... */\n+\t\t\tif (\n+#ifndef LWS_NO_EXTENSIONS\n+\t\t\t\t!wsi-\u003ecount_act_ext \u0026\u0026\n+#endif\n+\t\t\t\twsi-\u003eu.ws.rsv) {\n+\t\t\t\tlwsl_info(\u0022illegal rsv bits set\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\twsi-\u003eu.ws.final \u003d !!((c \u003e\u003e 7) \u0026 1);\n+\t\t\tlwsl_ext(\u0022%s: This RX frame Final %d\u005cn\u0022, __func__,\n+\t\t\t\t wsi-\u003eu.ws.final);\n+\n+\t\t\tif (wsi-\u003eu.ws.owed_a_fin \u0026\u0026\n+\t\t\t (wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_TEXT_FRAME ||\n+\t\t\t wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_BINARY_FRAME)) {\n+\t\t\t\tlwsl_info(\u0022hey you owed us a FIN\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tif ((!(wsi-\u003eu.ws.opcode \u0026 8)) \u0026\u0026 wsi-\u003eu.ws.final) {\n+\t\t\t\twsi-\u003eu.ws.continuation_possible \u003d 0;\n+\t\t\t\twsi-\u003eu.ws.owed_a_fin \u003d 0;\n+\t\t\t}\n+\n+\t\t\tif ((wsi-\u003eu.ws.opcode \u0026 8) \u0026\u0026 !wsi-\u003eu.ws.final) {\n+\t\t\t\tlwsl_info(\u0022control msg can't be fragmented\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tif (!wsi-\u003eu.ws.final)\n+\t\t\t\twsi-\u003eu.ws.owed_a_fin \u003d 1;\n+\n+\t\t\tswitch (wsi-\u003eu.ws.opcode) {\n+\t\t\tcase LWSWSOPC_TEXT_FRAME:\n+\t\t\tcase LWSWSOPC_BINARY_FRAME:\n+\t\t\t\twsi-\u003eu.ws.frame_is_binary \u003d wsi-\u003eu.ws.opcode \u003d\u003d\n+\t\t\t\t\t\t LWSWSOPC_BINARY_FRAME;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tlwsl_err(\u0022unknown spec version %02d\u005cn\u0022,\n+\t\t\t\t wsi-\u003eietf_spec_revision);\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN:\n+\n+\t\twsi-\u003eu.ws.this_frame_masked \u003d !!(c \u0026 0x80);\n+\n+\t\tswitch (c \u0026 0x7f) {\n+\t\tcase 126:\n+\t\t\t/* control frames are not allowed to have big lengths */\n+\t\t\tif (wsi-\u003eu.ws.opcode \u0026 8)\n+\t\t\t\tgoto illegal_ctl_length;\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN16_2;\n+\t\t\tbreak;\n+\t\tcase 127:\n+\t\t\t/* control frames are not allowed to have big lengths */\n+\t\t\tif (wsi-\u003eu.ws.opcode \u0026 8)\n+\t\t\t\tgoto illegal_ctl_length;\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_8;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\twsi-\u003eu.ws.rx_packet_length \u003d c;\n+\t\t\tif (wsi-\u003eu.ws.this_frame_masked)\n+\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n+\t\t\telse {\n+\t\t\t\tif (c)\n+\t\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n+\t\t\t\telse {\n+\t\t\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n+\t\t\t\t\tgoto spill;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN16_2:\n+\t\twsi-\u003eu.ws.rx_packet_length \u003d c \u003c\u003c 8;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN16_1;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN16_1:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d c;\n+\t\tif (wsi-\u003eu.ws.this_frame_masked)\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_1;\n+\t\telse {\n+\t\t\tif (wsi-\u003eu.ws.rx_packet_length)\n+\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n+\t\t\telse {\n+\t\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n+\t\t\t\tgoto spill;\n+\t\t\t}\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_8:\n+\t\tif (c \u0026 0x80) {\n+\t\t\tlwsl_warn(\u0022b63 of length must be zero\u005cn\u0022);\n+\t\t\t/* kill the connection */\n+\t\t\treturn -1;\n+\t\t}\n+#if defined __LP64__\n+\t\twsi-\u003eu.ws.rx_packet_length \u003d ((size_t)c) \u003c\u003c 56;\n+#else\n+\t\twsi-\u003eu.ws.rx_packet_length \u003d 0;\n+#endif\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_7;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_7:\n+#if defined __LP64__\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 48;\n+#endif\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_6;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_6:\n+#if defined __LP64__\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 40;\n+#endif\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_5;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_5:\n+#if defined __LP64__\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 32;\n+#endif\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_4;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_4:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 24;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_3;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_3:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 16;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_2;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_2:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 8;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_1;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_1:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d (size_t)c;\n+\t\tif (wsi-\u003eu.ws.this_frame_masked)\n+\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n+\t\telse {\n+\t\t\tif (wsi-\u003eu.ws.rx_packet_length)\n+\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n+\t\t\telse {\n+\t\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n+\t\t\t\tgoto spill;\n+\t\t\t}\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_1:\n+\t\twsi-\u003eu.ws.mask[0] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_2;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_2:\n+\t\twsi-\u003eu.ws.mask[1] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_3;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_3:\n+\t\twsi-\u003eu.ws.mask[2] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_4;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_4:\n+\t\twsi-\u003eu.ws.mask[3] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\n+\t\tif (wsi-\u003eu.ws.rx_packet_length)\n+\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n+\t\telse {\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n+\t\t\tgoto spill;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:\n+\n+\t\tassert(wsi-\u003eu.ws.rx_ubuf);\n+\n+\t\tif (wsi-\u003eu.ws.rx_draining_ext)\n+\t\t\tgoto drain_extension;\n+\n+\t\tif (wsi-\u003eu.ws.this_frame_masked \u0026\u0026 !wsi-\u003eu.ws.all_zero_nonce)\n+\t\t\tc ^\u003d wsi-\u003eu.ws.mask[(wsi-\u003eu.ws.mask_idx++) \u0026 3];\n+\n+\t\twsi-\u003eu.ws.rx_ubuf[LWS_PRE + (wsi-\u003eu.ws.rx_ubuf_head++)] \u003d c;\n+\n+\t\tif (--wsi-\u003eu.ws.rx_packet_length \u003d\u003d 0) {\n+\t\t\t/* spill because we have the whole frame */\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n+\t\t\tgoto spill;\n+\t\t}\n+\n+\t\t/*\n+\t\t * if there's no protocol max frame size given, we are\n+\t\t * supposed to default to context-\u003ept_serv_buf_size\n+\t\t */\n+\t\tif (!wsi-\u003eprotocol-\u003erx_buffer_size \u0026\u0026\n+\t\t wsi-\u003eu.ws.rx_ubuf_head !\u003d wsi-\u003econtext-\u003ept_serv_buf_size)\n+\t\t\tbreak;\n+\n+\t\tif (wsi-\u003eprotocol-\u003erx_buffer_size \u0026\u0026\n+\t\t wsi-\u003eu.ws.rx_ubuf_head !\u003d wsi-\u003eprotocol-\u003erx_buffer_size)\n+\t\t\tbreak;\n+\n+\t\t/* spill because we filled our rx buffer */\n+spill:\n+\n+\t\thandled \u003d 0;\n+\n+\t\t/*\n+\t\t * is this frame a control packet we should take care of at this\n+\t\t * layer? If so service it and hide it from the user callback\n+\t\t */\n+\n+\t\tswitch (wsi-\u003eu.ws.opcode) {\n+\t\tcase LWSWSOPC_CLOSE:\n+\t\t\tpp \u003d (unsigned char *)\u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n+\t\t\tif (lws_check_opt(wsi-\u003econtext-\u003eoptions,\n+\t\t\t\t\t LWS_SERVER_OPTION_VALIDATE_UTF8) \u0026\u0026\n+\t\t\t wsi-\u003eu.ws.rx_ubuf_head \u003e 2 \u0026\u0026\n+\t\t\t lws_check_utf8(\u0026wsi-\u003eu.ws.utf8, pp + 2,\n+\t\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head - 2))\n+\t\t\t\tgoto utf8_fail;\n+\n+\t\t\t/* is this an acknowledgement of our close? */\n+\t\t\tif (wsi-\u003estate \u003d\u003d LWSS_AWAITING_CLOSE_ACK) {\n+\t\t\t\t/*\n+\t\t\t\t * fine he has told us he is closing too, let's\n+\t\t\t\t * finish our close\n+\t\t\t\t */\n+\t\t\t\tlwsl_parser(\u0022seen server's close ack\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\n+\t\t\tlwsl_parser(\u0022client sees server close len \u003d %d\u005cn\u0022,\n+\t\t\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n+\t\t\tif (wsi-\u003eu.ws.rx_ubuf_head \u003e\u003d 2) {\n+\t\t\t\tclose_code \u003d (pp[0] \u003c\u003c 8) | pp[1];\n+\t\t\t\tif (close_code \u003c 1000 ||\n+\t\t\t\t close_code \u003d\u003d 1004 ||\n+\t\t\t\t close_code \u003d\u003d 1005 ||\n+\t\t\t\t close_code \u003d\u003d 1006 ||\n+\t\t\t\t close_code \u003d\u003d 1012 ||\n+\t\t\t\t close_code \u003d\u003d 1013 ||\n+\t\t\t\t close_code \u003d\u003d 1014 ||\n+\t\t\t\t close_code \u003d\u003d 1015 ||\n+\t\t\t\t (close_code \u003e\u003d 1016 \u0026\u0026 close_code \u003c 3000)\n+\t\t\t\t) {\n+\t\t\t\t\tpp[0] \u003d (LWS_CLOSE_STATUS_PROTOCOL_ERR \u003e\u003e 8) \u0026 0xff;\n+\t\t\t\t\tpp[1] \u003d LWS_CLOSE_STATUS_PROTOCOL_ERR \u0026 0xff;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif (user_callback_handle_rxflow(\n+\t\t\t\t\twsi-\u003eprotocol-\u003ecallback, wsi,\n+\t\t\t\t\tLWS_CALLBACK_WS_PEER_INITIATED_CLOSE,\n+\t\t\t\t\twsi-\u003euser_space, pp,\n+\t\t\t\t\twsi-\u003eu.ws.rx_ubuf_head))\n+\t\t\t\treturn -1;\n+\n+\t\t\tif (lws_partial_buffered(wsi))\n+\t\t\t\t/*\n+\t\t\t\t * if we're in the middle of something,\n+\t\t\t\t * we can't do a normal close response and\n+\t\t\t\t * have to just close our end.\n+\t\t\t\t */\n+\t\t\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n+\t\t\telse\n+\t\t\t\t/*\n+\t\t\t\t * parrot the close packet payload back\n+\t\t\t\t * we do not care about how it went, we are closing\n+\t\t\t\t * immediately afterwards\n+\t\t\t\t */\n+\t\t\t\tlws_write(wsi, (unsigned char *)\n+\t\t\t\t\t \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n+\t\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head,\n+\t\t\t\t\t LWS_WRITE_CLOSE);\n+\t\t\twsi-\u003estate \u003d LWSS_RETURNED_CLOSE_ALREADY;\n+\t\t\t/* close the connection */\n+\t\t\treturn -1;\n+\n+\t\tcase LWSWSOPC_PING:\n+\t\t\tlwsl_info(\u0022received %d byte ping, sending pong\u005cn\u0022,\n+\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n+\n+\t\t\t/* he set a close reason on this guy, ignore PING */\n+\t\t\tif (wsi-\u003eu.ws.close_in_ping_buffer_len)\n+\t\t\t\tgoto ping_drop;\n+\n+\t\t\tif (wsi-\u003eu.ws.ping_pending_flag) {\n+\t\t\t\t/*\n+\t\t\t\t * there is already a pending ping payload\n+\t\t\t\t * we should just log and drop\n+\t\t\t\t */\n+\t\t\t\tlwsl_parser(\u0022DROP PING since one pending\u005cn\u0022);\n+\t\t\t\tgoto ping_drop;\n+\t\t\t}\n+\n+\t\t\t/* control packets can only be \u003c 128 bytes long */\n+\t\t\tif (wsi-\u003eu.ws.rx_ubuf_head \u003e 128 - 3) {\n+\t\t\t\tlwsl_parser(\u0022DROP PING payload too large\u005cn\u0022);\n+\t\t\t\tgoto ping_drop;\n+\t\t\t}\n+\n+\t\t\t/* stash the pong payload */\n+\t\t\tmemcpy(wsi-\u003eu.ws.ping_payload_buf + LWS_PRE,\n+\t\t\t \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n+\t\t\t\twsi-\u003eu.ws.rx_ubuf_head);\n+\n+\t\t\twsi-\u003eu.ws.ping_payload_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n+\t\t\twsi-\u003eu.ws.ping_pending_flag \u003d 1;\n+\n+\t\t\t/* get it sent as soon as possible */\n+\t\t\tlws_callback_on_writable(wsi);\n+ping_drop:\n+\t\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n+\t\t\thandled \u003d 1;\n+\t\t\tbreak;\n+\n+\t\tcase LWSWSOPC_PONG:\n+\t\t\tlwsl_info(\u0022client receied pong\u005cn\u0022);\n+\t\t\tlwsl_hexdump(\u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n+\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n+\n+\t\t\tif (wsi-\u003epending_timeout \u003d\u003d\n+\t\t\t\t PENDING_TIMEOUT_WS_PONG_CHECK_GET_PONG) {\n+\t\t\t\tlwsl_info(\u0022%p: received expected PONG\u005cn\u0022, wsi);\n+\t\t\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\t\t\t}\n+\n+\t\t\t/* issue it */\n+\t\t\tcallback_action \u003d LWS_CALLBACK_CLIENT_RECEIVE_PONG;\n+\t\t\tbreak;\n+\n+\t\tcase LWSWSOPC_CONTINUATION:\n+\t\tcase LWSWSOPC_TEXT_FRAME:\n+\t\tcase LWSWSOPC_BINARY_FRAME:\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\n+\t\t\tlwsl_parser(\u0022Reserved opc 0x%2X\u005cn\u0022, wsi-\u003eu.ws.opcode);\n+\n+\t\t\t/*\n+\t\t\t * It's something special we can't understand here.\n+\t\t\t * Pass the payload up to the extension's parsing\n+\t\t\t * state machine.\n+\t\t\t */\n+\n+\t\t\teff_buf.token \u003d \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n+\t\t\teff_buf.token_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n+\n+\t\t\tif (lws_ext_cb_active(wsi,\n+\t\t\t\tLWS_EXT_CB_EXTENDED_PAYLOAD_RX,\n+\t\t\t\t\t\u0026eff_buf, 0) \u003c\u003d 0) {\n+\t\t\t\t/* not handled or failed */\n+\t\t\t\tlwsl_ext(\u0022Unhandled ext opc 0x%x\u005cn\u0022,\n+\t\t\t\t\t wsi-\u003eu.ws.opcode);\n+\t\t\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n+\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t\thandled \u003d 1;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/*\n+\t\t * No it's real payload, pass it up to the user callback.\n+\t\t * It's nicely buffered with the pre-padding taken care of\n+\t\t * so it can be sent straight out again using lws_write\n+\t\t */\n+\t\tif (handled)\n+\t\t\tgoto already_done;\n+\n+\t\teff_buf.token \u003d \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n+\t\teff_buf.token_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n+\n+\t\tif (wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_PONG \u0026\u0026 !eff_buf.token_len)\n+\t\t\tgoto already_done;\n+\n+drain_extension:\n+\t\tlwsl_ext(\u0022%s: passing %d to ext\u005cn\u0022, __func__, eff_buf.token_len);\n+\n+\t\tn \u003d lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, \u0026eff_buf, 0);\n+\t\tlwsl_ext(\u0022Ext RX returned %d\u005cn\u0022, n);\n+\t\tif (n \u003c 0) {\n+\t\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tlwsl_ext(\u0022post inflate eff_buf len %d\u005cn\u0022, eff_buf.token_len);\n+\n+\t\tif (rx_draining_ext \u0026\u0026 !eff_buf.token_len) {\n+\t\t\tlwsl_debug(\u0022 --- ending drain on 0 read result\u005cn\u0022);\n+\t\t\tgoto already_done;\n+\t\t}\n+\n+\t\tif (wsi-\u003eu.ws.check_utf8 \u0026\u0026 !wsi-\u003eu.ws.defeat_check_utf8) {\n+\t\t\tif (lws_check_utf8(\u0026wsi-\u003eu.ws.utf8,\n+\t\t\t\t\t (unsigned char *)eff_buf.token,\n+\t\t\t\t\t eff_buf.token_len))\n+\t\t\t\tgoto utf8_fail;\n+\n+\t\t\t/* we are ending partway through utf-8 character? */\n+\t\t\tif (!wsi-\u003eu.ws.rx_packet_length \u0026\u0026 wsi-\u003eu.ws.final \u0026\u0026\n+\t\t\t wsi-\u003eu.ws.utf8 \u0026\u0026 !n) {\n+\t\t\t\tlwsl_info(\u0022FINAL utf8 error\u005cn\u0022);\n+utf8_fail:\n+\t\t\t\tlwsl_info(\u0022utf8 error\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (eff_buf.token_len \u003c 0 \u0026\u0026\n+\t\t callback_action !\u003d LWS_CALLBACK_CLIENT_RECEIVE_PONG)\n+\t\t\tgoto already_done;\n+\n+\t\tif (!eff_buf.token)\n+\t\t\tgoto already_done;\n+\n+\t\teff_buf.token[eff_buf.token_len] \u003d '\u005c0';\n+\n+\t\tif (!wsi-\u003eprotocol-\u003ecallback)\n+\t\t\tgoto already_done;\n+\n+\t\tif (callback_action \u003d\u003d LWS_CALLBACK_CLIENT_RECEIVE_PONG)\n+\t\t\tlwsl_info(\u0022Client doing pong callback\u005cn\u0022);\n+\n+\t\tif (n \u0026\u0026 eff_buf.token_len)\n+\t\t\t/* extension had more... main loop will come back\n+\t\t\t * we want callback to be done with this set, if so,\n+\t\t\t * because lws_is_final() hides it was final until the\n+\t\t\t * last chunk\n+\t\t\t */\n+\t\t\tlws_add_wsi_to_draining_ext_list(wsi);\n+\t\telse\n+\t\t\tlws_remove_wsi_from_draining_ext_list(wsi);\n+\n+\t\tif (wsi-\u003estate \u003d\u003d LWSS_RETURNED_CLOSE_ALREADY ||\n+\t\t wsi-\u003estate \u003d\u003d LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION ||\n+\t\t wsi-\u003estate \u003d\u003d LWSS_AWAITING_CLOSE_ACK)\n+\t\t\tgoto already_done;\n+\n+\t\tm \u003d wsi-\u003eprotocol-\u003ecallback(wsi,\n+\t\t\t(enum lws_callback_reasons)callback_action,\n+\t\t\twsi-\u003euser_space, eff_buf.token, eff_buf.token_len);\n+\n+\t\t/* if user code wants to close, let caller know */\n+\t\tif (m)\n+\t\t\treturn 1;\n+\n+already_done:\n+\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n+\t\tbreak;\n+\tdefault:\n+\t\tlwsl_err(\u0022client rx illegal state\u005cn\u0022);\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+\n+illegal_ctl_length:\n+\tlwsl_warn(\u0022Control frame asking for extended length is illegal\u005cn\u0022);\n+\n+\t/* kill the connection */\n+\treturn -1;\n+}\n+\n+\ndiff --git a/lib/client/client.c b/lib/client/client.c\nnew file mode 100644\nindex 0000000..b2a4c12\n--- /dev/null\n+++ b/lib/client/client.c\n@@ -0,0 +1,1301 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2014 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+int\n+lws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)\n+{\n+\tint m;\n+\n+\tswitch (wsi-\u003emode) {\n+\tcase LWSCM_WSCL_WAITING_PROXY_REPLY:\n+\tcase LWSCM_WSCL_ISSUE_HANDSHAKE:\n+\tcase LWSCM_WSCL_WAITING_SERVER_REPLY:\n+\tcase LWSCM_WSCL_WAITING_EXTENSION_CONNECT:\n+\tcase LWSCM_WS_CLIENT:\n+\t\twhile (len) {\n+\t\t\t/*\n+\t\t\t * we were accepting input but now we stopped doing so\n+\t\t\t */\n+\t\t\tif (lws_is_flowcontrolled(wsi)) {\n+\t\t\t\tlwsl_debug(\u0022%s: caching %ld\u005cn\u0022, __func__, (long)len);\n+\t\t\t\tlws_rxflow_cache(wsi, *buf, 0, len);\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t\tif (wsi-\u003eu.ws.rx_draining_ext) {\n+#if !defined(LWS_NO_CLIENT)\n+\t\t\t\tif (wsi-\u003emode \u003d\u003d LWSCM_WS_CLIENT)\n+\t\t\t\t\tm \u003d lws_client_rx_sm(wsi, 0);\n+\t\t\t\telse\n+#endif\n+\t\t\t\t\tm \u003d lws_rx_sm(wsi, 0);\n+\t\t\t\tif (m \u003c 0)\n+\t\t\t\t\treturn -1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\t/* account for what we're using in rxflow buffer */\n+\t\t\tif (wsi-\u003erxflow_buffer)\n+\t\t\t\twsi-\u003erxflow_pos++;\n+\n+\t\t\tif (lws_client_rx_sm(wsi, *(*buf)++)) {\n+\t\t\t\tlwsl_debug(\u0022client_rx_sm exited\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tlen--;\n+\t\t}\n+\t\tlwsl_debug(\u0022%s: finished with %ld\u005cn\u0022, __func__, (long)len);\n+\t\treturn 0;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lws_client_http_body_pending(struct lws *wsi, int something_left_to_send)\n+{\n+\twsi-\u003eclient_http_body_pending \u003d !!something_left_to_send;\n+}\n+\n+int\n+lws_client_socket_service(struct lws_context *context, struct lws *wsi,\n+\t\t\t struct lws_pollfd *pollfd)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tchar *p \u003d (char *)\u0026pt-\u003eserv_buf[0];\n+\tconst char *cce \u003d NULL;\n+\tunsigned char c;\n+\tchar *sb \u003d p;\n+\tint n \u003d 0;\n+\tssize_t len \u003d 0;\n+#if defined(LWS_WITH_SOCKS5)\n+\tchar conn_mode \u003d 0, pending_timeout \u003d 0;\n+#endif\n+\n+\tswitch (wsi-\u003emode) {\n+\n+\tcase LWSCM_WSCL_WAITING_CONNECT:\n+\n+\t\t/*\n+\t\t * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE\n+\t\t * timeout protection set in client-handshake.c\n+\t\t */\n+\n+\t\tif (!lws_client_connect_2(wsi)) {\n+\t\t\t/* closed */\n+\t\t\tlwsl_client(\u0022closed\u005cn\u0022);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/* either still pending connection, or changed mode */\n+\t\treturn 0;\n+\n+#if defined(LWS_WITH_SOCKS5)\n+\t/* SOCKS Greeting Reply */\n+\tcase LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY:\n+\tcase LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY:\n+\tcase LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY:\n+\n+\t\t/* handle proxy hung up on us */\n+\n+\t\tif (pollfd-\u003erevents \u0026 LWS_POLLHUP) {\n+\t\t\tlwsl_warn(\u0022SOCKS connection %p (fd\u003d%d) dead\u005cn\u0022,\n+\t\t\t\t (void *)wsi, pollfd-\u003efd);\n+\t\t\tgoto bail3;\n+\t\t}\n+\n+\t\tn \u003d recv(wsi-\u003edesc.sockfd, sb, context-\u003ept_serv_buf_size, 0);\n+\t\tif (n \u003c 0) {\n+\t\t\tif (LWS_ERRNO \u003d\u003d LWS_EAGAIN) {\n+\t\t\t\tlwsl_debug(\u0022SOCKS read EAGAIN, retrying\u005cn\u0022);\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t\tlwsl_err(\u0022ERROR reading from SOCKS socket\u005cn\u0022);\n+\t\t\tgoto bail3;\n+\t\t}\n+\n+\t\tswitch (wsi-\u003emode) {\n+\n+\t\tcase LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY:\n+\t\t\tif (pt-\u003eserv_buf[0] !\u003d SOCKS_VERSION_5)\n+\t\t\t\tgoto socks_reply_fail;\n+\n+\t\t\tif (pt-\u003eserv_buf[1] \u003d\u003d SOCKS_AUTH_NO_AUTH) {\n+\t\t\t\tlwsl_client(\u0022SOCKS greeting reply: No Auth Method\u005cn\u0022);\n+\t\t\t\tsocks_generate_msg(wsi, SOCKS_MSG_CONNECT, \u0026len);\n+\t\t\t\tconn_mode \u003d LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;\n+\t\t\t\tpending_timeout \u003d PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;\n+\t\t\t\tgoto socks_send;\n+\t\t\t}\n+\n+\t\t\tif (pt-\u003eserv_buf[1] \u003d\u003d SOCKS_AUTH_USERNAME_PASSWORD) {\n+\t\t\t\tlwsl_client(\u0022SOCKS greeting reply: User/Pw Method\u005cn\u0022);\n+\t\t\t\tsocks_generate_msg(wsi, SOCKS_MSG_USERNAME_PASSWORD, \u0026len);\n+\t\t\t\tconn_mode \u003d LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY;\n+\t\t\t\tpending_timeout \u003d PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY;\n+\t\t\t\tgoto socks_send;\n+\t\t\t}\n+\t\t\tgoto socks_reply_fail;\n+\n+\t\tcase LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY:\n+\t\t\tif (pt-\u003eserv_buf[0] !\u003d SOCKS_SUBNEGOTIATION_VERSION_1 ||\n+\t\t\t pt-\u003eserv_buf[1] !\u003d SOCKS_SUBNEGOTIATION_STATUS_SUCCESS)\n+\t\t\t\tgoto socks_reply_fail;\n+\n+\t\t\tlwsl_client(\u0022SOCKS password OK, sending connect\u005cn\u0022);\n+\t\t\tsocks_generate_msg(wsi, SOCKS_MSG_CONNECT, \u0026len);\n+\t\t\tconn_mode \u003d LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;\n+\t\t\tpending_timeout \u003d PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;\n+socks_send:\n+\t\t\tn \u003d send(wsi-\u003edesc.sockfd, (char *)pt-\u003eserv_buf, len,\n+\t\t\t\t MSG_NOSIGNAL);\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tlwsl_debug(\u0022ERROR writing to socks proxy\u005cn\u0022);\n+\t\t\t\tgoto bail3;\n+\t\t\t}\n+\n+\t\t\tlws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);\n+\t\t\twsi-\u003emode \u003d conn_mode;\n+\t\t\tbreak;\n+\n+socks_reply_fail:\n+\t\t\tlwsl_notice(\u0022socks reply: v%d, err %d\u005cn\u0022,\n+\t\t\t\t pt-\u003eserv_buf[0], pt-\u003eserv_buf[1]);\n+\t\t\tgoto bail3;\n+\n+\t\tcase LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY:\n+\t\t\tif (pt-\u003eserv_buf[0] !\u003d SOCKS_VERSION_5 ||\n+\t\t\t pt-\u003eserv_buf[1] !\u003d SOCKS_REQUEST_REPLY_SUCCESS)\n+\t\t\t\tgoto socks_reply_fail;\n+\n+\t\t\tlwsl_client(\u0022socks connect OK\u005cn\u0022);\n+\n+\t\t\t/* free stash since we are done with it */\n+\t\t\tlws_free_set_NULL(wsi-\u003eu.hdr.stash);\n+\t\t\tif (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,\n+\t\t\t\t\t\t wsi-\u003evhost-\u003esocks_proxy_address))\n+\t\t\t\tgoto bail3;\n+\n+\t\t\twsi-\u003ec_port \u003d wsi-\u003evhost-\u003esocks_proxy_port;\n+\n+\t\t\t/* clear his proxy connection timeout */\n+\t\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\t\t\tgoto start_ws_handshake;\n+\t\t}\n+\t\tbreak;\n+#endif\n+\n+\tcase LWSCM_WSCL_WAITING_PROXY_REPLY:\n+\n+\t\t/* handle proxy hung up on us */\n+\n+\t\tif (pollfd-\u003erevents \u0026 LWS_POLLHUP) {\n+\n+\t\t\tlwsl_warn(\u0022Proxy connection %p (fd\u003d%d) dead\u005cn\u0022,\n+\t\t\t\t (void *)wsi, pollfd-\u003efd);\n+\n+\t\t\tgoto bail3;\n+\t\t}\n+\n+\t\tn \u003d recv(wsi-\u003edesc.sockfd, sb, context-\u003ept_serv_buf_size, 0);\n+\t\tif (n \u003c 0) {\n+\t\t\tif (LWS_ERRNO \u003d\u003d LWS_EAGAIN) {\n+\t\t\t\tlwsl_debug(\u0022Proxy read returned EAGAIN... retrying\u005cn\u0022);\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t\tlwsl_err(\u0022ERROR reading from proxy socket\u005cn\u0022);\n+\t\t\tgoto bail3;\n+\t\t}\n+\n+\t\tpt-\u003eserv_buf[13] \u003d '\u005c0';\n+\t\tif (strcmp(sb, \u0022HTTP/1.0 200 \u0022) \u0026\u0026\n+\t\t strcmp(sb, \u0022HTTP/1.1 200 \u0022)) {\n+\t\t\tlwsl_err(\u0022ERROR proxy: %s\u005cn\u0022, sb);\n+\t\t\tgoto bail3;\n+\t\t}\n+\n+\t\t/* clear his proxy connection timeout */\n+\n+\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\n+\t\t/* fallthru */\n+\n+\tcase LWSCM_WSCL_ISSUE_HANDSHAKE:\n+\n+\t\t/*\n+\t\t * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE\n+\t\t * timeout protection set in client-handshake.c\n+\t\t *\n+\t\t * take care of our lws_callback_on_writable\n+\t\t * happening at a time when there's no real connection yet\n+\t\t */\n+#if defined(LWS_WITH_SOCKS5)\n+start_ws_handshake:\n+#endif\n+\t\tif (lws_change_pollfd(wsi, LWS_POLLOUT, 0))\n+\t\t\treturn -1;\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\t\t/* we can retry this... just cook the SSL BIO the first time */\n+\n+\t\tif (wsi-\u003euse_ssl \u0026\u0026 !wsi-\u003essl) {\n+\t\t\tif (lws_ssl_client_bio_create(wsi))\n+\t\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (wsi-\u003euse_ssl) {\n+\t\t\tn \u003d lws_ssl_client_connect1(wsi);\n+\t\t\tif (!n)\n+\t\t\t\treturn 0;\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tcce \u003d \u0022lws_ssl_client_connect1 failed\u0022;\n+\t\t\t\tgoto bail3;\n+\t\t\t}\n+\t\t} else\n+\t\t\twsi-\u003essl \u003d NULL;\n+\n+\t\t/* fallthru */\n+\n+\tcase LWSCM_WSCL_WAITING_SSL:\n+\n+\t\tif (wsi-\u003euse_ssl) {\n+\t\t\tn \u003d lws_ssl_client_connect2(wsi);\n+\t\t\tif (!n)\n+\t\t\t\treturn 0;\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tcce \u003d \u0022lws_ssl_client_connect2 failed\u0022;\n+\t\t\t\tgoto bail3;\n+\t\t\t}\n+\t\t} else\n+\t\t\twsi-\u003essl \u003d NULL;\n+#endif\n+\n+\t\twsi-\u003emode \u003d LWSCM_WSCL_ISSUE_HANDSHAKE2;\n+\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,\n+\t\t\t\tcontext-\u003etimeout_secs);\n+\n+\t\t/* fallthru */\n+\n+\tcase LWSCM_WSCL_ISSUE_HANDSHAKE2:\n+\t\tp \u003d lws_generate_client_handshake(wsi, p);\n+\t\tif (p \u003d\u003d NULL) {\n+\t\t\tif (wsi-\u003emode \u003d\u003d LWSCM_RAW)\n+\t\t\t\treturn 0;\n+\n+\t\t\tlwsl_err(\u0022Failed to generate handshake for client\u005cn\u0022);\n+\t\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\t/* send our request to the server */\n+\t\tlws_latency_pre(context, wsi);\n+\n+\t\tn \u003d lws_ssl_capable_write(wsi, (unsigned char *)sb, p - sb);\n+\t\tlws_latency(context, wsi, \u0022send lws_issue_raw\u0022, n,\n+\t\t\t n \u003d\u003d p - sb);\n+\t\tswitch (n) {\n+\t\tcase LWS_SSL_CAPABLE_ERROR:\n+\t\t\tlwsl_debug(\u0022ERROR writing to client socket\u005cn\u0022);\n+\t\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\t\t\treturn 0;\n+\t\tcase LWS_SSL_CAPABLE_MORE_SERVICE:\n+\t\t\tlws_callback_on_writable(wsi);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (wsi-\u003eclient_http_body_pending) {\n+\t\t\twsi-\u003emode \u003d LWSCM_WSCL_ISSUE_HTTP_BODY;\n+\t\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,\n+\t\t\t\t\tcontext-\u003etimeout_secs);\n+\t\t\t/* user code must ask for writable callback */\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tgoto client_http_body_sent;\n+\n+\tcase LWSCM_WSCL_ISSUE_HTTP_BODY:\n+\t\tif (wsi-\u003eclient_http_body_pending) {\n+\t\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,\n+\t\t\t\t\tcontext-\u003etimeout_secs);\n+\t\t\t/* user code must ask for writable callback */\n+\t\t\tbreak;\n+\t\t}\n+client_http_body_sent:\n+\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_NAME_PART;\n+\t\twsi-\u003eu.hdr.lextable_pos \u003d 0;\n+\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SERVER_REPLY;\n+\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,\n+\t\t\t\tcontext-\u003etimeout_secs);\n+\t\tbreak;\n+\n+\tcase LWSCM_WSCL_WAITING_SERVER_REPLY:\n+\t\t/*\n+\t\t * handle server hanging up on us...\n+\t\t * but if there is POLLIN waiting, handle that first\n+\t\t */\n+\t\tif ((pollfd-\u003erevents \u0026 (LWS_POLLIN | LWS_POLLHUP)) \u003d\u003d\n+\t\t\t\t\t\t\t\tLWS_POLLHUP) {\n+\n+\t\t\tlwsl_debug(\u0022Server connection %p (fd\u003d%d) dead\u005cn\u0022,\n+\t\t\t\t(void *)wsi, pollfd-\u003efd);\n+\t\t\tcce \u003d \u0022Peer hung up\u0022;\n+\t\t\tgoto bail3;\n+\t\t}\n+\n+\t\tif (!(pollfd-\u003erevents \u0026 LWS_POLLIN))\n+\t\t\tbreak;\n+\n+\t\t/* interpret the server response\n+\t\t *\n+\t\t * HTTP/1.1 101 Switching Protocols\n+\t\t * Upgrade: websocket\n+\t\t * Connection: Upgrade\n+\t\t * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo\u003d\n+\t\t * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC\u003d\u003d\n+\t\t * Sec-WebSocket-Protocol: chat\n+\t\t *\n+\t\t * we have to take some care here to only take from the\n+\t\t * socket bytewise. The browser may (and has been seen to\n+\t\t * in the case that onopen() performs websocket traffic)\n+\t\t * coalesce both handshake response and websocket traffic\n+\t\t * in one packet, since at that point the connection is\n+\t\t * definitively ready from browser pov.\n+\t\t */\n+\t\tlen \u003d 1;\n+\t\twhile (wsi-\u003eu.hdr.parser_state !\u003d WSI_PARSING_COMPLETE \u0026\u0026\n+\t\t len \u003e 0) {\n+\t\t\tn \u003d lws_ssl_capable_read(wsi, \u0026c, 1);\n+\t\t\tlws_latency(context, wsi, \u0022send lws_issue_raw\u0022, n,\n+\t\t\t\t n \u003d\u003d 1);\n+\t\t\tswitch (n) {\n+\t\t\tcase 0:\n+\t\t\tcase LWS_SSL_CAPABLE_ERROR:\n+\t\t\t\tcce \u003d \u0022read failed\u0022;\n+\t\t\t\tgoto bail3;\n+\t\t\tcase LWS_SSL_CAPABLE_MORE_SERVICE:\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\n+\t\t\tif (lws_parse(wsi, c)) {\n+\t\t\t\tlwsl_warn(\u0022problems parsing header\u005cn\u0022);\n+\t\t\t\tgoto bail3;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/*\n+\t\t * hs may also be coming in multiple packets, there is a 5-sec\n+\t\t * libwebsocket timeout still active here too, so if parsing did\n+\t\t * not complete just wait for next packet coming in this state\n+\t\t */\n+\t\tif (wsi-\u003eu.hdr.parser_state !\u003d WSI_PARSING_COMPLETE)\n+\t\t\tbreak;\n+\n+\t\t/*\n+\t\t * otherwise deal with the handshake. If there's any\n+\t\t * packet traffic already arrived we'll trigger poll() again\n+\t\t * right away and deal with it that way\n+\t\t */\n+\t\treturn lws_client_interpret_server_handshake(wsi);\n+\n+bail3:\n+\t\tlwsl_info(\u0022closing conn at LWS_CONNMODE...SERVER_REPLY\u005cn\u0022);\n+\t\tif (cce)\n+\t\t\tlwsl_info(\u0022reason: %s\u005cn\u0022, cce);\n+\t\twsi-\u003eprotocol-\u003ecallback(wsi,\n+\t\t\tLWS_CALLBACK_CLIENT_CONNECTION_ERROR,\n+\t\t\twsi-\u003euser_space, (void *)cce, cce ? strlen(cce) : 0);\n+\t\twsi-\u003ealready_did_cce \u003d 1;\n+\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\t\treturn -1;\n+\n+\tcase LWSCM_WSCL_WAITING_EXTENSION_CONNECT:\n+\t\tlwsl_ext(\u0022LWSCM_WSCL_WAITING_EXTENSION_CONNECT\u005cn\u0022);\n+\t\tbreak;\n+\n+\tcase LWSCM_WSCL_PENDING_CANDIDATE_CHILD:\n+\t\tlwsl_ext(\u0022LWSCM_WSCL_PENDING_CANDIDATE_CHILD\u005cn\u0022);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * In-place str to lower case\n+ */\n+\n+static void\n+strtolower(char *s)\n+{\n+\twhile (*s) {\n+#ifdef LWS_PLAT_OPTEE\n+\t\tint tolower_optee(int c);\n+\t\t*s \u003d tolower_optee((int)*s);\n+#else\n+\t\t*s \u003d tolower((int)*s);\n+#endif\n+\t\ts++;\n+\t}\n+}\n+\n+int LWS_WARN_UNUSED_RESULT\n+lws_http_transaction_completed_client(struct lws *wsi)\n+{\n+\tlwsl_debug(\u0022%s: wsi %p\u005cn\u0022, __func__, wsi);\n+\t/* if we can't go back to accept new headers, drop the connection */\n+\tif (wsi-\u003eu.http.connection_type !\u003d HTTP_CONNECTION_KEEP_ALIVE) {\n+\t\tlwsl_info(\u0022%s: %p: close connection\u005cn\u0022, __func__, wsi);\n+\t\treturn 1;\n+\t}\n+\n+\t/* we don't support chained client connections yet */\n+\treturn 1;\n+#if 0\n+\t/* otherwise set ourselves up ready to go again */\n+\twsi-\u003estate \u003d LWSS_CLIENT_HTTP_ESTABLISHED;\n+\twsi-\u003emode \u003d LWSCM_HTTP_CLIENT_ACCEPTED;\n+\twsi-\u003eu.http.rx_content_length \u003d 0;\n+\twsi-\u003ehdr_parsing_completed \u003d 0;\n+\n+\t/* He asked for it to stay alive indefinitely */\n+\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\n+\t/*\n+\t * As client, nothing new is going to come until we ask for it\n+\t * we can drop the ah, if any\n+\t */\n+\tif (wsi-\u003eu.hdr.ah) {\n+\t\tlws_header_table_force_to_detachable_state(wsi);\n+\t\tlws_header_table_detach(wsi, 0);\n+\t}\n+\n+\t/* If we're (re)starting on headers, need other implied init */\n+\twsi-\u003eu.hdr.ues \u003d URIES_IDLE;\n+\n+\tlwsl_info(\u0022%s: %p: keep-alive await new transaction\u005cn\u0022, __func__, wsi);\n+\n+\treturn 0;\n+#endif\n+}\n+\n+LWS_VISIBLE LWS_EXTERN unsigned int\n+lws_http_client_http_response(struct lws *wsi)\n+{\n+\tif (!wsi-\u003eu.http.ah)\n+\t\treturn 0;\n+\n+\treturn wsi-\u003eu.http.ah-\u003ehttp_response;\n+}\n+\n+int\n+lws_client_interpret_server_handshake(struct lws *wsi)\n+{\n+\tint n, len, okay \u003d 0, port \u003d 0, ssl \u003d 0;\n+\tint close_reason \u003d LWS_CLOSE_STATUS_PROTOCOL_ERR;\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tconst char *pc, *prot, *ads \u003d NULL, *path, *cce \u003d NULL;\n+\tstruct allocated_headers *ah \u003d NULL;\n+\tchar *p, *q;\n+\tchar new_path[300];\n+#ifndef LWS_NO_EXTENSIONS\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tchar *sb \u003d (char *)\u0026pt-\u003eserv_buf[0];\n+\tconst struct lws_ext_options *opts;\n+\tconst struct lws_extension *ext;\n+\tchar ext_name[128];\n+\tconst char *c, *a;\n+\tchar ignore;\n+\tint more \u003d 1;\n+\tvoid *v;\n+#endif\n+\tif (wsi-\u003eu.hdr.stash)\n+\t\tlws_free_set_NULL(wsi-\u003eu.hdr.stash);\n+\n+\tah \u003d wsi-\u003eu.hdr.ah;\n+\tif (!wsi-\u003edo_ws) {\n+\t\t/* we are being an http client...\n+\t\t */\n+\t\tlws_union_transition(wsi, LWSCM_HTTP_CLIENT_ACCEPTED);\n+\t\twsi-\u003estate \u003d LWSS_CLIENT_HTTP_ESTABLISHED;\n+\t\twsi-\u003eu.http.ah \u003d ah;\n+\t\tah-\u003ehttp_response \u003d 0;\n+\t}\n+\n+\t/*\n+\t * well, what the server sent looked reasonable for syntax.\n+\t * Now let's confirm it sent all the necessary headers\n+\t *\n+\t * http (non-ws) client will expect something like this\n+\t *\n+\t * HTTP/1.0.200\n+\t * server:.libwebsockets\n+\t * content-type:.text/html\n+\t * content-length:.17703\n+\t * set-cookie:.test\u003dLWS_1456736240_336776_COOKIE;Max-Age\u003d360000\n+\t *\n+\t *\n+\t *\n+\t */\n+\n+\twsi-\u003eu.http.connection_type \u003d HTTP_CONNECTION_KEEP_ALIVE;\n+\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);\n+\tif (wsi-\u003edo_ws \u0026\u0026 !p) {\n+\t\tlwsl_info(\u0022no URI\u005cn\u0022);\n+\t\tcce \u003d \u0022HS: URI missing\u0022;\n+\t\tgoto bail3;\n+\t}\n+\tif (!p) {\n+\t\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP1_0);\n+\t\twsi-\u003eu.http.connection_type \u003d HTTP_CONNECTION_CLOSE;\n+\t}\n+\tif (!p) {\n+\t\tcce \u003d \u0022HS: URI missing\u0022;\n+\t\tlwsl_info(\u0022no URI\u005cn\u0022);\n+\t\tgoto bail3;\n+\t}\n+\tn \u003d atoi(p);\n+\tif (ah)\n+\t\tah-\u003ehttp_response \u003d n;\n+\n+\tif (n \u003d\u003d 301 || n \u003d\u003d 302 || n \u003d\u003d 303 || n \u003d\u003d 307 || n \u003d\u003d 308) {\n+\t\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);\n+\t\tif (!p) {\n+\t\t\tcce \u003d \u0022HS: Redirect code but no Location\u0022;\n+\t\t\tgoto bail3;\n+\t\t}\n+\n+\t\t/* Relative reference absolute path */\n+\t\tif (p[0] \u003d\u003d '/')\n+\t\t{\n+#ifdef LWS_OPENSSL_SUPPORT\n+\t\t\tssl \u003d wsi-\u003euse_ssl;\n+#endif\n+\t\t\tads \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);\n+\t\t\tport \u003d wsi-\u003ec_port;\n+\t\t\tpath \u003d p + 1; /* +1 as lws_client_reset expects leading / to be omitted */\n+\t\t}\n+\t\t/* Absolute (Full) URI */\n+\t\telse if (strchr(p, ':'))\n+\t\t{\n+\t\t\tif (lws_parse_uri(p, \u0026prot, \u0026ads, \u0026port, \u0026path)) {\n+\t\t\t\tcce \u003d \u0022HS: URI did not parse\u0022;\n+\t\t\t\tgoto bail3;\n+\t\t\t}\n+\n+\t\t\tif (!strcmp(prot, \u0022wss\u0022) || !strcmp(prot, \u0022https\u0022))\n+\t\t\t\tssl \u003d 1;\n+\t\t}\n+\t\t/* Relative reference relative path */\n+\t\telse\n+\t\t{\n+\t\t\t/* This doesn't try to calculate an absolute path, that will be left to the server */\n+#ifdef LWS_OPENSSL_SUPPORT\n+\t\t\tssl \u003d wsi-\u003euse_ssl;\n+#endif\n+\t\t\tads \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);\n+\t\t\tport \u003d wsi-\u003ec_port;\n+\t\t\tpath \u003d new_path + 1; /* +1 as lws_client_reset expects leading / to be omitted */\n+\t\t\tstrncpy(new_path, lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI), sizeof(new_path));\n+\t\t\tnew_path[sizeof(new_path) - 1] \u003d '\u005c0';\n+\t\t\tq \u003d strrchr(new_path, '/');\n+\t\t\tif (q)\n+\t\t\t{\n+\t\t\t\tstrncpy(q + 1, p, sizeof(new_path) - (q - new_path) - 1);\n+\t\t\t\tnew_path[sizeof(new_path) - 1] \u003d '\u005c0';\n+\t\t\t}\n+\t\t\telse\n+\t\t\t{\n+\t\t\t\tpath \u003d p;\n+\t\t\t}\n+\t\t}\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\t\tif (wsi-\u003euse_ssl \u0026\u0026 !ssl) {\n+\t\t\tcce \u003d \u0022HS: Redirect attempted SSL downgrade\u0022;\n+\t\t\tgoto bail3;\n+\t\t}\n+#endif\n+\n+\t\tif (!lws_client_reset(\u0026wsi, ssl, ads, port, path, ads)) {\n+\t\t\t/* there are two ways to fail out with NULL return...\n+\t\t\t * simple, early problem where the wsi is intact, or\n+\t\t\t * we went through with the reconnect attempt and the\n+\t\t\t * wsi is already closed. In the latter case, the wsi\n+\t\t\t * has beet set to NULL additionally.\n+\t\t\t */\n+\t\t\tlwsl_err(\u0022Redirect failed\u005cn\u0022);\n+\t\t\tcce \u003d \u0022HS: Redirect failed\u0022;\n+\t\t\tif (wsi)\n+\t\t\t\tgoto bail3;\n+\n+\t\t\treturn 1;\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\n+\tif (!wsi-\u003edo_ws) {\n+\t\tif (n !\u003d 200 \u0026\u0026 n !\u003d 201 \u0026\u0026 n !\u003d 304 \u0026\u0026 n !\u003d 401) {\n+\t\t\tlwsl_notice(\u0022Connection failed with code %d\u005cn\u0022, n);\n+\t\t\tcce \u003d \u0022HS: Server unrecognized response code\u0022;\n+\t\t\tgoto bail2;\n+\t\t}\n+\n+#ifdef LWS_WITH_HTTP_PROXY\n+\t\twsi-\u003eperform_rewrite \u003d 0;\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {\n+\t\t\tif (!strncmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE),\n+\t\t\t\t \u0022text/html\u0022, 9))\n+\t\t\t\twsi-\u003eperform_rewrite \u003d 1;\n+\t\t}\n+#endif\n+\n+\t\t/* allocate the per-connection user memory (if any) */\n+\t\tif (lws_ensure_user_space(wsi)) {\n+\t\t\tlwsl_err(\u0022Problem allocating wsi user mem\u005cn\u0022);\n+\t\t\tcce \u003d \u0022HS: OOM\u0022;\n+\t\t\tgoto bail2;\n+\t\t}\n+\n+\t\t/* he may choose to send us stuff in chunked transfer-coding */\n+\t\twsi-\u003echunked \u003d 0;\n+\t\twsi-\u003echunk_remaining \u003d 0; /* ie, next thing is chunk size */\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING)) {\n+\t\t\twsi-\u003echunked \u003d !strcmp(lws_hdr_simple_ptr(wsi,\n+\t\t\t\t\t WSI_TOKEN_HTTP_TRANSFER_ENCODING),\n+\t\t\t\t\t\u0022chunked\u0022);\n+\t\t\t/* first thing is hex, after payload there is crlf */\n+\t\t\twsi-\u003echunk_parser \u003d ELCP_HEX;\n+\t\t}\n+\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n+\t\t\twsi-\u003eu.http.rx_content_length \u003d\n+\t\t\t\t\tatoll(lws_hdr_simple_ptr(wsi,\n+\t\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_LENGTH));\n+\t\t\tlwsl_notice(\u0022%s: incoming content length %llu\u005cn\u0022, __func__,\n+\t\t\t\t\t(unsigned long long)wsi-\u003eu.http.rx_content_length);\n+\t\t\twsi-\u003eu.http.rx_content_remain \u003d wsi-\u003eu.http.rx_content_length;\n+\t\t} else /* can't do 1.1 without a content length or chunked */\n+\t\t\tif (!wsi-\u003echunked)\n+\t\t\t\twsi-\u003eu.http.connection_type \u003d HTTP_CONNECTION_CLOSE;\n+\n+\t\t/*\n+\t\t * we seem to be good to go, give client last chance to check\n+\t\t * headers and OK it\n+\t\t */\n+\t\tif (wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,\n+\t\t\t\t\t wsi-\u003euser_space, NULL, 0)) {\n+\n+\t\t\tcce \u003d \u0022HS: disallowed by client filter\u0022;\n+\t\t\tgoto bail2;\n+\t\t}\n+\n+\t\t/* clear his proxy connection timeout */\n+\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\n+\t\twsi-\u003erxflow_change_to \u003d LWS_RXFLOW_ALLOW;\n+\n+\t\t/* call him back to inform him he is up */\n+\t\tif (wsi-\u003eprotocol-\u003ecallback(wsi,\n+\t\t\t\t\t LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,\n+\t\t\t\t\t wsi-\u003euser_space, NULL, 0)) {\n+\t\t\tcce \u003d \u0022HS: disallowed at ESTABLISHED\u0022;\n+\t\t\tgoto bail3;\n+\t\t}\n+\n+\t\t/* free up his parsing allocations */\n+\t\tlws_header_table_detach(wsi, 0);\n+\n+\t\tlwsl_notice(\u0022%s: client connection up\u005cn\u0022, __func__);\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) \u003d\u003d 0) {\n+\t\tlwsl_info(\u0022no ACCEPT\u005cn\u0022);\n+\t\tcce \u003d \u0022HS: ACCEPT missing\u0022;\n+\t\tgoto bail3;\n+\t}\n+\n+\tif (p \u0026\u0026 strncmp(p, \u0022101\u0022, 3)) {\n+\t\tlwsl_warn(\n+\t\t \u0022lws_client_handshake: got bad HTTP response '%s'\u005cn\u0022, p);\n+\t\tcce \u003d \u0022HS: ws upgrade response not 101\u0022;\n+\t\tgoto bail3;\n+\t}\n+\n+\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE);\n+\tif (!p) {\n+\t\tlwsl_info(\u0022no UPGRADE\u005cn\u0022);\n+\t\tcce \u003d \u0022HS: UPGRADE missing\u0022;\n+\t\tgoto bail3;\n+\t}\n+\tstrtolower(p);\n+\tif (strcmp(p, \u0022websocket\u0022)) {\n+\t\tlwsl_warn(\n+\t\t \u0022lws_client_handshake: got bad Upgrade header '%s'\u005cn\u0022, p);\n+\t\tcce \u003d \u0022HS: Upgrade to something other than websocket\u0022;\n+\t\tgoto bail3;\n+\t}\n+\n+\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_CONNECTION);\n+\tif (!p) {\n+\t\tlwsl_info(\u0022no Connection hdr\u005cn\u0022);\n+\t\tcce \u003d \u0022HS: CONNECTION missing\u0022;\n+\t\tgoto bail3;\n+\t}\n+\tstrtolower(p);\n+\tif (strcmp(p, \u0022upgrade\u0022)) {\n+\t\tlwsl_warn(\u0022lws_client_int_s_hs: bad header %s\u005cn\u0022, p);\n+\t\tcce \u003d \u0022HS: UPGRADE malformed\u0022;\n+\t\tgoto bail3;\n+\t}\n+\n+\tpc \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);\n+\tif (!pc) {\n+\t\tlwsl_parser(\u0022lws_client_int_s_hs: no protocol list\u005cn\u0022);\n+\t} else\n+\t\tlwsl_parser(\u0022lws_client_int_s_hs: protocol list '%s'\u005cn\u0022, pc);\n+\n+\t/*\n+\t * confirm the protocol the server wants to talk was in the list\n+\t * of protocols we offered\n+\t */\n+\n+\tlen \u003d lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);\n+\tif (!len) {\n+\t\tlwsl_info(\u0022lws_client_int_s_hs: WSI_TOKEN_PROTOCOL is null\u005cn\u0022);\n+\t\t/*\n+\t\t * no protocol name to work from,\n+\t\t * default to first protocol\n+\t\t */\n+\t\tn \u003d 0;\n+\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[0];\n+\t\tgoto check_extensions;\n+\t}\n+\n+\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);\n+\tlen \u003d strlen(p);\n+\n+\twhile (pc \u0026\u0026 *pc \u0026\u0026 !okay) {\n+\t\tif (!strncmp(pc, p, len) \u0026\u0026\n+\t\t (pc[len] \u003d\u003d ',' || pc[len] \u003d\u003d '\u005c0')) {\n+\t\t\tokay \u003d 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\twhile (*pc \u0026\u0026 *pc++ !\u003d ',')\n+\t\t\t;\n+\t\twhile (*pc \u0026\u0026 *pc \u003d\u003d ' ')\n+\t\t\tpc++;\n+\t}\n+\n+\tif (!okay) {\n+\t\tlwsl_err(\u0022lws_client_int_s_hs: got bad protocol %s\u005cn\u0022, p);\n+\t\tcce \u003d \u0022HS: PROTOCOL malformed\u0022;\n+\t\tgoto bail2;\n+\t}\n+\n+\t/*\n+\t * identify the selected protocol struct and set it\n+\t */\n+\tn \u003d 0;\n+\twsi-\u003eprotocol \u003d NULL;\n+\twhile (wsi-\u003evhost-\u003eprotocols[n].callback \u0026\u0026 !wsi-\u003eprotocol) {\n+\t\tif (strcmp(p, wsi-\u003evhost-\u003eprotocols[n].name) \u003d\u003d 0) {\n+\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[n];\n+\t\t\tbreak;\n+\t\t}\n+\t\tn++;\n+\t}\n+\n+\tif (wsi-\u003eprotocol \u003d\u003d NULL) {\n+\t\tlwsl_err(\u0022lws_client_int_s_hs: fail protocol %s\u005cn\u0022, p);\n+\t\tcce \u003d \u0022HS: Cannot match protocol\u0022;\n+\t\tgoto bail2;\n+\t}\n+\n+check_extensions:\n+\t/*\n+\t * stitch protocol choice into the vh protocol linked list\n+\t * We always insert ourselves at the start of the list\n+\t *\n+\t * X \u003c-\u003e B\n+\t * X \u003c-\u003e pAn \u003c-\u003e pB\n+\t */\n+\t//lwsl_err(\u0022%s: pre insert vhost start wsi %p, that wsi prev \u003d\u003d %p\u005cn\u0022,\n+\t//\t\t__func__,\n+\t//\t\twsi-\u003evhost-\u003esame_vh_protocol_list[n],\n+\t//\t\twsi-\u003esame_vh_protocol_prev);\n+\twsi-\u003esame_vh_protocol_prev \u003d /* guy who points to us */\n+\t\t\u0026wsi-\u003evhost-\u003esame_vh_protocol_list[n];\n+\twsi-\u003esame_vh_protocol_next \u003d /* old first guy is our next */\n+\t\t\twsi-\u003evhost-\u003esame_vh_protocol_list[n];\n+\t/* we become the new first guy */\n+\twsi-\u003evhost-\u003esame_vh_protocol_list[n] \u003d wsi;\n+\n+\tif (wsi-\u003esame_vh_protocol_next)\n+\t\t/* old first guy points back to us now */\n+\t\twsi-\u003esame_vh_protocol_next-\u003esame_vh_protocol_prev \u003d\n+\t\t\t\t\u0026wsi-\u003esame_vh_protocol_next;\n+\n+#ifndef LWS_NO_EXTENSIONS\n+\t/* instantiate the accepted extensions */\n+\n+\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {\n+\t\tlwsl_ext(\u0022no client extensions allowed by server\u005cn\u0022);\n+\t\tgoto check_accept;\n+\t}\n+\n+\t/*\n+\t * break down the list of server accepted extensions\n+\t * and go through matching them or identifying bogons\n+\t */\n+\n+\tif (lws_hdr_copy(wsi, sb, context-\u003ept_serv_buf_size, WSI_TOKEN_EXTENSIONS) \u003c 0) {\n+\t\tlwsl_warn(\u0022ext list from server failed to copy\u005cn\u0022);\n+\t\tcce \u003d \u0022HS: EXT: list too big\u0022;\n+\t\tgoto bail2;\n+\t}\n+\n+\tc \u003d sb;\n+\tn \u003d 0;\n+\tignore \u003d 0;\n+\ta \u003d NULL;\n+\twhile (more) {\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 (!a)\n+\t\t\t\t\ta \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+\n+\t\t\text_name[n] \u003d *c++;\n+\t\t\tif (n \u003c sizeof(ext_name) - 1)\n+\t\t\t\tn++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\text_name[n] \u003d '\u005c0';\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\t/* check we actually support it */\n+\n+\t\tlwsl_notice(\u0022checking client ext %s\u005cn\u0022, ext_name);\n+\n+\t\tn \u003d 0;\n+\t\text \u003d wsi-\u003evhost-\u003eextensions;\n+\t\twhile (ext \u0026\u0026 ext-\u003ecallback) {\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\tn \u003d 1;\n+\t\t\tlwsl_notice(\u0022instantiating client ext %s\u005cn\u0022, ext_name);\n+\n+\t\t\t/* instantiate the extension on this conn */\n+\n+\t\t\twsi-\u003eactive_extensions[wsi-\u003ecount_act_ext] \u003d ext;\n+\n+\t\t\t/* allow him to construct his ext instance */\n+\n+\t\t\tif (ext-\u003ecallback(lws_get_context(wsi), ext, wsi,\n+\t\t\t\t LWS_EXT_CB_CLIENT_CONSTRUCT,\n+\t\t\t\t (void *)\u0026wsi-\u003eact_ext_user[wsi-\u003ecount_act_ext],\n+\t\t\t\t (void *)\u0026opts, 0)) {\n+\t\t\t\tlwsl_info(\u0022 ext %s failed construction\u005cn\u0022, ext_name);\n+\t\t\t\text++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/*\n+\t\t\t * allow the user code to override ext defaults if it\n+\t\t\t * wants to\n+\t\t\t */\n+\t\t\text_name[0] \u003d '\u005c0';\n+\t\t\tif (user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback,\n+\t\t\t\t\twsi, LWS_CALLBACK_WS_EXT_DEFAULTS,\n+\t\t\t\t\t(char *)ext-\u003ename, ext_name,\n+\t\t\t\t\tsizeof(ext_name))) {\n+\t\t\t\tcce \u003d \u0022HS: EXT: failed setting defaults\u0022;\n+\t\t\t\tgoto bail2;\n+\t\t\t}\n+\n+\t\t\tif (ext_name[0] \u0026\u0026\n+\t\t\t lws_ext_parse_options(ext, wsi, wsi-\u003eact_ext_user[\n+\t\t\t\t\t\t wsi-\u003ecount_act_ext], opts, ext_name,\n+\t\t\t\t\t\t strlen(ext_name))) {\n+\t\t\t\tlwsl_err(\u0022%s: unable to parse user defaults '%s'\u0022,\n+\t\t\t\t\t __func__, ext_name);\n+\t\t\t\tcce \u003d \u0022HS: EXT: failed parsing defaults\u0022;\n+\t\t\t\tgoto bail2;\n+\t\t\t}\n+\n+\t\t\t/*\n+\t\t\t * give the extension the server options\n+\t\t\t */\n+\t\t\tif (a \u0026\u0026 lws_ext_parse_options(ext, wsi,\n+\t\t\t\t\twsi-\u003eact_ext_user[wsi-\u003ecount_act_ext],\n+\t\t\t\t\topts, a, c - a)) {\n+\t\t\t\tlwsl_err(\u0022%s: unable to parse remote def '%s'\u0022,\n+\t\t\t\t\t __func__, a);\n+\t\t\t\tcce \u003d \u0022HS: EXT: failed parsing options\u0022;\n+\t\t\t\tgoto bail2;\n+\t\t\t}\n+\n+\t\t\tif (ext-\u003ecallback(lws_get_context(wsi), ext, wsi,\n+\t\t\t\t\tLWS_EXT_CB_OPTION_CONFIRM,\n+\t\t\t\t wsi-\u003eact_ext_user[wsi-\u003ecount_act_ext],\n+\t\t\t\t NULL, 0)) {\n+\t\t\t\tlwsl_err(\u0022%s: ext %s rejects server options %s\u0022,\n+\t\t\t\t\t __func__, ext-\u003ename, a);\n+\t\t\t\tcce \u003d \u0022HS: EXT: Rejects server options\u0022;\n+\t\t\t\tgoto bail2;\n+\t\t\t}\n+\n+\t\t\twsi-\u003ecount_act_ext++;\n+\n+\t\t\text++;\n+\t\t}\n+\n+\t\tif (n \u003d\u003d 0) {\n+\t\t\tlwsl_warn(\u0022Unknown ext '%s'!\u005cn\u0022, ext_name);\n+\t\t\tcce \u003d \u0022HS: EXT: unknown ext\u0022;\n+\t\t\tgoto bail2;\n+\t\t}\n+\n+\t\ta \u003d NULL;\n+\t\tn \u003d 0;\n+\t}\n+\n+check_accept:\n+#endif\n+\n+\t/*\n+\t * Confirm his accept token is the one we precomputed\n+\t */\n+\n+\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT);\n+\tif (strcmp(p, wsi-\u003eu.hdr.ah-\u003einitial_handshake_hash_base64)) {\n+\t\tlwsl_warn(\u0022lws_client_int_s_hs: accept '%s' wrong vs '%s'\u005cn\u0022, p,\n+\t\t\t\t wsi-\u003eu.hdr.ah-\u003einitial_handshake_hash_base64);\n+\t\tcce \u003d \u0022HS: Accept hash wrong\u0022;\n+\t\tgoto bail2;\n+\t}\n+\n+\t/* allocate the per-connection user memory (if any) */\n+\tif (lws_ensure_user_space(wsi)) {\n+\t\tlwsl_err(\u0022Problem allocating wsi user mem\u005cn\u0022);\n+\t\tcce \u003d \u0022HS: OOM\u0022;\n+\t\tgoto bail2;\n+\t}\n+\n+\t/*\n+\t * we seem to be good to go, give client last chance to check\n+\t * headers and OK it\n+\t */\n+\tif (wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,\n+\t\t\t\t wsi-\u003euser_space, NULL, 0)) {\n+\t\tcce \u003d \u0022HS: Rejected by filter cb\u0022;\n+\t\tgoto bail2;\n+\t}\n+\n+\t/* clear his proxy connection timeout */\n+\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\n+\t/* free up his parsing allocations */\n+\tlws_header_table_detach(wsi, 0);\n+\n+\tlws_union_transition(wsi, LWSCM_WS_CLIENT);\n+\twsi-\u003estate \u003d LWSS_ESTABLISHED;\n+\tlws_restart_ws_ping_pong_timer(wsi);\n+\n+\twsi-\u003erxflow_change_to \u003d LWS_RXFLOW_ALLOW;\n+\n+\t/*\n+\t * create the frame buffer for this connection according to the\n+\t * size mentioned in the protocol definition. If 0 there, then\n+\t * use a big default for compatibility\n+\t */\n+\tn \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n+\tif (!n)\n+\t\tn \u003d context-\u003ept_serv_buf_size;\n+\tn +\u003d LWS_PRE;\n+\twsi-\u003eu.ws.rx_ubuf \u003d lws_malloc(n + 4 /* 0x0000ffff zlib */, \u0022client frame buffer\u0022);\n+\tif (!wsi-\u003eu.ws.rx_ubuf) {\n+\t\tlwsl_err(\u0022Out of Mem allocating rx buffer %d\u005cn\u0022, n);\n+\t\tcce \u003d \u0022HS: OOM\u0022;\n+\t\tgoto bail2;\n+\t}\n+ wsi-\u003eu.ws.rx_ubuf_alloc \u003d n;\n+\tlwsl_info(\u0022Allocating client RX buffer %d\u005cn\u0022, n);\n+\n+#if !defined(LWS_WITH_ESP32)\n+\tif (setsockopt(wsi-\u003edesc.sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)\u0026n,\n+\t\t sizeof n)) {\n+\t\tlwsl_warn(\u0022Failed to set SNDBUF to %d\u0022, n);\n+\t\tcce \u003d \u0022HS: SO_SNDBUF failed\u0022;\n+\t\tgoto bail3;\n+\t}\n+#endif\n+\n+\tlwsl_debug(\u0022handshake OK for protocol %s\u005cn\u0022, wsi-\u003eprotocol-\u003ename);\n+\n+\t/* call him back to inform him he is up */\n+\n+\tif (wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_ESTABLISHED,\n+\t\t\t\t wsi-\u003euser_space, NULL, 0)) {\n+\t\tcce \u003d \u0022HS: Rejected at CLIENT_ESTABLISHED\u0022;\n+\t\tgoto bail3;\n+\t}\n+#ifndef LWS_NO_EXTENSIONS\n+\t/*\n+\t * inform all extensions, not just active ones since they\n+\t * already know\n+\t */\n+\text \u003d wsi-\u003evhost-\u003eextensions;\n+\n+\twhile (ext \u0026\u0026 ext-\u003ecallback) {\n+\t\tv \u003d NULL;\n+\t\tfor (n \u003d 0; n \u003c wsi-\u003ecount_act_ext; n++)\n+\t\t\tif (wsi-\u003eactive_extensions[n] \u003d\u003d ext)\n+\t\t\t\tv \u003d wsi-\u003eact_ext_user[n];\n+\n+\t\text-\u003ecallback(context, ext, wsi,\n+\t\t\t LWS_EXT_CB_ANY_WSI_ESTABLISHED, v, NULL, 0);\n+\t\text++;\n+\t}\n+#endif\n+\n+\treturn 0;\n+\n+bail3:\n+\tclose_reason \u003d LWS_CLOSE_STATUS_NOSTATUS;\n+\n+bail2:\n+\tif (wsi-\u003eprotocol)\n+\t\twsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR,\n+\t\t\t\twsi-\u003euser_space, (void *)cce,\n+\t\t\t\t(unsigned int)strlen(cce));\n+\twsi-\u003ealready_did_cce \u003d 1;\n+\n+\tlwsl_info(\u0022closing connection due to bail2 connection error\u005cn\u0022);\n+\n+\t/* closing will free up his parsing allocations */\n+\tlws_close_free_wsi(wsi, close_reason);\n+\n+\treturn 1;\n+}\n+\n+\n+char *\n+lws_generate_client_handshake(struct lws *wsi, char *pkt)\n+{\n+\tchar buf[128], hash[20], key_b64[40], *p \u003d pkt;\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tconst char *meth;\n+\tint n;\n+#ifndef LWS_NO_EXTENSIONS\n+\tconst struct lws_extension *ext;\n+\tint ext_count \u003d 0;\n+#endif\n+\tconst char *pp \u003d lws_hdr_simple_ptr(wsi,\n+\t\t\t\t_WSI_TOKEN_CLIENT_SENT_PROTOCOLS);\n+\n+\tmeth \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);\n+\tif (!meth) {\n+\t\tmeth \u003d \u0022GET\u0022;\n+\t\twsi-\u003edo_ws \u003d 1;\n+\t} else {\n+\t\twsi-\u003edo_ws \u003d 0;\n+\t}\n+\n+\tif (!strcmp(meth, \u0022RAW\u0022)) {\n+\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\t\tlwsl_notice(\u0022client transition to raw\u005cn\u0022);\n+\n+\t\tif (pp) {\n+\t\t\tconst struct lws_protocols *pr;\n+\n+\t\t\tpr \u003d lws_vhost_name_to_protocol(wsi-\u003evhost, pp);\n+\n+\t\t\tif (!pr) {\n+\t\t\t\tlwsl_err(\u0022protocol %s not enabled on vhost\u005cn\u0022,\n+\t\t\t\t\t pp);\n+\t\t\t\treturn NULL;\n+\t\t\t}\n+\n+\t\t\tlws_bind_protocol(wsi, pr);\n+\t\t}\n+\n+\t\tif ((wsi-\u003eprotocol-\u003ecallback)(wsi,\n+\t\t\t\tLWS_CALLBACK_RAW_ADOPT,\n+\t\t\t\twsi-\u003euser_space, NULL, 0))\n+\t\t\treturn NULL;\n+\n+\t\tlws_header_table_force_to_detachable_state(wsi);\n+\t\tlws_union_transition(wsi, LWSCM_RAW);\n+\t\tlws_header_table_detach(wsi, 1);\n+\n+\t\treturn NULL;\n+\t}\n+\n+\tif (wsi-\u003edo_ws) {\n+\t\t/*\n+\t\t * create the random key\n+\t\t */\n+\t\tn \u003d lws_get_random(context, hash, 16);\n+\t\tif (n !\u003d 16) {\n+\t\t\tlwsl_err(\u0022Unable to read from random dev %s\u005cn\u0022,\n+\t\t\t\t SYSTEM_RANDOM_FILEPATH);\n+\t\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\t\t\treturn NULL;\n+\t\t}\n+\n+\t\tlws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));\n+\t}\n+\n+\t/*\n+\t * 04 example client handshake\n+\t *\n+\t * GET /chat HTTP/1.1\n+\t * Host: server.example.com\n+\t * Upgrade: websocket\n+\t * Connection: Upgrade\n+\t * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ\u003d\u003d\n+\t * Sec-WebSocket-Origin: http://example.com\n+\t * Sec-WebSocket-Protocol: chat, superchat\n+\t * Sec-WebSocket-Version: 4\n+\t */\n+\n+\tp +\u003d sprintf(p, \u0022%s %s HTTP/1.1\u005cx0d\u005cx0a\u0022, meth,\n+\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));\n+\n+\tp +\u003d sprintf(p, \u0022Pragma: no-cache\u005cx0d\u005cx0a\u0022\n+\t\t\t\u0022Cache-Control: no-cache\u005cx0d\u005cx0a\u0022);\n+\n+\tp +\u003d sprintf(p, \u0022Host: %s\u005cx0d\u005cx0a\u0022,\n+\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));\n+\n+\tif (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) {\n+\t\tif (lws_check_opt(context-\u003eoptions, LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN))\n+\t\t\tp +\u003d sprintf(p, \u0022Origin: %s\u005cx0d\u005cx0a\u0022,\n+\t\t\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));\n+\t\telse\n+\t\t\tp +\u003d sprintf(p, \u0022Origin: http://%s\u005cx0d\u005cx0a\u0022,\n+\t\t\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));\n+\t}\n+\n+\tif (wsi-\u003edo_ws) {\n+\t\tp +\u003d sprintf(p, \u0022Upgrade: websocket\u005cx0d\u005cx0a\u0022\n+\t\t\t\t\u0022Connection: Upgrade\u005cx0d\u005cx0a\u0022\n+\t\t\t\t\u0022Sec-WebSocket-Key: \u0022);\n+\t\tstrcpy(p, key_b64);\n+\t\tp +\u003d strlen(key_b64);\n+\t\tp +\u003d sprintf(p, \u0022\u005cx0d\u005cx0a\u0022);\n+\t\tif (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))\n+\t\t\tp +\u003d sprintf(p, \u0022Sec-WebSocket-Protocol: %s\u005cx0d\u005cx0a\u0022,\n+\t\t\t lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));\n+\n+\t\t/* tell the server what extensions we could support */\n+\n+#ifndef LWS_NO_EXTENSIONS\n+\t\text \u003d wsi-\u003evhost-\u003eextensions;\n+\t\twhile (ext \u0026\u0026 ext-\u003ecallback) {\n+\t\t\tn \u003d lws_ext_cb_all_exts(context, wsi,\n+\t\t\t\t LWS_EXT_CB_CHECK_OK_TO_PROPOSE_EXTENSION,\n+\t\t\t\t (char *)ext-\u003ename, 0);\n+\t\t\tif (n) { /* an extension vetos us */\n+\t\t\t\tlwsl_ext(\u0022ext %s vetoed\u005cn\u0022, (char *)ext-\u003ename);\n+\t\t\t\text++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tn \u003d wsi-\u003evhost-\u003eprotocols[0].callback(wsi,\n+\t\t\t\tLWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,\n+\t\t\t\t\twsi-\u003euser_space, (char *)ext-\u003ename, 0);\n+\n+\t\t\t/*\n+\t\t\t * zero return from callback means\n+\t\t\t * go ahead and allow the extension,\n+\t\t\t * it's what we get if the callback is\n+\t\t\t * unhandled\n+\t\t\t */\n+\n+\t\t\tif (n) {\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\tif (ext_count)\n+\t\t\t\t*p++ \u003d ',';\n+\t\t\telse\n+\t\t\t\tp +\u003d sprintf(p, \u0022Sec-WebSocket-Extensions: \u0022);\n+\t\t\tp +\u003d sprintf(p, \u0022%s\u0022, ext-\u003eclient_offer);\n+\t\t\text_count++;\n+\n+\t\t\text++;\n+\t\t}\n+\t\tif (ext_count)\n+\t\t\tp +\u003d sprintf(p, \u0022\u005cx0d\u005cx0a\u0022);\n+#endif\n+\n+\t\tif (wsi-\u003eietf_spec_revision)\n+\t\t\tp +\u003d sprintf(p, \u0022Sec-WebSocket-Version: %d\u005cx0d\u005cx0a\u0022,\n+\t\t\t\t wsi-\u003eietf_spec_revision);\n+\n+\t\t/* prepare the expected server accept response */\n+\n+\t\tkey_b64[39] \u003d '\u005c0'; /* enforce composed length below buf sizeof */\n+\t\tn \u003d sprintf(buf, \u0022%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11\u0022, key_b64);\n+\n+\t\tlws_SHA1((unsigned char *)buf, n, (unsigned char *)hash);\n+\n+\t\tlws_b64_encode_string(hash, 20,\n+\t\t\t\t wsi-\u003eu.hdr.ah-\u003einitial_handshake_hash_base64,\n+\t\t\t\t sizeof(wsi-\u003eu.hdr.ah-\u003einitial_handshake_hash_base64));\n+\t}\n+\n+\t/* give userland a chance to append, eg, cookies */\n+\n+\twsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,\n+\t\t\t\twsi-\u003euser_space, \u0026p, (pkt + context-\u003ept_serv_buf_size) - p - 12);\n+\n+\tp +\u003d sprintf(p, \u0022\u005cx0d\u005cx0a\u0022);\n+\n+\treturn p;\n+}\n+\ndiff --git a/lib/client/ssl-client.c b/lib/client/ssl-client.c\nnew file mode 100644\nindex 0000000..b7cde51\n--- /dev/null\n+++ b/lib/client/ssl-client.c\n@@ -0,0 +1,623 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+extern int openssl_websocket_private_data_index,\n+ openssl_SSL_CTX_private_data_index;\n+\n+extern void\n+lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);\n+\n+extern int lws_ssl_get_error(struct lws *wsi, int n);\n+\n+#if defined(USE_WOLFSSL)\n+#else\n+\n+static int\n+OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)\n+{\n+#if defined(LWS_WITH_MBEDTLS)\n+\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n+\n+\treturn 0;\n+#else\n+\tSSL *ssl;\n+\tint n;\n+\tstruct lws *wsi;\n+\n+\t/* keep old behaviour accepting self-signed server certs */\n+\tif (!preverify_ok) {\n+\t\tint err \u003d X509_STORE_CTX_get_error(x509_ctx);\n+\n+\t\tif (err !\u003d X509_V_OK) {\n+\t\t\tssl \u003d X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());\n+\t\t\twsi \u003d SSL_get_ex_data(ssl, openssl_websocket_private_data_index);\n+\n+\t\t\tif ((err \u003d\u003d X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||\n+\t\t\t\t\terr \u003d\u003d X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \u0026\u0026\n+\t\t\t\t\twsi-\u003euse_ssl \u0026 LCCSCF_ALLOW_SELFSIGNED) {\n+\t\t\t\tlwsl_notice(\u0022accepting self-signed certificate (verify_callback)\u005cn\u0022);\n+\t\t\t\tX509_STORE_CTX_set_error(x509_ctx, X509_V_OK);\n+\t\t\t\treturn 1;\t// ok\n+\t\t\t} else if ((err \u003d\u003d X509_V_ERR_CERT_NOT_YET_VALID ||\n+\t\t\t\t\terr \u003d\u003d X509_V_ERR_CERT_HAS_EXPIRED) \u0026\u0026\n+\t\t\t\t\twsi-\u003euse_ssl \u0026 LCCSCF_ALLOW_EXPIRED) {\n+\t\t\t\tif (err \u003d\u003d X509_V_ERR_CERT_NOT_YET_VALID)\n+\t\t\t\t\tlwsl_notice(\u0022accepting not yet valid certificate (verify_callback)\u005cn\u0022);\n+\t\t\t\telse if (err \u003d\u003d X509_V_ERR_CERT_HAS_EXPIRED)\n+\t\t\t\t\tlwsl_notice(\u0022accepting expired certificate (verify_callback)\u005cn\u0022);\n+\t\t\t\tX509_STORE_CTX_set_error(x509_ctx, X509_V_OK);\n+\t\t\t\treturn 1;\t// ok\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tssl \u003d X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());\n+\twsi \u003d SSL_get_ex_data(ssl, openssl_websocket_private_data_index);\n+\n+\tn \u003d lws_get_context_protocol(wsi-\u003econtext, 0).callback(wsi,\n+\t\t\tLWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION,\n+\t\t\tx509_ctx, ssl, preverify_ok);\n+\n+\t/* keep old behaviour if something wrong with server certs */\n+\t/* if ssl error is overruled in callback and cert is ok,\n+\t * X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); must be set and\n+\t * return value is 0 from callback */\n+\tif (!preverify_ok) {\n+\t\tint err \u003d X509_STORE_CTX_get_error(x509_ctx);\n+\n+\t\tif (err !\u003d X509_V_OK) {\t/* cert validation error was not handled in callback */\n+\t\t\tint depth \u003d X509_STORE_CTX_get_error_depth(x509_ctx);\n+\t\t\tconst char* msg \u003d X509_verify_cert_error_string(err);\n+\t\t\tlwsl_err(\u0022SSL error: %s (preverify_ok\u003d%d;err\u003d%d;depth\u003d%d)\u005cn\u0022, msg, preverify_ok, err, depth);\n+\t\t\treturn preverify_ok;\t// not ok\n+\t\t}\n+\t}\n+\t/* convert callback return code from 0 \u003d OK to verify callback return value 1 \u003d OK */\n+\treturn !n;\n+#endif\n+}\n+#endif\n+\n+int\n+lws_ssl_client_bio_create(struct lws *wsi)\n+{\n+\tchar hostname[128], *p;\n+\n+\tif (lws_hdr_copy(wsi, hostname, sizeof(hostname),\n+\t\t\t _WSI_TOKEN_CLIENT_HOST) \u003c\u003d 0) {\n+\t\tlwsl_err(\u0022%s: Unable to get hostname\u005cn\u0022, __func__);\n+\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * remove any :port part on the hostname... necessary for network\n+\t * connection but typical certificates do not contain it\n+\t */\n+\tp \u003d hostname;\n+\twhile (*p) {\n+\t\tif (*p \u003d\u003d ':') {\n+\t\t\t*p \u003d '\u005c0';\n+\t\t\tbreak;\n+\t\t}\n+\t\tp++;\n+\t}\n+\n+\twsi-\u003essl \u003d SSL_new(wsi-\u003evhost-\u003essl_client_ctx);\n+\tif (!wsi-\u003essl) {\n+\t\tlwsl_err(\u0022SSL_new failed: %s\u005cn\u0022,\n+\t\t ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));\n+\t\tlws_ssl_elaborate_error();\n+\t\treturn -1;\n+\t}\n+\n+#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)\n+\tif (wsi-\u003evhost-\u003essl_info_event_mask)\n+\t\tSSL_set_info_callback(wsi-\u003essl, lws_ssl_info_callback);\n+#endif\n+\n+#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host\n+\tX509_VERIFY_PARAM *param;\n+\t(void)param;\n+\n+\tif (!(wsi-\u003euse_ssl \u0026 LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {\n+\t\tparam \u003d SSL_get0_param(wsi-\u003essl);\n+\t\t/* Enable automatic hostname checks */\n+\t\tX509_VERIFY_PARAM_set_hostflags(param,\n+\t\t\t\t\t\tX509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);\n+\t\tX509_VERIFY_PARAM_set1_host(param, hostname, 0);\n+\t}\n+\n+#endif\n+\n+#if !defined(USE_WOLFSSL) \u0026\u0026 !defined(LWS_WITH_MBEDTLS)\n+#ifndef USE_OLD_CYASSL\n+\t/* OpenSSL_client_verify_callback will be called @ SSL_connect() */\n+\tSSL_set_verify(wsi-\u003essl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback);\n+#endif\n+#endif\n+\n+#if !defined(USE_WOLFSSL) \u0026\u0026 !defined(LWS_WITH_MBEDTLS)\n+\tSSL_set_mode(wsi-\u003essl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);\n+#endif\n+\t/*\n+\t * use server name indication (SNI), if supported,\n+\t * when establishing connection\n+\t */\n+#ifdef USE_WOLFSSL\n+#ifdef USE_OLD_CYASSL\n+#ifdef CYASSL_SNI_HOST_NAME\n+\tCyaSSL_UseSNI(wsi-\u003essl, CYASSL_SNI_HOST_NAME, hostname, strlen(hostname));\n+#endif\n+#else\n+#ifdef WOLFSSL_SNI_HOST_NAME\n+\twolfSSL_UseSNI(wsi-\u003essl, WOLFSSL_SNI_HOST_NAME, hostname, strlen(hostname));\n+#endif\n+#endif\n+#else\n+#if defined(LWS_WITH_MBEDTLS)\n+\tif (wsi-\u003evhost-\u003ex509_client_CA)\n+\t\tSSL_set_verify(wsi-\u003essl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback);\n+\telse\n+\t\tSSL_set_verify(wsi-\u003essl, SSL_VERIFY_NONE, OpenSSL_client_verify_callback);\n+\n+#else\n+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME\n+\tSSL_set_tlsext_host_name(wsi-\u003essl, hostname);\n+#endif\n+#endif\n+#endif\n+\n+#ifdef USE_WOLFSSL\n+\t/*\n+\t * wolfSSL/CyaSSL does certificate verification differently\n+\t * from OpenSSL.\n+\t * If we should ignore the certificate, we need to set\n+\t * this before SSL_new and SSL_connect is called.\n+\t * Otherwise the connect will simply fail with error code -155\n+\t */\n+#ifdef USE_OLD_CYASSL\n+\tif (wsi-\u003euse_ssl \u003d\u003d 2)\n+\t\tCyaSSL_set_verify(wsi-\u003essl, SSL_VERIFY_NONE, NULL);\n+#else\n+\tif (wsi-\u003euse_ssl \u003d\u003d 2)\n+\t\twolfSSL_set_verify(wsi-\u003essl, SSL_VERIFY_NONE, NULL);\n+#endif\n+#endif /* USE_WOLFSSL */\n+\n+#if !defined(LWS_WITH_MBEDTLS)\n+\twsi-\u003eclient_bio \u003d BIO_new_socket(wsi-\u003edesc.sockfd, BIO_NOCLOSE);\n+\tSSL_set_bio(wsi-\u003essl, wsi-\u003eclient_bio, wsi-\u003eclient_bio);\n+#else\n+\tSSL_set_fd(wsi-\u003essl, wsi-\u003edesc.sockfd);\n+#endif\n+\n+#ifdef USE_WOLFSSL\n+#ifdef USE_OLD_CYASSL\n+\tCyaSSL_set_using_nonblock(wsi-\u003essl, 1);\n+#else\n+\twolfSSL_set_using_nonblock(wsi-\u003essl, 1);\n+#endif\n+#else\n+#if !defined(LWS_WITH_MBEDTLS)\n+\tBIO_set_nbio(wsi-\u003eclient_bio, 1); /* nonblocking */\n+#endif\n+#endif\n+\n+#if !defined(LWS_WITH_MBEDTLS)\n+\tSSL_set_ex_data(wsi-\u003essl, openssl_websocket_private_data_index,\n+\t\t\twsi);\n+#endif\n+\n+\treturn 0;\n+}\n+\n+#if defined(LWS_WITH_MBEDTLS)\n+int ERR_get_error(void)\n+{\n+\treturn 0;\n+}\n+#endif\n+\n+int\n+lws_ssl_client_connect1(struct lws *wsi)\n+{\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tint n \u003d 0;\n+\n+\tlws_latency_pre(context, wsi);\n+\n+\tn \u003d SSL_connect(wsi-\u003essl);\n+\n+\tlws_latency(context, wsi,\n+\t \u0022SSL_connect LWSCM_WSCL_ISSUE_HANDSHAKE\u0022, n, n \u003e 0);\n+\n+\tif (n \u003c 0) {\n+\t\tn \u003d lws_ssl_get_error(wsi, n);\n+\n+\t\tif (n \u003d\u003d SSL_ERROR_WANT_READ)\n+\t\t\tgoto some_wait;\n+\n+\t\tif (n \u003d\u003d SSL_ERROR_WANT_WRITE) {\n+\t\t\t/*\n+\t\t\t * wants us to retry connect due to\n+\t\t\t * state of the underlying ssl layer...\n+\t\t\t * but since it may be stalled on\n+\t\t\t * blocked write, no incoming data may\n+\t\t\t * arrive to trigger the retry.\n+\t\t\t * Force (possibly many times if the SSL\n+\t\t\t * state persists in returning the\n+\t\t\t * condition code, but other sockets\n+\t\t\t * are getting serviced inbetweentimes)\n+\t\t\t * us to get called back when writable.\n+\t\t\t */\n+\t\t\tlwsl_info(\u0022%s: WANT_WRITE... retrying\u005cn\u0022, __func__);\n+\t\t\tlws_callback_on_writable(wsi);\n+some_wait:\n+\t\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SSL;\n+\n+\t\t\treturn 0; /* no error */\n+\t\t}\n+\n+\t\t{\n+\t\t\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\t\t\tchar *p \u003d (char *)\u0026pt-\u003eserv_buf[0];\n+\t\t\tchar *sb \u003d p;\n+\n+\t\t\tlwsl_err(\u0022ssl hs1 error, X509_V_ERR \u003d %d: %s\u005cn\u0022,\n+\t\t\t\t n, ERR_error_string(n, sb));\n+\t\t\tlws_ssl_elaborate_error();\n+\t\t}\n+\n+\t\tn \u003d -1;\n+\t}\n+\n+\tif (n \u003c\u003d 0) {\n+\t\t/*\n+\t\t * retry if new data comes until we\n+\t\t * run into the connection timeout or win\n+\t\t */\n+\n+\t\tunsigned long error \u003d ERR_get_error();\n+\n+\t\tif (error !\u003d SSL_ERROR_NONE) {\n+\t\t\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\t\t\tchar *p \u003d (char *)\u0026pt-\u003eserv_buf[0];\n+\t\t\tchar *sb \u003d p;\n+\t\t\tlwsl_err(\u0022SSL connect error %lu: %s\u005cn\u0022,\n+\t\t\t\terror, ERR_error_string(error, sb));\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\treturn 1;\n+}\n+\n+int\n+lws_ssl_client_connect2(struct lws *wsi)\n+{\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tchar *p \u003d (char *)\u0026pt-\u003eserv_buf[0];\n+\tchar *sb \u003d p;\n+\tint n \u003d 0;\n+\n+\tif (wsi-\u003emode \u003d\u003d LWSCM_WSCL_WAITING_SSL) {\n+\t\tlws_latency_pre(context, wsi);\n+\t\tn \u003d SSL_connect(wsi-\u003essl);\n+\t\tlwsl_debug(\u0022%s: SSL_connect says %d\u005cn\u0022, __func__, n);\n+\n+\t\tlws_latency(context, wsi,\n+\t\t\t \u0022SSL_connect LWSCM_WSCL_WAITING_SSL\u0022, n, n \u003e 0);\n+\n+\t\tif (n \u003c 0) {\n+\t\t\tn \u003d lws_ssl_get_error(wsi, n);\n+\n+\t\t\tif (n \u003d\u003d SSL_ERROR_WANT_READ) {\n+\t\t\t\tlwsl_info(\u0022SSL_connect WANT_READ... retrying\u005cn\u0022);\n+\n+\t\t\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SSL;\n+\n+\t\t\t\treturn 0; /* no error */\n+\t\t\t}\n+\n+\t\t\tif (n \u003d\u003d SSL_ERROR_WANT_WRITE) {\n+\t\t\t\t/*\n+\t\t\t\t * wants us to retry connect due to\n+\t\t\t\t * state of the underlying ssl layer...\n+\t\t\t\t * but since it may be stalled on\n+\t\t\t\t * blocked write, no incoming data may\n+\t\t\t\t * arrive to trigger the retry.\n+\t\t\t\t * Force (possibly many times if the SSL\n+\t\t\t\t * state persists in returning the\n+\t\t\t\t * condition code, but other sockets\n+\t\t\t\t * are getting serviced inbetweentimes)\n+\t\t\t\t * us to get called back when writable.\n+\t\t\t\t */\n+\t\t\t\tlwsl_info(\u0022SSL_connect WANT_WRITE... retrying\u005cn\u0022);\n+\t\t\t\tlws_callback_on_writable(wsi);\n+\n+\t\t\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SSL;\n+\n+\t\t\t\treturn 0; /* no error */\n+\t\t\t}\n+\n+\t\t\tn \u003d -1;\n+\t\t}\n+\n+\t\tif (n \u003c\u003d 0) {\n+\t\t\t/*\n+\t\t\t * retry if new data comes until we\n+\t\t\t * run into the connection timeout or win\n+\t\t\t */\n+\t\t\tunsigned long error \u003d ERR_get_error();\n+\t\t\tif (error !\u003d SSL_ERROR_NONE) {\n+\t\t\t\tlwsl_err(\u0022SSL connect error %lu: %s\u005cn\u0022,\n+\t\t\t\t\t error, ERR_error_string(error, sb));\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+#if defined(LWS_WITH_MBEDTLS)\n+\t{\n+\t\tX509 *peer \u003d SSL_get_peer_certificate(wsi-\u003essl);\n+\n+\t\tif (!peer) {\n+\t\t\tlwsl_notice(\u0022peer did not provide cert\u005cn\u0022);\n+\n+\t\t\treturn -1;\n+\t\t}\n+\t\tlwsl_notice(\u0022peer provided cert\u005cn\u0022);\n+\t}\n+#endif\n+\n+#ifndef USE_WOLFSSL\n+\t/*\n+\t * See comment above about wolfSSL certificate\n+\t * verification\n+\t */\n+\tlws_latency_pre(context, wsi);\n+\tn \u003d SSL_get_verify_result(wsi-\u003essl);\n+\tlws_latency(context, wsi,\n+\t\t\u0022SSL_get_verify_result LWS_CONNMODE..HANDSHAKE\u0022, n, n \u003e 0);\n+\n+\tlwsl_debug(\u0022get_verify says %d\u005cn\u0022, n);\n+\n+\tif (n !\u003d X509_V_OK) {\n+\t\tif ((n \u003d\u003d X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||\n+\t\t n \u003d\u003d X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \u0026\u0026\n+\t\t (wsi-\u003euse_ssl \u0026 LCCSCF_ALLOW_SELFSIGNED)) {\n+\t\t\tlwsl_notice(\u0022accepting self-signed certificate\u005cn\u0022);\n+\t\t} else if ((n \u003d\u003d X509_V_ERR_CERT_NOT_YET_VALID ||\n+\t\t n \u003d\u003d X509_V_ERR_CERT_HAS_EXPIRED) \u0026\u0026\n+\t\t (wsi-\u003euse_ssl \u0026 LCCSCF_ALLOW_EXPIRED)) {\n+\t\t\tlwsl_notice(\u0022accepting expired certificate\u005cn\u0022);\n+\t\t} else if (n \u003d\u003d X509_V_ERR_CERT_NOT_YET_VALID) {\n+\t\t\tlwsl_notice(\u0022Cert is from the future... \u0022\n+\t\t\t\t \u0022probably our clock... accepting...\u005cn\u0022);\n+\t\t} else {\n+\t\t\tlwsl_err(\u0022server's cert didn't look good, X509_V_ERR \u003d %d: %s\u005cn\u0022,\n+\t\t\t\t n, ERR_error_string(n, sb));\n+\t\t\tlws_ssl_elaborate_error();\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+#endif /* USE_WOLFSSL */\n+\n+\treturn 1;\n+}\n+\n+\n+int lws_context_init_client_ssl(struct lws_context_creation_info *info,\n+\t\t\t\tstruct lws_vhost *vhost)\n+{\n+\tSSL_METHOD *method \u003d NULL;\n+\tstruct lws wsi;\n+\tunsigned long error;\n+\tconst char *ca_filepath \u003d info-\u003essl_ca_filepath;\n+#if !defined(LWS_WITH_MBEDTLS)\n+\tconst char *cipher_list \u003d info-\u003essl_cipher_list;\n+\tconst char *private_key_filepath \u003d info-\u003essl_private_key_filepath;\n+\tconst char *cert_filepath \u003d info-\u003essl_cert_filepath;\n+\tint n;\n+\n+\tif (vhost-\u003eoptions \u0026 LWS_SERVER_OPTION_ONLY_RAW)\n+\t\treturn 0;\n+\n+\t/*\n+\t * for backwards-compatibility default to using ssl_... members, but\n+\t * if the newer client-specific ones are given, use those\n+\t */\n+\tif (info-\u003eclient_ssl_cipher_list)\n+\t\tcipher_list \u003d info-\u003eclient_ssl_cipher_list;\n+\tif (info-\u003eclient_ssl_cert_filepath)\n+\t\tcert_filepath \u003d info-\u003eclient_ssl_cert_filepath;\n+\tif (info-\u003eclient_ssl_private_key_filepath)\n+\t\tprivate_key_filepath \u003d info-\u003eclient_ssl_private_key_filepath;\n+#endif\n+\tif (info-\u003eclient_ssl_ca_filepath)\n+\t\tca_filepath \u003d info-\u003eclient_ssl_ca_filepath;\n+\n+\tif (!lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))\n+\t\treturn 0;\n+\n+\tif (vhost-\u003essl_client_ctx)\n+\t\treturn 0;\n+\n+\tif (info-\u003eprovided_client_ssl_ctx) {\n+\t\t/* use the provided OpenSSL context if given one */\n+\t\tvhost-\u003essl_client_ctx \u003d info-\u003eprovided_client_ssl_ctx;\n+\t\t/* nothing for lib to delete */\n+\t\tvhost-\u003euser_supplied_ssl_ctx \u003d 1;\n+\n+\t\treturn 0;\n+\t}\n+\n+\t/* basic openssl init already happened in context init */\n+\n+\t/* choose the most recent spin of the api */\n+#if defined(LWS_HAVE_TLS_CLIENT_METHOD)\n+\tmethod \u003d (SSL_METHOD *)TLS_client_method();\n+#elif defined(LWS_HAVE_TLSV1_2_CLIENT_METHOD)\n+\tmethod \u003d (SSL_METHOD *)TLSv1_2_client_method();\n+#else\n+\tmethod \u003d (SSL_METHOD *)SSLv23_client_method();\n+#endif\n+\tif (!method) {\n+\t\terror \u003d ERR_get_error();\n+\t\tlwsl_err(\u0022problem creating ssl method %lu: %s\u005cn\u0022,\n+\t\t\terror, ERR_error_string(error,\n+\t\t\t\t (char *)vhost-\u003econtext-\u003ept[0].serv_buf));\n+\t\treturn 1;\n+\t}\n+\t/* create context */\n+\tvhost-\u003essl_client_ctx \u003d SSL_CTX_new(method);\n+\tif (!vhost-\u003essl_client_ctx) {\n+\t\terror \u003d ERR_get_error();\n+\t\tlwsl_err(\u0022problem creating ssl context %lu: %s\u005cn\u0022,\n+\t\t\terror, ERR_error_string(error,\n+\t\t\t\t (char *)vhost-\u003econtext-\u003ept[0].serv_buf));\n+\t\treturn 1;\n+\t}\n+\n+\tlwsl_notice(\u0022created client ssl context for %s\u005cn\u0022, vhost-\u003ename);\n+\n+#ifdef SSL_OP_NO_COMPRESSION\n+\tSSL_CTX_set_options(vhost-\u003essl_client_ctx, SSL_OP_NO_COMPRESSION);\n+#endif\n+\n+#if defined(LWS_WITH_MBEDTLS)\n+\tif (ca_filepath) {\n+\t\tlws_filepos_t len;\n+\t\tuint8_t *buf;\n+\t\t/*\n+\t\t * prototype this here, the shim does not export it in the\n+\t\t * header, and we need to use the shim unchanged for ESP32 case\n+\t\t */\n+\t\tX509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len);\n+\n+\t\tif (alloc_file(vhost-\u003econtext, ca_filepath, \u0026buf, \u0026len)) {\n+\t\t\tlwsl_err(\u0022Load CA cert file %s failed\u005cn\u0022, ca_filepath);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tvhost-\u003ex509_client_CA \u003d d2i_X509(NULL, buf, len);\n+\t\tfree(buf);\n+\t\tif (!vhost-\u003ex509_client_CA) {\n+\t\t\tlwsl_err(\u0022client CA: x509 parse failed\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tSSL_CTX_add_client_CA(vhost-\u003essl_client_ctx,\n+\t\t\t\t vhost-\u003ex509_client_CA);\n+\n+\t\tlwsl_notice(\u0022client loaded CA for verification %s\u005cn\u0022, ca_filepath);\n+\t}\n+#else\n+\tSSL_CTX_set_options(vhost-\u003essl_client_ctx,\n+\t\t\t SSL_OP_CIPHER_SERVER_PREFERENCE);\n+\n+\tif (cipher_list)\n+\t\tSSL_CTX_set_cipher_list(vhost-\u003essl_client_ctx, cipher_list);\n+\n+#ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS\n+\tif (!lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))\n+\t\t/* loads OS default CA certs */\n+\t\tSSL_CTX_set_default_verify_paths(vhost-\u003essl_client_ctx);\n+#endif\n+\n+\t/* openssl init for cert verification (for client sockets) */\n+\tif (!ca_filepath) {\n+\t\tif (!SSL_CTX_load_verify_locations(\n+\t\t\tvhost-\u003essl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS))\n+\t\t\tlwsl_err(\u0022Unable to load SSL Client certs from %s \u0022\n+\t\t\t \u0022(set by LWS_OPENSSL_CLIENT_CERTS) -- \u0022\n+\t\t\t \u0022client ssl isn't going to work\u005cn\u0022,\n+\t\t\t LWS_OPENSSL_CLIENT_CERTS);\n+\t} else\n+\t\tif (!SSL_CTX_load_verify_locations(\n+\t\t\tvhost-\u003essl_client_ctx, ca_filepath, NULL)) {\n+\t\t\tlwsl_err(\n+\t\t\t\t\u0022Unable to load SSL Client certs \u0022\n+\t\t\t\t\u0022file from %s -- client ssl isn't \u0022\n+\t\t\t\t\u0022going to work\u005cn\u0022, info-\u003eclient_ssl_ca_filepath);\n+\t\t\tlws_ssl_elaborate_error();\n+\t\t}\n+\t\telse\n+\t\t\tlwsl_info(\u0022loaded ssl_ca_filepath\u005cn\u0022);\n+\n+\t/*\n+\t * callback allowing user code to load extra verification certs\n+\t * helping the client to verify server identity\n+\t */\n+\n+\t/* support for client-side certificate authentication */\n+\tif (cert_filepath) {\n+\t\tlwsl_notice(\u0022%s: doing cert filepath\u005cn\u0022, __func__);\n+\t\tn \u003d SSL_CTX_use_certificate_chain_file(vhost-\u003essl_client_ctx,\n+\t\t\t\t\t\t cert_filepath);\n+\t\tif (n \u003c 1) {\n+\t\t\tlwsl_err(\u0022problem %d getting cert '%s'\u005cn\u0022, n,\n+\t\t\t\t cert_filepath);\n+\t\t\tlws_ssl_elaborate_error();\n+\t\t\treturn 1;\n+\t\t}\n+\t\tlwsl_notice(\u0022Loaded client cert %s\u005cn\u0022, cert_filepath);\n+\t}\n+\tif (private_key_filepath) {\n+\t\tlwsl_notice(\u0022%s: doing private key filepath\u005cn\u0022, __func__);\n+\t\tlws_ssl_bind_passphrase(vhost-\u003essl_client_ctx, info);\n+\t\t/* set the private key from KeyFile */\n+\t\tif (SSL_CTX_use_PrivateKey_file(vhost-\u003essl_client_ctx,\n+\t\t private_key_filepath, SSL_FILETYPE_PEM) !\u003d 1) {\n+\t\t\tlwsl_err(\u0022use_PrivateKey_file '%s'\u005cn\u0022,\n+\t\t\t\t private_key_filepath);\n+\t\t\tlws_ssl_elaborate_error();\n+\t\t\treturn 1;\n+\t\t}\n+\t\tlwsl_notice(\u0022Loaded client cert private key %s\u005cn\u0022,\n+\t\t\t private_key_filepath);\n+\n+\t\t/* verify private key */\n+\t\tif (!SSL_CTX_check_private_key(vhost-\u003essl_client_ctx)) {\n+\t\t\tlwsl_err(\u0022Private SSL key doesn't match cert\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+#endif\n+\t/*\n+\t * give him a fake wsi with context set, so he can use\n+\t * lws_get_context() in the callback\n+\t */\n+\tmemset(\u0026wsi, 0, sizeof(wsi));\n+\twsi.vhost \u003d vhost;\n+\twsi.context \u003d vhost-\u003econtext;\n+\n+\tvhost-\u003eprotocols[0].callback(\u0026wsi,\n+\t\t\tLWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,\n+\t\t\t\t vhost-\u003essl_client_ctx, NULL, 0);\n+\n+\treturn 0;\n+}\ndiff --git a/lib/context.c b/lib/context.c\nindex ae96ddf..d134459 100644\n--- a/lib/context.c\n+++ b/lib/context.c\n@@ -84,7 +84,7 @@ const struct http2_settings lws_h2_defaults \u003d { {\n \n const struct http2_settings lws_h2_stock_settings \u003d { {\n \t1,\n-\t/* H2SET_HEADER_TABLE_SIZE */\t\t\t 512,\n+\t/* H2SET_HEADER_TABLE_SIZE */\t\t\t4096,\n \t/* *** This controls how many entries in the dynamic table ***\n \t * Allows the sender to inform the remote endpoint of the maximum\n \t * size of the header compression table used to decode header\n@@ -92,6 +92,8 @@ const struct http2_settings lws_h2_stock_settings \u003d { {\n \t * less than this value by using signaling specific to the header\n \t * compression format inside a header block (see [COMPRESSION]).\n \t * The initial value is 4,096 octets.\n+\t *\n+\t * Can't pass h2spec with less than 4096 here...\n \t */\n \t/* H2SET_ENABLE_PUSH */\t\t\t\t 1,\n \t/* H2SET_MAX_CONCURRENT_STREAMS */\t\t 24,\ndiff --git a/lib/daemonize.c b/lib/daemonize.c\ndeleted file mode 100644\nindex 8ec58a3..0000000\n--- a/lib/daemonize.c\n+++ /dev/null\n@@ -1,225 +0,0 @@\n-/*\n- * This code is mainly taken from Doug Potter's page\n- *\n- * http://www-theorie.physik.unizh.ch/~dpotter/howto/daemonize\n- *\n- * I contacted him 2007-04-16 about the license for the original code,\n- * he replied it is Public Domain. Use the URL above to get the original\n- * Public Domain version if you want it.\n- *\n- * This version is LGPL2.1+SLE like the rest of libwebsockets and is\n- * Copyright (c)2006 - 2013 Andy Green \u003candy@warmcat.com\u003e\n- */\n-\n-#include \u003cstdlib.h\u003e\n-#include \u003cstring.h\u003e\n-#include \u003cstdio.h\u003e\n-#include \u003csignal.h\u003e\n-#include \u003csys/types.h\u003e\n-#include \u003csys/stat.h\u003e\n-#include \u003cfcntl.h\u003e\n-#include \u003climits.h\u003e\n-#include \u003cunistd.h\u003e\n-#include \u003cerrno.h\u003e\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-int pid_daemon;\n-static char *lock_path;\n-\n-int get_daemonize_pid()\n-{\n-\treturn pid_daemon;\n-}\n-\n-static void\n-child_handler(int signum)\n-{\n-\tint fd, len, sent;\n-\tchar sz[20];\n-\n-\tswitch (signum) {\n-\n-\tcase SIGALRM: /* timed out daemonizing */\n-\t\texit(0);\n-\t\tbreak;\n-\n-\tcase SIGUSR1: /* positive confirmation we daemonized well */\n-\n-\t\tif (lock_path) {\n-\t\t\t/* Create the lock file as the current user */\n-\n-\t\t\tfd \u003d open(lock_path, O_TRUNC | O_RDWR | O_CREAT, 0640);\n-\t\t\tif (fd \u003c 0) {\n-\t\t\t\tfprintf(stderr,\n-\t\t\t\t \u0022unable to create lock file %s, code\u003d%d (%s)\u005cn\u0022,\n-\t\t\t\t\tlock_path, errno, strerror(errno));\n-\t\t\t\texit(0);\n-\t\t\t}\n-\t\t\tlen \u003d sprintf(sz, \u0022%u\u0022, pid_daemon);\n-\t\t\tsent \u003d write(fd, sz, len);\n-\t\t\tif (sent !\u003d len)\n-\t\t\t\tfprintf(stderr,\n-\t\t\t\t \u0022unable to write pid to lock file %s, code\u003d%d (%s)\u005cn\u0022,\n-\t\t\t\t\t\t lock_path, errno, strerror(errno));\n-\n-\t\t\tclose(fd);\n-\t\t}\n-\t\texit(0);\n-\t\t//!!(sent \u003d\u003d len));\n-\n-\tcase SIGCHLD: /* daemonization failed */\n-\t\texit(0);\n-\t\tbreak;\n-\t}\n-}\n-\n-static void lws_daemon_closing(int sigact)\n-{\n-\tif (getpid() \u003d\u003d pid_daemon)\n-\t\tif (lock_path) {\n-\t\t\tunlink(lock_path);\n-\t\t\tlws_free_set_NULL(lock_path);\n-\t\t}\n-\n-\tkill(getpid(), SIGKILL);\n-}\n-\n-/*\n- * You just need to call this from your main(), when it\n- * returns you are all set \u0022in the background\u0022 decoupled\n- * from the console you were started from.\n- *\n- * The process context you called from has been terminated then.\n- */\n-\n-LWS_VISIBLE int\n-lws_daemonize(const char *_lock_path)\n-{\n-\tstruct sigaction act;\n-\tpid_t sid, parent;\n-\tint n, fd, ret;\n-\tchar buf[10];\n-\n-\t/* already a daemon */\n-//\tif (getppid() \u003d\u003d 1)\n-//\t\treturn 1;\n-\n-\tif (_lock_path) {\n-\t\tfd \u003d open(_lock_path, O_RDONLY);\n-\t\tif (fd \u003e\u003d 0) {\n-\t\t\tn \u003d read(fd, buf, sizeof(buf));\n-\t\t\tclose(fd);\n-\t\t\tif (n) {\n-\t\t\t\tn \u003d atoi(buf);\n-\t\t\t\tret \u003d kill(n, 0);\n-\t\t\t\tif (ret \u003e\u003d 0) {\n-\t\t\t\t\tfprintf(stderr,\n-\t\t\t\t\t \u0022Daemon already running from pid %d\u005cn\u0022, n);\n-\t\t\t\t\texit(1);\n-\t\t\t\t}\n-\t\t\t\tfprintf(stderr,\n-\t\t\t\t \u0022Removing stale lock file %s from dead pid %d\u005cn\u0022,\n-\t\t\t\t\t\t\t\t\t _lock_path, n);\n-\t\t\t\tunlink(lock_path);\n-\t\t\t}\n-\t\t}\n-\n-\t\tn \u003d strlen(_lock_path) + 1;\n-\t\tlock_path \u003d lws_malloc(n);\n-\t\tif (!lock_path) {\n-\t\t\tfprintf(stderr, \u0022Out of mem in lws_daemonize\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\t\tstrcpy(lock_path, _lock_path);\n-\t}\n-\n-\t/* Trap signals that we expect to receive */\n-\tsignal(SIGCHLD, child_handler);\t/* died */\n-\tsignal(SIGUSR1, child_handler); /* was happy */\n-\tsignal(SIGALRM, child_handler); /* timeout daemonizing */\n-\n-\t/* Fork off the parent process */\n-\tpid_daemon \u003d fork();\n-\tif (pid_daemon \u003c 0) {\n-\t\tfprintf(stderr, \u0022unable to fork daemon, code\u003d%d (%s)\u0022,\n-\t\t errno, strerror(errno));\n-\t\texit(9);\n-\t}\n-\n- /* If we got a good PID, then we can exit the parent process. */\n-\tif (pid_daemon \u003e 0) {\n-\n- /*\n- * Wait for confirmation signal from the child via\n- * SIGCHILD / USR1, or for two seconds to elapse\n- * (SIGALRM). pause() should not return.\n- */\n- alarm(2);\n-\n- pause();\n- /* should not be reachable */\n- exit(1);\n- }\n-\n-\t/* At this point we are executing as the child process */\n-\tparent \u003d getppid();\n-\tpid_daemon \u003d getpid();\n-\n-\t/* Cancel certain signals */\n-\tsignal(SIGCHLD, SIG_DFL); /* A child process dies */\n-\tsignal(SIGTSTP, SIG_IGN); /* Various TTY signals */\n-\tsignal(SIGTTOU, SIG_IGN);\n-\tsignal(SIGTTIN, SIG_IGN);\n-\tsignal(SIGHUP, SIG_IGN); /* Ignore hangup signal */\n-\n-\t/* Change the file mode mask */\n-\tumask(0);\n-\n-\t/* Create a new SID for the child process */\n-\tsid \u003d setsid();\n-\tif (sid \u003c 0) {\n-\t\tfprintf(stderr,\n-\t\t\t\u0022unable to create a new session, code %d (%s)\u0022,\n-\t\t\terrno, strerror(errno));\n-\t\texit(2);\n-\t}\n-\n-\t/*\n-\t * Change the current working directory. This prevents the current\n-\t * directory from being locked; hence not being able to remove it.\n-\t */\n-\tif (chdir(\u0022/tmp\u0022) \u003c 0) {\n-\t\tfprintf(stderr,\n-\t\t\t\u0022unable to change directory to %s, code %d (%s)\u0022,\n-\t\t\t\u0022/\u0022, errno, strerror(errno));\n-\t\texit(3);\n-\t}\n-\n-\t/* Redirect standard files to /dev/null */\n-\tif (!freopen(\u0022/dev/null\u0022, \u0022r\u0022, stdin))\n-\t\tfprintf(stderr, \u0022unable to freopen() stdin, code %d (%s)\u0022,\n-\t\t\t\t\t\t errno, strerror(errno));\n-\n-\tif (!freopen(\u0022/dev/null\u0022, \u0022w\u0022, stdout))\n-\t\tfprintf(stderr, \u0022unable to freopen() stdout, code %d (%s)\u0022,\n-\t\t\t\t\t\t errno, strerror(errno));\n-\n-\tif (!freopen(\u0022/dev/null\u0022, \u0022w\u0022, stderr))\n-\t\tfprintf(stderr, \u0022unable to freopen() stderr, code %d (%s)\u0022,\n-\t\t\t\t\t\t errno, strerror(errno));\n-\n-\t/* Tell the parent process that we are A-okay */\n-\tkill(parent, SIGUSR1);\n-\n-\tact.sa_handler \u003d lws_daemon_closing;\n-\tsigemptyset(\u0026act.sa_mask);\n-\tact.sa_flags \u003d 0;\n-\n-\tsigaction(SIGTERM, \u0026act, NULL);\n-\n-\t/* return to continue what is now \u0022the daemon\u0022 */\n-\n-\treturn 0;\n-}\n-\ndiff --git a/lib/event-libs/libev.c b/lib/event-libs/libev.c\nnew file mode 100644\nindex 0000000..2410488\n--- /dev/null\n+++ b/lib/event-libs/libev.c\n@@ -0,0 +1,236 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+void lws_feature_status_libev(struct lws_context_creation_info *info)\n+{\n+\tif (lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_LIBEV))\n+\t\tlwsl_info(\u0022libev support compiled in and enabled\u005cn\u0022);\n+\telse\n+\t\tlwsl_info(\u0022libev support compiled in but disabled\u005cn\u0022);\n+}\n+\n+static void\n+lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)\n+{\n+\tstruct lws_io_watcher *lws_io \u003d lws_container_of(watcher,\n+\t\t\t\t\tstruct lws_io_watcher, ev_watcher);\n+\tstruct lws_context *context \u003d lws_io-\u003econtext;\n+\tstruct lws_pollfd eventfd;\n+\n+\tif (revents \u0026 EV_ERROR)\n+\t\treturn;\n+\n+\teventfd.fd \u003d watcher-\u003efd;\n+\teventfd.events \u003d 0;\n+\teventfd.revents \u003d EV_NONE;\n+\n+\tif (revents \u0026 EV_READ) {\n+\t\teventfd.events |\u003d LWS_POLLIN;\n+\t\teventfd.revents |\u003d LWS_POLLIN;\n+\t}\n+\tif (revents \u0026 EV_WRITE) {\n+\t\teventfd.events |\u003d LWS_POLLOUT;\n+\t\teventfd.revents |\u003d LWS_POLLOUT;\n+\t}\n+\n+\tlws_service_fd(context, \u0026eventfd);\n+}\n+\n+LWS_VISIBLE void\n+lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)\n+{\n+\tev_break(loop, EVBREAK_ALL);\n+}\n+\n+LWS_VISIBLE int\n+lws_ev_sigint_cfg(struct lws_context *context, int use_ev_sigint,\n+\t\t lws_ev_signal_cb_t *cb)\n+{\n+\tcontext-\u003euse_ev_sigint \u003d use_ev_sigint;\n+\tif (cb)\n+\t\tcontext-\u003elws_ev_sigint_cb \u003d cb;\n+\telse\n+\t\tcontext-\u003elws_ev_sigint_cb \u003d \u0026lws_ev_sigint_cb;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)\n+{\n+\tstruct ev_signal *w_sigint \u003d \u0026context-\u003ept[tsi].w_sigint.ev_watcher;\n+\tstruct ev_io *w_accept \u003d \u0026context-\u003ept[tsi].w_accept.ev_watcher;\n+\tstruct lws_vhost *vh \u003d context-\u003evhost_list;\n+\tconst char *backend_name;\n+\tint status \u003d 0;\n+\tint backend;\n+\n+\tif (!loop)\n+\t\tloop \u003d ev_loop_new(0);\n+\telse\n+\t\tcontext-\u003ept[tsi].ev_loop_foreign \u003d 1;\n+\n+\tcontext-\u003ept[tsi].io_loop_ev \u003d loop;\n+\n+\t/*\n+\t * Initialize the accept w_accept with all the listening sockets\n+\t * and register a callback for read operations\n+\t */\n+\twhile (vh) {\n+\t\tif (vh-\u003elserv_wsi) {\n+\t\t\tvh-\u003elserv_wsi-\u003ew_read.context \u003d context;\n+\t\t\tev_io_init(w_accept, lws_accept_cb,\n+\t\t\t\t vh-\u003elserv_wsi-\u003edesc.sockfd, EV_READ);\n+\t\t}\n+\t\tvh \u003d vh-\u003evhost_next;\n+\t}\n+\tev_io_start(context-\u003ept[tsi].io_loop_ev, w_accept);\n+\n+\t/* Register the signal watcher unless the user says not to */\n+\tif (context-\u003euse_ev_sigint) {\n+\t\tev_signal_init(w_sigint, context-\u003elws_ev_sigint_cb, SIGINT);\n+\t\tev_signal_start(context-\u003ept[tsi].io_loop_ev, w_sigint);\n+\t}\n+\tbackend \u003d ev_backend(loop);\n+\n+\tswitch (backend) {\n+\tcase EVBACKEND_SELECT:\n+\t\tbackend_name \u003d \u0022select\u0022;\n+\t\tbreak;\n+\tcase EVBACKEND_POLL:\n+\t\tbackend_name \u003d \u0022poll\u0022;\n+\t\tbreak;\n+\tcase EVBACKEND_EPOLL:\n+\t\tbackend_name \u003d \u0022epoll\u0022;\n+\t\tbreak;\n+\tcase EVBACKEND_KQUEUE:\n+\t\tbackend_name \u003d \u0022kqueue\u0022;\n+\t\tbreak;\n+\tcase EVBACKEND_DEVPOLL:\n+\t\tbackend_name \u003d \u0022/dev/poll\u0022;\n+\t\tbreak;\n+\tcase EVBACKEND_PORT:\n+\t\tbackend_name \u003d \u0022Solaris 10 \u005c\u0022port\u005c\u0022\u0022;\n+\t\tbreak;\n+\tdefault:\n+\t\tbackend_name \u003d \u0022Unknown libev backend\u0022;\n+\t\tbreak;\n+\t}\n+\n+\tlwsl_info(\u0022 libev backend: %s\u005cn\u0022, backend_name);\n+\t(void)backend_name;\n+\n+\treturn status;\n+}\n+\n+void\n+lws_libev_destroyloop(struct lws_context *context, int tsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n+\n+\tif (!lws_check_opt(context-\u003eoptions, LWS_SERVER_OPTION_LIBEV))\n+\t\treturn;\n+\n+\tif (!pt-\u003eio_loop_ev)\n+\t\treturn;\n+\n+\tev_io_stop(pt-\u003eio_loop_ev, \u0026pt-\u003ew_accept.ev_watcher);\n+\tif (context-\u003euse_ev_sigint)\n+\t\tev_signal_stop(pt-\u003eio_loop_ev,\n+\t\t \u0026pt-\u003ew_sigint.ev_watcher);\n+\tif (!pt-\u003eev_loop_foreign)\n+\t\tev_loop_destroy(pt-\u003eio_loop_ev);\n+}\n+\n+LWS_VISIBLE void\n+lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)\n+{\n+\tstruct lws_context *context \u003d lws_get_context(new_wsi);\n+\tstruct ev_io *r \u003d \u0026new_wsi-\u003ew_read.ev_watcher;\n+\tstruct ev_io *w \u003d \u0026new_wsi-\u003ew_write.ev_watcher;\n+\tint fd;\n+\n+\tif (!LWS_LIBEV_ENABLED(context))\n+\t\treturn;\n+\n+\tif (new_wsi-\u003emode \u003d\u003d LWSCM_RAW_FILEDESC)\n+\t\tfd \u003d desc.filefd;\n+\telse\n+\t\tfd \u003d desc.sockfd;\n+\n+\tnew_wsi-\u003ew_read.context \u003d context;\n+\tnew_wsi-\u003ew_write.context \u003d context;\n+\tev_io_init(r, lws_accept_cb, fd, EV_READ);\n+\tev_io_init(w, lws_accept_cb, fd, EV_WRITE);\n+}\n+\n+LWS_VISIBLE void\n+lws_libev_io(struct lws *wsi, int flags)\n+{\n+\tstruct lws_context *context \u003d lws_get_context(wsi);\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\n+\tif (!LWS_LIBEV_ENABLED(context))\n+\t\treturn;\n+\n+\tif (!pt-\u003eio_loop_ev)\n+\t\treturn;\n+\n+\tassert((flags \u0026 (LWS_EV_START | LWS_EV_STOP)) \u0026\u0026\n+\t (flags \u0026 (LWS_EV_READ | LWS_EV_WRITE)));\n+\n+\tif (flags \u0026 LWS_EV_START) {\n+\t\tif (flags \u0026 LWS_EV_WRITE)\n+\t\t\tev_io_start(pt-\u003eio_loop_ev, \u0026wsi-\u003ew_write.ev_watcher);\n+\t\tif (flags \u0026 LWS_EV_READ)\n+\t\t\tev_io_start(pt-\u003eio_loop_ev, \u0026wsi-\u003ew_read.ev_watcher);\n+\t} else {\n+\t\tif (flags \u0026 LWS_EV_WRITE)\n+\t\t\tev_io_stop(pt-\u003eio_loop_ev, \u0026wsi-\u003ew_write.ev_watcher);\n+\t\tif (flags \u0026 LWS_EV_READ)\n+\t\t\tev_io_stop(pt-\u003eio_loop_ev, \u0026wsi-\u003ew_read.ev_watcher);\n+\t}\n+}\n+\n+LWS_VISIBLE int\n+lws_libev_init_fd_table(struct lws_context *context)\n+{\n+\tint n;\n+\n+\tif (!LWS_LIBEV_ENABLED(context))\n+\t\treturn 0;\n+\n+\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++) {\n+\t\tcontext-\u003ept[n].w_accept.context \u003d context;\n+\t\tcontext-\u003ept[n].w_sigint.context \u003d context;\n+\t}\n+\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE void\n+lws_libev_run(const struct lws_context *context, int tsi)\n+{\n+\tif (context-\u003ept[tsi].io_loop_ev \u0026\u0026 LWS_LIBEV_ENABLED(context))\n+\t\tev_run(context-\u003ept[tsi].io_loop_ev, 0);\n+}\ndiff --git a/lib/event-libs/libevent.c b/lib/event-libs/libevent.c\nnew file mode 100644\nindex 0000000..08b5a8d\n--- /dev/null\n+++ b/lib/event-libs/libevent.c\n@@ -0,0 +1,235 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+void lws_feature_status_libevent(struct lws_context_creation_info *info)\n+{\n+\tif (lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_LIBEVENT))\n+\t\tlwsl_info(\u0022libevent support compiled in and enabled\u005cn\u0022);\n+\telse\n+\t\tlwsl_info(\u0022libevent support compiled in but disabled\u005cn\u0022);\n+}\n+\n+static void\n+lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx)\n+{\n+\tstruct lws_io_watcher *lws_io \u003d (struct lws_io_watcher *)ctx;\n+\tstruct lws_context *context \u003d lws_io-\u003econtext;\n+\tstruct lws_pollfd eventfd;\n+\n+\tif (revents \u0026 EV_TIMEOUT)\n+\t\treturn;\n+\n+\t/* !!! EV_CLOSED doesn't exist in libevent2 */\n+\t#if LIBEVENT_VERSION_NUMBER \u003c 0x02000000\n+\tif (revents \u0026 EV_CLOSED) {\n+\t\tevent_del(lws_io-\u003eevent_watcher);\n+\t\tevent_free(lws_io-\u003eevent_watcher);\n+\t\treturn;\n+\t}\n+\t#endif\n+\n+\teventfd.fd \u003d sock_fd;\n+\teventfd.events \u003d 0;\n+\teventfd.revents \u003d 0;\n+\tif (revents \u0026 EV_READ) {\n+\t\teventfd.events |\u003d LWS_POLLIN;\n+\t\teventfd.revents |\u003d LWS_POLLIN;\n+\t}\n+\tif (revents \u0026 EV_WRITE) {\n+\t\teventfd.events |\u003d LWS_POLLOUT;\n+\t\teventfd.revents |\u003d LWS_POLLOUT;\n+\t}\n+\n+\tlws_service_fd(context, \u0026eventfd);\n+}\n+\n+LWS_VISIBLE void\n+lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx)\n+{\n+\tstruct lws_context_per_thread *pt \u003d ctx;\n+\n+\tif (!pt-\u003eev_loop_foreign)\n+\t\tevent_base_loopbreak(pt-\u003eio_loop_event_base);\n+}\n+\n+LWS_VISIBLE int\n+lws_event_sigint_cfg(struct lws_context *context, int use_event_sigint,\n+lws_event_signal_cb_t *cb)\n+{\n+\tcontext-\u003euse_ev_sigint \u003d use_event_sigint;\n+\tif (cb)\n+\t\tcontext-\u003elws_event_sigint_cb \u003d cb;\n+\telse\n+\t\tcontext-\u003elws_event_sigint_cb \u003d \u0026lws_event_sigint_cb;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_event_initloop(struct lws_context *context, struct event_base *loop,\n+int tsi)\n+{\n+\tstruct lws_vhost *vh \u003d context-\u003evhost_list;\n+\n+\tif (!loop)\n+\t\tcontext-\u003ept[tsi].io_loop_event_base \u003d event_base_new();\n+\telse {\n+\t\tcontext-\u003ept[tsi].ev_loop_foreign \u003d 1;\n+\t\tcontext-\u003ept[tsi].io_loop_event_base \u003d loop;\n+\t}\n+\n+\t/*\n+\t* Initialize all events with the listening sockets\n+\t* and register a callback for read operations\n+\t*/\n+\n+\twhile (vh) {\n+\t\tif (vh-\u003elserv_wsi) {\n+\t\t\tvh-\u003elserv_wsi-\u003ew_read.context \u003d context;\n+\t\t\tvh-\u003elserv_wsi-\u003ew_read.event_watcher \u003d event_new(\n+\t\t\t\t\tloop, vh-\u003elserv_wsi-\u003edesc.sockfd,\n+\t\t\t\t\t(EV_READ | EV_PERSIST), lws_event_cb,\n+\t\t\t\t\t\u0026vh-\u003elserv_wsi-\u003ew_read);\n+\t\t\tevent_add(vh-\u003elserv_wsi-\u003ew_read.event_watcher, NULL);\n+\t\t}\n+\t\tvh \u003d vh-\u003evhost_next;\n+\t}\n+\n+\t/* Register the signal watcher unless the user says not to */\n+\tif (!context-\u003euse_ev_sigint)\n+\t\treturn 0;\n+\n+\tcontext-\u003ept[tsi].w_sigint.event_watcher \u003d evsignal_new(loop, SIGINT,\n+\t\t\tcontext-\u003elws_event_sigint_cb, \u0026context-\u003ept[tsi]);\n+\tevent_add(context-\u003ept[tsi].w_sigint.event_watcher, NULL);\n+\n+\treturn 0;\n+}\n+\n+void\n+lws_libevent_destroyloop(struct lws_context *context, int tsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n+\tstruct lws_vhost *vh \u003d context-\u003evhost_list;\n+\n+\tif (!lws_check_opt(context-\u003eoptions, LWS_SERVER_OPTION_LIBEVENT))\n+\t\treturn;\n+\n+\tif (!pt-\u003eio_loop_event_base)\n+\t\treturn;\n+\n+\t/*\n+\t * Free all events with the listening sockets\n+\t */\n+\twhile (vh) {\n+\t\tif (vh-\u003elserv_wsi) {\n+\t\t\tevent_free(vh-\u003elserv_wsi-\u003ew_read.event_watcher);\n+\t\t\tvh-\u003elserv_wsi-\u003ew_read.event_watcher \u003d NULL;\n+\t\t}\n+\t\tvh \u003d vh-\u003evhost_next;\n+\t}\n+\n+\tif (context-\u003euse_ev_sigint)\n+\t\tevent_free(pt-\u003ew_sigint.event_watcher);\n+\tif (!pt-\u003eev_loop_foreign)\n+\t\tevent_base_free(pt-\u003eio_loop_event_base);\n+}\n+\n+LWS_VISIBLE void\n+lws_libevent_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)\n+{\n+\tstruct lws_context *context \u003d lws_get_context(new_wsi);\n+\tstruct lws_context_per_thread *pt;\n+\tint fd;\n+\n+\tif (!LWS_LIBEVENT_ENABLED(context))\n+\t\treturn;\n+\n+\tnew_wsi-\u003ew_read.context \u003d context;\n+\tnew_wsi-\u003ew_write.context \u003d context;\n+\n+\t// Initialize the event\n+\tpt \u003d \u0026context-\u003ept[(int)new_wsi-\u003etsi];\n+\n+\tif (new_wsi-\u003emode \u003d\u003d LWSCM_RAW_FILEDESC)\n+\t\tfd \u003d desc.filefd;\n+\telse\n+\t\tfd \u003d desc.sockfd;\n+\n+\tnew_wsi-\u003ew_read.event_watcher \u003d event_new(pt-\u003eio_loop_event_base, fd,\n+\t\t(EV_READ | EV_PERSIST), lws_event_cb, \u0026new_wsi-\u003ew_read);\n+\tnew_wsi-\u003ew_write.event_watcher \u003d event_new(pt-\u003eio_loop_event_base, fd,\n+\t\t(EV_WRITE | EV_PERSIST), lws_event_cb, \u0026new_wsi-\u003ew_write);\n+}\n+\n+LWS_VISIBLE void\n+lws_libevent_io(struct lws *wsi, int flags)\n+{\n+\tstruct lws_context *context \u003d lws_get_context(wsi);\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\n+\tif (!LWS_LIBEVENT_ENABLED(context))\n+\t\treturn;\n+\n+\tif (!pt-\u003eio_loop_event_base || context-\u003ebeing_destroyed)\n+\t\treturn;\n+\n+\tassert((flags \u0026 (LWS_EV_START | LWS_EV_STOP)) \u0026\u0026\n+\t (flags \u0026 (LWS_EV_READ | LWS_EV_WRITE)));\n+\n+\tif (flags \u0026 LWS_EV_START) {\n+\t\tif (flags \u0026 LWS_EV_WRITE)\n+\t\t\tevent_add(wsi-\u003ew_write.event_watcher, NULL);\n+\t\tif (flags \u0026 LWS_EV_READ)\n+\t\t\tevent_add(wsi-\u003ew_read.event_watcher, NULL);\n+\t} else {\n+\t\tif (flags \u0026 LWS_EV_WRITE)\n+\t\t\tevent_del(wsi-\u003ew_write.event_watcher);\n+\n+\t\tif (flags \u0026 LWS_EV_READ)\n+\t\t\tevent_del(wsi-\u003ew_read.event_watcher);\n+\t}\n+}\n+\n+LWS_VISIBLE int\n+lws_libevent_init_fd_table(struct lws_context *context)\n+{\n+\tint n;\n+\n+\tif (!LWS_LIBEVENT_ENABLED(context))\n+\t\treturn 0;\n+\n+\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++)\n+\t\tcontext-\u003ept[n].w_sigint.context \u003d context;\n+\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE void\n+lws_libevent_run(const struct lws_context *context, int tsi)\n+{\n+\t/* Run / Dispatch the event_base loop */\n+\tif (context-\u003ept[tsi].io_loop_event_base \u0026\u0026\n+\t LWS_LIBEVENT_ENABLED(context))\n+\t\tevent_base_dispatch(context-\u003ept[tsi].io_loop_event_base);\n+}\ndiff --git a/lib/event-libs/libuv.c b/lib/event-libs/libuv.c\nnew file mode 100644\nindex 0000000..28dd959\n--- /dev/null\n+++ b/lib/event-libs/libuv.c\n@@ -0,0 +1,706 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+void\n+lws_feature_status_libuv(struct lws_context_creation_info *info)\n+{\n+\tif (lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_LIBUV))\n+\t\tlwsl_info(\u0022libuv support compiled in and enabled\u005cn\u0022);\n+\telse\n+\t\tlwsl_info(\u0022libuv support compiled in but disabled\u005cn\u0022);\n+}\n+\n+static void\n+lws_uv_idle(uv_idle_t *handle\n+#if UV_VERSION_MAJOR \u003d\u003d 0\n+\t\t, int status\n+#endif\n+)\n+{\n+\tstruct lws_context_per_thread *pt \u003d lws_container_of(handle,\n+\t\t\t\t\tstruct lws_context_per_thread, uv_idle);\n+\n+\t/*\n+\t * is there anybody with pending stuff that needs service forcing?\n+\t */\n+\tif (!lws_service_adjust_timeout(pt-\u003econtext, 1, pt-\u003etid)) {\n+\t\t/* -1 timeout means just do forced service */\n+\t\t_lws_plat_service_tsi(pt-\u003econtext, -1, pt-\u003etid);\n+\t\t/* still somebody left who wants forced service? */\n+\t\tif (!lws_service_adjust_timeout(pt-\u003econtext, 1, pt-\u003etid))\n+\t\t\t/* yes... come back again later */\n+\t\treturn;\n+\t}\n+\n+\t/* there is nobody who needs service forcing, shut down idle */\n+\tuv_idle_stop(handle);\n+}\n+\n+static void\n+lws_io_cb(uv_poll_t *watcher, int status, int revents)\n+{\n+\tstruct lws_io_watcher *lws_io \u003d lws_container_of(watcher,\n+\t\t\t\t\tstruct lws_io_watcher, uv_watcher);\n+\tstruct lws *wsi \u003d lws_container_of(lws_io, struct lws, w_read);\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tstruct lws_pollfd eventfd;\n+\n+#if defined(WIN32) || defined(_WIN32)\n+\teventfd.fd \u003d watcher-\u003esocket;\n+#else\n+\teventfd.fd \u003d watcher-\u003eio_watcher.fd;\n+#endif\n+\teventfd.events \u003d 0;\n+\teventfd.revents \u003d 0;\n+\n+\tif (status \u003c 0) {\n+\t\t/*\n+\t\t * At this point status will be an UV error, like UV_EBADF,\n+\t\t * we treat all errors as LWS_POLLHUP\n+\t\t *\n+\t\t * You might want to return; instead of servicing the fd in\n+\t\t * some cases */\n+\t\tif (status \u003d\u003d UV_EAGAIN)\n+\t\t\treturn;\n+\n+\t\teventfd.events |\u003d LWS_POLLHUP;\n+\t\teventfd.revents |\u003d LWS_POLLHUP;\n+\t} else {\n+\t\tif (revents \u0026 UV_READABLE) {\n+\t\t\teventfd.events |\u003d LWS_POLLIN;\n+\t\t\teventfd.revents |\u003d LWS_POLLIN;\n+\t\t}\n+\t\tif (revents \u0026 UV_WRITABLE) {\n+\t\t\teventfd.events |\u003d LWS_POLLOUT;\n+\t\t\teventfd.revents |\u003d LWS_POLLOUT;\n+\t\t}\n+\t}\n+\tlws_service_fd(context, \u0026eventfd);\n+\n+\tuv_idle_start(\u0026context-\u003ept[(int)wsi-\u003etsi].uv_idle, lws_uv_idle);\n+}\n+\n+LWS_VISIBLE void\n+lws_uv_sigint_cb(uv_signal_t *watcher, int signum)\n+{\n+\tlwsl_err(\u0022internal signal handler caught signal %d\u005cn\u0022, signum);\n+\tlws_libuv_stop(watcher-\u003edata);\n+}\n+\n+LWS_VISIBLE int\n+lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,\n+\t\t uv_signal_cb cb)\n+{\n+\tcontext-\u003euse_ev_sigint \u003d use_uv_sigint;\n+\tif (cb)\n+\t\tcontext-\u003elws_uv_sigint_cb \u003d cb;\n+\telse\n+\t\tcontext-\u003elws_uv_sigint_cb \u003d \u0026lws_uv_sigint_cb;\n+\n+\treturn 0;\n+}\n+\n+static void\n+lws_uv_timeout_cb(uv_timer_t *timer\n+#if UV_VERSION_MAJOR \u003d\u003d 0\n+\t\t, int status\n+#endif\n+)\n+{\n+\tstruct lws_context_per_thread *pt \u003d lws_container_of(timer,\n+\t\t\tstruct lws_context_per_thread, uv_timeout_watcher);\n+\n+\tif (pt-\u003econtext-\u003erequested_kill)\n+\t\treturn;\n+\n+\tlwsl_debug(\u0022%s\u005cn\u0022, __func__);\n+\n+\tlws_service_fd_tsi(pt-\u003econtext, NULL, pt-\u003etid);\n+}\n+\n+static const int sigs[] \u003d { SIGINT, SIGTERM, SIGSEGV, SIGFPE, SIGHUP };\n+\n+int\n+lws_uv_initvhost(struct lws_vhost* vh, struct lws* wsi)\n+{\n+\tstruct lws_context_per_thread *pt;\n+\tint n;\n+\n+\tif (!LWS_LIBUV_ENABLED(vh-\u003econtext))\n+\t\treturn 0;\n+\tif (!wsi)\n+\t\twsi \u003d vh-\u003elserv_wsi;\n+\tif (!wsi)\n+\t\treturn 0;\n+\tif (wsi-\u003ew_read.context)\n+\t\treturn 0;\n+\n+\tpt \u003d \u0026vh-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tif (!pt-\u003eio_loop_uv)\n+\t\treturn 0;\n+\n+\twsi-\u003ew_read.context \u003d vh-\u003econtext;\n+\tn \u003d uv_poll_init_socket(pt-\u003eio_loop_uv,\n+\t\t\t\t\u0026wsi-\u003ew_read.uv_watcher, wsi-\u003edesc.sockfd);\n+\tif (n) {\n+\t\tlwsl_err(\u0022uv_poll_init failed %d, sockfd\u003d%p\u005cn\u0022,\n+\t\t\t\t n, (void *)(lws_intptr_t)wsi-\u003edesc.sockfd);\n+\n+\t\treturn -1;\n+\t}\n+\tlws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * This needs to be called after vhosts have been defined.\n+ *\n+ * If later, after server start, another vhost is added, this must be\n+ * called again to bind the vhost\n+ */\n+\n+LWS_VISIBLE int\n+lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n+\tstruct lws_vhost *vh \u003d context-\u003evhost_list;\n+\tint status \u003d 0, n, ns, first \u003d 1;\n+\n+\tif (!pt-\u003eio_loop_uv) {\n+\t\tif (!loop) {\n+\t\t\tloop \u003d lws_malloc(sizeof(*loop), \u0022libuv loop\u0022);\n+\t\t\tif (!loop) {\n+\t\t\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t#if UV_VERSION_MAJOR \u003e 0\n+\t\t\tuv_loop_init(loop);\n+\t#else\n+\t\t\tlwsl_err(\u0022This libuv is too old to work...\u005cn\u0022);\n+\t\t\treturn 1;\n+\t#endif\n+\t\t\tpt-\u003eev_loop_foreign \u003d 0;\n+\t\t} else {\n+\t\t\tlwsl_notice(\u0022 Using foreign event loop...\u005cn\u0022);\n+\t\t\tpt-\u003eev_loop_foreign \u003d 1;\n+\t\t}\n+\n+\t\tpt-\u003eio_loop_uv \u003d loop;\n+\t\tuv_idle_init(loop, \u0026pt-\u003euv_idle);\n+\n+\t\tns \u003d ARRAY_SIZE(sigs);\n+\t\tif (lws_check_opt(context-\u003eoptions,\n+\t\t\t\t LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))\n+\t\t\tns \u003d 2;\n+\n+\t\tif (pt-\u003econtext-\u003euse_ev_sigint) {\n+\t\t\tassert(ns \u003c\u003d ARRAY_SIZE(pt-\u003esignals));\n+\t\t\tfor (n \u003d 0; n \u003c ns; n++) {\n+\t\t\t\tuv_signal_init(loop, \u0026pt-\u003esignals[n]);\n+\t\t\t\tpt-\u003esignals[n].data \u003d pt-\u003econtext;\n+\t\t\t\tuv_signal_start(\u0026pt-\u003esignals[n],\n+\t\t\t\t\t\tcontext-\u003elws_uv_sigint_cb,\n+\t\t\t\t\t\tsigs[n]);\n+\t\t\t}\n+\t\t}\n+\t} else\n+\t\tfirst \u003d 0;\n+\n+\t/*\n+\t * Initialize the accept wsi read watcher with all the listening sockets\n+\t * and register a callback for read operations\n+\t *\n+\t * We have to do it here because the uv loop(s) are not\n+\t * initialized until after context creation.\n+\t */\n+\twhile (vh) {\n+\t\tif (lws_uv_initvhost(vh, vh-\u003elserv_wsi) \u003d\u003d -1)\n+\t\t\treturn -1;\n+\t\tvh \u003d vh-\u003evhost_next;\n+\t}\n+\n+\tif (first) {\n+\t\tuv_timer_init(pt-\u003eio_loop_uv, \u0026pt-\u003euv_timeout_watcher);\n+\t\tuv_timer_start(\u0026pt-\u003euv_timeout_watcher, lws_uv_timeout_cb,\n+\t\t\t 10, 1000);\n+\t}\n+\n+\treturn status;\n+}\n+\n+static void lws_uv_close_cb(uv_handle_t *handle)\n+{\n+}\n+\n+static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)\n+{\n+\tif (!uv_is_closing(handle))\n+\t\tuv_close(handle, lws_uv_close_cb);\n+}\n+\n+LWS_VISIBLE void\n+lws_close_all_handles_in_loop(uv_loop_t *loop)\n+{\n+\tuv_walk(loop, lws_uv_walk_cb, NULL);\n+}\n+\n+void\n+lws_libuv_destroyloop(struct lws_context *context, int tsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n+\tint m, budget \u003d 100, ns;\n+\n+\tif (!lws_check_opt(context-\u003eoptions, LWS_SERVER_OPTION_LIBUV))\n+\t\treturn;\n+\n+\tif (!pt-\u003eio_loop_uv)\n+\t\treturn;\n+\n+\tif (context-\u003euse_ev_sigint) {\n+\t\tuv_signal_stop(\u0026pt-\u003ew_sigint.uv_watcher);\n+\n+\t\tns \u003d ARRAY_SIZE(sigs);\n+\t\tif (lws_check_opt(context-\u003eoptions,\n+\t\t\t\t LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))\n+\t\t\tns \u003d 2;\n+\n+\t\tfor (m \u003d 0; m \u003c ns; m++) {\n+\t\t\tuv_signal_stop(\u0026pt-\u003esignals[m]);\n+\t\t\tuv_close((uv_handle_t *)\u0026pt-\u003esignals[m], lws_uv_close_cb);\n+\t\t}\n+\t}\n+\n+\tuv_timer_stop(\u0026pt-\u003euv_timeout_watcher);\n+\tuv_close((uv_handle_t *)\u0026pt-\u003euv_timeout_watcher, lws_uv_close_cb);\n+\n+\tuv_idle_stop(\u0026pt-\u003euv_idle);\n+\tuv_close((uv_handle_t *)\u0026pt-\u003euv_idle, lws_uv_close_cb);\n+\n+\tif (pt-\u003eev_loop_foreign)\n+\t\treturn;\n+\n+\twhile (budget-- \u0026\u0026 uv_run(pt-\u003eio_loop_uv, UV_RUN_NOWAIT))\n+\t\t;\n+\n+\tuv_stop(pt-\u003eio_loop_uv);\n+\tuv_walk(pt-\u003eio_loop_uv, lws_uv_walk_cb, NULL);\n+\twhile (uv_run(pt-\u003eio_loop_uv, UV_RUN_NOWAIT))\n+\t\t;\n+#if UV_VERSION_MAJOR \u003e 0\n+\tm \u003d uv_loop_close(pt-\u003eio_loop_uv);\n+\tif (m \u003d\u003d UV_EBUSY)\n+\t\tlwsl_err(\u0022%s: uv_loop_close: UV_EBUSY\u005cn\u0022, __func__);\n+#endif\n+\tlws_free(pt-\u003eio_loop_uv);\n+}\n+\n+void\n+lws_libuv_accept(struct lws *wsi, lws_sock_file_fd_type desc)\n+{\n+\tstruct lws_context *context \u003d lws_get_context(wsi);\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\n+\tif (!LWS_LIBUV_ENABLED(context))\n+\t\treturn;\n+\n+\twsi-\u003ew_read.context \u003d context;\n+\tif (wsi-\u003emode \u003d\u003d LWSCM_RAW_FILEDESC)\n+\t\tuv_poll_init(pt-\u003eio_loop_uv, \u0026wsi-\u003ew_read.uv_watcher,\n+\t\t\t (int)desc.filefd);\n+\telse\n+\t\tuv_poll_init_socket(pt-\u003eio_loop_uv, \u0026wsi-\u003ew_read.uv_watcher,\n+\t\t\t\t desc.sockfd);\n+}\n+\n+void\n+lws_libuv_io(struct lws *wsi, int flags)\n+{\n+\tstruct lws_context *context \u003d lws_get_context(wsi);\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tstruct lws_io_watcher *w \u003d \u0026wsi-\u003ew_read;\n+//#if defined(WIN32) || defined(_WIN32)\n+//\tint current_events \u003d w-\u003euv_watcher.events \u0026\n+//\t\t\t (UV_READABLE | UV_WRITABLE);\n+//#else\n+\tint current_events \u003d w-\u003eactual_events \u0026 (UV_READABLE | UV_WRITABLE);\n+//#endif\n+\n+\tif (!LWS_LIBUV_ENABLED(context))\n+\t\treturn;\n+\n+\t// w-\u003econtext is set after the loop is initialized\n+\n+\tif (!pt-\u003eio_loop_uv || !w-\u003econtext) {\n+\t\tlwsl_info(\u0022%s: no io loop yet\u005cn\u0022, __func__);\n+\t\treturn;\n+\t}\n+\n+\tif (!((flags \u0026 (LWS_EV_START | LWS_EV_STOP)) \u0026\u0026\n+\t (flags \u0026 (LWS_EV_READ | LWS_EV_WRITE)))) {\n+\t\tlwsl_err(\u0022%s: assert: flags %d\u0022, __func__, flags);\n+\t\tassert(0);\n+\t}\n+\n+\tif (flags \u0026 LWS_EV_START) {\n+\t\tif (flags \u0026 LWS_EV_WRITE)\n+\t\t\tcurrent_events |\u003d UV_WRITABLE;\n+\n+\t\tif (flags \u0026 LWS_EV_READ)\n+\t\t\tcurrent_events |\u003d UV_READABLE;\n+\n+\t\tuv_poll_start(\u0026w-\u003euv_watcher, current_events, lws_io_cb);\n+\t} else {\n+\t\tif (flags \u0026 LWS_EV_WRITE)\n+\t\t\tcurrent_events \u0026\u003d ~UV_WRITABLE;\n+\n+\t\tif (flags \u0026 LWS_EV_READ)\n+\t\t\tcurrent_events \u0026\u003d ~UV_READABLE;\n+\n+\t\tif (!(current_events \u0026 (UV_READABLE | UV_WRITABLE)))\n+\t\t\tuv_poll_stop(\u0026w-\u003euv_watcher);\n+\t\telse\n+\t\t\tuv_poll_start(\u0026w-\u003euv_watcher, current_events,\n+\t\t\t\t lws_io_cb);\n+\t}\n+\n+\tw-\u003eactual_events \u003d current_events;\n+}\n+\n+int\n+lws_libuv_init_fd_table(struct lws_context *context)\n+{\n+\tint n;\n+\n+\tif (!LWS_LIBUV_ENABLED(context))\n+\t\treturn 0;\n+\n+\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++)\n+\t\tcontext-\u003ept[n].w_sigint.context \u003d context;\n+\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE void\n+lws_libuv_run(const struct lws_context *context, int tsi)\n+{\n+\tif (context-\u003ept[tsi].io_loop_uv \u0026\u0026 LWS_LIBUV_ENABLED(context))\n+\t\tuv_run(context-\u003ept[tsi].io_loop_uv, 0);\n+}\n+\n+LWS_VISIBLE void\n+lws_libuv_stop_without_kill(const struct lws_context *context, int tsi)\n+{\n+\tif (context-\u003ept[tsi].io_loop_uv \u0026\u0026 LWS_LIBUV_ENABLED(context))\n+\t\tuv_stop(context-\u003ept[tsi].io_loop_uv);\n+}\n+\n+static void\n+lws_libuv_kill(const struct lws_context *context)\n+{\n+\tint n;\n+\n+\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++)\n+\t\tif (context-\u003ept[n].io_loop_uv \u0026\u0026\n+\t\t LWS_LIBUV_ENABLED(context))\n+\t\t\tuv_stop(context-\u003ept[n].io_loop_uv);\n+}\n+\n+/*\n+ * This does not actually stop the event loop. The reason is we have to pass\n+ * libuv handle closures through its event loop. So this tries to close all\n+ * wsi, and set a flag; when all the wsi closures are finalized then we\n+ * actually stop the libuv event loops.\n+ */\n+LWS_VISIBLE void\n+lws_libuv_stop(struct lws_context *context)\n+{\n+\tstruct lws_context_per_thread *pt;\n+\tint n, m;\n+\n+\tif (context-\u003erequested_kill)\n+\t\treturn;\n+\n+\tcontext-\u003erequested_kill \u003d 1;\n+\n+\tm \u003d context-\u003ecount_threads;\n+\tcontext-\u003ebeing_destroyed \u003d 1;\n+\n+\twhile (m--) {\n+\t\tpt \u003d \u0026context-\u003ept[m];\n+\n+\t\tfor (n \u003d 0; (unsigned int)n \u003c context-\u003ept[m].fds_count; n++) {\n+\t\t\tstruct lws *wsi \u003d wsi_from_fd(context, pt-\u003efds[n].fd);\n+\n+\t\t\tif (!wsi)\n+\t\t\t\tcontinue;\n+\t\t\tlws_close_free_wsi(wsi,\n+\t\t\t\tLWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY\n+\t\t\t\t/* no protocol close */);\n+\t\t\tn--;\n+\t\t}\n+\t}\n+\n+\tlwsl_info(\u0022%s: feels everything closed\u005cn\u0022, __func__);\n+\tif (context-\u003ecount_wsi_allocated \u003d\u003d 0)\n+\t\tlws_libuv_kill(context);\n+}\n+\n+LWS_VISIBLE uv_loop_t *\n+lws_uv_getloop(struct lws_context *context, int tsi)\n+{\n+\tif (context-\u003ept[tsi].io_loop_uv \u0026\u0026 LWS_LIBUV_ENABLED(context))\n+\t\treturn context-\u003ept[tsi].io_loop_uv;\n+\n+\treturn NULL;\n+}\n+\n+static void\n+lws_libuv_closewsi(uv_handle_t* handle)\n+{\n+\tstruct lws *n \u003d NULL, *wsi \u003d (struct lws *)(((char *)handle) -\n+\t\t\t (char *)(\u0026n-\u003ew_read.uv_watcher));\n+\tstruct lws_context *context \u003d lws_get_context(wsi);\n+\tint lspd \u003d 0;\n+\n+\tif (wsi-\u003emode \u003d\u003d LWSCM_SERVER_LISTENER \u0026\u0026\n+\t wsi-\u003econtext-\u003edeprecated) {\n+\t\tlspd \u003d 1;\n+\t\tcontext-\u003edeprecation_pending_listen_close_count--;\n+\t\tif (!context-\u003edeprecation_pending_listen_close_count)\n+\t\t\tlspd \u003d 2;\n+\t}\n+\n+\tlws_close_free_wsi_final(wsi);\n+\n+\tif (lspd \u003d\u003d 2 \u0026\u0026 context-\u003edeprecation_cb) {\n+\t\tlwsl_notice(\u0022calling deprecation callback\u005cn\u0022);\n+\t\tcontext-\u003edeprecation_cb();\n+\t}\n+\n+\tif (context-\u003erequested_kill \u0026\u0026 context-\u003ecount_wsi_allocated \u003d\u003d 0)\n+\t\tlws_libuv_kill(context);\n+}\n+\n+void\n+lws_libuv_closehandle(struct lws *wsi)\n+{\n+\tstruct lws_context *context \u003d lws_get_context(wsi);\n+\n+\t/* required to defer actual deletion until libuv has processed it */\n+\tuv_close((uv_handle_t*)\u0026wsi-\u003ew_read.uv_watcher, lws_libuv_closewsi);\n+\n+\tif (context-\u003erequested_kill \u0026\u0026 context-\u003ecount_wsi_allocated \u003d\u003d 0)\n+\t\tlws_libuv_kill(context);\n+}\n+\n+static void\n+lws_libuv_closewsi_m(uv_handle_t* handle)\n+{\n+\tlws_sockfd_type sockfd \u003d (lws_sockfd_type)(lws_intptr_t)handle-\u003edata;\n+\n+\tcompatible_close(sockfd);\n+}\n+\n+void\n+lws_libuv_closehandle_manually(struct lws *wsi)\n+{\n+\tuv_handle_t *h \u003d (void *)\u0026wsi-\u003ew_read.uv_watcher;\n+\n+\th-\u003edata \u003d (void *)(lws_intptr_t)wsi-\u003edesc.sockfd;\n+\t/* required to defer actual deletion until libuv has processed it */\n+\tuv_close((uv_handle_t*)\u0026wsi-\u003ew_read.uv_watcher, lws_libuv_closewsi_m);\n+}\n+\n+int\n+lws_libuv_check_watcher_active(struct lws *wsi)\n+{\n+\tuv_handle_t *h \u003d (void *)\u0026wsi-\u003ew_read.uv_watcher;\n+\n+\treturn uv_is_active(h);\n+}\n+\n+\n+#if defined(LWS_WITH_PLUGINS) \u0026\u0026 (UV_VERSION_MAJOR \u003e 0)\n+\n+LWS_VISIBLE int\n+lws_plat_plugins_init(struct lws_context *context, const char * const *d)\n+{\n+\tstruct lws_plugin_capability lcaps;\n+\tstruct lws_plugin *plugin;\n+\tlws_plugin_init_func initfunc;\n+\tint m, ret \u003d 0;\n+\tvoid *v;\n+\tuv_dirent_t dent;\n+\tuv_fs_t req;\n+\tchar path[256];\n+\tuv_lib_t lib;\n+\tint pofs \u003d 0;\n+\n+#if defined(__MINGW32__) || !defined(WIN32)\n+\tpofs \u003d 3;\n+#endif\n+\n+\tlib.errmsg \u003d NULL;\n+\tlib.handle \u003d NULL;\n+\n+\tuv_loop_init(\u0026context-\u003epu_loop);\n+\n+\tlwsl_notice(\u0022 Plugins:\u005cn\u0022);\n+\n+\twhile (d \u0026\u0026 *d) {\n+\n+\t\tlwsl_notice(\u0022 Scanning %s\u005cn\u0022, *d);\n+\t\tm \u003duv_fs_scandir(\u0026context-\u003epu_loop, \u0026req, *d, 0, NULL);\n+\t\tif (m \u003c 1) {\n+\t\t\tlwsl_err(\u0022Scandir on %s failed\u005cn\u0022, *d);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\twhile (uv_fs_scandir_next(\u0026req, \u0026dent) !\u003d UV_EOF) {\n+\t\t\tif (strlen(dent.name) \u003c 7)\n+\t\t\t\tcontinue;\n+\n+\t\t\tlwsl_notice(\u0022 %s\u005cn\u0022, dent.name);\n+\n+\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, *d,\n+\t\t\t\t dent.name);\n+\t\t\tif (uv_dlopen(path, \u0026lib)) {\n+\t\t\t\tuv_dlerror(\u0026lib);\n+\t\t\t\tlwsl_err(\u0022Error loading DSO: %s\u005cn\u0022, lib.errmsg);\n+\t\t\t\tuv_dlclose(\u0026lib);\n+\t\t\t\tgoto bail;\n+\t\t\t}\n+\n+\t\t\t/* we could open it, can we get his init function? */\n+\n+#if !defined(WIN32) \u0026\u0026 !defined(__MINGW32__)\n+\t\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022init_%s\u0022,\n+\t\t\t\t dent.name + pofs /* snip lib... */);\n+\t\t\tpath[m - 3] \u003d '\u005c0'; /* snip the .so */\n+#else\n+\t\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022init_%s\u0022,\n+\t\t\t\t dent.name + pofs);\n+\t\t\tpath[m - 4] \u003d '\u005c0'; /* snip the .dll */\n+#endif\n+\t\t\tif (uv_dlsym(\u0026lib, path, \u0026v)) {\n+\t\t\t\tuv_dlerror(\u0026lib);\n+\t\t\t\tlwsl_err(\u0022Failed to get %s on %s: %s\u0022, path,\n+\t\t\t\t\t\tdent.name, lib.errmsg);\n+\t\t\t\tuv_dlclose(\u0026lib);\n+\t\t\t\tgoto bail;\n+\t\t\t}\n+\t\t\tinitfunc \u003d (lws_plugin_init_func)v;\n+\t\t\tlcaps.api_magic \u003d LWS_PLUGIN_API_MAGIC;\n+\t\t\tm \u003d initfunc(context, \u0026lcaps);\n+\t\t\tif (m) {\n+\t\t\t\tlwsl_err(\u0022Init %s failed %d\u005cn\u0022, dent.name, m);\n+\t\t\t\tgoto skip;\n+\t\t\t}\n+\n+\t\t\tplugin \u003d lws_malloc(sizeof(*plugin), \u0022plugin\u0022);\n+\t\t\tif (!plugin) {\n+\t\t\t\tuv_dlclose(\u0026lib);\n+\t\t\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n+\t\t\t\tgoto bail;\n+\t\t\t}\n+\t\t\tplugin-\u003elist \u003d context-\u003eplugin_list;\n+\t\t\tcontext-\u003eplugin_list \u003d plugin;\n+\t\t\tstrncpy(plugin-\u003ename, dent.name, sizeof(plugin-\u003ename) - 1);\n+\t\t\tplugin-\u003ename[sizeof(plugin-\u003ename) - 1] \u003d '\u005c0';\n+\t\t\tplugin-\u003elib \u003d lib;\n+\t\t\tplugin-\u003ecaps \u003d lcaps;\n+\t\t\tcontext-\u003eplugin_protocol_count +\u003d lcaps.count_protocols;\n+\t\t\tcontext-\u003eplugin_extension_count +\u003d lcaps.count_extensions;\n+\n+\t\t\tcontinue;\n+\n+skip:\n+\t\t\tuv_dlclose(\u0026lib);\n+\t\t}\n+bail:\n+\t\tuv_fs_req_cleanup(\u0026req);\n+\t\td++;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_plugins_destroy(struct lws_context *context)\n+{\n+\tstruct lws_plugin *plugin \u003d context-\u003eplugin_list, *p;\n+\tlws_plugin_destroy_func func;\n+\tchar path[256];\n+\tint pofs \u003d 0;\n+\tvoid *v;\n+\tint m;\n+\n+#if defined(__MINGW32__) || !defined(WIN32)\n+\tpofs \u003d 3;\n+#endif\n+\n+\tif (!plugin)\n+\t\treturn 0;\n+\n+\twhile (plugin) {\n+\t\tp \u003d plugin;\n+\n+#if !defined(WIN32) \u0026\u0026 !defined(__MINGW32__)\n+\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022destroy_%s\u0022,\n+\t\t\t\t plugin-\u003ename + pofs);\n+\t\tpath[m - 3] \u003d '\u005c0';\n+#else\n+\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022destroy_%s\u0022,\n+\t\t\t\t plugin-\u003ename + pofs);\n+\t\tpath[m - 4] \u003d '\u005c0';\n+#endif\n+\n+\t\tif (uv_dlsym(\u0026plugin-\u003elib, path, \u0026v)) {\n+\t\t\tuv_dlerror(\u0026plugin-\u003elib);\n+\t\t\tlwsl_err(\u0022Failed to get %s on %s: %s\u0022, path,\n+\t\t\t\t\tplugin-\u003ename, plugin-\u003elib.errmsg);\n+\t\t} else {\n+\t\t\tfunc \u003d (lws_plugin_destroy_func)v;\n+\t\t\tm \u003d func(context);\n+\t\t\tif (m)\n+\t\t\t\tlwsl_err(\u0022Destroying %s failed %d\u005cn\u0022,\n+\t\t\t\t\t\tplugin-\u003ename, m);\n+\t\t}\n+\n+\t\tuv_dlclose(\u0026p-\u003elib);\n+\t\tplugin \u003d p-\u003elist;\n+\t\tp-\u003elist \u003d NULL;\n+\t\tfree(p);\n+\t}\n+\n+\tcontext-\u003eplugin_list \u003d NULL;\n+\n+\twhile (uv_loop_close(\u0026context-\u003epu_loop))\n+\t\t;\n+\n+\treturn 0;\n+}\n+\n+#endif\n+\ndiff --git a/lib/ext/extension-permessage-deflate.c b/lib/ext/extension-permessage-deflate.c\nnew file mode 100644\nindex 0000000..e2be2ae\n--- /dev/null\n+++ b/lib/ext/extension-permessage-deflate.c\n@@ -0,0 +1,473 @@\n+/*\n+ * ./lib/extension-permessage-deflate.c\n+ *\n+ * Copyright (C) 2016 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+#include \u0022extension-permessage-deflate.h\u0022\n+#include \u003cstdio.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u003cassert.h\u003e\n+\n+#define LWS_ZLIB_MEMLEVEL 8\n+\n+const struct lws_ext_options lws_ext_pm_deflate_options[] \u003d {\n+\t/* public RFC7692 settings */\n+\t{ \u0022server_no_context_takeover\u0022, EXTARG_NONE },\n+\t{ \u0022client_no_context_takeover\u0022, EXTARG_NONE },\n+\t{ \u0022server_max_window_bits\u0022,\tEXTARG_OPT_DEC },\n+\t{ \u0022client_max_window_bits\u0022,\tEXTARG_OPT_DEC },\n+\t/* ones only user code can set */\n+\t{ \u0022rx_buf_size\u0022,\t\tEXTARG_DEC },\n+\t{ \u0022tx_buf_size\u0022,\t\tEXTARG_DEC },\n+\t{ \u0022compression_level\u0022,\t\tEXTARG_DEC },\n+\t{ \u0022mem_level\u0022,\t\t\tEXTARG_DEC },\n+\t{ NULL, 0 }, /* sentinel */\n+};\n+\n+static void\n+lws_extension_pmdeflate_restrict_args(struct lws *wsi,\n+\t\t\t\t struct lws_ext_pm_deflate_priv *priv)\n+{\n+\tint n, extra;\n+\n+\t/* cap the RX buf at the nearest power of 2 to protocol rx buf */\n+\n+\tn \u003d wsi-\u003econtext-\u003ept_serv_buf_size;\n+\tif (wsi-\u003eprotocol-\u003erx_buffer_size)\n+\t\tn \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n+\n+\textra \u003d 7;\n+\twhile (n \u003e\u003d 1 \u003c\u003c (extra + 1))\n+\t\textra++;\n+\n+\tif (extra \u003c priv-\u003eargs[PMD_RX_BUF_PWR2]) {\n+\t\tpriv-\u003eargs[PMD_RX_BUF_PWR2] \u003d extra;\n+\t\tlwsl_info(\u0022 Capping pmd rx to %d\u005cn\u0022, 1 \u003c\u003c extra);\n+\t}\n+}\n+\n+LWS_VISIBLE int\n+lws_extension_callback_pm_deflate(struct lws_context *context,\n+\t\t\t\t const struct lws_extension *ext,\n+\t\t\t\t struct lws *wsi,\n+\t\t\t\t enum lws_extension_callback_reasons reason,\n+\t\t\t\t void *user, void *in, size_t len)\n+{\n+\tstruct lws_ext_pm_deflate_priv *priv \u003d\n+\t\t\t\t (struct lws_ext_pm_deflate_priv *)user;\n+\tstruct lws_tokens *eff_buf \u003d (struct lws_tokens *)in;\n+\tstatic unsigned char trail[] \u003d { 0, 0, 0xff, 0xff };\n+\tint n, ret \u003d 0, was_fin \u003d 0, extra;\n+\tstruct lws_ext_option_arg *oa;\n+\n+\tswitch (reason) {\n+\tcase LWS_EXT_CB_NAMED_OPTION_SET:\n+\t\toa \u003d in;\n+\t\tif (!oa-\u003eoption_name)\n+\t\t\tbreak;\n+\t\tfor (n \u003d 0; n \u003c ARRAY_SIZE(lws_ext_pm_deflate_options); n++)\n+\t\t\tif (!strcmp(lws_ext_pm_deflate_options[n].name, oa-\u003eoption_name))\n+\t\t\t\tbreak;\n+\n+\t\tif (n \u003d\u003d ARRAY_SIZE(lws_ext_pm_deflate_options))\n+\t\t\tbreak;\n+\t\toa-\u003eoption_index \u003d n;\n+\n+\t\t/* fallthru */\n+\n+\tcase LWS_EXT_CB_OPTION_SET:\n+\t\toa \u003d in;\n+\t\tlwsl_notice(\u0022%s: option set: idx %d, %s, len %d\u005cn\u0022, __func__,\n+\t\t\t oa-\u003eoption_index, oa-\u003estart, oa-\u003elen);\n+\t\tif (oa-\u003estart)\n+\t\t\tpriv-\u003eargs[oa-\u003eoption_index] \u003d atoi(oa-\u003estart);\n+\t\telse\n+\t\t\tpriv-\u003eargs[oa-\u003eoption_index] \u003d 1;\n+\n+\t\tif (priv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003d\u003d 8)\n+\t\t\tpriv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003d 9;\n+\n+\t\tlws_extension_pmdeflate_restrict_args(wsi, priv);\n+\t\tbreak;\n+\n+\tcase LWS_EXT_CB_OPTION_CONFIRM:\n+\t\tif (priv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS] \u003c 8 ||\n+\t\t priv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS] \u003e 15 ||\n+\t\t priv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003c 8 ||\n+\t\t priv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003e 15)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase LWS_EXT_CB_CLIENT_CONSTRUCT:\n+\tcase LWS_EXT_CB_CONSTRUCT:\n+\n+\t\tn \u003d context-\u003ept_serv_buf_size;\n+\t\tif (wsi-\u003eprotocol-\u003erx_buffer_size)\n+\t\t\tn \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n+\n+\t\tif (n \u003c 128) {\n+\t\t\tlwsl_info(\u0022 permessage-deflate requires the protocol (%s) to have an RX buffer \u003e\u003d 128\u005cn\u0022,\n+\t\t\t\t\twsi-\u003eprotocol-\u003ename);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/* fill in **user */\n+\t\tpriv \u003d lws_zalloc(sizeof(*priv), \u0022pmd priv\u0022);\n+\t\t*((void **)user) \u003d priv;\n+\t\tlwsl_ext(\u0022%s: LWS_EXT_CB_*CONSTRUCT\u005cn\u0022, __func__);\n+\t\tmemset(priv, 0, sizeof(*priv));\n+\n+\t\t/* fill in pointer to options list */\n+\t\tif (in)\n+\t\t\t*((const struct lws_ext_options **)in) \u003d\n+\t\t\t\t\tlws_ext_pm_deflate_options;\n+\n+\t\t/* fallthru */\n+\n+\tcase LWS_EXT_CB_OPTION_DEFAULT:\n+\n+\t\t/* set the public, RFC7692 defaults... */\n+\n+\t\tpriv-\u003eargs[PMD_SERVER_NO_CONTEXT_TAKEOVER] \u003d 0,\n+\t\tpriv-\u003eargs[PMD_CLIENT_NO_CONTEXT_TAKEOVER] \u003d 0;\n+\t\tpriv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS] \u003d 15;\n+\t\tpriv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003d 15;\n+\n+\t\t/* ...and the ones the user code can override */\n+\n+\t\tpriv-\u003eargs[PMD_RX_BUF_PWR2] \u003d 10; /* ie, 1024 */\n+\t\tpriv-\u003eargs[PMD_TX_BUF_PWR2] \u003d 10; /* ie, 1024 */\n+\t\tpriv-\u003eargs[PMD_COMP_LEVEL] \u003d 1;\n+\t\tpriv-\u003eargs[PMD_MEM_LEVEL] \u003d 8;\n+\n+\t\tlws_extension_pmdeflate_restrict_args(wsi, priv);\n+\t\tbreak;\n+\n+\tcase LWS_EXT_CB_DESTROY:\n+\t\tlwsl_ext(\u0022%s: LWS_EXT_CB_DESTROY\u005cn\u0022, __func__);\n+\t\tlws_free(priv-\u003ebuf_rx_inflated);\n+\t\tlws_free(priv-\u003ebuf_tx_deflated);\n+\t\tif (priv-\u003erx_init)\n+\t\t\t(void)inflateEnd(\u0026priv-\u003erx);\n+\t\tif (priv-\u003etx_init)\n+\t\t\t(void)deflateEnd(\u0026priv-\u003etx);\n+\t\tlws_free(priv);\n+\t\treturn ret;\n+\n+\tcase LWS_EXT_CB_PAYLOAD_RX:\n+\t\tlwsl_ext(\u0022 %s: LWS_EXT_CB_PAYLOAD_RX: in %d, existing in %d\u005cn\u0022,\n+\t\t\t __func__, eff_buf-\u003etoken_len, priv-\u003erx.avail_in);\n+\t\tif (!(wsi-\u003eu.ws.rsv_first_msg \u0026 0x40))\n+\t\t\treturn 0;\n+\n+#if 0\n+\t\tfor (n \u003d 0; n \u003c eff_buf-\u003etoken_len; n++) {\n+\t\t\tprintf(\u0022%02X \u0022, (unsigned char)eff_buf-\u003etoken[n]);\n+\t\t\tif ((n \u0026 15) \u003d\u003d 15)\n+\t\t\t\tprintf(\u0022\u005cn\u0022);\n+\t\t}\n+\t\tprintf(\u0022\u005cn\u0022);\n+#endif\n+\t\tif (!priv-\u003erx_init)\n+\t\t\tif (inflateInit2(\u0026priv-\u003erx, -priv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS]) !\u003d Z_OK) {\n+\t\t\t\tlwsl_err(\u0022%s: iniflateInit failed\u005cn\u0022, __func__);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\tpriv-\u003erx_init \u003d 1;\n+\t\tif (!priv-\u003ebuf_rx_inflated)\n+\t\t\tpriv-\u003ebuf_rx_inflated \u003d lws_malloc(LWS_PRE + 7 + 5 +\n+\t\t\t\t\t (1 \u003c\u003c priv-\u003eargs[PMD_RX_BUF_PWR2]), \u0022pmd rx inflate buf\u0022);\n+\t\tif (!priv-\u003ebuf_rx_inflated) {\n+\t\t\tlwsl_err(\u0022%s: OOM\u005cn\u0022, __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/*\n+\t\t * We have to leave the input stream alone if we didn't\n+\t\t * finish with it yet. The input stream is held in the wsi\n+\t\t * rx buffer by the caller, so this assumption is safe while\n+\t\t * we block new rx while draining the existing rx\n+\t\t */\n+\t\tif (!priv-\u003erx.avail_in \u0026\u0026 eff_buf-\u003etoken \u0026\u0026 eff_buf-\u003etoken_len) {\n+\t\t\tpriv-\u003erx.next_in \u003d (unsigned char *)eff_buf-\u003etoken;\n+\t\t\tpriv-\u003erx.avail_in \u003d eff_buf-\u003etoken_len;\n+\t\t}\n+\t\tpriv-\u003erx.next_out \u003d priv-\u003ebuf_rx_inflated + LWS_PRE;\n+\t\teff_buf-\u003etoken \u003d (char *)priv-\u003erx.next_out;\n+\t\tpriv-\u003erx.avail_out \u003d 1 \u003c\u003c priv-\u003eargs[PMD_RX_BUF_PWR2];\n+\n+\t\tif (priv-\u003erx_held_valid) {\n+\t\t\tlwsl_ext(\u0022-- RX piling on held byte --\u005cn\u0022);\n+\t\t\t*(priv-\u003erx.next_out++) \u003d priv-\u003erx_held;\n+\t\t\tpriv-\u003erx.avail_out--;\n+\t\t\tpriv-\u003erx_held_valid \u003d 0;\n+\t\t}\n+\n+\t\t/* if...\n+\t\t *\n+\t\t * - he has no remaining input content for this message, and\n+\t\t * - and this is the final fragment, and\n+\t\t * - we used everything that could be drained on the input side\n+\t\t *\n+\t\t * ...then put back the 00 00 FF FF the sender stripped as our\n+\t\t * input to zlib\n+\t\t */\n+\t\tif (!priv-\u003erx.avail_in \u0026\u0026 wsi-\u003eu.ws.final \u0026\u0026\n+\t\t !wsi-\u003eu.ws.rx_packet_length) {\n+\t\t\tlwsl_ext(\u0022RX APPEND_TRAILER-DO\u005cn\u0022);\n+\t\t\twas_fin \u003d 1;\n+\t\t\tpriv-\u003erx.next_in \u003d trail;\n+\t\t\tpriv-\u003erx.avail_in \u003d sizeof(trail);\n+\t\t}\n+\n+\t\tn \u003d inflate(\u0026priv-\u003erx, Z_NO_FLUSH);\n+\t\tlwsl_ext(\u0022inflate ret %d, avi %d, avo %d, wsifinal %d\u005cn\u0022, n,\n+\t\t\t priv-\u003erx.avail_in, priv-\u003erx.avail_out, wsi-\u003eu.ws.final);\n+\t\tswitch (n) {\n+\t\tcase Z_NEED_DICT:\n+\t\tcase Z_STREAM_ERROR:\n+\t\tcase Z_DATA_ERROR:\n+\t\tcase Z_MEM_ERROR:\n+\t\t\tlwsl_info(\u0022zlib error inflate %d: %s\u005cn\u0022,\n+\t\t\t\t n, priv-\u003erx.msg);\n+\t\t\treturn -1;\n+\t\t}\n+\t\t/*\n+\t\t * If we did not already send in the 00 00 FF FF, and he's\n+\t\t * out of input, he did not EXACTLY fill the output buffer\n+\t\t * (which is ambiguous and we will force it to go around\n+\t\t * again by withholding a byte), and he's otherwise working on\n+\t\t * being a FIN fragment, then do the FIN message processing\n+\t\t * of faking up the 00 00 FF FF that the sender stripped.\n+\t\t */\n+\t\tif (!priv-\u003erx.avail_in \u0026\u0026 wsi-\u003eu.ws.final \u0026\u0026\n+\t\t !wsi-\u003eu.ws.rx_packet_length \u0026\u0026 !was_fin \u0026\u0026\n+\t\t priv-\u003erx.avail_out /* ambiguous as to if it is the end */\n+\t\t) {\n+\t\t\tlwsl_ext(\u0022RX APPEND_TRAILER-DO\u005cn\u0022);\n+\t\t\twas_fin \u003d 1;\n+\t\t\tpriv-\u003erx.next_in \u003d trail;\n+\t\t\tpriv-\u003erx.avail_in \u003d sizeof(trail);\n+\t\t\tn \u003d inflate(\u0026priv-\u003erx, Z_SYNC_FLUSH);\n+\t\t\tlwsl_ext(\u0022RX trailer inf returned %d, avi %d, avo %d\u005cn\u0022, n,\n+\t\t\t\t priv-\u003erx.avail_in, priv-\u003erx.avail_out);\n+\t\t\tswitch (n) {\n+\t\t\tcase Z_NEED_DICT:\n+\t\t\tcase Z_STREAM_ERROR:\n+\t\t\tcase Z_DATA_ERROR:\n+\t\t\tcase Z_MEM_ERROR:\n+\t\t\t\tlwsl_info(\u0022zlib error inflate %d: %s\u005cn\u0022,\n+\t\t\t\t\t n, priv-\u003erx.msg);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\t\t/*\n+\t\t * we must announce in our returncode now if there is more\n+\t\t * output to be expected from inflate, so we can decide to\n+\t\t * set the FIN bit on this bufferload or not. However zlib\n+\t\t * is ambiguous when we exactly filled the inflate buffer. It\n+\t\t * does not give us a clue as to whether we should understand\n+\t\t * that to mean he ended on a buffer boundary, or if there is\n+\t\t * more in the pipeline.\n+\t\t *\n+\t\t * So to work around that safely, if it used all output space\n+\t\t * exactly, we ALWAYS say there is more coming and we withhold\n+\t\t * the last byte of the buffer to guarantee that is true.\n+\t\t *\n+\t\t * That still leaves us at least one byte to finish with a FIN\n+\t\t * on, even if actually nothing more is coming from the next\n+\t\t * inflate action itself.\n+\t\t */\n+\t\tif (!priv-\u003erx.avail_out) { /* he used all available out buf */\n+\t\t\tlwsl_ext(\u0022-- rx grabbing held --\u005cn\u0022);\n+\t\t\t/* snip the last byte and hold it for next time */\n+\t\t\tpriv-\u003erx_held \u003d *(--priv-\u003erx.next_out);\n+\t\t\tpriv-\u003erx_held_valid \u003d 1;\n+\t\t}\n+\n+\t\teff_buf-\u003etoken_len \u003d (char *)priv-\u003erx.next_out - eff_buf-\u003etoken;\n+\t\tpriv-\u003ecount_rx_between_fin +\u003d eff_buf-\u003etoken_len;\n+\n+\t\tlwsl_ext(\u0022 %s: RX leaving with new effbuff len %d, \u0022\n+\t\t\t \u0022ret %d, rx.avail_in\u003d%d, TOTAL RX since FIN %lu\u005cn\u0022,\n+\t\t\t __func__, eff_buf-\u003etoken_len, priv-\u003erx_held_valid,\n+\t\t\t priv-\u003erx.avail_in,\n+\t\t\t (unsigned long)priv-\u003ecount_rx_between_fin);\n+\n+\t\tif (was_fin) {\n+\t\t\tpriv-\u003ecount_rx_between_fin \u003d 0;\n+\t\t\tif (priv-\u003eargs[PMD_SERVER_NO_CONTEXT_TAKEOVER]) {\n+\t\t\t\t(void)inflateEnd(\u0026priv-\u003erx);\n+\t\t\t\tpriv-\u003erx_init \u003d 0;\n+\t\t\t}\n+\t\t}\n+#if 0\n+\t\tfor (n \u003d 0; n \u003c eff_buf-\u003etoken_len; n++)\n+\t\t\tputchar(eff_buf-\u003etoken[n]);\n+\t\tputs(\u0022\u005cn\u0022);\n+#endif\n+\n+\t\treturn priv-\u003erx_held_valid;\n+\n+\tcase LWS_EXT_CB_PAYLOAD_TX:\n+\n+\t\tif (!priv-\u003etx_init) {\n+\t\t\tn \u003d deflateInit2(\u0026priv-\u003etx, priv-\u003eargs[PMD_COMP_LEVEL],\n+\t\t\t\t\t Z_DEFLATED,\n+\t\t\t\t\t -priv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS +\n+\t\t\t\t\t\t (wsi-\u003evhost-\u003elisten_port \u003c\u003d 0)],\n+\t\t\t\t\t priv-\u003eargs[PMD_MEM_LEVEL],\n+\t\t\t\t\t Z_DEFAULT_STRATEGY);\n+\t\t\tif (n !\u003d Z_OK) {\n+\t\t\t\tlwsl_ext(\u0022inflateInit2 failed %d\u005cn\u0022, n);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t}\n+\t\tpriv-\u003etx_init \u003d 1;\n+\t\tif (!priv-\u003ebuf_tx_deflated)\n+\t\t\tpriv-\u003ebuf_tx_deflated \u003d lws_malloc(LWS_PRE + 7 + 5 +\n+\t\t\t\t\t (1 \u003c\u003c priv-\u003eargs[PMD_TX_BUF_PWR2]), \u0022pmd tx deflate buf\u0022);\n+\t\tif (!priv-\u003ebuf_tx_deflated) {\n+\t\t\tlwsl_err(\u0022%s: OOM\u005cn\u0022, __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (eff_buf-\u003etoken) {\n+\t\t\tlwsl_ext(\u0022%s: TX: eff_buf length %d\u005cn\u0022, __func__,\n+\t\t\t\t eff_buf-\u003etoken_len);\n+\t\t\tpriv-\u003etx.next_in \u003d (unsigned char *)eff_buf-\u003etoken;\n+\t\t\tpriv-\u003etx.avail_in \u003d eff_buf-\u003etoken_len;\n+\t\t}\n+\n+#if 0\n+\t\tfor (n \u003d 0; n \u003c eff_buf-\u003etoken_len; n++) {\n+\t\t\tprintf(\u0022%02X \u0022, (unsigned char)eff_buf-\u003etoken[n]);\n+\t\t\tif ((n \u0026 15) \u003d\u003d 15)\n+\t\t\t\tprintf(\u0022\u005cn\u0022);\n+\t\t}\n+\t\tprintf(\u0022\u005cn\u0022);\n+#endif\n+\n+\t\tpriv-\u003etx.next_out \u003d priv-\u003ebuf_tx_deflated + LWS_PRE + 5;\n+\t\teff_buf-\u003etoken \u003d (char *)priv-\u003etx.next_out;\n+\t\tpriv-\u003etx.avail_out \u003d 1 \u003c\u003c priv-\u003eargs[PMD_TX_BUF_PWR2];\n+\n+\t\tn \u003d deflate(\u0026priv-\u003etx, Z_SYNC_FLUSH);\n+\t\tif (n \u003d\u003d Z_STREAM_ERROR) {\n+\t\t\tlwsl_ext(\u0022%s: Z_STREAM_ERROR\u005cn\u0022, __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (priv-\u003etx_held_valid) {\n+\t\t\tpriv-\u003etx_held_valid \u003d 0;\n+\t\t\tif (priv-\u003etx.avail_out \u003d\u003d 1 \u003c\u003c priv-\u003eargs[PMD_TX_BUF_PWR2])\n+\t\t\t\t/*\n+\t\t\t\t * we can get a situation he took something in\n+\t\t\t\t * but did not generate anything out, at the end\n+\t\t\t\t * of a message (eg, next thing he sends is 80\n+\t\t\t\t * 00, a zero length FIN, like Authobahn can\n+\t\t\t\t * send).\n+\t\t\t\t * If we have come back as a FIN, we must not\n+\t\t\t\t * place the pending trailer 00 00 FF FF, just\n+\t\t\t\t * the 1 byte of live data\n+\t\t\t\t */\n+\t\t\t\t*(--eff_buf-\u003etoken) \u003d priv-\u003etx_held[0];\n+\t\t\telse {\n+\t\t\t\t/* he generated data, prepend whole pending */\n+\t\t\t\teff_buf-\u003etoken -\u003d 5;\n+\t\t\t\tfor (n \u003d 0; n \u003c 5; n++)\n+\t\t\t\t\teff_buf-\u003etoken[n] \u003d priv-\u003etx_held[n];\n+\n+\t\t\t}\n+\t\t}\n+\t\tpriv-\u003ecompressed_out \u003d 1;\n+\t\teff_buf-\u003etoken_len \u003d (int)(priv-\u003etx.next_out -\n+\t\t\t\t\t (unsigned char *)eff_buf-\u003etoken);\n+\n+\t\t/*\n+\t\t * we must announce in our returncode now if there is more\n+\t\t * output to be expected from inflate, so we can decide to\n+\t\t * set the FIN bit on this bufferload or not. However zlib\n+\t\t * is ambiguous when we exactly filled the inflate buffer. It\n+\t\t * does not give us a clue as to whether we should understand\n+\t\t * that to mean he ended on a buffer boundary, or if there is\n+\t\t * more in the pipeline.\n+\t\t *\n+\t\t * Worse, the guy providing the stuff we are sending may not\n+\t\t * know until after that this was, actually, the last chunk,\n+\t\t * that can happen even if we did not fill the output buf, ie\n+\t\t * he may send after this a zero-length FIN fragment.\n+\t\t *\n+\t\t * This is super difficult because we must snip the last 4\n+\t\t * bytes in the case this is the last compressed output of the\n+\t\t * message. The only way to deal with it is defer sending the\n+\t\t * last 5 bytes of each frame until the next one, when we will\n+\t\t * be in a position to understand if that has a FIN or not.\n+\t\t */\n+\n+\t\textra \u003d !!(len \u0026 LWS_WRITE_NO_FIN) || !priv-\u003etx.avail_out;\n+\n+\t\tif (eff_buf-\u003etoken_len \u003e\u003d 4 + extra) {\n+\t\t\tlwsl_ext(\u0022tx held %d\u005cn\u0022, 4 + extra);\n+\t\t\tpriv-\u003etx_held_valid \u003d extra;\n+\t\t\tfor (n \u003d 3 + extra; n \u003e\u003d 0; n--)\n+\t\t\t\tpriv-\u003etx_held[n] \u003d *(--priv-\u003etx.next_out);\n+\t\t\teff_buf-\u003etoken_len -\u003d 4 + extra;\n+\t\t}\n+\t\tlwsl_ext(\u0022 TX rewritten with new effbuff len %d, ret %d\u005cn\u0022,\n+\t\t\t eff_buf-\u003etoken_len, !priv-\u003etx.avail_out);\n+\n+\t\treturn !priv-\u003etx.avail_out; /* 1 \u003d\u003d have more tx pending */\n+\n+\tcase LWS_EXT_CB_PACKET_TX_PRESEND:\n+\t\tif (!priv-\u003ecompressed_out)\n+\t\t\tbreak;\n+\t\tpriv-\u003ecompressed_out \u003d 0;\n+\n+\t\tif ((*(eff_buf-\u003etoken) \u0026 0x80) \u0026\u0026\n+\t\t priv-\u003eargs[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {\n+\t\t\tlwsl_debug(\u0022PMD_CLIENT_NO_CONTEXT_TAKEOVER\u005cn\u0022);\n+\t\t\t(void)deflateEnd(\u0026priv-\u003etx);\n+\t\t\tpriv-\u003etx_init \u003d 0;\n+\t\t}\n+\n+\t\tn \u003d *(eff_buf-\u003etoken) \u0026 15;\n+\t\t/* set RSV1, but not on CONTINUATION */\n+\t\tif (n \u003d\u003d LWSWSOPC_TEXT_FRAME || n \u003d\u003d LWSWSOPC_BINARY_FRAME)\n+\t\t\t*eff_buf-\u003etoken |\u003d 0x40;\n+#if 0\n+\t\tfor (n \u003d 0; n \u003c eff_buf-\u003etoken_len; n++) {\n+\t\t\tprintf(\u0022%02X \u0022, (unsigned char)eff_buf-\u003etoken[n]);\n+\t\t\tif ((n \u0026 15) \u003d\u003d 15)\n+\t\t\t\tputs(\u0022\u005cn\u0022);\n+\t\t}\n+\t\tputs(\u0022\u005cn\u0022);\n+#endif\n+\t\tlwsl_ext(\u0022%s: tx opcode 0x%02X\u005cn\u0022, __func__,\n+\t\t\t (unsigned char)*eff_buf-\u003etoken);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\ndiff --git a/lib/ext/extension-permessage-deflate.h b/lib/ext/extension-permessage-deflate.h\nnew file mode 100644\nindex 0000000..8737736\n--- /dev/null\n+++ b/lib/ext/extension-permessage-deflate.h\n@@ -0,0 +1,41 @@\n+\n+#include \u003czlib.h\u003e\n+\n+#define DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER 1\n+#define DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT Z_DEFAULT_COMPRESSION\n+\n+enum arg_indexes {\n+\tPMD_SERVER_NO_CONTEXT_TAKEOVER,\n+\tPMD_CLIENT_NO_CONTEXT_TAKEOVER,\n+\tPMD_SERVER_MAX_WINDOW_BITS,\n+\tPMD_CLIENT_MAX_WINDOW_BITS,\n+\tPMD_RX_BUF_PWR2,\n+\tPMD_TX_BUF_PWR2,\n+\tPMD_COMP_LEVEL,\n+\tPMD_MEM_LEVEL,\n+\n+\tPMD_ARG_COUNT\n+};\n+\n+struct lws_ext_pm_deflate_priv {\n+\tz_stream rx;\n+\tz_stream tx;\n+\n+\tunsigned char *buf_rx_inflated; /* RX inflated output buffer */\n+\tunsigned char *buf_tx_deflated; /* TX deflated output buffer */\n+\n+\tsize_t count_rx_between_fin;\n+\n+\tunsigned char args[PMD_ARG_COUNT];\n+\tunsigned char tx_held[5];\n+\tunsigned char rx_held;\n+\n+\tunsigned char tx_init:1;\n+\tunsigned char rx_init:1;\n+\tunsigned char compressed_out:1;\n+\tunsigned char rx_held_valid:1;\n+\tunsigned char tx_held_valid:1;\n+\tunsigned char rx_append_trailer:1;\n+\tunsigned char pending_tx_trailer:1;\n+};\n+\ndiff --git a/lib/ext/extension.c b/lib/ext/extension.c\nnew file mode 100644\nindex 0000000..ac28204\n--- /dev/null\n+++ b/lib/ext/extension.c\n@@ -0,0 +1,344 @@\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#include \u0022extension-permessage-deflate.h\u0022\n+\n+LWS_VISIBLE void\n+lws_context_init_extensions(struct lws_context_creation_info *info,\n+\t\t\t struct lws_context *context)\n+{\n+\tlwsl_info(\u0022 LWS_MAX_EXTENSIONS_ACTIVE: %u\u005cn\u0022, LWS_MAX_EXTENSIONS_ACTIVE);\n+}\n+\n+enum lws_ext_option_parser_states {\n+\tLEAPS_SEEK_NAME,\n+\tLEAPS_EAT_NAME,\n+\tLEAPS_SEEK_VAL,\n+\tLEAPS_EAT_DEC,\n+\tLEAPS_SEEK_ARG_TERM\n+};\n+\n+LWS_VISIBLE int\n+lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,\n+\t\t void *ext_user, const struct lws_ext_options *opts,\n+\t\t const char *in, int len)\n+{\n+\tenum lws_ext_option_parser_states leap \u003d LEAPS_SEEK_NAME;\n+\tunsigned int match_map \u003d 0, n, m, w \u003d 0, count_options \u003d 0,\n+\t\t pending_close_quote \u003d 0;\n+\tstruct lws_ext_option_arg oa;\n+\n+\toa.option_name \u003d NULL;\n+\n+\twhile (opts[count_options].name)\n+\t\tcount_options++;\n+\twhile (len) {\n+\t\tlwsl_ext(\u0022'%c' %d\u0022, *in, leap);\n+\t\tswitch (leap) {\n+\t\tcase LEAPS_SEEK_NAME:\n+\t\t\tif (*in \u003d\u003d ' ')\n+\t\t\t\tbreak;\n+\t\t\tif (*in \u003d\u003d ',') {\n+\t\t\t\tlen \u003d 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tmatch_map \u003d (1 \u003c\u003c count_options) - 1;\n+\t\t\tleap \u003d LEAPS_EAT_NAME;\n+\t\t\tw \u003d 0;\n+\n+\t\t/* fallthru */\n+\n+\t\tcase LEAPS_EAT_NAME:\n+\t\t\toa.start \u003d NULL;\n+\t\t\toa.len \u003d 0;\n+\t\t\tm \u003d match_map;\n+\t\t\tn \u003d 0;\n+\t\t\tpending_close_quote \u003d 0;\n+\t\t\twhile (m) {\n+\t\t\t\tif (m \u0026 1) {\n+\t\t\t\t\tlwsl_ext(\u0022 m\u003d%d, n\u003d%d, w\u003d%d\u005cn\u0022, m, n, w);\n+\n+\t\t\t\t\tif (*in \u003d\u003d opts[n].name[w]) {\n+\t\t\t\t\t\tif (!opts[n].name[w + 1]) {\n+\t\t\t\t\t\t\toa.option_index \u003d n;\n+\t\t\t\t\t\t\tlwsl_ext(\u0022hit %d\u005cn\u0022, oa.option_index);\n+\t\t\t\t\t\t\tleap \u003d LEAPS_SEEK_VAL;\n+\t\t\t\t\t\t\tif (len \u003d\u003d 1)\n+\t\t\t\t\t\t\t\tgoto set_arg;\n+\t\t\t\t\t\t\tbreak;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tmatch_map \u0026\u003d ~(1 \u003c\u003c n);\n+\t\t\t\t\t\tif (!match_map) {\n+\t\t\t\t\t\t\tlwsl_ext(\u0022empty match map\u005cn\u0022);\n+\t\t\t\t\t\t\treturn -1;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\tm \u003e\u003e\u003d 1;\n+\t\t\t\tn++;\n+\t\t\t}\n+\t\t\tw++;\n+\t\t\tbreak;\n+\t\tcase LEAPS_SEEK_VAL:\n+\t\t\tif (*in \u003d\u003d ' ')\n+\t\t\t\tbreak;\n+\t\t\tif (*in \u003d\u003d ',') {\n+\t\t\t\tlen \u003d 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (*in \u003d\u003d ';' || len \u003d\u003d 1) { /* ie,nonoptional */\n+\t\t\t\tif (opts[oa.option_index].type \u003d\u003d EXTARG_DEC)\n+\t\t\t\t\treturn -1;\n+\t\t\t\tleap \u003d LEAPS_SEEK_NAME;\n+\t\t\t\tgoto set_arg;\n+\t\t\t}\n+\t\t\tif (*in \u003d\u003d '\u003d') {\n+\t\t\t\tw \u003d 0;\n+\t\t\t\tpending_close_quote \u003d 0;\n+\t\t\t\tif (opts[oa.option_index].type \u003d\u003d EXTARG_NONE)\n+\t\t\t\t\treturn -1;\n+\n+\t\t\t\tleap \u003d LEAPS_EAT_DEC;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\treturn -1;\n+\n+\t\tcase LEAPS_EAT_DEC:\n+\t\t\tif (*in \u003e\u003d '0' \u0026\u0026 *in \u003c\u003d '9') {\n+\t\t\t\tif (!w)\n+\t\t\t\t\toa.start \u003d in;\n+\t\t\t\tw++;\n+\t\t\t\tif (len !\u003d 1)\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (!w \u0026\u0026 *in \u003d\u003d'\u0022') {\n+\t\t\t\tpending_close_quote \u003d 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (!w)\n+\t\t\t\treturn -1;\n+\t\t\tif (pending_close_quote \u0026\u0026 *in !\u003d '\u0022' \u0026\u0026 len !\u003d 1)\n+\t\t\t\treturn -1;\n+\t\t\tleap \u003d LEAPS_SEEK_ARG_TERM;\n+\t\t\tif (oa.start)\n+\t\t\t\toa.len \u003d in - oa.start;\n+\t\t\tif (len \u003d\u003d 1)\n+\t\t\t\toa.len++;\n+\n+set_arg:\n+\t\t\text-\u003ecallback(lws_get_context(wsi),\n+\t\t\t\text, wsi, LWS_EXT_CB_OPTION_SET,\n+\t\t\t\text_user, (char *)\u0026oa, 0);\n+\t\t\tif (len \u003d\u003d 1)\n+\t\t\t\tbreak;\n+\t\t\tif (pending_close_quote \u0026\u0026 *in \u003d\u003d '\u0022')\n+\t\t\t\tbreak;\n+\n+\t\t\t/* fallthru */\n+\n+\t\tcase LEAPS_SEEK_ARG_TERM:\n+\t\t\tif (*in \u003d\u003d ' ')\n+\t\t\t\tbreak;\n+\t\t\tif (*in \u003d\u003d ';') {\n+\t\t\t\tleap \u003d LEAPS_SEEK_NAME;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (*in \u003d\u003d ',') {\n+\t\t\t\tlen \u003d 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\treturn -1;\n+\t\t}\n+\t\tlen--;\n+\t\tin++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+/* 0 \u003d nobody had nonzero return, 1 \u003d somebody had positive return, -1 \u003d fail */\n+\n+int lws_ext_cb_active(struct lws *wsi, int reason, void *arg, int len)\n+{\n+\tint n, m, handled \u003d 0;\n+\n+\tfor (n \u003d 0; n \u003c wsi-\u003ecount_act_ext; n++) {\n+\t\tm \u003d wsi-\u003eactive_extensions[n]-\u003ecallback(lws_get_context(wsi),\n+\t\t\twsi-\u003eactive_extensions[n], wsi, reason,\n+\t\t\twsi-\u003eact_ext_user[n], arg, len);\n+\t\tif (m \u003c 0) {\n+\t\t\tlwsl_ext(\u0022Ext '%s' failed to handle callback %d!\u005cn\u0022,\n+\t\t\t\t wsi-\u003eactive_extensions[n]-\u003ename, reason);\n+\t\t\treturn -1;\n+\t\t}\n+\t\t/* valgrind... */\n+\t\tif (reason \u003d\u003d LWS_EXT_CB_DESTROY)\n+\t\t\twsi-\u003eact_ext_user[n] \u003d NULL;\n+\t\tif (m \u003e handled)\n+\t\t\thandled \u003d m;\n+\t}\n+\n+\treturn handled;\n+}\n+\n+int lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi,\n+\t\t\tint reason, void *arg, int len)\n+{\n+\tint n \u003d 0, m, handled \u003d 0;\n+\tconst struct lws_extension *ext;\n+\n+\tif (!wsi || !wsi-\u003evhost)\n+\t\treturn 0;\n+\n+\text \u003d wsi-\u003evhost-\u003eextensions;\n+\n+\twhile (ext \u0026\u0026 ext-\u003ecallback \u0026\u0026 !handled) {\n+\t\tm \u003d ext-\u003ecallback(context, ext, wsi, reason,\n+\t\t\t\t (void *)(lws_intptr_t)n, arg, len);\n+\t\tif (m \u003c 0) {\n+\t\t\tlwsl_ext(\u0022Ext '%s' failed to handle callback %d!\u005cn\u0022,\n+\t\t\t\t wsi-\u003eactive_extensions[n]-\u003ename, reason);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (m)\n+\t\t\thandled \u003d 1;\n+\n+\t\text++;\n+\t\tn++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len)\n+{\n+\tstruct lws_tokens eff_buf;\n+\tint ret, m, n \u003d 0;\n+\n+\teff_buf.token \u003d (char *)buf;\n+\teff_buf.token_len \u003d len;\n+\n+\t/*\n+\t * while we have original buf to spill ourselves, or extensions report\n+\t * more in their pipeline\n+\t */\n+\n+\tret \u003d 1;\n+\twhile (ret \u003d\u003d 1) {\n+\n+\t\t/* default to nobody has more to spill */\n+\n+\t\tret \u003d 0;\n+\n+\t\t/* show every extension the new incoming data */\n+\t\tm \u003d lws_ext_cb_active(wsi,\n+\t\t\t LWS_EXT_CB_PACKET_TX_PRESEND, \u0026eff_buf, 0);\n+\t\tif (m \u003c 0)\n+\t\t\treturn -1;\n+\t\tif (m) /* handled */\n+\t\t\tret \u003d 1;\n+\n+\t\tif ((char *)buf !\u003d eff_buf.token)\n+\t\t\t/*\n+\t\t\t * extension recreated it:\n+\t\t\t * need to buffer this if not all sent\n+\t\t\t */\n+\t\t\twsi-\u003eu.ws.clean_buffer \u003d 0;\n+\n+\t\t/* assuming they left us something to send, send it */\n+\n+\t\tif (eff_buf.token_len) {\n+\t\t\tn \u003d lws_issue_raw(wsi, (unsigned char *)eff_buf.token,\n+\t\t\t\t\t\t\t eff_buf.token_len);\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tlwsl_info(\u0022closing from ext access\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\n+\t\t\t/* always either sent it all or privately buffered */\n+\t\t\tif (wsi-\u003eu.ws.clean_buffer)\n+\t\t\t\tlen \u003d n;\n+\t\t}\n+\n+\t\tlwsl_parser(\u0022written %d bytes to client\u005cn\u0022, n);\n+\n+\t\t/* no extension has more to spill? Then we can go */\n+\n+\t\tif (!ret)\n+\t\t\tbreak;\n+\n+\t\t/* we used up what we had */\n+\n+\t\teff_buf.token \u003d NULL;\n+\t\teff_buf.token_len \u003d 0;\n+\n+\t\t/*\n+\t\t * Did that leave the pipe choked?\n+\t\t * Or we had to hold on to some of it?\n+\t\t */\n+\n+\t\tif (!lws_send_pipe_choked(wsi) \u0026\u0026 !wsi-\u003etrunc_len)\n+\t\t\t/* no we could add more, lets's do that */\n+\t\t\tcontinue;\n+\n+\t\tlwsl_debug(\u0022choked\u005cn\u0022);\n+\n+\t\t/*\n+\t\t * Yes, he's choked. Don't spill the rest now get a callback\n+\t\t * when he is ready to send and take care of it there\n+\t\t */\n+\t\tlws_callback_on_writable(wsi);\n+\t\twsi-\u003eextension_data_pending \u003d 1;\n+\t\tret \u003d 0;\n+\t}\n+\n+\treturn len;\n+}\n+\n+int\n+lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r,\n+\t\t\t void *v, size_t len)\n+{\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tint n, handled \u003d 0;\n+\n+\t/* maybe an extension will take care of it for us */\n+\n+\tfor (n \u003d 0; n \u003c wsi-\u003ecount_act_ext \u0026\u0026 !handled; n++) {\n+\t\tif (!wsi-\u003eactive_extensions[n]-\u003ecallback)\n+\t\t\tcontinue;\n+\n+\t\thandled |\u003d wsi-\u003eactive_extensions[n]-\u003ecallback(context,\n+\t\t\twsi-\u003eactive_extensions[n], wsi,\n+\t\t\tr, wsi-\u003eact_ext_user[n], v, len);\n+\t}\n+\n+\treturn handled;\n+}\n+\n+int\n+lws_set_extension_option(struct lws *wsi, const char *ext_name,\n+\t\t\t const char *opt_name, const char *opt_val)\n+{\n+\tstruct lws_ext_option_arg oa;\n+\tint idx \u003d 0;\n+\n+\t/* first identify if the ext is active on this wsi */\n+\twhile (idx \u003c wsi-\u003ecount_act_ext \u0026\u0026\n+\t strcmp(wsi-\u003eactive_extensions[idx]-\u003ename, ext_name))\n+\t\tidx++;\n+\n+\tif (idx \u003d\u003d wsi-\u003ecount_act_ext)\n+\t\treturn -1; /* request ext not active on this wsi */\n+\n+\toa.option_name \u003d opt_name;\n+\toa.option_index \u003d 0;\n+\toa.start \u003d opt_val;\n+\toa.len \u003d 0;\n+\n+\treturn wsi-\u003eactive_extensions[idx]-\u003ecallback(\n+\t\t\twsi-\u003econtext, wsi-\u003eactive_extensions[idx], wsi,\n+\t\t\tLWS_EXT_CB_NAMED_OPTION_SET, wsi-\u003eact_ext_user[idx], \u0026oa, 0);\n+}\ndiff --git a/lib/extension-permessage-deflate.c b/lib/extension-permessage-deflate.c\ndeleted file mode 100644\nindex e2be2ae..0000000\n--- a/lib/extension-permessage-deflate.c\n+++ /dev/null\n@@ -1,473 +0,0 @@\n-/*\n- * ./lib/extension-permessage-deflate.c\n- *\n- * Copyright (C) 2016 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-#include \u0022extension-permessage-deflate.h\u0022\n-#include \u003cstdio.h\u003e\n-#include \u003cstring.h\u003e\n-#include \u003cassert.h\u003e\n-\n-#define LWS_ZLIB_MEMLEVEL 8\n-\n-const struct lws_ext_options lws_ext_pm_deflate_options[] \u003d {\n-\t/* public RFC7692 settings */\n-\t{ \u0022server_no_context_takeover\u0022, EXTARG_NONE },\n-\t{ \u0022client_no_context_takeover\u0022, EXTARG_NONE },\n-\t{ \u0022server_max_window_bits\u0022,\tEXTARG_OPT_DEC },\n-\t{ \u0022client_max_window_bits\u0022,\tEXTARG_OPT_DEC },\n-\t/* ones only user code can set */\n-\t{ \u0022rx_buf_size\u0022,\t\tEXTARG_DEC },\n-\t{ \u0022tx_buf_size\u0022,\t\tEXTARG_DEC },\n-\t{ \u0022compression_level\u0022,\t\tEXTARG_DEC },\n-\t{ \u0022mem_level\u0022,\t\t\tEXTARG_DEC },\n-\t{ NULL, 0 }, /* sentinel */\n-};\n-\n-static void\n-lws_extension_pmdeflate_restrict_args(struct lws *wsi,\n-\t\t\t\t struct lws_ext_pm_deflate_priv *priv)\n-{\n-\tint n, extra;\n-\n-\t/* cap the RX buf at the nearest power of 2 to protocol rx buf */\n-\n-\tn \u003d wsi-\u003econtext-\u003ept_serv_buf_size;\n-\tif (wsi-\u003eprotocol-\u003erx_buffer_size)\n-\t\tn \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n-\n-\textra \u003d 7;\n-\twhile (n \u003e\u003d 1 \u003c\u003c (extra + 1))\n-\t\textra++;\n-\n-\tif (extra \u003c priv-\u003eargs[PMD_RX_BUF_PWR2]) {\n-\t\tpriv-\u003eargs[PMD_RX_BUF_PWR2] \u003d extra;\n-\t\tlwsl_info(\u0022 Capping pmd rx to %d\u005cn\u0022, 1 \u003c\u003c extra);\n-\t}\n-}\n-\n-LWS_VISIBLE int\n-lws_extension_callback_pm_deflate(struct lws_context *context,\n-\t\t\t\t const struct lws_extension *ext,\n-\t\t\t\t struct lws *wsi,\n-\t\t\t\t enum lws_extension_callback_reasons reason,\n-\t\t\t\t void *user, void *in, size_t len)\n-{\n-\tstruct lws_ext_pm_deflate_priv *priv \u003d\n-\t\t\t\t (struct lws_ext_pm_deflate_priv *)user;\n-\tstruct lws_tokens *eff_buf \u003d (struct lws_tokens *)in;\n-\tstatic unsigned char trail[] \u003d { 0, 0, 0xff, 0xff };\n-\tint n, ret \u003d 0, was_fin \u003d 0, extra;\n-\tstruct lws_ext_option_arg *oa;\n-\n-\tswitch (reason) {\n-\tcase LWS_EXT_CB_NAMED_OPTION_SET:\n-\t\toa \u003d in;\n-\t\tif (!oa-\u003eoption_name)\n-\t\t\tbreak;\n-\t\tfor (n \u003d 0; n \u003c ARRAY_SIZE(lws_ext_pm_deflate_options); n++)\n-\t\t\tif (!strcmp(lws_ext_pm_deflate_options[n].name, oa-\u003eoption_name))\n-\t\t\t\tbreak;\n-\n-\t\tif (n \u003d\u003d ARRAY_SIZE(lws_ext_pm_deflate_options))\n-\t\t\tbreak;\n-\t\toa-\u003eoption_index \u003d n;\n-\n-\t\t/* fallthru */\n-\n-\tcase LWS_EXT_CB_OPTION_SET:\n-\t\toa \u003d in;\n-\t\tlwsl_notice(\u0022%s: option set: idx %d, %s, len %d\u005cn\u0022, __func__,\n-\t\t\t oa-\u003eoption_index, oa-\u003estart, oa-\u003elen);\n-\t\tif (oa-\u003estart)\n-\t\t\tpriv-\u003eargs[oa-\u003eoption_index] \u003d atoi(oa-\u003estart);\n-\t\telse\n-\t\t\tpriv-\u003eargs[oa-\u003eoption_index] \u003d 1;\n-\n-\t\tif (priv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003d\u003d 8)\n-\t\t\tpriv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003d 9;\n-\n-\t\tlws_extension_pmdeflate_restrict_args(wsi, priv);\n-\t\tbreak;\n-\n-\tcase LWS_EXT_CB_OPTION_CONFIRM:\n-\t\tif (priv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS] \u003c 8 ||\n-\t\t priv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS] \u003e 15 ||\n-\t\t priv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003c 8 ||\n-\t\t priv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003e 15)\n-\t\t\treturn -1;\n-\t\tbreak;\n-\n-\tcase LWS_EXT_CB_CLIENT_CONSTRUCT:\n-\tcase LWS_EXT_CB_CONSTRUCT:\n-\n-\t\tn \u003d context-\u003ept_serv_buf_size;\n-\t\tif (wsi-\u003eprotocol-\u003erx_buffer_size)\n-\t\t\tn \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n-\n-\t\tif (n \u003c 128) {\n-\t\t\tlwsl_info(\u0022 permessage-deflate requires the protocol (%s) to have an RX buffer \u003e\u003d 128\u005cn\u0022,\n-\t\t\t\t\twsi-\u003eprotocol-\u003ename);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\t/* fill in **user */\n-\t\tpriv \u003d lws_zalloc(sizeof(*priv), \u0022pmd priv\u0022);\n-\t\t*((void **)user) \u003d priv;\n-\t\tlwsl_ext(\u0022%s: LWS_EXT_CB_*CONSTRUCT\u005cn\u0022, __func__);\n-\t\tmemset(priv, 0, sizeof(*priv));\n-\n-\t\t/* fill in pointer to options list */\n-\t\tif (in)\n-\t\t\t*((const struct lws_ext_options **)in) \u003d\n-\t\t\t\t\tlws_ext_pm_deflate_options;\n-\n-\t\t/* fallthru */\n-\n-\tcase LWS_EXT_CB_OPTION_DEFAULT:\n-\n-\t\t/* set the public, RFC7692 defaults... */\n-\n-\t\tpriv-\u003eargs[PMD_SERVER_NO_CONTEXT_TAKEOVER] \u003d 0,\n-\t\tpriv-\u003eargs[PMD_CLIENT_NO_CONTEXT_TAKEOVER] \u003d 0;\n-\t\tpriv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS] \u003d 15;\n-\t\tpriv-\u003eargs[PMD_CLIENT_MAX_WINDOW_BITS] \u003d 15;\n-\n-\t\t/* ...and the ones the user code can override */\n-\n-\t\tpriv-\u003eargs[PMD_RX_BUF_PWR2] \u003d 10; /* ie, 1024 */\n-\t\tpriv-\u003eargs[PMD_TX_BUF_PWR2] \u003d 10; /* ie, 1024 */\n-\t\tpriv-\u003eargs[PMD_COMP_LEVEL] \u003d 1;\n-\t\tpriv-\u003eargs[PMD_MEM_LEVEL] \u003d 8;\n-\n-\t\tlws_extension_pmdeflate_restrict_args(wsi, priv);\n-\t\tbreak;\n-\n-\tcase LWS_EXT_CB_DESTROY:\n-\t\tlwsl_ext(\u0022%s: LWS_EXT_CB_DESTROY\u005cn\u0022, __func__);\n-\t\tlws_free(priv-\u003ebuf_rx_inflated);\n-\t\tlws_free(priv-\u003ebuf_tx_deflated);\n-\t\tif (priv-\u003erx_init)\n-\t\t\t(void)inflateEnd(\u0026priv-\u003erx);\n-\t\tif (priv-\u003etx_init)\n-\t\t\t(void)deflateEnd(\u0026priv-\u003etx);\n-\t\tlws_free(priv);\n-\t\treturn ret;\n-\n-\tcase LWS_EXT_CB_PAYLOAD_RX:\n-\t\tlwsl_ext(\u0022 %s: LWS_EXT_CB_PAYLOAD_RX: in %d, existing in %d\u005cn\u0022,\n-\t\t\t __func__, eff_buf-\u003etoken_len, priv-\u003erx.avail_in);\n-\t\tif (!(wsi-\u003eu.ws.rsv_first_msg \u0026 0x40))\n-\t\t\treturn 0;\n-\n-#if 0\n-\t\tfor (n \u003d 0; n \u003c eff_buf-\u003etoken_len; n++) {\n-\t\t\tprintf(\u0022%02X \u0022, (unsigned char)eff_buf-\u003etoken[n]);\n-\t\t\tif ((n \u0026 15) \u003d\u003d 15)\n-\t\t\t\tprintf(\u0022\u005cn\u0022);\n-\t\t}\n-\t\tprintf(\u0022\u005cn\u0022);\n-#endif\n-\t\tif (!priv-\u003erx_init)\n-\t\t\tif (inflateInit2(\u0026priv-\u003erx, -priv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS]) !\u003d Z_OK) {\n-\t\t\t\tlwsl_err(\u0022%s: iniflateInit failed\u005cn\u0022, __func__);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\tpriv-\u003erx_init \u003d 1;\n-\t\tif (!priv-\u003ebuf_rx_inflated)\n-\t\t\tpriv-\u003ebuf_rx_inflated \u003d lws_malloc(LWS_PRE + 7 + 5 +\n-\t\t\t\t\t (1 \u003c\u003c priv-\u003eargs[PMD_RX_BUF_PWR2]), \u0022pmd rx inflate buf\u0022);\n-\t\tif (!priv-\u003ebuf_rx_inflated) {\n-\t\t\tlwsl_err(\u0022%s: OOM\u005cn\u0022, __func__);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\t/*\n-\t\t * We have to leave the input stream alone if we didn't\n-\t\t * finish with it yet. The input stream is held in the wsi\n-\t\t * rx buffer by the caller, so this assumption is safe while\n-\t\t * we block new rx while draining the existing rx\n-\t\t */\n-\t\tif (!priv-\u003erx.avail_in \u0026\u0026 eff_buf-\u003etoken \u0026\u0026 eff_buf-\u003etoken_len) {\n-\t\t\tpriv-\u003erx.next_in \u003d (unsigned char *)eff_buf-\u003etoken;\n-\t\t\tpriv-\u003erx.avail_in \u003d eff_buf-\u003etoken_len;\n-\t\t}\n-\t\tpriv-\u003erx.next_out \u003d priv-\u003ebuf_rx_inflated + LWS_PRE;\n-\t\teff_buf-\u003etoken \u003d (char *)priv-\u003erx.next_out;\n-\t\tpriv-\u003erx.avail_out \u003d 1 \u003c\u003c priv-\u003eargs[PMD_RX_BUF_PWR2];\n-\n-\t\tif (priv-\u003erx_held_valid) {\n-\t\t\tlwsl_ext(\u0022-- RX piling on held byte --\u005cn\u0022);\n-\t\t\t*(priv-\u003erx.next_out++) \u003d priv-\u003erx_held;\n-\t\t\tpriv-\u003erx.avail_out--;\n-\t\t\tpriv-\u003erx_held_valid \u003d 0;\n-\t\t}\n-\n-\t\t/* if...\n-\t\t *\n-\t\t * - he has no remaining input content for this message, and\n-\t\t * - and this is the final fragment, and\n-\t\t * - we used everything that could be drained on the input side\n-\t\t *\n-\t\t * ...then put back the 00 00 FF FF the sender stripped as our\n-\t\t * input to zlib\n-\t\t */\n-\t\tif (!priv-\u003erx.avail_in \u0026\u0026 wsi-\u003eu.ws.final \u0026\u0026\n-\t\t !wsi-\u003eu.ws.rx_packet_length) {\n-\t\t\tlwsl_ext(\u0022RX APPEND_TRAILER-DO\u005cn\u0022);\n-\t\t\twas_fin \u003d 1;\n-\t\t\tpriv-\u003erx.next_in \u003d trail;\n-\t\t\tpriv-\u003erx.avail_in \u003d sizeof(trail);\n-\t\t}\n-\n-\t\tn \u003d inflate(\u0026priv-\u003erx, Z_NO_FLUSH);\n-\t\tlwsl_ext(\u0022inflate ret %d, avi %d, avo %d, wsifinal %d\u005cn\u0022, n,\n-\t\t\t priv-\u003erx.avail_in, priv-\u003erx.avail_out, wsi-\u003eu.ws.final);\n-\t\tswitch (n) {\n-\t\tcase Z_NEED_DICT:\n-\t\tcase Z_STREAM_ERROR:\n-\t\tcase Z_DATA_ERROR:\n-\t\tcase Z_MEM_ERROR:\n-\t\t\tlwsl_info(\u0022zlib error inflate %d: %s\u005cn\u0022,\n-\t\t\t\t n, priv-\u003erx.msg);\n-\t\t\treturn -1;\n-\t\t}\n-\t\t/*\n-\t\t * If we did not already send in the 00 00 FF FF, and he's\n-\t\t * out of input, he did not EXACTLY fill the output buffer\n-\t\t * (which is ambiguous and we will force it to go around\n-\t\t * again by withholding a byte), and he's otherwise working on\n-\t\t * being a FIN fragment, then do the FIN message processing\n-\t\t * of faking up the 00 00 FF FF that the sender stripped.\n-\t\t */\n-\t\tif (!priv-\u003erx.avail_in \u0026\u0026 wsi-\u003eu.ws.final \u0026\u0026\n-\t\t !wsi-\u003eu.ws.rx_packet_length \u0026\u0026 !was_fin \u0026\u0026\n-\t\t priv-\u003erx.avail_out /* ambiguous as to if it is the end */\n-\t\t) {\n-\t\t\tlwsl_ext(\u0022RX APPEND_TRAILER-DO\u005cn\u0022);\n-\t\t\twas_fin \u003d 1;\n-\t\t\tpriv-\u003erx.next_in \u003d trail;\n-\t\t\tpriv-\u003erx.avail_in \u003d sizeof(trail);\n-\t\t\tn \u003d inflate(\u0026priv-\u003erx, Z_SYNC_FLUSH);\n-\t\t\tlwsl_ext(\u0022RX trailer inf returned %d, avi %d, avo %d\u005cn\u0022, n,\n-\t\t\t\t priv-\u003erx.avail_in, priv-\u003erx.avail_out);\n-\t\t\tswitch (n) {\n-\t\t\tcase Z_NEED_DICT:\n-\t\t\tcase Z_STREAM_ERROR:\n-\t\t\tcase Z_DATA_ERROR:\n-\t\t\tcase Z_MEM_ERROR:\n-\t\t\t\tlwsl_info(\u0022zlib error inflate %d: %s\u005cn\u0022,\n-\t\t\t\t\t n, priv-\u003erx.msg);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t}\n-\t\t/*\n-\t\t * we must announce in our returncode now if there is more\n-\t\t * output to be expected from inflate, so we can decide to\n-\t\t * set the FIN bit on this bufferload or not. However zlib\n-\t\t * is ambiguous when we exactly filled the inflate buffer. It\n-\t\t * does not give us a clue as to whether we should understand\n-\t\t * that to mean he ended on a buffer boundary, or if there is\n-\t\t * more in the pipeline.\n-\t\t *\n-\t\t * So to work around that safely, if it used all output space\n-\t\t * exactly, we ALWAYS say there is more coming and we withhold\n-\t\t * the last byte of the buffer to guarantee that is true.\n-\t\t *\n-\t\t * That still leaves us at least one byte to finish with a FIN\n-\t\t * on, even if actually nothing more is coming from the next\n-\t\t * inflate action itself.\n-\t\t */\n-\t\tif (!priv-\u003erx.avail_out) { /* he used all available out buf */\n-\t\t\tlwsl_ext(\u0022-- rx grabbing held --\u005cn\u0022);\n-\t\t\t/* snip the last byte and hold it for next time */\n-\t\t\tpriv-\u003erx_held \u003d *(--priv-\u003erx.next_out);\n-\t\t\tpriv-\u003erx_held_valid \u003d 1;\n-\t\t}\n-\n-\t\teff_buf-\u003etoken_len \u003d (char *)priv-\u003erx.next_out - eff_buf-\u003etoken;\n-\t\tpriv-\u003ecount_rx_between_fin +\u003d eff_buf-\u003etoken_len;\n-\n-\t\tlwsl_ext(\u0022 %s: RX leaving with new effbuff len %d, \u0022\n-\t\t\t \u0022ret %d, rx.avail_in\u003d%d, TOTAL RX since FIN %lu\u005cn\u0022,\n-\t\t\t __func__, eff_buf-\u003etoken_len, priv-\u003erx_held_valid,\n-\t\t\t priv-\u003erx.avail_in,\n-\t\t\t (unsigned long)priv-\u003ecount_rx_between_fin);\n-\n-\t\tif (was_fin) {\n-\t\t\tpriv-\u003ecount_rx_between_fin \u003d 0;\n-\t\t\tif (priv-\u003eargs[PMD_SERVER_NO_CONTEXT_TAKEOVER]) {\n-\t\t\t\t(void)inflateEnd(\u0026priv-\u003erx);\n-\t\t\t\tpriv-\u003erx_init \u003d 0;\n-\t\t\t}\n-\t\t}\n-#if 0\n-\t\tfor (n \u003d 0; n \u003c eff_buf-\u003etoken_len; n++)\n-\t\t\tputchar(eff_buf-\u003etoken[n]);\n-\t\tputs(\u0022\u005cn\u0022);\n-#endif\n-\n-\t\treturn priv-\u003erx_held_valid;\n-\n-\tcase LWS_EXT_CB_PAYLOAD_TX:\n-\n-\t\tif (!priv-\u003etx_init) {\n-\t\t\tn \u003d deflateInit2(\u0026priv-\u003etx, priv-\u003eargs[PMD_COMP_LEVEL],\n-\t\t\t\t\t Z_DEFLATED,\n-\t\t\t\t\t -priv-\u003eargs[PMD_SERVER_MAX_WINDOW_BITS +\n-\t\t\t\t\t\t (wsi-\u003evhost-\u003elisten_port \u003c\u003d 0)],\n-\t\t\t\t\t priv-\u003eargs[PMD_MEM_LEVEL],\n-\t\t\t\t\t Z_DEFAULT_STRATEGY);\n-\t\t\tif (n !\u003d Z_OK) {\n-\t\t\t\tlwsl_ext(\u0022inflateInit2 failed %d\u005cn\u0022, n);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t}\n-\t\tpriv-\u003etx_init \u003d 1;\n-\t\tif (!priv-\u003ebuf_tx_deflated)\n-\t\t\tpriv-\u003ebuf_tx_deflated \u003d lws_malloc(LWS_PRE + 7 + 5 +\n-\t\t\t\t\t (1 \u003c\u003c priv-\u003eargs[PMD_TX_BUF_PWR2]), \u0022pmd tx deflate buf\u0022);\n-\t\tif (!priv-\u003ebuf_tx_deflated) {\n-\t\t\tlwsl_err(\u0022%s: OOM\u005cn\u0022, __func__);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tif (eff_buf-\u003etoken) {\n-\t\t\tlwsl_ext(\u0022%s: TX: eff_buf length %d\u005cn\u0022, __func__,\n-\t\t\t\t eff_buf-\u003etoken_len);\n-\t\t\tpriv-\u003etx.next_in \u003d (unsigned char *)eff_buf-\u003etoken;\n-\t\t\tpriv-\u003etx.avail_in \u003d eff_buf-\u003etoken_len;\n-\t\t}\n-\n-#if 0\n-\t\tfor (n \u003d 0; n \u003c eff_buf-\u003etoken_len; n++) {\n-\t\t\tprintf(\u0022%02X \u0022, (unsigned char)eff_buf-\u003etoken[n]);\n-\t\t\tif ((n \u0026 15) \u003d\u003d 15)\n-\t\t\t\tprintf(\u0022\u005cn\u0022);\n-\t\t}\n-\t\tprintf(\u0022\u005cn\u0022);\n-#endif\n-\n-\t\tpriv-\u003etx.next_out \u003d priv-\u003ebuf_tx_deflated + LWS_PRE + 5;\n-\t\teff_buf-\u003etoken \u003d (char *)priv-\u003etx.next_out;\n-\t\tpriv-\u003etx.avail_out \u003d 1 \u003c\u003c priv-\u003eargs[PMD_TX_BUF_PWR2];\n-\n-\t\tn \u003d deflate(\u0026priv-\u003etx, Z_SYNC_FLUSH);\n-\t\tif (n \u003d\u003d Z_STREAM_ERROR) {\n-\t\t\tlwsl_ext(\u0022%s: Z_STREAM_ERROR\u005cn\u0022, __func__);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tif (priv-\u003etx_held_valid) {\n-\t\t\tpriv-\u003etx_held_valid \u003d 0;\n-\t\t\tif (priv-\u003etx.avail_out \u003d\u003d 1 \u003c\u003c priv-\u003eargs[PMD_TX_BUF_PWR2])\n-\t\t\t\t/*\n-\t\t\t\t * we can get a situation he took something in\n-\t\t\t\t * but did not generate anything out, at the end\n-\t\t\t\t * of a message (eg, next thing he sends is 80\n-\t\t\t\t * 00, a zero length FIN, like Authobahn can\n-\t\t\t\t * send).\n-\t\t\t\t * If we have come back as a FIN, we must not\n-\t\t\t\t * place the pending trailer 00 00 FF FF, just\n-\t\t\t\t * the 1 byte of live data\n-\t\t\t\t */\n-\t\t\t\t*(--eff_buf-\u003etoken) \u003d priv-\u003etx_held[0];\n-\t\t\telse {\n-\t\t\t\t/* he generated data, prepend whole pending */\n-\t\t\t\teff_buf-\u003etoken -\u003d 5;\n-\t\t\t\tfor (n \u003d 0; n \u003c 5; n++)\n-\t\t\t\t\teff_buf-\u003etoken[n] \u003d priv-\u003etx_held[n];\n-\n-\t\t\t}\n-\t\t}\n-\t\tpriv-\u003ecompressed_out \u003d 1;\n-\t\teff_buf-\u003etoken_len \u003d (int)(priv-\u003etx.next_out -\n-\t\t\t\t\t (unsigned char *)eff_buf-\u003etoken);\n-\n-\t\t/*\n-\t\t * we must announce in our returncode now if there is more\n-\t\t * output to be expected from inflate, so we can decide to\n-\t\t * set the FIN bit on this bufferload or not. However zlib\n-\t\t * is ambiguous when we exactly filled the inflate buffer. It\n-\t\t * does not give us a clue as to whether we should understand\n-\t\t * that to mean he ended on a buffer boundary, or if there is\n-\t\t * more in the pipeline.\n-\t\t *\n-\t\t * Worse, the guy providing the stuff we are sending may not\n-\t\t * know until after that this was, actually, the last chunk,\n-\t\t * that can happen even if we did not fill the output buf, ie\n-\t\t * he may send after this a zero-length FIN fragment.\n-\t\t *\n-\t\t * This is super difficult because we must snip the last 4\n-\t\t * bytes in the case this is the last compressed output of the\n-\t\t * message. The only way to deal with it is defer sending the\n-\t\t * last 5 bytes of each frame until the next one, when we will\n-\t\t * be in a position to understand if that has a FIN or not.\n-\t\t */\n-\n-\t\textra \u003d !!(len \u0026 LWS_WRITE_NO_FIN) || !priv-\u003etx.avail_out;\n-\n-\t\tif (eff_buf-\u003etoken_len \u003e\u003d 4 + extra) {\n-\t\t\tlwsl_ext(\u0022tx held %d\u005cn\u0022, 4 + extra);\n-\t\t\tpriv-\u003etx_held_valid \u003d extra;\n-\t\t\tfor (n \u003d 3 + extra; n \u003e\u003d 0; n--)\n-\t\t\t\tpriv-\u003etx_held[n] \u003d *(--priv-\u003etx.next_out);\n-\t\t\teff_buf-\u003etoken_len -\u003d 4 + extra;\n-\t\t}\n-\t\tlwsl_ext(\u0022 TX rewritten with new effbuff len %d, ret %d\u005cn\u0022,\n-\t\t\t eff_buf-\u003etoken_len, !priv-\u003etx.avail_out);\n-\n-\t\treturn !priv-\u003etx.avail_out; /* 1 \u003d\u003d have more tx pending */\n-\n-\tcase LWS_EXT_CB_PACKET_TX_PRESEND:\n-\t\tif (!priv-\u003ecompressed_out)\n-\t\t\tbreak;\n-\t\tpriv-\u003ecompressed_out \u003d 0;\n-\n-\t\tif ((*(eff_buf-\u003etoken) \u0026 0x80) \u0026\u0026\n-\t\t priv-\u003eargs[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {\n-\t\t\tlwsl_debug(\u0022PMD_CLIENT_NO_CONTEXT_TAKEOVER\u005cn\u0022);\n-\t\t\t(void)deflateEnd(\u0026priv-\u003etx);\n-\t\t\tpriv-\u003etx_init \u003d 0;\n-\t\t}\n-\n-\t\tn \u003d *(eff_buf-\u003etoken) \u0026 15;\n-\t\t/* set RSV1, but not on CONTINUATION */\n-\t\tif (n \u003d\u003d LWSWSOPC_TEXT_FRAME || n \u003d\u003d LWSWSOPC_BINARY_FRAME)\n-\t\t\t*eff_buf-\u003etoken |\u003d 0x40;\n-#if 0\n-\t\tfor (n \u003d 0; n \u003c eff_buf-\u003etoken_len; n++) {\n-\t\t\tprintf(\u0022%02X \u0022, (unsigned char)eff_buf-\u003etoken[n]);\n-\t\t\tif ((n \u0026 15) \u003d\u003d 15)\n-\t\t\t\tputs(\u0022\u005cn\u0022);\n-\t\t}\n-\t\tputs(\u0022\u005cn\u0022);\n-#endif\n-\t\tlwsl_ext(\u0022%s: tx opcode 0x%02X\u005cn\u0022, __func__,\n-\t\t\t (unsigned char)*eff_buf-\u003etoken);\n-\t\tbreak;\n-\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-}\n-\ndiff --git a/lib/extension-permessage-deflate.h b/lib/extension-permessage-deflate.h\ndeleted file mode 100644\nindex 8737736..0000000\n--- a/lib/extension-permessage-deflate.h\n+++ /dev/null\n@@ -1,41 +0,0 @@\n-\n-#include \u003czlib.h\u003e\n-\n-#define DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER 1\n-#define DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT Z_DEFAULT_COMPRESSION\n-\n-enum arg_indexes {\n-\tPMD_SERVER_NO_CONTEXT_TAKEOVER,\n-\tPMD_CLIENT_NO_CONTEXT_TAKEOVER,\n-\tPMD_SERVER_MAX_WINDOW_BITS,\n-\tPMD_CLIENT_MAX_WINDOW_BITS,\n-\tPMD_RX_BUF_PWR2,\n-\tPMD_TX_BUF_PWR2,\n-\tPMD_COMP_LEVEL,\n-\tPMD_MEM_LEVEL,\n-\n-\tPMD_ARG_COUNT\n-};\n-\n-struct lws_ext_pm_deflate_priv {\n-\tz_stream rx;\n-\tz_stream tx;\n-\n-\tunsigned char *buf_rx_inflated; /* RX inflated output buffer */\n-\tunsigned char *buf_tx_deflated; /* TX deflated output buffer */\n-\n-\tsize_t count_rx_between_fin;\n-\n-\tunsigned char args[PMD_ARG_COUNT];\n-\tunsigned char tx_held[5];\n-\tunsigned char rx_held;\n-\n-\tunsigned char tx_init:1;\n-\tunsigned char rx_init:1;\n-\tunsigned char compressed_out:1;\n-\tunsigned char rx_held_valid:1;\n-\tunsigned char tx_held_valid:1;\n-\tunsigned char rx_append_trailer:1;\n-\tunsigned char pending_tx_trailer:1;\n-};\n-\ndiff --git a/lib/extension.c b/lib/extension.c\ndeleted file mode 100644\nindex ac28204..0000000\n--- a/lib/extension.c\n+++ /dev/null\n@@ -1,344 +0,0 @@\n-#include \u0022private-libwebsockets.h\u0022\n-\n-#include \u0022extension-permessage-deflate.h\u0022\n-\n-LWS_VISIBLE void\n-lws_context_init_extensions(struct lws_context_creation_info *info,\n-\t\t\t struct lws_context *context)\n-{\n-\tlwsl_info(\u0022 LWS_MAX_EXTENSIONS_ACTIVE: %u\u005cn\u0022, LWS_MAX_EXTENSIONS_ACTIVE);\n-}\n-\n-enum lws_ext_option_parser_states {\n-\tLEAPS_SEEK_NAME,\n-\tLEAPS_EAT_NAME,\n-\tLEAPS_SEEK_VAL,\n-\tLEAPS_EAT_DEC,\n-\tLEAPS_SEEK_ARG_TERM\n-};\n-\n-LWS_VISIBLE int\n-lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,\n-\t\t void *ext_user, const struct lws_ext_options *opts,\n-\t\t const char *in, int len)\n-{\n-\tenum lws_ext_option_parser_states leap \u003d LEAPS_SEEK_NAME;\n-\tunsigned int match_map \u003d 0, n, m, w \u003d 0, count_options \u003d 0,\n-\t\t pending_close_quote \u003d 0;\n-\tstruct lws_ext_option_arg oa;\n-\n-\toa.option_name \u003d NULL;\n-\n-\twhile (opts[count_options].name)\n-\t\tcount_options++;\n-\twhile (len) {\n-\t\tlwsl_ext(\u0022'%c' %d\u0022, *in, leap);\n-\t\tswitch (leap) {\n-\t\tcase LEAPS_SEEK_NAME:\n-\t\t\tif (*in \u003d\u003d ' ')\n-\t\t\t\tbreak;\n-\t\t\tif (*in \u003d\u003d ',') {\n-\t\t\t\tlen \u003d 1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tmatch_map \u003d (1 \u003c\u003c count_options) - 1;\n-\t\t\tleap \u003d LEAPS_EAT_NAME;\n-\t\t\tw \u003d 0;\n-\n-\t\t/* fallthru */\n-\n-\t\tcase LEAPS_EAT_NAME:\n-\t\t\toa.start \u003d NULL;\n-\t\t\toa.len \u003d 0;\n-\t\t\tm \u003d match_map;\n-\t\t\tn \u003d 0;\n-\t\t\tpending_close_quote \u003d 0;\n-\t\t\twhile (m) {\n-\t\t\t\tif (m \u0026 1) {\n-\t\t\t\t\tlwsl_ext(\u0022 m\u003d%d, n\u003d%d, w\u003d%d\u005cn\u0022, m, n, w);\n-\n-\t\t\t\t\tif (*in \u003d\u003d opts[n].name[w]) {\n-\t\t\t\t\t\tif (!opts[n].name[w + 1]) {\n-\t\t\t\t\t\t\toa.option_index \u003d n;\n-\t\t\t\t\t\t\tlwsl_ext(\u0022hit %d\u005cn\u0022, oa.option_index);\n-\t\t\t\t\t\t\tleap \u003d LEAPS_SEEK_VAL;\n-\t\t\t\t\t\t\tif (len \u003d\u003d 1)\n-\t\t\t\t\t\t\t\tgoto set_arg;\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\t}\n-\t\t\t\t\t} else {\n-\t\t\t\t\t\tmatch_map \u0026\u003d ~(1 \u003c\u003c n);\n-\t\t\t\t\t\tif (!match_map) {\n-\t\t\t\t\t\t\tlwsl_ext(\u0022empty match map\u005cn\u0022);\n-\t\t\t\t\t\t\treturn -1;\n-\t\t\t\t\t\t}\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\tm \u003e\u003e\u003d 1;\n-\t\t\t\tn++;\n-\t\t\t}\n-\t\t\tw++;\n-\t\t\tbreak;\n-\t\tcase LEAPS_SEEK_VAL:\n-\t\t\tif (*in \u003d\u003d ' ')\n-\t\t\t\tbreak;\n-\t\t\tif (*in \u003d\u003d ',') {\n-\t\t\t\tlen \u003d 1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (*in \u003d\u003d ';' || len \u003d\u003d 1) { /* ie,nonoptional */\n-\t\t\t\tif (opts[oa.option_index].type \u003d\u003d EXTARG_DEC)\n-\t\t\t\t\treturn -1;\n-\t\t\t\tleap \u003d LEAPS_SEEK_NAME;\n-\t\t\t\tgoto set_arg;\n-\t\t\t}\n-\t\t\tif (*in \u003d\u003d '\u003d') {\n-\t\t\t\tw \u003d 0;\n-\t\t\t\tpending_close_quote \u003d 0;\n-\t\t\t\tif (opts[oa.option_index].type \u003d\u003d EXTARG_NONE)\n-\t\t\t\t\treturn -1;\n-\n-\t\t\t\tleap \u003d LEAPS_EAT_DEC;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\treturn -1;\n-\n-\t\tcase LEAPS_EAT_DEC:\n-\t\t\tif (*in \u003e\u003d '0' \u0026\u0026 *in \u003c\u003d '9') {\n-\t\t\t\tif (!w)\n-\t\t\t\t\toa.start \u003d in;\n-\t\t\t\tw++;\n-\t\t\t\tif (len !\u003d 1)\n-\t\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (!w \u0026\u0026 *in \u003d\u003d'\u0022') {\n-\t\t\t\tpending_close_quote \u003d 1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (!w)\n-\t\t\t\treturn -1;\n-\t\t\tif (pending_close_quote \u0026\u0026 *in !\u003d '\u0022' \u0026\u0026 len !\u003d 1)\n-\t\t\t\treturn -1;\n-\t\t\tleap \u003d LEAPS_SEEK_ARG_TERM;\n-\t\t\tif (oa.start)\n-\t\t\t\toa.len \u003d in - oa.start;\n-\t\t\tif (len \u003d\u003d 1)\n-\t\t\t\toa.len++;\n-\n-set_arg:\n-\t\t\text-\u003ecallback(lws_get_context(wsi),\n-\t\t\t\text, wsi, LWS_EXT_CB_OPTION_SET,\n-\t\t\t\text_user, (char *)\u0026oa, 0);\n-\t\t\tif (len \u003d\u003d 1)\n-\t\t\t\tbreak;\n-\t\t\tif (pending_close_quote \u0026\u0026 *in \u003d\u003d '\u0022')\n-\t\t\t\tbreak;\n-\n-\t\t\t/* fallthru */\n-\n-\t\tcase LEAPS_SEEK_ARG_TERM:\n-\t\t\tif (*in \u003d\u003d ' ')\n-\t\t\t\tbreak;\n-\t\t\tif (*in \u003d\u003d ';') {\n-\t\t\t\tleap \u003d LEAPS_SEEK_NAME;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (*in \u003d\u003d ',') {\n-\t\t\t\tlen \u003d 1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\treturn -1;\n-\t\t}\n-\t\tlen--;\n-\t\tin++;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-\n-/* 0 \u003d nobody had nonzero return, 1 \u003d somebody had positive return, -1 \u003d fail */\n-\n-int lws_ext_cb_active(struct lws *wsi, int reason, void *arg, int len)\n-{\n-\tint n, m, handled \u003d 0;\n-\n-\tfor (n \u003d 0; n \u003c wsi-\u003ecount_act_ext; n++) {\n-\t\tm \u003d wsi-\u003eactive_extensions[n]-\u003ecallback(lws_get_context(wsi),\n-\t\t\twsi-\u003eactive_extensions[n], wsi, reason,\n-\t\t\twsi-\u003eact_ext_user[n], arg, len);\n-\t\tif (m \u003c 0) {\n-\t\t\tlwsl_ext(\u0022Ext '%s' failed to handle callback %d!\u005cn\u0022,\n-\t\t\t\t wsi-\u003eactive_extensions[n]-\u003ename, reason);\n-\t\t\treturn -1;\n-\t\t}\n-\t\t/* valgrind... */\n-\t\tif (reason \u003d\u003d LWS_EXT_CB_DESTROY)\n-\t\t\twsi-\u003eact_ext_user[n] \u003d NULL;\n-\t\tif (m \u003e handled)\n-\t\t\thandled \u003d m;\n-\t}\n-\n-\treturn handled;\n-}\n-\n-int lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi,\n-\t\t\tint reason, void *arg, int len)\n-{\n-\tint n \u003d 0, m, handled \u003d 0;\n-\tconst struct lws_extension *ext;\n-\n-\tif (!wsi || !wsi-\u003evhost)\n-\t\treturn 0;\n-\n-\text \u003d wsi-\u003evhost-\u003eextensions;\n-\n-\twhile (ext \u0026\u0026 ext-\u003ecallback \u0026\u0026 !handled) {\n-\t\tm \u003d ext-\u003ecallback(context, ext, wsi, reason,\n-\t\t\t\t (void *)(lws_intptr_t)n, arg, len);\n-\t\tif (m \u003c 0) {\n-\t\t\tlwsl_ext(\u0022Ext '%s' failed to handle callback %d!\u005cn\u0022,\n-\t\t\t\t wsi-\u003eactive_extensions[n]-\u003ename, reason);\n-\t\t\treturn -1;\n-\t\t}\n-\t\tif (m)\n-\t\t\thandled \u003d 1;\n-\n-\t\text++;\n-\t\tn++;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-int\n-lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len)\n-{\n-\tstruct lws_tokens eff_buf;\n-\tint ret, m, n \u003d 0;\n-\n-\teff_buf.token \u003d (char *)buf;\n-\teff_buf.token_len \u003d len;\n-\n-\t/*\n-\t * while we have original buf to spill ourselves, or extensions report\n-\t * more in their pipeline\n-\t */\n-\n-\tret \u003d 1;\n-\twhile (ret \u003d\u003d 1) {\n-\n-\t\t/* default to nobody has more to spill */\n-\n-\t\tret \u003d 0;\n-\n-\t\t/* show every extension the new incoming data */\n-\t\tm \u003d lws_ext_cb_active(wsi,\n-\t\t\t LWS_EXT_CB_PACKET_TX_PRESEND, \u0026eff_buf, 0);\n-\t\tif (m \u003c 0)\n-\t\t\treturn -1;\n-\t\tif (m) /* handled */\n-\t\t\tret \u003d 1;\n-\n-\t\tif ((char *)buf !\u003d eff_buf.token)\n-\t\t\t/*\n-\t\t\t * extension recreated it:\n-\t\t\t * need to buffer this if not all sent\n-\t\t\t */\n-\t\t\twsi-\u003eu.ws.clean_buffer \u003d 0;\n-\n-\t\t/* assuming they left us something to send, send it */\n-\n-\t\tif (eff_buf.token_len) {\n-\t\t\tn \u003d lws_issue_raw(wsi, (unsigned char *)eff_buf.token,\n-\t\t\t\t\t\t\t eff_buf.token_len);\n-\t\t\tif (n \u003c 0) {\n-\t\t\t\tlwsl_info(\u0022closing from ext access\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t\t/* always either sent it all or privately buffered */\n-\t\t\tif (wsi-\u003eu.ws.clean_buffer)\n-\t\t\t\tlen \u003d n;\n-\t\t}\n-\n-\t\tlwsl_parser(\u0022written %d bytes to client\u005cn\u0022, n);\n-\n-\t\t/* no extension has more to spill? Then we can go */\n-\n-\t\tif (!ret)\n-\t\t\tbreak;\n-\n-\t\t/* we used up what we had */\n-\n-\t\teff_buf.token \u003d NULL;\n-\t\teff_buf.token_len \u003d 0;\n-\n-\t\t/*\n-\t\t * Did that leave the pipe choked?\n-\t\t * Or we had to hold on to some of it?\n-\t\t */\n-\n-\t\tif (!lws_send_pipe_choked(wsi) \u0026\u0026 !wsi-\u003etrunc_len)\n-\t\t\t/* no we could add more, lets's do that */\n-\t\t\tcontinue;\n-\n-\t\tlwsl_debug(\u0022choked\u005cn\u0022);\n-\n-\t\t/*\n-\t\t * Yes, he's choked. Don't spill the rest now get a callback\n-\t\t * when he is ready to send and take care of it there\n-\t\t */\n-\t\tlws_callback_on_writable(wsi);\n-\t\twsi-\u003eextension_data_pending \u003d 1;\n-\t\tret \u003d 0;\n-\t}\n-\n-\treturn len;\n-}\n-\n-int\n-lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r,\n-\t\t\t void *v, size_t len)\n-{\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tint n, handled \u003d 0;\n-\n-\t/* maybe an extension will take care of it for us */\n-\n-\tfor (n \u003d 0; n \u003c wsi-\u003ecount_act_ext \u0026\u0026 !handled; n++) {\n-\t\tif (!wsi-\u003eactive_extensions[n]-\u003ecallback)\n-\t\t\tcontinue;\n-\n-\t\thandled |\u003d wsi-\u003eactive_extensions[n]-\u003ecallback(context,\n-\t\t\twsi-\u003eactive_extensions[n], wsi,\n-\t\t\tr, wsi-\u003eact_ext_user[n], v, len);\n-\t}\n-\n-\treturn handled;\n-}\n-\n-int\n-lws_set_extension_option(struct lws *wsi, const char *ext_name,\n-\t\t\t const char *opt_name, const char *opt_val)\n-{\n-\tstruct lws_ext_option_arg oa;\n-\tint idx \u003d 0;\n-\n-\t/* first identify if the ext is active on this wsi */\n-\twhile (idx \u003c wsi-\u003ecount_act_ext \u0026\u0026\n-\t strcmp(wsi-\u003eactive_extensions[idx]-\u003ename, ext_name))\n-\t\tidx++;\n-\n-\tif (idx \u003d\u003d wsi-\u003ecount_act_ext)\n-\t\treturn -1; /* request ext not active on this wsi */\n-\n-\toa.option_name \u003d opt_name;\n-\toa.option_index \u003d 0;\n-\toa.start \u003d opt_val;\n-\toa.len \u003d 0;\n-\n-\treturn wsi-\u003eactive_extensions[idx]-\u003ecallback(\n-\t\t\twsi-\u003econtext, wsi-\u003eactive_extensions[idx], wsi,\n-\t\t\tLWS_EXT_CB_NAMED_OPTION_SET, wsi-\u003eact_ext_user[idx], \u0026oa, 0);\n-}\ndiff --git a/lib/fops-zip.c b/lib/fops-zip.c\ndeleted file mode 100644\nindex 2b254f6..0000000\n--- a/lib/fops-zip.c\n+++ /dev/null\n@@ -1,669 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Original code used in this source file:\n- *\n- * https://github.com/PerBothner/DomTerm.git @912add15f3d0aec\n- *\n- * ./lws-term/io.c\n- * ./lws-term/junzip.c\n- *\n- * Copyright (C) 2017 Per Bothner \u003cper@bothner.com\u003e\n- *\n- * MIT License\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 deal\n- * in the Software without restriction, including without limitation the rights\n- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n- * ( 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 FROM,\n- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n- * SOFTWARE.\n- *\n- *\n- * lws rewrite:\n- *\n- * Copyright (C) 2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-#include \u003czlib.h\u003e\n-\n-/*\n- * This code works with zip format containers which may have files compressed\n- * with gzip deflate (type 8) or store uncompressed (type 0).\n- *\n- * Linux zip produces such zipfiles by default, eg\n- *\n- * $ zip ../myzip.zip file1 file2 file3\n- */\n-\n-#define ZIP_COMPRESSION_METHOD_STORE 0\n-#define ZIP_COMPRESSION_METHOD_DEFLATE 8\n-\n-typedef struct {\n-\tlws_filepos_t\t\tfilename_start;\n-\tuint32_t\t\tcrc32;\n-\tuint32_t\t\tcomp_size;\n-\tuint32_t\t\tuncomp_size;\n-\tuint32_t\t\toffset;\n-\tuint32_t\t\tmod_time;\n-\tuint16_t\t\tfilename_len;\n-\tuint16_t\t\textra;\n-\tuint16_t\t\tmethod;\n-\tuint16_t\t\tfile_com_len;\n-} lws_fops_zip_hdr_t;\n-\n-typedef struct {\n-\tstruct lws_fop_fd\tfop_fd; /* MUST BE FIRST logical fop_fd into\n-\t \t \t \t \t * file inside zip: fops_zip fops */\n-\tlws_fop_fd_t\t\tzip_fop_fd; /* logical fop fd on to zip file\n-\t \t \t \t \t * itself: using platform fops */\n-\tlws_fops_zip_hdr_t\thdr;\n-\tz_stream\t\tinflate;\n-\tlws_filepos_t\t\tcontent_start;\n-\tlws_filepos_t\t\texp_uncomp_pos;\n-\tunion {\n-\t\tuint8_t\t\ttrailer8[8];\n-\t\tuint32_t\ttrailer32[2];\n-\t} u;\n-\tuint8_t\t\t\trbuf[128]; /* decompression chunk size */\n-\tint\t\t\tentry_count;\n-\n-\tunsigned int\t\tdecompress:1; /* 0 \u003d direct from file */\n-\tunsigned int\t\tadd_gzip_container:1;\n-} *lws_fops_zip_t;\n-\n-struct lws_plat_file_ops fops_zip;\n-#define fop_fd_to_priv(FD) ((lws_fops_zip_t)(FD))\n-\n-static const uint8_t hd[] \u003d { 31, 139, 8, 0, 0, 0, 0, 0, 0, 3 };\n-\n-enum {\n-\tZC_SIGNATURE\t\t\t\t\u003d 0,\n-\tZC_VERSION_MADE_BY \t\t\t\u003d 4,\n-\tZC_VERSION_NEEDED_TO_EXTRACT \t\t\u003d 6,\n-\tZC_GENERAL_PURPOSE_BIT_FLAG \t\t\u003d 8,\n-\tZC_COMPRESSION_METHOD \t\t\t\u003d 10,\n-\tZC_LAST_MOD_FILE_TIME \t\t\t\u003d 12,\n-\tZC_LAST_MOD_FILE_DATE \t\t\t\u003d 14,\n-\tZC_CRC32 \t\t\t\t\u003d 16,\n-\tZC_COMPRESSED_SIZE \t\t\t\u003d 20,\n-\tZC_UNCOMPRESSED_SIZE \t\t\t\u003d 24,\n-\tZC_FILE_NAME_LENGTH \t\t\t\u003d 28,\n-\tZC_EXTRA_FIELD_LENGTH \t\t\t\u003d 30,\n-\n-\tZC_FILE_COMMENT_LENGTH \t\t\t\u003d 32,\n-\tZC_DISK_NUMBER_START \t\t\t\u003d 34,\n-\tZC_INTERNAL_FILE_ATTRIBUTES \t\t\u003d 36,\n-\tZC_EXTERNAL_FILE_ATTRIBUTES \t\t\u003d 38,\n-\tZC_REL_OFFSET_LOCAL_HEADER \t\t\u003d 42,\n-\tZC_DIRECTORY_LENGTH \t\t\t\u003d 46,\n-\n-\tZE_SIGNATURE_OFFSET \t\t\t\u003d 0,\n-\tZE_DESK_NUMBER \t\t\t\t\u003d 4,\n-\tZE_CENTRAL_DIRECTORY_DISK_NUMBER \t\u003d 6,\n-\tZE_NUM_ENTRIES_THIS_DISK \t\t\u003d 8,\n-\tZE_NUM_ENTRIES \t\t\t\t\u003d 10,\n-\tZE_CENTRAL_DIRECTORY_SIZE \t\t\u003d 12,\n-\tZE_CENTRAL_DIR_OFFSET \t\t\t\u003d 16,\n-\tZE_ZIP_COMMENT_LENGTH \t\t\t\u003d 20,\n-\tZE_DIRECTORY_LENGTH \t\t\t\u003d 22,\n-\n-\tZL_REL_OFFSET_CONTENT\t\t\t\u003d 28,\n-\tZL_HEADER_LENGTH\t\t\t\u003d 30,\n-\n-\tLWS_FZ_ERR_SEEK_END_RECORD\t\t\u003d 1,\n-\tLWS_FZ_ERR_READ_END_RECORD,\n-\tLWS_FZ_ERR_END_RECORD_MAGIC,\n-\tLWS_FZ_ERR_END_RECORD_SANITY,\n-\tLWS_FZ_ERR_CENTRAL_SEEK,\n-\tLWS_FZ_ERR_CENTRAL_READ,\n-\tLWS_FZ_ERR_CENTRAL_SANITY,\n-\tLWS_FZ_ERR_NAME_TOO_LONG,\n-\tLWS_FZ_ERR_NAME_SEEK,\n-\tLWS_FZ_ERR_NAME_READ,\n-\tLWS_FZ_ERR_CONTENT_SANITY,\n-\tLWS_FZ_ERR_CONTENT_SEEK,\n-\tLWS_FZ_ERR_SCAN_SEEK,\n-\tLWS_FZ_ERR_NOT_FOUND,\n-\tLWS_FZ_ERR_ZLIB_INIT,\n-\tLWS_FZ_ERR_READ_CONTENT,\n-\tLWS_FZ_ERR_SEEK_COMPRESSED,\n-};\n-\n-static uint16_t\n-get_u16(void *p)\n-{\n-\tconst uint8_t *c \u003d (const uint8_t *)p;\n-\n-\treturn (uint16_t)((c[0] | (c[1] \u003c\u003c 8)));\n-}\n-\n-static uint32_t\n-get_u32(void *p)\n-{\n-\tconst uint8_t *c \u003d (const uint8_t *)p;\n-\n-\treturn (uint32_t)((c[0] | (c[1] \u003c\u003c 8) | (c[2] \u003c\u003c 16) | (c[3] \u003c\u003c 24)));\n-}\n-\n-int\n-lws_fops_zip_scan(lws_fops_zip_t priv, const char *name, int len)\n-{\n-\tlws_filepos_t amount;\n-\tuint8_t buf[96];\n-\tint i;\n-\n-\tif (lws_vfs_file_seek_end(priv-\u003ezip_fop_fd, -ZE_DIRECTORY_LENGTH) \u003c 0)\n-\t\treturn LWS_FZ_ERR_SEEK_END_RECORD;\n-\n-\tif (lws_vfs_file_read(priv-\u003ezip_fop_fd, \u0026amount, buf,\n-\t\t\t ZE_DIRECTORY_LENGTH))\n-\t\treturn LWS_FZ_ERR_READ_END_RECORD;\n-\n-\tif (amount !\u003d ZE_DIRECTORY_LENGTH)\n-\t\treturn LWS_FZ_ERR_READ_END_RECORD;\n-\n-\t/*\n-\t * We require the zip to have the last record right at the end\n-\t * Linux zip always does this if no zip comment.\n-\t */\n-\tif (buf[0] !\u003d 'P' || buf[1] !\u003d 'K' || buf[2] !\u003d 5 || buf[3] !\u003d 6)\n-\t\treturn LWS_FZ_ERR_END_RECORD_MAGIC;\n-\n-\ti \u003d get_u16(buf + ZE_NUM_ENTRIES);\n-\n-\tif (get_u16(buf + ZE_DESK_NUMBER) ||\n-\t get_u16(buf + ZE_CENTRAL_DIRECTORY_DISK_NUMBER) ||\n-\t i !\u003d get_u16(buf + ZE_NUM_ENTRIES_THIS_DISK))\n-\t\treturn LWS_FZ_ERR_END_RECORD_SANITY;\n-\n-\t/* end record is OK... look for our file in the central dir */\n-\n-\tif (lws_vfs_file_seek_set(priv-\u003ezip_fop_fd,\n-\t\t\t\t get_u32(buf + ZE_CENTRAL_DIR_OFFSET)) \u003c 0)\n-\t\treturn LWS_FZ_ERR_CENTRAL_SEEK;\n-\n-\twhile (i--) {\n-\t\tpriv-\u003econtent_start \u003d lws_vfs_tell(priv-\u003ezip_fop_fd);\n-\n-\t\tif (lws_vfs_file_read(priv-\u003ezip_fop_fd, \u0026amount, buf,\n-\t\t\t\t ZC_DIRECTORY_LENGTH))\n-\t\t\treturn LWS_FZ_ERR_CENTRAL_READ;\n-\n-\t\tif (amount !\u003d ZC_DIRECTORY_LENGTH)\n-\t\t\treturn LWS_FZ_ERR_CENTRAL_READ;\n-\n-\t\tif (get_u32(buf + ZC_SIGNATURE) !\u003d 0x02014B50)\n-\t\t\treturn LWS_FZ_ERR_CENTRAL_SANITY;\n-\n- lwsl_debug(\u0022cstart 0x%lx\u005cn\u0022, (unsigned long)priv-\u003econtent_start);\n-\n-\t\tpriv-\u003ehdr.filename_len \u003d get_u16(buf + ZC_FILE_NAME_LENGTH);\n-\t\tpriv-\u003ehdr.extra \u003d get_u16(buf + ZC_EXTRA_FIELD_LENGTH);\n-\t\tpriv-\u003ehdr.filename_start \u003d lws_vfs_tell(priv-\u003ezip_fop_fd);\n-\n-\t\tpriv-\u003ehdr.method \u003d get_u16(buf + ZC_COMPRESSION_METHOD);\n-\t\tpriv-\u003ehdr.crc32 \u003d get_u32(buf + ZC_CRC32);\n-\t\tpriv-\u003ehdr.comp_size \u003d get_u32(buf + ZC_COMPRESSED_SIZE);\n-\t\tpriv-\u003ehdr.uncomp_size \u003d get_u32(buf + ZC_UNCOMPRESSED_SIZE);\n-\t\tpriv-\u003ehdr.offset \u003d get_u32(buf + ZC_REL_OFFSET_LOCAL_HEADER);\n-\t\tpriv-\u003ehdr.mod_time \u003d get_u32(buf + ZC_LAST_MOD_FILE_TIME);\n-\t\tpriv-\u003ehdr.file_com_len \u003d get_u16(buf + ZC_FILE_COMMENT_LENGTH);\n-\n-\t\tif (priv-\u003ehdr.filename_len !\u003d len)\n-\t\t\tgoto next;\n-\n-\t\tif (len \u003e\u003d sizeof(buf) - 1)\n-\t\t\treturn LWS_FZ_ERR_NAME_TOO_LONG;\n-\n-\t\tif (priv-\u003ezip_fop_fd-\u003efops-\u003eLWS_FOP_READ(priv-\u003ezip_fop_fd,\n-\t\t\t\t\t\t\t\u0026amount, buf, len))\n-\t\t\treturn LWS_FZ_ERR_NAME_READ;\n-\t\tif (amount !\u003d len)\n-\t\t\treturn LWS_FZ_ERR_NAME_READ;\n-\n-\t\tbuf[len] \u003d '\u005c0';\n-\t\tlwsl_debug(\u0022check %s vs %s\u005cn\u0022, buf, name);\n-\n-\t\tif (strcmp((const char *)buf, name))\n-\t\t\tgoto next;\n-\n-\t\t/* we found a match */\n-\t\tif (lws_vfs_file_seek_set(priv-\u003ezip_fop_fd, priv-\u003ehdr.offset) \u003c 0)\n-\t\t\treturn LWS_FZ_ERR_NAME_SEEK;\n-\t\tif (priv-\u003ezip_fop_fd-\u003efops-\u003eLWS_FOP_READ(priv-\u003ezip_fop_fd,\n-\t\t\t\t\t\t\t\u0026amount, buf,\n-\t\t\t\t\t\t\tZL_HEADER_LENGTH))\n-\t\t\treturn LWS_FZ_ERR_NAME_READ;\n-\t\tif (amount !\u003d ZL_HEADER_LENGTH)\n-\t\t\treturn LWS_FZ_ERR_NAME_READ;\n-\n-\t\tpriv-\u003econtent_start \u003d priv-\u003ehdr.offset +\n-\t\t\t\t ZL_HEADER_LENGTH +\n-\t\t\t\t priv-\u003ehdr.filename_len +\n-\t\t\t\t get_u16(buf + ZL_REL_OFFSET_CONTENT);\n-\n-\t\tlwsl_debug(\u0022content supposed to start at 0x%lx\u005cn\u0022,\n- (unsigned long)priv-\u003econtent_start);\n-\n-\t\tif (priv-\u003econtent_start \u003e priv-\u003ezip_fop_fd-\u003elen)\n-\t\t\treturn LWS_FZ_ERR_CONTENT_SANITY;\n-\n-\t\tif (lws_vfs_file_seek_set(priv-\u003ezip_fop_fd,\n-\t\t\t\t\t priv-\u003econtent_start) \u003c 0)\n-\t\t\treturn LWS_FZ_ERR_CONTENT_SEEK;\n-\n-\t\t/* we are aligned at the start of the content */\n-\n-\t\tpriv-\u003eexp_uncomp_pos \u003d 0;\n-\n-\t\treturn 0;\n-\n-next:\n-\t\tif (i \u0026\u0026 lws_vfs_file_seek_set(priv-\u003ezip_fop_fd,\n-\t\t\t\t\t priv-\u003econtent_start +\n-\t\t\t\t\t ZC_DIRECTORY_LENGTH +\n-\t\t\t\t\t priv-\u003ehdr.filename_len +\n-\t\t\t\t\t priv-\u003ehdr.extra +\n-\t\t\t\t\t priv-\u003ehdr.file_com_len) \u003c 0)\n-\t\t\treturn LWS_FZ_ERR_SCAN_SEEK;\n-\t}\n-\n-\treturn LWS_FZ_ERR_NOT_FOUND;\n-}\n-\n-static int\n-lws_fops_zip_reset_inflate(lws_fops_zip_t priv)\n-{\n-\tif (priv-\u003edecompress)\n-\t\tinflateEnd(\u0026priv-\u003einflate);\n-\n-\tpriv-\u003einflate.zalloc \u003d Z_NULL;\n-\tpriv-\u003einflate.zfree \u003d Z_NULL;\n-\tpriv-\u003einflate.opaque \u003d Z_NULL;\n-\tpriv-\u003einflate.avail_in \u003d 0;\n-\tpriv-\u003einflate.next_in \u003d Z_NULL;\n-\n-\tif (inflateInit2(\u0026priv-\u003einflate, -MAX_WBITS) !\u003d Z_OK) {\n-\t\tlwsl_err(\u0022inflate init failed\u005cn\u0022);\n-\t\treturn LWS_FZ_ERR_ZLIB_INIT;\n-\t}\n-\n-\tif (lws_vfs_file_seek_set(priv-\u003ezip_fop_fd, priv-\u003econtent_start) \u003c 0)\n-\t\treturn LWS_FZ_ERR_CONTENT_SEEK;\n-\n-\tpriv-\u003eexp_uncomp_pos \u003d 0;\n-\n-\treturn 0;\n-}\n-\n-static lws_fop_fd_t\n-lws_fops_zip_open(const struct lws_plat_file_ops *fops, const char *vfs_path,\n-\t\t const char *vpath, lws_fop_flags_t *flags)\n-{\n-\tlws_fop_flags_t local_flags \u003d 0;\n-\tlws_fops_zip_t priv;\n-\tchar rp[192];\n-\tint m;\n-\n-\t/*\n-\t * vpath points at the / after the fops signature in vfs_path, eg\n-\t * with a vfs_path \u0022/var/www/docs/manual.zip/index.html\u0022, vpath\n-\t * will come pointing at \u0022/index.html\u0022\n-\t */\n-\n-\tpriv \u003d lws_zalloc(sizeof(*priv), \u0022fops_zip priv\u0022);\n-\tif (!priv)\n-\t\treturn NULL;\n-\n-\tpriv-\u003efop_fd.fops \u003d \u0026fops_zip;\n-\n-\tm \u003d sizeof(rp) - 1;\n-\tif ((vpath - vfs_path - 1) \u003c m)\n-\t\tm \u003d vpath - vfs_path - 1;\n-\tstrncpy(rp, vfs_path, m);\n-\trp[m] \u003d '\u005c0';\n-\n-\t/* open the zip file itself using the incoming fops, not fops_zip */\n-\n-\tpriv-\u003ezip_fop_fd \u003d fops-\u003eLWS_FOP_OPEN(fops, rp, NULL, \u0026local_flags);\n-\tif (!priv-\u003ezip_fop_fd) {\n-\t\tlwsl_err(\u0022unable to open zip %s\u005cn\u0022, rp);\n-\t\tgoto bail1;\n-\t}\n-\n-\tif (*vpath \u003d\u003d '/')\n-\t\tvpath++;\n-\n-\tm \u003d lws_fops_zip_scan(priv, vpath, strlen(vpath));\n-\tif (m) {\n-\t\tlwsl_err(\u0022unable to find record matching '%s' %d\u005cn\u0022, vpath, m);\n-\t\tgoto bail2;\n-\t}\n-\n-\t/* the directory metadata tells us modification time, so pass it on */\n-\tpriv-\u003efop_fd.mod_time \u003d priv-\u003ehdr.mod_time;\n-\t*flags |\u003d LWS_FOP_FLAG_MOD_TIME_VALID | LWS_FOP_FLAG_VIRTUAL;\n-\tpriv-\u003efop_fd.flags \u003d *flags;\n-\n-\t/* The zip fop_fd is left pointing at the start of the content.\n-\t *\n-\t * 1) Content could be uncompressed (STORE), and we can always serve\n-\t * that directly\n-\t *\n-\t * 2) Content could be compressed (GZIP), and the client can handle\n-\t * receiving GZIP... we can wrap it in a GZIP header and trailer\n-\t * and serve the content part directly. The flag indicating we\n-\t * are providing GZIP directly is set so lws will send the right\n-\t * headers.\n-\t *\n-\t * 3) Content could be compressed (GZIP) but the client can't handle\n-\t * receiving GZIP... we can decompress it and serve as it is\n-\t * inflated piecemeal.\n-\t *\n-\t * 4) Content may be compressed some unknown way... fail\n-\t *\n-\t */\n-\tif (priv-\u003ehdr.method \u003d\u003d ZIP_COMPRESSION_METHOD_STORE) {\n-\t\t/*\n-\t\t * it is stored uncompressed, leave it indicated as\n-\t\t * uncompressed, and just serve it from inside the\n-\t\t * zip with no gzip container;\n-\t\t */\n-\n-\t\tlwsl_info(\u0022direct zip serving (stored)\u005cn\u0022);\n-\n-\t\tpriv-\u003efop_fd.len \u003d priv-\u003ehdr.uncomp_size;\n-\n-\t\treturn \u0026priv-\u003efop_fd;\n-\t}\n-\n-\tif ((*flags \u0026 LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP) \u0026\u0026\n-\t priv-\u003ehdr.method \u003d\u003d ZIP_COMPRESSION_METHOD_DEFLATE) {\n-\n-\t\t/*\n-\t\t * We can serve the gzipped file contents directly as gzip\n-\t\t * from inside the zip container; client says it is OK.\n-\t\t *\n-\t\t * To convert to standalone gzip, we have to add a 10-byte\n-\t\t * constant header and a variable 8-byte trailer around the\n-\t\t * content.\n-\t\t *\n-\t\t * The 8-byte trailer is prepared now and held in the priv.\n-\t\t */\n-\n-\t\tlwsl_info(\u0022direct zip serving (gzipped)\u005cn\u0022);\n-\n-\t\tpriv-\u003efop_fd.len \u003d sizeof(hd) + priv-\u003ehdr.comp_size +\n-\t\t\t\t sizeof(priv-\u003eu);\n-\n-\t\tif (lws_is_be()) {\n-\t\t\tuint8_t *p \u003d priv-\u003eu.trailer8;\n-\n-\t\t\t*p++ \u003d (uint8_t)priv-\u003ehdr.crc32;\n-\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.crc32 \u003e\u003e 8);\n-\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.crc32 \u003e\u003e 16);\n-\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.crc32 \u003e\u003e 24);\n-\t\t\t*p++ \u003d (uint8_t)priv-\u003ehdr.uncomp_size;\n-\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.uncomp_size \u003e\u003e 8);\n-\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.uncomp_size \u003e\u003e 16);\n-\t\t\t*p \u003d (uint8_t)(priv-\u003ehdr.uncomp_size \u003e\u003e 24);\n-\t\t} else {\n-\t\t\tpriv-\u003eu.trailer32[0] \u003d priv-\u003ehdr.crc32;\n-\t\t\tpriv-\u003eu.trailer32[1] \u003d priv-\u003ehdr.uncomp_size;\n-\t\t}\n-\n-\t\t*flags |\u003d LWS_FOP_FLAG_COMPR_IS_GZIP;\n-\t\tpriv-\u003efop_fd.flags \u003d *flags;\n-\t\tpriv-\u003eadd_gzip_container \u003d 1;\n-\n-\t\treturn \u0026priv-\u003efop_fd;\n-\t}\n-\n-\tif (priv-\u003ehdr.method \u003d\u003d ZIP_COMPRESSION_METHOD_DEFLATE) {\n-\n-\t\t/* we must decompress it to serve it */\n-\n-\t\tlwsl_info(\u0022decompressed zip serving\u005cn\u0022);\n-\n-\t\tpriv-\u003efop_fd.len \u003d priv-\u003ehdr.uncomp_size;\n-\n-\t\tif (lws_fops_zip_reset_inflate(priv)) {\n-\t\t\tlwsl_err(\u0022inflate init failed\u005cn\u0022);\n-\t\t\tgoto bail2;\n-\t\t}\n-\n-\t\tpriv-\u003edecompress \u003d 1;\n-\n-\t\treturn \u0026priv-\u003efop_fd;\n-\t}\n-\n-\t/* we can't handle it ... */\n-\n-\tlwsl_err(\u0022zipped file %s compressed in unknown way (%d)\u005cn\u0022, vfs_path,\n-\t\t priv-\u003ehdr.method);\n-\n-bail2:\n-\tlws_vfs_file_close(\u0026priv-\u003ezip_fop_fd);\n-bail1:\n-\tfree(priv);\n-\n-\treturn NULL;\n-}\n-\n-/* ie, we are closing the fop_fd for the file inside the gzip */\n-\n-static int\n-lws_fops_zip_close(lws_fop_fd_t *fd)\n-{\n-\tlws_fops_zip_t priv \u003d fop_fd_to_priv(*fd);\n-\n-\tif (priv-\u003edecompress)\n-\t\tinflateEnd(\u0026priv-\u003einflate);\n-\n-\tlws_vfs_file_close(\u0026priv-\u003ezip_fop_fd); /* close the gzip fop_fd */\n-\n-\tfree(priv);\n-\t*fd \u003d NULL;\n-\n-\treturn 0;\n-}\n-\n-static lws_fileofs_t\n-lws_fops_zip_seek_cur(lws_fop_fd_t fd, lws_fileofs_t offset_from_cur_pos)\n-{\n-\tfd-\u003epos +\u003d offset_from_cur_pos;\n-\n-\treturn fd-\u003epos;\n-}\n-\n-static int\n-lws_fops_zip_read(lws_fop_fd_t fd, lws_filepos_t *amount, uint8_t *buf,\n-\t\t lws_filepos_t len)\n-{\n-\tlws_fops_zip_t priv \u003d fop_fd_to_priv(fd);\n-\tlws_filepos_t ramount, rlen, cur \u003d lws_vfs_tell(fd);\n-\tint ret;\n-\n-\tif (priv-\u003edecompress) {\n-\n-\t\tif (priv-\u003eexp_uncomp_pos !\u003d fd-\u003epos) {\n-\t\t\t/*\n-\t\t\t * there has been a seek in the uncompressed fop_fd\n-\t\t\t * we have to restart the decompression and loop eating\n-\t\t\t * the decompressed data up to the seek point\n-\t\t\t */\n-\t\t\tlwsl_info(\u0022seek in decompressed\u005cn\u0022);\n-\n-\t\t\tlws_fops_zip_reset_inflate(priv);\n-\n-\t\t\twhile (priv-\u003eexp_uncomp_pos !\u003d fd-\u003epos) {\n-\t\t\t\trlen \u003d len;\n-\t\t\t\tif (rlen \u003e fd-\u003epos - priv-\u003eexp_uncomp_pos)\n-\t\t\t\t\trlen \u003d fd-\u003epos - priv-\u003eexp_uncomp_pos;\n-\t\t\t\tif (lws_fops_zip_read(fd, amount, buf, rlen))\n-\t\t\t\t\treturn LWS_FZ_ERR_SEEK_COMPRESSED;\n-\t\t\t}\n-\t\t\t*amount \u003d 0;\n-\t\t}\n-\n-\t\tpriv-\u003einflate.avail_out \u003d (unsigned int)len;\n-\t\tpriv-\u003einflate.next_out \u003d buf;\n-\n-spin:\n-\t\tif (!priv-\u003einflate.avail_in) {\n-\t\t\trlen \u003d sizeof(priv-\u003erbuf);\n-\t\t\tif (rlen \u003e priv-\u003ehdr.comp_size -\n-\t\t\t\t (cur - priv-\u003econtent_start))\n-\t\t\t\trlen \u003d priv-\u003ehdr.comp_size -\n-\t\t\t\t (priv-\u003ehdr.comp_size -\n-\t\t\t\t\tpriv-\u003econtent_start);\n-\n-\t\t\tif (priv-\u003ezip_fop_fd-\u003efops-\u003eLWS_FOP_READ(\n-\t\t\t\t\tpriv-\u003ezip_fop_fd, \u0026ramount, priv-\u003erbuf,\n-\t\t\t\t\trlen))\n-\t\t\t\treturn LWS_FZ_ERR_READ_CONTENT;\n-\n-\t\t\tcur +\u003d ramount;\n-\n-\t\t\tpriv-\u003einflate.avail_in \u003d (unsigned int)ramount;\n-\t\t\tpriv-\u003einflate.next_in \u003d priv-\u003erbuf;\n-\t\t}\n-\n-\t\tret \u003d inflate(\u0026priv-\u003einflate, Z_NO_FLUSH);\n-\t\tif (ret \u003d\u003d Z_STREAM_ERROR)\n-\t\t\treturn ret;\n-\n-\t\tswitch (ret) {\n-\t\tcase Z_NEED_DICT:\n-\t\t\tret \u003d Z_DATA_ERROR;\n-\t\t\t/* and fall through */\n-\t\tcase Z_DATA_ERROR:\n-\t\tcase Z_MEM_ERROR:\n-\n-\t\t\treturn ret;\n-\t\t}\n-\n-\t\tif (!priv-\u003einflate.avail_in \u0026\u0026 priv-\u003einflate.avail_out \u0026\u0026\n-\t\t cur !\u003d priv-\u003econtent_start + priv-\u003ehdr.comp_size)\n-\t\t\tgoto spin;\n-\n-\t\t*amount \u003d len - priv-\u003einflate.avail_out;\n-\n-\t\tpriv-\u003eexp_uncomp_pos +\u003d *amount;\n-\t\tfd-\u003epos +\u003d *amount;\n-\n-\t\treturn 0;\n-\t}\n-\n-\tif (priv-\u003eadd_gzip_container) {\n-\n-\t\tlwsl_info(\u0022%s: gzip + container\u005cn\u0022, __func__);\n-\t\t*amount \u003d 0;\n-\n-\t\t/* place the canned header at the start */\n-\n-\t\tif (len \u0026\u0026 fd-\u003epos \u003c sizeof(hd)) {\n-\t\t\trlen \u003d sizeof(hd) - fd-\u003epos;\n-\t\t\tif (rlen \u003e len)\n-\t\t\t\trlen \u003d len;\n-\t\t\t/* provide stuff from canned header */\n-\t\t\tmemcpy(buf, hd + fd-\u003epos, (size_t)rlen);\n-\t\t\tfd-\u003epos +\u003d rlen;\n-\t\t\tbuf +\u003d rlen;\n-\t\t\tlen -\u003d rlen;\n-\t\t\t*amount +\u003d rlen;\n-\t\t}\n-\n-\t\t/* serve gzipped data direct from zipfile */\n-\n-\t\tif (len \u0026\u0026 fd-\u003epos \u003e\u003d sizeof(hd) \u0026\u0026\n-\t\t fd-\u003epos \u003c priv-\u003ehdr.comp_size + sizeof(hd)) {\n-\n-\t\t\trlen \u003d priv-\u003ehdr.comp_size - (priv-\u003ezip_fop_fd-\u003epos -\n-\t\t\t\t\t\t priv-\u003econtent_start);\n-\t\t\tif (rlen \u003e len)\n-\t\t\t\trlen \u003d len;\n-\n-\t\t\tif (rlen \u0026\u0026\n-\t\t\t priv-\u003ezip_fop_fd-\u003epos \u003c (priv-\u003ehdr.comp_size +\n-\t\t\t\t\t \t priv-\u003econtent_start)) {\n-\t\t\t\tif (lws_vfs_file_read(priv-\u003ezip_fop_fd,\n-\t\t\t\t\t\t \u0026ramount, buf, rlen))\n-\t\t\t\t\treturn LWS_FZ_ERR_READ_CONTENT;\n-\t\t\t\t*amount +\u003d ramount;\n-\t\t\t\tfd-\u003epos +\u003d ramount; // virtual pos\n-\t\t\t\tbuf +\u003d ramount;\n-\t\t\t\tlen -\u003d ramount;\n-\t\t\t}\n-\t\t}\n-\n-\t\t/* place the prepared trailer at the end */\n-\n-\t\tif (len \u0026\u0026 fd-\u003epos \u003e\u003d priv-\u003ehdr.comp_size + sizeof(hd) \u0026\u0026\n-\t\t fd-\u003epos \u003c priv-\u003ehdr.comp_size + sizeof(hd) +\n-\t\t \t sizeof(priv-\u003eu)) {\n-\t\t\tcur \u003d fd-\u003epos - priv-\u003ehdr.comp_size - sizeof(hd);\n-\t\t\trlen \u003d sizeof(priv-\u003eu) - cur;\n-\t\t\tif (rlen \u003e len)\n-\t\t\t\trlen \u003d len;\n-\n-\t\t\tmemcpy(buf, priv-\u003eu.trailer8 + cur, (size_t)rlen);\n-\n-\t\t\t*amount +\u003d rlen;\n-\t\t\tfd-\u003epos +\u003d rlen;\n-\t\t}\n-\n-\t\treturn 0;\n-\t}\n-\n-\tlwsl_info(\u0022%s: store\u005cn\u0022, __func__);\n-\n-\tif (len \u003e priv-\u003ehdr.uncomp_size - (cur - priv-\u003econtent_start))\n-\t\tlen \u003d priv-\u003ehdr.comp_size - (priv-\u003ehdr.comp_size -\n-\t\t\t\t\t priv-\u003econtent_start);\n-\n-\tif (priv-\u003ezip_fop_fd-\u003efops-\u003eLWS_FOP_READ(priv-\u003ezip_fop_fd,\n-\t\t\t\t\t\t amount, buf, len))\n-\t\treturn LWS_FZ_ERR_READ_CONTENT;\n-\n-\treturn 0;\n-}\n-\n-struct lws_plat_file_ops fops_zip \u003d {\n-\tlws_fops_zip_open,\n-\tlws_fops_zip_close,\n-\tlws_fops_zip_seek_cur,\n-\tlws_fops_zip_read,\n-\tNULL,\n-\t{ { \u0022.zip/\u0022, 5 }, { \u0022.jar/\u0022, 5 }, { \u0022.war/\u0022, 5 } },\n-\tNULL,\n-};\ndiff --git a/lib/getifaddrs.c b/lib/getifaddrs.c\ndeleted file mode 100644\nindex beecad9..0000000\n--- a/lib/getifaddrs.c\n+++ /dev/null\n@@ -1,272 +0,0 @@\n-/*\n- * downloaded from\n- * http://ftp.uninett.no/pub/OpenBSD/src/kerberosV/src/lib/roken/getifaddrs.c\n- */\n-#if !LWS_HAVE_GETIFADDRS\n-/*\n- * Copyright (c) 2000 - 2001 Kungliga Tekniska H�gskolan\n- * (Royal Institute of Technology, Stockholm, Sweden).\n- * All rights reserved.\n- *\n- * Redistribution and use in source and binary forms, with or without\n- * modification, are permitted provided that the following conditions\n- * are met:\n- *\n- * 1. Redistributions of source code must retain the above copyright\n- * notice, this list of conditions and the following disclaimer.\n- *\n- * 2. Redistributions in binary form must reproduce the above copyright\n- * notice, this list of conditions and the following disclaimer in the\n- * documentation and/or other materials provided with the distribution.\n- *\n- * 3. Neither the name of the Institute nor the names of its contributors\n- * may be used to endorse or promote products derived from this software\n- * without specific prior written permission.\n- *\n- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND\n- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE\n- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n- * SUCH DAMAGE.\n- */\n-\n-#include \u003cerrno.h\u003e\n-#include \u003csys/types.h\u003e\n-#include \u003csys/socket.h\u003e\n-#include \u003cnet/if.h\u003e\n-#include \u003cstdlib.h\u003e\n-#include \u003cstring.h\u003e\n-#include \u003csys/ioctl.h\u003e\n-#include \u003cunistd.h\u003e\n-#include \u0022private-libwebsockets.h\u0022\n-\n-#ifdef LWS_HAVE_SYS_SOCKIO_H\n-#include \u003csys/sockio.h\u003e\n-#endif\n-\n-#ifdef LWS_HAVE_NETINET_IN6_VAR_H\n-#include \u003cnetinet/in6_var.h\u003e\n-#endif\n-\n-#ifndef max\n-#define max(a, b) ((a) \u003e (b) ? (a) : (b))\n-#endif\n-\n-#include \u0022getifaddrs.h\u0022\n-\n-static int\n-getifaddrs2(struct ifaddrs **ifap, int af, int siocgifconf, int siocgifflags,\n-\t size_t ifreq_sz)\n-{\n-\tint ret;\n-\tint fd;\n-\tsize_t buf_size;\n-\tchar *buf;\n-\tstruct ifconf ifconf;\n-\tchar *p;\n-\tsize_t sz;\n-\tstruct sockaddr sa_zero;\n-\tstruct ifreq *ifr;\n-\tstruct ifaddrs *start, **end \u003d \u0026start;\n-\n-\tbuf \u003d NULL;\n-\n-\tmemset(\u0026sa_zero, 0, sizeof(sa_zero));\n-\tfd \u003d socket(af, SOCK_DGRAM, 0);\n-\tif (fd \u003c 0)\n-\t\treturn -1;\n-\n-\tbuf_size \u003d 8192;\n-\tfor (;;) {\n-\t\tbuf \u003d lws_zalloc(buf_size, \u0022getifaddrs2\u0022);\n-\t\tif (buf \u003d\u003d NULL) {\n-\t\t\tret \u003d ENOMEM;\n-\t\t\tgoto error_out;\n-\t\t}\n-\t\tifconf.ifc_len \u003d buf_size;\n-\t\tifconf.ifc_buf \u003d buf;\n-\n-\t\t/*\n-\t\t * Solaris returns EINVAL when the buffer is too small.\n-\t\t */\n-\t\tif (ioctl(fd, siocgifconf, \u0026ifconf) \u003c 0 \u0026\u0026 errno !\u003d EINVAL) {\n-\t\t\tret \u003d errno;\n-\t\t\tgoto error_out;\n-\t\t}\n-\t\t/*\n-\t\t * Can the difference between a full and a overfull buf\n-\t\t * be determined?\n-\t\t */\n-\n-\t\tif (ifconf.ifc_len \u003c (int)buf_size)\n-\t\t\tbreak;\n-\t\tlws_free(buf);\n-\t\tbuf_size *\u003d 2;\n-\t}\n-\n-\tfor (p \u003d ifconf.ifc_buf; p \u003c ifconf.ifc_buf + ifconf.ifc_len; p +\u003d sz) {\n-\t\tstruct ifreq ifreq;\n-\t\tstruct sockaddr *sa;\n-\t\tsize_t salen;\n-\n-\t\tifr \u003d (struct ifreq *)p;\n-\t\tsa \u003d \u0026ifr-\u003eifr_addr;\n-\n-\t\tsz \u003d ifreq_sz;\n-\t\tsalen \u003d sizeof(struct sockaddr);\n-#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN\n-\t\tsalen \u003d sa-\u003esa_len;\n-\t\tsz \u003d max(sz, sizeof(ifr-\u003eifr_name) + sa-\u003esa_len);\n-#endif\n-#ifdef SA_LEN\n-\t\tsalen \u003d SA_LEN(sa);\n-\t\tsz \u003d max(sz, sizeof(ifr-\u003eifr_name) + SA_LEN(sa));\n-#endif\n-\t\tmemset(\u0026ifreq, 0, sizeof(ifreq));\n-\t\tmemcpy(ifreq.ifr_name, ifr-\u003eifr_name, sizeof(ifr-\u003eifr_name));\n-\n-\t\tif (ioctl(fd, siocgifflags, \u0026ifreq) \u003c 0) {\n-\t\t\tret \u003d errno;\n-\t\t\tgoto error_out;\n-\t\t}\n-\n-\t\t*end \u003d lws_malloc(sizeof(**end), \u0022getifaddrs\u0022);\n-\n-\t\t(*end)-\u003eifa_next \u003d NULL;\n-\t\t(*end)-\u003eifa_name \u003d strdup(ifr-\u003eifr_name);\n-\t\t(*end)-\u003eifa_flags \u003d ifreq.ifr_flags;\n-\t\t(*end)-\u003eifa_addr \u003d lws_malloc(salen);\n-\t\tmemcpy((*end)-\u003eifa_addr, sa, salen);\n-\t\t(*end)-\u003eifa_netmask \u003d NULL;\n-\n-#if 0\n-\t\t/* fix these when we actually need them */\n-\t\tif (ifreq.ifr_flags \u0026 IFF_BROADCAST) {\n-\t\t\t(*end)-\u003eifa_broadaddr \u003d\n-\t\t\t\tlws_malloc(sizeof(ifr-\u003eifr_broadaddr), \u0022getifaddrs\u0022);\n-\t\t\tmemcpy((*end)-\u003eifa_broadaddr, \u0026ifr-\u003eifr_broadaddr,\n-\t\t\t\t\t\t sizeof(ifr-\u003eifr_broadaddr));\n-\t\t} else if (ifreq.ifr_flags \u0026 IFF_POINTOPOINT) {\n-\t\t\t(*end)-\u003eifa_dstaddr \u003d\n-\t\t\t\tlws_malloc(sizeof(ifr-\u003eifr_dstaddr), \u0022getifaddrs\u0022);\n-\t\t\tmemcpy((*end)-\u003eifa_dstaddr, \u0026ifr-\u003eifr_dstaddr,\n-\t\t\t\t\t\t sizeof(ifr-\u003eifr_dstaddr));\n-\t\t} else\n-\t\t\t(*end)-\u003eifa_dstaddr \u003d NULL;\n-#else\n-\t\t(*end)-\u003eifa_dstaddr \u003d NULL;\n-#endif\n-\t\t(*end)-\u003eifa_data \u003d NULL;\n-\n-\t\tend \u003d \u0026(*end)-\u003eifa_next;\n-\n-\t}\n-\t*ifap \u003d start;\n-\tclose(fd);\n-\tlws_free(buf);\n-\treturn 0;\n-\n-error_out:\n-\tclose(fd);\n-\tlws_free(buf);\n-\terrno \u003d ret;\n-\n-\treturn -1;\n-}\n-\n-int\n-getifaddrs(struct ifaddrs **ifap)\n-{\n-\tint ret \u003d -1;\n-\terrno \u003d ENXIO;\n-#if defined(AF_INET6) \u0026\u0026 defined(SIOCGIF6CONF) \u0026\u0026 defined(SIOCGIF6FLAGS)\n-\tif (ret)\n-\t\tret \u003d getifaddrs2(ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,\n-\t\t\t sizeof(struct in6_ifreq));\n-#endif\n-#if defined(LWS_HAVE_IPV6) \u0026\u0026 defined(SIOCGIFCONF)\n-\tif (ret)\n-\t\tret \u003d getifaddrs2(ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,\n-\t\t\t sizeof(struct ifreq));\n-#endif\n-#if defined(AF_INET) \u0026\u0026 defined(SIOCGIFCONF) \u0026\u0026 defined(SIOCGIFFLAGS)\n-\tif (ret)\n-\t\tret \u003d getifaddrs2(ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,\n-\t\t\t sizeof(struct ifreq));\n-#endif\n-\treturn ret;\n-}\n-\n-void\n-freeifaddrs(struct ifaddrs *ifp)\n-{\n-\tstruct ifaddrs *p, *q;\n-\n-\tfor (p \u003d ifp; p; ) {\n-\t\tlws_free(p-\u003eifa_name);\n-\t\tlws_free(p-\u003eifa_addr);\n-\t\tlws_free(p-\u003eifa_dstaddr);\n-\t\tlws_free(p-\u003eifa_netmask);\n-\t\tlws_free(p-\u003eifa_data);\n-\t\tq \u003d p;\n-\t\tp \u003d p-\u003eifa_next;\n-\t\tlws_free(q);\n-\t}\n-}\n-\n-#ifdef TEST\n-\n-void\n-print_addr(const char *s, struct sockaddr *sa)\n-{\n-\tint i;\n-\tprintf(\u0022 %s\u003d%d/\u0022, s, sa-\u003esa_family);\n-#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN\n-\tfor (i \u003d 0;\n-\t i \u003c sa-\u003esa_len - ((lws_intptr_t)sa-\u003esa_data - (lws_intptr_t)\u0026sa-\u003esa_family); i++)\n-\t\tprintf(\u0022%02x\u0022, ((unsigned char *)sa-\u003esa_data)[i]);\n-#else\n-\tfor (i \u003d 0; i \u003c sizeof(sa-\u003esa_data); i++)\n-\t\tprintf(\u0022%02x\u0022, ((unsigned char *)sa-\u003esa_data)[i]);\n-#endif\n-\tprintf(\u0022\u005cn\u0022);\n-}\n-\n-void\n-print_ifaddrs(struct ifaddrs *x)\n-{\n-\tstruct ifaddrs *p;\n-\n-\tfor (p \u003d x; p; p \u003d p-\u003eifa_next) {\n-\t\tprintf(\u0022%s\u005cn\u0022, p-\u003eifa_name);\n-\t\tprintf(\u0022 flags\u003d%x\u005cn\u0022, p-\u003eifa_flags);\n-\t\tif (p-\u003eifa_addr)\n-\t\t\tprint_addr(\u0022addr\u0022, p-\u003eifa_addr);\n-\t\tif (p-\u003eifa_dstaddr)\n-\t\t\tprint_addr(\u0022dstaddr\u0022, p-\u003eifa_dstaddr);\n-\t\tif (p-\u003eifa_netmask)\n-\t\t\tprint_addr(\u0022netmask\u0022, p-\u003eifa_netmask);\n-\t\tprintf(\u0022 %p\u005cn\u0022, p-\u003eifa_data);\n-\t}\n-}\n-\n-int\n-main()\n-{\n-\tstruct ifaddrs *a \u003d NULL, *b;\n-\tgetifaddrs2(\u0026a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,\n-\t\t sizeof(struct ifreq));\n-\tprint_ifaddrs(a);\n-\tprintf(\u0022---\u005cn\u0022);\n-\tgetifaddrs(\u0026b);\n-\tprint_ifaddrs(b);\n-\treturn 0;\n-}\n-#endif\n-#endif\ndiff --git a/lib/getifaddrs.h b/lib/getifaddrs.h\ndeleted file mode 100644\nindex d26670c..0000000\n--- a/lib/getifaddrs.h\n+++ /dev/null\n@@ -1,80 +0,0 @@\n-#ifndef LWS_HAVE_GETIFADDRS\n-#define LWS_HAVE_GETIFADDRS 0\n-#endif\n-\n-#if LWS_HAVE_GETIFADDRS\n-#include \u003csys/types.h\u003e\n-#include \u003cifaddrs.h\u003e\n-#else\n-#ifdef __cplusplus\n-extern \u0022C\u0022 {\n-#endif\n-/*\n- * Copyright (c) 2000 Kungliga Tekniska H�gskolan\n- * (Royal Institute of Technology, Stockholm, Sweden).\n- * All rights reserved.\n- *\n- * Redistribution and use in source and binary forms, with or without\n- * modification, are permitted provided that the following conditions\n- * are met:\n- *\n- * 1. Redistributions of source code must retain the above copyright\n- * notice, this list of conditions and the following disclaimer.\n- *\n- * 2. Redistributions in binary form must reproduce the above copyright\n- * notice, this list of conditions and the following disclaimer in the\n- * documentation and/or other materials provided with the distribution.\n- *\n- * 3. Neither the name of the Institute nor the names of its contributors\n- * may be used to endorse or promote products derived from this software\n- * without specific prior written permission.\n- *\n- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND\n- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE\n- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n- * SUCH DAMAGE.\n- */\n-\n-/* $KTH: ifaddrs.hin,v 1.3 2000/12/11 00:01:13 assar Exp $ */\n-\n-#ifndef ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791\n-#define ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791\n-\n-/*\n- * the interface is defined in terms of the fields below, and this is\n- * sometimes #define'd, so there seems to be no simple way of solving\n- * this and this seemed the best. */\n-\n-#undef ifa_dstaddr\n-\n-struct ifaddrs {\n-\tstruct ifaddrs *ifa_next;\n-\tchar *ifa_name;\n-\tunsigned int ifa_flags;\n-\tstruct sockaddr *ifa_addr;\n-\tstruct sockaddr *ifa_netmask;\n-\tstruct sockaddr *ifa_dstaddr;\n-\tvoid *ifa_data;\n-};\n-\n-#ifndef ifa_broadaddr\n-#define ifa_broadaddr ifa_dstaddr\n-#endif\n-\n-int getifaddrs(struct ifaddrs **);\n-\n-void freeifaddrs(struct ifaddrs *);\n-\n-#endif /* __ifaddrs_h__ */\n-\n-#ifdef __cplusplus\n-}\n-#endif\n-#endif\ndiff --git a/lib/hpack.c b/lib/hpack.c\ndeleted file mode 100644\nindex f7d916f..0000000\n--- a/lib/hpack.c\n+++ /dev/null\n@@ -1,1321 +0,0 @@\n-/*\n- * lib/hpack.c\n- *\n- * Copyright (C) 2014-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-/*\n- * Official static header table for HPACK\n- * +-------+-----------------------------+---------------+\n- | 1 | :authority | |\n- | 2 | :method | GET |\n- | 3 | :method | POST |\n- | 4 | :path | / |\n- | 5 | :path | /index.html |\n- | 6 | :scheme | http |\n- | 7 | :scheme | https |\n- | 8 | :status | 200 |\n- | 9 | :status | 204 |\n- | 10 | :status | 206 |\n- | 11 | :status | 304 |\n- | 12 | :status | 400 |\n- | 13 | :status | 404 |\n- | 14 | :status | 500 |\n- | 15 | accept-charset | |\n- | 16 | accept-encoding | gzip, deflate |\n- | 17 | accept-language | |\n- | 18 | accept-ranges | |\n- | 19 | accept | |\n- | 20 | access-control-allow-origin | |\n- | 21 | age | |\n- | 22 | allow | |\n- | 23 | authorization | |\n- | 24 | cache-control | |\n- | 25 | content-disposition | |\n- | 26 | content-encoding | |\n- | 27 | content-language | |\n- | 28 | content-length | |\n- | 29 | content-location | |\n- | 30 | content-range | |\n- | 31 | content-type | |\n- | 32 | cookie | |\n- | 33 | date | |\n- | 34 | etag | |\n- | 35 | expect | |\n- | 36 | expires | |\n- | 37 | from | |\n- | 38 | host | |\n- | 39 | if-match | |\n- | 40 | if-modified-since | |\n- | 41 | if-none-match | |\n- | 42 | if-range | |\n- | 43 | if-unmodified-since | |\n- | 44 | last-modified | |\n- | 45 | link | |\n- | 46 | location | |\n- | 47 | max-forwards | |\n- | 48 | proxy-authenticate | |\n- | 49 | proxy-authorization | |\n- | 50 | range | |\n- | 51 | referer | |\n- | 52 | refresh | |\n- | 53 | retry-after | |\n- | 54 | server | |\n- | 55 | set-cookie | |\n- | 56 | strict-transport-security | |\n- | 57 | transfer-encoding | |\n- | 58 | user-agent | |\n- | 59 | vary | |\n- | 60 | via | |\n- | 61 | www-authenticate | |\n- +-------+-----------------------------+---------------+\n-*/\n-\n-static const uint8_t static_hdr_len[] \u003d {\n-\t\t0, /* starts at 1 */\n-\t\t10, 7, 7, 5, 5, 7, 7, 7, 7, 7,\n-\t\t7, 7, 7, 7, 14, 15, 15, 13, 6, 27,\n-\t\t3, 5, 13, 13, 19, 16, 16, 14, 16, 13,\n-\t\t12, 6, 4, 4, 6, 7, 4, 4, 8, 17,\n-\t\t13, 8, 19, 13, 4, 8, 12, 18, 19,\n-\t\t5, 7, 7, 11, 6, 10, 25, 17, 10, 4,\n-\t\t3, 16\n-};\n-\n-static const unsigned char static_token[] \u003d {\n-\t0,\n-\tWSI_TOKEN_HTTP_COLON_AUTHORITY,\n-\tWSI_TOKEN_HTTP_COLON_METHOD,\n-\tWSI_TOKEN_HTTP_COLON_METHOD,\n-\tWSI_TOKEN_HTTP_COLON_PATH,\n-\tWSI_TOKEN_HTTP_COLON_PATH,\n-\tWSI_TOKEN_HTTP_COLON_SCHEME,\n-\tWSI_TOKEN_HTTP_COLON_SCHEME,\n-\tWSI_TOKEN_HTTP_COLON_STATUS,\n-\tWSI_TOKEN_HTTP_COLON_STATUS,\n-\tWSI_TOKEN_HTTP_COLON_STATUS,\n-\tWSI_TOKEN_HTTP_COLON_STATUS,\n-\tWSI_TOKEN_HTTP_COLON_STATUS,\n-\tWSI_TOKEN_HTTP_COLON_STATUS,\n-\tWSI_TOKEN_HTTP_COLON_STATUS,\n-\tWSI_TOKEN_HTTP_ACCEPT_CHARSET,\n-\tWSI_TOKEN_HTTP_ACCEPT_ENCODING,\n-\tWSI_TOKEN_HTTP_ACCEPT_LANGUAGE,\n-\tWSI_TOKEN_HTTP_ACCEPT_RANGES,\n-\tWSI_TOKEN_HTTP_ACCEPT,\n-\tWSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,\n-\tWSI_TOKEN_HTTP_AGE,\n-\tWSI_TOKEN_HTTP_ALLOW,\n-\tWSI_TOKEN_HTTP_AUTHORIZATION,\n-\tWSI_TOKEN_HTTP_CACHE_CONTROL,\n-\tWSI_TOKEN_HTTP_CONTENT_DISPOSITION,\n-\tWSI_TOKEN_HTTP_CONTENT_ENCODING,\n-\tWSI_TOKEN_HTTP_CONTENT_LANGUAGE,\n-\tWSI_TOKEN_HTTP_CONTENT_LENGTH,\n-\tWSI_TOKEN_HTTP_CONTENT_LOCATION,\n-\tWSI_TOKEN_HTTP_CONTENT_RANGE,\n-\tWSI_TOKEN_HTTP_CONTENT_TYPE,\n-\tWSI_TOKEN_HTTP_COOKIE,\n-\tWSI_TOKEN_HTTP_DATE,\n-\tWSI_TOKEN_HTTP_ETAG,\n-\tWSI_TOKEN_HTTP_EXPECT,\n-\tWSI_TOKEN_HTTP_EXPIRES,\n-\tWSI_TOKEN_HTTP_FROM,\n-\tWSI_TOKEN_HOST,\n-\tWSI_TOKEN_HTTP_IF_MATCH,\n-\tWSI_TOKEN_HTTP_IF_MODIFIED_SINCE,\n-\tWSI_TOKEN_HTTP_IF_NONE_MATCH,\n-\tWSI_TOKEN_HTTP_IF_RANGE,\n-\tWSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE,\n-\tWSI_TOKEN_HTTP_LAST_MODIFIED,\n-\tWSI_TOKEN_HTTP_LINK,\n-\tWSI_TOKEN_HTTP_LOCATION,\n-\tWSI_TOKEN_HTTP_MAX_FORWARDS,\n-\tWSI_TOKEN_HTTP_PROXY_AUTHENTICATE,\n-\tWSI_TOKEN_HTTP_PROXY_AUTHORIZATION,\n-\tWSI_TOKEN_HTTP_RANGE,\n-\tWSI_TOKEN_HTTP_REFERER,\n-\tWSI_TOKEN_HTTP_REFRESH,\n-\tWSI_TOKEN_HTTP_RETRY_AFTER,\n-\tWSI_TOKEN_HTTP_SERVER,\n-\tWSI_TOKEN_HTTP_SET_COOKIE,\n-\tWSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY,\n-\tWSI_TOKEN_HTTP_TRANSFER_ENCODING,\n-\tWSI_TOKEN_HTTP_USER_AGENT,\n-\tWSI_TOKEN_HTTP_VARY,\n-\tWSI_TOKEN_HTTP_VIA,\n-\tWSI_TOKEN_HTTP_WWW_AUTHENTICATE,\n-};\n-\n-/* some of the entries imply values as well as header names */\n-\n-static const char * const http2_canned[] \u003d {\n-\t\u0022\u0022,\n-\t\u0022\u0022,\n-\t\u0022GET\u0022,\n-\t\u0022POST\u0022,\n-\t\u0022/\u0022,\n-\t\u0022/index.html\u0022,\n-\t\u0022http\u0022,\n-\t\u0022https\u0022,\n-\t\u0022200\u0022,\n-\t\u0022204\u0022,\n-\t\u0022206\u0022,\n-\t\u0022304\u0022,\n-\t\u0022400\u0022,\n-\t\u0022404\u0022,\n-\t\u0022500\u0022,\n-\t\u0022\u0022,\n-\t\u0022gzip, deflate\u0022\n-};\n-\n-/* see minihuf.c */\n-\n-#include \u0022huftable.h\u0022\n-\n-static int huftable_decode(int pos, char c)\n-{\n-\tint q \u003d pos + !!c;\n-\n-\tif (lextable_terms[q \u003e\u003e 3] \u0026 (1 \u003c\u003c (q \u0026 7))) /* terminal */\n-\t\treturn lextable[q] | 0x8000;\n-\n-\treturn pos + (lextable[q] \u003c\u003c 1);\n-}\n-\n-static int lws_frag_start(struct lws *wsi, int hdr_token_idx)\n-{\n-\tstruct allocated_headers *ah \u003d wsi-\u003eu.h2.http.ah;\n-\n-\tif (!ah) {\n-\t\tlwsl_notice(\u0022%s: no ah\u005cn\u0022, __func__);\n-\t\treturn 1;\n-\t}\n-\n-\tah-\u003ehdr_token_idx \u003d -1;\n-\n-\tlwsl_header(\u0022%s: token %d ah-\u003epos \u003d %d, ah-\u003enfrag \u003d %d\u005cn\u0022,\n-\t\t __func__, hdr_token_idx, ah-\u003epos, ah-\u003enfrag);\n-\n-\tif (!hdr_token_idx) {\n-\t\tlwsl_err(\u0022%s: zero hdr_token_idx\u005cn\u0022, __func__);\n-\t\treturn 1;\n-\t}\n-\n-\tif (ah-\u003enfrag \u003e\u003d ARRAY_SIZE(ah-\u003efrag_index)) {\n-\t\tlwsl_err(\u0022%s: frag index %d too big\u005cn\u0022, __func__, ah-\u003enfrag);\n-\t\treturn 1;\n-\t}\n-\n-\tif ((hdr_token_idx \u003d\u003d WSI_TOKEN_HTTP_COLON_AUTHORITY ||\n-\t hdr_token_idx \u003d\u003d WSI_TOKEN_HTTP_COLON_METHOD ||\n-\t hdr_token_idx \u003d\u003d WSI_TOKEN_HTTP_COLON_PATH ||\n-\t hdr_token_idx \u003d\u003d WSI_TOKEN_HTTP_COLON_SCHEME) \u0026\u0026\n-\t ah-\u003efrag_index[hdr_token_idx]) {\n-\t\tif (!(ah-\u003efrags[ah-\u003efrag_index[hdr_token_idx]].flags \u0026 1)) {\n-\t\t\tlws_h2_goaway(lws_get_network_wsi(wsi),\n-\t\t\t\t H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t \u0022Duplicated pseudoheader\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\t}\n-\n-\tif (ah-\u003enfrag \u003d\u003d 0)\n-\t\tah-\u003enfrag \u003d 1;\n-\n-\tah-\u003efrags[ah-\u003enfrag].offset \u003d ah-\u003epos;\n-\tah-\u003efrags[ah-\u003enfrag].len \u003d 0;\n-\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d 0;\n-\tah-\u003efrags[ah-\u003enfrag].flags \u003d 2; /* we had reason to set it */\n-\n-\tah-\u003ehdr_token_idx \u003d hdr_token_idx;\n-\n-\tah-\u003efrag_index[hdr_token_idx] \u003d ah-\u003enfrag;\n-\n-\treturn 0;\n-}\n-\n-static int lws_frag_append(struct lws *wsi, unsigned char c)\n-{\n-\tstruct allocated_headers * ah \u003d wsi-\u003eu.h2.http.ah;\n-\n-\tah-\u003edata[ah-\u003epos++] \u003d c;\n-\tah-\u003efrags[ah-\u003enfrag].len++;\n-\n-\treturn ah-\u003epos \u003e\u003d wsi-\u003econtext-\u003emax_http_header_data;\n-}\n-\n-static int lws_frag_end(struct lws *wsi)\n-{\n-\tlwsl_header(\u0022%s\u005cn\u0022, __func__);\n-\tif (lws_frag_append(wsi, 0))\n-\t\treturn 1;\n-\n-\t/* don't account for the terminating NUL in the logical length */\n-\twsi-\u003eu.h2.http.ah-\u003efrags[wsi-\u003eu.h2.http.ah-\u003enfrag].len--;\n-\n-\twsi-\u003eu.h2.http.ah-\u003enfrag++;\n-\treturn 0;\n-}\n-\n-int\n-lws_hdr_extant(struct lws *wsi, enum lws_token_indexes h)\n-{\n-\tstruct allocated_headers *ah \u003d wsi-\u003eu.h2.http.ah;\n-\tint n;\n-\n-\tif (!ah)\n-\t\treturn 0;\n-\n-\tn \u003d ah-\u003efrag_index[h];\n-\tif (!n)\n-\t\treturn 0;\n-\n-\treturn !!(ah-\u003efrags[n].flags \u0026 2);\n-}\n-\n-static void lws_dump_header(struct lws *wsi, int hdr)\n-{\n-\tchar s[200];\n-\tconst unsigned char *p;\n-\tint len;\n-\n-\tif (hdr \u003d\u003d LWS_HPACK_IGNORE_ENTRY) {\n-\t\tlwsl_notice(\u0022hdr tok ignored\u005cn\u0022);\n-\t\treturn;\n-\t}\n-\n-\t(void)p;\n-\n-\tlen \u003d lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);\n-\tif (len \u003c 0)\n-\t\tstrcpy(s, \u0022(too big to show)\u0022);\n-\telse\n-\t\ts[len] \u003d '\u005c0';\n-\tp \u003d lws_token_to_string(hdr);\n-\tlwsl_header(\u0022 hdr tok %d (%s) \u003d '%s' (len %d)\u005cn\u0022, hdr,\n-\t\t p ? (char *)p : (char *)\u0022null\u0022, s, len);\n-}\n-\n-/*\n- * dynamic table\n- *\n- * [ 0 .... num_entries - 1]\n- *\n- * Starts filling at 0+\n- *\n- * #62 is *most recently entered*\n- *\n- * Number of entries is not restricted, but aggregated size of the entry\n- * payloads is. Unfortunately the way HPACK does this is specific to an\n- * imagined implementation, and lws implementation is much more efficient\n- * (ignoring unknown headers and using the lws token index for the header\n- * name part).\n- */\n-\n-/*\n- * returns 0 if dynamic entry (arg and len are filled)\n- * returns -1 if failure\n- * returns nonzero token index if actually static token\n- */\n-static int\n-lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,\n-\t\t uint32_t *hdr_len)\n-{\n-\tstruct hpack_dynamic_table *dyn;\n-\n-\tif (index \u003d\u003d LWS_HPACK_IGNORE_ENTRY)\n-\t\treturn LWS_HPACK_IGNORE_ENTRY;\n-\n-\t/* dynamic table only belongs to network wsi */\n-\twsi \u003d lws_get_network_wsi(wsi);\n-\tif (!wsi-\u003eu.h2.h2n)\n-\t\treturn -1;\n-\n-\tdyn \u003d \u0026wsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n-\n-\tif (index \u003c 0)\n-\t\treturn -1;\n-\n-\tif (index \u003c ARRAY_SIZE(static_token)) {\n-\t\tif (arg \u0026\u0026 index \u003c ARRAY_SIZE(http2_canned)) {\n-\t\t\t*arg \u003d http2_canned[index];\n-\t\t\t*len \u003d strlen(http2_canned[index]);\n-\t\t}\n-\t\tif (hdr_len)\n-\t\t\t*hdr_len \u003d static_hdr_len[index];\n-\n-\t\treturn static_token[index];\n-\t}\n-\n-\tif (!dyn) {\n-\t\tlwsl_notice(\u0022no dynamic table\u005cn\u0022);\n-\t\treturn -1;\n-\t}\n-\n-\tif (index \u003c ARRAY_SIZE(static_token) ||\n-\t index \u003e\u003d ARRAY_SIZE(static_token) + dyn-\u003eused_entries) {\n-\t\tlwsl_err(\u0022 %s: adjusted index %d \u003e\u003d %d\u005cn\u0022, __func__, index,\n-\t\t\t dyn-\u003eused_entries);\n-\t\tlws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,\n-\t\t\t \u0022index out of range\u0022);\n-\t\treturn -1;\n-\t}\n-\n-\tindex -\u003d ARRAY_SIZE(static_token);\n-\tindex \u003d (dyn-\u003epos - 1 - index) % dyn-\u003enum_entries;\n-\tif (index \u003c 0)\n-\t\tindex +\u003d dyn-\u003enum_entries;\n-\n-\tlwsl_header(\u0022%s: dyn index %d, tok %d\u005cn\u0022, __func__, index, dyn-\u003eentries[index].lws_hdr_idx);\n-\n-\tif (arg \u0026\u0026 len) {\n-\t\t*arg \u003d dyn-\u003eentries[index].value;\n-\t\t*len \u003d dyn-\u003eentries[index].value_len;\n-\t}\n-\n-\tif (hdr_len)\n-\t\t*hdr_len \u003d dyn-\u003eentries[index].hdr_len;\n-\n-\treturn dyn-\u003eentries[index].lws_hdr_idx;\n-}\n-\n-static int\n-lws_h2_dynamic_table_dump(struct lws *wsi)\n-{\n-#if 0\n-\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n-\tstruct hpack_dynamic_table *dyn;\n-\tint n, m;\n-\tconst char *p;\n-\n-\tif (!nwsi-\u003eu.h2.h2n)\n-\t\treturn 1;\n-\tdyn \u003d \u0026nwsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n-\n-\tlwsl_header(\u0022Dump dyn table for nwsi %p (%d / %d members, pos \u003d %d, start index %d, virt used %d / %d)\u005cn\u0022, nwsi,\n-\t\t\tdyn-\u003eused_entries, dyn-\u003enum_entries, dyn-\u003epos, (uint32_t)ARRAY_SIZE(static_token),\n-\t\t\tdyn-\u003evirtual_payload_usage, dyn-\u003evirtual_payload_max);\n-\n-\tfor (n \u003d 0; n \u003c dyn-\u003eused_entries; n++) {\n-\t\tm \u003d (dyn-\u003epos - 1 - n) % dyn-\u003enum_entries;\n-\t\tif (m \u003c 0)\n-\t\t\tm +\u003d dyn-\u003enum_entries;\n-\t\tif (dyn-\u003eentries[m].lws_hdr_idx !\u003d LWS_HPACK_IGNORE_ENTRY)\n-\t\t\tp \u003d (const char *)lws_token_to_string(\n-\t\t\t\t\tdyn-\u003eentries[m].lws_hdr_idx);\n-\t\telse\n-\t\t\tp \u003d \u0022(ignored)\u0022;\n-\t\tlwsl_header(\u0022 %3d: tok %s: (len %d) val '%s'\u005cn\u0022,\n-\t\t\t (int)(n + ARRAY_SIZE(static_token)), p, dyn-\u003eentries[m].hdr_len,\n-\t\t\t dyn-\u003eentries[m].value ? dyn-\u003eentries[m].value : \u0022null\u0022);\n-\t}\n-#endif\n-\treturn 0;\n-}\n-\n-static void\n-lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)\n-{\n-\tlwsl_header(\u0022freeing %d for reuse\u005cn\u0022, idx);\n-\tdyn-\u003evirtual_payload_usage -\u003d dyn-\u003eentries[idx].value_len +\n-\t\t\t\tdyn-\u003eentries[idx].hdr_len;\n-\tlws_free_set_NULL(dyn-\u003eentries[idx].value);\n-\tdyn-\u003eentries[idx].value \u003d NULL;\n-\tdyn-\u003eentries[idx].value_len \u003d 0;\n-\tdyn-\u003eentries[idx].hdr_len \u003d 0;\n-\tdyn-\u003eentries[idx].lws_hdr_idx \u003d LWS_HPACK_IGNORE_ENTRY;\n-\tdyn-\u003eused_entries--;\n-}\n-\n-/*\n- * There are two address spaces, 1) internal ringbuffer and 2) HPACK indexes.\n- *\n- * Internal ringbuffer:\n- *\n- * The internal ringbuffer wraps as we keep filling it, dyn-\u003epos points to\n- * the next index to be written.\n- *\n- * HPACK indexes:\n- *\n- * The last-written entry becomes entry 0, the previously-last-written entry\n- * becomes entry 1 etc.\n- */\n-\n-static int\n-lws_dynamic_token_insert(struct lws *wsi, int hdr_len,\n-\t\t\t int lws_hdr_index, char *arg, int len)\n-{\n-\tstruct hpack_dynamic_table *dyn;\n-\tint new_index, n;\n-\n-\t/* dynamic table only belongs to network wsi */\n-\twsi \u003d lws_get_network_wsi(wsi);\n-\tif (!wsi-\u003eu.h2.h2n)\n-\t\treturn 1;\n-\tdyn \u003d \u0026wsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n-\n-\tif (!dyn-\u003eentries) {\n-\t\tlwsl_err(\u0022%s: unsized dyn table\u005cn\u0022, __func__);\n-\n-\t\treturn 1;\n-\t}\n-\tlws_h2_dynamic_table_dump(wsi);\n-\n-\tnew_index \u003d (dyn-\u003epos) % dyn-\u003enum_entries;\n-\tif (dyn-\u003enum_entries \u0026\u0026 dyn-\u003eused_entries \u003d\u003d dyn-\u003enum_entries) {\n-\t\tif (dyn-\u003evirtual_payload_usage \u003c dyn-\u003evirtual_payload_max)\n-\t\t\tlwsl_err(\u0022Dropping header content before limit!\u005cn\u0022);\n-\t\t/* we have to drop the oldest to make space */\n-\t\tlws_dynamic_free(dyn, new_index);\n-\t}\n-\n-\t/*\n-\t * evict guys to make room, allowing for some overage. We have to\n-\t * take care about getting a single huge header, and evicting\n-\t * everything\n-\t */\n-\n-\twhile (dyn-\u003evirtual_payload_usage \u0026\u0026\n-\t dyn-\u003eused_entries \u0026\u0026\n-\t dyn-\u003evirtual_payload_usage + hdr_len + len \u003e\n-\t\t\t\tdyn-\u003evirtual_payload_max + 1024) {\n-\t\tn \u003d (dyn-\u003epos - dyn-\u003eused_entries) % dyn-\u003enum_entries;\n-\t\tif (n \u003c 0)\n-\t\t\tn +\u003d dyn-\u003enum_entries;\n-\t\tlws_dynamic_free(dyn, n);\n-\t}\n-\n-\tif (dyn-\u003eused_entries \u003c dyn-\u003enum_entries)\n-\t\tdyn-\u003eused_entries++;\n-\n-\tdyn-\u003eentries[new_index].value_len \u003d 0;\n-\n-\tif (lws_hdr_index !\u003d LWS_HPACK_IGNORE_ENTRY) {\n-\t\tdyn-\u003eentries[new_index].value \u003d lws_malloc(len + 1, \u0022hpack dyn\u0022);\n-\t\tif (!dyn-\u003eentries[new_index].value)\n-\t\t\treturn 1;\n-\n-\t\tmemcpy(dyn-\u003eentries[new_index].value, arg, len);\n-\t\tdyn-\u003eentries[new_index].value[len] \u003d '\u005c0';\n-\t\tdyn-\u003eentries[new_index].value_len \u003d len;\n-\t} else\n-\t\tdyn-\u003eentries[new_index].value \u003d NULL;\n-\n-\tdyn-\u003eentries[new_index].lws_hdr_idx \u003d lws_hdr_index;\n-\tdyn-\u003eentries[new_index].hdr_len \u003d hdr_len;\n-\n-\tdyn-\u003evirtual_payload_usage +\u003d hdr_len + len;\n-\n-\tlwsl_info(\u0022%s: index %ld: lws_hdr_index 0x%x, hdr len %d, '%s' len %d\u005cn\u0022,\n-\t\t __func__, (long)ARRAY_SIZE(static_token),\n-\t\t lws_hdr_index, hdr_len, dyn-\u003eentries[new_index].value ?\n-\t\t\t\t dyn-\u003eentries[new_index].value : \u0022null\u0022, len);\n-\n-\tdyn-\u003epos \u003d (dyn-\u003epos + 1) % dyn-\u003enum_entries;\n-\n-\tlws_h2_dynamic_table_dump(wsi);\n-\n-\treturn 0;\n-}\n-\n-int\n-lws_hpack_dynamic_size(struct lws *wsi, int size)\n-{\n-\tstruct hpack_dynamic_table *dyn;\n-\tstruct hpack_dt_entry *dte;\n-\tstruct lws *nwsi;\n-\tint min, n \u003d 0, m;\n-\n-\t/*\n-\t * \u0022size\u0022 here is coming from the http/2 SETTING\n-\t * SETTINGS_HEADER_TABLE_SIZE. This is a (virtual, in our case)\n-\t * linear buffer containing dynamic header names and values... when it\n-\t * is full, old entries are evicted.\n-\t *\n-\t * We encode the header as an lws_hdr_idx, which is all the rest of\n-\t * lws cares about; if there is no matching header we store an empty\n-\t * entry in the dyn table as a placeholder.\n-\t *\n-\t * So to make the two systems work together we keep an accounting of\n-\t * what we are using to decide when to evict... we must only evict\n-\t * things when the remote peer's accounting also makes him feel he\n-\t * should evict something.\n-\t */\n-\n-\tnwsi \u003d lws_get_network_wsi(wsi);\n-\tif (!nwsi-\u003eu.h2.h2n)\n-\t\tgoto bail;\n-\n-\tdyn \u003d \u0026nwsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n-\tlwsl_info(\u0022%s: from %d to %d\u005cn\u0022, __func__, (int)dyn-\u003enum_entries, size);\n-\n-\tif (size \u003e nwsi-\u003eu.h2.h2n-\u003eset.s[H2SET_HEADER_TABLE_SIZE]) {\n-\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n-\t\t\t\u0022Asked for header table bigger than we told\u0022);\n-\t\tgoto bail;\n-\t}\n-\n-\tdyn-\u003evirtual_payload_max \u003d size;\n-\n-\tsize \u003d size / 8;\n-\tmin \u003d size;\n-\tif (min \u003e dyn-\u003eused_entries)\n-\t\tmin \u003d dyn-\u003eused_entries;\n-\n-\tif (size \u003d\u003d dyn-\u003enum_entries)\n-\t\treturn 0;\n-\n-\tif (dyn-\u003enum_entries \u003c min)\n-\t\tmin \u003d dyn-\u003enum_entries;\n-\n-\tdte \u003d lws_zalloc(sizeof(*dte) * (size + 1), \u0022dynamic table entries\u0022);\n-\tif (!dte)\n-\t\tgoto bail;\n-\n-\twhile (dyn-\u003evirtual_payload_usage \u0026\u0026 dyn-\u003eused_entries \u0026\u0026\n-\t dyn-\u003evirtual_payload_usage \u003e dyn-\u003evirtual_payload_max) {\n-\t\tn \u003d (dyn-\u003epos - dyn-\u003eused_entries) % dyn-\u003enum_entries;\n-\t\tif (n \u003c 0)\n-\t\t\tn +\u003d dyn-\u003enum_entries;\n-\t\tlws_dynamic_free(dyn, n);\n-\t}\n-\n-\tif (min \u003e dyn-\u003eused_entries)\n-\t\tmin \u003d dyn-\u003eused_entries;\n-\n-\tif (dyn-\u003eentries) {\n-\t\tfor (n \u003d 0; n \u003c min; n++) {\n-\t\t\tm \u003d (dyn-\u003epos - dyn-\u003eused_entries + n) % dyn-\u003enum_entries;\n-\t\t\tif (m \u003c 0)\n-\t\t\t\tm +\u003d dyn-\u003enum_entries;\n-\t\t\tdte[n] \u003d dyn-\u003eentries[m];\n-\t\t}\n-\n-\t\tlws_free(dyn-\u003eentries);\n-\t}\n-\n-\tdyn-\u003eentries \u003d dte;\n-\tdyn-\u003enum_entries \u003d size;\n-\tdyn-\u003eused_entries \u003d min;\n-\tdyn-\u003epos \u003d min % size;\n-\n-\tlws_h2_dynamic_table_dump(wsi);\n-\n-\treturn 0;\n-\n-bail:\n-\tlwsl_info(\u0022%s: failed to resize to %d\u005cn\u0022, __func__, size);\n-\n-\treturn 1;\n-}\n-\n-void\n-lws_hpack_destroy_dynamic_header(struct lws *wsi)\n-{\n-\tstruct hpack_dynamic_table *dyn;\n-\tint n;\n-\n-\tif (!wsi-\u003eu.h2.h2n)\n-\t\treturn;\n-\n-\tdyn \u003d \u0026wsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n-\n-\tif (!dyn-\u003eentries)\n-\t\treturn;\n-\n-\tfor (n \u003d 0; n \u003c dyn-\u003enum_entries; n++)\n-\t\tif (dyn-\u003eentries[n].value)\n-\t\t\tlws_free_set_NULL(dyn-\u003eentries[n].value);\n-\n-\tlws_free_set_NULL(dyn-\u003eentries);\n-}\n-\n-static int\n-lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)\n-{\n-\tconst char *arg \u003d NULL;\n-\tint len \u003d 0;\n-\tconst char *p \u003d NULL;\n-\tint tok \u003d lws_token_from_index(wsi, idx, \u0026arg, \u0026len, NULL);\n-\n-\tif (tok \u003d\u003d LWS_HPACK_IGNORE_ENTRY) {\n-\t\tlwsl_header(\u0022%s: lws_token says ignore, returning\u005cn\u0022, __func__);\n-\t\treturn 0;\n-\t}\n-\n-\tif (tok \u003d\u003d -1) {\n-\t\tlwsl_info(\u0022%s: idx %d mapped to tok %d\u005cn\u0022, __func__, idx, tok);\n-\t\treturn 1;\n-\t}\n-\n-\tif (arg) {\n-\t\t/* dynamic result */\n-\t\tif (known_token \u003e 0)\n-\t\t\ttok \u003d known_token;\n-\t\tlwsl_header(\u0022%s: dyn: idx %d '%s' tok %d\u005cn\u0022, __func__, idx, arg,\n-\t\t\t tok);\n-\t} else\n-\t\tlwsl_header(\u0022writing indexed hdr %d (tok %d '%s')\u005cn\u0022, idx, tok,\n-\t\t\t\tlws_token_to_string(tok));\n-\n-\tif (tok \u003d\u003d LWS_HPACK_IGNORE_ENTRY)\n-\t\treturn 0;\n-\n-\tif (arg)\n-\t\tp \u003d arg;\n-\n-\tif (idx \u003c ARRAY_SIZE(http2_canned))\n-\t\tp \u003d http2_canned[idx];\n-\n-\tif (lws_frag_start(wsi, tok))\n-\t\treturn 1;\n-\n-\tif (p)\n-\t\twhile (*p \u0026\u0026 len--)\n-\t\t\tif (lws_frag_append(wsi, *p++))\n-\t\t\t\treturn 1;\n-\n-\tif (lws_frag_end(wsi))\n-\t\treturn 1;\n-\n-\tlws_dump_header(wsi, tok);\n-\n-\treturn 0;\n-}\n-\n-int lws_hpack_interpret(struct lws *wsi, unsigned char c)\n-{\n-\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n-\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eu.h2.h2n;\n-\tstruct allocated_headers *ah \u003d wsi-\u003eu.h2.http.ah;\n-\tunsigned int prev;\n-\tunsigned char c1;\n-\tint n, m;\n-\n-\tif (!h2n)\n-\t\treturn -1;\n-\n-\t/*\n-\t * HPKT_INDEXED_HDR_7\t\t 1xxxxxxx: just \u0022header field\u0022\n-\t * HPKT_INDEXED_HDR_6_VALUE_INCR 01xxxxxx: NEW indexed hdr + val\n-\t * HPKT_LITERAL_HDR_VALUE_INCR\t 01000000: NEW literal hdr + val\n-\t * HPKT_INDEXED_HDR_4_VALUE\t 0000xxxx: indexed hdr + val\n-\t * HPKT_INDEXED_HDR_4_VALUE_NEVER 0001xxxx: NEVER NEW indexed hdr + val\n-\t * HPKT_LITERAL_HDR_VALUE\t 00000000: literal hdr + val\n-\t * HPKT_LITERAL_HDR_VALUE_NEVER\t 00010000: NEVER NEW literal hdr + val\n-\t */\n-\tswitch (h2n-\u003ehpack) {\n-\n-\tcase HPKS_TYPE:\n-\t\th2n-\u003eis_first_header_char \u003d 1;\n-\t\th2n-\u003ehuff_pad \u003d 0;\n-\t\th2n-\u003ezero_huff_padding \u003d 0;\n-\t\th2n-\u003elast_action_dyntable_resize \u003d 0;\n-\t\th2n-\u003eext_count \u003d 0;\n-\t\th2n-\u003ehpack_hdr_len \u003d 0;\n-\t\th2n-\u003eunknown_header \u003d 0;\n-\t\th2n-\u003eseen_nonpseudoheader \u003d 0;\n-\n-\t\tif (c \u0026 0x80) { /* 1.... indexed header field only */\n-\t\t\t/* just a possibly-extended integer */\n-\t\t\th2n-\u003ehpack_type \u003d HPKT_INDEXED_HDR_7;\n-\t\t\tlwsl_header(\u0022HPKT_INDEXED_HDR_7 hdr %d\u005cn\u0022, c \u0026 0x7f);\n-\t\t\tlws_h2_dynamic_table_dump(wsi);\n-\n-\t\t\th2n-\u003ehdr_idx \u003d c \u0026 0x7f;\n-\t\t\tif ((c \u0026 0x7f) \u003d\u003d 0x7f) {\n-\t\t\t\th2n-\u003ehpack_len \u003d 0;\n-\t\t\t\th2n-\u003ehpack_m \u003d 0x7f;\n-\t\t\t\th2n-\u003ehpack \u003d HPKS_IDX_EXT;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (!h2n-\u003ehdr_idx) {\n-\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n-\t\t\t\t\t \u0022hdr index 0 seen\u0022);\n-\t\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\tlwsl_header(\u0022HPKT_INDEXED_HDR_7: hdr %d\u005cn\u0022, c \u0026 0x7f);\n-\t\t\tif (lws_hpack_use_idx_hdr(wsi, c \u0026 0x7f, -1)) {\n-\t\t\t\tlwsl_header(\u0022%s: idx hdr wr fail\u005cn\u0022, __func__);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\t/* stay at same state */\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (c \u0026 0x40) { /* 01.... indexed or literal header incr idx */\n-\t\t\t/*\n-\t\t\t * [possibly-ext hdr idx (6) | new literal hdr name]\n-\t\t\t * H + possibly-ext value length\n-\t\t\t * literal value\n-\t\t\t */\n-\t\t\th2n-\u003ehdr_idx \u003d 0;\n-\t\t\tif (c \u003d\u003d 0x40) { /* literal header */\n-\t\t\t\tlwsl_header(\u0022 HPKT_LITERAL_HDR_VALUE_INCR\u005cn\u0022);\n-\t\t\t\th2n-\u003ehpack_type \u003d HPKT_LITERAL_HDR_VALUE_INCR;\n-\t\t\t\th2n-\u003evalue \u003d 0;\n-\t\t\t\th2n-\u003ehpack_len \u003d 0;\n-\t\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\t/* indexed header */\n-\t\t\th2n-\u003ehpack_type \u003d HPKT_INDEXED_HDR_6_VALUE_INCR;\n-\t\t\tlwsl_header(\u0022 HPKT_INDEXED_HDR_6_VALUE_INCR (hdr %d)\u005cn\u0022,\n-\t\t\t\t c \u0026 0x3f);\n-\t\t\th2n-\u003ehdr_idx \u003d c \u0026 0x3f;\n-\t\t\tif ((c \u0026 0x3f) \u003d\u003d 0x3f) {\n-\t\t\t\th2n-\u003ehpack_m \u003d 0x3f;\n-\t\t\t\th2n-\u003ehpack_len \u003d 0;\n-\t\t\t\th2n-\u003ehpack \u003d HPKS_IDX_EXT;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\t\th2n-\u003evalue \u003d 1;\n-\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n-\t\t\tif (!h2n-\u003ehdr_idx) {\n-\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n-\t\t\t\t\t \u0022hdr index 0 seen\u0022);\n-\t\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\t}\n-\t\tswitch(c \u0026 0xf0) {\n-\t\tcase 0x10: /* literal header never index */\n-\t\tcase 0: /* literal header without indexing */\n-\t\t\t/*\n-\t\t\t * follows 0x40 except 4-bit hdr idx\n-\t\t\t * and don't add to index\n-\t\t\t */\n-\t\t\tif (c \u003d\u003d 0) { /* literal name */\n-\t\t\t\th2n-\u003ehpack_type \u003d HPKT_LITERAL_HDR_VALUE;\n-\t\t\t\tlwsl_header(\u0022 HPKT_LITERAL_HDR_VALUE\u005cn\u0022);\n-\t\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n-\t\t\t\th2n-\u003evalue \u003d 0;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (c \u003d\u003d 0x10) { /* literal name NEVER */\n-\t\t\t\th2n-\u003ehpack_type \u003d HPKT_LITERAL_HDR_VALUE_NEVER;\n-\t\t\t\tlwsl_header(\u0022 HPKT_LITERAL_HDR_VALUE_NEVER\u005cn\u0022);\n-\t\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n-\t\t\t\th2n-\u003evalue \u003d 0;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tlwsl_header(\u0022indexed\u005cn\u0022);\n-\t\t\t/* indexed name */\n-\t\t\tif (c \u0026 0x10) {\n-\t\t\t\th2n-\u003ehpack_type \u003d HPKT_INDEXED_HDR_4_VALUE_NEVER;\n-\t\t\t\tlwsl_header(\u0022 HPKT_LITERAL_HDR_4_VALUE_NEVER\u005cn\u0022);\n-\t\t\t} else {\n-\t\t\t\th2n-\u003ehpack_type \u003d HPKT_INDEXED_HDR_4_VALUE;\n-\t\t\t\tlwsl_header(\u0022 HPKT_INDEXED_HDR_4_VALUE\u005cn\u0022);\n-\t\t\t}\n-\t\t\th2n-\u003ehdr_idx \u003d 0;\n-\t\t\tif ((c \u0026 0xf) \u003d\u003d 0xf) {\n-\t\t\t\th2n-\u003ehpack_len \u003d c \u0026 0xf;\n-\t\t\t\th2n-\u003ehpack_m \u003d 0xf;\n-\t\t\t\th2n-\u003ehpack_len \u003d 0;\n-\t\t\t\th2n-\u003ehpack \u003d HPKS_IDX_EXT;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\th2n-\u003ehdr_idx \u003d c \u0026 0xf;\n-\t\t\th2n-\u003evalue \u003d 1;\n-\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n-\t\t\tbreak;\n-\n-\t\tcase 0x20:\n-\t\tcase 0x30: /* header table size update */\n-\t\t\t/* possibly-extended size value (5) */\n-\t\t\tlwsl_header(\u0022HPKT_SIZE_5 %x\u005cn\u0022, c \u00260x1f);\n-\t\t\th2n-\u003ehpack_type \u003d HPKT_SIZE_5;\n-\t\t\th2n-\u003ehpack_len \u003d c \u0026 0x1f;\n-\t\t\tif (h2n-\u003ehpack_len \u003d\u003d 0x1f) {\n-\t\t\t\th2n-\u003ehpack_m \u003d 0x1f;\n-\t\t\t\th2n-\u003ehpack_len \u003d 0;\n-\t\t\t\th2n-\u003ehpack \u003d HPKS_IDX_EXT;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\th2n-\u003elast_action_dyntable_resize \u003d 1;\n-\t\t\tif (lws_hpack_dynamic_size(wsi, h2n-\u003ehpack_len))\n-\t\t\t\treturn 1;\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase HPKS_IDX_EXT:\n-\t\th2n-\u003ehpack_len \u003d h2n-\u003ehpack_len |\n-\t\t\t\t ((c \u0026 0x7f) \u003c\u003c h2n-\u003eext_count);\n-\t\th2n-\u003eext_count +\u003d 7;\n-\t\tif (c \u0026 0x80) /* extended int not complete yet */\n-\t\t\tbreak;\n-\n-\t\t/* extended integer done */\n-\t\th2n-\u003ehpack_len +\u003d h2n-\u003ehpack_m;\n-\t\tlwsl_header(\u0022HPKS_IDX_EXT: hpack_len %d\u005cn\u0022, h2n-\u003ehpack_len);\n-\n-\t\tswitch (h2n-\u003ehpack_type) {\n-\t\tcase HPKT_INDEXED_HDR_7:\n-\t\t\tif (lws_hpack_use_idx_hdr(wsi, h2n-\u003ehpack_len,\n-\t\t\t\t\t\t h2n-\u003ehdr_idx)) {\n-\t\t\t\tlwsl_notice(\u0022%s: hd7 use fail\u005cn\u0022, __func__);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\th2n-\u003ehpack \u003d HPKS_TYPE;\n-\t\t\tbreak;\n-\n-\t\tcase HPKT_SIZE_5:\n-\t\t\th2n-\u003elast_action_dyntable_resize \u003d 1;\n-\t\t\tif (lws_hpack_dynamic_size(wsi, h2n-\u003ehpack_len))\n-\t\t\t\treturn 1;\n-\t\t\th2n-\u003ehpack \u003d HPKS_TYPE;\n-\t\t\tbreak;\n-\n-\t\tdefault:\n-\t\t\th2n-\u003ehdr_idx \u003d h2n-\u003ehpack_len;\n-\t\t\tif (!h2n-\u003ehdr_idx) {\n-\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n-\t\t\t\t\t \u0022extended header index was 0\u0022);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\th2n-\u003evalue \u003d 1;\n-\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase HPKS_HLEN: /* [ H | 7+ ] */\n-\t\th2n-\u003ehuff \u003d !!(c \u0026 0x80);\n-\t\th2n-\u003ehpack_pos \u003d 0;\n-\t\th2n-\u003ehpack_len \u003d c \u0026 0x7f;\n-\n-\t\tif (h2n-\u003ehpack_len \u003d\u003d 0x7f) {\n-\t\t\th2n-\u003ehpack_m \u003d 0x7f;\n-\t\t\th2n-\u003ehpack_len \u003d 0;\n-\t\t\th2n-\u003eext_count \u003d 0;\n-\t\t\th2n-\u003ehpack \u003d HPKS_HLEN_EXT;\n-\t\t\tbreak;\n-\t\t}\n-pre_data:\n-\t\th2n-\u003ehpack \u003d HPKS_DATA;\n-\t\tif (!h2n-\u003evalue || !h2n-\u003ehdr_idx) {\n-\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_NAME_PART;\n-\t\t\twsi-\u003eu.hdr.lextable_pos \u003d 0;\n-\t\t\th2n-\u003eunknown_header \u003d 0;\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE ||\n-\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_INCR ||\n-\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_NEVER) {\n-\t\t\tn \u003d wsi-\u003eu.hdr.parser_state;\n-\t\t\tif (n \u003d\u003d 255) {\n-\t\t\t\tn \u003d -1;\n-\t\t\t\th2n-\u003ehdr_idx \u003d -1;\n-\t\t\t} else\n-\t\t\t\th2n-\u003ehdr_idx \u003d 1;\n-\t\t} else {\n-\t\t\tn \u003d lws_token_from_index(wsi, h2n-\u003ehdr_idx, NULL, NULL, NULL);\n-\t\t\tlwsl_header(\u0022 lws_tok_from_idx(%d) says %d\u005cn\u0022,\n-\t\t\t\t h2n-\u003ehdr_idx, n);\n-\t\t}\n-\n-\t\tif (n \u003d\u003d LWS_HPACK_IGNORE_ENTRY || n \u003d\u003d -1)\n-\t\t\th2n-\u003ehdr_idx \u003d LWS_HPACK_IGNORE_ENTRY;\n-\n-\t\tswitch (h2n-\u003ehpack_type) {\n-\t\t/*\n-\t\t * hpack types with literal headers were parsed by the lws\n-\t\t * header SM... on recognition of a known lws header, it does\n-\t\t * the correct lws_frag_start() for us already. Other types\n-\t\t * (ie, indexed header) need us to do it here.\n-\t\t */\n-\t\tcase HPKT_LITERAL_HDR_VALUE_INCR:\n-\t\tcase HPKT_LITERAL_HDR_VALUE:\n-\t\tcase HPKT_LITERAL_HDR_VALUE_NEVER:\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tif (n !\u003d -1 \u0026\u0026 n !\u003d LWS_HPACK_IGNORE_ENTRY \u0026\u0026\n-\t\t\t lws_frag_start(wsi, n)) {\n-\t\t\t\tlwsl_header(\u0022%s: frag start failed\u005cn\u0022, __func__);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase HPKS_HLEN_EXT:\n-\t\th2n-\u003ehpack_len \u003d h2n-\u003ehpack_len |\n-\t\t\t\t ((c \u0026 0x7f) \u003c\u003c h2n-\u003eext_count);\n-\t\th2n-\u003eext_count +\u003d 7;\n-\t\tif (c \u0026 0x80) /* extended integer not complete yet */\n-\t\t\tbreak;\n-\n-\t\th2n-\u003ehpack_len +\u003d h2n-\u003ehpack_m;\n-\t\tgoto pre_data;\n-\n-\tcase HPKS_DATA:\n-\t\t//lwsl_header(\u0022 0x%02X huff %d\u005cn\u0022, c, h2n-\u003ehuff);\n-\t\t\tc1 \u003d c;\n-\n-\t\tfor (n \u003d 0; n \u003c 8; n++) {\n-\t\t\tif (h2n-\u003ehuff) {\n-\t\t\t\tchar b \u003d (c \u003e\u003e 7) \u0026 1;\n-\t\t\t\tprev \u003d h2n-\u003ehpack_pos;\n-\t\t\t\th2n-\u003ehpack_pos \u003d huftable_decode(\n-\t\t\t\t\t\th2n-\u003ehpack_pos, b);\n-\t\t\t\tc \u003c\u003c\u003d 1;\n-\t\t\t\tif (h2n-\u003ehpack_pos \u003d\u003d 0xffff) {\n-\t\t\t\t\tlwsl_notice(\u0022Huffman err\u005cn\u0022);\n-\t\t\t\t\treturn 1;\n-\t\t\t\t}\n-\t\t\t\tif (!(h2n-\u003ehpack_pos \u0026 0x8000)) {\n-\t\t\t\t\tif (!b)\n-\t\t\t\t\t\th2n-\u003ezero_huff_padding \u003d 1;\n-\t\t\t\t\th2n-\u003ehuff_pad++;\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\t\t\t\tc1 \u003d h2n-\u003ehpack_pos \u0026 0x7fff;\n-\t\t\t\th2n-\u003ehpack_pos \u003d 0;\n-\t\t\t\th2n-\u003ehuff_pad \u003d 0;\n-\t\t\t\th2n-\u003ezero_huff_padding \u003d 0;\n-\n-\t\t\t\t/* EOS |11111111|11111111|11111111|111111 */\n-\t\t\t\tif (!c1 \u0026\u0026 prev \u003d\u003d HUFTABLE_0x100_PREV) {\n-\t\t\t\t\tlws_h2_goaway(nwsi,\n-\t\t\t\t\t\tH2_ERR_COMPRESSION_ERROR,\n-\t\t\t\t\t\t\u0022Huffman EOT seen\u0022);\n-\t\t\t\t\treturn 1;\n-\t\t\t\t}\n-\t\t\t} else\n-\t\t\t\tn \u003d 8;\n-\n-\t\t\tif (h2n-\u003evalue) { /* value */\n-\n-\t\t\t\tif (h2n-\u003ehdr_idx \u0026\u0026\n-\t\t\t\t h2n-\u003ehdr_idx !\u003d LWS_HPACK_IGNORE_ENTRY) {\n-\n-\t\t\t\t\tif (ah-\u003ehdr_token_idx \u003d\u003d WSI_TOKEN_HTTP_COLON_PATH) {\n-\n-\t\t\t\t\t\tswitch (lws_parse_urldecode(wsi, \u0026c1)) {\n-\t\t\t\t\t\tcase LPUR_CONTINUE:\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\tcase LPUR_SWALLOW:\n-\t\t\t\t\t\t\tgoto swallow;\n-\t\t\t\t\t\tcase LPUR_EXCESSIVE:\n-\t\t\t\t\t\tcase LPUR_FORBID:\n-\t\t\t\t\t\t\tlws_h2_goaway(nwsi,\n-\t\t\t\t\t\t\t\tH2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t\t\t\t\u0022Evil URI\u0022);\n-\t\t\t\t\t\t\treturn 1;\n-\n-\t\t\t\t\t\tdefault:\n-\t\t\t\t\t\t\treturn -1;\n-\t\t\t\t\t\t}\n-\t\t\t\t\t}\n-\t\t\t\t\tif (lws_frag_append(wsi, c1)) {\n-\t\t\t\t\t\tlwsl_notice(\u0022%s: frag app fail\u005cn\u0022,\n-\t\t\t\t\t\t\t\t\t__func__);\n-\t\t\t\t\t\treturn 1;\n-\t\t\t\t\t}\n-\t\t\t\t} else\n-\t\t\t\t\tlwsl_header(\u0022ignoring %c\u005cn\u0022, c1);\n-\t\t\t} else {\n-\t\t\t\t/*\n-\t\t\t\t * Convert name using existing parser,\n-\t\t\t \t * If h2n-\u003eunknown_header \u003d\u003d 0, result is\n-\t\t\t \t * in wsi-\u003eu.hdr.parser_state\n-\t\t\t \t * using WSI_TOKEN_GET_URI.\n-\t\t\t \t *\n-\t\t\t \t * If unknown header h2n-\u003eunknown_header\n-\t\t\t \t * will be set.\n-\t\t\t \t */\n-\t\t\t\th2n-\u003ehpack_hdr_len++;\n-\t\t\t\tif (h2n-\u003eis_first_header_char) {\n-\t\t\t\t\th2n-\u003eis_first_header_char \u003d 0;\n-\t\t\t\t\th2n-\u003efirst_hdr_char \u003d c1;\n-\t\t\t\t}\n-\t\t\t\tlwsl_header(\u0022parser: %c\u005cn\u0022, c1);\n-\t\t\t\t/* uppercase header names illegal */\n-\t\t\t\tif (c1 \u003e\u003d 'A' \u0026\u0026 c1 \u003c\u003d 'Z') {\n-\t\t\t\t\tlws_h2_goaway(nwsi,\n-\t\t\t\t\t\tH2_ERR_COMPRESSION_ERROR,\n-\t\t\t\t\t\t\u0022Uppercase literal hpack hdr\u0022);\n-\t\t\t\t\treturn 1;\n-\t\t\t\t}\n-\t\t\t\tif (!h2n-\u003eunknown_header \u0026\u0026 lws_parse(wsi, c1))\n-\t\t\t\t\th2n-\u003eunknown_header \u003d 1;\n-\t\t\t}\n-swallow:\n-\t\t\t(void)n;\n-\t\t} // for n\n-\n-\t\tif (--h2n-\u003ehpack_len)\n-\t\t\tbreak;\n-\n-\t\t/*\n-\t\t * The header (h2n-\u003evalue \u003d 0) or the payload (h2n-\u003evalue \u003d 1)\n-\t\t * is complete.\n-\t\t */\n-\n-\t\tif (h2n-\u003ehuff \u0026\u0026 (h2n-\u003ehuff_pad \u003e 7 ||\n-\t\t (h2n-\u003ezero_huff_padding \u0026\u0026 h2n-\u003ehuff_pad))) {\n-\t\t\tlwsl_notice(\u0022zero_huff_padding: %d huff_pad: %d\u005cn\u0022,\n-\t\t\t\t h2n-\u003ezero_huff_padding, h2n-\u003ehuff_pad);\n-\t\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n-\t\t\t\t \u0022Huffman padding excessive or wrong\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\tif (!h2n-\u003evalue \u0026\u0026 (\n-\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE ||\n-\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_INCR ||\n-\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_NEVER)) {\n-\t\t\th2n-\u003ehdr_idx \u003d LWS_HPACK_IGNORE_ENTRY;\n-\t\t\tlwsl_header(\u0022wsi-\u003eu.hdr.parser_state: %d\u005cn\u0022,\n-\t\t\t\t wsi-\u003eu.hdr.parser_state);\n-\n-\t\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_NAME_PART) {\n-\t\t\t\t/* h2 headers come without the colon */\n-\t\t\t\tn \u003d lws_parse(wsi, ':');\n-\t\t\t\t(void)n;\n-\t\t\t}\n-\n-\t\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_NAME_PART ||\n-\t\t\t wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_SKIPPING) {\n-\t\t\t\th2n-\u003eunknown_header \u003d 1;\n-\t\t\t\twsi-\u003eu.hdr.parser_state \u003d -1;\n-\t\t\t}\n-\t\t}\n-\n-\t\tn \u003d 8;\n-\n-\t\t/* we have the header */\n-\t\tif (!h2n-\u003evalue) {\n-\t\t\th2n-\u003evalue \u003d 1;\n-\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n-\t\t\th2n-\u003ehuff_pad \u003d 0;\n-\t\t\th2n-\u003ezero_huff_padding \u003d 0;\n-\t\t\th2n-\u003eext_count \u003d 0;\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\t/*\n-\t\t * we have got both the header and value\n-\t\t */\n-\n-\t\tswitch (h2n-\u003ehpack_type) {\n-\t\t/*\n-\t\t * These are the only two that insert to the dyntable\n-\t\t */\n-\t\t/* NEW indexed hdr with value */\n-\t\tcase HPKT_INDEXED_HDR_6_VALUE_INCR:\n-\t\t\t/* header length is determined by known index */\n-\t\t\tm \u003d lws_token_from_index(wsi, h2n-\u003ehdr_idx, NULL, NULL,\n-\t\t\t\t\t\u0026h2n-\u003ehpack_hdr_len);\n-\t\t\tgoto add_it;\n-\t\t/* NEW literal hdr with value */\n-\t\tcase HPKT_LITERAL_HDR_VALUE_INCR:\n-\t\t\t/*\n-\t\t\t * hdr is a new literal, so length is already in\n-\t\t\t * h2n-\u003ehpack_hdr_len\n-\t\t\t */\n-\t\t\tm \u003d wsi-\u003eu.hdr.parser_state;\n-\t\t\tif (h2n-\u003eunknown_header ||\n-\t\t\t wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_NAME_PART ||\n-\t\t\t wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_SKIPPING) {\n-\t\t\t\tif (h2n-\u003efirst_hdr_char \u003d\u003d ':') {\n-\t\t\t\t\tlwsl_info(\u0022HPKT_LITERAL_HDR_VALUE_INCR: end parser state %d unk hdr %d\u005cn\u0022,\n-\t\t\t\t\t\twsi-\u003eu.hdr.parser_state,\n-\t\t\t\t\t\th2n-\u003eunknown_header);\n-\t\t\t\t\t/* unknown pseudoheaders are illegal */\n-\t\t\t\t\tlws_h2_goaway(nwsi,\n-\t\t\t\t\t\t H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t\t \u0022Unknown pseudoheader\u0022);\n-\t\t\t\t\treturn 1;\n-\t\t\t\t}\n-\t\t\t\tm \u003d LWS_HPACK_IGNORE_ENTRY;\n-\t\t\t}\n-add_it:\n-\t\t\t/*\n-\t\t\t * mark us as having been set at the time of dynamic\n-\t\t\t * token insertion.\n-\t\t\t */\n-\t\t\tah-\u003efrags[ah-\u003enfrag].flags |\u003d 1;\n-\n-\t\t\tif (lws_dynamic_token_insert(wsi, h2n-\u003ehpack_hdr_len, m,\n-\t\t\t\t\t\u0026ah-\u003edata[ah-\u003efrags[ah-\u003enfrag].offset],\n-\t\t\t\t\tah-\u003efrags[ah-\u003enfrag].len)) {\n-\t\t\t\tlwsl_notice(\u0022%s: tok_insert fail\u005cn\u0022, __func__);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tdefault:\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (h2n-\u003ehdr_idx !\u003d LWS_HPACK_IGNORE_ENTRY \u0026\u0026 lws_frag_end(wsi))\n-\t\t\treturn 1;\n-\n-\t\tif (h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE ||\n-\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_INCR ||\n-\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_NEVER) {\n-\t\t\tm \u003d wsi-\u003eu.hdr.parser_state;\n-\t\t\tif (m \u003d\u003d 255)\n-\t\t\t\tm \u003d -1;\n-\t\t} else\n-\t\t\tm \u003d lws_token_from_index(wsi, h2n-\u003ehdr_idx, NULL, NULL, NULL);\n-\t\tif (m !\u003d -1 \u0026\u0026 m !\u003d LWS_HPACK_IGNORE_ENTRY)\n-\t\t\tlws_dump_header(wsi, m);\n-\n-\t\tif (h2n-\u003eseen_nonpseudoheader \u0026\u0026 (\n-\t\t m \u003d\u003d WSI_TOKEN_HTTP_COLON_AUTHORITY ||\n-\t\t m \u003d\u003d WSI_TOKEN_HTTP_COLON_METHOD ||\n-\t\t m \u003d\u003d WSI_TOKEN_HTTP_COLON_PATH ||\n-\t\t m \u003d\u003d WSI_TOKEN_HTTP_COLON_SCHEME)) {\n-\t\t\t/*\n-\t\t\t * it's not legal to see a\n-\t\t\t * pseudoheader after normal\n-\t\t\t * headers\n-\t\t\t */\n-\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\u0022Pseudoheader after normal hdrs\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\tif (m !\u003d WSI_TOKEN_HTTP_COLON_AUTHORITY \u0026\u0026\n-\t\t m !\u003d WSI_TOKEN_HTTP_COLON_METHOD \u0026\u0026\n-\t\t m !\u003d WSI_TOKEN_HTTP_COLON_PATH \u0026\u0026\n-\t\t m !\u003d WSI_TOKEN_HTTP_COLON_SCHEME)\n-\t\t\th2n-\u003eseen_nonpseudoheader \u003d 1;\n-\n-\t\th2n-\u003eis_first_header_char \u003d 1;\n-\t\th2n-\u003ehpack \u003d HPKS_TYPE;\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static int\n-lws_h2_num_start(int starting_bits, unsigned long num)\n-{\n-\tint mask \u003d (1 \u003c\u003c starting_bits) - 1;\n-\n-\tif (num \u003c mask)\n-\t\treturn (int)num;\n-\n-\treturn mask;\n-}\n-\n-static int\n-lws_h2_num(int starting_bits, unsigned long num,\n-\t\t\t unsigned char **p, unsigned char *end)\n-{\n-\tint mask \u003d (1 \u003c\u003c starting_bits) - 1;\n-\n-\tif (num \u003c mask)\n-\t\treturn 0;\n-\n-\tnum -\u003d mask;\n-\tdo {\n-\t\tif (num \u003e 127)\n-\t\t\t*((*p)++) \u003d 0x80 | (num \u0026 0x7f);\n-\t\telse\n-\t\t\t*((*p)++) \u003d 0x00 | (num \u0026 0x7f);\n-\t\tif (*p \u003e\u003d end)\n-\t\t\treturn 1;\n-\t\tnum \u003e\u003e\u003d 7;\n-\t} while (num);\n-\n-\treturn 0;\n-}\n-\n-int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name,\n-\t\t\t\t const unsigned char *value, int length,\n-\t\t\t\t unsigned char **p, unsigned char *end)\n-{\n-\tint len;\n-\n-\tlwsl_header(\u0022%s: %p %s:%s\u005cn\u0022, __func__, *p, name, value);\n-\n-\tlen \u003d strlen((char *)name);\n-\tif (len)\n-\t\tif (name[len - 1] \u003d\u003d ':')\n-\t\t\tlen--;\n-\n-\tif (wsi-\u003ehttp2_substream \u0026\u0026 !strncmp((const char *)name,\n-\t\t\t\t\t \u0022transfer-encoding\u0022, len)) {\n-\t\tlwsl_header(\u0022rejecting %s\u005cn\u0022, name);\n-\n-\t\treturn 0;\n-\t}\n-\n-\tif (end - *p \u003c len + length + 8)\n-\t\treturn 1;\n-\n-\t*((*p)++) \u003d 0; /* literal hdr, literal name, */\n-\n-\t*((*p)++) \u003d 0 | lws_h2_num_start(7, len); /* non-HUF */\n-\tif (lws_h2_num(7, len, p, end))\n-\t\treturn 1;\n-\tmemcpy(*p, name, len);\n-\t*p +\u003d len;\n-\n-\t*((*p)++) \u003d 0 | lws_h2_num_start(7, length); /* non-HUF */\n-\tif (lws_h2_num(7, length, p, end))\n-\t\treturn 1;\n-\n-\tmemcpy(*p, value, length);\n-\t*p +\u003d length;\n-\n-\t//lwsl_hexdump(op, *p -op);\n-\n-\treturn 0;\n-}\n-\n-int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token,\n-\t\t\t\t const unsigned char *value, int length,\n-\t\t\t\t unsigned char **p, unsigned char *end)\n-{\n-\tconst unsigned char *name;\n-\n-\tname \u003d lws_token_to_string(token);\n-\tif (!name)\n-\t\treturn 1;\n-\n-\treturn lws_add_http2_header_by_name(wsi, name, value, length, p, end);\n-}\n-\n-int lws_add_http2_header_status(struct lws *wsi, unsigned int code,\n-\t\t\t\tunsigned char **p, unsigned char *end)\n-{\n-\tunsigned char status[10];\n-\tint n;\n-\n-\twsi-\u003eu.h2.send_END_STREAM \u003d 0; // !!(code \u003e\u003d 400);\n-\n-\tn \u003d sprintf((char *)status, \u0022%u\u0022, code);\n-\tif (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,\n-\t\t\t\t\t status, n, p, end))\n-\n-\t\treturn 1;\n-\n-\treturn 0;\n-}\ndiff --git a/lib/http2.c b/lib/http2.c\ndeleted file mode 100644\nindex 560f414..0000000\n--- a/lib/http2.c\n+++ /dev/null\n@@ -1,1573 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-/*\n- * bitmap of control messages that are valid to receive for each http2 state\n- */\n-\n-static const uint16_t http2_rx_validity[] \u003d {\n-\t/* LWS_H2S_IDLE */\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n-//\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE)| /* ignore */\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION),\n-\t/* LWS_H2S_RESERVED_LOCAL */\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE),\n-\t/* LWS_H2S_RESERVED_REMOTE */\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY),\n-\t/* LWS_H2S_OPEN */\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_DATA) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PUSH_PROMISE) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PING) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_GOAWAY) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION),\n-\t/* LWS_H2S_HALF_CLOSED_REMOTE */\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM),\n-\t/* LWS_H2S_HALF_CLOSED_LOCAL */\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_DATA) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PUSH_PROMISE) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PING) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_GOAWAY) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION),\n-\t/* LWS_H2S_CLOSED */\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n-\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM),\n-};\n-\n-static const char *preface \u003d \u0022PRI * HTTP/2.0\u005cx0d\u005cx0a\u005cx0d\u005cx0aSM\u005cx0d\u005cx0a\u005cx0d\u005cx0a\u0022;\n-\n-static const char * const h2_state_names[] \u003d {\n-\t\u0022LWS_H2S_IDLE\u0022,\n-\t\u0022LWS_H2S_RESERVED_LOCAL\u0022,\n-\t\u0022LWS_H2S_RESERVED_REMOTE\u0022,\n-\t\u0022LWS_H2S_OPEN\u0022,\n-\t\u0022LWS_H2S_HALF_CLOSED_REMOTE\u0022,\n-\t\u0022LWS_H2S_HALF_CLOSED_LOCAL\u0022,\n-\t\u0022LWS_H2S_CLOSED\u0022,\n-};\n-\n-#if 0\n-static const char * const h2_setting_names[] \u003d {\n-\t\u0022\u0022,\n-\t\u0022H2SET_HEADER_TABLE_SIZE\u0022,\n-\t\u0022H2SET_ENABLE_PUSH\u0022,\n-\t\u0022H2SET_MAX_CONCURRENT_STREAMS\u0022,\n-\t\u0022H2SET_INITIAL_WINDOW_SIZE\u0022,\n-\t\u0022H2SET_MAX_FRAME_SIZE\u0022,\n-\t\u0022H2SET_MAX_HEADER_LIST_SIZE\u0022,\n-};\n-\n-void\n-lws_h2_dump_settings(struct http2_settings *set)\n-{\n-\tint n;\n-\n-\tfor (n \u003d 1; n \u003c H2SET_COUNT; n++)\n-\t\tlwsl_notice(\u0022 %30s: %10d\u005cn\u0022, h2_setting_names[n], set-\u003es[n]);\n-}\n-#else\n-void\n-lws_h2_dump_settings(struct http2_settings *set)\n-{\n-}\n-#endif\n-\n-void lws_h2_init(struct lws *wsi)\n-{\n-\twsi-\u003eu.h2.h2n-\u003eset \u003d wsi-\u003evhost-\u003eset;\n-}\n-\n-static void\n-lws_h2_state(struct lws *wsi, enum lws_h2_states s)\n-{\n-\tif (!wsi)\n-\t\treturn;\n-\tlwsl_info(\u0022%s: wsi %p: state %s -\u003e %s\u005cn\u0022, __func__, wsi,\n-\t\t\th2_state_names[wsi-\u003eu.h2.h2_state],\n-\t\t\th2_state_names[s]);\n-\twsi-\u003eu.h2.h2_state \u003d (uint8_t)s;\n-}\n-\n-struct lws *\n-lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,\n-\t\t\t unsigned int sid)\n-{\n-\tstruct lws *wsi;\n-\tstruct lws *nwsi \u003d lws_get_network_wsi(parent_wsi);\n-\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eu.h2.h2n;\n-\n-\t/*\n-\t * The identifier of a newly established stream MUST be numerically\n- \t * greater than all streams that the initiating endpoint has opened or\n- \t * reserved. This governs streams that are opened using a HEADERS frame\n- \t * and streams that are reserved using PUSH_PROMISE. An endpoint that\n- \t * receives an unexpected stream identifier MUST respond with a\n- \t * connection error (Section 5.4.1) of type PROTOCOL_ERROR.\n-\t */\n-\tif (sid \u003c\u003d h2n-\u003ehighest_sid_opened) {\n-\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, \u0022Bad sid\u0022);\n-\t\treturn NULL;\n-\t}\n-\n-\t/* no more children allowed by parent */\n-\tif (parent_wsi-\u003eu.h2.child_count + 1 \u003e\n-\t parent_wsi-\u003eu.h2.h2n-\u003eset.s[H2SET_MAX_CONCURRENT_STREAMS]) {\n-\t\tlwsl_notice(\u0022reached concurrent stream limit\u005cn\u0022);\n-\t\treturn NULL;\n-\t}\n-\twsi \u003d lws_create_new_server_wsi(vh);\n-\tif (!wsi) {\n-\t\tlwsl_notice(\u0022new server wsi failed (vh %p)\u005cn\u0022, vh);\n-\t\treturn NULL;\n-\t}\n-\n-\th2n-\u003ehighest_sid_opened \u003d sid;\n-\twsi-\u003eu.h2.my_sid \u003d sid;\n-\twsi-\u003ehttp2_substream \u003d 1;\n-\n-\twsi-\u003eu.h2.parent_wsi \u003d parent_wsi;\n-\t/* new guy's sibling is whoever was the first child before */\n-\twsi-\u003eu.h2.sibling_list \u003d parent_wsi-\u003eu.h2.child_list;\n-\t/* first child is now the new guy */\n-\tparent_wsi-\u003eu.h2.child_list \u003d wsi;\n-\tparent_wsi-\u003eu.h2.child_count++;\n-\n-\twsi-\u003eu.h2.my_priority \u003d 16;\n-\twsi-\u003eu.h2.tx_cr \u003d nwsi-\u003eu.h2.h2n-\u003eset.s[H2SET_INITIAL_WINDOW_SIZE];\n-\twsi-\u003eu.h2.peer_tx_cr_est \u003d nwsi-\u003evhost-\u003eset.s[H2SET_INITIAL_WINDOW_SIZE];\n-\n-\twsi-\u003estate \u003d LWSS_HTTP2_ESTABLISHED;\n-\twsi-\u003emode \u003d parent_wsi-\u003emode;\n-\n-\twsi-\u003eprotocol \u003d \u0026vh-\u003eprotocols[0];\n-\tif (lws_ensure_user_space(wsi))\n-\t\tgoto bail1;\n-\n-\twsi-\u003evhost-\u003econn_stats.h2_subs++;\n-\n-\tlwsl_info(\u0022%s: %p new ch %p, sid %d, usersp\u003d%p, tx cr %d, peer_credit %d (nwsi tx_cr %d)\u005cn\u0022,\n-\t\t __func__, parent_wsi, wsi, sid, wsi-\u003euser_space,\n-\t\t wsi-\u003eu.h2.tx_cr, wsi-\u003eu.h2.peer_tx_cr_est, nwsi-\u003eu.h2.tx_cr);\n-\n-\treturn wsi;\n-\n-bail1:\n-\t/* undo the insert */\n-\tparent_wsi-\u003eu.h2.child_list \u003d wsi-\u003eu.h2.sibling_list;\n-\tparent_wsi-\u003eu.h2.child_count--;\n-\n-\tif (wsi-\u003euser_space)\n-\t\tlws_free_set_NULL(wsi-\u003euser_space);\n-\tvh-\u003eprotocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);\n-\tlws_free(wsi);\n-\n-\treturn NULL;\n-}\n-\n-struct lws *\n-lws_h2_wsi_from_id(struct lws *parent_wsi, unsigned int sid)\n-{\n-\tlws_start_foreach_ll(struct lws *, wsi, parent_wsi-\u003eu.h2.child_list) {\n-\t\tif (wsi-\u003eu.h2.my_sid \u003d\u003d sid)\n-\t\t\treturn wsi;\n-\t} lws_end_foreach_ll(wsi, u.h2.sibling_list);\n-\n-\treturn NULL;\n-}\n-\n-int lws_remove_server_child_wsi(struct lws_context *context, struct lws *wsi)\n-{\n-\tlws_start_foreach_llp(struct lws **, w, wsi-\u003eu.h2.child_list) {\n-\t\tif (*w \u003d\u003d wsi) {\n-\t\t\t*w \u003d wsi-\u003eu.h2.sibling_list;\n-\t\t\t(wsi-\u003eu.h2.parent_wsi)-\u003eu.h2.child_count--;\n-\t\t\treturn 0;\n-\t\t}\n-\t} lws_end_foreach_llp(w, u.h2.sibling_list);\n-\n-\tlwsl_err(\u0022%s: can't find %p\u005cn\u0022, __func__, wsi);\n-\n-\treturn 1;\n-}\n-\n-void\n-lws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pps)\n-{\n-\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n-\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eu.h2.h2n;\n-\n-\tpps-\u003enext \u003d h2n-\u003epps;\n-\th2n-\u003epps \u003d pps;\n-\tlws_rx_flow_control(wsi, LWS_RXFLOW_REASON_APPLIES_DISABLE |\n-\t\t\t\t LWS_RXFLOW_REASON_H2_PPS_PENDING);\n-\tlws_callback_on_writable(wsi);\n-}\n-\n-static struct lws_h2_protocol_send *\n-lws_h2_new_pps(enum lws_h2_protocol_send_type type)\n-{\n-\tstruct lws_h2_protocol_send *pps \u003d lws_malloc(sizeof(*pps), \u0022pps\u0022);\n-\n-\tif (pps)\n-\t\tpps-\u003etype \u003d type;\n-\n-\treturn pps;\n-}\n-\n-int\n-lws_h2_goaway(struct lws *wsi, uint32_t err, const char *reason)\n-{\n-\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n-\tstruct lws_h2_protocol_send *pps;\n-\n-\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n-\t\treturn 0;\n-\n-\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_GOAWAY);\n-\tif (!pps)\n-\t\treturn 1;\n-\n-\tlwsl_info(\u0022%s: %p: ERR 0x%x, '%s'\u005cn\u0022, __func__, wsi, err, reason);\n-\n-\tpps-\u003eu.ga.err \u003d err;\n-\tstrncpy(pps-\u003eu.ga.str, reason, sizeof(pps-\u003eu.ga.str) - 1);\n-\tpps-\u003eu.ga.str[sizeof(pps-\u003eu.ga.str) - 1] \u003d '\u005c0';\n-\tlws_pps_schedule(wsi, pps);\n-\n-\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n-\n-\treturn 0;\n-}\n-\n-int\n-lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason)\n-{\n-\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n-\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eu.h2.h2n;\n-\tstruct lws_h2_protocol_send *pps;\n-\n-\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n-\t\treturn 0;\n-\n-\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_RST_STREAM);\n-\tif (!pps)\n-\t\treturn 1;\n-\n-\tlwsl_info(\u0022%s: RST_STREAM 0x%x, REASON '%s'\u005cn\u0022, __func__, err, reason);\n-\n-\tpps-\u003eu.rs.sid \u003d h2n-\u003esid;\n-\tpps-\u003eu.rs.err \u003d err;\n-\tlws_pps_schedule(wsi, pps);\n-\n-\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n-\tlws_h2_state(wsi, LWS_H2_STATE_CLOSED);\n-\n-\treturn 0;\n-}\n-\n-int\n-lws_h2_settings(struct lws *wsi, struct http2_settings *settings,\n-\t\t\tunsigned char *buf, int len)\n-{\n-\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n-\tunsigned int a, b;\n-\n-\tif (!len)\n-\t\treturn 0;\n-\n-\tif (len \u003c LWS_H2_SETTINGS_LEN)\n-\t\treturn 1;\n-\n-\twhile (len \u003e\u003d LWS_H2_SETTINGS_LEN) {\n-\t\ta \u003d (buf[0] \u003c\u003c 8) | buf[1];\n-\t\tif (!a || a \u003e\u003d H2SET_COUNT)\n-\t\t\tgoto skip;\n-\t\tb \u003d buf[2] \u003c\u003c 24 | buf[3] \u003c\u003c 16 | buf[4] \u003c\u003c 8 | buf[5];\n-\n-\t\tswitch (a) {\n-\t\tcase H2SET_HEADER_TABLE_SIZE:\n-\t\t\tbreak;\n-\t\tcase H2SET_ENABLE_PUSH:\n-\t\t\tif (b \u003e 1) {\n-\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t\t\u0022ENABLE_PUSH invalid arg\u0022);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\tcase H2SET_MAX_CONCURRENT_STREAMS:\n-\t\t\tbreak;\n-\t\tcase H2SET_INITIAL_WINDOW_SIZE:\n-\t\t\tif (b \u003e 0x7fffffff) {\n-\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_FLOW_CONTROL_ERROR,\n-\t\t\t\t\t\t\u0022Inital Window beyond max\u0022);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\t/*\n-\t\t\t * In addition to changing the flow-control window for\n-\t\t\t * streams that are not yet active, a SETTINGS frame\n-\t\t\t * can alter the initial flow-control window size for\n-\t\t\t * streams with active flow-control windows (that is,\n-\t\t\t * streams in the \u0022open\u0022 or \u0022half-closed (remote)\u0022\n-\t\t\t * state). When the value of\n-\t\t\t * SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver\n-\t\t\t * MUST adjust the size of all stream flow-control\n-\t\t\t * windows that it maintains by the difference between\n-\t\t\t * the new value and the old value.\n-\t\t\t */\n-\n-\t\t\tlws_start_foreach_ll(struct lws *, w,\n-\t\t\t\t\t nwsi-\u003eu.h2.child_list) {\n-\t\t\t\tlwsl_info(\u0022%s: adi child tc cr %d +%d -\u003e %d\u0022,\n-\t\t\t\t\t __func__,\n-\t\t\t\t\t w-\u003eu.h2.tx_cr, b - settings-\u003es[a],\n-\t\t\t\t\t w-\u003eu.h2.tx_cr + b - settings-\u003es[a]);\n-\t\t\t\tw-\u003eu.h2.tx_cr +\u003d b - settings-\u003es[a];\n-\t\t\t\tif (w-\u003eu.h2.tx_cr \u003e 0 \u0026\u0026\n-\t\t\t\t w-\u003eu.h2.tx_cr \u003c\u003d b - settings-\u003es[a])\n-\t\t\t\t\tlws_callback_on_writable(w);\n-\t\t\t} lws_end_foreach_ll(w, u.h2.sibling_list);\n-\n-\t\t\tbreak;\n-\t\tcase H2SET_MAX_FRAME_SIZE:\n-\t\t\tif (b \u003c wsi-\u003evhost-\u003eset.s[H2SET_MAX_FRAME_SIZE]) {\n-\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t \u0022Frame size \u003c initial\u0022);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\tif (b \u003e 0x007fffff) {\n-\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t \u0022Settings Frame size above max\u0022);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\tcase H2SET_MAX_HEADER_LIST_SIZE:\n-\t\t\tbreak;\n-\t\t}\n-\t\tsettings-\u003es[a] \u003d b;\n-\t\tlwsl_info(\u0022http2 settings %d \u003c- 0x%x\u005cn\u0022, a, b);\n-skip:\n-\t\tlen -\u003d LWS_H2_SETTINGS_LEN;\n-\t\tbuf +\u003d LWS_H2_SETTINGS_LEN;\n-\t}\n-\n-\tif (len)\n-\t\treturn 1;\n-\n-\tlws_h2_dump_settings(settings);\n-\n-\treturn 0;\n-}\n-\n-/* RFC7640 Sect 6.9\n- *\n- * The WINDOW_UPDATE frame can be specific to a stream or to the entire\n- * connection. In the former case, the frame's stream identifier\n- * indicates the affected stream; in the latter, the value \u00220\u0022 indicates\n- * that the entire connection is the subject of the frame.\n- *\n- * ...\n- *\n- * Two flow-control windows are applicable: the stream flow-control\n- * window and the connection flow-control window. The sender MUST NOT\n- * send a flow-controlled frame with a length that exceeds the space\n- * available in either of the flow-control windows advertised by the\n- * receiver. Frames with zero length with the END_STREAM flag set (that\n- * is, an empty DATA frame) MAY be sent if there is no available space\n- * in either flow-control window.\n- */\n-\n-int\n-lws_h2_tx_cr_get(struct lws *wsi)\n-{\n-\tint c \u003d wsi-\u003eu.h2.tx_cr;\n-\tstruct lws *nwsi;\n-\n-\tif (!wsi-\u003ehttp2_substream \u0026\u0026 !wsi-\u003eupgraded_to_http2)\n-\t\treturn ~0x80000000;\n-\n-\tnwsi \u003d lws_get_network_wsi(wsi);\n-\n-\tlwsl_info (\u0022%s: %p: own tx credit %d: nwsi credit %d\u005cn\u0022,\n-\t\t __func__, wsi, c, nwsi-\u003eu.h2.tx_cr);\n-\n-\tif (nwsi-\u003eu.h2.tx_cr \u003c c)\n-\t\tc \u003d nwsi-\u003eu.h2.tx_cr;\n-\n-\tif (c \u003c 0)\n-\t\treturn 0;\n-\n-\treturn c;\n-}\n-\n-void\n-lws_h2_tx_cr_consume(struct lws *wsi, int consumed)\n-{\n-\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n-\n-\twsi-\u003eu.h2.tx_cr -\u003d consumed;\n-\n-\tif (nwsi !\u003d wsi)\n-\t\tnwsi-\u003eu.h2.tx_cr -\u003d consumed;\n-}\n-\n-int lws_h2_frame_write(struct lws *wsi, int type, int flags,\n-\t\t unsigned int sid, unsigned int len, unsigned char *buf)\n-{\n-\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n-\tunsigned char *p \u003d \u0026buf[-LWS_H2_FRAME_HEADER_LENGTH];\n-\tint n;\n-\n-\t*p++ \u003d len \u003e\u003e 16;\n-\t*p++ \u003d len \u003e\u003e 8;\n-\t*p++ \u003d len;\n-\t*p++ \u003d type;\n-\t*p++ \u003d flags;\n-\t*p++ \u003d sid \u003e\u003e 24;\n-\t*p++ \u003d sid \u003e\u003e 16;\n-\t*p++ \u003d sid \u003e\u003e 8;\n-\t*p++ \u003d sid;\n-\n-\tlwsl_debug(\u0022%s: %p (eff %p). typ %d, fl 0x%x, sid\u003d%d, len\u003d%d, \u0022\n-\t\t \u0022txcr\u003d%d, nwsi-\u003etxcr\u003d%d\u005cn\u0022, __func__, wsi, nwsi, type, flags,\n-\t\t sid, len, wsi-\u003eu.h2.tx_cr, nwsi-\u003eu.h2.tx_cr);\n-\n-\tif (type \u003d\u003d LWS_H2_FRAME_TYPE_DATA) {\n-\t\tif (wsi-\u003eu.h2.tx_cr \u003c len)\n-\t\t\tlwsl_err(\u0022%s: %p: sending payload len %d\u0022\n-\t\t\t\t \u0022 but tx_cr only %d!\u005cn\u0022, __func__, wsi,\n-\t\t\t\t len, wsi-\u003eu.h2.tx_cr);\n-\t\tlws_h2_tx_cr_consume(wsi, len);\n-\t}\n-\n-\tn \u003d lws_issue_raw(nwsi, \u0026buf[-LWS_H2_FRAME_HEADER_LENGTH],\n-\t\t\t len + LWS_H2_FRAME_HEADER_LENGTH);\n-\tif (n \u003c 0)\n-\t\treturn n;\n-\n-\tif (n \u003e\u003d LWS_H2_FRAME_HEADER_LENGTH)\n-\t\treturn n - LWS_H2_FRAME_HEADER_LENGTH;\n-\n-\treturn n;\n-}\n-\n-static void lws_h2_set_bin(struct lws *wsi, int n, unsigned char *buf)\n-{\n-\t*buf++ \u003d n \u003e\u003e 8;\n-\t*buf++ \u003d n;\n-\t*buf++ \u003d wsi-\u003eu.h2.h2n-\u003eset.s[n] \u003e\u003e 24;\n-\t*buf++ \u003d wsi-\u003eu.h2.h2n-\u003eset.s[n] \u003e\u003e 16;\n-\t*buf++ \u003d wsi-\u003eu.h2.h2n-\u003eset.s[n] \u003e\u003e 8;\n-\t*buf \u003d wsi-\u003eu.h2.h2n-\u003eset.s[n];\n-}\n-\n-int lws_h2_do_pps_send(struct lws *wsi)\n-{\n-\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n-\tstruct lws_h2_protocol_send *pps \u003d NULL;\n-\tstruct lws *cwsi;\n-\tuint8_t set[LWS_PRE + 64], *p \u003d \u0026set[LWS_PRE], *q;\n-\tint n, m \u003d 0;\n-\n-\tif (!h2n)\n-\t\treturn 1;\n-\n-\t/* get the oldest pps */\n-\n-\tlws_start_foreach_llp(struct lws_h2_protocol_send **, pps1, h2n-\u003epps) {\n-\t\tif ((*pps1)-\u003enext \u003d\u003d NULL) { /* we are the oldest in the list */\n-\t\t\tpps \u003d *pps1; /* remove us from the list */\n-\t\t\t*pps1 \u003d NULL;\n-\t\t\tcontinue;\n-\t\t}\n-\t} lws_end_foreach_llp(pps1, next);\n-\n-\tif (!pps)\n-\t\treturn 1;\n-\n-\tlwsl_info(\u0022%s: %p: %d\u005cn\u0022, __func__, wsi, pps-\u003etype);\n-\n-\tswitch (pps-\u003etype) {\n-\n-\tcase LWS_H2_PPS_MY_SETTINGS:\n-\t\t/*\n-\t\t * if any of our settings varies from h2 \u0022default defaults\u0022\n-\t\t * then we must inform the perr\n-\t\t */\n-\t\tfor (n \u003d 1; n \u003c H2SET_COUNT; n++)\n-\t\t\tif (h2n-\u003eset.s[n] !\u003d lws_h2_defaults.s[n]) {\n-\t\t\t\tlwsl_debug(\u0022sending SETTING %d 0x%x\u005cn\u0022, n,\n-\t\t\t\t\t\twsi-\u003eu.h2.h2n-\u003eset.s[n]);\n-\t\t\t\tlws_h2_set_bin(wsi, n, \u0026set[LWS_PRE + m]);\n-\t\t\t\tm +\u003d sizeof(h2n-\u003eone_setting);\n-\t\t\t}\n-\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,\n-\t\t \t\t 0, LWS_H2_STREAM_ID_MASTER, m,\n-\t\t \t\t \u0026set[LWS_PRE]);\n-\t\tif (n !\u003d m) {\n-\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n-\t\t\tgoto bail;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_H2_PPS_ACK_SETTINGS:\n-\t\t/* send ack ... always empty */\n-\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS, 1,\n-\t\t\t\t LWS_H2_STREAM_ID_MASTER, 0, \u0026set[LWS_PRE]);\n-\t\tif (n) {\n-\t\t\tlwsl_err(\u0022ack tells %d\u005cn\u0022, n);\n-\t\t\tgoto bail;\n-\t\t}\n-\t\t/* this is the end of the preface dance then? */\n-\t\tif (wsi-\u003estate \u003d\u003d LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS) {\n-\t\t\twsi-\u003estate \u003d LWSS_HTTP2_ESTABLISHED;\n-\t\t\twsi-\u003eu.http.fop_fd \u003d NULL;\n-\t\t\tif (lws_is_ssl(lws_get_network_wsi(wsi)))\n-\t\t\t\tbreak;\n-\t\t\t/*\n-\t\t\t * we need to treat the headers from the upgrade as the\n-\t\t\t * first job. So these need to get shifted to sid 1.\n-\t\t\t */\n-\t\t\th2n-\u003eswsi \u003d lws_wsi_server_new(wsi-\u003evhost, wsi, 1);\n-\t\t\tif (!h2n-\u003eswsi)\n-\t\t\t\tgoto bail;\n-\n-\t\t\t/* pass on the initial headers to SID 1 */\n-\t\t\th2n-\u003eswsi-\u003eu.http.ah \u003d wsi-\u003eu.http.ah;\n-\t\t\twsi-\u003eu.http.ah \u003d NULL;\n-\n-\t\t\tlwsl_info(\u0022%s: inherited headers %p\u005cn\u0022, __func__,\n-\t\t\t\t h2n-\u003eswsi-\u003eu.http.ah);\n-\t\t\th2n-\u003eswsi-\u003eu.h2.tx_cr \u003d\n-\t\t\t\th2n-\u003eset.s[H2SET_INITIAL_WINDOW_SIZE];\n-\t\t\tlwsl_info(\u0022initial tx credit on conn %p: %d\u005cn\u0022,\n-\t\t\t\t h2n-\u003eswsi, h2n-\u003eswsi-\u003eu.h2.tx_cr);\n-\t\t\th2n-\u003eswsi-\u003eu.h2.initialized \u003d 1;\n-\t\t\t/* demanded by HTTP2 */\n-\t\t\th2n-\u003eswsi-\u003eu.h2.END_STREAM \u003d 1;\n-\t\t\tlwsl_info(\u0022servicing initial http request\u005cn\u0022);\n-\n-\t\t\twsi-\u003evhost-\u003econn_stats.h2_trans++;\n-\n-\t\t\tif (lws_http_action(h2n-\u003eswsi))\n-\t\t\t\tgoto bail;\n-\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\tcase LWS_H2_PPS_PONG:\n-\t\tlwsl_debug(\u0022sending PONG\u005cn\u0022);\n-\t\tmemcpy(\u0026set[LWS_PRE], pps-\u003eu.ping.ping_payload, 8);\n-\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING,\n-\t\t \t\t LWS_H2_FLAG_SETTINGS_ACK,\n-\t\t\t\t LWS_H2_STREAM_ID_MASTER, 8,\n-\t\t\t\t \u0026set[LWS_PRE]);\n-\t\tif (n !\u003d 8) {\n-\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n-\t\t\tgoto bail;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_H2_PPS_GOAWAY:\n-\t\tlwsl_info(\u0022LWS_H2_PPS_GOAWAY\u005cn\u0022);\n-\t\t*p++ \u003d pps-\u003eu.ga.highest_sid \u003e\u003e 24;\n-\t\t*p++ \u003d pps-\u003eu.ga.highest_sid \u003e\u003e 16;\n-\t\t*p++ \u003d pps-\u003eu.ga.highest_sid \u003e\u003e 8;\n-\t\t*p++ \u003d pps-\u003eu.ga.highest_sid;\n-\t\t*p++ \u003d pps-\u003eu.ga.err \u003e\u003e 24;\n-\t\t*p++ \u003d pps-\u003eu.ga.err \u003e\u003e 16;\n-\t\t*p++ \u003d pps-\u003eu.ga.err \u003e\u003e 8;\n-\t\t*p++ \u003d pps-\u003eu.ga.err;\n-\t\tq \u003d (unsigned char *)h2n-\u003egoaway_str;\n-\t\tn \u003d 0;\n-\t\twhile (*q \u0026\u0026 n++ \u003c sizeof(h2n-\u003egoaway_str))\n-\t\t\t*p++ \u003d *q++;\n-\t\th2n-\u003ewe_told_goaway \u003d 1;\n-\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_GOAWAY, 0,\n-\t\t\t\t LWS_H2_STREAM_ID_MASTER,\n-\t\t\t\t p - \u0026set[LWS_PRE], \u0026set[LWS_PRE]);\n-\t\tif (n !\u003d 4) {\n-\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n-\t\t\tgoto bail;\n-\t\t}\n-\t\tgoto bail;\n-\n-\tcase LWS_H2_PPS_RST_STREAM:\n-\t\tlwsl_info(\u0022LWS_H2_PPS_RST_STREAM\u005cn\u0022);\n-\t\t*p++ \u003d pps-\u003eu.rs.err \u003e\u003e 24;\n-\t\t*p++ \u003d pps-\u003eu.rs.err \u003e\u003e 16;\n-\t\t*p++ \u003d pps-\u003eu.rs.err \u003e\u003e 8;\n-\t\t*p++ \u003d pps-\u003eu.rs.err;\n-\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_RST_STREAM,\n-\t\t\t\t 0, pps-\u003eu.rs.sid, 4, \u0026set[LWS_PRE]);\n-\t\tif (n !\u003d 4) {\n-\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n-\t\t\tgoto bail;\n-\t\t}\n-\t\tcwsi \u003d lws_h2_wsi_from_id(wsi, pps-\u003eu.rs.sid);\n-\t\tif (cwsi)\n-\t\t\tlws_close_free_wsi(cwsi, 0);\n-\t\tbreak;\n-\n-\tcase LWS_H2_PPS_UPDATE_WINDOW:\n-\t\tlwsl_notice(\u0022LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\u005cn\u0022, pps-\u003eu.update_window.sid, pps-\u003eu.update_window.credit);\n-\t\t*p++ \u003d pps-\u003eu.update_window.credit \u003e\u003e 24;\n-\t\t*p++ \u003d pps-\u003eu.update_window.credit \u003e\u003e 16;\n-\t\t*p++ \u003d pps-\u003eu.update_window.credit \u003e\u003e 8;\n-\t\t*p++ \u003d pps-\u003eu.update_window.credit;\n-\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_WINDOW_UPDATE,\n-\t\t\t\t 0, pps-\u003eu.update_window.sid, 4, \u0026set[LWS_PRE]);\n-\t\tif (n !\u003d 4) {\n-\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n-\t\t\tgoto bail;\n-\t\t}\n-\t\tbreak;\n-\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\n-\tlws_free(pps);\n-\n-\treturn 0;\n-\n-bail:\n-\tlws_free(pps);\n-\n-\treturn 1;\n-}\n-\n-/*\n- * The frame header part has just completely arrived.\n- * Perform actions for frame completion.\n- */\n-static int\n-lws_h2_parse_frame_header(struct lws *wsi)\n-{\n-\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n-\tstruct lws_h2_protocol_send *pps;\n-\tint n;\n-\n-\t/*\n-\t * We just got the frame header\n-\t */\n-\th2n-\u003ecount \u003d 0;\n-\th2n-\u003eswsi \u003d wsi;\n-\t/* b31 is a reserved bit */\n-\th2n-\u003esid \u003d h2n-\u003esid \u0026 0x7fffffff;\n-\n-\tif (h2n-\u003esid \u0026\u0026 !(h2n-\u003esid \u0026 1)) {\n-\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022Even Stream ID\u0022);\n-\n-\t\treturn 0;\n-\t}\n-\n-\t/* let the network wsi live a bit longer if subs are active */\n-\tlws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 10);\n-\n-\t/* let the network wsi live a bit longer if subs are active */\n-\tlws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 10);\n-\n-\tif (h2n-\u003esid)\n-\t\th2n-\u003eswsi \u003d lws_h2_wsi_from_id(wsi, h2n-\u003esid);\n-\n-\tlwsl_info(\u0022%p (%p): fr hdr: typ 0x%x, flags 0x%x, sid 0x%x, len 0x%x\u005cn\u0022,\n-\t\t wsi, h2n-\u003eswsi, h2n-\u003etype, h2n-\u003eflags, h2n-\u003esid,\n-\t\t h2n-\u003elength);\n-\n-\tif (h2n-\u003ewe_told_goaway \u0026\u0026 h2n-\u003esid \u003e h2n-\u003ehighest_sid)\n-\t\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n-\n-\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n-\t\treturn 0;\n-\n-\tif (h2n-\u003elength \u003e h2n-\u003eset.s[H2SET_MAX_FRAME_SIZE]) {\n-\t\t/*\n-\t\t * peer sent us something bigger than we told\n-\t\t * it we would allow\n-\t\t */\n-\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n-\t\t\t \u0022Peer ignored our frame size setting\u0022);\n-\t\treturn 0;\n-\t}\n-\n-\tif (h2n-\u003eswsi)\n-\t\tlwsl_info(\u0022%s: wsi %p, State: %s, received cmd %d\u005cn\u0022,\n-\t\t __func__, h2n-\u003eswsi,\n-\t\t h2_state_names[h2n-\u003eswsi-\u003eu.h2.h2_state], h2n-\u003etype);\n-\telse {\n-\t\t/* if it's data, either way no swsi means CLOSED state */\n-\t\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_DATA) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,\n-\t\t\t\t \u0022Data for nonexistant sid\u0022);\n-\t\t\treturn 0;\n-\t\t}\n-\t\t/* if the sid is credible, treat as wsi for it closed */\n-\t\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid_opened \u0026\u0026\n-\t\t h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_HEADERS \u0026\u0026\n-\t\t h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_PRIORITY) {\n-\t\t\t/* if not credible, reject it */\n-\t\t\tlwsl_info(\u0022%s: wsi %p, No child for sid %d, rx cmd %d\u005cn\u0022,\n-\t\t\t __func__, h2n-\u003eswsi, h2n-\u003esid, h2n-\u003etype);\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,\n-\t\t\t\t \u0022Data for nonexistant sid\u0022);\n-\t\t\treturn 0;\n-\t\t}\n-\t}\n-\n-\tif (h2n-\u003eswsi \u0026\u0026 h2n-\u003esid \u0026\u0026\n-\t !(http2_rx_validity[h2n-\u003eswsi-\u003eu.h2.h2_state] \u0026 (1 \u003c\u003c h2n-\u003etype))) {\n-\t\tlwsl_info(\u0022%s: wsi %p, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\u005cn\u0022,\n-\t\t\t __func__, h2n-\u003eswsi,\n-\t\t\t h2_state_names[h2n-\u003eswsi-\u003eu.h2.h2_state], h2n-\u003etype,\n-\t\t\t http2_rx_validity[h2n-\u003eswsi-\u003eu.h2.h2_state]);\n-\n-\t\tif (h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED ||\n-\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_REMOTE)\n-\t\t\tn \u003d H2_ERR_STREAM_CLOSED;\n-\t\telse\n-\t\t\tn \u003d H2_ERR_PROTOCOL_ERROR;\n-\t\tlws_h2_goaway(wsi, n, \u0022invalid rx for state\u0022);\n-\n-\t\treturn 0;\n-\t}\n-\n-\tif (h2n-\u003econt_exp \u0026\u0026 (h2n-\u003econt_exp_sid !\u003d h2n-\u003esid ||\n-\t\t\t h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_CONTINUATION)) {\n-\t\tlwsl_info(\u0022%s: expected cont on sid %d (got %d on sid %d)\u005cn\u0022,\n-\t\t\t __func__, h2n-\u003econt_exp_sid, h2n-\u003etype, h2n-\u003esid);\n-\t\th2n-\u003econt_exp \u003d 0;\n-\t\tif (h2n-\u003econt_exp_headers)\n-\t\t\tn \u003d H2_ERR_COMPRESSION_ERROR;\n-\t\telse\n-\t\t\tn \u003d H2_ERR_PROTOCOL_ERROR;\n-\t\tlws_h2_goaway(wsi, n, \u0022Continuation hdrs State\u0022);\n-\n-\t\treturn 0;\n-\t}\n-\n-\tswitch (h2n-\u003etype) {\n-\tcase LWS_H2_FRAME_TYPE_DATA:\n-\t\tlwsl_info(\u0022seen incoming LWS_H2_FRAME_TYPE_DATA start\u005cn\u0022);\n-\t\tif (!h2n-\u003esid) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022DATA 0 sid\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tlwsl_info(\u0022Frame header DATA: sid %d\u005cn\u0022, h2n-\u003esid);\n-\n-\t\tif (!h2n-\u003eswsi)\n-\t\t\tbreak;\n-\n-\t\th2n-\u003eswsi-\u003eu.h2.peer_tx_cr_est -\u003d h2n-\u003elength;\n-\t\tlwsl_debug(\u0022 peer_tx_cr_est %d\u005cn\u0022, h2n-\u003eswsi-\u003eu.h2.peer_tx_cr_est);\n-\t\tif (h2n-\u003eswsi-\u003eu.h2.peer_tx_cr_est \u003c 32768) {\n-\t\t\th2n-\u003eswsi-\u003eu.h2.peer_tx_cr_est +\u003d 65536;\n-\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);\n-\t\t\tif (!pps)\n-\t\t\t\treturn 1;\n-\t\t\tpps-\u003eu.update_window.sid \u003d h2n-\u003esid;\n-\t\t\tpps-\u003eu.update_window.credit \u003d 65536;\n-\t\t\tlws_pps_schedule(wsi, pps);\n-\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);\n-\t\t\tif (!pps)\n-\t\t\t\treturn 1;\n-\t\t\tpps-\u003eu.update_window.sid \u003d 0;\n-\t\t\tpps-\u003eu.update_window.credit \u003d 65536;\n-\t\t\tlws_pps_schedule(wsi, pps);\n-\t\t}\n-\n-\t\tif ((\n-\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_REMOTE ||\n-\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED)) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, \u0022conn closed\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\tcase LWS_H2_FRAME_TYPE_PRIORITY:\n-\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_PRIORITY complete frame\u005cn\u0022);\n-\t\tif (!h2n-\u003esid) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t \u0022Priority has 0 sid\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (h2n-\u003elength !\u003d 5) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n-\t\t\t\t \u0022Priority has length other than 5\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\tcase LWS_H2_FRAME_TYPE_PUSH_PROMISE:\n-\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_PUSH_PROMISE complete frame\u005cn\u0022);\n-\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022Server only\u0022);\n-\t\tbreak;\n-\n-\tcase LWS_H2_FRAME_TYPE_GOAWAY:\n-\t\tbreak;\n-\n-\tcase LWS_H2_FRAME_TYPE_RST_STREAM:\n-\t\tif (!h2n-\u003esid)\n-\t\t\treturn 1;\n-\t\tif (!h2n-\u003eswsi) {\n-\t\t\tif (h2n-\u003esid \u003c\u003d h2n-\u003ehighest_sid_opened)\n-\t\t\t\tbreak;\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t \u0022crazy sid on RST_STREAM\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\t\tif (h2n-\u003elength !\u003d 4) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n-\t\t\t\t \u0022RST_STREAM can only be length 4\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n-\t\tbreak;\n-\n-\tcase LWS_H2_FRAME_TYPE_SETTINGS:\n-\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_SETTINGS complete frame\u005cn\u0022);\n-\t\t/* nonzero sid on settings is illegal */\n-\t\tif (h2n-\u003esid) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t \u0022Settings has nonzero sid\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (!(h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK)) {\n-\t\t\tif ((!h2n-\u003elength) || h2n-\u003elength % 6) {\n-\t\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n-\t\t\t\t\t\t \u0022Settings length error\u0022);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tlwsl_info(\u0022scheduled settings ack PPS\u005cn\u0022);\n-\t\t\t/* non-ACK coming in means we must ACK it */\n-\n-\n-\t\t\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n-\t\t\t\treturn 0;\n-\n-\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);\n-\t\t\tif (!pps)\n-\t\t\t\treturn 1;\n-\t\t\tlws_pps_schedule(wsi, pps);\n-\t\t\tbreak;\n-\t\t}\n-\t\t/* came to us with ACK set... not allowed to have payload */\n-\n-\t\tif (h2n-\u003elength) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n-\t\t\t\t \u0022Settings with ACK not allowed payload\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\tcase LWS_H2_FRAME_TYPE_PING:\n-\t\tif (h2n-\u003esid) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t \u0022Ping has nonzero sid\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (h2n-\u003elength !\u003d 8) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n-\t\t\t\t \u0022Ping payload can only be 8\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\tcase LWS_H2_FRAME_TYPE_CONTINUATION:\n-\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_CONTINUATION: sid \u003d %d\u005cn\u0022,\n-\t\t\t h2n-\u003esid);\n-\n-\t\tif (!h2n-\u003econt_exp ||\n-\t\t h2n-\u003econt_exp_sid !\u003d h2n-\u003esid ||\n-\t\t !h2n-\u003esid ||\n-\t\t !h2n-\u003eswsi) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t \u0022unexpected CONTINUATION\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (h2n-\u003eswsi-\u003eu.h2.END_HEADERS) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t \u0022END_HEADERS already seen\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\t/* END_STREAM is in HEADERS, skip resetting it */\n-\t\tgoto update_end_headers;\n-\n-\tcase LWS_H2_FRAME_TYPE_HEADERS:\n-\t\tlwsl_info(\u0022HEADERS: frame header: sid \u003d %d\u005cn\u0022, h2n-\u003esid);\n-\t\tif (!h2n-\u003esid) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022sid 0\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\tif (!h2n-\u003eswsi) {\n-\t\t\t/* no more children allowed by parent */\n-\t\t\tif (wsi-\u003eu.h2.child_count + 1 \u003e\n-\t\t\t wsi-\u003eu.h2.h2n-\u003eset.s[H2SET_MAX_CONCURRENT_STREAMS]) {\n-\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\u0022Another stream not allowed\u0022);\n-\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\n-\t\t\th2n-\u003eswsi \u003d lws_wsi_server_new(wsi-\u003evhost, wsi, h2n-\u003esid);\n-\t\t\tif (!h2n-\u003eswsi) {\n-\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022OOM\u0022);\n-\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t}\n-\n-\t\t/*\n-\t\t * ah needs attaching to child wsi, even though\n-\t\t * we only fill it from network wsi\n-\t\t */\n-\t\tif (!h2n-\u003eswsi-\u003eu.hdr.ah)\n-\t\t\tif (lws_header_table_attach(h2n-\u003eswsi, 0)) {\n-\t\t\t\tlwsl_err(\u0022%s: Failed to get ah\u005cn\u0022, __func__);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\n-\t\t/*\n-\t\t * The first use of a new stream identifier implicitly closes\n-\t\t * all streams in the \u0022idle\u0022 state that might have been\n-\t\t * initiated by that peer with a lower-valued stream identifier.\n-\t\t *\n-\t\t * For example, if a client sends a HEADERS frame on stream 7\n-\t\t * without ever sending a frame on stream 5, then stream 5\n-\t\t * transitions to the \u0022closed\u0022 state when the first frame for\n-\t\t * stream 7 is sent or received.\n-\t\t */\n-\t\tlws_start_foreach_ll(struct lws *, w, wsi-\u003eu.h2.child_list) {\n-\t\t\tif (w-\u003eu.h2.my_sid \u003c h2n-\u003esid \u0026\u0026\n-\t\t\t w-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_IDLE)\n-\t\t\t\tlws_close_free_wsi(w, 0);\n-\t\t} lws_end_foreach_ll(w, u.h2.sibling_list);\n-\n-\n-\t\t/* END_STREAM means after servicing this, close the stream */\n-\t\th2n-\u003eswsi-\u003eu.h2.END_STREAM \u003d !!(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_STREAM);\n-\t\tlwsl_info(\u0022%s: hdr END_STREAM \u003d %d\u005cn\u0022,__func__,\n-\t\t\t h2n-\u003eswsi-\u003eu.h2.END_STREAM);\n-\n-\t\th2n-\u003econt_exp \u003d !(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_HEADERS);\n-\t\th2n-\u003econt_exp_sid \u003d h2n-\u003esid;\n-\t\th2n-\u003econt_exp_headers \u003d 1;\n-\t\th2n-\u003eseen_nonpseudoheader \u003d 0;\n-\t\tlws_header_table_reset(h2n-\u003eswsi, 0);\n-\n-update_end_headers:\n-\t\t/* no END_HEADERS means CONTINUATION must come */\n-\t\th2n-\u003eswsi-\u003eu.h2.END_HEADERS \u003d\n-\t\t\t\t!!(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_HEADERS);\n-\t\tif (h2n-\u003eswsi-\u003eu.h2.END_HEADERS)\n-\t\t\th2n-\u003econt_exp \u003d 0;\n-\t\tlwsl_debug(\u0022END_HEADERS %d\u005cn\u0022, h2n-\u003eswsi-\u003eu.h2.END_HEADERS);\n-\t\tbreak;\n-\n-\tcase LWS_H2_FRAME_TYPE_WINDOW_UPDATE:\n-\t\tif (h2n-\u003elength !\u003d 4) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n-\t\t\t\t \u0022window update frame not 4\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_WINDOW_UPDATE\u005cn\u0022);\n-\t\tbreak;\n-\tdefault:\n-\t\tlwsl_info(\u0022%s: ILLEGAL FRAME TYPE %d\u005cn\u0022, __func__, h2n-\u003etype);\n-\t\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n-\t\tbreak;\n-\t}\n-\tif (h2n-\u003elength \u003d\u003d 0)\n-\t\th2n-\u003eframe_state \u003d 0;\n-\n-\treturn 0;\n-}\n-\n-/*\n- * The last byte of the whole frame has been handled.\n- * Perform actions for frame completion.\n- */\n-static int\n-lws_h2_parse_end_of_frame(struct lws *wsi)\n-{\n-\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n-\tstruct lws_h2_protocol_send *pps;\n-\tstruct lws *eff_wsi \u003d wsi;\n-\tconst char *p;\n-\tint n;\n-\n-\th2n-\u003eframe_state \u003d 0;\n-\th2n-\u003ecount \u003d 0;\n-\n-\tif (h2n-\u003esid)\n-\t\th2n-\u003eswsi \u003d lws_h2_wsi_from_id(wsi, h2n-\u003esid);\n-\n-\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid)\n-\t\th2n-\u003ehighest_sid \u003d h2n-\u003esid;\n-\n-\t/* set our initial window size */\n-\tif (!wsi-\u003eu.h2.initialized) {\n-\t\twsi-\u003eu.h2.tx_cr \u003d h2n-\u003eset.s[H2SET_INITIAL_WINDOW_SIZE];\n-\t\tlwsl_info(\u0022initial tx credit on master %p: %d\u005cn\u0022, wsi,\n-\t\t\t wsi-\u003eu.h2.tx_cr);\n-\t\twsi-\u003eu.h2.initialized \u003d 1;\n-\t}\n-\n-\tif (h2n-\u003ecollected_priority \u0026\u0026 (h2n-\u003edep \u0026 ~(1 \u003c\u003c 31)) \u003d\u003d h2n-\u003esid) {\n-\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022depends on own sid\u0022);\n-\t\treturn 0;\n-\t}\n-\n-\tswitch (h2n-\u003etype) {\n-\tcase LWS_H2_FRAME_TYPE_CONTINUATION:\n-\tcase LWS_H2_FRAME_TYPE_HEADERS:\n-\n-\t\t/* service the http request itself */\n-\n-\t\tif (h2n-\u003elast_action_dyntable_resize) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,\n-\t\t\t\t\u0022dyntable resize last in headers\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (!h2n-\u003eswsi-\u003eu.h2.END_HEADERS) {\n-\t\t\t/* we are not finished yet */\n-\t\t\tlwsl_info(\u0022witholding http action for continuation\u005cn\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\t/* confirm the hpack stream state is reasonable for finishing */\n-\n-\t\tif (h2n-\u003ehpack !\u003d HPKS_TYPE) {\n-\t\t\t/* hpack incomplete */\n-\t\t\tlwsl_info(\u0022hpack incomplete %d (type %d, len %d)\u005cn\u0022,\n-\t\t\t\t h2n-\u003ehpack, h2n-\u003etype, h2n-\u003ehpack_len);\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,\n-\t\t\t\t \u0022hpack incomplete\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\t/* this is the last part of HEADERS */\n-\t\tswitch (h2n-\u003eswsi-\u003eu.h2.h2_state) {\n-\t\tcase LWS_H2_STATE_IDLE:\n-\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_OPEN);\n-\t\t\tbreak;\n-\t\tcase LWS_H2_STATE_RESERVED_REMOTE:\n-\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_HALF_CLOSED_LOCAL);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tlwsl_info(\u0022http req, wsi\u003d%p, h2n-\u003eswsi\u003d%p\u005cn\u0022, wsi, h2n-\u003eswsi);\n-\t\th2n-\u003eswsi-\u003ehdr_parsing_completed \u003d 1;\n-\n-\t\tif (lws_hdr_extant(h2n-\u003eswsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n-\t\t\th2n-\u003eswsi-\u003eu.http.rx_content_length \u003d atoll(\n-\t\t\t\tlws_hdr_simple_ptr(h2n-\u003eswsi,\n-\t\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH));\n-\t\t\th2n-\u003eswsi-\u003eu.http.rx_content_remain \u003d\n-\t\t\t\t\th2n-\u003eswsi-\u003eu.http.rx_content_length;\n-\t\t\tlwsl_info(\u0022setting rx_content_length %lld\u005cn\u0022,\n-\t\t\t\t (long long)h2n-\u003eswsi-\u003eu.http.rx_content_length);\n-\t\t}\n-\n-\t\t{\n-\t\t\tint n \u003d 0, len;\n-\t\t\tchar buf[256];\n-\t\t\tconst unsigned char *c;\n-\n-\t\t\tdo {\n-\t\t\t\tc \u003d lws_token_to_string(n);\n-\t\t\t\tif (!c) {\n-\t\t\t\t\tn++;\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\n-\t\t\t\tlen \u003d lws_hdr_total_length(h2n-\u003eswsi, n);\n-\t\t\t\tif (!len || len \u003e sizeof(buf) - 1) {\n-\t\t\t\t\tn++;\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\n-\t\t\t\tlws_hdr_copy(h2n-\u003eswsi, buf, sizeof buf, n);\n-\t\t\t\tbuf[sizeof(buf) - 1] \u003d '\u005c0';\n-\n-\t\t\t\tlwsl_info(\u0022 %s \u003d %s\u005cn\u0022, (char *)c, buf);\n-\t\t\t\tn++;\n-\t\t\t} while (c);\n-\t\t}\n-\n-\t\tif (h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_REMOTE ||\n-\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,\n-\t\t\t\t \u0022Banning service on CLOSED_REMOTE\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tswitch (h2n-\u003eswsi-\u003eu.h2.h2_state) {\n-\t\tcase LWS_H2_STATE_OPEN:\n-\t\t\tif (h2n-\u003eswsi-\u003eu.h2.END_STREAM)\n-\t\t\t\tlws_h2_state(h2n-\u003eswsi,\n-\t\t\t\t\t LWS_H2_STATE_HALF_CLOSED_REMOTE);\n-\t\t\tbreak;\n-\t\tcase LWS_H2_STATE_HALF_CLOSED_LOCAL:\n-\t\t\tif (h2n-\u003eswsi-\u003eu.h2.END_STREAM)\n-\t\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (!lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_PATH) ||\n-\t\t !lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_METHOD) ||\n-\t\t !lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_SCHEME) ||\n-\t\t lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_STATUS) ||\n-\t\t lws_hdr_extant(h2n-\u003eswsi, WSI_TOKEN_CONNECTION)) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t \u0022Pseudoheader checks\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (lws_hdr_extant(h2n-\u003eswsi, WSI_TOKEN_TE)) {\n-\t\t\tn \u003d lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_TE);\n-\n-\t\t\tif (n !\u003d 8 ||\n-\t\t\t strncmp(lws_hdr_simple_ptr(h2n-\u003eswsi, WSI_TOKEN_TE),\n-\t\t\t\t \u0022trailers\u0022, n)) {\n-\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t \u0022Illegal transfer-encoding\u0022);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\n-\t\tp \u003d lws_hdr_simple_ptr(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_METHOD);\n-\t\tif (!strcmp(p, \u0022POST\u0022))\n-\t\t\th2n-\u003eswsi-\u003eu.hdr.ah-\u003efrag_index[WSI_TOKEN_POST_URI] \u003d\n-\t\t\t\th2n-\u003eswsi-\u003eu.hdr.ah-\u003efrag_index[WSI_TOKEN_HTTP_COLON_PATH];\n-\n-\t\twsi-\u003evhost-\u003econn_stats.h2_trans++;\n-\n-\t\tlwsl_info(\u0022 action start...\u005cn\u0022);\n-\t\tn \u003d lws_http_action(h2n-\u003eswsi);\n-\t\tlwsl_info(\u0022 action result %d (wsi-\u003eu.http.rx_content_remain %lld)\u005cn\u0022, n, h2n-\u003eswsi-\u003eu.http.rx_content_remain);\n-\n-\t\t/*\n-\t\t * Commonly we only managed to start a larger transfer that will\n-\t\t * complete asynchronously. In those cases we will hear about\n-\t\t * END_STREAM going out in the POLLOUT handler.\n-\t\t */\n-\t\tif (n || h2n-\u003eswsi-\u003eu.h2.send_END_STREAM) {\n-\t\t\tlws_close_free_wsi(h2n-\u003eswsi, 0);\n-\t\t\th2n-\u003eswsi \u003d NULL;\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_H2_FRAME_TYPE_DATA:\n-\t\tif (!h2n-\u003eswsi)\n-\t\t\tbreak;\n-\n-\t\tif (lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) \u0026\u0026\n-\t\t h2n-\u003eswsi-\u003eu.h2.END_STREAM \u0026\u0026 h2n-\u003eswsi-\u003eu.http.rx_content_length \u0026\u0026\n-\t\t h2n-\u003eswsi-\u003eu.http.rx_content_remain) {\n-\t\t\tlws_h2_rst_stream(h2n-\u003eswsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t \u0022Not enough rx content\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (h2n-\u003eswsi-\u003eu.h2.END_STREAM \u0026\u0026\n-\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_OPEN)\n-\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_HALF_CLOSED_REMOTE);\n-\n-\t\tif (h2n-\u003eswsi-\u003eu.h2.END_STREAM \u0026\u0026\n-\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_LOCAL)\n-\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n-\t\tbreak;\n-\n-\tcase LWS_H2_FRAME_TYPE_PING:\n-\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK) { // ack\n-\t\t} else {/* they're sending us a ping request */\n-\t\t\tlwsl_info(\u0022rx ping, preparing pong\u005cn\u0022);\n-\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_PONG);\n-\t\t\tif (!pps)\n-\t\t\t\treturn 1;\n-\t\t\tmemcpy(pps-\u003eu.ping.ping_payload, h2n-\u003eping_payload, 8);\n-\t\t\tlws_pps_schedule(wsi, pps);\n-\t\t}\n-\n-\t\tbreak;\n-\n-\tcase LWS_H2_FRAME_TYPE_WINDOW_UPDATE:\n-\t\th2n-\u003ehpack_e_dep \u0026\u003d ~(1 \u003c\u003c 31);\n-\t\tlwsl_info(\u0022WINDOW_UPDATE: sid %d %u (0x%x)\u005cn\u0022, h2n-\u003esid,\n-\t\t\t h2n-\u003ehpack_e_dep, h2n-\u003ehpack_e_dep);\n-\n-\t\tif (h2n-\u003esid)\n-\t\t\teff_wsi \u003d h2n-\u003eswsi;\n-\n-\t\tif (!eff_wsi) {\n-\t\t\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid_opened)\n-\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t \u0022alien sid\u0022);\n-\t\t\tbreak; /* ignore */\n-\t\t}\n-\n-\t\tif ((uint64_t)eff_wsi-\u003eu.h2.tx_cr + (uint64_t)h2n-\u003ehpack_e_dep \u003e\n-\t\t (uint64_t)0x7fffffff) {\n-\t\t\tif (h2n-\u003esid)\n-\t\t\t\tlws_h2_rst_stream(h2n-\u003eswsi,\n-\t\t\t\t\t\t H2_ERR_FLOW_CONTROL_ERROR,\n-\t\t\t\t\t\t \u0022Flow control exceeded max\u0022);\n-\t\t\telse\n-\t\t\t\tlws_h2_goaway(wsi, H2_ERR_FLOW_CONTROL_ERROR,\n-\t\t\t\t\t \u0022Flow control exceeded max\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (!h2n-\u003ehpack_e_dep) {\n-\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t \u0022Zero length window update\u0022);\n-\t\t\tbreak;\n-\t\t}\n-\t\tn \u003d eff_wsi-\u003eu.h2.tx_cr;\n-\t\teff_wsi-\u003eu.h2.tx_cr +\u003d h2n-\u003ehpack_e_dep;\n-\n-\t\tif (n \u003c\u003d 0 \u0026\u0026 eff_wsi-\u003eu.h2.tx_cr \u003c\u003d 0)\n-\t\t\t/* it helps, but won't change sendability for anyone */\n-\t\t\tbreak;\n-\n-\t\t/*\n-\t\t * It did change sendability... for us and any children waiting\n-\t\t * on us... reassess blockage for all children first\n-\t\t */\n-\t\tlws_start_foreach_ll(struct lws *, w, wsi-\u003eu.h2.child_list) {\n-\t\t\tlws_callback_on_writable(w);\n-\t\t} lws_end_foreach_ll(w, u.h2.sibling_list);\n-\n-\t\tif (eff_wsi-\u003eu.h2.skint \u0026\u0026 lws_h2_tx_cr_get(eff_wsi)) {\n-\t\t\tlwsl_info(\u0022%s: %p: skint\u005cn\u0022, __func__, wsi);\n-\t\t\teff_wsi-\u003eu.h2.skint \u003d 0;\n-\t\t\tlws_callback_on_writable(eff_wsi);\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_H2_FRAME_TYPE_GOAWAY:\n-\t\tlwsl_info(\u0022GOAWAY: last sid %d, error 0x%08X, string '%s'\u005cn\u0022,\n-\t\t\t h2n-\u003egoaway_last_sid, h2n-\u003egoaway_err, h2n-\u003egoaway_str);\n-\t\twsi-\u003eu.h2.GOING_AWAY \u003d 1;\n-\n-\t\treturn 1;\n-\n-\tcase LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-int\n-lws_h2_parser(struct lws *wsi, unsigned char c)\n-{\n-\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n-\tstruct lws_h2_protocol_send *pps;\n-\tint n;\n-\n-\tif (!h2n)\n-\t\treturn 1;\n-\n-\tswitch (wsi-\u003estate) {\n-\tcase LWSS_HTTP2_AWAIT_CLIENT_PREFACE:\n-\t\tif (preface[h2n-\u003ecount++] !\u003d c)\n-\t\t\treturn 1;\n-\n-\t\tif (preface[h2n-\u003ecount])\n-\t\t\tbreak;\n-\n-\t\tlwsl_info(\u0022http2: %p: established\u005cn\u0022, wsi);\n-\t\twsi-\u003estate \u003d LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS;\n-\t\th2n-\u003ecount \u003d 0;\n-\t\twsi-\u003eu.h2.tx_cr \u003d 65535;\n-\n-\t\t/*\n-\t\t * we must send a settings frame -- empty one is OK...\n-\t\t * that must be the first thing sent by server\n-\t\t * and the peer must send a SETTINGS with ACK flag...\n-\t\t */\n-\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS);\n-\t\tif (!pps)\n-\t\t\treturn 1;\n-\t\tlws_pps_schedule(wsi, pps);\n-\t\tbreak;\n-\n-\tcase LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS:\n-\tcase LWSS_HTTP2_ESTABLISHED:\n-\t\tif (h2n-\u003eframe_state !\u003d LWS_H2_FRAME_HEADER_LENGTH)\n-\t\t\tgoto try_frame_start;\n-\n-\t\t/*\n-\t\t * post-header, preamble / payload / padding part\n-\t\t */\n-\t\th2n-\u003ecount++;\n-\n-\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_PADDED \u0026\u0026 !h2n-\u003epad_length) {\n-\t\t\t/*\n-\t\t\t * Get the padding count... actual padding is\n-\t\t\t * at the end of the frame.\n-\t\t\t */\n-\t\t\th2n-\u003epadding \u003d c;\n-\t\t\th2n-\u003epad_length \u003d 1;\n-\t\t\th2n-\u003epreamble++;\n-\n-\t\t\tif (h2n-\u003epadding \u003e h2n-\u003elength - 1)\n-\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t \u0022execssive padding\u0022);\n-\t\t\tbreak; /* we consumed this */\n-\t\t}\n-\n-\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_PRIORITY \u0026\u0026\n-\t\t !h2n-\u003ecollected_priority) {\n-\t\t\t/* going to be 5 preamble bytes */\n-\n-\t\t\tlwsl_debug(\u0022PRIORITY FLAG: 0x%x\u005cn\u0022, c);\n-\n-\t\t\tif (h2n-\u003epreamble++ - h2n-\u003epad_length \u003c 4) {\n-\t\t\t\th2n-\u003edep \u003d ((h2n-\u003edep) \u003c\u003c 8) | c;\n-\t\t\t\tbreak; /* we consumed this */\n-\t\t\t}\n-\t\t\th2n-\u003eweight_temp \u003d c;\n-\t\t\th2n-\u003ecollected_priority \u003d 1;\n-\t\t\tlwsl_debug(\u0022PRI FL: dep 0x%x, weight 0x%02X\u005cn\u0022,\n-\t\t\t\t h2n-\u003edep, h2n-\u003eweight_temp);\n-\t\t\tbreak; /* we consumed this */\n-\t\t}\n-\t\tif (h2n-\u003epadding \u0026\u0026 h2n-\u003ecount \u003e (h2n-\u003elength - h2n-\u003epadding)) {\n-\t\t\tif (c) {\n-\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t \u0022nonzero padding\u0022);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tgoto frame_end;\n-\t\t}\n-\n-\t\t/* applies to wsi-\u003eu.h2.swsi which may be wsi */\n-\t\tswitch(h2n-\u003etype) {\n-\n-\t\tcase LWS_H2_FRAME_TYPE_SETTINGS:\n-\t\t\tn \u003d (h2n-\u003ecount - 1 - h2n-\u003epreamble) %\n-\t\t\t LWS_H2_SETTINGS_LEN;\n-\t\t\th2n-\u003eone_setting[n] \u003d c;\n-\t\t\tif (n !\u003d LWS_H2_SETTINGS_LEN - 1)\n-\t\t\t\tbreak;\n-\t\t\tlws_h2_settings(wsi, \u0026h2n-\u003eset, h2n-\u003eone_setting,\n-\t\t\t\t\tLWS_H2_SETTINGS_LEN);\n-\t\t\tbreak;\n-\n-\t\tcase LWS_H2_FRAME_TYPE_CONTINUATION:\n-\t\tcase LWS_H2_FRAME_TYPE_HEADERS:\n-\t\t\tif (!h2n-\u003eswsi)\n-\t\t\t\tbreak;\n-\t\t\tif (lws_hpack_interpret(h2n-\u003eswsi, c)) {\n-\t\t\t\tlwsl_info(\u0022%s: hpack failed\u005cn\u0022, __func__);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tcase LWS_H2_FRAME_TYPE_GOAWAY:\n-\t\t\tswitch (h2n-\u003einside++) {\n-\t\t\tcase 0:\n-\t\t\tcase 1:\n-\t\t\tcase 2:\n-\t\t\tcase 3:\n-\t\t\t\th2n-\u003egoaway_last_sid \u003c\u003c\u003d 8;\n-\t\t\t\th2n-\u003egoaway_last_sid |\u003d c;\n-\t\t\t\th2n-\u003egoaway_str[0] \u003d '\u005c0';\n-\t\t\t\tbreak;\n-\n-\t\t\tcase 4:\n-\t\t\tcase 5:\n-\t\t\tcase 6:\n-\t\t\tcase 7:\n-\t\t\t\th2n-\u003egoaway_err \u003c\u003c\u003d 8;\n-\t\t\t\th2n-\u003egoaway_err |\u003d c;\n-\t\t\t\tbreak;\n-\n-\t\t\tdefault:\n-\t\t\t\tif (h2n-\u003einside - 9 \u003c\n-\t\t\t\t sizeof(h2n-\u003egoaway_str) - 1)\n-\t\t\t\t\th2n-\u003egoaway_str[h2n-\u003einside - 9] \u003d c;\n-\t\t\t\th2n-\u003egoaway_str[sizeof(h2n-\u003egoaway_str) - 1] \u003d '\u005c0';\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tcase LWS_H2_FRAME_TYPE_DATA:\n-\t\t\t//lwsl_notice(\u0022incoming LWS_H2_FRAME_TYPE_DATA content\u005cn\u0022);\n-\t\t\tif (!h2n-\u003eswsi) {\n-\t\t\t\t//lwsl_notice(\u0022data sid %d has no swsi\u005cn\u0022, h2n-\u003esid);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\t\th2n-\u003eswsi-\u003estate \u003d LWSS_HTTP_BODY;\n-\n-\t\t\th2n-\u003einside++;\n-\t\t\t/* because the HTTP_BODY stuff will handle it */\n-\t\t\t//h2n-\u003eswsi-\u003eu.http.rx_content_remain--;\n-\t\t\t//lwsl_info(\u0022remain %lld, %d / %d\u0022,\n-\t\t\t//\t (long long)h2n-\u003eswsi-\u003eu.http.rx_content_remain,\n-\t\t\t//\t h2n-\u003einside, h2n-\u003elength);\n-\t\t\tif (lws_hdr_total_length(h2n-\u003eswsi,\n-\t\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH) \u0026\u0026\n-\t\t\t h2n-\u003eswsi-\u003eu.http.rx_content_length \u0026\u0026\n-\t\t\t h2n-\u003eswsi-\u003eu.http.rx_content_remain \u003d\u003d 1 \u0026\u0026 /* last byte */\n-\t\t\t h2n-\u003einside \u003c h2n-\u003elength) { /* unread data in frame */\n-\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t \u0022More rx than content_length told\u0022);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\t\tn \u003d lws_read(h2n-\u003eswsi, \u0026c, 1);\n-\t\t\tif (n \u003c 0) {\n-\t\t\t//\tlws_h2_rst_stream(wsi, LWS_H2_PPS_RST_STREAM,\n-\t\t\t//\t\t\t \u0022post body done\u0022);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tcase LWS_H2_FRAME_TYPE_PRIORITY:\n-\t\t\tif (h2n-\u003ecount \u003c\u003d 4) {\n-\t\t\t\th2n-\u003edep \u003c\u003c\u003d 8;\n-\t\t\t\th2n-\u003edep |\u003d c;\n-\t\t\t} else {\n-\t\t\t\th2n-\u003eweight_temp \u003d c;\n-\t\t\t\tlwsl_info(\u0022PRIORITY: dep 0x%x, weight 0x%02X\u005cn\u0022,\n-\t\t\t\t\t h2n-\u003edep, h2n-\u003eweight_temp);\n-\n-\t\t\t\tif ((h2n-\u003edep \u0026 ~(1 \u003c\u003c 31)) \u003d\u003d h2n-\u003esid) {\n-\t\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n-\t\t\t\t\t\t \u0022cant depend on own sid\u0022);\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tcase LWS_H2_FRAME_TYPE_RST_STREAM:\n-\t\t\tbreak;\n-\n-\t\tcase LWS_H2_FRAME_TYPE_PUSH_PROMISE:\n-\t\t\tbreak;\n-\n-\t\tcase LWS_H2_FRAME_TYPE_PING:\n-\t\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK) { // ack\n-\t\t\t} else { /* they're sending us a ping request */\n-\t\t\t\tif (h2n-\u003ecount \u003e 8)\n-\t\t\t\t\treturn 1;\n-\t\t\t\th2n-\u003eping_payload[h2n-\u003ecount - 1] \u003d c;\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tcase LWS_H2_FRAME_TYPE_WINDOW_UPDATE:\n-\t\t\th2n-\u003ehpack_e_dep \u003c\u003c\u003d 8;\n-\t\t\th2n-\u003ehpack_e_dep |\u003d c;\n-\t\t\tbreak;\n-\n-\t\tcase LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */\n-\t\t\tbreak;\n-\n-\t\tdefault:\n-\t\t\tlwsl_notice(\u0022%s: unhandled frame type %d\u005cn\u0022,\n-\t\t\t\t __func__, h2n-\u003etype);\n-\n-\t\t\treturn 1;\n-\t\t}\n-\n-frame_end:\n-\t\tif (h2n-\u003ecount !\u003d h2n-\u003elength)\n-\t\t\tbreak;\n-\n-\t\t/*\n-\t\t * end of frame just happened\n-\t\t */\n-\t\tif (lws_h2_parse_end_of_frame(wsi))\n-\t\t\treturn 1;\n-\t\tbreak;\n-\n-try_frame_start:\n-\t\tif (h2n-\u003eframe_state \u003c\u003d 8) {\n-\n-\t\t\tswitch (h2n-\u003eframe_state++) {\n-\t\t\tcase 0:\n-\t\t\t\th2n-\u003epad_length \u003d 0;\n-\t\t\t\th2n-\u003ecollected_priority \u003d 0;\n-\t\t\t\th2n-\u003epadding \u003d 0;\n-\t\t\t\th2n-\u003epreamble \u003d 0;\n-\t\t\t\th2n-\u003elength \u003d c;\n-\t\t\t\th2n-\u003einside \u003d 0;\n-\t\t\t\tbreak;\n-\t\t\tcase 1:\n-\t\t\tcase 2:\n-\t\t\t\th2n-\u003elength \u003c\u003c\u003d 8;\n-\t\t\t\th2n-\u003elength |\u003d c;\n-\t\t\t\tbreak;\n-\t\t\tcase 3:\n-\t\t\t\th2n-\u003etype \u003d c;\n-\t\t\t\tbreak;\n-\t\t\tcase 4:\n-\t\t\t\th2n-\u003eflags \u003d c;\n-\t\t\t\tbreak;\n-\n-\t\t\tcase 5:\n-\t\t\tcase 6:\n-\t\t\tcase 7:\n-\t\t\tcase 8:\n-\t\t\t\th2n-\u003esid \u003c\u003c\u003d 8;\n-\t\t\t\th2n-\u003esid |\u003d c;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tif (h2n-\u003eframe_state \u003d\u003d LWS_H2_FRAME_HEADER_LENGTH)\n-\t\t\tif (lws_h2_parse_frame_header(wsi))\n-\t\t\t\treturn 1;\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-}\n-\ndiff --git a/lib/http2/hpack.c b/lib/http2/hpack.c\nnew file mode 100644\nindex 0000000..eb1e97c\n--- /dev/null\n+++ b/lib/http2/hpack.c\n@@ -0,0 +1,1336 @@\n+/*\n+ * lib/hpack.c\n+ *\n+ * Copyright (C) 2014-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+/*\n+ * Official static header table for HPACK\n+ * +-------+-----------------------------+---------------+\n+ | 1 | :authority | |\n+ | 2 | :method | GET |\n+ | 3 | :method | POST |\n+ | 4 | :path | / |\n+ | 5 | :path | /index.html |\n+ | 6 | :scheme | http |\n+ | 7 | :scheme | https |\n+ | 8 | :status | 200 |\n+ | 9 | :status | 204 |\n+ | 10 | :status | 206 |\n+ | 11 | :status | 304 |\n+ | 12 | :status | 400 |\n+ | 13 | :status | 404 |\n+ | 14 | :status | 500 |\n+ | 15 | accept-charset | |\n+ | 16 | accept-encoding | gzip, deflate |\n+ | 17 | accept-language | |\n+ | 18 | accept-ranges | |\n+ | 19 | accept | |\n+ | 20 | access-control-allow-origin | |\n+ | 21 | age | |\n+ | 22 | allow | |\n+ | 23 | authorization | |\n+ | 24 | cache-control | |\n+ | 25 | content-disposition | |\n+ | 26 | content-encoding | |\n+ | 27 | content-language | |\n+ | 28 | content-length | |\n+ | 29 | content-location | |\n+ | 30 | content-range | |\n+ | 31 | content-type | |\n+ | 32 | cookie | |\n+ | 33 | date | |\n+ | 34 | etag | |\n+ | 35 | expect | |\n+ | 36 | expires | |\n+ | 37 | from | |\n+ | 38 | host | |\n+ | 39 | if-match | |\n+ | 40 | if-modified-since | |\n+ | 41 | if-none-match | |\n+ | 42 | if-range | |\n+ | 43 | if-unmodified-since | |\n+ | 44 | last-modified | |\n+ | 45 | link | |\n+ | 46 | location | |\n+ | 47 | max-forwards | |\n+ | 48 | proxy-authenticate | |\n+ | 49 | proxy-authorization | |\n+ | 50 | range | |\n+ | 51 | referer | |\n+ | 52 | refresh | |\n+ | 53 | retry-after | |\n+ | 54 | server | |\n+ | 55 | set-cookie | |\n+ | 56 | strict-transport-security | |\n+ | 57 | transfer-encoding | |\n+ | 58 | user-agent | |\n+ | 59 | vary | |\n+ | 60 | via | |\n+ | 61 | www-authenticate | |\n+ +-------+-----------------------------+---------------+\n+*/\n+\n+static const uint8_t static_hdr_len[] \u003d {\n+\t\t0, /* starts at 1 */\n+\t\t10, 7, 7, 5, 5, 7, 7, 7, 7, 7,\n+\t\t7, 7, 7, 7, 14, 15, 15, 13, 6, 27,\n+\t\t3, 5, 13, 13, 19, 16, 16, 14, 16, 13,\n+\t\t12, 6, 4, 4, 6, 7, 4, 4, 8, 17,\n+\t\t13, 8, 19, 13, 4, 8, 12, 18, 19,\n+\t\t5, 7, 7, 11, 6, 10, 25, 17, 10, 4,\n+\t\t3, 16\n+};\n+\n+static const unsigned char static_token[] \u003d {\n+\t0,\n+\tWSI_TOKEN_HTTP_COLON_AUTHORITY,\n+\tWSI_TOKEN_HTTP_COLON_METHOD,\n+\tWSI_TOKEN_HTTP_COLON_METHOD,\n+\tWSI_TOKEN_HTTP_COLON_PATH,\n+\tWSI_TOKEN_HTTP_COLON_PATH,\n+\tWSI_TOKEN_HTTP_COLON_SCHEME,\n+\tWSI_TOKEN_HTTP_COLON_SCHEME,\n+\tWSI_TOKEN_HTTP_COLON_STATUS,\n+\tWSI_TOKEN_HTTP_COLON_STATUS,\n+\tWSI_TOKEN_HTTP_COLON_STATUS,\n+\tWSI_TOKEN_HTTP_COLON_STATUS,\n+\tWSI_TOKEN_HTTP_COLON_STATUS,\n+\tWSI_TOKEN_HTTP_COLON_STATUS,\n+\tWSI_TOKEN_HTTP_COLON_STATUS,\n+\tWSI_TOKEN_HTTP_ACCEPT_CHARSET,\n+\tWSI_TOKEN_HTTP_ACCEPT_ENCODING,\n+\tWSI_TOKEN_HTTP_ACCEPT_LANGUAGE,\n+\tWSI_TOKEN_HTTP_ACCEPT_RANGES,\n+\tWSI_TOKEN_HTTP_ACCEPT,\n+\tWSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,\n+\tWSI_TOKEN_HTTP_AGE,\n+\tWSI_TOKEN_HTTP_ALLOW,\n+\tWSI_TOKEN_HTTP_AUTHORIZATION,\n+\tWSI_TOKEN_HTTP_CACHE_CONTROL,\n+\tWSI_TOKEN_HTTP_CONTENT_DISPOSITION,\n+\tWSI_TOKEN_HTTP_CONTENT_ENCODING,\n+\tWSI_TOKEN_HTTP_CONTENT_LANGUAGE,\n+\tWSI_TOKEN_HTTP_CONTENT_LENGTH,\n+\tWSI_TOKEN_HTTP_CONTENT_LOCATION,\n+\tWSI_TOKEN_HTTP_CONTENT_RANGE,\n+\tWSI_TOKEN_HTTP_CONTENT_TYPE,\n+\tWSI_TOKEN_HTTP_COOKIE,\n+\tWSI_TOKEN_HTTP_DATE,\n+\tWSI_TOKEN_HTTP_ETAG,\n+\tWSI_TOKEN_HTTP_EXPECT,\n+\tWSI_TOKEN_HTTP_EXPIRES,\n+\tWSI_TOKEN_HTTP_FROM,\n+\tWSI_TOKEN_HOST,\n+\tWSI_TOKEN_HTTP_IF_MATCH,\n+\tWSI_TOKEN_HTTP_IF_MODIFIED_SINCE,\n+\tWSI_TOKEN_HTTP_IF_NONE_MATCH,\n+\tWSI_TOKEN_HTTP_IF_RANGE,\n+\tWSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE,\n+\tWSI_TOKEN_HTTP_LAST_MODIFIED,\n+\tWSI_TOKEN_HTTP_LINK,\n+\tWSI_TOKEN_HTTP_LOCATION,\n+\tWSI_TOKEN_HTTP_MAX_FORWARDS,\n+\tWSI_TOKEN_HTTP_PROXY_AUTHENTICATE,\n+\tWSI_TOKEN_HTTP_PROXY_AUTHORIZATION,\n+\tWSI_TOKEN_HTTP_RANGE,\n+\tWSI_TOKEN_HTTP_REFERER,\n+\tWSI_TOKEN_HTTP_REFRESH,\n+\tWSI_TOKEN_HTTP_RETRY_AFTER,\n+\tWSI_TOKEN_HTTP_SERVER,\n+\tWSI_TOKEN_HTTP_SET_COOKIE,\n+\tWSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY,\n+\tWSI_TOKEN_HTTP_TRANSFER_ENCODING,\n+\tWSI_TOKEN_HTTP_USER_AGENT,\n+\tWSI_TOKEN_HTTP_VARY,\n+\tWSI_TOKEN_HTTP_VIA,\n+\tWSI_TOKEN_HTTP_WWW_AUTHENTICATE,\n+};\n+\n+/* some of the entries imply values as well as header names */\n+\n+static const char * const http2_canned[] \u003d {\n+\t\u0022\u0022,\n+\t\u0022\u0022,\n+\t\u0022GET\u0022,\n+\t\u0022POST\u0022,\n+\t\u0022/\u0022,\n+\t\u0022/index.html\u0022,\n+\t\u0022http\u0022,\n+\t\u0022https\u0022,\n+\t\u0022200\u0022,\n+\t\u0022204\u0022,\n+\t\u0022206\u0022,\n+\t\u0022304\u0022,\n+\t\u0022400\u0022,\n+\t\u0022404\u0022,\n+\t\u0022500\u0022,\n+\t\u0022\u0022,\n+\t\u0022gzip, deflate\u0022\n+};\n+\n+/* see minihuf.c */\n+\n+#include \u0022huftable.h\u0022\n+\n+static int huftable_decode(int pos, char c)\n+{\n+\tint q \u003d pos + !!c;\n+\n+\tif (lextable_terms[q \u003e\u003e 3] \u0026 (1 \u003c\u003c (q \u0026 7))) /* terminal */\n+\t\treturn lextable[q] | 0x8000;\n+\n+\treturn pos + (lextable[q] \u003c\u003c 1);\n+}\n+\n+static int lws_frag_start(struct lws *wsi, int hdr_token_idx)\n+{\n+\tstruct allocated_headers *ah \u003d wsi-\u003eu.h2.http.ah;\n+\n+\tif (!ah) {\n+\t\tlwsl_notice(\u0022%s: no ah\u005cn\u0022, __func__);\n+\t\treturn 1;\n+\t}\n+\n+\tah-\u003ehdr_token_idx \u003d -1;\n+\n+\tlwsl_header(\u0022%s: token %d ah-\u003epos \u003d %d, ah-\u003enfrag \u003d %d\u005cn\u0022,\n+\t\t __func__, hdr_token_idx, ah-\u003epos, ah-\u003enfrag);\n+\n+\tif (!hdr_token_idx) {\n+\t\tlwsl_err(\u0022%s: zero hdr_token_idx\u005cn\u0022, __func__);\n+\t\treturn 1;\n+\t}\n+\n+\tif (ah-\u003enfrag \u003e\u003d ARRAY_SIZE(ah-\u003efrag_index)) {\n+\t\tlwsl_err(\u0022%s: frag index %d too big\u005cn\u0022, __func__, ah-\u003enfrag);\n+\t\treturn 1;\n+\t}\n+\n+\tif ((hdr_token_idx \u003d\u003d WSI_TOKEN_HTTP_COLON_AUTHORITY ||\n+\t hdr_token_idx \u003d\u003d WSI_TOKEN_HTTP_COLON_METHOD ||\n+\t hdr_token_idx \u003d\u003d WSI_TOKEN_HTTP_COLON_PATH ||\n+\t hdr_token_idx \u003d\u003d WSI_TOKEN_HTTP_COLON_SCHEME) \u0026\u0026\n+\t ah-\u003efrag_index[hdr_token_idx]) {\n+\t\tif (!(ah-\u003efrags[ah-\u003efrag_index[hdr_token_idx]].flags \u0026 1)) {\n+\t\t\tlws_h2_goaway(lws_get_network_wsi(wsi),\n+\t\t\t\t H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t \u0022Duplicated pseudoheader\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+\n+\tif (ah-\u003enfrag \u003d\u003d 0)\n+\t\tah-\u003enfrag \u003d 1;\n+\n+\tah-\u003efrags[ah-\u003enfrag].offset \u003d ah-\u003epos;\n+\tah-\u003efrags[ah-\u003enfrag].len \u003d 0;\n+\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d 0;\n+\tah-\u003efrags[ah-\u003enfrag].flags \u003d 2; /* we had reason to set it */\n+\n+\tah-\u003ehdr_token_idx \u003d hdr_token_idx;\n+\n+\tah-\u003efrag_index[hdr_token_idx] \u003d ah-\u003enfrag;\n+\n+\treturn 0;\n+}\n+\n+static int lws_frag_append(struct lws *wsi, unsigned char c)\n+{\n+\tstruct allocated_headers * ah \u003d wsi-\u003eu.h2.http.ah;\n+\n+\tah-\u003edata[ah-\u003epos++] \u003d c;\n+\tah-\u003efrags[ah-\u003enfrag].len++;\n+\n+\treturn ah-\u003epos \u003e\u003d wsi-\u003econtext-\u003emax_http_header_data;\n+}\n+\n+static int lws_frag_end(struct lws *wsi)\n+{\n+\tlwsl_header(\u0022%s\u005cn\u0022, __func__);\n+\tif (lws_frag_append(wsi, 0))\n+\t\treturn 1;\n+\n+\t/* don't account for the terminating NUL in the logical length */\n+\twsi-\u003eu.h2.http.ah-\u003efrags[wsi-\u003eu.h2.http.ah-\u003enfrag].len--;\n+\n+\twsi-\u003eu.h2.http.ah-\u003enfrag++;\n+\treturn 0;\n+}\n+\n+int\n+lws_hdr_extant(struct lws *wsi, enum lws_token_indexes h)\n+{\n+\tstruct allocated_headers *ah \u003d wsi-\u003eu.h2.http.ah;\n+\tint n;\n+\n+\tif (!ah)\n+\t\treturn 0;\n+\n+\tn \u003d ah-\u003efrag_index[h];\n+\tif (!n)\n+\t\treturn 0;\n+\n+\treturn !!(ah-\u003efrags[n].flags \u0026 2);\n+}\n+\n+static void lws_dump_header(struct lws *wsi, int hdr)\n+{\n+\tchar s[200];\n+\tconst unsigned char *p;\n+\tint len;\n+\n+\tif (hdr \u003d\u003d LWS_HPACK_IGNORE_ENTRY) {\n+\t\tlwsl_notice(\u0022hdr tok ignored\u005cn\u0022);\n+\t\treturn;\n+\t}\n+\n+\t(void)p;\n+\n+\tlen \u003d lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);\n+\tif (len \u003c 0)\n+\t\tstrcpy(s, \u0022(too big to show)\u0022);\n+\telse\n+\t\ts[len] \u003d '\u005c0';\n+\tp \u003d lws_token_to_string(hdr);\n+\tlwsl_header(\u0022 hdr tok %d (%s) \u003d '%s' (len %d)\u005cn\u0022, hdr,\n+\t\t p ? (char *)p : (char *)\u0022null\u0022, s, len);\n+}\n+\n+/*\n+ * dynamic table\n+ *\n+ * [ 0 .... num_entries - 1]\n+ *\n+ * Starts filling at 0+\n+ *\n+ * #62 is *most recently entered*\n+ *\n+ * Number of entries is not restricted, but aggregated size of the entry\n+ * payloads is. Unfortunately the way HPACK does this is specific to an\n+ * imagined implementation, and lws implementation is much more efficient\n+ * (ignoring unknown headers and using the lws token index for the header\n+ * name part).\n+ */\n+\n+/*\n+ * returns 0 if dynamic entry (arg and len are filled)\n+ * returns -1 if failure\n+ * returns nonzero token index if actually static token\n+ */\n+static int\n+lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,\n+\t\t uint32_t *hdr_len)\n+{\n+\tstruct hpack_dynamic_table *dyn;\n+\n+\tif (index \u003d\u003d LWS_HPACK_IGNORE_ENTRY)\n+\t\treturn LWS_HPACK_IGNORE_ENTRY;\n+\n+\t/* dynamic table only belongs to network wsi */\n+\twsi \u003d lws_get_network_wsi(wsi);\n+\tif (!wsi-\u003eu.h2.h2n)\n+\t\treturn -1;\n+\n+\tdyn \u003d \u0026wsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n+\n+\tif (index \u003c 0)\n+\t\treturn -1;\n+\n+\tif (index \u003c ARRAY_SIZE(static_token)) {\n+\t\tif (arg \u0026\u0026 index \u003c ARRAY_SIZE(http2_canned)) {\n+\t\t\t*arg \u003d http2_canned[index];\n+\t\t\t*len \u003d strlen(http2_canned[index]);\n+\t\t}\n+\t\tif (hdr_len)\n+\t\t\t*hdr_len \u003d static_hdr_len[index];\n+\n+\t\treturn static_token[index];\n+\t}\n+\n+\tif (!dyn) {\n+\t\tlwsl_notice(\u0022no dynamic table\u005cn\u0022);\n+\t\treturn -1;\n+\t}\n+\n+\tif (index \u003c ARRAY_SIZE(static_token) ||\n+\t index \u003e\u003d ARRAY_SIZE(static_token) + dyn-\u003eused_entries) {\n+\t\tlwsl_err(\u0022 %s: adjusted index %d \u003e\u003d %d\u005cn\u0022, __func__, index,\n+\t\t\t dyn-\u003eused_entries);\n+\t\tlws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,\n+\t\t\t \u0022index out of range\u0022);\n+\t\treturn -1;\n+\t}\n+\n+\tindex -\u003d ARRAY_SIZE(static_token);\n+\tindex \u003d (dyn-\u003epos - 1 - index) % dyn-\u003enum_entries;\n+\tif (index \u003c 0)\n+\t\tindex +\u003d dyn-\u003enum_entries;\n+\n+\tlwsl_header(\u0022%s: dyn index %d, tok %d\u005cn\u0022, __func__, index,\n+\t\t dyn-\u003eentries[index].lws_hdr_idx);\n+\n+\tif (arg \u0026\u0026 len) {\n+\t\t*arg \u003d dyn-\u003eentries[index].value;\n+\t\t*len \u003d dyn-\u003eentries[index].value_len;\n+\t}\n+\n+\tif (hdr_len)\n+\t\t*hdr_len \u003d dyn-\u003eentries[index].hdr_len;\n+\n+\treturn dyn-\u003eentries[index].lws_hdr_idx;\n+}\n+\n+static int\n+lws_h2_dynamic_table_dump(struct lws *wsi)\n+{\n+#if 0\n+\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n+\tstruct hpack_dynamic_table *dyn;\n+\tint n, m;\n+\tconst char *p;\n+\n+\tif (!nwsi-\u003eu.h2.h2n)\n+\t\treturn 1;\n+\tdyn \u003d \u0026nwsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n+\n+\tlwsl_header(\u0022Dump dyn table for nwsi %p (%d / %d members, pos \u003d %d, \u0022\n+\t\t \u0022start index %d, virt used %d / %d)\u005cn\u0022, nwsi,\n+\t\t dyn-\u003eused_entries, dyn-\u003enum_entries, dyn-\u003epos,\n+\t\t (uint32_t)ARRAY_SIZE(static_token),\n+\t\t dyn-\u003evirtual_payload_usage, dyn-\u003evirtual_payload_max);\n+\n+\tfor (n \u003d 0; n \u003c dyn-\u003eused_entries; n++) {\n+\t\tm \u003d (dyn-\u003epos - 1 - n) % dyn-\u003enum_entries;\n+\t\tif (m \u003c 0)\n+\t\t\tm +\u003d dyn-\u003enum_entries;\n+\t\tif (dyn-\u003eentries[m].lws_hdr_idx !\u003d LWS_HPACK_IGNORE_ENTRY)\n+\t\t\tp \u003d (const char *)lws_token_to_string(\n+\t\t\t\t\tdyn-\u003eentries[m].lws_hdr_idx);\n+\t\telse\n+\t\t\tp \u003d \u0022(ignored)\u0022;\n+\t\tlwsl_header(\u0022 %3d: tok %s: (len %d) val '%s'\u005cn\u0022,\n+\t\t\t (int)(n + ARRAY_SIZE(static_token)), p,\n+\t\t\t dyn-\u003eentries[m].hdr_len, dyn-\u003eentries[m].value ?\n+\t\t\t dyn-\u003eentries[m].value : \u0022null\u0022);\n+\t}\n+#endif\n+\treturn 0;\n+}\n+\n+static void\n+lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)\n+{\n+\tlwsl_header(\u0022freeing %d for reuse\u005cn\u0022, idx);\n+\tdyn-\u003evirtual_payload_usage -\u003d dyn-\u003eentries[idx].value_len +\n+\t\t\t\tdyn-\u003eentries[idx].hdr_len;\n+\tlws_free_set_NULL(dyn-\u003eentries[idx].value);\n+\tdyn-\u003eentries[idx].value \u003d NULL;\n+\tdyn-\u003eentries[idx].value_len \u003d 0;\n+\tdyn-\u003eentries[idx].hdr_len \u003d 0;\n+\tdyn-\u003eentries[idx].lws_hdr_idx \u003d LWS_HPACK_IGNORE_ENTRY;\n+\tdyn-\u003eused_entries--;\n+}\n+\n+/*\n+ * There are two address spaces, 1) internal ringbuffer and 2) HPACK indexes.\n+ *\n+ * Internal ringbuffer:\n+ *\n+ * The internal ringbuffer wraps as we keep filling it, dyn-\u003epos points to\n+ * the next index to be written.\n+ *\n+ * HPACK indexes:\n+ *\n+ * The last-written entry becomes entry 0, the previously-last-written entry\n+ * becomes entry 1 etc.\n+ */\n+\n+static int\n+lws_dynamic_token_insert(struct lws *wsi, int hdr_len,\n+\t\t\t int lws_hdr_index, char *arg, int len)\n+{\n+\tstruct hpack_dynamic_table *dyn;\n+\tint new_index, n;\n+\n+\t/* dynamic table only belongs to network wsi */\n+\twsi \u003d lws_get_network_wsi(wsi);\n+\tif (!wsi-\u003eu.h2.h2n)\n+\t\treturn 1;\n+\tdyn \u003d \u0026wsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n+\n+\tif (!dyn-\u003eentries) {\n+\t\tlwsl_err(\u0022%s: unsized dyn table\u005cn\u0022, __func__);\n+\n+\t\treturn 1;\n+\t}\n+\tlws_h2_dynamic_table_dump(wsi);\n+\n+\tnew_index \u003d (dyn-\u003epos) % dyn-\u003enum_entries;\n+\tif (dyn-\u003enum_entries \u0026\u0026 dyn-\u003eused_entries \u003d\u003d dyn-\u003enum_entries) {\n+\t\tif (dyn-\u003evirtual_payload_usage \u003c dyn-\u003evirtual_payload_max)\n+\t\t\tlwsl_err(\u0022Dropping header content before limit!\u005cn\u0022);\n+\t\t/* we have to drop the oldest to make space */\n+\t\tlws_dynamic_free(dyn, new_index);\n+\t}\n+\n+\t/*\n+\t * evict guys to make room, allowing for some overage. We have to\n+\t * take care about getting a single huge header, and evicting\n+\t * everything\n+\t */\n+\n+\twhile (dyn-\u003evirtual_payload_usage \u0026\u0026\n+\t dyn-\u003eused_entries \u0026\u0026\n+\t dyn-\u003evirtual_payload_usage + hdr_len + len \u003e\n+\t\t\t\tdyn-\u003evirtual_payload_max + 1024) {\n+\t\tn \u003d (dyn-\u003epos - dyn-\u003eused_entries) % dyn-\u003enum_entries;\n+\t\tif (n \u003c 0)\n+\t\t\tn +\u003d dyn-\u003enum_entries;\n+\t\tlws_dynamic_free(dyn, n);\n+\t}\n+\n+\tif (dyn-\u003eused_entries \u003c dyn-\u003enum_entries)\n+\t\tdyn-\u003eused_entries++;\n+\n+\tdyn-\u003eentries[new_index].value_len \u003d 0;\n+\n+\tif (lws_hdr_index !\u003d LWS_HPACK_IGNORE_ENTRY) {\n+\t\tif (dyn-\u003eentries[new_index].value)\n+\t\t\tlws_free_set_NULL(dyn-\u003eentries[new_index].value);\n+\t\tdyn-\u003eentries[new_index].value \u003d lws_malloc(len + 1, \u0022hpack dyn\u0022);\n+\t\tif (!dyn-\u003eentries[new_index].value)\n+\t\t\treturn 1;\n+\n+\t\tmemcpy(dyn-\u003eentries[new_index].value, arg, len);\n+\t\tdyn-\u003eentries[new_index].value[len] \u003d '\u005c0';\n+\t\tdyn-\u003eentries[new_index].value_len \u003d len;\n+\t} else\n+\t\tdyn-\u003eentries[new_index].value \u003d NULL;\n+\n+\tdyn-\u003eentries[new_index].lws_hdr_idx \u003d lws_hdr_index;\n+\tdyn-\u003eentries[new_index].hdr_len \u003d hdr_len;\n+\n+\tdyn-\u003evirtual_payload_usage +\u003d hdr_len + len;\n+\n+\tlwsl_info(\u0022%s: index %ld: lws_hdr_index 0x%x, hdr len %d, '%s' len %d\u005cn\u0022,\n+\t\t __func__, (long)ARRAY_SIZE(static_token),\n+\t\t lws_hdr_index, hdr_len, dyn-\u003eentries[new_index].value ?\n+\t\t\t\t dyn-\u003eentries[new_index].value : \u0022null\u0022, len);\n+\n+\tdyn-\u003epos \u003d (dyn-\u003epos + 1) % dyn-\u003enum_entries;\n+\n+\tlws_h2_dynamic_table_dump(wsi);\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_hpack_dynamic_size(struct lws *wsi, int size)\n+{\n+\tstruct hpack_dynamic_table *dyn;\n+\tstruct hpack_dt_entry *dte;\n+\tstruct lws *nwsi;\n+\tint min, n \u003d 0, m;\n+\n+\t/*\n+\t * \u0022size\u0022 here is coming from the http/2 SETTING\n+\t * SETTINGS_HEADER_TABLE_SIZE. This is a (virtual, in our case)\n+\t * linear buffer containing dynamic header names and values... when it\n+\t * is full, old entries are evicted.\n+\t *\n+\t * We encode the header as an lws_hdr_idx, which is all the rest of\n+\t * lws cares about; if there is no matching header we store an empty\n+\t * entry in the dyn table as a placeholder.\n+\t *\n+\t * So to make the two systems work together we keep an accounting of\n+\t * what we are using to decide when to evict... we must only evict\n+\t * things when the remote peer's accounting also makes him feel he\n+\t * should evict something.\n+\t */\n+\n+\tnwsi \u003d lws_get_network_wsi(wsi);\n+\tif (!nwsi-\u003eu.h2.h2n)\n+\t\tgoto bail;\n+\n+\tdyn \u003d \u0026nwsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n+\tlwsl_info(\u0022%s: from %d to %d, lim %d\u005cn\u0022, __func__,\n+\t\t (int)dyn-\u003enum_entries, size,\n+\t\t nwsi-\u003eu.h2.h2n-\u003eset.s[H2SET_HEADER_TABLE_SIZE]);\n+\n+\tif (size \u003e nwsi-\u003eu.h2.h2n-\u003eset.s[H2SET_HEADER_TABLE_SIZE]) {\n+\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n+\t\t\t\u0022Asked for header table bigger than we told\u0022);\n+\t\tgoto bail;\n+\t}\n+\n+\tdyn-\u003evirtual_payload_max \u003d size;\n+\n+\tsize \u003d size / 8;\n+\tmin \u003d size;\n+\tif (min \u003e dyn-\u003eused_entries)\n+\t\tmin \u003d dyn-\u003eused_entries;\n+\n+\tif (size \u003d\u003d dyn-\u003enum_entries)\n+\t\treturn 0;\n+\n+\tif (dyn-\u003enum_entries \u003c min)\n+\t\tmin \u003d dyn-\u003enum_entries;\n+\n+\tdte \u003d lws_zalloc(sizeof(*dte) * (size + 1), \u0022dynamic table entries\u0022);\n+\tif (!dte)\n+\t\tgoto bail;\n+\n+\twhile (dyn-\u003evirtual_payload_usage \u0026\u0026 dyn-\u003eused_entries \u0026\u0026\n+\t dyn-\u003evirtual_payload_usage \u003e dyn-\u003evirtual_payload_max) {\n+\t\tn \u003d (dyn-\u003epos - dyn-\u003eused_entries) % dyn-\u003enum_entries;\n+\t\tif (n \u003c 0)\n+\t\t\tn +\u003d dyn-\u003enum_entries;\n+\t\tlws_dynamic_free(dyn, n);\n+\t}\n+\n+\tif (min \u003e dyn-\u003eused_entries)\n+\t\tmin \u003d dyn-\u003eused_entries;\n+\n+\tif (dyn-\u003eentries) {\n+\t\tfor (n \u003d 0; n \u003c min; n++) {\n+\t\t\tm \u003d (dyn-\u003epos - dyn-\u003eused_entries + n) % dyn-\u003enum_entries;\n+\t\t\tif (m \u003c 0)\n+\t\t\t\tm +\u003d dyn-\u003enum_entries;\n+\t\t\tdte[n] \u003d dyn-\u003eentries[m];\n+\t\t}\n+\n+\t\tlws_free(dyn-\u003eentries);\n+\t}\n+\n+\tdyn-\u003eentries \u003d dte;\n+\tdyn-\u003enum_entries \u003d size;\n+\tdyn-\u003eused_entries \u003d min;\n+\tif (size)\n+\t\tdyn-\u003epos \u003d min % size;\n+\telse\n+\t\tdyn-\u003epos \u003d 0;\n+\n+\tlws_h2_dynamic_table_dump(wsi);\n+\n+\treturn 0;\n+\n+bail:\n+\tlwsl_info(\u0022%s: failed to resize to %d\u005cn\u0022, __func__, size);\n+\n+\treturn 1;\n+}\n+\n+void\n+lws_hpack_destroy_dynamic_header(struct lws *wsi)\n+{\n+\tstruct hpack_dynamic_table *dyn;\n+\tint n;\n+\n+\tif (!wsi-\u003eu.h2.h2n)\n+\t\treturn;\n+\n+\tdyn \u003d \u0026wsi-\u003eu.h2.h2n-\u003ehpack_dyn_table;\n+\n+\tif (!dyn-\u003eentries)\n+\t\treturn;\n+\n+\tfor (n \u003d 0; n \u003c dyn-\u003enum_entries; n++)\n+\t\tif (dyn-\u003eentries[n].value)\n+\t\t\tlws_free_set_NULL(dyn-\u003eentries[n].value);\n+\n+\tlws_free_set_NULL(dyn-\u003eentries);\n+}\n+\n+static int\n+lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)\n+{\n+\tconst char *arg \u003d NULL;\n+\tint len \u003d 0;\n+\tconst char *p \u003d NULL;\n+\tint tok \u003d lws_token_from_index(wsi, idx, \u0026arg, \u0026len, NULL);\n+\n+\tif (tok \u003d\u003d LWS_HPACK_IGNORE_ENTRY) {\n+\t\tlwsl_header(\u0022%s: lws_token says ignore, returning\u005cn\u0022, __func__);\n+\t\treturn 0;\n+\t}\n+\n+\tif (tok \u003d\u003d -1) {\n+\t\tlwsl_info(\u0022%s: idx %d mapped to tok %d\u005cn\u0022, __func__, idx, tok);\n+\t\treturn 1;\n+\t}\n+\n+\tif (arg) {\n+\t\t/* dynamic result */\n+\t\tif (known_token \u003e 0)\n+\t\t\ttok \u003d known_token;\n+\t\tlwsl_header(\u0022%s: dyn: idx %d '%s' tok %d\u005cn\u0022, __func__, idx, arg,\n+\t\t\t tok);\n+\t} else\n+\t\tlwsl_header(\u0022writing indexed hdr %d (tok %d '%s')\u005cn\u0022, idx, tok,\n+\t\t\t\tlws_token_to_string(tok));\n+\n+\tif (tok \u003d\u003d LWS_HPACK_IGNORE_ENTRY)\n+\t\treturn 0;\n+\n+\tif (arg)\n+\t\tp \u003d arg;\n+\n+\tif (idx \u003c ARRAY_SIZE(http2_canned))\n+\t\tp \u003d http2_canned[idx];\n+\n+\tif (lws_frag_start(wsi, tok))\n+\t\treturn 1;\n+\n+\tif (p)\n+\t\twhile (*p \u0026\u0026 len--)\n+\t\t\tif (lws_frag_append(wsi, *p++))\n+\t\t\t\treturn 1;\n+\n+\tif (lws_frag_end(wsi))\n+\t\treturn 1;\n+\n+\tlws_dump_header(wsi, tok);\n+\n+\treturn 0;\n+}\n+\n+int lws_hpack_interpret(struct lws *wsi, unsigned char c)\n+{\n+\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n+\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eu.h2.h2n;\n+\tstruct allocated_headers *ah \u003d wsi-\u003eu.h2.http.ah;\n+\tunsigned int prev;\n+\tunsigned char c1;\n+\tint n, m;\n+\n+\tif (!h2n)\n+\t\treturn -1;\n+\n+\t/*\n+\t * HPKT_INDEXED_HDR_7\t\t 1xxxxxxx: just \u0022header field\u0022\n+\t * HPKT_INDEXED_HDR_6_VALUE_INCR 01xxxxxx: NEW indexed hdr + val\n+\t * HPKT_LITERAL_HDR_VALUE_INCR\t 01000000: NEW literal hdr + val\n+\t * HPKT_INDEXED_HDR_4_VALUE\t 0000xxxx: indexed hdr + val\n+\t * HPKT_INDEXED_HDR_4_VALUE_NEVER 0001xxxx: NEVER NEW indexed hdr + val\n+\t * HPKT_LITERAL_HDR_VALUE\t 00000000: literal hdr + val\n+\t * HPKT_LITERAL_HDR_VALUE_NEVER\t 00010000: NEVER NEW literal hdr + val\n+\t */\n+\tswitch (h2n-\u003ehpack) {\n+\n+\tcase HPKS_TYPE:\n+\t\th2n-\u003eis_first_header_char \u003d 1;\n+\t\th2n-\u003ehuff_pad \u003d 0;\n+\t\th2n-\u003ezero_huff_padding \u003d 0;\n+\t\th2n-\u003elast_action_dyntable_resize \u003d 0;\n+\t\th2n-\u003eext_count \u003d 0;\n+\t\th2n-\u003ehpack_hdr_len \u003d 0;\n+\t\th2n-\u003eunknown_header \u003d 0;\n+\n+\t\tif (c \u0026 0x80) { /* 1.... indexed header field only */\n+\t\t\t/* just a possibly-extended integer */\n+\t\t\th2n-\u003ehpack_type \u003d HPKT_INDEXED_HDR_7;\n+\t\t\tlwsl_header(\u0022HPKT_INDEXED_HDR_7 hdr %d\u005cn\u0022, c \u0026 0x7f);\n+\t\t\tlws_h2_dynamic_table_dump(wsi);\n+\n+\t\t\th2n-\u003ehdr_idx \u003d c \u0026 0x7f;\n+\t\t\tif ((c \u0026 0x7f) \u003d\u003d 0x7f) {\n+\t\t\t\th2n-\u003ehpack_len \u003d 0;\n+\t\t\t\th2n-\u003ehpack_m \u003d 0x7f;\n+\t\t\t\th2n-\u003ehpack \u003d HPKS_IDX_EXT;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (!h2n-\u003ehdr_idx) {\n+\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n+\t\t\t\t\t \u0022hdr index 0 seen\u0022);\n+\t\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\tlwsl_header(\u0022HPKT_INDEXED_HDR_7: hdr %d\u005cn\u0022, c \u0026 0x7f);\n+\t\t\tif (lws_hpack_use_idx_hdr(wsi, c \u0026 0x7f, -1)) {\n+\t\t\t\tlwsl_header(\u0022%s: idx hdr wr fail\u005cn\u0022, __func__);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\t/* stay at same state */\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (c \u0026 0x40) { /* 01.... indexed or literal header incr idx */\n+\t\t\t/*\n+\t\t\t * [possibly-ext hdr idx (6) | new literal hdr name]\n+\t\t\t * H + possibly-ext value length\n+\t\t\t * literal value\n+\t\t\t */\n+\t\t\th2n-\u003ehdr_idx \u003d 0;\n+\t\t\tif (c \u003d\u003d 0x40) { /* literal header */\n+\t\t\t\tlwsl_header(\u0022 HPKT_LITERAL_HDR_VALUE_INCR\u005cn\u0022);\n+\t\t\t\th2n-\u003ehpack_type \u003d HPKT_LITERAL_HDR_VALUE_INCR;\n+\t\t\t\th2n-\u003evalue \u003d 0;\n+\t\t\t\th2n-\u003ehpack_len \u003d 0;\n+\t\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\t/* indexed header */\n+\t\t\th2n-\u003ehpack_type \u003d HPKT_INDEXED_HDR_6_VALUE_INCR;\n+\t\t\tlwsl_header(\u0022 HPKT_INDEXED_HDR_6_VALUE_INCR (hdr %d)\u005cn\u0022,\n+\t\t\t\t c \u0026 0x3f);\n+\t\t\th2n-\u003ehdr_idx \u003d c \u0026 0x3f;\n+\t\t\tif ((c \u0026 0x3f) \u003d\u003d 0x3f) {\n+\t\t\t\th2n-\u003ehpack_m \u003d 0x3f;\n+\t\t\t\th2n-\u003ehpack_len \u003d 0;\n+\t\t\t\th2n-\u003ehpack \u003d HPKS_IDX_EXT;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\th2n-\u003evalue \u003d 1;\n+\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n+\t\t\tif (!h2n-\u003ehdr_idx) {\n+\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n+\t\t\t\t\t \u0022hdr index 0 seen\u0022);\n+\t\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\tswitch(c \u0026 0xf0) {\n+\t\tcase 0x10: /* literal header never index */\n+\t\tcase 0: /* literal header without indexing */\n+\t\t\t/*\n+\t\t\t * follows 0x40 except 4-bit hdr idx\n+\t\t\t * and don't add to index\n+\t\t\t */\n+\t\t\tif (c \u003d\u003d 0) { /* literal name */\n+\t\t\t\th2n-\u003ehpack_type \u003d HPKT_LITERAL_HDR_VALUE;\n+\t\t\t\tlwsl_header(\u0022 HPKT_LITERAL_HDR_VALUE\u005cn\u0022);\n+\t\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n+\t\t\t\th2n-\u003evalue \u003d 0;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (c \u003d\u003d 0x10) { /* literal name NEVER */\n+\t\t\t\th2n-\u003ehpack_type \u003d HPKT_LITERAL_HDR_VALUE_NEVER;\n+\t\t\t\tlwsl_header(\u0022 HPKT_LITERAL_HDR_VALUE_NEVER\u005cn\u0022);\n+\t\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n+\t\t\t\th2n-\u003evalue \u003d 0;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tlwsl_header(\u0022indexed\u005cn\u0022);\n+\t\t\t/* indexed name */\n+\t\t\tif (c \u0026 0x10) {\n+\t\t\t\th2n-\u003ehpack_type \u003d HPKT_INDEXED_HDR_4_VALUE_NEVER;\n+\t\t\t\tlwsl_header(\u0022 HPKT_LITERAL_HDR_4_VALUE_NEVER\u005cn\u0022);\n+\t\t\t} else {\n+\t\t\t\th2n-\u003ehpack_type \u003d HPKT_INDEXED_HDR_4_VALUE;\n+\t\t\t\tlwsl_header(\u0022 HPKT_INDEXED_HDR_4_VALUE\u005cn\u0022);\n+\t\t\t}\n+\t\t\th2n-\u003ehdr_idx \u003d 0;\n+\t\t\tif ((c \u0026 0xf) \u003d\u003d 0xf) {\n+\t\t\t\th2n-\u003ehpack_len \u003d c \u0026 0xf;\n+\t\t\t\th2n-\u003ehpack_m \u003d 0xf;\n+\t\t\t\th2n-\u003ehpack_len \u003d 0;\n+\t\t\t\th2n-\u003ehpack \u003d HPKS_IDX_EXT;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\th2n-\u003ehdr_idx \u003d c \u0026 0xf;\n+\t\t\th2n-\u003evalue \u003d 1;\n+\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n+\t\t\tbreak;\n+\n+\t\tcase 0x20:\n+\t\tcase 0x30: /* header table size update */\n+\t\t\t/* possibly-extended size value (5) */\n+\t\t\tlwsl_header(\u0022HPKT_SIZE_5 %x\u005cn\u0022, c \u00260x1f);\n+\t\t\th2n-\u003ehpack_type \u003d HPKT_SIZE_5;\n+\t\t\th2n-\u003ehpack_len \u003d c \u0026 0x1f;\n+\t\t\tif (h2n-\u003ehpack_len \u003d\u003d 0x1f) {\n+\t\t\t\th2n-\u003ehpack_m \u003d 0x1f;\n+\t\t\t\th2n-\u003ehpack_len \u003d 0;\n+\t\t\t\th2n-\u003ehpack \u003d HPKS_IDX_EXT;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\th2n-\u003elast_action_dyntable_resize \u003d 1;\n+\t\t\tif (lws_hpack_dynamic_size(wsi, h2n-\u003ehpack_len))\n+\t\t\t\treturn 1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase HPKS_IDX_EXT:\n+\t\th2n-\u003ehpack_len \u003d h2n-\u003ehpack_len |\n+\t\t\t\t ((c \u0026 0x7f) \u003c\u003c h2n-\u003eext_count);\n+\t\th2n-\u003eext_count +\u003d 7;\n+\t\tif (c \u0026 0x80) /* extended int not complete yet */\n+\t\t\tbreak;\n+\n+\t\t/* extended integer done */\n+\t\th2n-\u003ehpack_len +\u003d h2n-\u003ehpack_m;\n+\t\tlwsl_header(\u0022HPKS_IDX_EXT: hpack_len %d\u005cn\u0022, h2n-\u003ehpack_len);\n+\n+\t\tswitch (h2n-\u003ehpack_type) {\n+\t\tcase HPKT_INDEXED_HDR_7:\n+\t\t\tif (lws_hpack_use_idx_hdr(wsi, h2n-\u003ehpack_len,\n+\t\t\t\t\t\t h2n-\u003ehdr_idx)) {\n+\t\t\t\tlwsl_notice(\u0022%s: hd7 use fail\u005cn\u0022, __func__);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\th2n-\u003ehpack \u003d HPKS_TYPE;\n+\t\t\tbreak;\n+\n+\t\tcase HPKT_SIZE_5:\n+\t\t\th2n-\u003elast_action_dyntable_resize \u003d 1;\n+\t\t\tif (lws_hpack_dynamic_size(wsi, h2n-\u003ehpack_len))\n+\t\t\t\treturn 1;\n+\t\t\th2n-\u003ehpack \u003d HPKS_TYPE;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\th2n-\u003ehdr_idx \u003d h2n-\u003ehpack_len;\n+\t\t\tif (!h2n-\u003ehdr_idx) {\n+\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n+\t\t\t\t\t \u0022extended header index was 0\u0022);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\th2n-\u003evalue \u003d 1;\n+\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase HPKS_HLEN: /* [ H | 7+ ] */\n+\t\th2n-\u003ehuff \u003d !!(c \u0026 0x80);\n+\t\th2n-\u003ehpack_pos \u003d 0;\n+\t\th2n-\u003ehpack_len \u003d c \u0026 0x7f;\n+\n+\t\tif (h2n-\u003ehpack_len \u003d\u003d 0x7f) {\n+\t\t\th2n-\u003ehpack_m \u003d 0x7f;\n+\t\t\th2n-\u003ehpack_len \u003d 0;\n+\t\t\th2n-\u003eext_count \u003d 0;\n+\t\t\th2n-\u003ehpack \u003d HPKS_HLEN_EXT;\n+\t\t\tbreak;\n+\t\t}\n+pre_data:\n+\t\th2n-\u003ehpack \u003d HPKS_DATA;\n+\t\tif (!h2n-\u003evalue || !h2n-\u003ehdr_idx) {\n+\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_NAME_PART;\n+\t\t\twsi-\u003eu.hdr.lextable_pos \u003d 0;\n+\t\t\th2n-\u003eunknown_header \u003d 0;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE ||\n+\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_INCR ||\n+\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_NEVER) {\n+\t\t\tn \u003d wsi-\u003eu.hdr.parser_state;\n+\t\t\tif (n \u003d\u003d 255) {\n+\t\t\t\tn \u003d -1;\n+\t\t\t\th2n-\u003ehdr_idx \u003d -1;\n+\t\t\t} else\n+\t\t\t\th2n-\u003ehdr_idx \u003d 1;\n+\t\t} else {\n+\t\t\tn \u003d lws_token_from_index(wsi, h2n-\u003ehdr_idx, NULL,\n+\t\t\t\t\t\t NULL, NULL);\n+\t\t\tlwsl_header(\u0022 lws_tok_from_idx(%d) says %d\u005cn\u0022,\n+\t\t\t\t h2n-\u003ehdr_idx, n);\n+\t\t}\n+\n+\t\tif (n \u003d\u003d LWS_HPACK_IGNORE_ENTRY || n \u003d\u003d -1)\n+\t\t\th2n-\u003ehdr_idx \u003d LWS_HPACK_IGNORE_ENTRY;\n+\n+\t\tswitch (h2n-\u003ehpack_type) {\n+\t\t/*\n+\t\t * hpack types with literal headers were parsed by the lws\n+\t\t * header SM... on recognition of a known lws header, it does\n+\t\t * the correct lws_frag_start() for us already. Other types\n+\t\t * (ie, indexed header) need us to do it here.\n+\t\t */\n+\t\tcase HPKT_LITERAL_HDR_VALUE_INCR:\n+\t\tcase HPKT_LITERAL_HDR_VALUE:\n+\t\tcase HPKT_LITERAL_HDR_VALUE_NEVER:\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tif (n !\u003d -1 \u0026\u0026 n !\u003d LWS_HPACK_IGNORE_ENTRY \u0026\u0026\n+\t\t\t lws_frag_start(wsi, n)) {\n+\t\t\t\tlwsl_header(\u0022%s: frag start failed\u005cn\u0022, __func__);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase HPKS_HLEN_EXT:\n+\t\th2n-\u003ehpack_len \u003d h2n-\u003ehpack_len |\n+\t\t\t\t ((c \u0026 0x7f) \u003c\u003c h2n-\u003eext_count);\n+\t\th2n-\u003eext_count +\u003d 7;\n+\t\tif (c \u0026 0x80) /* extended integer not complete yet */\n+\t\t\tbreak;\n+\n+\t\th2n-\u003ehpack_len +\u003d h2n-\u003ehpack_m;\n+\t\tgoto pre_data;\n+\n+\tcase HPKS_DATA:\n+\t\t//lwsl_header(\u0022 0x%02X huff %d\u005cn\u0022, c, h2n-\u003ehuff);\n+\t\t\tc1 \u003d c;\n+\n+\t\tfor (n \u003d 0; n \u003c 8; n++) {\n+\t\t\tif (h2n-\u003ehuff) {\n+\t\t\t\tchar b \u003d (c \u003e\u003e 7) \u0026 1;\n+\t\t\t\tprev \u003d h2n-\u003ehpack_pos;\n+\t\t\t\th2n-\u003ehpack_pos \u003d huftable_decode(\n+\t\t\t\t\t\th2n-\u003ehpack_pos, b);\n+\t\t\t\tc \u003c\u003c\u003d 1;\n+\t\t\t\tif (h2n-\u003ehpack_pos \u003d\u003d 0xffff) {\n+\t\t\t\t\tlwsl_notice(\u0022Huffman err\u005cn\u0022);\n+\t\t\t\t\treturn 1;\n+\t\t\t\t}\n+\t\t\t\tif (!(h2n-\u003ehpack_pos \u0026 0x8000)) {\n+\t\t\t\t\tif (!b)\n+\t\t\t\t\t\th2n-\u003ezero_huff_padding \u003d 1;\n+\t\t\t\t\th2n-\u003ehuff_pad++;\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t\tc1 \u003d h2n-\u003ehpack_pos \u0026 0x7fff;\n+\t\t\t\th2n-\u003ehpack_pos \u003d 0;\n+\t\t\t\th2n-\u003ehuff_pad \u003d 0;\n+\t\t\t\th2n-\u003ezero_huff_padding \u003d 0;\n+\n+\t\t\t\t/* EOS |11111111|11111111|11111111|111111 */\n+\t\t\t\tif (!c1 \u0026\u0026 prev \u003d\u003d HUFTABLE_0x100_PREV) {\n+\t\t\t\t\tlws_h2_goaway(nwsi,\n+\t\t\t\t\t\tH2_ERR_COMPRESSION_ERROR,\n+\t\t\t\t\t\t\u0022Huffman EOT seen\u0022);\n+\t\t\t\t\treturn 1;\n+\t\t\t\t}\n+\t\t\t} else\n+\t\t\t\tn \u003d 8;\n+\n+\t\t\tif (h2n-\u003evalue) { /* value */\n+\n+\t\t\t\tif (h2n-\u003ehdr_idx \u0026\u0026\n+\t\t\t\t h2n-\u003ehdr_idx !\u003d LWS_HPACK_IGNORE_ENTRY) {\n+\n+\t\t\t\t\tif (ah-\u003ehdr_token_idx \u003d\u003d\n+\t\t\t\t\t WSI_TOKEN_HTTP_COLON_PATH) {\n+\n+\t\t\t\t\t\tswitch (lws_parse_urldecode(\n+\t\t\t\t\t\t\t\t wsi, \u0026c1)) {\n+\t\t\t\t\t\tcase LPUR_CONTINUE:\n+\t\t\t\t\t\t\tbreak;\n+\t\t\t\t\t\tcase LPUR_SWALLOW:\n+\t\t\t\t\t\t\tgoto swallow;\n+\t\t\t\t\t\tcase LPUR_EXCESSIVE:\n+\t\t\t\t\t\tcase LPUR_FORBID:\n+\t\t\t\t\t\t\tlws_h2_goaway(nwsi,\n+\t\t\t\t\t\t\t H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t\t\t \u0022Evil URI\u0022);\n+\t\t\t\t\t\t\treturn 1;\n+\n+\t\t\t\t\t\tdefault:\n+\t\t\t\t\t\t\treturn -1;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t\tif (lws_frag_append(wsi, c1)) {\n+\t\t\t\t\t\tlwsl_notice(\u0022%s: frag app fail\u005cn\u0022,\n+\t\t\t\t\t\t\t __func__);\n+\t\t\t\t\t\treturn 1;\n+\t\t\t\t\t}\n+\t\t\t\t} //else\n+\t\t\t\t\t//lwsl_header(\u0022ignoring %c\u005cn\u0022, c1);\n+\t\t\t} else {\n+\t\t\t\t/*\n+\t\t\t\t * Convert name using existing parser,\n+\t\t\t \t * If h2n-\u003eunknown_header \u003d\u003d 0, result is\n+\t\t\t \t * in wsi-\u003eu.hdr.parser_state\n+\t\t\t \t * using WSI_TOKEN_GET_URI.\n+\t\t\t \t *\n+\t\t\t \t * If unknown header h2n-\u003eunknown_header\n+\t\t\t \t * will be set.\n+\t\t\t \t */\n+\t\t\t\th2n-\u003ehpack_hdr_len++;\n+\t\t\t\tif (h2n-\u003eis_first_header_char) {\n+\t\t\t\t\th2n-\u003eis_first_header_char \u003d 0;\n+\t\t\t\t\th2n-\u003efirst_hdr_char \u003d c1;\n+\t\t\t\t}\n+\t\t\t\tlwsl_header(\u0022parser: %c\u005cn\u0022, c1);\n+\t\t\t\t/* uppercase header names illegal */\n+\t\t\t\tif (c1 \u003e\u003d 'A' \u0026\u0026 c1 \u003c\u003d 'Z') {\n+\t\t\t\t\tlws_h2_goaway(nwsi,\n+\t\t\t\t\t\tH2_ERR_COMPRESSION_ERROR,\n+\t\t\t\t\t\t\u0022Uppercase literal hpack hdr\u0022);\n+\t\t\t\t\treturn 1;\n+\t\t\t\t}\n+\t\t\t\tif (!h2n-\u003eunknown_header \u0026\u0026 lws_parse(wsi, c1))\n+\t\t\t\t\th2n-\u003eunknown_header \u003d 1;\n+\t\t\t}\n+swallow:\n+\t\t\t(void)n;\n+\t\t} // for n\n+\n+\t\tif (--h2n-\u003ehpack_len)\n+\t\t\tbreak;\n+\n+\t\t/*\n+\t\t * The header (h2n-\u003evalue \u003d 0) or the payload (h2n-\u003evalue \u003d 1)\n+\t\t * is complete.\n+\t\t */\n+\n+\t\tif (h2n-\u003ehuff \u0026\u0026 (h2n-\u003ehuff_pad \u003e 7 ||\n+\t\t (h2n-\u003ezero_huff_padding \u0026\u0026 h2n-\u003ehuff_pad))) {\n+\t\t\tlwsl_notice(\u0022zero_huff_padding: %d huff_pad: %d\u005cn\u0022,\n+\t\t\t\t h2n-\u003ezero_huff_padding, h2n-\u003ehuff_pad);\n+\t\t\tlws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,\n+\t\t\t\t \u0022Huffman padding excessive or wrong\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tif (!h2n-\u003evalue \u0026\u0026 (\n+\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE ||\n+\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_INCR ||\n+\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_NEVER)) {\n+\t\t\th2n-\u003ehdr_idx \u003d LWS_HPACK_IGNORE_ENTRY;\n+\t\t\tlwsl_header(\u0022wsi-\u003eu.hdr.parser_state: %d\u005cn\u0022,\n+\t\t\t\t wsi-\u003eu.hdr.parser_state);\n+\n+\t\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_NAME_PART) {\n+\t\t\t\t/* h2 headers come without the colon */\n+\t\t\t\tn \u003d lws_parse(wsi, ':');\n+\t\t\t\t(void)n;\n+\t\t\t}\n+\n+\t\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_NAME_PART ||\n+\t\t\t wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_SKIPPING) {\n+\t\t\t\th2n-\u003eunknown_header \u003d 1;\n+\t\t\t\twsi-\u003eu.hdr.parser_state \u003d -1;\n+\t\t\t}\n+\t\t}\n+\n+\t\tn \u003d 8;\n+\n+\t\t/* we have the header */\n+\t\tif (!h2n-\u003evalue) {\n+\t\t\th2n-\u003evalue \u003d 1;\n+\t\t\th2n-\u003ehpack \u003d HPKS_HLEN;\n+\t\t\th2n-\u003ehuff_pad \u003d 0;\n+\t\t\th2n-\u003ezero_huff_padding \u003d 0;\n+\t\t\th2n-\u003eext_count \u003d 0;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/*\n+\t\t * we have got both the header and value\n+\t\t */\n+\n+\t\tswitch (h2n-\u003ehpack_type) {\n+\t\t/*\n+\t\t * These are the only two that insert to the dyntable\n+\t\t */\n+\t\t/* NEW indexed hdr with value */\n+\t\tcase HPKT_INDEXED_HDR_6_VALUE_INCR:\n+\t\t\t/* header length is determined by known index */\n+\t\t\tm \u003d lws_token_from_index(wsi, h2n-\u003ehdr_idx, NULL, NULL,\n+\t\t\t\t\t\u0026h2n-\u003ehpack_hdr_len);\n+\t\t\tgoto add_it;\n+\t\t/* NEW literal hdr with value */\n+\t\tcase HPKT_LITERAL_HDR_VALUE_INCR:\n+\t\t\t/*\n+\t\t\t * hdr is a new literal, so length is already in\n+\t\t\t * h2n-\u003ehpack_hdr_len\n+\t\t\t */\n+\t\t\tm \u003d wsi-\u003eu.hdr.parser_state;\n+\t\t\tif (h2n-\u003eunknown_header ||\n+\t\t\t wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_NAME_PART ||\n+\t\t\t wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_SKIPPING) {\n+\t\t\t\tif (h2n-\u003efirst_hdr_char \u003d\u003d ':') {\n+\t\t\t\t\tlwsl_info(\u0022HPKT_LITERAL_HDR_VALUE_INCR:\u0022\n+\t\t\t\t\t\t \u0022 end state %d unk hdr %d\u005cn\u0022,\n+\t\t\t\t\t\twsi-\u003eu.hdr.parser_state,\n+\t\t\t\t\t\th2n-\u003eunknown_header);\n+\t\t\t\t\t/* unknown pseudoheaders are illegal */\n+\t\t\t\t\tlws_h2_goaway(nwsi,\n+\t\t\t\t\t\t H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t\t \u0022Unknown pseudoheader\u0022);\n+\t\t\t\t\treturn 1;\n+\t\t\t\t}\n+\t\t\t\tm \u003d LWS_HPACK_IGNORE_ENTRY;\n+\t\t\t}\n+add_it:\n+\t\t\t/*\n+\t\t\t * mark us as having been set at the time of dynamic\n+\t\t\t * token insertion.\n+\t\t\t */\n+\t\t\tah-\u003efrags[ah-\u003enfrag].flags |\u003d 1;\n+\n+\t\t\tif (lws_dynamic_token_insert(wsi, h2n-\u003ehpack_hdr_len, m,\n+\t\t\t\t\t\u0026ah-\u003edata[ah-\u003efrags[ah-\u003enfrag].offset],\n+\t\t\t\t\tah-\u003efrags[ah-\u003enfrag].len)) {\n+\t\t\t\tlwsl_notice(\u0022%s: tok_insert fail\u005cn\u0022, __func__);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (h2n-\u003ehdr_idx !\u003d LWS_HPACK_IGNORE_ENTRY \u0026\u0026 lws_frag_end(wsi))\n+\t\t\treturn 1;\n+\n+\t\tif (h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE ||\n+\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_INCR ||\n+\t\t h2n-\u003ehpack_type \u003d\u003d HPKT_LITERAL_HDR_VALUE_NEVER) {\n+\t\t\tm \u003d wsi-\u003eu.hdr.parser_state;\n+\t\t\tif (m \u003d\u003d 255)\n+\t\t\t\tm \u003d -1;\n+\t\t} else\n+\t\t\tm \u003d lws_token_from_index(wsi, h2n-\u003ehdr_idx, NULL, NULL,\n+\t\t\t\t\t\t NULL);\n+\t\tif (m !\u003d -1 \u0026\u0026 m !\u003d LWS_HPACK_IGNORE_ENTRY)\n+\t\t\tlws_dump_header(wsi, m);\n+\n+\t\tif (h2n-\u003eseen_nonpseudoheader \u0026\u0026 (\n+\t\t m \u003d\u003d WSI_TOKEN_HTTP_COLON_AUTHORITY ||\n+\t\t m \u003d\u003d WSI_TOKEN_HTTP_COLON_METHOD ||\n+\t\t m \u003d\u003d WSI_TOKEN_HTTP_COLON_PATH ||\n+\t\t m \u003d\u003d WSI_TOKEN_HTTP_COLON_SCHEME)) {\n+\t\t\t/*\n+\t\t\t * it's not legal to see a\n+\t\t\t * pseudoheader after normal\n+\t\t\t * headers\n+\t\t\t */\n+\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\u0022Pseudoheader after normal hdrs\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tif (m !\u003d WSI_TOKEN_HTTP_COLON_AUTHORITY \u0026\u0026\n+\t\t m !\u003d WSI_TOKEN_HTTP_COLON_METHOD \u0026\u0026\n+\t\t m !\u003d WSI_TOKEN_HTTP_COLON_PATH \u0026\u0026\n+\t\t m !\u003d WSI_TOKEN_HTTP_COLON_SCHEME)\n+\t\t\th2n-\u003eseen_nonpseudoheader \u003d 1;\n+\n+\t\th2n-\u003eis_first_header_char \u003d 1;\n+\t\th2n-\u003ehpack \u003d HPKS_TYPE;\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+lws_h2_num_start(int starting_bits, unsigned long num)\n+{\n+\tint mask \u003d (1 \u003c\u003c starting_bits) - 1;\n+\n+\tif (num \u003c mask)\n+\t\treturn (int)num;\n+\n+\treturn mask;\n+}\n+\n+static int\n+lws_h2_num(int starting_bits, unsigned long num,\n+\t\t\t unsigned char **p, unsigned char *end)\n+{\n+\tint mask \u003d (1 \u003c\u003c starting_bits) - 1;\n+\n+\tif (num \u003c mask)\n+\t\treturn 0;\n+\n+\tnum -\u003d mask;\n+\tdo {\n+\t\tif (num \u003e 127)\n+\t\t\t*((*p)++) \u003d 0x80 | (num \u0026 0x7f);\n+\t\telse\n+\t\t\t*((*p)++) \u003d 0x00 | (num \u0026 0x7f);\n+\t\tif (*p \u003e\u003d end)\n+\t\t\treturn 1;\n+\t\tnum \u003e\u003e\u003d 7;\n+\t} while (num);\n+\n+\treturn 0;\n+}\n+\n+int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name,\n+\t\t\t\t const unsigned char *value, int length,\n+\t\t\t\t unsigned char **p, unsigned char *end)\n+{\n+\tint len;\n+\n+\tlwsl_header(\u0022%s: %p %s:%s\u005cn\u0022, __func__, *p, name, value);\n+\n+\tlen \u003d strlen((char *)name);\n+\tif (len)\n+\t\tif (name[len - 1] \u003d\u003d ':')\n+\t\t\tlen--;\n+\n+\tif (wsi-\u003ehttp2_substream \u0026\u0026 !strncmp((const char *)name,\n+\t\t\t\t\t \u0022transfer-encoding\u0022, len)) {\n+\t\tlwsl_header(\u0022rejecting %s\u005cn\u0022, name);\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (end - *p \u003c len + length + 8)\n+\t\treturn 1;\n+\n+\t*((*p)++) \u003d 0; /* literal hdr, literal name, */\n+\n+\t*((*p)++) \u003d 0 | lws_h2_num_start(7, len); /* non-HUF */\n+\tif (lws_h2_num(7, len, p, end))\n+\t\treturn 1;\n+\tmemcpy(*p, name, len);\n+\t*p +\u003d len;\n+\n+\t*((*p)++) \u003d 0 | lws_h2_num_start(7, length); /* non-HUF */\n+\tif (lws_h2_num(7, length, p, end))\n+\t\treturn 1;\n+\n+\tmemcpy(*p, value, length);\n+\t*p +\u003d length;\n+\n+\t//lwsl_hexdump(op, *p -op);\n+\n+\treturn 0;\n+}\n+\n+int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token,\n+\t\t\t\t const unsigned char *value, int length,\n+\t\t\t\t unsigned char **p, unsigned char *end)\n+{\n+\tconst unsigned char *name;\n+\n+\tname \u003d lws_token_to_string(token);\n+\tif (!name)\n+\t\treturn 1;\n+\n+\treturn lws_add_http2_header_by_name(wsi, name, value, length, p, end);\n+}\n+\n+int lws_add_http2_header_status(struct lws *wsi, unsigned int code,\n+\t\t\t\tunsigned char **p, unsigned char *end)\n+{\n+\tunsigned char status[10];\n+\tint n;\n+\n+\twsi-\u003eu.h2.send_END_STREAM \u003d 0; // !!(code \u003e\u003d 400);\n+\n+\tn \u003d sprintf((char *)status, \u0022%u\u0022, code);\n+\tif (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,\n+\t\t\t\t\t status, n, p, end))\n+\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\ndiff --git a/lib/http2/http2.c b/lib/http2/http2.c\nnew file mode 100644\nindex 0000000..7ba1060\n--- /dev/null\n+++ b/lib/http2/http2.c\n@@ -0,0 +1,1579 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+/*\n+ * bitmap of control messages that are valid to receive for each http2 state\n+ */\n+\n+static const uint16_t http2_rx_validity[] \u003d {\n+\t/* LWS_H2S_IDLE */\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n+//\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE)| /* ignore */\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION),\n+\t/* LWS_H2S_RESERVED_LOCAL */\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE),\n+\t/* LWS_H2S_RESERVED_REMOTE */\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY),\n+\t/* LWS_H2S_OPEN */\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_DATA) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PUSH_PROMISE) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PING) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_GOAWAY) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION),\n+\t/* LWS_H2S_HALF_CLOSED_REMOTE */\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM),\n+\t/* LWS_H2S_HALF_CLOSED_LOCAL */\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_DATA) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PUSH_PROMISE) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PING) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_GOAWAY) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION),\n+\t/* LWS_H2S_CLOSED */\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n+\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM),\n+};\n+\n+static const char *preface \u003d \u0022PRI * HTTP/2.0\u005cx0d\u005cx0a\u005cx0d\u005cx0aSM\u005cx0d\u005cx0a\u005cx0d\u005cx0a\u0022;\n+\n+static const char * const h2_state_names[] \u003d {\n+\t\u0022LWS_H2S_IDLE\u0022,\n+\t\u0022LWS_H2S_RESERVED_LOCAL\u0022,\n+\t\u0022LWS_H2S_RESERVED_REMOTE\u0022,\n+\t\u0022LWS_H2S_OPEN\u0022,\n+\t\u0022LWS_H2S_HALF_CLOSED_REMOTE\u0022,\n+\t\u0022LWS_H2S_HALF_CLOSED_LOCAL\u0022,\n+\t\u0022LWS_H2S_CLOSED\u0022,\n+};\n+\n+#if 0\n+static const char * const h2_setting_names[] \u003d {\n+\t\u0022\u0022,\n+\t\u0022H2SET_HEADER_TABLE_SIZE\u0022,\n+\t\u0022H2SET_ENABLE_PUSH\u0022,\n+\t\u0022H2SET_MAX_CONCURRENT_STREAMS\u0022,\n+\t\u0022H2SET_INITIAL_WINDOW_SIZE\u0022,\n+\t\u0022H2SET_MAX_FRAME_SIZE\u0022,\n+\t\u0022H2SET_MAX_HEADER_LIST_SIZE\u0022,\n+};\n+\n+void\n+lws_h2_dump_settings(struct http2_settings *set)\n+{\n+\tint n;\n+\n+\tfor (n \u003d 1; n \u003c H2SET_COUNT; n++)\n+\t\tlwsl_notice(\u0022 %30s: %10d\u005cn\u0022, h2_setting_names[n], set-\u003es[n]);\n+}\n+#else\n+void\n+lws_h2_dump_settings(struct http2_settings *set)\n+{\n+}\n+#endif\n+\n+void lws_h2_init(struct lws *wsi)\n+{\n+\twsi-\u003eu.h2.h2n-\u003eset \u003d wsi-\u003evhost-\u003eset;\n+}\n+\n+static void\n+lws_h2_state(struct lws *wsi, enum lws_h2_states s)\n+{\n+\tif (!wsi)\n+\t\treturn;\n+\tlwsl_info(\u0022%s: wsi %p: state %s -\u003e %s\u005cn\u0022, __func__, wsi,\n+\t\t\th2_state_names[wsi-\u003eu.h2.h2_state],\n+\t\t\th2_state_names[s]);\n+\twsi-\u003eu.h2.h2_state \u003d (uint8_t)s;\n+}\n+\n+struct lws *\n+lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,\n+\t\t\t unsigned int sid)\n+{\n+\tstruct lws *wsi;\n+\tstruct lws *nwsi \u003d lws_get_network_wsi(parent_wsi);\n+\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eu.h2.h2n;\n+\n+\t/*\n+\t * The identifier of a newly established stream MUST be numerically\n+ \t * greater than all streams that the initiating endpoint has opened or\n+ \t * reserved. This governs streams that are opened using a HEADERS frame\n+ \t * and streams that are reserved using PUSH_PROMISE. An endpoint that\n+ \t * receives an unexpected stream identifier MUST respond with a\n+ \t * connection error (Section 5.4.1) of type PROTOCOL_ERROR.\n+\t */\n+\tif (sid \u003c\u003d h2n-\u003ehighest_sid_opened) {\n+\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, \u0022Bad sid\u0022);\n+\t\treturn NULL;\n+\t}\n+\n+\t/* no more children allowed by parent */\n+\tif (parent_wsi-\u003eu.h2.child_count + 1 \u003e\n+\t parent_wsi-\u003eu.h2.h2n-\u003eset.s[H2SET_MAX_CONCURRENT_STREAMS]) {\n+\t\tlwsl_notice(\u0022reached concurrent stream limit\u005cn\u0022);\n+\t\treturn NULL;\n+\t}\n+\twsi \u003d lws_create_new_server_wsi(vh);\n+\tif (!wsi) {\n+\t\tlwsl_notice(\u0022new server wsi failed (vh %p)\u005cn\u0022, vh);\n+\t\treturn NULL;\n+\t}\n+\n+\th2n-\u003ehighest_sid_opened \u003d sid;\n+\twsi-\u003eu.h2.my_sid \u003d sid;\n+\twsi-\u003ehttp2_substream \u003d 1;\n+\n+\twsi-\u003eu.h2.parent_wsi \u003d parent_wsi;\n+\t/* new guy's sibling is whoever was the first child before */\n+\twsi-\u003eu.h2.sibling_list \u003d parent_wsi-\u003eu.h2.child_list;\n+\t/* first child is now the new guy */\n+\tparent_wsi-\u003eu.h2.child_list \u003d wsi;\n+\tparent_wsi-\u003eu.h2.child_count++;\n+\n+\twsi-\u003eu.h2.my_priority \u003d 16;\n+\twsi-\u003eu.h2.tx_cr \u003d nwsi-\u003eu.h2.h2n-\u003eset.s[H2SET_INITIAL_WINDOW_SIZE];\n+\twsi-\u003eu.h2.peer_tx_cr_est \u003d nwsi-\u003evhost-\u003eset.s[H2SET_INITIAL_WINDOW_SIZE];\n+\n+\twsi-\u003estate \u003d LWSS_HTTP2_ESTABLISHED;\n+\twsi-\u003emode \u003d parent_wsi-\u003emode;\n+\n+\twsi-\u003eprotocol \u003d \u0026vh-\u003eprotocols[0];\n+\tif (lws_ensure_user_space(wsi))\n+\t\tgoto bail1;\n+\n+\twsi-\u003evhost-\u003econn_stats.h2_subs++;\n+\n+\tlwsl_info(\u0022%s: %p new ch %p, sid %d, usersp\u003d%p, tx cr %d, \u0022\n+\t\t \u0022peer_credit %d (nwsi tx_cr %d)\u005cn\u0022,\n+\t\t __func__, parent_wsi, wsi, sid, wsi-\u003euser_space,\n+\t\t wsi-\u003eu.h2.tx_cr, wsi-\u003eu.h2.peer_tx_cr_est, nwsi-\u003eu.h2.tx_cr);\n+\n+\treturn wsi;\n+\n+bail1:\n+\t/* undo the insert */\n+\tparent_wsi-\u003eu.h2.child_list \u003d wsi-\u003eu.h2.sibling_list;\n+\tparent_wsi-\u003eu.h2.child_count--;\n+\n+\tif (wsi-\u003euser_space)\n+\t\tlws_free_set_NULL(wsi-\u003euser_space);\n+\tvh-\u003eprotocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);\n+\tlws_free(wsi);\n+\n+\treturn NULL;\n+}\n+\n+struct lws *\n+lws_h2_wsi_from_id(struct lws *parent_wsi, unsigned int sid)\n+{\n+\tlws_start_foreach_ll(struct lws *, wsi, parent_wsi-\u003eu.h2.child_list) {\n+\t\tif (wsi-\u003eu.h2.my_sid \u003d\u003d sid)\n+\t\t\treturn wsi;\n+\t} lws_end_foreach_ll(wsi, u.h2.sibling_list);\n+\n+\treturn NULL;\n+}\n+\n+int lws_remove_server_child_wsi(struct lws_context *context, struct lws *wsi)\n+{\n+\tlws_start_foreach_llp(struct lws **, w, wsi-\u003eu.h2.child_list) {\n+\t\tif (*w \u003d\u003d wsi) {\n+\t\t\t*w \u003d wsi-\u003eu.h2.sibling_list;\n+\t\t\t(wsi-\u003eu.h2.parent_wsi)-\u003eu.h2.child_count--;\n+\t\t\treturn 0;\n+\t\t}\n+\t} lws_end_foreach_llp(w, u.h2.sibling_list);\n+\n+\tlwsl_err(\u0022%s: can't find %p\u005cn\u0022, __func__, wsi);\n+\n+\treturn 1;\n+}\n+\n+void\n+lws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pps)\n+{\n+\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n+\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eu.h2.h2n;\n+\n+\tpps-\u003enext \u003d h2n-\u003epps;\n+\th2n-\u003epps \u003d pps;\n+\tlws_rx_flow_control(wsi, LWS_RXFLOW_REASON_APPLIES_DISABLE |\n+\t\t\t\t LWS_RXFLOW_REASON_H2_PPS_PENDING);\n+\tlws_callback_on_writable(wsi);\n+}\n+\n+static struct lws_h2_protocol_send *\n+lws_h2_new_pps(enum lws_h2_protocol_send_type type)\n+{\n+\tstruct lws_h2_protocol_send *pps \u003d lws_malloc(sizeof(*pps), \u0022pps\u0022);\n+\n+\tif (pps)\n+\t\tpps-\u003etype \u003d type;\n+\n+\treturn pps;\n+}\n+\n+int\n+lws_h2_goaway(struct lws *wsi, uint32_t err, const char *reason)\n+{\n+\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n+\tstruct lws_h2_protocol_send *pps;\n+\n+\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n+\t\treturn 0;\n+\n+\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_GOAWAY);\n+\tif (!pps)\n+\t\treturn 1;\n+\n+\tlwsl_info(\u0022%s: %p: ERR 0x%x, '%s'\u005cn\u0022, __func__, wsi, err, reason);\n+\n+\tpps-\u003eu.ga.err \u003d err;\n+\tpps-\u003eu.ga.highest_sid \u003d h2n-\u003ehighest_sid;\n+\tstrncpy(pps-\u003eu.ga.str, reason, sizeof(pps-\u003eu.ga.str) - 1);\n+\tpps-\u003eu.ga.str[sizeof(pps-\u003eu.ga.str) - 1] \u003d '\u005c0';\n+\tlws_pps_schedule(wsi, pps);\n+\n+\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason)\n+{\n+\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n+\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eu.h2.h2n;\n+\tstruct lws_h2_protocol_send *pps;\n+\n+\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n+\t\treturn 0;\n+\n+\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_RST_STREAM);\n+\tif (!pps)\n+\t\treturn 1;\n+\n+\tlwsl_info(\u0022%s: RST_STREAM 0x%x, REASON '%s'\u005cn\u0022, __func__, err, reason);\n+\n+\tpps-\u003eu.rs.sid \u003d h2n-\u003esid;\n+\tpps-\u003eu.rs.err \u003d err;\n+\tlws_pps_schedule(wsi, pps);\n+\n+\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n+\tlws_h2_state(wsi, LWS_H2_STATE_CLOSED);\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_h2_settings(struct lws *wsi, struct http2_settings *settings,\n+\t\t\tunsigned char *buf, int len)\n+{\n+\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n+\tunsigned int a, b;\n+\n+\tif (!len)\n+\t\treturn 0;\n+\n+\tif (len \u003c LWS_H2_SETTINGS_LEN)\n+\t\treturn 1;\n+\n+\twhile (len \u003e\u003d LWS_H2_SETTINGS_LEN) {\n+\t\ta \u003d (buf[0] \u003c\u003c 8) | buf[1];\n+\t\tif (!a || a \u003e\u003d H2SET_COUNT)\n+\t\t\tgoto skip;\n+\t\tb \u003d buf[2] \u003c\u003c 24 | buf[3] \u003c\u003c 16 | buf[4] \u003c\u003c 8 | buf[5];\n+\n+\t\tswitch (a) {\n+\t\tcase H2SET_HEADER_TABLE_SIZE:\n+\t\t\tbreak;\n+\t\tcase H2SET_ENABLE_PUSH:\n+\t\t\tif (b \u003e 1) {\n+\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022ENABLE_PUSH invalid arg\u0022);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase H2SET_MAX_CONCURRENT_STREAMS:\n+\t\t\tbreak;\n+\t\tcase H2SET_INITIAL_WINDOW_SIZE:\n+\t\t\tif (b \u003e 0x7fffffff) {\n+\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_FLOW_CONTROL_ERROR,\n+\t\t\t\t\t \u0022Inital Window beyond max\u0022);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t * In addition to changing the flow-control window for\n+\t\t\t * streams that are not yet active, a SETTINGS frame\n+\t\t\t * can alter the initial flow-control window size for\n+\t\t\t * streams with active flow-control windows (that is,\n+\t\t\t * streams in the \u0022open\u0022 or \u0022half-closed (remote)\u0022\n+\t\t\t * state). When the value of\n+\t\t\t * SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver\n+\t\t\t * MUST adjust the size of all stream flow-control\n+\t\t\t * windows that it maintains by the difference between\n+\t\t\t * the new value and the old value.\n+\t\t\t */\n+\n+\t\t\tlws_start_foreach_ll(struct lws *, w,\n+\t\t\t\t\t nwsi-\u003eu.h2.child_list) {\n+\t\t\t\tlwsl_info(\u0022%s: adi child tc cr %d +%d -\u003e %d\u0022,\n+\t\t\t\t\t __func__,\n+\t\t\t\t\t w-\u003eu.h2.tx_cr, b - settings-\u003es[a],\n+\t\t\t\t\t w-\u003eu.h2.tx_cr + b - settings-\u003es[a]);\n+\t\t\t\tw-\u003eu.h2.tx_cr +\u003d b - settings-\u003es[a];\n+\t\t\t\tif (w-\u003eu.h2.tx_cr \u003e 0 \u0026\u0026\n+\t\t\t\t w-\u003eu.h2.tx_cr \u003c\u003d b - settings-\u003es[a])\n+\t\t\t\t\tlws_callback_on_writable(w);\n+\t\t\t} lws_end_foreach_ll(w, u.h2.sibling_list);\n+\n+\t\t\tbreak;\n+\t\tcase H2SET_MAX_FRAME_SIZE:\n+\t\t\tif (b \u003c wsi-\u003evhost-\u003eset.s[H2SET_MAX_FRAME_SIZE]) {\n+\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022Frame size \u003c initial\u0022);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\tif (b \u003e 0x007fffff) {\n+\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022Settings Frame size above max\u0022);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase H2SET_MAX_HEADER_LIST_SIZE:\n+\t\t\tbreak;\n+\t\t}\n+\t\tsettings-\u003es[a] \u003d b;\n+\t\tlwsl_info(\u0022http2 settings %d \u003c- 0x%x\u005cn\u0022, a, b);\n+skip:\n+\t\tlen -\u003d LWS_H2_SETTINGS_LEN;\n+\t\tbuf +\u003d LWS_H2_SETTINGS_LEN;\n+\t}\n+\n+\tif (len)\n+\t\treturn 1;\n+\n+\tlws_h2_dump_settings(settings);\n+\n+\treturn 0;\n+}\n+\n+/* RFC7640 Sect 6.9\n+ *\n+ * The WINDOW_UPDATE frame can be specific to a stream or to the entire\n+ * connection. In the former case, the frame's stream identifier\n+ * indicates the affected stream; in the latter, the value \u00220\u0022 indicates\n+ * that the entire connection is the subject of the frame.\n+ *\n+ * ...\n+ *\n+ * Two flow-control windows are applicable: the stream flow-control\n+ * window and the connection flow-control window. The sender MUST NOT\n+ * send a flow-controlled frame with a length that exceeds the space\n+ * available in either of the flow-control windows advertised by the\n+ * receiver. Frames with zero length with the END_STREAM flag set (that\n+ * is, an empty DATA frame) MAY be sent if there is no available space\n+ * in either flow-control window.\n+ */\n+\n+int\n+lws_h2_tx_cr_get(struct lws *wsi)\n+{\n+\tint c \u003d wsi-\u003eu.h2.tx_cr;\n+\tstruct lws *nwsi;\n+\n+\tif (!wsi-\u003ehttp2_substream \u0026\u0026 !wsi-\u003eupgraded_to_http2)\n+\t\treturn ~0x80000000;\n+\n+\tnwsi \u003d lws_get_network_wsi(wsi);\n+\n+\tlwsl_info (\u0022%s: %p: own tx credit %d: nwsi credit %d\u005cn\u0022,\n+\t\t __func__, wsi, c, nwsi-\u003eu.h2.tx_cr);\n+\n+\tif (nwsi-\u003eu.h2.tx_cr \u003c c)\n+\t\tc \u003d nwsi-\u003eu.h2.tx_cr;\n+\n+\tif (c \u003c 0)\n+\t\treturn 0;\n+\n+\treturn c;\n+}\n+\n+void\n+lws_h2_tx_cr_consume(struct lws *wsi, int consumed)\n+{\n+\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n+\n+\twsi-\u003eu.h2.tx_cr -\u003d consumed;\n+\n+\tif (nwsi !\u003d wsi)\n+\t\tnwsi-\u003eu.h2.tx_cr -\u003d consumed;\n+}\n+\n+int lws_h2_frame_write(struct lws *wsi, int type, int flags,\n+\t\t unsigned int sid, unsigned int len, unsigned char *buf)\n+{\n+\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n+\tunsigned char *p \u003d \u0026buf[-LWS_H2_FRAME_HEADER_LENGTH];\n+\tint n;\n+\n+\t*p++ \u003d len \u003e\u003e 16;\n+\t*p++ \u003d len \u003e\u003e 8;\n+\t*p++ \u003d len;\n+\t*p++ \u003d type;\n+\t*p++ \u003d flags;\n+\t*p++ \u003d sid \u003e\u003e 24;\n+\t*p++ \u003d sid \u003e\u003e 16;\n+\t*p++ \u003d sid \u003e\u003e 8;\n+\t*p++ \u003d sid;\n+\n+\tlwsl_debug(\u0022%s: %p (eff %p). typ %d, fl 0x%x, sid\u003d%d, len\u003d%d, \u0022\n+\t\t \u0022txcr\u003d%d, nwsi-\u003etxcr\u003d%d\u005cn\u0022, __func__, wsi, nwsi, type, flags,\n+\t\t sid, len, wsi-\u003eu.h2.tx_cr, nwsi-\u003eu.h2.tx_cr);\n+\n+\tif (type \u003d\u003d LWS_H2_FRAME_TYPE_DATA) {\n+\t\tif (wsi-\u003eu.h2.tx_cr \u003c len)\n+\t\t\tlwsl_err(\u0022%s: %p: sending payload len %d\u0022\n+\t\t\t\t \u0022 but tx_cr only %d!\u005cn\u0022, __func__, wsi,\n+\t\t\t\t len, wsi-\u003eu.h2.tx_cr);\n+\t\tlws_h2_tx_cr_consume(wsi, len);\n+\t}\n+\n+\tn \u003d lws_issue_raw(nwsi, \u0026buf[-LWS_H2_FRAME_HEADER_LENGTH],\n+\t\t\t len + LWS_H2_FRAME_HEADER_LENGTH);\n+\tif (n \u003c 0)\n+\t\treturn n;\n+\n+\tif (n \u003e\u003d LWS_H2_FRAME_HEADER_LENGTH)\n+\t\treturn n - LWS_H2_FRAME_HEADER_LENGTH;\n+\n+\treturn n;\n+}\n+\n+static void lws_h2_set_bin(struct lws *wsi, int n, unsigned char *buf)\n+{\n+\t*buf++ \u003d n \u003e\u003e 8;\n+\t*buf++ \u003d n;\n+\t*buf++ \u003d wsi-\u003eu.h2.h2n-\u003eset.s[n] \u003e\u003e 24;\n+\t*buf++ \u003d wsi-\u003eu.h2.h2n-\u003eset.s[n] \u003e\u003e 16;\n+\t*buf++ \u003d wsi-\u003eu.h2.h2n-\u003eset.s[n] \u003e\u003e 8;\n+\t*buf \u003d wsi-\u003eu.h2.h2n-\u003eset.s[n];\n+}\n+\n+int lws_h2_do_pps_send(struct lws *wsi)\n+{\n+\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n+\tstruct lws_h2_protocol_send *pps \u003d NULL;\n+\tstruct lws *cwsi;\n+\tuint8_t set[LWS_PRE + 64], *p \u003d \u0026set[LWS_PRE], *q;\n+\tint n, m \u003d 0;\n+\n+\tif (!h2n)\n+\t\treturn 1;\n+\n+\t/* get the oldest pps */\n+\n+\tlws_start_foreach_llp(struct lws_h2_protocol_send **, pps1, h2n-\u003epps) {\n+\t\tif ((*pps1)-\u003enext \u003d\u003d NULL) { /* we are the oldest in the list */\n+\t\t\tpps \u003d *pps1; /* remove us from the list */\n+\t\t\t*pps1 \u003d NULL;\n+\t\t\tcontinue;\n+\t\t}\n+\t} lws_end_foreach_llp(pps1, next);\n+\n+\tif (!pps)\n+\t\treturn 1;\n+\n+\tlwsl_info(\u0022%s: %p: %d\u005cn\u0022, __func__, wsi, pps-\u003etype);\n+\n+\tswitch (pps-\u003etype) {\n+\n+\tcase LWS_H2_PPS_MY_SETTINGS:\n+\t\t/*\n+\t\t * if any of our settings varies from h2 \u0022default defaults\u0022\n+\t\t * then we must inform the perr\n+\t\t */\n+\t\tfor (n \u003d 1; n \u003c H2SET_COUNT; n++)\n+\t\t\tif (h2n-\u003eset.s[n] !\u003d lws_h2_defaults.s[n]) {\n+\t\t\t\tlwsl_debug(\u0022sending SETTING %d 0x%x\u005cn\u0022, n,\n+\t\t\t\t\t\twsi-\u003eu.h2.h2n-\u003eset.s[n]);\n+\t\t\t\tlws_h2_set_bin(wsi, n, \u0026set[LWS_PRE + m]);\n+\t\t\t\tm +\u003d sizeof(h2n-\u003eone_setting);\n+\t\t\t}\n+\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,\n+\t\t \t\t 0, LWS_H2_STREAM_ID_MASTER, m,\n+\t\t \t\t \u0026set[LWS_PRE]);\n+\t\tif (n !\u003d m) {\n+\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n+\t\t\tgoto bail;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_H2_PPS_ACK_SETTINGS:\n+\t\t/* send ack ... always empty */\n+\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS, 1,\n+\t\t\t\t LWS_H2_STREAM_ID_MASTER, 0, \u0026set[LWS_PRE]);\n+\t\tif (n) {\n+\t\t\tlwsl_err(\u0022ack tells %d\u005cn\u0022, n);\n+\t\t\tgoto bail;\n+\t\t}\n+\t\t/* this is the end of the preface dance then? */\n+\t\tif (wsi-\u003estate \u003d\u003d LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS) {\n+\t\t\twsi-\u003estate \u003d LWSS_HTTP2_ESTABLISHED;\n+\t\t\twsi-\u003eu.http.fop_fd \u003d NULL;\n+\t\t\tif (lws_is_ssl(lws_get_network_wsi(wsi)))\n+\t\t\t\tbreak;\n+\t\t\t/*\n+\t\t\t * we need to treat the headers from the upgrade as the\n+\t\t\t * first job. So these need to get shifted to sid 1.\n+\t\t\t */\n+\t\t\th2n-\u003eswsi \u003d lws_wsi_server_new(wsi-\u003evhost, wsi, 1);\n+\t\t\tif (!h2n-\u003eswsi)\n+\t\t\t\tgoto bail;\n+\n+\t\t\t/* pass on the initial headers to SID 1 */\n+\t\t\th2n-\u003eswsi-\u003eu.http.ah \u003d wsi-\u003eu.http.ah;\n+\t\t\twsi-\u003eu.http.ah \u003d NULL;\n+\n+\t\t\tlwsl_info(\u0022%s: inherited headers %p\u005cn\u0022, __func__,\n+\t\t\t\t h2n-\u003eswsi-\u003eu.http.ah);\n+\t\t\th2n-\u003eswsi-\u003eu.h2.tx_cr \u003d\n+\t\t\t\th2n-\u003eset.s[H2SET_INITIAL_WINDOW_SIZE];\n+\t\t\tlwsl_info(\u0022initial tx credit on conn %p: %d\u005cn\u0022,\n+\t\t\t\t h2n-\u003eswsi, h2n-\u003eswsi-\u003eu.h2.tx_cr);\n+\t\t\th2n-\u003eswsi-\u003eu.h2.initialized \u003d 1;\n+\t\t\t/* demanded by HTTP2 */\n+\t\t\th2n-\u003eswsi-\u003eu.h2.END_STREAM \u003d 1;\n+\t\t\tlwsl_info(\u0022servicing initial http request\u005cn\u0022);\n+\n+\t\t\twsi-\u003evhost-\u003econn_stats.h2_trans++;\n+\n+\t\t\tif (lws_http_action(h2n-\u003eswsi))\n+\t\t\t\tgoto bail;\n+\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\tcase LWS_H2_PPS_PONG:\n+\t\tlwsl_debug(\u0022sending PONG\u005cn\u0022);\n+\t\tmemcpy(\u0026set[LWS_PRE], pps-\u003eu.ping.ping_payload, 8);\n+\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING,\n+\t\t \t\t LWS_H2_FLAG_SETTINGS_ACK,\n+\t\t\t\t LWS_H2_STREAM_ID_MASTER, 8,\n+\t\t\t\t \u0026set[LWS_PRE]);\n+\t\tif (n !\u003d 8) {\n+\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n+\t\t\tgoto bail;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_H2_PPS_GOAWAY:\n+\t\tlwsl_info(\u0022LWS_H2_PPS_GOAWAY\u005cn\u0022);\n+\t\t*p++ \u003d pps-\u003eu.ga.highest_sid \u003e\u003e 24;\n+\t\t*p++ \u003d pps-\u003eu.ga.highest_sid \u003e\u003e 16;\n+\t\t*p++ \u003d pps-\u003eu.ga.highest_sid \u003e\u003e 8;\n+\t\t*p++ \u003d pps-\u003eu.ga.highest_sid;\n+\t\t*p++ \u003d pps-\u003eu.ga.err \u003e\u003e 24;\n+\t\t*p++ \u003d pps-\u003eu.ga.err \u003e\u003e 16;\n+\t\t*p++ \u003d pps-\u003eu.ga.err \u003e\u003e 8;\n+\t\t*p++ \u003d pps-\u003eu.ga.err;\n+\t\tq \u003d (unsigned char *)pps-\u003eu.ga.str;\n+\t\tn \u003d 0;\n+\t\twhile (*q \u0026\u0026 n++ \u003c sizeof(pps-\u003eu.ga.str))\n+\t\t\t*p++ \u003d *q++;\n+\t\th2n-\u003ewe_told_goaway \u003d 1;\n+\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_GOAWAY, 0,\n+\t\t\t\t LWS_H2_STREAM_ID_MASTER,\n+\t\t\t\t p - \u0026set[LWS_PRE], \u0026set[LWS_PRE]);\n+\t\tif (n !\u003d 4) {\n+\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n+\t\t\tgoto bail;\n+\t\t}\n+\t\tgoto bail;\n+\n+\tcase LWS_H2_PPS_RST_STREAM:\n+\t\tlwsl_info(\u0022LWS_H2_PPS_RST_STREAM\u005cn\u0022);\n+\t\t*p++ \u003d pps-\u003eu.rs.err \u003e\u003e 24;\n+\t\t*p++ \u003d pps-\u003eu.rs.err \u003e\u003e 16;\n+\t\t*p++ \u003d pps-\u003eu.rs.err \u003e\u003e 8;\n+\t\t*p++ \u003d pps-\u003eu.rs.err;\n+\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_RST_STREAM,\n+\t\t\t\t 0, pps-\u003eu.rs.sid, 4, \u0026set[LWS_PRE]);\n+\t\tif (n !\u003d 4) {\n+\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n+\t\t\tgoto bail;\n+\t\t}\n+\t\tcwsi \u003d lws_h2_wsi_from_id(wsi, pps-\u003eu.rs.sid);\n+\t\tif (cwsi)\n+\t\t\tlws_close_free_wsi(cwsi, 0);\n+\t\tbreak;\n+\n+\tcase LWS_H2_PPS_UPDATE_WINDOW:\n+\t\tlwsl_notice(\u0022LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\u005cn\u0022,\n+\t\t\t pps-\u003eu.update_window.sid,\n+\t\t\t pps-\u003eu.update_window.credit);\n+\t\t*p++ \u003d pps-\u003eu.update_window.credit \u003e\u003e 24;\n+\t\t*p++ \u003d pps-\u003eu.update_window.credit \u003e\u003e 16;\n+\t\t*p++ \u003d pps-\u003eu.update_window.credit \u003e\u003e 8;\n+\t\t*p++ \u003d pps-\u003eu.update_window.credit;\n+\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_WINDOW_UPDATE,\n+\t\t\t\t 0, pps-\u003eu.update_window.sid, 4,\n+\t\t\t\t \u0026set[LWS_PRE]);\n+\t\tif (n !\u003d 4) {\n+\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n+\t\t\tgoto bail;\n+\t\t}\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tlws_free(pps);\n+\n+\treturn 0;\n+\n+bail:\n+\tlws_free(pps);\n+\n+\treturn 1;\n+}\n+\n+/*\n+ * The frame header part has just completely arrived.\n+ * Perform actions for frame completion.\n+ */\n+static int\n+lws_h2_parse_frame_header(struct lws *wsi)\n+{\n+\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n+\tstruct lws_h2_protocol_send *pps;\n+\tint n;\n+\n+\t/*\n+\t * We just got the frame header\n+\t */\n+\th2n-\u003ecount \u003d 0;\n+\th2n-\u003eswsi \u003d wsi;\n+\t/* b31 is a reserved bit */\n+\th2n-\u003esid \u003d h2n-\u003esid \u0026 0x7fffffff;\n+\n+\tif (h2n-\u003esid \u0026\u0026 !(h2n-\u003esid \u0026 1)) {\n+\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022Even Stream ID\u0022);\n+\n+\t\treturn 0;\n+\t}\n+\n+\t/* let the network wsi live a bit longer if subs are active */\n+\tlws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 10);\n+\n+\t/* let the network wsi live a bit longer if subs are active */\n+\tlws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 10);\n+\n+\tif (h2n-\u003esid)\n+\t\th2n-\u003eswsi \u003d lws_h2_wsi_from_id(wsi, h2n-\u003esid);\n+\n+\tlwsl_info(\u0022%p (%p): fr hdr: typ 0x%x, flags 0x%x, sid 0x%x, len 0x%x\u005cn\u0022,\n+\t\t wsi, h2n-\u003eswsi, h2n-\u003etype, h2n-\u003eflags, h2n-\u003esid,\n+\t\t h2n-\u003elength);\n+\n+\tif (h2n-\u003ewe_told_goaway \u0026\u0026 h2n-\u003esid \u003e h2n-\u003ehighest_sid)\n+\t\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n+\n+\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n+\t\treturn 0;\n+\n+\tif (h2n-\u003elength \u003e h2n-\u003eset.s[H2SET_MAX_FRAME_SIZE]) {\n+\t\t/*\n+\t\t * peer sent us something bigger than we told\n+\t\t * it we would allow\n+\t\t */\n+\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n+\t\t\t \u0022Peer ignored our frame size setting\u0022);\n+\t\treturn 0;\n+\t}\n+\n+\tif (h2n-\u003eswsi)\n+\t\tlwsl_info(\u0022%s: wsi %p, State: %s, received cmd %d\u005cn\u0022,\n+\t\t __func__, h2n-\u003eswsi,\n+\t\t h2_state_names[h2n-\u003eswsi-\u003eu.h2.h2_state], h2n-\u003etype);\n+\telse {\n+\t\t/* if it's data, either way no swsi means CLOSED state */\n+\t\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_DATA) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,\n+\t\t\t\t \u0022Data for nonexistant sid\u0022);\n+\t\t\treturn 0;\n+\t\t}\n+\t\t/* if the sid is credible, treat as wsi for it closed */\n+\t\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid_opened \u0026\u0026\n+\t\t h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_HEADERS \u0026\u0026\n+\t\t h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_PRIORITY) {\n+\t\t\t/* if not credible, reject it */\n+\t\t\tlwsl_info(\u0022%s: wsi %p, No child for sid %d, rx cmd %d\u005cn\u0022,\n+\t\t\t __func__, h2n-\u003eswsi, h2n-\u003esid, h2n-\u003etype);\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,\n+\t\t\t\t \u0022Data for nonexistant sid\u0022);\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\tif (h2n-\u003eswsi \u0026\u0026 h2n-\u003esid \u0026\u0026\n+\t !(http2_rx_validity[h2n-\u003eswsi-\u003eu.h2.h2_state] \u0026 (1 \u003c\u003c h2n-\u003etype))) {\n+\t\tlwsl_info(\u0022%s: wsi %p, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\u005cn\u0022,\n+\t\t\t __func__, h2n-\u003eswsi,\n+\t\t\t h2_state_names[h2n-\u003eswsi-\u003eu.h2.h2_state], h2n-\u003etype,\n+\t\t\t http2_rx_validity[h2n-\u003eswsi-\u003eu.h2.h2_state]);\n+\n+\t\tif (h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED ||\n+\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_REMOTE)\n+\t\t\tn \u003d H2_ERR_STREAM_CLOSED;\n+\t\telse\n+\t\t\tn \u003d H2_ERR_PROTOCOL_ERROR;\n+\t\tlws_h2_goaway(wsi, n, \u0022invalid rx for state\u0022);\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (h2n-\u003econt_exp \u0026\u0026 (h2n-\u003econt_exp_sid !\u003d h2n-\u003esid ||\n+\t\t\t h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_CONTINUATION)) {\n+\t\tlwsl_info(\u0022%s: expected cont on sid %d (got %d on sid %d)\u005cn\u0022,\n+\t\t\t __func__, h2n-\u003econt_exp_sid, h2n-\u003etype, h2n-\u003esid);\n+\t\th2n-\u003econt_exp \u003d 0;\n+\t\tif (h2n-\u003econt_exp_headers)\n+\t\t\tn \u003d H2_ERR_COMPRESSION_ERROR;\n+\t\telse\n+\t\t\tn \u003d H2_ERR_PROTOCOL_ERROR;\n+\t\tlws_h2_goaway(wsi, n, \u0022Continuation hdrs State\u0022);\n+\n+\t\treturn 0;\n+\t}\n+\n+\tswitch (h2n-\u003etype) {\n+\tcase LWS_H2_FRAME_TYPE_DATA:\n+\t\tlwsl_info(\u0022seen incoming LWS_H2_FRAME_TYPE_DATA start\u005cn\u0022);\n+\t\tif (!h2n-\u003esid) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022DATA 0 sid\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tlwsl_info(\u0022Frame header DATA: sid %d\u005cn\u0022, h2n-\u003esid);\n+\n+\t\tif (!h2n-\u003eswsi)\n+\t\t\tbreak;\n+\n+\t\th2n-\u003eswsi-\u003eu.h2.peer_tx_cr_est -\u003d h2n-\u003elength;\n+\t\tlwsl_debug(\u0022 peer_tx_cr_est %d\u005cn\u0022,\n+\t\t\t h2n-\u003eswsi-\u003eu.h2.peer_tx_cr_est);\n+\t\tif (h2n-\u003eswsi-\u003eu.h2.peer_tx_cr_est \u003c 32768) {\n+\t\t\th2n-\u003eswsi-\u003eu.h2.peer_tx_cr_est +\u003d 65536;\n+\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);\n+\t\t\tif (!pps)\n+\t\t\t\treturn 1;\n+\t\t\tpps-\u003eu.update_window.sid \u003d h2n-\u003esid;\n+\t\t\tpps-\u003eu.update_window.credit \u003d 65536;\n+\t\t\tlws_pps_schedule(wsi, pps);\n+\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);\n+\t\t\tif (!pps)\n+\t\t\t\treturn 1;\n+\t\t\tpps-\u003eu.update_window.sid \u003d 0;\n+\t\t\tpps-\u003eu.update_window.credit \u003d 65536;\n+\t\t\tlws_pps_schedule(wsi, pps);\n+\t\t}\n+\n+\t\tif (\n+\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_REMOTE ||\n+\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, \u0022conn closed\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\tcase LWS_H2_FRAME_TYPE_PRIORITY:\n+\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_PRIORITY complete frame\u005cn\u0022);\n+\t\tif (!h2n-\u003esid) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t \u0022Priority has 0 sid\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (h2n-\u003elength !\u003d 5) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n+\t\t\t\t \u0022Priority has length other than 5\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\tcase LWS_H2_FRAME_TYPE_PUSH_PROMISE:\n+\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_PUSH_PROMISE complete frame\u005cn\u0022);\n+\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022Server only\u0022);\n+\t\tbreak;\n+\n+\tcase LWS_H2_FRAME_TYPE_GOAWAY:\n+\t\tbreak;\n+\n+\tcase LWS_H2_FRAME_TYPE_RST_STREAM:\n+\t\tif (!h2n-\u003esid)\n+\t\t\treturn 1;\n+\t\tif (!h2n-\u003eswsi) {\n+\t\t\tif (h2n-\u003esid \u003c\u003d h2n-\u003ehighest_sid_opened)\n+\t\t\t\tbreak;\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t \u0022crazy sid on RST_STREAM\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\t\tif (h2n-\u003elength !\u003d 4) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n+\t\t\t\t \u0022RST_STREAM can only be length 4\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n+\t\tbreak;\n+\n+\tcase LWS_H2_FRAME_TYPE_SETTINGS:\n+\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_SETTINGS complete frame\u005cn\u0022);\n+\t\t/* nonzero sid on settings is illegal */\n+\t\tif (h2n-\u003esid) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022Settings has nonzero sid\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (!(h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK)) {\n+\t\t\tif ((!h2n-\u003elength) || h2n-\u003elength % 6) {\n+\t\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n+\t\t\t\t\t\t \u0022Settings length error\u0022);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tlwsl_info(\u0022scheduled settings ack PPS\u005cn\u0022);\n+\t\t\t/* non-ACK coming in means we must ACK it */\n+\n+\n+\t\t\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n+\t\t\t\treturn 0;\n+\n+\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);\n+\t\t\tif (!pps)\n+\t\t\t\treturn 1;\n+\t\t\tlws_pps_schedule(wsi, pps);\n+\t\t\tbreak;\n+\t\t}\n+\t\t/* came to us with ACK set... not allowed to have payload */\n+\n+\t\tif (h2n-\u003elength) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n+\t\t\t\t \u0022Settings with ACK not allowed payload\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\tcase LWS_H2_FRAME_TYPE_PING:\n+\t\tif (h2n-\u003esid) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t \u0022Ping has nonzero sid\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (h2n-\u003elength !\u003d 8) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n+\t\t\t\t \u0022Ping payload can only be 8\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\tcase LWS_H2_FRAME_TYPE_CONTINUATION:\n+\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_CONTINUATION: sid \u003d %d\u005cn\u0022,\n+\t\t\t h2n-\u003esid);\n+\n+\t\tif (!h2n-\u003econt_exp ||\n+\t\t h2n-\u003econt_exp_sid !\u003d h2n-\u003esid ||\n+\t\t !h2n-\u003esid ||\n+\t\t !h2n-\u003eswsi) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t \u0022unexpected CONTINUATION\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (h2n-\u003eswsi-\u003eu.h2.END_HEADERS) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t \u0022END_HEADERS already seen\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\t/* END_STREAM is in HEADERS, skip resetting it */\n+\t\tgoto update_end_headers;\n+\n+\tcase LWS_H2_FRAME_TYPE_HEADERS:\n+\t\tlwsl_info(\u0022HEADERS: frame header: sid \u003d %d\u005cn\u0022, h2n-\u003esid);\n+\t\tif (!h2n-\u003esid) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022sid 0\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tif (!h2n-\u003eswsi) {\n+\t\t\t/* no more children allowed by parent */\n+\t\t\tif (wsi-\u003eu.h2.child_count + 1 \u003e\n+\t\t\t wsi-\u003eu.h2.h2n-\u003eset.s[H2SET_MAX_CONCURRENT_STREAMS]) {\n+\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\u0022Another stream not allowed\u0022);\n+\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n+\t\t\th2n-\u003eswsi \u003d lws_wsi_server_new(wsi-\u003evhost, wsi,\n+\t\t\t\t\t\t h2n-\u003esid);\n+\t\t\tif (!h2n-\u003eswsi) {\n+\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022OOM\u0022);\n+\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/*\n+\t\t * ah needs attaching to child wsi, even though\n+\t\t * we only fill it from network wsi\n+\t\t */\n+\t\tif (!h2n-\u003eswsi-\u003eu.hdr.ah)\n+\t\t\tif (lws_header_table_attach(h2n-\u003eswsi, 0)) {\n+\t\t\t\tlwsl_err(\u0022%s: Failed to get ah\u005cn\u0022, __func__);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n+\t\t/*\n+\t\t * The first use of a new stream identifier implicitly closes\n+\t\t * all streams in the \u0022idle\u0022 state that might have been\n+\t\t * initiated by that peer with a lower-valued stream identifier.\n+\t\t *\n+\t\t * For example, if a client sends a HEADERS frame on stream 7\n+\t\t * without ever sending a frame on stream 5, then stream 5\n+\t\t * transitions to the \u0022closed\u0022 state when the first frame for\n+\t\t * stream 7 is sent or received.\n+\t\t */\n+\t\tlws_start_foreach_ll(struct lws *, w, wsi-\u003eu.h2.child_list) {\n+\t\t\tif (w-\u003eu.h2.my_sid \u003c h2n-\u003esid \u0026\u0026\n+\t\t\t w-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_IDLE)\n+\t\t\t\tlws_close_free_wsi(w, 0);\n+\t\t} lws_end_foreach_ll(w, u.h2.sibling_list);\n+\n+\n+\t\t/* END_STREAM means after servicing this, close the stream */\n+\t\th2n-\u003eswsi-\u003eu.h2.END_STREAM \u003d\n+\t\t\t\t\t!!(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_STREAM);\n+\t\tlwsl_info(\u0022%s: hdr END_STREAM \u003d %d\u005cn\u0022,__func__,\n+\t\t\t h2n-\u003eswsi-\u003eu.h2.END_STREAM);\n+\n+\t\th2n-\u003econt_exp \u003d !(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_HEADERS);\n+\t\th2n-\u003econt_exp_sid \u003d h2n-\u003esid;\n+\t\th2n-\u003econt_exp_headers \u003d 1;\n+\t\th2n-\u003eseen_nonpseudoheader \u003d 0;\n+\t\tlws_header_table_reset(h2n-\u003eswsi, 0);\n+\n+update_end_headers:\n+\t\t/* no END_HEADERS means CONTINUATION must come */\n+\t\th2n-\u003eswsi-\u003eu.h2.END_HEADERS \u003d\n+\t\t\t\t!!(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_HEADERS);\n+\t\tif (h2n-\u003eswsi-\u003eu.h2.END_HEADERS)\n+\t\t\th2n-\u003econt_exp \u003d 0;\n+\t\tlwsl_debug(\u0022END_HEADERS %d\u005cn\u0022, h2n-\u003eswsi-\u003eu.h2.END_HEADERS);\n+\t\tbreak;\n+\n+\tcase LWS_H2_FRAME_TYPE_WINDOW_UPDATE:\n+\t\tif (h2n-\u003elength !\u003d 4) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n+\t\t\t\t \u0022window update frame not 4\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_WINDOW_UPDATE\u005cn\u0022);\n+\t\tbreak;\n+\tdefault:\n+\t\tlwsl_info(\u0022%s: ILLEGAL FRAME TYPE %d\u005cn\u0022, __func__, h2n-\u003etype);\n+\t\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n+\t\tbreak;\n+\t}\n+\tif (h2n-\u003elength \u003d\u003d 0)\n+\t\th2n-\u003eframe_state \u003d 0;\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * The last byte of the whole frame has been handled.\n+ * Perform actions for frame completion.\n+ */\n+static int\n+lws_h2_parse_end_of_frame(struct lws *wsi)\n+{\n+\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n+\tstruct lws_h2_protocol_send *pps;\n+\tstruct lws *eff_wsi \u003d wsi;\n+\tconst char *p;\n+\tint n;\n+\n+\th2n-\u003eframe_state \u003d 0;\n+\th2n-\u003ecount \u003d 0;\n+\n+\tif (h2n-\u003esid)\n+\t\th2n-\u003eswsi \u003d lws_h2_wsi_from_id(wsi, h2n-\u003esid);\n+\n+\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid)\n+\t\th2n-\u003ehighest_sid \u003d h2n-\u003esid;\n+\n+\t/* set our initial window size */\n+\tif (!wsi-\u003eu.h2.initialized) {\n+\t\twsi-\u003eu.h2.tx_cr \u003d h2n-\u003eset.s[H2SET_INITIAL_WINDOW_SIZE];\n+\t\tlwsl_info(\u0022initial tx credit on master %p: %d\u005cn\u0022, wsi,\n+\t\t\t wsi-\u003eu.h2.tx_cr);\n+\t\twsi-\u003eu.h2.initialized \u003d 1;\n+\t}\n+\n+\tif (h2n-\u003ecollected_priority \u0026\u0026 (h2n-\u003edep \u0026 ~(1 \u003c\u003c 31)) \u003d\u003d h2n-\u003esid) {\n+\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022depends on own sid\u0022);\n+\t\treturn 0;\n+\t}\n+\n+\tswitch (h2n-\u003etype) {\n+\tcase LWS_H2_FRAME_TYPE_CONTINUATION:\n+\tcase LWS_H2_FRAME_TYPE_HEADERS:\n+\n+\t\t/* service the http request itself */\n+\n+\t\tif (h2n-\u003elast_action_dyntable_resize) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,\n+\t\t\t\t\u0022dyntable resize last in headers\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (!h2n-\u003eswsi-\u003eu.h2.END_HEADERS) {\n+\t\t\t/* we are not finished yet */\n+\t\t\tlwsl_info(\u0022witholding http action for continuation\u005cn\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* confirm the hpack stream state is reasonable for finishing */\n+\n+\t\tif (h2n-\u003ehpack !\u003d HPKS_TYPE) {\n+\t\t\t/* hpack incomplete */\n+\t\t\tlwsl_info(\u0022hpack incomplete %d (type %d, len %d)\u005cn\u0022,\n+\t\t\t\t h2n-\u003ehpack, h2n-\u003etype, h2n-\u003ehpack_len);\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,\n+\t\t\t\t \u0022hpack incomplete\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* this is the last part of HEADERS */\n+\t\tswitch (h2n-\u003eswsi-\u003eu.h2.h2_state) {\n+\t\tcase LWS_H2_STATE_IDLE:\n+\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_OPEN);\n+\t\t\tbreak;\n+\t\tcase LWS_H2_STATE_RESERVED_REMOTE:\n+\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_HALF_CLOSED_LOCAL);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tlwsl_info(\u0022http req, wsi\u003d%p, h2n-\u003eswsi\u003d%p\u005cn\u0022, wsi, h2n-\u003eswsi);\n+\t\th2n-\u003eswsi-\u003ehdr_parsing_completed \u003d 1;\n+\n+\t\tif (lws_hdr_extant(h2n-\u003eswsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n+\t\t\th2n-\u003eswsi-\u003eu.http.rx_content_length \u003d atoll(\n+\t\t\t\tlws_hdr_simple_ptr(h2n-\u003eswsi,\n+\t\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH));\n+\t\t\th2n-\u003eswsi-\u003eu.http.rx_content_remain \u003d\n+\t\t\t\t\th2n-\u003eswsi-\u003eu.http.rx_content_length;\n+\t\t\tlwsl_info(\u0022setting rx_content_length %lld\u005cn\u0022,\n+\t\t\t\t (long long)h2n-\u003eswsi-\u003eu.http.rx_content_length);\n+\t\t}\n+\n+\t\t{\n+\t\t\tint n \u003d 0, len;\n+\t\t\tchar buf[256];\n+\t\t\tconst unsigned char *c;\n+\n+\t\t\tdo {\n+\t\t\t\tc \u003d lws_token_to_string(n);\n+\t\t\t\tif (!c) {\n+\t\t\t\t\tn++;\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\n+\t\t\t\tlen \u003d lws_hdr_total_length(h2n-\u003eswsi, n);\n+\t\t\t\tif (!len || len \u003e sizeof(buf) - 1) {\n+\t\t\t\t\tn++;\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\n+\t\t\t\tlws_hdr_copy(h2n-\u003eswsi, buf, sizeof buf, n);\n+\t\t\t\tbuf[sizeof(buf) - 1] \u003d '\u005c0';\n+\n+\t\t\t\tlwsl_info(\u0022 %s \u003d %s\u005cn\u0022, (char *)c, buf);\n+\t\t\t\tn++;\n+\t\t\t} while (c);\n+\t\t}\n+\n+\t\tif (h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_REMOTE ||\n+\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,\n+\t\t\t\t \u0022Banning service on CLOSED_REMOTE\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tswitch (h2n-\u003eswsi-\u003eu.h2.h2_state) {\n+\t\tcase LWS_H2_STATE_OPEN:\n+\t\t\tif (h2n-\u003eswsi-\u003eu.h2.END_STREAM)\n+\t\t\t\tlws_h2_state(h2n-\u003eswsi,\n+\t\t\t\t\t LWS_H2_STATE_HALF_CLOSED_REMOTE);\n+\t\t\tbreak;\n+\t\tcase LWS_H2_STATE_HALF_CLOSED_LOCAL:\n+\t\t\tif (h2n-\u003eswsi-\u003eu.h2.END_STREAM)\n+\t\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (!lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_PATH) ||\n+\t\t !lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_METHOD) ||\n+\t\t !lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_SCHEME) ||\n+\t\t lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_STATUS) ||\n+\t\t lws_hdr_extant(h2n-\u003eswsi, WSI_TOKEN_CONNECTION)) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t \u0022Pseudoheader checks\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (lws_hdr_extant(h2n-\u003eswsi, WSI_TOKEN_TE)) {\n+\t\t\tn \u003d lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_TE);\n+\n+\t\t\tif (n !\u003d 8 ||\n+\t\t\t strncmp(lws_hdr_simple_ptr(h2n-\u003eswsi, WSI_TOKEN_TE),\n+\t\t\t\t \u0022trailers\u0022, n)) {\n+\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022Illegal transfer-encoding\u0022);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tp \u003d lws_hdr_simple_ptr(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_METHOD);\n+\t\tif (!strcmp(p, \u0022POST\u0022))\n+\t\t\th2n-\u003eswsi-\u003eu.hdr.ah-\u003efrag_index[WSI_TOKEN_POST_URI] \u003d\n+\t\t\t\th2n-\u003eswsi-\u003eu.hdr.ah-\u003efrag_index[WSI_TOKEN_HTTP_COLON_PATH];\n+\n+\t\twsi-\u003evhost-\u003econn_stats.h2_trans++;\n+\n+\t\tlwsl_info(\u0022 action start...\u005cn\u0022);\n+\t\tn \u003d lws_http_action(h2n-\u003eswsi);\n+\t\tlwsl_info(\u0022 action result %d \u0022\n+\t\t\t \u0022(wsi-\u003eu.http.rx_content_remain %lld)\u005cn\u0022,\n+\t\t\t n, h2n-\u003eswsi-\u003eu.http.rx_content_remain);\n+\n+\t\t/*\n+\t\t * Commonly we only managed to start a larger transfer that will\n+\t\t * complete asynchronously. In those cases we will hear about\n+\t\t * END_STREAM going out in the POLLOUT handler.\n+\t\t */\n+\t\tif (n || h2n-\u003eswsi-\u003eu.h2.send_END_STREAM) {\n+\t\t\tlws_close_free_wsi(h2n-\u003eswsi, 0);\n+\t\t\th2n-\u003eswsi \u003d NULL;\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_H2_FRAME_TYPE_DATA:\n+\t\tif (!h2n-\u003eswsi)\n+\t\t\tbreak;\n+\n+\t\tif (lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) \u0026\u0026\n+\t\t h2n-\u003eswsi-\u003eu.h2.END_STREAM \u0026\u0026\n+\t\t h2n-\u003eswsi-\u003eu.http.rx_content_length \u0026\u0026\n+\t\t h2n-\u003eswsi-\u003eu.http.rx_content_remain) {\n+\t\t\tlws_h2_rst_stream(h2n-\u003eswsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022Not enough rx content\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (h2n-\u003eswsi-\u003eu.h2.END_STREAM \u0026\u0026\n+\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_OPEN)\n+\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_HALF_CLOSED_REMOTE);\n+\n+\t\tif (h2n-\u003eswsi-\u003eu.h2.END_STREAM \u0026\u0026\n+\t\t h2n-\u003eswsi-\u003eu.h2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_LOCAL)\n+\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n+\t\tbreak;\n+\n+\tcase LWS_H2_FRAME_TYPE_PING:\n+\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK) { // ack\n+\t\t} else {/* they're sending us a ping request */\n+\t\t\tlwsl_info(\u0022rx ping, preparing pong\u005cn\u0022);\n+\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_PONG);\n+\t\t\tif (!pps)\n+\t\t\t\treturn 1;\n+\t\t\tmemcpy(pps-\u003eu.ping.ping_payload, h2n-\u003eping_payload, 8);\n+\t\t\tlws_pps_schedule(wsi, pps);\n+\t\t}\n+\n+\t\tbreak;\n+\n+\tcase LWS_H2_FRAME_TYPE_WINDOW_UPDATE:\n+\t\th2n-\u003ehpack_e_dep \u0026\u003d ~(1 \u003c\u003c 31);\n+\t\tlwsl_info(\u0022WINDOW_UPDATE: sid %d %u (0x%x)\u005cn\u0022, h2n-\u003esid,\n+\t\t\t h2n-\u003ehpack_e_dep, h2n-\u003ehpack_e_dep);\n+\n+\t\tif (h2n-\u003esid)\n+\t\t\teff_wsi \u003d h2n-\u003eswsi;\n+\n+\t\tif (!eff_wsi) {\n+\t\t\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid_opened)\n+\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022alien sid\u0022);\n+\t\t\tbreak; /* ignore */\n+\t\t}\n+\n+\t\tif ((uint64_t)eff_wsi-\u003eu.h2.tx_cr + (uint64_t)h2n-\u003ehpack_e_dep \u003e\n+\t\t (uint64_t)0x7fffffff) {\n+\t\t\tif (h2n-\u003esid)\n+\t\t\t\tlws_h2_rst_stream(h2n-\u003eswsi,\n+\t\t\t\t\t\t H2_ERR_FLOW_CONTROL_ERROR,\n+\t\t\t\t\t\t \u0022Flow control exceeded max\u0022);\n+\t\t\telse\n+\t\t\t\tlws_h2_goaway(wsi, H2_ERR_FLOW_CONTROL_ERROR,\n+\t\t\t\t\t \u0022Flow control exceeded max\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (!h2n-\u003ehpack_e_dep) {\n+\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t \u0022Zero length window update\u0022);\n+\t\t\tbreak;\n+\t\t}\n+\t\tn \u003d eff_wsi-\u003eu.h2.tx_cr;\n+\t\teff_wsi-\u003eu.h2.tx_cr +\u003d h2n-\u003ehpack_e_dep;\n+\n+\t\tif (n \u003c\u003d 0 \u0026\u0026 eff_wsi-\u003eu.h2.tx_cr \u003c\u003d 0)\n+\t\t\t/* it helps, but won't change sendability for anyone */\n+\t\t\tbreak;\n+\n+\t\t/*\n+\t\t * It did change sendability... for us and any children waiting\n+\t\t * on us... reassess blockage for all children first\n+\t\t */\n+\t\tlws_start_foreach_ll(struct lws *, w, wsi-\u003eu.h2.child_list) {\n+\t\t\tlws_callback_on_writable(w);\n+\t\t} lws_end_foreach_ll(w, u.h2.sibling_list);\n+\n+\t\tif (eff_wsi-\u003eu.h2.skint \u0026\u0026 lws_h2_tx_cr_get(eff_wsi)) {\n+\t\t\tlwsl_info(\u0022%s: %p: skint\u005cn\u0022, __func__, wsi);\n+\t\t\teff_wsi-\u003eu.h2.skint \u003d 0;\n+\t\t\tlws_callback_on_writable(eff_wsi);\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_H2_FRAME_TYPE_GOAWAY:\n+\t\tlwsl_info(\u0022GOAWAY: last sid %d, error 0x%08X, string '%s'\u005cn\u0022,\n+\t\t\t h2n-\u003egoaway_last_sid, h2n-\u003egoaway_err,\n+\t\t\t h2n-\u003egoaway_str);\n+\t\twsi-\u003eu.h2.GOING_AWAY \u003d 1;\n+\n+\t\treturn 1;\n+\n+\tcase LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_h2_parser(struct lws *wsi, unsigned char c)\n+{\n+\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eu.h2.h2n;\n+\tstruct lws_h2_protocol_send *pps;\n+\tint n;\n+\n+\tif (!h2n)\n+\t\treturn 1;\n+\n+\tswitch (wsi-\u003estate) {\n+\tcase LWSS_HTTP2_AWAIT_CLIENT_PREFACE:\n+\t\tif (preface[h2n-\u003ecount++] !\u003d c)\n+\t\t\treturn 1;\n+\n+\t\tif (preface[h2n-\u003ecount])\n+\t\t\tbreak;\n+\n+\t\tlwsl_info(\u0022http2: %p: established\u005cn\u0022, wsi);\n+\t\twsi-\u003estate \u003d LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS;\n+\t\th2n-\u003ecount \u003d 0;\n+\t\twsi-\u003eu.h2.tx_cr \u003d 65535;\n+\n+\t\t/*\n+\t\t * we must send a settings frame -- empty one is OK...\n+\t\t * that must be the first thing sent by server\n+\t\t * and the peer must send a SETTINGS with ACK flag...\n+\t\t */\n+\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS);\n+\t\tif (!pps)\n+\t\t\treturn 1;\n+\t\tlws_pps_schedule(wsi, pps);\n+\t\tbreak;\n+\n+\tcase LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS:\n+\tcase LWSS_HTTP2_ESTABLISHED:\n+\t\tif (h2n-\u003eframe_state !\u003d LWS_H2_FRAME_HEADER_LENGTH)\n+\t\t\tgoto try_frame_start;\n+\n+\t\t/*\n+\t\t * post-header, preamble / payload / padding part\n+\t\t */\n+\t\th2n-\u003ecount++;\n+\n+\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_PADDED \u0026\u0026 !h2n-\u003epad_length) {\n+\t\t\t/*\n+\t\t\t * Get the padding count... actual padding is\n+\t\t\t * at the end of the frame.\n+\t\t\t */\n+\t\t\th2n-\u003epadding \u003d c;\n+\t\t\th2n-\u003epad_length \u003d 1;\n+\t\t\th2n-\u003epreamble++;\n+\n+\t\t\tif (h2n-\u003epadding \u003e h2n-\u003elength - 1)\n+\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022execssive padding\u0022);\n+\t\t\tbreak; /* we consumed this */\n+\t\t}\n+\n+\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_PRIORITY \u0026\u0026\n+\t\t !h2n-\u003ecollected_priority) {\n+\t\t\t/* going to be 5 preamble bytes */\n+\n+\t\t\tlwsl_debug(\u0022PRIORITY FLAG: 0x%x\u005cn\u0022, c);\n+\n+\t\t\tif (h2n-\u003epreamble++ - h2n-\u003epad_length \u003c 4) {\n+\t\t\t\th2n-\u003edep \u003d ((h2n-\u003edep) \u003c\u003c 8) | c;\n+\t\t\t\tbreak; /* we consumed this */\n+\t\t\t}\n+\t\t\th2n-\u003eweight_temp \u003d c;\n+\t\t\th2n-\u003ecollected_priority \u003d 1;\n+\t\t\tlwsl_debug(\u0022PRI FL: dep 0x%x, weight 0x%02X\u005cn\u0022,\n+\t\t\t\t h2n-\u003edep, h2n-\u003eweight_temp);\n+\t\t\tbreak; /* we consumed this */\n+\t\t}\n+\t\tif (h2n-\u003epadding \u0026\u0026 h2n-\u003ecount \u003e (h2n-\u003elength - h2n-\u003epadding)) {\n+\t\t\tif (c) {\n+\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022nonzero padding\u0022);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tgoto frame_end;\n+\t\t}\n+\n+\t\t/* applies to wsi-\u003eu.h2.swsi which may be wsi */\n+\t\tswitch(h2n-\u003etype) {\n+\n+\t\tcase LWS_H2_FRAME_TYPE_SETTINGS:\n+\t\t\tn \u003d (h2n-\u003ecount - 1 - h2n-\u003epreamble) %\n+\t\t\t LWS_H2_SETTINGS_LEN;\n+\t\t\th2n-\u003eone_setting[n] \u003d c;\n+\t\t\tif (n !\u003d LWS_H2_SETTINGS_LEN - 1)\n+\t\t\t\tbreak;\n+\t\t\tlws_h2_settings(wsi, \u0026h2n-\u003eset, h2n-\u003eone_setting,\n+\t\t\t\t\tLWS_H2_SETTINGS_LEN);\n+\t\t\tbreak;\n+\n+\t\tcase LWS_H2_FRAME_TYPE_CONTINUATION:\n+\t\tcase LWS_H2_FRAME_TYPE_HEADERS:\n+\t\t\tif (!h2n-\u003eswsi)\n+\t\t\t\tbreak;\n+\t\t\tif (lws_hpack_interpret(h2n-\u003eswsi, c)) {\n+\t\t\t\tlwsl_info(\u0022%s: hpack failed\u005cn\u0022, __func__);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase LWS_H2_FRAME_TYPE_GOAWAY:\n+\t\t\tswitch (h2n-\u003einside++) {\n+\t\t\tcase 0:\n+\t\t\tcase 1:\n+\t\t\tcase 2:\n+\t\t\tcase 3:\n+\t\t\t\th2n-\u003egoaway_last_sid \u003c\u003c\u003d 8;\n+\t\t\t\th2n-\u003egoaway_last_sid |\u003d c;\n+\t\t\t\th2n-\u003egoaway_str[0] \u003d '\u005c0';\n+\t\t\t\tbreak;\n+\n+\t\t\tcase 4:\n+\t\t\tcase 5:\n+\t\t\tcase 6:\n+\t\t\tcase 7:\n+\t\t\t\th2n-\u003egoaway_err \u003c\u003c\u003d 8;\n+\t\t\t\th2n-\u003egoaway_err |\u003d c;\n+\t\t\t\tbreak;\n+\n+\t\t\tdefault:\n+\t\t\t\tif (h2n-\u003einside - 9 \u003c\n+\t\t\t\t sizeof(h2n-\u003egoaway_str) - 1)\n+\t\t\t\t\th2n-\u003egoaway_str[h2n-\u003einside - 9] \u003d c;\n+\t\t\t\th2n-\u003egoaway_str[sizeof(h2n-\u003egoaway_str) - 1] \u003d '\u005c0';\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase LWS_H2_FRAME_TYPE_DATA:\n+\t\t\t//lwsl_notice(\u0022incoming LWS_H2_FRAME_TYPE_DATA content\u005cn\u0022);\n+\t\t\tif (!h2n-\u003eswsi) {\n+\t\t\t\t//lwsl_notice(\u0022data sid %d has no swsi\u005cn\u0022, h2n-\u003esid);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\th2n-\u003eswsi-\u003estate \u003d LWSS_HTTP_BODY;\n+\t\t\th2n-\u003einside++;\n+\t\t\tif (lws_hdr_total_length(h2n-\u003eswsi,\n+\t\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH) \u0026\u0026\n+\t\t\t h2n-\u003eswsi-\u003eu.http.rx_content_length \u0026\u0026\n+\t\t\t h2n-\u003eswsi-\u003eu.http.rx_content_remain \u003d\u003d 1 \u0026\u0026 /* last */\n+\t\t\t h2n-\u003einside \u003c h2n-\u003elength) { /* unread data in frame */\n+\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t \u0022More rx than content_length told\u0022);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tn \u003d lws_read(h2n-\u003eswsi, \u0026c, 1);\n+\t\t\tif (n \u003c 0) {\n+\t\t\t//\tlws_h2_rst_stream(wsi, LWS_H2_PPS_RST_STREAM,\n+\t\t\t//\t\t\t \u0022post body done\u0022);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase LWS_H2_FRAME_TYPE_PRIORITY:\n+\t\t\tif (h2n-\u003ecount \u003c\u003d 4) {\n+\t\t\t\th2n-\u003edep \u003c\u003c\u003d 8;\n+\t\t\t\th2n-\u003edep |\u003d c;\n+\t\t\t} else {\n+\t\t\t\th2n-\u003eweight_temp \u003d c;\n+\t\t\t\tlwsl_info(\u0022PRIORITY: dep 0x%x, weight 0x%02X\u005cn\u0022,\n+\t\t\t\t\t h2n-\u003edep, h2n-\u003eweight_temp);\n+\n+\t\t\t\tif ((h2n-\u003edep \u0026 ~(1 \u003c\u003c 31)) \u003d\u003d h2n-\u003esid) {\n+\t\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n+\t\t\t\t\t\t \u0022cant depend on own sid\u0022);\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase LWS_H2_FRAME_TYPE_RST_STREAM:\n+\t\t\tbreak;\n+\n+\t\tcase LWS_H2_FRAME_TYPE_PUSH_PROMISE:\n+\t\t\tbreak;\n+\n+\t\tcase LWS_H2_FRAME_TYPE_PING:\n+\t\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK) { // ack\n+\t\t\t} else { /* they're sending us a ping request */\n+\t\t\t\tif (h2n-\u003ecount \u003e 8)\n+\t\t\t\t\treturn 1;\n+\t\t\t\th2n-\u003eping_payload[h2n-\u003ecount - 1] \u003d c;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase LWS_H2_FRAME_TYPE_WINDOW_UPDATE:\n+\t\t\th2n-\u003ehpack_e_dep \u003c\u003c\u003d 8;\n+\t\t\th2n-\u003ehpack_e_dep |\u003d c;\n+\t\t\tbreak;\n+\n+\t\tcase LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tlwsl_notice(\u0022%s: unhandled frame type %d\u005cn\u0022,\n+\t\t\t\t __func__, h2n-\u003etype);\n+\n+\t\t\treturn 1;\n+\t\t}\n+\n+frame_end:\n+\t\tif (h2n-\u003ecount !\u003d h2n-\u003elength)\n+\t\t\tbreak;\n+\n+\t\t/*\n+\t\t * end of frame just happened\n+\t\t */\n+\t\tif (lws_h2_parse_end_of_frame(wsi))\n+\t\t\treturn 1;\n+\t\tbreak;\n+\n+try_frame_start:\n+\t\tif (h2n-\u003eframe_state \u003c\u003d 8) {\n+\n+\t\t\tswitch (h2n-\u003eframe_state++) {\n+\t\t\tcase 0:\n+\t\t\t\th2n-\u003epad_length \u003d 0;\n+\t\t\t\th2n-\u003ecollected_priority \u003d 0;\n+\t\t\t\th2n-\u003epadding \u003d 0;\n+\t\t\t\th2n-\u003epreamble \u003d 0;\n+\t\t\t\th2n-\u003elength \u003d c;\n+\t\t\t\th2n-\u003einside \u003d 0;\n+\t\t\t\tbreak;\n+\t\t\tcase 1:\n+\t\t\tcase 2:\n+\t\t\t\th2n-\u003elength \u003c\u003c\u003d 8;\n+\t\t\t\th2n-\u003elength |\u003d c;\n+\t\t\t\tbreak;\n+\t\t\tcase 3:\n+\t\t\t\th2n-\u003etype \u003d c;\n+\t\t\t\tbreak;\n+\t\t\tcase 4:\n+\t\t\t\th2n-\u003eflags \u003d c;\n+\t\t\t\tbreak;\n+\n+\t\t\tcase 5:\n+\t\t\tcase 6:\n+\t\t\tcase 7:\n+\t\t\tcase 8:\n+\t\t\t\th2n-\u003esid \u003c\u003c\u003d 8;\n+\t\t\t\th2n-\u003esid |\u003d c;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tif (h2n-\u003eframe_state \u003d\u003d LWS_H2_FRAME_HEADER_LENGTH)\n+\t\t\tif (lws_h2_parse_frame_header(wsi))\n+\t\t\t\treturn 1;\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\ndiff --git a/lib/http2/huftable.h b/lib/http2/huftable.h\nnew file mode 100644\nindex 0000000..385a83b\n--- /dev/null\n+++ b/lib/http2/huftable.h\n@@ -0,0 +1,530 @@\n+static unsigned char lextable[] \u003d {\n+/* pos 0000: 0 */ /* 0 */ 0x42 /* (to 0x0084 state 98) */,\n+ /* 1 */ 0x01 /* (to 0x0002 state 1) */,\n+/* pos 0002: 1 */ /* 0 */ 0x5C /* (to 0x00BA state 151) */,\n+ /* 1 */ 0x01 /* (to 0x0004 state 2) */,\n+/* pos 0004: 2 */ /* 0 */ 0x66 /* (to 0x00D0 state 173) */,\n+ /* 1 */ 0x01 /* (to 0x0006 state 3) */,\n+/* pos 0006: 3 */ /* 0 */ 0x74 /* (to 0x00EE state 204) */,\n+ /* 1 */ 0x01 /* (to 0x0008 state 4) */,\n+/* pos 0008: 4 */ /* 0 */ 0x8C /* (to 0x0120 state 263) */,\n+ /* 1 */ 0x01 /* (to 0x000A state 5) */,\n+/* pos 000a: 5 */ /* 0 */ 0x46 /* (to 0x0096 state 113) */,\n+ /* 1 */ 0x01 /* (to 0x000C state 6) */,\n+/* pos 000c: 6 */ /* 0 */ 0x75 /* (to 0x00F6 state 211) */,\n+ /* 1 */ 0x01 /* (to 0x000E state 7) */,\n+/* pos 000e: 7 */ /* 0 */ 0x40 /* (to 0x008E state 104) */,\n+ /* 1 */ 0x01 /* (to 0x0010 state 8) */,\n+/* pos 0010: 8 */ /* 0 */ 0x45 /* (to 0x009A state 116) */,\n+ /* 1 */ 0x01 /* (to 0x0012 state 9) */,\n+/* pos 0012: 9 */ /* 0 */ 0x40 /* (to 0x0092 state 108) */,\n+ /* 1 */ 0x01 /* (to 0x0014 state 10) */,\n+/* pos 0014: 10 */ /* 0 */ 0x01 /* (to 0x0016 state 11) */,\n+ /* 1 */ 0x03 /* (to 0x001A state 14) */,\n+/* pos 0016: 11 */ /* 0 */ 0x01 /* (to 0x0018 state 12) */,\n+ /* 1 */ 0x5B /* (to 0x00CC state 166) */,\n+/* pos 0018: 12 */ /* terminal 0 */ 0x00,\n+ /* terminal 36 */ 0x24,\n+/* pos 001a: 14 */ /* 0 */ 0x72 /* (to 0x00FE state 220) */,\n+ /* 1 */ 0x01 /* (to 0x001C state 15) */,\n+/* pos 001c: 15 */ /* 0 */ 0x72 /* (to 0x0100 state 222) */,\n+ /* 1 */ 0x01 /* (to 0x001E state 16) */,\n+/* pos 001e: 16 */ /* 0 */ 0x53 /* (to 0x00C4 state 158) */,\n+ /* 1 */ 0x01 /* (to 0x0020 state 17) */,\n+/* pos 0020: 17 */ /* terminal 123 */ 0x7B,\n+ /* 1 */ 0x01 /* (to 0x0022 state 18) */,\n+/* pos 0022: 18 */ /* 0 */ 0x6B /* (to 0x00F8 state 216) */,\n+ /* 1 */ 0x01 /* (to 0x0024 state 19) */,\n+/* pos 0024: 19 */ /* 0 */ 0x84 /* (to 0x012C state 279) */,\n+ /* 1 */ 0x01 /* (to 0x0026 state 20) */,\n+/* pos 0026: 20 */ /* 0 */ 0x01 /* (to 0x0028 state 21) */,\n+ /* 1 */ 0x06 /* (to 0x0032 state 27) */,\n+/* pos 0028: 21 */ /* 0 */ 0xB3 /* (to 0x018E state 377) */,\n+ /* 1 */ 0x01 /* (to 0x002A state 22) */,\n+/* pos 002a: 22 */ /* 0 */ 0xC3 /* (to 0x01B0 state 414) */,\n+ /* 1 */ 0x01 /* (to 0x002C state 23) */,\n+/* pos 002c: 23 */ /* 0 */ 0x01 /* (to 0x002E state 24) */,\n+ /* 1 */ 0x8C /* (to 0x0144 state 301) */,\n+/* pos 002e: 24 */ /* 0 */ 0x01 /* (to 0x0030 state 25) */,\n+ /* 1 */ 0x8A /* (to 0x0142 state 298) */,\n+/* pos 0030: 25 */ /* terminal 1 */ 0x01,\n+ /* terminal 135 */ 0x87,\n+/* pos 0032: 27 */ /* 0 */ 0x8E /* (to 0x014E state 314) */,\n+ /* 1 */ 0x01 /* (to 0x0034 state 28) */,\n+/* pos 0034: 28 */ /* 0 */ 0x0F /* (to 0x0052 state 50) */,\n+ /* 1 */ 0x01 /* (to 0x0036 state 29) */,\n+/* pos 0036: 29 */ /* 0 */ 0xA4 /* (to 0x017E state 362) */,\n+ /* 1 */ 0x01 /* (to 0x0038 state 30) */,\n+/* pos 0038: 30 */ /* 0 */ 0xB7 /* (to 0x01A6 state 403) */,\n+ /* 1 */ 0x01 /* (to 0x003A state 31) */,\n+/* pos 003a: 31 */ /* 0 */ 0xC8 /* (to 0x01CA state 440) */,\n+ /* 1 */ 0x01 /* (to 0x003C state 32) */,\n+/* pos 003c: 32 */ /* 0 */ 0x01 /* (to 0x003E state 33) */,\n+ /* 1 */ 0x0F /* (to 0x005A state 55) */,\n+/* pos 003e: 33 */ /* 0 */ 0x01 /* (to 0x0040 state 34) */,\n+ /* 1 */ 0x07 /* (to 0x004C state 46) */,\n+/* pos 0040: 34 */ /* 0 */ 0x01 /* (to 0x0042 state 35) */,\n+ /* 1 */ 0x03 /* (to 0x0046 state 39) */,\n+/* pos 0042: 35 */ /* terminal 254 */ 0xFE,\n+ /* 1 */ 0x01 /* (to 0x0044 state 36) */,\n+/* pos 0044: 36 */ /* terminal 2 */ 0x02,\n+ /* terminal 3 */ 0x03,\n+/* pos 0046: 39 */ /* 0 */ 0x01 /* (to 0x0048 state 40) */,\n+ /* 1 */ 0x02 /* (to 0x004A state 43) */,\n+/* pos 0048: 40 */ /* terminal 4 */ 0x04,\n+ /* terminal 5 */ 0x05,\n+/* pos 004a: 43 */ /* terminal 6 */ 0x06,\n+ /* terminal 7 */ 0x07,\n+/* pos 004c: 46 */ /* 0 */ 0x01 /* (to 0x004E state 47) */,\n+ /* 1 */ 0x0E /* (to 0x0068 state 67) */,\n+/* pos 004e: 47 */ /* 0 */ 0x01 /* (to 0x0050 state 48) */,\n+ /* 1 */ 0x0C /* (to 0x0066 state 63) */,\n+/* pos 0050: 48 */ /* terminal 8 */ 0x08,\n+ /* terminal 11 */ 0x0B,\n+/* pos 0052: 50 */ /* 0 */ 0xA7 /* (to 0x01A0 state 396) */,\n+ /* 1 */ 0x01 /* (to 0x0054 state 51) */,\n+/* pos 0054: 51 */ /* 0 */ 0x01 /* (to 0x0056 state 52) */,\n+ /* 1 */ 0x7B /* (to 0x014A state 309) */,\n+/* pos 0056: 52 */ /* terminal 239 */ 0xEF,\n+ /* 1 */ 0x01 /* (to 0x0058 state 53) */,\n+/* pos 0058: 53 */ /* terminal 9 */ 0x09,\n+ /* terminal 142 */ 0x8E,\n+/* pos 005a: 55 */ /* 0 */ 0x0A /* (to 0x006E state 74) */,\n+ /* 1 */ 0x01 /* (to 0x005C state 56) */,\n+/* pos 005c: 56 */ /* 0 */ 0x11 /* (to 0x007E state 91) */,\n+ /* 1 */ 0x01 /* (to 0x005E state 57) */,\n+/* pos 005e: 57 */ /* 0 */ 0x64 /* (to 0x0126 state 274) */,\n+ /* 1 */ 0x01 /* (to 0x0060 state 58) */,\n+/* pos 0060: 58 */ /* terminal 249 */ 0xF9,\n+ /* 1 */ 0x01 /* (to 0x0062 state 59) */,\n+/* pos 0062: 59 */ /* 0 */ 0x01 /* (to 0x0064 state 60) */,\n+ /* 1 */ 0x0A /* (to 0x0076 state 81) */,\n+/* pos 0064: 60 */ /* terminal 10 */ 0x0A,\n+ /* terminal 13 */ 0x0D,\n+/* pos 0066: 63 */ /* terminal 12 */ 0x0C,\n+ /* terminal 14 */ 0x0E,\n+/* pos 0068: 67 */ /* 0 */ 0x01 /* (to 0x006A state 68) */,\n+ /* 1 */ 0x02 /* (to 0x006C state 71) */,\n+/* pos 006a: 68 */ /* terminal 15 */ 0x0F,\n+ /* terminal 16 */ 0x10,\n+/* pos 006c: 71 */ /* terminal 17 */ 0x11,\n+ /* terminal 18 */ 0x12,\n+/* pos 006e: 74 */ /* 0 */ 0x01 /* (to 0x0070 state 75) */,\n+ /* 1 */ 0x05 /* (to 0x0078 state 84) */,\n+/* pos 0070: 75 */ /* 0 */ 0x01 /* (to 0x0072 state 76) */,\n+ /* 1 */ 0x02 /* (to 0x0074 state 79) */,\n+/* pos 0072: 76 */ /* terminal 19 */ 0x13,\n+ /* terminal 20 */ 0x14,\n+/* pos 0074: 79 */ /* terminal 21 */ 0x15,\n+ /* terminal 23 */ 0x17,\n+/* pos 0076: 81 */ /* terminal 22 */ 0x16,\n+ /* terminal 256 */ 0x00,\n+/* pos 0078: 84 */ /* 0 */ 0x01 /* (to 0x007A state 85) */,\n+ /* 1 */ 0x02 /* (to 0x007C state 88) */,\n+/* pos 007a: 85 */ /* terminal 24 */ 0x18,\n+ /* terminal 25 */ 0x19,\n+/* pos 007c: 88 */ /* terminal 26 */ 0x1A,\n+ /* terminal 27 */ 0x1B,\n+/* pos 007e: 91 */ /* 0 */ 0x01 /* (to 0x0080 state 92) */,\n+ /* 1 */ 0x02 /* (to 0x0082 state 95) */,\n+/* pos 0080: 92 */ /* terminal 28 */ 0x1C,\n+ /* terminal 29 */ 0x1D,\n+/* pos 0082: 95 */ /* terminal 30 */ 0x1E,\n+ /* terminal 31 */ 0x1F,\n+/* pos 0084: 98 */ /* 0 */ 0x13 /* (to 0x00AA state 133) */,\n+ /* 1 */ 0x01 /* (to 0x0086 state 99) */,\n+/* pos 0086: 99 */ /* 0 */ 0x01 /* (to 0x0088 state 100) */,\n+ /* 1 */ 0x0F /* (to 0x00A4 state 129) */,\n+/* pos 0088: 100 */ /* 0 */ 0x4B /* (to 0x011E state 258) */,\n+ /* 1 */ 0x01 /* (to 0x008A state 101) */,\n+/* pos 008a: 101 */ /* 0 */ 0x01 /* (to 0x008C state 102) */,\n+ /* 1 */ 0x0C /* (to 0x00A2 state 126) */,\n+/* pos 008c: 102 */ /* terminal 32 */ 0x20,\n+ /* terminal 37 */ 0x25,\n+/* pos 008e: 104 */ /* 0 */ 0x01 /* (to 0x0090 state 105) */,\n+ /* 1 */ 0x08 /* (to 0x009E state 119) */,\n+/* pos 0090: 105 */ /* terminal 33 */ 0x21,\n+ /* terminal 34 */ 0x22,\n+/* pos 0092: 108 */ /* terminal 124 */ 0x7C,\n+ /* 1 */ 0x01 /* (to 0x0094 state 109) */,\n+/* pos 0094: 109 */ /* terminal 35 */ 0x23,\n+ /* terminal 62 */ 0x3E,\n+/* pos 0096: 113 */ /* 0 */ 0x01 /* (to 0x0098 state 114) */,\n+ /* 1 */ 0x05 /* (to 0x00A0 state 124) */,\n+/* pos 0098: 114 */ /* terminal 38 */ 0x26,\n+ /* terminal 42 */ 0x2A,\n+/* pos 009a: 116 */ /* terminal 63 */ 0x3F,\n+ /* 1 */ 0x01 /* (to 0x009C state 117) */,\n+/* pos 009c: 117 */ /* terminal 39 */ 0x27,\n+ /* terminal 43 */ 0x2B,\n+/* pos 009e: 119 */ /* terminal 40 */ 0x28,\n+ /* terminal 41 */ 0x29,\n+/* pos 00a0: 124 */ /* terminal 44 */ 0x2C,\n+ /* terminal 59 */ 0x3B,\n+/* pos 00a2: 126 */ /* terminal 45 */ 0x2D,\n+ /* terminal 46 */ 0x2E,\n+/* pos 00a4: 129 */ /* 0 */ 0x01 /* (to 0x00A6 state 130) */,\n+ /* 1 */ 0x08 /* (to 0x00B4 state 144) */,\n+/* pos 00a6: 130 */ /* 0 */ 0x01 /* (to 0x00A8 state 131) */,\n+ /* 1 */ 0x06 /* (to 0x00B2 state 141) */,\n+/* pos 00a8: 131 */ /* terminal 47 */ 0x2F,\n+ /* terminal 51 */ 0x33,\n+/* pos 00aa: 133 */ /* 0 */ 0x01 /* (to 0x00AC state 134) */,\n+ /* 1 */ 0x2D /* (to 0x0104 state 229) */,\n+/* pos 00ac: 134 */ /* 0 */ 0x01 /* (to 0x00AE state 135) */,\n+ /* 1 */ 0x02 /* (to 0x00B0 state 138) */,\n+/* pos 00ae: 135 */ /* terminal 48 */ 0x30,\n+ /* terminal 49 */ 0x31,\n+/* pos 00b0: 138 */ /* terminal 50 */ 0x32,\n+ /* terminal 97 */ 0x61,\n+/* pos 00b2: 141 */ /* terminal 52 */ 0x34,\n+ /* terminal 53 */ 0x35,\n+/* pos 00b4: 144 */ /* 0 */ 0x01 /* (to 0x00B6 state 145) */,\n+ /* 1 */ 0x02 /* (to 0x00B8 state 148) */,\n+/* pos 00b6: 145 */ /* terminal 54 */ 0x36,\n+ /* terminal 55 */ 0x37,\n+/* pos 00b8: 148 */ /* terminal 56 */ 0x38,\n+ /* terminal 57 */ 0x39,\n+/* pos 00ba: 151 */ /* 0 */ 0x06 /* (to 0x00C6 state 160) */,\n+ /* 1 */ 0x01 /* (to 0x00BC state 152) */,\n+/* pos 00bc: 152 */ /* 0 */ 0x2C /* (to 0x0114 state 246) */,\n+ /* 1 */ 0x01 /* (to 0x00BE state 153) */,\n+/* pos 00be: 153 */ /* 0 */ 0x2F /* (to 0x011C state 256) */,\n+ /* 1 */ 0x01 /* (to 0x00C0 state 154) */,\n+/* pos 00c0: 154 */ /* 0 */ 0x01 /* (to 0x00C2 state 155) */,\n+ /* 1 */ 0x07 /* (to 0x00CE state 170) */,\n+/* pos 00c2: 155 */ /* terminal 58 */ 0x3A,\n+ /* terminal 66 */ 0x42,\n+/* pos 00c4: 158 */ /* terminal 60 */ 0x3C,\n+ /* terminal 96 */ 0x60,\n+/* pos 00c6: 160 */ /* 0 */ 0x01 /* (to 0x00C8 state 161) */,\n+ /* 1 */ 0x21 /* (to 0x0108 state 232) */,\n+/* pos 00c8: 161 */ /* 0 */ 0x01 /* (to 0x00CA state 162) */,\n+ /* 1 */ 0x1D /* (to 0x0102 state 224) */,\n+/* pos 00ca: 162 */ /* terminal 61 */ 0x3D,\n+ /* terminal 65 */ 0x41,\n+/* pos 00cc: 166 */ /* terminal 64 */ 0x40,\n+ /* terminal 91 */ 0x5B,\n+/* pos 00ce: 170 */ /* terminal 67 */ 0x43,\n+ /* terminal 68 */ 0x44,\n+/* pos 00d0: 173 */ /* 0 */ 0x01 /* (to 0x00D2 state 174) */,\n+ /* 1 */ 0x08 /* (to 0x00E0 state 189) */,\n+/* pos 00d2: 174 */ /* 0 */ 0x01 /* (to 0x00D4 state 175) */,\n+ /* 1 */ 0x04 /* (to 0x00DA state 182) */,\n+/* pos 00d4: 175 */ /* 0 */ 0x01 /* (to 0x00D6 state 176) */,\n+ /* 1 */ 0x02 /* (to 0x00D8 state 179) */,\n+/* pos 00d6: 176 */ /* terminal 69 */ 0x45,\n+ /* terminal 70 */ 0x46,\n+/* pos 00d8: 179 */ /* terminal 71 */ 0x47,\n+ /* terminal 72 */ 0x48,\n+/* pos 00da: 182 */ /* 0 */ 0x01 /* (to 0x00DC state 183) */,\n+ /* 1 */ 0x02 /* (to 0x00DE state 186) */,\n+/* pos 00dc: 183 */ /* terminal 73 */ 0x49,\n+ /* terminal 74 */ 0x4A,\n+/* pos 00de: 186 */ /* terminal 75 */ 0x4B,\n+ /* terminal 76 */ 0x4C,\n+/* pos 00e0: 189 */ /* 0 */ 0x01 /* (to 0x00E2 state 190) */,\n+ /* 1 */ 0x04 /* (to 0x00E8 state 197) */,\n+/* pos 00e2: 190 */ /* 0 */ 0x01 /* (to 0x00E4 state 191) */,\n+ /* 1 */ 0x02 /* (to 0x00E6 state 194) */,\n+/* pos 00e4: 191 */ /* terminal 77 */ 0x4D,\n+ /* terminal 78 */ 0x4E,\n+/* pos 00e6: 194 */ /* terminal 79 */ 0x4F,\n+ /* terminal 80 */ 0x50,\n+/* pos 00e8: 197 */ /* 0 */ 0x01 /* (to 0x00EA state 198) */,\n+ /* 1 */ 0x02 /* (to 0x00EC state 201) */,\n+/* pos 00ea: 198 */ /* terminal 81 */ 0x51,\n+ /* terminal 82 */ 0x52,\n+/* pos 00ec: 201 */ /* terminal 83 */ 0x53,\n+ /* terminal 84 */ 0x54,\n+/* pos 00ee: 204 */ /* 0 */ 0x01 /* (to 0x00F0 state 205) */,\n+ /* 1 */ 0x11 /* (to 0x0110 state 242) */,\n+/* pos 00f0: 205 */ /* 0 */ 0x01 /* (to 0x00F2 state 206) */,\n+ /* 1 */ 0x02 /* (to 0x00F4 state 209) */,\n+/* pos 00f2: 206 */ /* terminal 85 */ 0x55,\n+ /* terminal 86 */ 0x56,\n+/* pos 00f4: 209 */ /* terminal 87 */ 0x57,\n+ /* terminal 89 */ 0x59,\n+/* pos 00f6: 211 */ /* terminal 88 */ 0x58,\n+ /* terminal 90 */ 0x5A,\n+/* pos 00f8: 216 */ /* 0 */ 0x01 /* (to 0x00FA state 217) */,\n+ /* 1 */ 0x1F /* (to 0x0136 state 286) */,\n+/* pos 00fa: 217 */ /* 0 */ 0x01 /* (to 0x00FC state 218) */,\n+ /* 1 */ 0x17 /* (to 0x0128 state 276) */,\n+/* pos 00fc: 218 */ /* terminal 92 */ 0x5C,\n+ /* terminal 195 */ 0xC3,\n+/* pos 00fe: 220 */ /* terminal 93 */ 0x5D,\n+ /* terminal 126 */ 0x7E,\n+/* pos 0100: 222 */ /* terminal 94 */ 0x5E,\n+ /* terminal 125 */ 0x7D,\n+/* pos 0102: 224 */ /* terminal 95 */ 0x5F,\n+ /* terminal 98 */ 0x62,\n+/* pos 0104: 229 */ /* 0 */ 0x01 /* (to 0x0106 state 230) */,\n+ /* 1 */ 0x05 /* (to 0x010E state 240) */,\n+/* pos 0106: 230 */ /* terminal 99 */ 0x63,\n+ /* terminal 101 */ 0x65,\n+/* pos 0108: 232 */ /* 0 */ 0x01 /* (to 0x010A state 233) */,\n+ /* 1 */ 0x02 /* (to 0x010C state 237) */,\n+/* pos 010a: 233 */ /* terminal 100 */ 0x64,\n+ /* terminal 102 */ 0x66,\n+/* pos 010c: 237 */ /* terminal 103 */ 0x67,\n+ /* terminal 104 */ 0x68,\n+/* pos 010e: 240 */ /* terminal 105 */ 0x69,\n+ /* terminal 111 */ 0x6F,\n+/* pos 0110: 242 */ /* 0 */ 0x01 /* (to 0x0112 state 243) */,\n+ /* 1 */ 0x05 /* (to 0x011A state 254) */,\n+/* pos 0112: 243 */ /* terminal 106 */ 0x6A,\n+ /* terminal 107 */ 0x6B,\n+/* pos 0114: 246 */ /* 0 */ 0x01 /* (to 0x0116 state 247) */,\n+ /* 1 */ 0x02 /* (to 0x0118 state 250) */,\n+/* pos 0116: 247 */ /* terminal 108 */ 0x6C,\n+ /* terminal 109 */ 0x6D,\n+/* pos 0118: 250 */ /* terminal 110 */ 0x6E,\n+ /* terminal 112 */ 0x70,\n+/* pos 011a: 254 */ /* terminal 113 */ 0x71,\n+ /* terminal 118 */ 0x76,\n+/* pos 011c: 256 */ /* terminal 114 */ 0x72,\n+ /* terminal 117 */ 0x75,\n+/* pos 011e: 258 */ /* terminal 115 */ 0x73,\n+ /* terminal 116 */ 0x74,\n+/* pos 0120: 263 */ /* 0 */ 0x01 /* (to 0x0122 state 264) */,\n+ /* 1 */ 0x02 /* (to 0x0124 state 267) */,\n+/* pos 0122: 264 */ /* terminal 119 */ 0x77,\n+ /* terminal 120 */ 0x78,\n+/* pos 0124: 267 */ /* terminal 121 */ 0x79,\n+ /* terminal 122 */ 0x7A,\n+/* pos 0126: 274 */ /* terminal 127 */ 0x7F,\n+ /* terminal 220 */ 0xDC,\n+/* pos 0128: 276 */ /* terminal 208 */ 0xD0,\n+ /* 1 */ 0x01 /* (to 0x012A state 277) */,\n+/* pos 012a: 277 */ /* terminal 128 */ 0x80,\n+ /* terminal 130 */ 0x82,\n+/* pos 012c: 279 */ /* 0 */ 0x2E /* (to 0x0188 state 372) */,\n+ /* 1 */ 0x01 /* (to 0x012E state 280) */,\n+/* pos 012e: 280 */ /* 0 */ 0x01 /* (to 0x0130 state 281) */,\n+ /* 1 */ 0x1B /* (to 0x0164 state 332) */,\n+/* pos 0130: 281 */ /* 0 */ 0x01 /* (to 0x0132 state 282) */,\n+ /* 1 */ 0x06 /* (to 0x013C state 291) */,\n+/* pos 0132: 282 */ /* terminal 230 */ 0xE6,\n+ /* 1 */ 0x01 /* (to 0x0134 state 283) */,\n+/* pos 0134: 283 */ /* terminal 129 */ 0x81,\n+ /* terminal 132 */ 0x84,\n+/* pos 0136: 286 */ /* 0 */ 0x01 /* (to 0x0138 state 287) */,\n+ /* 1 */ 0x14 /* (to 0x015E state 328) */,\n+/* pos 0138: 287 */ /* 0 */ 0x01 /* (to 0x013A state 288) */,\n+ /* 1 */ 0x30 /* (to 0x0198 state 388) */,\n+/* pos 013a: 288 */ /* terminal 131 */ 0x83,\n+ /* terminal 162 */ 0xA2,\n+/* pos 013c: 291 */ /* 0 */ 0x01 /* (to 0x013E state 292) */,\n+ /* 1 */ 0x02 /* (to 0x0140 state 296) */,\n+/* pos 013e: 292 */ /* terminal 133 */ 0x85,\n+ /* terminal 134 */ 0x86,\n+/* pos 0140: 296 */ /* terminal 136 */ 0x88,\n+ /* terminal 146 */ 0x92,\n+/* pos 0142: 298 */ /* terminal 137 */ 0x89,\n+ /* terminal 138 */ 0x8A,\n+/* pos 0144: 301 */ /* 0 */ 0x01 /* (to 0x0146 state 302) */,\n+ /* 1 */ 0x02 /* (to 0x0148 state 305) */,\n+/* pos 0146: 302 */ /* terminal 139 */ 0x8B,\n+ /* terminal 140 */ 0x8C,\n+/* pos 0148: 305 */ /* terminal 141 */ 0x8D,\n+ /* terminal 143 */ 0x8F,\n+/* pos 014a: 309 */ /* 0 */ 0x01 /* (to 0x014C state 310) */,\n+ /* 1 */ 0x06 /* (to 0x0156 state 319) */,\n+/* pos 014c: 310 */ /* terminal 144 */ 0x90,\n+ /* terminal 145 */ 0x91,\n+/* pos 014e: 314 */ /* 0 */ 0x01 /* (to 0x0150 state 315) */,\n+ /* 1 */ 0x12 /* (to 0x0172 state 350) */,\n+/* pos 0150: 315 */ /* 0 */ 0x01 /* (to 0x0152 state 316) */,\n+ /* 1 */ 0x05 /* (to 0x015A state 325) */,\n+/* pos 0152: 316 */ /* 0 */ 0x01 /* (to 0x0154 state 317) */,\n+ /* 1 */ 0x03 /* (to 0x0158 state 322) */,\n+/* pos 0154: 317 */ /* terminal 147 */ 0x93,\n+ /* terminal 149 */ 0x95,\n+/* pos 0156: 319 */ /* terminal 148 */ 0x94,\n+ /* terminal 159 */ 0x9F,\n+/* pos 0158: 322 */ /* terminal 150 */ 0x96,\n+ /* terminal 151 */ 0x97,\n+/* pos 015a: 325 */ /* 0 */ 0x01 /* (to 0x015C state 326) */,\n+ /* 1 */ 0x08 /* (to 0x016A state 338) */,\n+/* pos 015c: 326 */ /* terminal 152 */ 0x98,\n+ /* terminal 155 */ 0x9B,\n+/* pos 015e: 328 */ /* 0 */ 0x42 /* (to 0x01E2 state 465) */,\n+ /* 1 */ 0x01 /* (to 0x0160 state 329) */,\n+/* pos 0160: 329 */ /* 0 */ 0x01 /* (to 0x0162 state 330) */,\n+ /* 1 */ 0x0C /* (to 0x0178 state 355) */,\n+/* pos 0162: 330 */ /* terminal 153 */ 0x99,\n+ /* terminal 161 */ 0xA1,\n+/* pos 0164: 332 */ /* 0 */ 0x01 /* (to 0x0166 state 333) */,\n+ /* 1 */ 0x05 /* (to 0x016E state 347) */,\n+/* pos 0166: 333 */ /* 0 */ 0x01 /* (to 0x0168 state 334) */,\n+ /* 1 */ 0x03 /* (to 0x016C state 342) */,\n+/* pos 0168: 334 */ /* terminal 154 */ 0x9A,\n+ /* terminal 156 */ 0x9C,\n+/* pos 016a: 338 */ /* terminal 157 */ 0x9D,\n+ /* terminal 158 */ 0x9E,\n+/* pos 016c: 342 */ /* terminal 160 */ 0xA0,\n+ /* terminal 163 */ 0xA3,\n+/* pos 016e: 347 */ /* 0 */ 0x01 /* (to 0x0170 state 348) */,\n+ /* 1 */ 0x07 /* (to 0x017C state 360) */,\n+/* pos 0170: 348 */ /* terminal 164 */ 0xA4,\n+ /* terminal 169 */ 0xA9,\n+/* pos 0172: 350 */ /* 0 */ 0x01 /* (to 0x0174 state 351) */,\n+ /* 1 */ 0x09 /* (to 0x0184 state 369) */,\n+/* pos 0174: 351 */ /* 0 */ 0x01 /* (to 0x0176 state 352) */,\n+ /* 1 */ 0x03 /* (to 0x017A state 357) */,\n+/* pos 0176: 352 */ /* terminal 165 */ 0xA5,\n+ /* terminal 166 */ 0xA6,\n+/* pos 0178: 355 */ /* terminal 167 */ 0xA7,\n+ /* terminal 172 */ 0xAC,\n+/* pos 017a: 357 */ /* terminal 168 */ 0xA8,\n+ /* terminal 174 */ 0xAE,\n+/* pos 017c: 360 */ /* terminal 170 */ 0xAA,\n+ /* terminal 173 */ 0xAD,\n+/* pos 017e: 362 */ /* 0 */ 0x01 /* (to 0x0180 state 363) */,\n+ /* 1 */ 0x1B /* (to 0x01B4 state 417) */,\n+/* pos 0180: 363 */ /* 0 */ 0x01 /* (to 0x0182 state 364) */,\n+ /* 1 */ 0x2A /* (to 0x01D4 state 449) */,\n+/* pos 0182: 364 */ /* terminal 171 */ 0xAB,\n+ /* terminal 206 */ 0xCE,\n+/* pos 0184: 369 */ /* 0 */ 0x01 /* (to 0x0186 state 370) */,\n+ /* 1 */ 0x09 /* (to 0x0196 state 385) */,\n+/* pos 0186: 370 */ /* terminal 175 */ 0xAF,\n+ /* terminal 180 */ 0xB4,\n+/* pos 0188: 372 */ /* 0 */ 0x01 /* (to 0x018A state 373) */,\n+ /* 1 */ 0x27 /* (to 0x01D6 state 451) */,\n+/* pos 018a: 373 */ /* 0 */ 0x01 /* (to 0x018C state 374) */,\n+ /* 1 */ 0x05 /* (to 0x0194 state 381) */,\n+/* pos 018c: 374 */ /* terminal 176 */ 0xB0,\n+ /* terminal 177 */ 0xB1,\n+/* pos 018e: 377 */ /* 0 */ 0x01 /* (to 0x0190 state 378) */,\n+ /* 1 */ 0x07 /* (to 0x019C state 393) */,\n+/* pos 0190: 378 */ /* 0 */ 0x01 /* (to 0x0192 state 379) */,\n+ /* 1 */ 0x05 /* (to 0x019A state 390) */,\n+/* pos 0192: 379 */ /* terminal 178 */ 0xB2,\n+ /* terminal 181 */ 0xB5,\n+/* pos 0194: 381 */ /* terminal 179 */ 0xB3,\n+ /* terminal 209 */ 0xD1,\n+/* pos 0196: 385 */ /* terminal 182 */ 0xB6,\n+ /* terminal 183 */ 0xB7,\n+/* pos 0198: 388 */ /* terminal 184 */ 0xB8,\n+ /* terminal 194 */ 0xC2,\n+/* pos 019a: 390 */ /* terminal 185 */ 0xB9,\n+ /* terminal 186 */ 0xBA,\n+/* pos 019c: 393 */ /* 0 */ 0x01 /* (to 0x019E state 394) */,\n+ /* 1 */ 0x04 /* (to 0x01A4 state 400) */,\n+/* pos 019e: 394 */ /* terminal 187 */ 0xBB,\n+ /* terminal 189 */ 0xBD,\n+/* pos 01a0: 396 */ /* 0 */ 0x01 /* (to 0x01A2 state 397) */,\n+ /* 1 */ 0x07 /* (to 0x01AE state 412) */,\n+/* pos 01a2: 397 */ /* terminal 188 */ 0xBC,\n+ /* terminal 191 */ 0xBF,\n+/* pos 01a4: 400 */ /* terminal 190 */ 0xBE,\n+ /* terminal 196 */ 0xC4,\n+/* pos 01a6: 403 */ /* 0 */ 0x01 /* (to 0x01A8 state 404) */,\n+ /* 1 */ 0x0D /* (to 0x01C0 state 427) */,\n+/* pos 01a8: 404 */ /* 0 */ 0x01 /* (to 0x01AA state 405) */,\n+ /* 1 */ 0x0A /* (to 0x01BC state 424) */,\n+/* pos 01aa: 405 */ /* 0 */ 0x01 /* (to 0x01AC state 406) */,\n+ /* 1 */ 0x08 /* (to 0x01BA state 421) */,\n+/* pos 01ac: 406 */ /* terminal 192 */ 0xC0,\n+ /* terminal 193 */ 0xC1,\n+/* pos 01ae: 412 */ /* terminal 197 */ 0xC5,\n+ /* terminal 231 */ 0xE7,\n+/* pos 01b0: 414 */ /* 0 */ 0x01 /* (to 0x01B2 state 415) */,\n+ /* 1 */ 0x1B /* (to 0x01E6 state 475) */,\n+/* pos 01b2: 415 */ /* terminal 198 */ 0xC6,\n+ /* terminal 228 */ 0xE4,\n+/* pos 01b4: 417 */ /* 0 */ 0x1B /* (to 0x01EA state 481) */,\n+ /* 1 */ 0x01 /* (to 0x01B6 state 418) */,\n+/* pos 01b6: 418 */ /* 0 */ 0x01 /* (to 0x01B8 state 419) */,\n+ /* 1 */ 0x19 /* (to 0x01E8 state 478) */,\n+/* pos 01b8: 419 */ /* terminal 199 */ 0xC7,\n+ /* terminal 207 */ 0xCF,\n+/* pos 01ba: 421 */ /* terminal 200 */ 0xC8,\n+ /* terminal 201 */ 0xC9,\n+/* pos 01bc: 424 */ /* 0 */ 0x01 /* (to 0x01BE state 425) */,\n+ /* 1 */ 0x06 /* (to 0x01C8 state 438) */,\n+/* pos 01be: 425 */ /* terminal 202 */ 0xCA,\n+ /* terminal 205 */ 0xCD,\n+/* pos 01c0: 427 */ /* 0 */ 0x0D /* (to 0x01DA state 455) */,\n+ /* 1 */ 0x01 /* (to 0x01C2 state 428) */,\n+/* pos 01c2: 428 */ /* 0 */ 0x17 /* (to 0x01F0 state 490) */,\n+ /* 1 */ 0x01 /* (to 0x01C4 state 429) */,\n+/* pos 01c4: 429 */ /* terminal 255 */ 0xFF,\n+ /* 1 */ 0x01 /* (to 0x01C6 state 430) */,\n+/* pos 01c6: 430 */ /* terminal 203 */ 0xCB,\n+ /* terminal 204 */ 0xCC,\n+/* pos 01c8: 438 */ /* terminal 210 */ 0xD2,\n+ /* terminal 213 */ 0xD5,\n+/* pos 01ca: 440 */ /* 0 */ 0x01 /* (to 0x01CC state 441) */,\n+ /* 1 */ 0x14 /* (to 0x01F2 state 494) */,\n+/* pos 01cc: 441 */ /* 0 */ 0x01 /* (to 0x01CE state 442) */,\n+ /* 1 */ 0x09 /* (to 0x01DE state 461) */,\n+/* pos 01ce: 442 */ /* 0 */ 0x01 /* (to 0x01D0 state 443) */,\n+ /* 1 */ 0x02 /* (to 0x01D2 state 447) */,\n+/* pos 01d0: 443 */ /* terminal 211 */ 0xD3,\n+ /* terminal 212 */ 0xD4,\n+/* pos 01d2: 447 */ /* terminal 214 */ 0xD6,\n+ /* terminal 221 */ 0xDD,\n+/* pos 01d4: 449 */ /* terminal 215 */ 0xD7,\n+ /* terminal 225 */ 0xE1,\n+/* pos 01d6: 451 */ /* 0 */ 0x01 /* (to 0x01D8 state 452) */,\n+ /* 1 */ 0x07 /* (to 0x01E4 state 469) */,\n+/* pos 01d8: 452 */ /* terminal 216 */ 0xD8,\n+ /* terminal 217 */ 0xD9,\n+/* pos 01da: 455 */ /* 0 */ 0x01 /* (to 0x01DC state 456) */,\n+ /* 1 */ 0x09 /* (to 0x01EC state 484) */,\n+/* pos 01dc: 456 */ /* terminal 218 */ 0xDA,\n+ /* terminal 219 */ 0xDB,\n+/* pos 01de: 461 */ /* 0 */ 0x01 /* (to 0x01E0 state 462) */,\n+ /* 1 */ 0x08 /* (to 0x01EE state 488) */,\n+/* pos 01e0: 462 */ /* terminal 222 */ 0xDE,\n+ /* terminal 223 */ 0xDF,\n+/* pos 01e2: 465 */ /* terminal 224 */ 0xE0,\n+ /* terminal 226 */ 0xE2,\n+/* pos 01e4: 469 */ /* terminal 227 */ 0xE3,\n+ /* terminal 229 */ 0xE5,\n+/* pos 01e6: 475 */ /* terminal 232 */ 0xE8,\n+ /* terminal 233 */ 0xE9,\n+/* pos 01e8: 478 */ /* terminal 234 */ 0xEA,\n+ /* terminal 235 */ 0xEB,\n+/* pos 01ea: 481 */ /* terminal 236 */ 0xEC,\n+ /* terminal 237 */ 0xED,\n+/* pos 01ec: 484 */ /* terminal 238 */ 0xEE,\n+ /* terminal 240 */ 0xF0,\n+/* pos 01ee: 488 */ /* terminal 241 */ 0xF1,\n+ /* terminal 244 */ 0xF4,\n+/* pos 01f0: 490 */ /* terminal 242 */ 0xF2,\n+ /* terminal 243 */ 0xF3,\n+/* pos 01f2: 494 */ /* 0 */ 0x01 /* (to 0x01F4 state 495) */,\n+ /* 1 */ 0x04 /* (to 0x01FA state 503) */,\n+/* pos 01f4: 495 */ /* 0 */ 0x01 /* (to 0x01F6 state 496) */,\n+ /* 1 */ 0x02 /* (to 0x01F8 state 499) */,\n+/* pos 01f6: 496 */ /* terminal 245 */ 0xF5,\n+ /* terminal 246 */ 0xF6,\n+/* pos 01f8: 499 */ /* terminal 247 */ 0xF7,\n+ /* terminal 248 */ 0xF8,\n+/* pos 01fa: 503 */ /* 0 */ 0x01 /* (to 0x01FC state 504) */,\n+ /* 1 */ 0x02 /* (to 0x01FE state 507) */,\n+/* pos 01fc: 504 */ /* terminal 250 */ 0xFA,\n+ /* terminal 251 */ 0xFB,\n+/* pos 01fe: 507 */ /* terminal 252 */ 0xFC,\n+ /* terminal 253 */ 0xFD,\n+/* total size 512 bytes, biggest jump 200/256, fails\u003d0 */\n+};\n+\n+ static unsigned char lextable_terms[] \u003d {\n+\n+\t0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00, \n+\t0x34, 0x0f, 0x43, 0x03, 0xf1, 0x3c, 0xfc, 0x3c, \n+\t0x0f, 0x30, 0x37, 0xf7, 0x0f, 0xc3, 0xcf, 0x03, \n+\t0x3c, 0xfc, 0xc0, 0xf3, 0xf0, 0x3c, 0xfc, 0xf0, \n+\t0xcf, 0xfc, 0xcc, 0xff, 0xfc, 0x0d, 0x34, 0xcc, \n+\t0xcf, 0x33, 0xf0, 0x33, 0x0c, 0x3f, 0xc3, 0x3f, \n+\t0xcc, 0x30, 0xfc, 0xcf, 0x3c, 0xf0, 0x0c, 0xcf, \n+\t0xd0, 0x03, 0x3f, 0x33, 0xff, 0xff, 0xc3, 0xf3, \n+};\n+\n+/* state that points to 0x100 for disambiguation with 0x0 */\n+#define HUFTABLE_0x100_PREV 118\ndiff --git a/lib/http2/minihuf.c b/lib/http2/minihuf.c\nnew file mode 100644\nindex 0000000..eaf84e5\n--- /dev/null\n+++ b/lib/http2/minihuf.c\n@@ -0,0 +1,518 @@\n+/*\n+ * minilex.c\n+ *\n+ * High efficiency lexical state parser\n+ *\n+ * Copyright (C)2011-2014 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * Licensed under LGPL2\n+ *\n+ * Usage: gcc minihuf.c -o minihuf \u0026\u0026 ./minihuf \u003e huftable.h\n+ *\n+ * Run it twice to test parsing on the generated table on stderr\n+ */\n+\n+#include \u003cstdio.h\u003e\n+#include \u003cstdlib.h\u003e\n+#include \u003cstring.h\u003e\n+\n+#define ARRAY_SIZE(n) (sizeof(n) / sizeof(n[0]))\n+\n+struct huf {\n+\tunsigned int code;\n+\tunsigned char len;\n+};\n+\n+static struct huf huf_literal[] \u003d {\n+\t/* 0x00 */ { 0x1ff8, 13 },\n+\t/* 0x01 */ { 0x7fffd8, 23 },\n+\t/* 0x02 */ { 0xfffffe2, 28 },\n+\t/* 0x03 */ { 0xfffffe3, 28 },\n+\t/* 0x04 */ { 0xfffffe4, 28 },\n+\t/* 0x05 */ { 0xfffffe5, 28 },\n+\t/* 0x06 */ { 0xfffffe6, 28 },\n+\t/* 0x07 */ { 0xfffffe7, 28 },\n+\t/* 0x08 */ { 0xfffffe8, 28 },\n+\t/* 0x09 */ { 0xffffea, 24 },\n+\t/* 0x0a */ { 0x3ffffffc, 30 },\n+\t/* 0x0b */ { 0xfffffe9, 28 },\n+\n+\t/* 0x0c */ { 0xfffffea, 28 },\n+\t/* 0x0d */ { 0x3ffffffd, 30 },\n+\t/* 0x0e */ { 0xfffffeb, 28 },\n+\t/* 0x0f */ { 0xfffffec, 28 },\n+\t/* 0x10 */ { 0xfffffed, 28 },\n+\t/* 0x11 */ { 0xfffffee, 28 },\n+\t/* 0x12 */ { 0xfffffef, 28 },\n+\t/* 0x13 */ { 0xffffff0, 28 },\n+\t/* 0x14 */ { 0xffffff1, 28 },\n+\t/* 0x15 */ { 0xffffff2, 28 },\n+\t/* 0x16 */ { 0x3ffffffe, 30 },\n+\t/* 0x17 */ { 0xffffff3, 28 },\n+\t/* 0x18 */ { 0xffffff4, 28 },\n+\t/* 0x19 */ { 0xffffff5, 28 },\n+\t/* 0x1a */ { 0xffffff6, 28 },\n+\t/* 0x1b */ { 0xffffff7, 28 },\n+\t/* 0x1c */ { 0xffffff8, 28 },\n+\t/* 0x1d */ { 0xffffff9, 28 },\n+\t/* 0x1e */ { 0xffffffa, 28 },\n+\t/* 0x1f */ { 0xffffffb, 28 },\n+\t/* 0x20 */ { 0x14, 6 },\n+\t/* 0x21 */ { 0x3f8, 10 },\n+\t/* 0x22 */ { 0x3f9, 10 },\n+\t/* 0x23 */ { 0xffa, 12 },\n+\t/* 0x24 */ { 0x1ff9, 13 },\n+\t/* 0x25 */ { 0x15, 6 },\n+\t/* 0x26 */ { 0xf8, 8 },\n+\t/* 0x27 */ { 0x7fa, 11 },\n+\t/* 0x28 */ { 0x3fa, 10 },\n+\t/* 0x29 */ { 0x3fb, 10 },\n+\t/* 0x2a */ { 0xf9, 8 },\n+\t/* 0x2b */ { 0x7fb, 11 },\n+\t/* 0x2c */ { 0xfa, 8 },\n+\t/* 0x2d */ { 0x16, 6 },\n+\t/* 0x2e */ { 0x17, 6 },\n+\t/* 0x2f */ { 0x18, 6 },\n+\t/* 0x30 */ { 0x0, 5 },\n+\t/* 0x31 */ { 0x1, 5 },\n+\t/* 0x32 */ { 0x2, 5 },\n+\t/* 0x33 */ { 0x19, 6 },\n+\t/* 0x34 */ { 0x1a, 6 },\n+\t/* 0x35 */ { 0x1b, 6 },\n+\t/* 0x36 */ { 0x1c, 6 },\n+\t/* 0x37 */ { 0x1d, 6 },\n+\t/* 0x38 */ { 0x1e, 6 },\n+\t/* 0x39 */ { 0x1f, 6 },\n+\t/* 0x3a */ { 0x5c, 7 },\n+\t/* 0x3b */ { 0xfb, 8 },\n+\n+\t/* 0x3c */ { 0x7ffc, 15 },\n+\t/* 0x3d */ { 0x20, 6 },\n+\t/* 0x3e */ { 0xffb, 12 },\n+\t/* 0x3f */ { 0x3fc, 10 },\n+\t/* 0x40 */ { 0x1ffa, 13 },\n+\t/* 0x41 */ { 0x21, 6 },\n+\t/* 0x42 */ { 0x5d, 7 },\n+\t/* 0x43 */ { 0x5e, 7 },\n+\t/* 0x44 */ { 0x5f, 7 },\n+\t/* 0x45 */ { 0x60, 7 },\n+\t/* 0x46 */ { 0x61, 7 },\n+\t/* 0x47 */ { 0x62, 7 },\n+\t/* 0x48 */ { 0x63, 7 },\n+\t/* 0x49 */ { 0x64, 7 },\n+\t/* 0x4a */ { 0x65, 7 },\n+\t/* 0x4b */ { 0x66, 7 },\n+\t/* 0x4c */ { 0x67, 7 },\n+\t/* 0x4d */ { 0x68, 7 },\n+\t/* 0x4e */ { 0x69, 7 },\n+\t/* 0x4f */ { 0x6a, 7 },\n+\t/* 0x50 */ { 0x6b, 7 },\n+\t/* 0x51 */ { 0x6c, 7 },\n+\t/* 0x52 */ { 0x6d, 7 },\n+\t/* 0x53 */ { 0x6e, 7 },\n+\t/* 0x54 */ { 0x6f, 7 },\n+\t/* 0x55 */ { 0x70, 7 },\n+\t/* 0x56 */ { 0x71, 7 },\n+\t/* 0x57 */ { 0x72, 7 },\n+\t/* 0x58 */ { 0xfc, 8 },\n+\t/* 0x59 */ { 0x73, 7 },\n+\t/* 0x5a */ { 0xfd, 8 },\n+\t/* 0x5b */ { 0x1ffb, 13 },\n+\t/* 0x5c */ { 0x7fff0, 19 },\n+\t/* 0x5d */ { 0x1ffc, 13 },\n+\t/* 0x5e */ { 0x3ffc, 14 },\n+\t/* 0x5f */ { 0x22, 6 },\n+\t/* 0x60 */ { 0x7ffd, 15 },\n+\t/* 0x61 */ { 0x3, 5 },\n+\t/* 0x62 */ { 0x23, 6 },\n+\t/* 0x63 */ { 0x4, 5 },\n+\t/* 0x64 */ { 0x24, 6 },\n+\t/* 0x65 */ { 0x5, 5 },\n+\t/* 0x66 */ { 0x25, 6 },\n+\t/* 0x67 */ { 0x26, 6 },\n+\t/* 0x68 */ { 0x27, 6 },\n+\t/* 0x69 */ { 0x6, 5 },\n+\t/* 0x6a */ { 0x74, 7 },\n+\t/* 0x6b */ { 0x75, 7 },\n+\n+\n+\t/* 0x6c */ { 0x28, 6 },\n+\t/* 0x6d */ { 0x29, 6 },\n+\t/* 0x6e */ { 0x2a, 6 },\n+\t/* 0x6f */ { 0x7, 5 },\n+\t/* 0x70 */ { 0x2b, 6 },\n+\t/* 0x71 */ { 0x76, 7 },\n+\t/* 0x72 */ { 0x2c, 6 },\n+\t/* 0x73 */ { 0x8, 5 },\n+\t/* 0x74 */ { 0x9, 5 },\n+\t/* 0x75 */ { 0x2d, 6 },\n+\t/* 0x76 */ { 0x77, 7 },\n+\t/* 0x77 */ { 0x78, 7 },\n+\t/* 0x78 */ { 0x79, 7 },\n+\t/* 0x79 */ { 0x7a, 7 },\n+\t/* 0x7a */ { 0x7b, 7 },\n+\t/* 0x7b */ { 0x7ffe, 15 },\n+\t/* 0x7c */ { 0x7fc, 11 },\n+\t/* 0x7d */ { 0x3ffd, 14 },\n+\t/* 0x7e */ { 0x1ffd, 13 },\n+\t/* 0x7f */ { 0xffffffc, 28 },\n+\t/* 0x80 */ { 0xfffe6, 20 },\n+\t/* 0x81 */ { 0x3fffd2, 22 },\n+\t/* 0x82 */ { 0xfffe7, 20 },\n+\t/* 0x83 */ { 0xfffe8, 20 },\n+\t/* 0x84 */ { 0x3fffd3, 22 },\n+\t/* 0x85 */ { 0x3fffd4, 22 },\n+\t/* 0x86 */ { 0x3fffd5, 22 },\n+\t/* 0x87 */ { 0x7fffd9, 23 },\n+\t/* 0x88 */ { 0x3fffd6, 22 },\n+\t/* 0x89 */ { 0x7fffda, 23 },\n+\t/* 0x8a */ { 0x7fffdb, 23 },\n+\t/* 0x8b */ { 0x7fffdc, 23 },\n+\t/* 0x8c */ { 0x7fffdd, 23 },\n+\t/* 0x8d */ { 0x7fffde, 23 },\n+\t/* 0x8e */ { 0xffffeb, 24 },\n+\t/* 0x8f */ { 0x7fffdf, 23 },\n+\t/* 0x90 */ { 0xffffec, 24 },\n+\t/* 0x91 */ { 0xffffed, 24 },\n+\t/* 0x92 */ { 0x3fffd7, 22 },\n+\t/* 0x93 */ { 0x7fffe0, 23 },\n+\t/* 0x94 */ { 0xffffee, 24 },\n+\t/* 0x95 */ { 0x7fffe1, 23 },\n+\t/* 0x96 */ { 0x7fffe2, 23 },\n+\t/* 0x97 */ { 0x7fffe3, 23 },\n+\t/* 0x98 */ { 0x7fffe4, 23 },\n+\t/* 0x99 */ { 0x1fffdc, 21 },\n+\t/* 0x9a */ { 0x3fffd8, 22 },\n+\t/* 0x9b */ { 0x7fffe5, 23 },\n+\n+\t/* 0x9c */ { 0x3fffd9, 22 },\n+\t/* 0x9d */ { 0x7fffe6, 23 },\n+\t/* 0x9e */ { 0x7fffe7, 23 },\n+\t/* 0x9f */ { 0xffffef, 24 },\n+\t/* 0xa0 */ { 0x3fffda, 22 },\n+\t/* 0xa1 */ { 0x1fffdd, 21 },\n+\t/* 0xa2 */ { 0xfffe9, 20 },\n+\t/* 0xa3 */ { 0x3fffdb, 22 },\n+\t/* 0xa4 */ { 0x3fffdc, 22 },\n+\t/* 0xa5 */ { 0x7fffe8, 23 },\n+\t/* 0xa6 */ { 0x7fffe9, 23 },\n+\t/* 0xa7 */ { 0x1fffde, 21 },\n+\t/* 0xa8 */ { 0x7fffea, 23 },\n+\t/* 0xa9 */ { 0x3fffdd, 22 },\n+\t/* 0xaa */ { 0x3fffde, 22 },\n+\t/* 0xab */ { 0xfffff0, 24 },\n+\t/* 0xac */ { 0x1fffdf, 21 },\n+\t/* 0xad */ { 0x3fffdf, 22 },\n+\t/* 0xae */ { 0x7fffeb, 23 },\n+\t/* 0xaf */ { 0x7fffec, 23 },\n+\t/* 0xb0 */ { 0x1fffe0, 21 },\n+\t/* 0xb1 */ { 0x1fffe1, 21 },\n+\t/* 0xb2 */ { 0x3fffe0, 22 },\n+\t/* 0xb3 */ { 0x1fffe2, 21 },\n+\t/* 0xb4 */ { 0x7fffed, 23 },\n+\t/* 0xb5 */ { 0x3fffe1, 22 },\n+\t/* 0xb6 */ { 0x7fffee, 23 },\n+\t/* 0xb7 */ { 0x7fffef, 23 },\n+\t/* 0xb8 */ { 0xfffea, 20 },\n+\t/* 0xb9 */ { 0x3fffe2, 22 },\n+\t/* 0xba */ { 0x3fffe3, 22 },\n+\t/* 0xbb */ { 0x3fffe4, 22 },\n+\t/* 0xbc */ { 0x7ffff0, 23 },\n+\t/* 0xbd */ { 0x3fffe5, 22 },\n+\t/* 0xbe */ { 0x3fffe6, 22 },\n+\t/* 0xbf */ { 0x7ffff1, 23 },\n+\t/* 0xc0 */ { 0x3ffffe0, 26 },\n+\t/* 0xc1 */ { 0x3ffffe1, 26 },\n+\t/* 0xc2 */ { 0xfffeb, 20 },\n+\t/* 0xc3 */ { 0x7fff1, 19 },\n+\t/* 0xc4 */ { 0x3fffe7, 22 },\n+\t/* 0xc5 */ { 0x7ffff2, 23 },\n+\t/* 0xc6 */ { 0x3fffe8, 22 },\n+\t/* 0xc7 */ { 0x1ffffec, 25 },\n+\t/* 0xc8 */ { 0x3ffffe2, 26 },\n+\t/* 0xc9 */ { 0x3ffffe3, 26 },\n+\t/* 0xca */ { 0x3ffffe4, 26 },\n+\t/* 0xcb */ { 0x7ffffde, 27 },\n+\n+\t/* 0xcc */ { 0x7ffffdf, 27 },\n+\t/* 0xcd */ { 0x3ffffe5, 26 },\n+\t/* 0xce */ { 0xfffff1, 24 },\n+\t/* 0xcf */ { 0x1ffffed, 25 },\n+\t/* 0xd0 */ { 0x7fff2, 19 },\n+\t/* 0xd1 */ { 0x1fffe3, 21 },\n+\t/* 0xd2 */ { 0x3ffffe6, 26 },\n+\t/* 0xd3 */ { 0x7ffffe0, 27 },\n+\t/* 0xd4 */ { 0x7ffffe1, 27 },\n+\t/* 0xd5 */ { 0x3ffffe7, 26 },\n+\t/* 0xd6 */ { 0x7ffffe2, 27 },\n+\t/* 0xd7 */ { 0xfffff2, 24 },\n+\t/* 0xd8 */ { 0x1fffe4, 21 },\n+\t/* 0xd9 */ { 0x1fffe5, 21 },\n+\t/* 0xda */ { 0x3ffffe8, 26 },\n+\t/* 0xdb */ { 0x3ffffe9, 26 },\n+\t/* 0xdc */ { 0xffffffd, 28 },\n+\t/* 0xdd */ { 0x7ffffe3, 27 },\n+\t/* 0xde */ { 0x7ffffe4, 27 },\n+\t/* 0xdf */ { 0x7ffffe5, 27 },\n+\t/* 0xe0 */ { 0xfffec, 20 },\n+\t/* 0xe1 */ { 0xfffff3, 24 },\n+\t/* 0xe2 */ { 0xfffed, 20 },\n+\t/* 0xe3 */ { 0x1fffe6, 21 },\n+\t/* 0xe4 */ { 0x3fffe9, 22 },\n+\t/* 0xe5 */ { 0x1fffe7, 21 },\n+\t/* 0xe6 */ { 0x1fffe8, 21 },\n+\t/* 0xe7 */ { 0x7ffff3, 23 },\n+\t/* 0xe8 */ { 0x3fffea, 22 },\n+\t/* 0xe9 */ { 0x3fffeb, 22 },\n+\t/* 0xea */ { 0x1ffffee, 25 },\n+\t/* 0xeb */ { 0x1ffffef, 25 },\n+\t/* 0xec */ { 0xfffff4, 24 },\n+\t/* 0xed */ { 0xfffff5, 24 },\n+\t/* 0xee */ { 0x3ffffea, 26 },\n+\t/* 0xef */ { 0x7ffff4, 23 },\n+\t/* 0xf0 */ { 0x3ffffeb, 26 },\n+\t/* 0xf1 */ { 0x7ffffe6, 27 },\n+\t/* 0xf2 */ { 0x3ffffec, 26 },\n+\t/* 0xf3 */ { 0x3ffffed, 26 },\n+\t/* 0xf4 */ { 0x7ffffe7, 27 },\n+\t/* 0xf5 */ { 0x7ffffe8, 27 },\n+\t/* 0xf6 */ { 0x7ffffe9, 27 },\n+\t/* 0xf7 */ { 0x7ffffea, 27 },\n+\t/* 0xf8 */ { 0x7ffffeb, 27 },\n+\t/* 0xf9 */ { 0xffffffe, 28 },\n+\t/* 0xfa */ { 0x7ffffec, 27 },\n+\t/* 0xfb */ { 0x7ffffed, 27 },\n+\n+\t/* 0xfc */ { 0x7ffffee, 27 },\n+\t/* 0xfd */ { 0x7ffffef, 27 },\n+\t/* 0xfe */ { 0x7fffff0, 27 },\n+\t/* 0xff */ { 0x3ffffee, 26 },\n+\t/* 0x100 */ { 0x3fffffff, 30 },\n+};\n+\n+int code_bit(int idx, int bit)\n+{\n+\tif (bit \u003c huf_literal[idx].len)\n+\t\treturn !!(huf_literal[idx].code \u0026 (1 \u003c\u003c (huf_literal[idx].len - 1 - bit)));\n+\n+\treturn -1;\n+}\n+\n+#include \u0022huftable.h\u0022\n+\n+#define PARALLEL 2\n+\n+struct state {\n+\tint terminal;\n+\tint state[PARALLEL];\n+\tint bytepos;\n+\n+\tint real_pos;\n+};\n+\n+struct state state[2000];\n+unsigned char terms[2000];\n+int next \u003d 1;\n+\n+int lextable_decode(int pos, char c)\n+{\n+\tint q \u003d pos + !!c;\n+\n+\tif (lextable_terms[q \u003e\u003e 3] \u0026 (1 \u003c\u003c (q \u0026 7))) /* terminal */\n+\t\treturn lextable[q] | 0x8000;\n+\n+\treturn pos + (lextable[q] \u003c\u003c 1);\n+}\n+\n+int main(void)\n+{\n+\tint n \u003d 0;\n+\tint m \u003d 0;\n+\tint prev;\n+\tchar c;\n+\tint walk;\n+\tint saw;\n+\tint y;\n+\tint j;\n+\tint q;\n+\tint pos \u003d 0;\n+\tint biggest \u003d 0;\n+\tint fails \u003d 0;\n+\n+\tm \u003d 0;\n+\twhile (m \u003c ARRAY_SIZE(state)) {\n+\t\tfor (j \u003d 0; j \u003c PARALLEL; j++) {\n+\t\t\tstate[m].state[j] \u003d 0xffff;\n+\t\t\tstate[m].terminal \u003d 0;\n+\t\t}\n+\t\tm++;\n+\t}\n+\n+\twhile (n \u003c ARRAY_SIZE(huf_literal)) {\n+\n+\t\tm \u003d 0;\n+\t\twalk \u003d 0;\n+\t\tprev \u003d 0;\n+\n+\t\twhile (m \u003c huf_literal[n].len) {\n+\n+\t\t\tsaw \u003d 0;\n+\t\t\tif (state[walk].state[code_bit(n, m)] !\u003d 0xffff) {\n+\t\t\t\t/* exists -- go forward */\n+\t\t\t\twalk \u003d state[walk].state[code_bit(n, m)];\n+\t\t\t\tgoto again;\n+\t\t\t}\n+\n+\t\t\t/* something we didn't see before */\n+\n+\t\t\tstate[walk].state[code_bit(n, m)] \u003d next;\n+\t\t\twalk \u003d next++;\n+again:\n+\t\t\tm++;\n+\t\t}\n+\n+\t\tstate[walk].terminal \u003d n++;\n+\t\tstate[walk].state[0] \u003d 0; /* terminal marker */\n+\t}\n+\n+\twalk \u003d 0;\n+\tfor (n \u003d 0; n \u003c next; n++) {\n+\t\tstate[n].bytepos \u003d walk;\n+\t\twalk +\u003d (2 * 2);\n+\t}\n+\n+\t/* compute everyone's position first */\n+\n+\tpos \u003d 0;\n+\twalk \u003d 0;\n+\tfor (n \u003d 0; n \u003c next; n++) {\n+\n+\t\tstate[n].real_pos \u003d pos;\n+\n+\t\tif (state[n].state[0]) /* nonterminal */\n+\t\t\tpos +\u003d 2;\n+\n+\t\twalk ++;\n+\t}\n+\n+\tfprintf(stdout, \u0022static unsigned char lextable[] \u003d {\u005cn\u0022);\n+\n+#define TERMINAL_MASK 0x8000\n+\n+\twalk \u003d 0;\n+\tpos \u003d 0;\n+\tq \u003d 0;\n+\tfor (n \u003d 0; n \u003c next; n++) {\n+\t\tq \u003d pos;\n+\t\tfor (m \u003d 0; m \u003c 2; m++) {\n+\t\t\tsaw \u003d state[n].state[m];\n+\n+\t\t\tif (saw \u003d\u003d 0) { // c is a terminal then\n+\t\t\t\tm \u003d 2;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!m)\n+\t\t\t\tfprintf(stdout, \u0022/* pos %04x: %3d */ \u0022,\n+\t\t\t\t\t\t\t state[n].real_pos, n);\n+\t\t\telse\n+\t\t\t\tfprintf(stdout, \u0022 \u0022);\n+\n+\t\t\tif (saw \u003d\u003d 0xffff) {\n+\t\t\t\tfprintf(stdout,\n+\t\t\t\t \u0022 0xff, 0xff, /* 0 \u003d fail */\u005cn \u0022);\n+\t\t\t\tpos ++; /* fail */\n+\t\t\t\tfails++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\tif (state[saw].state[0] \u003d\u003d 0) { /* points to terminal */\n+\t\t\t\tfprintf(stdout, \u0022 /* terminal %d */ 0x%02X,\u005cn\u0022,\n+\t\t\t\t\tstate[saw].terminal,\n+\t\t\t\t\tstate[saw].terminal \u0026 0xff);\n+\t\t\t\tterms[(state[n].real_pos + m) \u003e\u003e 3] |\u003d\n+\t\t\t\t\t1 \u003c\u003c ((state[n].real_pos + m) \u0026 7);\n+\t\t\t\tpos++;\n+\t\t\t\twalk++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\tj \u003d (state[saw].real_pos - q) \u003e\u003e 1;\n+\n+\t\t\tif (j \u003e biggest)\n+\t\t\t\tbiggest \u003d j;\n+\n+\t\t\tif (j \u003e 0xffff) {\n+\t\t\t\tfprintf(stderr,\n+\t\t\t\t \u0022Jump \u003e 64K bytes ahead (%d to %d)\u005cn\u0022,\n+\t\t\t\t\tstate[n].real_pos, state[saw].real_pos);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n+\t\t\tfprintf(stdout, \u0022 /* %d */ 0x%02X \u0022\n+\t\t\t\t\u0022/* (to 0x%04X state %3d) */,\u005cn\u0022,\n+\t\t\t\tm,\n+\t\t\t\tj \u0026 0xff,\n+\t\t\t\tstate[saw].real_pos, saw);\n+\t\t\tpos++;\n+\n+\t\t\twalk++;\n+\t\t}\n+\t}\n+\n+\tfprintf(stdout, \u0022/* total size %d bytes, biggest jump %d/256, fails\u003d%d */\u005cn};\u005cn\u0022\n+\t\t\t\u0022\u005cn static unsigned char lextable_terms[] \u003d {\u005cn\u0022,\n+\t \t\tpos, biggest, fails);\n+\n+\tfor (n \u003d 0; n \u003c (walk + 7) / 8; n++) {\n+\t\tif (!(n \u0026 7))\n+\t\t\tfprintf(stdout, \u0022\u005cn\u005ct\u0022);\n+\t\tfprintf(stdout, \u00220x%02x, \u0022, terms[n]);\n+\t}\n+\tfprintf(stdout, \u0022\u005cn};\u005cn\u0022);\n+\n+\t/*\n+\t * Try to parse every legal input string\n+\t */\n+\n+\tfor (n \u003d 0; n \u003c ARRAY_SIZE(huf_literal); n++) {\n+\t\twalk \u003d 0;\n+\t\tm \u003d 0;\n+\t\ty \u003d -1;\n+\n+\t\tfprintf(stderr, \u0022 trying %d\u005cn\u0022, n);\n+\n+\t\twhile (m \u003c huf_literal[n].len) {\n+\t\t\tprev \u003d walk;\n+\t\t\twalk \u003d lextable_decode(walk, code_bit(n, m));\n+\n+\t\t\tif (walk \u003d\u003d 0xffff) {\n+\t\t\t\tfprintf(stderr, \u0022failed\u005cn\u0022);\n+\t\t\t\treturn 3;\n+\t\t\t}\n+\n+\t\t\tif (walk \u0026 0x8000) {\n+\t\t\t\ty \u003d walk \u0026 0x7fff;\n+\t\t\t\tif (y \u003d\u003d 0 \u0026\u0026 m \u003d\u003d 29) {\n+\t\t\t\t\ty |\u003d 0x100;\n+\t\t\t\t\tfprintf(stdout,\n+\t\t\t\t\t\t\u0022\u005cn/* state that points to \u0022\n+\t\t\t\t\t\t\u00220x100 for disambiguation with \u0022\n+\t\t\t\t\t\t\u00220x0 */\u005cn\u0022\n+\t\t\t\t\t\t\u0022#define HUFTABLE_0x100_PREV \u0022\n+\t\t\t\t\t\t\u0022%d\u005cn\u0022, prev);\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tm++;\n+\t\t}\n+\n+\t\tif (y !\u003d n) {\n+\t\t\tfprintf(stderr, \u0022decode failed %d got %d (0x%x)\u005cn\u0022, n, y, y);\n+\t\t\treturn 4;\n+\t\t}\n+\t}\n+\n+\tfprintf(stderr, \u0022All decode OK\u005cn\u0022);\n+\n+\treturn 0;\n+}\ndiff --git a/lib/http2/ssl-http2.c b/lib/http2/ssl-http2.c\nnew file mode 100644\nindex 0000000..f017343\n--- /dev/null\n+++ b/lib/http2/ssl-http2.c\n@@ -0,0 +1,155 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ *\n+ * Some or all of this file is based on code from nghttp2, which has the\n+ * following license. Since it's more liberal than lws license, you're also\n+ * at liberty to get the original code from\n+ * https://github.com/tatsuhiro-t/nghttp2 under his liberal terms alone.\n+ *\n+ * nghttp2 - HTTP/2.0 C Library\n+ *\n+ * Copyright (c) 2012 Tatsuhiro Tsujikawa\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining\n+ * a copy of this software and associated documentation files (the\n+ * \u0022Software\u0022), to deal in the Software without restriction, including\n+ * without limitation the rights to use, copy, modify, merge, publish,\n+ * distribute, sublicense, and/or sell copies of the Software, and to\n+ * permit persons to whom the Software is furnished to do so, subject to\n+ * the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be\n+ * included in all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \u0022AS IS\u0022, WITHOUT WARRANTY OF ANY KIND,\n+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#if !defined(LWS_NO_SERVER)\n+#if defined(LWS_OPENSSL_SUPPORT)\n+\n+#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) \u0026\u0026 \u005c\n+\t\t\t\t OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000L)\n+\n+struct alpn_ctx {\n+\tunsigned char *data;\n+\tunsigned short len;\n+};\n+\n+\n+static int\n+alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen,\n+\tconst unsigned char *in, unsigned int inlen, void *arg)\n+{\n+#if !defined(LWS_WITH_MBEDTLS)\n+\tstruct alpn_ctx *alpn_ctx \u003d arg;\n+\n+\tif (SSL_select_next_proto((unsigned char **)out, outlen, alpn_ctx-\u003edata,\n+\t\t\t\t alpn_ctx-\u003elen, in, inlen) !\u003d\n+\t OPENSSL_NPN_NEGOTIATED)\n+\t\treturn SSL_TLSEXT_ERR_NOACK;\n+#endif\n+\treturn SSL_TLSEXT_ERR_OK;\n+}\n+#endif\n+\n+LWS_VISIBLE void\n+lws_context_init_http2_ssl(struct lws_vhost *vhost)\n+{\n+#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) \u0026\u0026 \u005c\n+\t\t\t\t OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000L)\n+\tstatic struct alpn_ctx protos \u003d { (unsigned char *)\u0022\u005cx02h2\u0022\n+\t\t\t\t\t \u0022\u005cx08http/1.1\u0022, 6 + 9 };\n+\n+\tSSL_CTX_set_alpn_select_cb(vhost-\u003essl_ctx, alpn_cb, \u0026protos);\n+\tlwsl_notice(\u0022 HTTP2 / ALPN enabled\u005cn\u0022);\n+#else\n+\tlwsl_notice(\n+\t\t\u0022 HTTP2 / ALPN configured but not supported by OpenSSL 0x%lx\u005cn\u0022,\n+\t\t OPENSSL_VERSION_NUMBER);\n+#endif // OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000L\n+}\n+\n+int lws_h2_configure_if_upgraded(struct lws *wsi)\n+{\n+#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) \u0026\u0026 \u005c\n+\t\t\t\t OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000L)\n+\tstruct allocated_headers *ah;\n+\tconst unsigned char *name \u003d NULL;\n+\tchar cstr[10];\n+\tunsigned len;\n+\n+\tSSL_get0_alpn_selected(wsi-\u003essl, \u0026name, \u0026len);\n+\tif (!len) {\n+\t\tlwsl_info(\u0022no ALPN upgrade\u005cn\u0022);\n+\t\treturn 0;\n+\t}\n+\n+\tif (len \u003e sizeof(cstr) - 1)\n+\t\tlen \u003d sizeof(cstr) - 1;\n+\n+\tmemcpy(cstr, name, len);\n+\tcstr[len] \u003d '\u005c0';\n+\n+\tlwsl_info(\u0022negotiated '%s' using ALPN\u005cn\u0022, cstr);\n+\twsi-\u003euse_ssl \u003d 1;\n+\tif (strncmp((char *)name, \u0022http/1.1\u0022, 8) \u003d\u003d 0)\n+\t\treturn 0;\n+\n+\t/* http2 */\n+\n+\twsi-\u003eupgraded_to_http2 \u003d 1;\n+\twsi-\u003evhost-\u003econn_stats.h2_alpn++;\n+\n+\t/* adopt the header info */\n+\n+\tah \u003d wsi-\u003eu.hdr.ah;\n+\n+\tlws_union_transition(wsi, LWSCM_HTTP2_SERVING);\n+\twsi-\u003estate \u003d LWSS_HTTP2_AWAIT_CLIENT_PREFACE;\n+\n+\t/* http2 union member has http union struct at start */\n+\twsi-\u003eu.http.ah \u003d ah;\n+\n+\twsi-\u003eu.h2.h2n \u003d lws_zalloc(sizeof(*wsi-\u003eu.h2.h2n), \u0022h2n\u0022);\n+\tif (!wsi-\u003eu.h2.h2n)\n+\t\treturn 1;\n+\n+\tlws_h2_init(wsi);\n+\n+\t/* HTTP2 union */\n+\n+\tlws_hpack_dynamic_size(wsi, wsi-\u003eu.h2.h2n-\u003eset.s[H2SET_HEADER_TABLE_SIZE]);\n+\twsi-\u003eu.h2.tx_cr \u003d 65535;\n+\n+\tlwsl_info(\u0022%s: wsi %p: configured for h2\u005cn\u0022, __func__, wsi);\n+\n+\treturn 0;\n+#endif\n+}\n+#endif\n+#endif\ndiff --git a/lib/huftable.h b/lib/huftable.h\ndeleted file mode 100644\nindex 385a83b..0000000\n--- a/lib/huftable.h\n+++ /dev/null\n@@ -1,530 +0,0 @@\n-static unsigned char lextable[] \u003d {\n-/* pos 0000: 0 */ /* 0 */ 0x42 /* (to 0x0084 state 98) */,\n- /* 1 */ 0x01 /* (to 0x0002 state 1) */,\n-/* pos 0002: 1 */ /* 0 */ 0x5C /* (to 0x00BA state 151) */,\n- /* 1 */ 0x01 /* (to 0x0004 state 2) */,\n-/* pos 0004: 2 */ /* 0 */ 0x66 /* (to 0x00D0 state 173) */,\n- /* 1 */ 0x01 /* (to 0x0006 state 3) */,\n-/* pos 0006: 3 */ /* 0 */ 0x74 /* (to 0x00EE state 204) */,\n- /* 1 */ 0x01 /* (to 0x0008 state 4) */,\n-/* pos 0008: 4 */ /* 0 */ 0x8C /* (to 0x0120 state 263) */,\n- /* 1 */ 0x01 /* (to 0x000A state 5) */,\n-/* pos 000a: 5 */ /* 0 */ 0x46 /* (to 0x0096 state 113) */,\n- /* 1 */ 0x01 /* (to 0x000C state 6) */,\n-/* pos 000c: 6 */ /* 0 */ 0x75 /* (to 0x00F6 state 211) */,\n- /* 1 */ 0x01 /* (to 0x000E state 7) */,\n-/* pos 000e: 7 */ /* 0 */ 0x40 /* (to 0x008E state 104) */,\n- /* 1 */ 0x01 /* (to 0x0010 state 8) */,\n-/* pos 0010: 8 */ /* 0 */ 0x45 /* (to 0x009A state 116) */,\n- /* 1 */ 0x01 /* (to 0x0012 state 9) */,\n-/* pos 0012: 9 */ /* 0 */ 0x40 /* (to 0x0092 state 108) */,\n- /* 1 */ 0x01 /* (to 0x0014 state 10) */,\n-/* pos 0014: 10 */ /* 0 */ 0x01 /* (to 0x0016 state 11) */,\n- /* 1 */ 0x03 /* (to 0x001A state 14) */,\n-/* pos 0016: 11 */ /* 0 */ 0x01 /* (to 0x0018 state 12) */,\n- /* 1 */ 0x5B /* (to 0x00CC state 166) */,\n-/* pos 0018: 12 */ /* terminal 0 */ 0x00,\n- /* terminal 36 */ 0x24,\n-/* pos 001a: 14 */ /* 0 */ 0x72 /* (to 0x00FE state 220) */,\n- /* 1 */ 0x01 /* (to 0x001C state 15) */,\n-/* pos 001c: 15 */ /* 0 */ 0x72 /* (to 0x0100 state 222) */,\n- /* 1 */ 0x01 /* (to 0x001E state 16) */,\n-/* pos 001e: 16 */ /* 0 */ 0x53 /* (to 0x00C4 state 158) */,\n- /* 1 */ 0x01 /* (to 0x0020 state 17) */,\n-/* pos 0020: 17 */ /* terminal 123 */ 0x7B,\n- /* 1 */ 0x01 /* (to 0x0022 state 18) */,\n-/* pos 0022: 18 */ /* 0 */ 0x6B /* (to 0x00F8 state 216) */,\n- /* 1 */ 0x01 /* (to 0x0024 state 19) */,\n-/* pos 0024: 19 */ /* 0 */ 0x84 /* (to 0x012C state 279) */,\n- /* 1 */ 0x01 /* (to 0x0026 state 20) */,\n-/* pos 0026: 20 */ /* 0 */ 0x01 /* (to 0x0028 state 21) */,\n- /* 1 */ 0x06 /* (to 0x0032 state 27) */,\n-/* pos 0028: 21 */ /* 0 */ 0xB3 /* (to 0x018E state 377) */,\n- /* 1 */ 0x01 /* (to 0x002A state 22) */,\n-/* pos 002a: 22 */ /* 0 */ 0xC3 /* (to 0x01B0 state 414) */,\n- /* 1 */ 0x01 /* (to 0x002C state 23) */,\n-/* pos 002c: 23 */ /* 0 */ 0x01 /* (to 0x002E state 24) */,\n- /* 1 */ 0x8C /* (to 0x0144 state 301) */,\n-/* pos 002e: 24 */ /* 0 */ 0x01 /* (to 0x0030 state 25) */,\n- /* 1 */ 0x8A /* (to 0x0142 state 298) */,\n-/* pos 0030: 25 */ /* terminal 1 */ 0x01,\n- /* terminal 135 */ 0x87,\n-/* pos 0032: 27 */ /* 0 */ 0x8E /* (to 0x014E state 314) */,\n- /* 1 */ 0x01 /* (to 0x0034 state 28) */,\n-/* pos 0034: 28 */ /* 0 */ 0x0F /* (to 0x0052 state 50) */,\n- /* 1 */ 0x01 /* (to 0x0036 state 29) */,\n-/* pos 0036: 29 */ /* 0 */ 0xA4 /* (to 0x017E state 362) */,\n- /* 1 */ 0x01 /* (to 0x0038 state 30) */,\n-/* pos 0038: 30 */ /* 0 */ 0xB7 /* (to 0x01A6 state 403) */,\n- /* 1 */ 0x01 /* (to 0x003A state 31) */,\n-/* pos 003a: 31 */ /* 0 */ 0xC8 /* (to 0x01CA state 440) */,\n- /* 1 */ 0x01 /* (to 0x003C state 32) */,\n-/* pos 003c: 32 */ /* 0 */ 0x01 /* (to 0x003E state 33) */,\n- /* 1 */ 0x0F /* (to 0x005A state 55) */,\n-/* pos 003e: 33 */ /* 0 */ 0x01 /* (to 0x0040 state 34) */,\n- /* 1 */ 0x07 /* (to 0x004C state 46) */,\n-/* pos 0040: 34 */ /* 0 */ 0x01 /* (to 0x0042 state 35) */,\n- /* 1 */ 0x03 /* (to 0x0046 state 39) */,\n-/* pos 0042: 35 */ /* terminal 254 */ 0xFE,\n- /* 1 */ 0x01 /* (to 0x0044 state 36) */,\n-/* pos 0044: 36 */ /* terminal 2 */ 0x02,\n- /* terminal 3 */ 0x03,\n-/* pos 0046: 39 */ /* 0 */ 0x01 /* (to 0x0048 state 40) */,\n- /* 1 */ 0x02 /* (to 0x004A state 43) */,\n-/* pos 0048: 40 */ /* terminal 4 */ 0x04,\n- /* terminal 5 */ 0x05,\n-/* pos 004a: 43 */ /* terminal 6 */ 0x06,\n- /* terminal 7 */ 0x07,\n-/* pos 004c: 46 */ /* 0 */ 0x01 /* (to 0x004E state 47) */,\n- /* 1 */ 0x0E /* (to 0x0068 state 67) */,\n-/* pos 004e: 47 */ /* 0 */ 0x01 /* (to 0x0050 state 48) */,\n- /* 1 */ 0x0C /* (to 0x0066 state 63) */,\n-/* pos 0050: 48 */ /* terminal 8 */ 0x08,\n- /* terminal 11 */ 0x0B,\n-/* pos 0052: 50 */ /* 0 */ 0xA7 /* (to 0x01A0 state 396) */,\n- /* 1 */ 0x01 /* (to 0x0054 state 51) */,\n-/* pos 0054: 51 */ /* 0 */ 0x01 /* (to 0x0056 state 52) */,\n- /* 1 */ 0x7B /* (to 0x014A state 309) */,\n-/* pos 0056: 52 */ /* terminal 239 */ 0xEF,\n- /* 1 */ 0x01 /* (to 0x0058 state 53) */,\n-/* pos 0058: 53 */ /* terminal 9 */ 0x09,\n- /* terminal 142 */ 0x8E,\n-/* pos 005a: 55 */ /* 0 */ 0x0A /* (to 0x006E state 74) */,\n- /* 1 */ 0x01 /* (to 0x005C state 56) */,\n-/* pos 005c: 56 */ /* 0 */ 0x11 /* (to 0x007E state 91) */,\n- /* 1 */ 0x01 /* (to 0x005E state 57) */,\n-/* pos 005e: 57 */ /* 0 */ 0x64 /* (to 0x0126 state 274) */,\n- /* 1 */ 0x01 /* (to 0x0060 state 58) */,\n-/* pos 0060: 58 */ /* terminal 249 */ 0xF9,\n- /* 1 */ 0x01 /* (to 0x0062 state 59) */,\n-/* pos 0062: 59 */ /* 0 */ 0x01 /* (to 0x0064 state 60) */,\n- /* 1 */ 0x0A /* (to 0x0076 state 81) */,\n-/* pos 0064: 60 */ /* terminal 10 */ 0x0A,\n- /* terminal 13 */ 0x0D,\n-/* pos 0066: 63 */ /* terminal 12 */ 0x0C,\n- /* terminal 14 */ 0x0E,\n-/* pos 0068: 67 */ /* 0 */ 0x01 /* (to 0x006A state 68) */,\n- /* 1 */ 0x02 /* (to 0x006C state 71) */,\n-/* pos 006a: 68 */ /* terminal 15 */ 0x0F,\n- /* terminal 16 */ 0x10,\n-/* pos 006c: 71 */ /* terminal 17 */ 0x11,\n- /* terminal 18 */ 0x12,\n-/* pos 006e: 74 */ /* 0 */ 0x01 /* (to 0x0070 state 75) */,\n- /* 1 */ 0x05 /* (to 0x0078 state 84) */,\n-/* pos 0070: 75 */ /* 0 */ 0x01 /* (to 0x0072 state 76) */,\n- /* 1 */ 0x02 /* (to 0x0074 state 79) */,\n-/* pos 0072: 76 */ /* terminal 19 */ 0x13,\n- /* terminal 20 */ 0x14,\n-/* pos 0074: 79 */ /* terminal 21 */ 0x15,\n- /* terminal 23 */ 0x17,\n-/* pos 0076: 81 */ /* terminal 22 */ 0x16,\n- /* terminal 256 */ 0x00,\n-/* pos 0078: 84 */ /* 0 */ 0x01 /* (to 0x007A state 85) */,\n- /* 1 */ 0x02 /* (to 0x007C state 88) */,\n-/* pos 007a: 85 */ /* terminal 24 */ 0x18,\n- /* terminal 25 */ 0x19,\n-/* pos 007c: 88 */ /* terminal 26 */ 0x1A,\n- /* terminal 27 */ 0x1B,\n-/* pos 007e: 91 */ /* 0 */ 0x01 /* (to 0x0080 state 92) */,\n- /* 1 */ 0x02 /* (to 0x0082 state 95) */,\n-/* pos 0080: 92 */ /* terminal 28 */ 0x1C,\n- /* terminal 29 */ 0x1D,\n-/* pos 0082: 95 */ /* terminal 30 */ 0x1E,\n- /* terminal 31 */ 0x1F,\n-/* pos 0084: 98 */ /* 0 */ 0x13 /* (to 0x00AA state 133) */,\n- /* 1 */ 0x01 /* (to 0x0086 state 99) */,\n-/* pos 0086: 99 */ /* 0 */ 0x01 /* (to 0x0088 state 100) */,\n- /* 1 */ 0x0F /* (to 0x00A4 state 129) */,\n-/* pos 0088: 100 */ /* 0 */ 0x4B /* (to 0x011E state 258) */,\n- /* 1 */ 0x01 /* (to 0x008A state 101) */,\n-/* pos 008a: 101 */ /* 0 */ 0x01 /* (to 0x008C state 102) */,\n- /* 1 */ 0x0C /* (to 0x00A2 state 126) */,\n-/* pos 008c: 102 */ /* terminal 32 */ 0x20,\n- /* terminal 37 */ 0x25,\n-/* pos 008e: 104 */ /* 0 */ 0x01 /* (to 0x0090 state 105) */,\n- /* 1 */ 0x08 /* (to 0x009E state 119) */,\n-/* pos 0090: 105 */ /* terminal 33 */ 0x21,\n- /* terminal 34 */ 0x22,\n-/* pos 0092: 108 */ /* terminal 124 */ 0x7C,\n- /* 1 */ 0x01 /* (to 0x0094 state 109) */,\n-/* pos 0094: 109 */ /* terminal 35 */ 0x23,\n- /* terminal 62 */ 0x3E,\n-/* pos 0096: 113 */ /* 0 */ 0x01 /* (to 0x0098 state 114) */,\n- /* 1 */ 0x05 /* (to 0x00A0 state 124) */,\n-/* pos 0098: 114 */ /* terminal 38 */ 0x26,\n- /* terminal 42 */ 0x2A,\n-/* pos 009a: 116 */ /* terminal 63 */ 0x3F,\n- /* 1 */ 0x01 /* (to 0x009C state 117) */,\n-/* pos 009c: 117 */ /* terminal 39 */ 0x27,\n- /* terminal 43 */ 0x2B,\n-/* pos 009e: 119 */ /* terminal 40 */ 0x28,\n- /* terminal 41 */ 0x29,\n-/* pos 00a0: 124 */ /* terminal 44 */ 0x2C,\n- /* terminal 59 */ 0x3B,\n-/* pos 00a2: 126 */ /* terminal 45 */ 0x2D,\n- /* terminal 46 */ 0x2E,\n-/* pos 00a4: 129 */ /* 0 */ 0x01 /* (to 0x00A6 state 130) */,\n- /* 1 */ 0x08 /* (to 0x00B4 state 144) */,\n-/* pos 00a6: 130 */ /* 0 */ 0x01 /* (to 0x00A8 state 131) */,\n- /* 1 */ 0x06 /* (to 0x00B2 state 141) */,\n-/* pos 00a8: 131 */ /* terminal 47 */ 0x2F,\n- /* terminal 51 */ 0x33,\n-/* pos 00aa: 133 */ /* 0 */ 0x01 /* (to 0x00AC state 134) */,\n- /* 1 */ 0x2D /* (to 0x0104 state 229) */,\n-/* pos 00ac: 134 */ /* 0 */ 0x01 /* (to 0x00AE state 135) */,\n- /* 1 */ 0x02 /* (to 0x00B0 state 138) */,\n-/* pos 00ae: 135 */ /* terminal 48 */ 0x30,\n- /* terminal 49 */ 0x31,\n-/* pos 00b0: 138 */ /* terminal 50 */ 0x32,\n- /* terminal 97 */ 0x61,\n-/* pos 00b2: 141 */ /* terminal 52 */ 0x34,\n- /* terminal 53 */ 0x35,\n-/* pos 00b4: 144 */ /* 0 */ 0x01 /* (to 0x00B6 state 145) */,\n- /* 1 */ 0x02 /* (to 0x00B8 state 148) */,\n-/* pos 00b6: 145 */ /* terminal 54 */ 0x36,\n- /* terminal 55 */ 0x37,\n-/* pos 00b8: 148 */ /* terminal 56 */ 0x38,\n- /* terminal 57 */ 0x39,\n-/* pos 00ba: 151 */ /* 0 */ 0x06 /* (to 0x00C6 state 160) */,\n- /* 1 */ 0x01 /* (to 0x00BC state 152) */,\n-/* pos 00bc: 152 */ /* 0 */ 0x2C /* (to 0x0114 state 246) */,\n- /* 1 */ 0x01 /* (to 0x00BE state 153) */,\n-/* pos 00be: 153 */ /* 0 */ 0x2F /* (to 0x011C state 256) */,\n- /* 1 */ 0x01 /* (to 0x00C0 state 154) */,\n-/* pos 00c0: 154 */ /* 0 */ 0x01 /* (to 0x00C2 state 155) */,\n- /* 1 */ 0x07 /* (to 0x00CE state 170) */,\n-/* pos 00c2: 155 */ /* terminal 58 */ 0x3A,\n- /* terminal 66 */ 0x42,\n-/* pos 00c4: 158 */ /* terminal 60 */ 0x3C,\n- /* terminal 96 */ 0x60,\n-/* pos 00c6: 160 */ /* 0 */ 0x01 /* (to 0x00C8 state 161) */,\n- /* 1 */ 0x21 /* (to 0x0108 state 232) */,\n-/* pos 00c8: 161 */ /* 0 */ 0x01 /* (to 0x00CA state 162) */,\n- /* 1 */ 0x1D /* (to 0x0102 state 224) */,\n-/* pos 00ca: 162 */ /* terminal 61 */ 0x3D,\n- /* terminal 65 */ 0x41,\n-/* pos 00cc: 166 */ /* terminal 64 */ 0x40,\n- /* terminal 91 */ 0x5B,\n-/* pos 00ce: 170 */ /* terminal 67 */ 0x43,\n- /* terminal 68 */ 0x44,\n-/* pos 00d0: 173 */ /* 0 */ 0x01 /* (to 0x00D2 state 174) */,\n- /* 1 */ 0x08 /* (to 0x00E0 state 189) */,\n-/* pos 00d2: 174 */ /* 0 */ 0x01 /* (to 0x00D4 state 175) */,\n- /* 1 */ 0x04 /* (to 0x00DA state 182) */,\n-/* pos 00d4: 175 */ /* 0 */ 0x01 /* (to 0x00D6 state 176) */,\n- /* 1 */ 0x02 /* (to 0x00D8 state 179) */,\n-/* pos 00d6: 176 */ /* terminal 69 */ 0x45,\n- /* terminal 70 */ 0x46,\n-/* pos 00d8: 179 */ /* terminal 71 */ 0x47,\n- /* terminal 72 */ 0x48,\n-/* pos 00da: 182 */ /* 0 */ 0x01 /* (to 0x00DC state 183) */,\n- /* 1 */ 0x02 /* (to 0x00DE state 186) */,\n-/* pos 00dc: 183 */ /* terminal 73 */ 0x49,\n- /* terminal 74 */ 0x4A,\n-/* pos 00de: 186 */ /* terminal 75 */ 0x4B,\n- /* terminal 76 */ 0x4C,\n-/* pos 00e0: 189 */ /* 0 */ 0x01 /* (to 0x00E2 state 190) */,\n- /* 1 */ 0x04 /* (to 0x00E8 state 197) */,\n-/* pos 00e2: 190 */ /* 0 */ 0x01 /* (to 0x00E4 state 191) */,\n- /* 1 */ 0x02 /* (to 0x00E6 state 194) */,\n-/* pos 00e4: 191 */ /* terminal 77 */ 0x4D,\n- /* terminal 78 */ 0x4E,\n-/* pos 00e6: 194 */ /* terminal 79 */ 0x4F,\n- /* terminal 80 */ 0x50,\n-/* pos 00e8: 197 */ /* 0 */ 0x01 /* (to 0x00EA state 198) */,\n- /* 1 */ 0x02 /* (to 0x00EC state 201) */,\n-/* pos 00ea: 198 */ /* terminal 81 */ 0x51,\n- /* terminal 82 */ 0x52,\n-/* pos 00ec: 201 */ /* terminal 83 */ 0x53,\n- /* terminal 84 */ 0x54,\n-/* pos 00ee: 204 */ /* 0 */ 0x01 /* (to 0x00F0 state 205) */,\n- /* 1 */ 0x11 /* (to 0x0110 state 242) */,\n-/* pos 00f0: 205 */ /* 0 */ 0x01 /* (to 0x00F2 state 206) */,\n- /* 1 */ 0x02 /* (to 0x00F4 state 209) */,\n-/* pos 00f2: 206 */ /* terminal 85 */ 0x55,\n- /* terminal 86 */ 0x56,\n-/* pos 00f4: 209 */ /* terminal 87 */ 0x57,\n- /* terminal 89 */ 0x59,\n-/* pos 00f6: 211 */ /* terminal 88 */ 0x58,\n- /* terminal 90 */ 0x5A,\n-/* pos 00f8: 216 */ /* 0 */ 0x01 /* (to 0x00FA state 217) */,\n- /* 1 */ 0x1F /* (to 0x0136 state 286) */,\n-/* pos 00fa: 217 */ /* 0 */ 0x01 /* (to 0x00FC state 218) */,\n- /* 1 */ 0x17 /* (to 0x0128 state 276) */,\n-/* pos 00fc: 218 */ /* terminal 92 */ 0x5C,\n- /* terminal 195 */ 0xC3,\n-/* pos 00fe: 220 */ /* terminal 93 */ 0x5D,\n- /* terminal 126 */ 0x7E,\n-/* pos 0100: 222 */ /* terminal 94 */ 0x5E,\n- /* terminal 125 */ 0x7D,\n-/* pos 0102: 224 */ /* terminal 95 */ 0x5F,\n- /* terminal 98 */ 0x62,\n-/* pos 0104: 229 */ /* 0 */ 0x01 /* (to 0x0106 state 230) */,\n- /* 1 */ 0x05 /* (to 0x010E state 240) */,\n-/* pos 0106: 230 */ /* terminal 99 */ 0x63,\n- /* terminal 101 */ 0x65,\n-/* pos 0108: 232 */ /* 0 */ 0x01 /* (to 0x010A state 233) */,\n- /* 1 */ 0x02 /* (to 0x010C state 237) */,\n-/* pos 010a: 233 */ /* terminal 100 */ 0x64,\n- /* terminal 102 */ 0x66,\n-/* pos 010c: 237 */ /* terminal 103 */ 0x67,\n- /* terminal 104 */ 0x68,\n-/* pos 010e: 240 */ /* terminal 105 */ 0x69,\n- /* terminal 111 */ 0x6F,\n-/* pos 0110: 242 */ /* 0 */ 0x01 /* (to 0x0112 state 243) */,\n- /* 1 */ 0x05 /* (to 0x011A state 254) */,\n-/* pos 0112: 243 */ /* terminal 106 */ 0x6A,\n- /* terminal 107 */ 0x6B,\n-/* pos 0114: 246 */ /* 0 */ 0x01 /* (to 0x0116 state 247) */,\n- /* 1 */ 0x02 /* (to 0x0118 state 250) */,\n-/* pos 0116: 247 */ /* terminal 108 */ 0x6C,\n- /* terminal 109 */ 0x6D,\n-/* pos 0118: 250 */ /* terminal 110 */ 0x6E,\n- /* terminal 112 */ 0x70,\n-/* pos 011a: 254 */ /* terminal 113 */ 0x71,\n- /* terminal 118 */ 0x76,\n-/* pos 011c: 256 */ /* terminal 114 */ 0x72,\n- /* terminal 117 */ 0x75,\n-/* pos 011e: 258 */ /* terminal 115 */ 0x73,\n- /* terminal 116 */ 0x74,\n-/* pos 0120: 263 */ /* 0 */ 0x01 /* (to 0x0122 state 264) */,\n- /* 1 */ 0x02 /* (to 0x0124 state 267) */,\n-/* pos 0122: 264 */ /* terminal 119 */ 0x77,\n- /* terminal 120 */ 0x78,\n-/* pos 0124: 267 */ /* terminal 121 */ 0x79,\n- /* terminal 122 */ 0x7A,\n-/* pos 0126: 274 */ /* terminal 127 */ 0x7F,\n- /* terminal 220 */ 0xDC,\n-/* pos 0128: 276 */ /* terminal 208 */ 0xD0,\n- /* 1 */ 0x01 /* (to 0x012A state 277) */,\n-/* pos 012a: 277 */ /* terminal 128 */ 0x80,\n- /* terminal 130 */ 0x82,\n-/* pos 012c: 279 */ /* 0 */ 0x2E /* (to 0x0188 state 372) */,\n- /* 1 */ 0x01 /* (to 0x012E state 280) */,\n-/* pos 012e: 280 */ /* 0 */ 0x01 /* (to 0x0130 state 281) */,\n- /* 1 */ 0x1B /* (to 0x0164 state 332) */,\n-/* pos 0130: 281 */ /* 0 */ 0x01 /* (to 0x0132 state 282) */,\n- /* 1 */ 0x06 /* (to 0x013C state 291) */,\n-/* pos 0132: 282 */ /* terminal 230 */ 0xE6,\n- /* 1 */ 0x01 /* (to 0x0134 state 283) */,\n-/* pos 0134: 283 */ /* terminal 129 */ 0x81,\n- /* terminal 132 */ 0x84,\n-/* pos 0136: 286 */ /* 0 */ 0x01 /* (to 0x0138 state 287) */,\n- /* 1 */ 0x14 /* (to 0x015E state 328) */,\n-/* pos 0138: 287 */ /* 0 */ 0x01 /* (to 0x013A state 288) */,\n- /* 1 */ 0x30 /* (to 0x0198 state 388) */,\n-/* pos 013a: 288 */ /* terminal 131 */ 0x83,\n- /* terminal 162 */ 0xA2,\n-/* pos 013c: 291 */ /* 0 */ 0x01 /* (to 0x013E state 292) */,\n- /* 1 */ 0x02 /* (to 0x0140 state 296) */,\n-/* pos 013e: 292 */ /* terminal 133 */ 0x85,\n- /* terminal 134 */ 0x86,\n-/* pos 0140: 296 */ /* terminal 136 */ 0x88,\n- /* terminal 146 */ 0x92,\n-/* pos 0142: 298 */ /* terminal 137 */ 0x89,\n- /* terminal 138 */ 0x8A,\n-/* pos 0144: 301 */ /* 0 */ 0x01 /* (to 0x0146 state 302) */,\n- /* 1 */ 0x02 /* (to 0x0148 state 305) */,\n-/* pos 0146: 302 */ /* terminal 139 */ 0x8B,\n- /* terminal 140 */ 0x8C,\n-/* pos 0148: 305 */ /* terminal 141 */ 0x8D,\n- /* terminal 143 */ 0x8F,\n-/* pos 014a: 309 */ /* 0 */ 0x01 /* (to 0x014C state 310) */,\n- /* 1 */ 0x06 /* (to 0x0156 state 319) */,\n-/* pos 014c: 310 */ /* terminal 144 */ 0x90,\n- /* terminal 145 */ 0x91,\n-/* pos 014e: 314 */ /* 0 */ 0x01 /* (to 0x0150 state 315) */,\n- /* 1 */ 0x12 /* (to 0x0172 state 350) */,\n-/* pos 0150: 315 */ /* 0 */ 0x01 /* (to 0x0152 state 316) */,\n- /* 1 */ 0x05 /* (to 0x015A state 325) */,\n-/* pos 0152: 316 */ /* 0 */ 0x01 /* (to 0x0154 state 317) */,\n- /* 1 */ 0x03 /* (to 0x0158 state 322) */,\n-/* pos 0154: 317 */ /* terminal 147 */ 0x93,\n- /* terminal 149 */ 0x95,\n-/* pos 0156: 319 */ /* terminal 148 */ 0x94,\n- /* terminal 159 */ 0x9F,\n-/* pos 0158: 322 */ /* terminal 150 */ 0x96,\n- /* terminal 151 */ 0x97,\n-/* pos 015a: 325 */ /* 0 */ 0x01 /* (to 0x015C state 326) */,\n- /* 1 */ 0x08 /* (to 0x016A state 338) */,\n-/* pos 015c: 326 */ /* terminal 152 */ 0x98,\n- /* terminal 155 */ 0x9B,\n-/* pos 015e: 328 */ /* 0 */ 0x42 /* (to 0x01E2 state 465) */,\n- /* 1 */ 0x01 /* (to 0x0160 state 329) */,\n-/* pos 0160: 329 */ /* 0 */ 0x01 /* (to 0x0162 state 330) */,\n- /* 1 */ 0x0C /* (to 0x0178 state 355) */,\n-/* pos 0162: 330 */ /* terminal 153 */ 0x99,\n- /* terminal 161 */ 0xA1,\n-/* pos 0164: 332 */ /* 0 */ 0x01 /* (to 0x0166 state 333) */,\n- /* 1 */ 0x05 /* (to 0x016E state 347) */,\n-/* pos 0166: 333 */ /* 0 */ 0x01 /* (to 0x0168 state 334) */,\n- /* 1 */ 0x03 /* (to 0x016C state 342) */,\n-/* pos 0168: 334 */ /* terminal 154 */ 0x9A,\n- /* terminal 156 */ 0x9C,\n-/* pos 016a: 338 */ /* terminal 157 */ 0x9D,\n- /* terminal 158 */ 0x9E,\n-/* pos 016c: 342 */ /* terminal 160 */ 0xA0,\n- /* terminal 163 */ 0xA3,\n-/* pos 016e: 347 */ /* 0 */ 0x01 /* (to 0x0170 state 348) */,\n- /* 1 */ 0x07 /* (to 0x017C state 360) */,\n-/* pos 0170: 348 */ /* terminal 164 */ 0xA4,\n- /* terminal 169 */ 0xA9,\n-/* pos 0172: 350 */ /* 0 */ 0x01 /* (to 0x0174 state 351) */,\n- /* 1 */ 0x09 /* (to 0x0184 state 369) */,\n-/* pos 0174: 351 */ /* 0 */ 0x01 /* (to 0x0176 state 352) */,\n- /* 1 */ 0x03 /* (to 0x017A state 357) */,\n-/* pos 0176: 352 */ /* terminal 165 */ 0xA5,\n- /* terminal 166 */ 0xA6,\n-/* pos 0178: 355 */ /* terminal 167 */ 0xA7,\n- /* terminal 172 */ 0xAC,\n-/* pos 017a: 357 */ /* terminal 168 */ 0xA8,\n- /* terminal 174 */ 0xAE,\n-/* pos 017c: 360 */ /* terminal 170 */ 0xAA,\n- /* terminal 173 */ 0xAD,\n-/* pos 017e: 362 */ /* 0 */ 0x01 /* (to 0x0180 state 363) */,\n- /* 1 */ 0x1B /* (to 0x01B4 state 417) */,\n-/* pos 0180: 363 */ /* 0 */ 0x01 /* (to 0x0182 state 364) */,\n- /* 1 */ 0x2A /* (to 0x01D4 state 449) */,\n-/* pos 0182: 364 */ /* terminal 171 */ 0xAB,\n- /* terminal 206 */ 0xCE,\n-/* pos 0184: 369 */ /* 0 */ 0x01 /* (to 0x0186 state 370) */,\n- /* 1 */ 0x09 /* (to 0x0196 state 385) */,\n-/* pos 0186: 370 */ /* terminal 175 */ 0xAF,\n- /* terminal 180 */ 0xB4,\n-/* pos 0188: 372 */ /* 0 */ 0x01 /* (to 0x018A state 373) */,\n- /* 1 */ 0x27 /* (to 0x01D6 state 451) */,\n-/* pos 018a: 373 */ /* 0 */ 0x01 /* (to 0x018C state 374) */,\n- /* 1 */ 0x05 /* (to 0x0194 state 381) */,\n-/* pos 018c: 374 */ /* terminal 176 */ 0xB0,\n- /* terminal 177 */ 0xB1,\n-/* pos 018e: 377 */ /* 0 */ 0x01 /* (to 0x0190 state 378) */,\n- /* 1 */ 0x07 /* (to 0x019C state 393) */,\n-/* pos 0190: 378 */ /* 0 */ 0x01 /* (to 0x0192 state 379) */,\n- /* 1 */ 0x05 /* (to 0x019A state 390) */,\n-/* pos 0192: 379 */ /* terminal 178 */ 0xB2,\n- /* terminal 181 */ 0xB5,\n-/* pos 0194: 381 */ /* terminal 179 */ 0xB3,\n- /* terminal 209 */ 0xD1,\n-/* pos 0196: 385 */ /* terminal 182 */ 0xB6,\n- /* terminal 183 */ 0xB7,\n-/* pos 0198: 388 */ /* terminal 184 */ 0xB8,\n- /* terminal 194 */ 0xC2,\n-/* pos 019a: 390 */ /* terminal 185 */ 0xB9,\n- /* terminal 186 */ 0xBA,\n-/* pos 019c: 393 */ /* 0 */ 0x01 /* (to 0x019E state 394) */,\n- /* 1 */ 0x04 /* (to 0x01A4 state 400) */,\n-/* pos 019e: 394 */ /* terminal 187 */ 0xBB,\n- /* terminal 189 */ 0xBD,\n-/* pos 01a0: 396 */ /* 0 */ 0x01 /* (to 0x01A2 state 397) */,\n- /* 1 */ 0x07 /* (to 0x01AE state 412) */,\n-/* pos 01a2: 397 */ /* terminal 188 */ 0xBC,\n- /* terminal 191 */ 0xBF,\n-/* pos 01a4: 400 */ /* terminal 190 */ 0xBE,\n- /* terminal 196 */ 0xC4,\n-/* pos 01a6: 403 */ /* 0 */ 0x01 /* (to 0x01A8 state 404) */,\n- /* 1 */ 0x0D /* (to 0x01C0 state 427) */,\n-/* pos 01a8: 404 */ /* 0 */ 0x01 /* (to 0x01AA state 405) */,\n- /* 1 */ 0x0A /* (to 0x01BC state 424) */,\n-/* pos 01aa: 405 */ /* 0 */ 0x01 /* (to 0x01AC state 406) */,\n- /* 1 */ 0x08 /* (to 0x01BA state 421) */,\n-/* pos 01ac: 406 */ /* terminal 192 */ 0xC0,\n- /* terminal 193 */ 0xC1,\n-/* pos 01ae: 412 */ /* terminal 197 */ 0xC5,\n- /* terminal 231 */ 0xE7,\n-/* pos 01b0: 414 */ /* 0 */ 0x01 /* (to 0x01B2 state 415) */,\n- /* 1 */ 0x1B /* (to 0x01E6 state 475) */,\n-/* pos 01b2: 415 */ /* terminal 198 */ 0xC6,\n- /* terminal 228 */ 0xE4,\n-/* pos 01b4: 417 */ /* 0 */ 0x1B /* (to 0x01EA state 481) */,\n- /* 1 */ 0x01 /* (to 0x01B6 state 418) */,\n-/* pos 01b6: 418 */ /* 0 */ 0x01 /* (to 0x01B8 state 419) */,\n- /* 1 */ 0x19 /* (to 0x01E8 state 478) */,\n-/* pos 01b8: 419 */ /* terminal 199 */ 0xC7,\n- /* terminal 207 */ 0xCF,\n-/* pos 01ba: 421 */ /* terminal 200 */ 0xC8,\n- /* terminal 201 */ 0xC9,\n-/* pos 01bc: 424 */ /* 0 */ 0x01 /* (to 0x01BE state 425) */,\n- /* 1 */ 0x06 /* (to 0x01C8 state 438) */,\n-/* pos 01be: 425 */ /* terminal 202 */ 0xCA,\n- /* terminal 205 */ 0xCD,\n-/* pos 01c0: 427 */ /* 0 */ 0x0D /* (to 0x01DA state 455) */,\n- /* 1 */ 0x01 /* (to 0x01C2 state 428) */,\n-/* pos 01c2: 428 */ /* 0 */ 0x17 /* (to 0x01F0 state 490) */,\n- /* 1 */ 0x01 /* (to 0x01C4 state 429) */,\n-/* pos 01c4: 429 */ /* terminal 255 */ 0xFF,\n- /* 1 */ 0x01 /* (to 0x01C6 state 430) */,\n-/* pos 01c6: 430 */ /* terminal 203 */ 0xCB,\n- /* terminal 204 */ 0xCC,\n-/* pos 01c8: 438 */ /* terminal 210 */ 0xD2,\n- /* terminal 213 */ 0xD5,\n-/* pos 01ca: 440 */ /* 0 */ 0x01 /* (to 0x01CC state 441) */,\n- /* 1 */ 0x14 /* (to 0x01F2 state 494) */,\n-/* pos 01cc: 441 */ /* 0 */ 0x01 /* (to 0x01CE state 442) */,\n- /* 1 */ 0x09 /* (to 0x01DE state 461) */,\n-/* pos 01ce: 442 */ /* 0 */ 0x01 /* (to 0x01D0 state 443) */,\n- /* 1 */ 0x02 /* (to 0x01D2 state 447) */,\n-/* pos 01d0: 443 */ /* terminal 211 */ 0xD3,\n- /* terminal 212 */ 0xD4,\n-/* pos 01d2: 447 */ /* terminal 214 */ 0xD6,\n- /* terminal 221 */ 0xDD,\n-/* pos 01d4: 449 */ /* terminal 215 */ 0xD7,\n- /* terminal 225 */ 0xE1,\n-/* pos 01d6: 451 */ /* 0 */ 0x01 /* (to 0x01D8 state 452) */,\n- /* 1 */ 0x07 /* (to 0x01E4 state 469) */,\n-/* pos 01d8: 452 */ /* terminal 216 */ 0xD8,\n- /* terminal 217 */ 0xD9,\n-/* pos 01da: 455 */ /* 0 */ 0x01 /* (to 0x01DC state 456) */,\n- /* 1 */ 0x09 /* (to 0x01EC state 484) */,\n-/* pos 01dc: 456 */ /* terminal 218 */ 0xDA,\n- /* terminal 219 */ 0xDB,\n-/* pos 01de: 461 */ /* 0 */ 0x01 /* (to 0x01E0 state 462) */,\n- /* 1 */ 0x08 /* (to 0x01EE state 488) */,\n-/* pos 01e0: 462 */ /* terminal 222 */ 0xDE,\n- /* terminal 223 */ 0xDF,\n-/* pos 01e2: 465 */ /* terminal 224 */ 0xE0,\n- /* terminal 226 */ 0xE2,\n-/* pos 01e4: 469 */ /* terminal 227 */ 0xE3,\n- /* terminal 229 */ 0xE5,\n-/* pos 01e6: 475 */ /* terminal 232 */ 0xE8,\n- /* terminal 233 */ 0xE9,\n-/* pos 01e8: 478 */ /* terminal 234 */ 0xEA,\n- /* terminal 235 */ 0xEB,\n-/* pos 01ea: 481 */ /* terminal 236 */ 0xEC,\n- /* terminal 237 */ 0xED,\n-/* pos 01ec: 484 */ /* terminal 238 */ 0xEE,\n- /* terminal 240 */ 0xF0,\n-/* pos 01ee: 488 */ /* terminal 241 */ 0xF1,\n- /* terminal 244 */ 0xF4,\n-/* pos 01f0: 490 */ /* terminal 242 */ 0xF2,\n- /* terminal 243 */ 0xF3,\n-/* pos 01f2: 494 */ /* 0 */ 0x01 /* (to 0x01F4 state 495) */,\n- /* 1 */ 0x04 /* (to 0x01FA state 503) */,\n-/* pos 01f4: 495 */ /* 0 */ 0x01 /* (to 0x01F6 state 496) */,\n- /* 1 */ 0x02 /* (to 0x01F8 state 499) */,\n-/* pos 01f6: 496 */ /* terminal 245 */ 0xF5,\n- /* terminal 246 */ 0xF6,\n-/* pos 01f8: 499 */ /* terminal 247 */ 0xF7,\n- /* terminal 248 */ 0xF8,\n-/* pos 01fa: 503 */ /* 0 */ 0x01 /* (to 0x01FC state 504) */,\n- /* 1 */ 0x02 /* (to 0x01FE state 507) */,\n-/* pos 01fc: 504 */ /* terminal 250 */ 0xFA,\n- /* terminal 251 */ 0xFB,\n-/* pos 01fe: 507 */ /* terminal 252 */ 0xFC,\n- /* terminal 253 */ 0xFD,\n-/* total size 512 bytes, biggest jump 200/256, fails\u003d0 */\n-};\n-\n- static unsigned char lextable_terms[] \u003d {\n-\n-\t0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00, \n-\t0x34, 0x0f, 0x43, 0x03, 0xf1, 0x3c, 0xfc, 0x3c, \n-\t0x0f, 0x30, 0x37, 0xf7, 0x0f, 0xc3, 0xcf, 0x03, \n-\t0x3c, 0xfc, 0xc0, 0xf3, 0xf0, 0x3c, 0xfc, 0xf0, \n-\t0xcf, 0xfc, 0xcc, 0xff, 0xfc, 0x0d, 0x34, 0xcc, \n-\t0xcf, 0x33, 0xf0, 0x33, 0x0c, 0x3f, 0xc3, 0x3f, \n-\t0xcc, 0x30, 0xfc, 0xcf, 0x3c, 0xf0, 0x0c, 0xcf, \n-\t0xd0, 0x03, 0x3f, 0x33, 0xff, 0xff, 0xc3, 0xf3, \n-};\n-\n-/* state that points to 0x100 for disambiguation with 0x0 */\n-#define HUFTABLE_0x100_PREV 118\ndiff --git a/lib/lejp-conf.c b/lib/lejp-conf.c\ndeleted file mode 100644\nindex e84f4b2..0000000\n--- a/lib/lejp-conf.c\n+++ /dev/null\n@@ -1,929 +0,0 @@\n-/*\n- * libwebsockets web server application\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-#include \u0022lejp.h\u0022\n-\n-#ifndef _WIN32\n-/* this is needed for Travis CI */\n-#include \u003cdirent.h\u003e\n-#endif\n-\n-#define ESC_INSTALL_DATADIR \u0022_lws_ddir_\u0022\n-\n-static const char * const paths_global[] \u003d {\n-\t\u0022global.uid\u0022,\n-\t\u0022global.gid\u0022,\n-\t\u0022global.count-threads\u0022,\n-\t\u0022global.init-ssl\u0022,\n-\t\u0022global.server-string\u0022,\n-\t\u0022global.plugin-dir\u0022,\n-\t\u0022global.ws-pingpong-secs\u0022,\n-\t\u0022global.timeout-secs\u0022,\n-\t\u0022global.reject-service-keywords[].*\u0022,\n-\t\u0022global.reject-service-keywords[]\u0022,\n-};\n-\n-enum lejp_global_paths {\n-\tLEJPGP_UID,\n-\tLEJPGP_GID,\n-\tLEJPGP_COUNT_THREADS,\n-\tLWJPGP_INIT_SSL,\n-\tLEJPGP_SERVER_STRING,\n-\tLEJPGP_PLUGIN_DIR,\n-\tLWJPGP_PINGPONG_SECS,\n-\tLWJPGP_TIMEOUT_SECS,\n-\tLWJPGP_REJECT_SERVICE_KEYWORDS_NAME,\n-\tLWJPGP_REJECT_SERVICE_KEYWORDS\n-};\n-\n-static const char * const paths_vhosts[] \u003d {\n-\t\u0022vhosts[]\u0022,\n-\t\u0022vhosts[].mounts[]\u0022,\n-\t\u0022vhosts[].name\u0022,\n-\t\u0022vhosts[].port\u0022,\n-\t\u0022vhosts[].interface\u0022,\n-\t\u0022vhosts[].unix-socket\u0022,\n-\t\u0022vhosts[].sts\u0022,\n-\t\u0022vhosts[].host-ssl-key\u0022,\n-\t\u0022vhosts[].host-ssl-cert\u0022,\n-\t\u0022vhosts[].host-ssl-ca\u0022,\n-\t\u0022vhosts[].access-log\u0022,\n-\t\u0022vhosts[].mounts[].mountpoint\u0022,\n-\t\u0022vhosts[].mounts[].origin\u0022,\n-\t\u0022vhosts[].mounts[].protocol\u0022,\n-\t\u0022vhosts[].mounts[].default\u0022,\n-\t\u0022vhosts[].mounts[].auth-mask\u0022,\n-\t\u0022vhosts[].mounts[].cgi-timeout\u0022,\n-\t\u0022vhosts[].mounts[].cgi-env[].*\u0022,\n-\t\u0022vhosts[].mounts[].cache-max-age\u0022,\n-\t\u0022vhosts[].mounts[].cache-reuse\u0022,\n-\t\u0022vhosts[].mounts[].cache-revalidate\u0022,\n-\t\u0022vhosts[].mounts[].basic-auth\u0022,\n-\t\u0022vhosts[].mounts[].cache-intermediaries\u0022,\n-\t\u0022vhosts[].mounts[].extra-mimetypes.*\u0022,\n-\t\u0022vhosts[].mounts[].interpret.*\u0022,\n-\t\u0022vhosts[].ws-protocols[].*.*\u0022,\n-\t\u0022vhosts[].ws-protocols[].*\u0022,\n-\t\u0022vhosts[].ws-protocols[]\u0022,\n-\t\u0022vhosts[].keepalive_timeout\u0022,\n-\t\u0022vhosts[].enable-client-ssl\u0022,\n-\t\u0022vhosts[].ciphers\u0022,\n-\t\u0022vhosts[].ecdh-curve\u0022,\n-\t\u0022vhosts[].noipv6\u0022,\n-\t\u0022vhosts[].ipv6only\u0022,\n-\t\u0022vhosts[].ssl-option-set\u0022,\n-\t\u0022vhosts[].ssl-option-clear\u0022,\n-\t\u0022vhosts[].mounts[].pmo[].*\u0022,\n-\t\u0022vhosts[].headers[].*\u0022,\n-\t\u0022vhosts[].headers[]\u0022,\n-\t\u0022vhosts[].client-ssl-key\u0022,\n-\t\u0022vhosts[].client-ssl-cert\u0022,\n-\t\u0022vhosts[].client-ssl-ca\u0022,\n-\t\u0022vhosts[].client-ssl-ciphers\u0022,\n-\t\u0022vhosts[].onlyraw\u0022,\n-};\n-\n-enum lejp_vhost_paths {\n-\tLEJPVP,\n-\tLEJPVP_MOUNTS,\n-\tLEJPVP_NAME,\n-\tLEJPVP_PORT,\n-\tLEJPVP_INTERFACE,\n-\tLEJPVP_UNIXSKT,\n-\tLEJPVP_STS,\n-\tLEJPVP_HOST_SSL_KEY,\n-\tLEJPVP_HOST_SSL_CERT,\n-\tLEJPVP_HOST_SSL_CA,\n-\tLEJPVP_ACCESS_LOG,\n-\tLEJPVP_MOUNTPOINT,\n-\tLEJPVP_ORIGIN,\n-\tLEJPVP_MOUNT_PROTOCOL,\n-\tLEJPVP_DEFAULT,\n-\tLEJPVP_DEFAULT_AUTH_MASK,\n-\tLEJPVP_CGI_TIMEOUT,\n-\tLEJPVP_CGI_ENV,\n-\tLEJPVP_MOUNT_CACHE_MAX_AGE,\n-\tLEJPVP_MOUNT_CACHE_REUSE,\n-\tLEJPVP_MOUNT_CACHE_REVALIDATE,\n-\tLEJPVP_MOUNT_BASIC_AUTH,\n-\tLEJPVP_MOUNT_CACHE_INTERMEDIARIES,\n-\tLEJPVP_MOUNT_EXTRA_MIMETYPES,\n-\tLEJPVP_MOUNT_INTERPRET,\n-\tLEJPVP_PROTOCOL_NAME_OPT,\n-\tLEJPVP_PROTOCOL_NAME,\n-\tLEJPVP_PROTOCOL,\n-\tLEJPVP_KEEPALIVE_TIMEOUT,\n-\tLEJPVP_ENABLE_CLIENT_SSL,\n-\tLEJPVP_CIPHERS,\n-\tLEJPVP_ECDH_CURVE,\n-\tLEJPVP_NOIPV6,\n-\tLEJPVP_IPV6ONLY,\n-\tLEJPVP_SSL_OPTION_SET,\n-\tLEJPVP_SSL_OPTION_CLEAR,\n-\tLEJPVP_PMO,\n-\tLEJPVP_HEADERS_NAME,\n-\tLEJPVP_HEADERS,\n-\tLEJPVP_CLIENT_SSL_KEY,\n-\tLEJPVP_CLIENT_SSL_CERT,\n-\tLEJPVP_CLIENT_SSL_CA,\n-\tLEJPVP_CLIENT_CIPHERS,\n-\tLEJPVP_FLAG_ONLYRAW,\n-};\n-\n-static const char * const parser_errs[] \u003d {\n-\t\u0022\u0022,\n-\t\u0022\u0022,\n-\t\u0022No opening '{'\u0022,\n-\t\u0022Expected closing '}'\u0022,\n-\t\u0022Expected '\u005c\u0022'\u0022,\n-\t\u0022String underrun\u0022,\n-\t\u0022Illegal unescaped control char\u0022,\n-\t\u0022Illegal escape format\u0022,\n-\t\u0022Illegal hex number\u0022,\n-\t\u0022Expected ':'\u0022,\n-\t\u0022Illegal value start\u0022,\n-\t\u0022Digit required after decimal point\u0022,\n-\t\u0022Bad number format\u0022,\n-\t\u0022Bad exponent format\u0022,\n-\t\u0022Unknown token\u0022,\n-\t\u0022Too many ']'\u0022,\n-\t\u0022Mismatched ']'\u0022,\n-\t\u0022Expected ']'\u0022,\n-\t\u0022JSON nesting limit exceeded\u0022,\n-\t\u0022Nesting tracking used up\u0022,\n-\t\u0022Number too long\u0022,\n-\t\u0022Comma or block end expected\u0022,\n-\t\u0022Unknown\u0022,\n-\t\u0022Parser callback errored (see earlier error)\u0022,\n-};\n-\n-#define MAX_PLUGIN_DIRS 10\n-\n-struct jpargs {\n-\tstruct lws_context_creation_info *info;\n-\tstruct lws_context *context;\n-\tconst struct lws_protocols *protocols;\n-\tconst struct lws_extension *extensions;\n-\tchar *p, *end, valid;\n-\tstruct lws_http_mount *head, *last;\n-\n-\tstruct lws_protocol_vhost_options *pvo;\n-\tstruct lws_protocol_vhost_options *pvo_em;\n-\tstruct lws_protocol_vhost_options *pvo_int;\n-\tstruct lws_http_mount m;\n-\tconst char **plugin_dirs;\n-\tint count_plugin_dirs;\n-\n-\tunsigned int enable_client_ssl:1;\n-\tunsigned int fresh_mount:1;\n-\tunsigned int any_vhosts:1;\n-};\n-\n-static void *\n-lwsws_align(struct jpargs *a)\n-{\n-\tif ((lws_intptr_t)(a-\u003ep) \u0026 15)\n-\t\ta-\u003ep +\u003d 16 - ((lws_intptr_t)(a-\u003ep) \u0026 15);\n-\n-\treturn a-\u003ep;\n-}\n-\n-static int\n-arg_to_bool(const char *s)\n-{\n-\tstatic const char * const on[] \u003d { \u0022on\u0022, \u0022yes\u0022, \u0022true\u0022 };\n-\tint n \u003d atoi(s);\n-\n-\tif (n)\n-\t\treturn 1;\n-\n-\tfor (n \u003d 0; n \u003c ARRAY_SIZE(on); n++)\n-\t\tif (!strcasecmp(s, on[n]))\n-\t\t\treturn 1;\n-\n-\treturn 0;\n-}\n-\n-static char\n-lejp_globals_cb(struct lejp_ctx *ctx, char reason)\n-{\n-\tstruct jpargs *a \u003d (struct jpargs *)ctx-\u003euser;\n-\tstruct lws_protocol_vhost_options *rej;\n-\tint n;\n-\n-\t/* we only match on the prepared path strings */\n-\tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n-\t\treturn 0;\n-\n-\t/* this catches, eg, vhosts[].headers[].xxx */\n-\tif (reason \u003d\u003d LEJPCB_VAL_STR_END \u0026\u0026\n-\t ctx-\u003epath_match \u003d\u003d LWJPGP_REJECT_SERVICE_KEYWORDS_NAME + 1) {\n-\t\trej \u003d lwsws_align(a);\n-\t\ta-\u003ep +\u003d sizeof(*rej);\n-\n-\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n-\t\trej-\u003enext \u003d a-\u003einfo-\u003ereject_service_keywords;\n-\t\ta-\u003einfo-\u003ereject_service_keywords \u003d rej;\n-\t\trej-\u003ename \u003d a-\u003ep;\n-\t\t lwsl_notice(\u0022 adding rej %s\u003d%s\u005cn\u0022, a-\u003ep, ctx-\u003ebuf);\n-\t\ta-\u003ep +\u003d n - 1;\n-\t\t*(a-\u003ep++) \u003d '\u005c0';\n-\t\trej-\u003evalue \u003d a-\u003ep;\n-\t\trej-\u003eoptions \u003d NULL;\n-\t\tgoto dostring;\n-\t}\n-\n-\tswitch (ctx-\u003epath_match - 1) {\n-\tcase LEJPGP_UID:\n-\t\ta-\u003einfo-\u003euid \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPGP_GID:\n-\t\ta-\u003einfo-\u003egid \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPGP_COUNT_THREADS:\n-\t\ta-\u003einfo-\u003ecount_threads \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LWJPGP_INIT_SSL:\n-\t\tif (arg_to_bool(ctx-\u003ebuf))\n-\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n-\t\treturn 0;\n-\tcase LEJPGP_SERVER_STRING:\n-\t\ta-\u003einfo-\u003eserver_string \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPGP_PLUGIN_DIR:\n-\t\tif (a-\u003ecount_plugin_dirs \u003d\u003d MAX_PLUGIN_DIRS - 1) {\n-\t\t\tlwsl_err(\u0022Too many plugin dirs\u005cn\u0022);\n-\t\t\treturn -1;\n-\t\t}\n-\t\ta-\u003eplugin_dirs[a-\u003ecount_plugin_dirs++] \u003d a-\u003ep;\n-\t\tbreak;\n-\n-\tcase LWJPGP_PINGPONG_SECS:\n-\t\ta-\u003einfo-\u003ews_ping_pong_interval \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\n-\tcase LWJPGP_TIMEOUT_SECS:\n-\t\ta-\u003einfo-\u003etimeout_secs \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\n-\tdefault:\n-\t\treturn 0;\n-\t}\n-\n-dostring:\n-\ta-\u003ep +\u003d lws_snprintf(a-\u003ep, a-\u003eend - a-\u003ep, \u0022%s\u0022, ctx-\u003ebuf);\n-\t*(a-\u003ep)++ \u003d '\u005c0';\n-\n-\treturn 0;\n-}\n-\n-static char\n-lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)\n-{\n-\tstruct jpargs *a \u003d (struct jpargs *)ctx-\u003euser;\n-\tstruct lws_protocol_vhost_options *pvo, *mp_cgienv, *headers;\n-\tstruct lws_http_mount *m;\n-\tchar *p, *p1;\n-\tint n;\n-\n-#if 0\n-\tlwsl_notice(\u0022 %d: %s (%d)\u005cn\u0022, reason, ctx-\u003epath, ctx-\u003epath_match);\n-\tfor (n \u003d 0; n \u003c ctx-\u003ewildcount; n++)\n-\t\tlwsl_notice(\u0022 %d\u005cn\u0022, ctx-\u003ewild[n]);\n-#endif\n-\n-\tif (reason \u003d\u003d LEJPCB_OBJECT_START \u0026\u0026 ctx-\u003epath_match \u003d\u003d LEJPVP + 1) {\n-\t\t/* set the defaults for this vhost */\n-\t\ta-\u003evalid \u003d 1;\n-\t\ta-\u003ehead \u003d NULL;\n-\t\ta-\u003elast \u003d NULL;\n-\t\ta-\u003einfo-\u003eport \u003d 0;\n-\t\ta-\u003einfo-\u003eiface \u003d NULL;\n-\t\ta-\u003einfo-\u003eprotocols \u003d a-\u003eprotocols;\n-\t\ta-\u003einfo-\u003eextensions \u003d a-\u003eextensions;\n-\t\ta-\u003einfo-\u003essl_cert_filepath \u003d NULL;\n-\t\ta-\u003einfo-\u003essl_private_key_filepath \u003d NULL;\n-\t\ta-\u003einfo-\u003essl_ca_filepath \u003d NULL;\n-\t\ta-\u003einfo-\u003eclient_ssl_cert_filepath \u003d NULL;\n-\t\ta-\u003einfo-\u003eclient_ssl_private_key_filepath \u003d NULL;\n-\t\ta-\u003einfo-\u003eclient_ssl_ca_filepath \u003d NULL;\n-\t\ta-\u003einfo-\u003eclient_ssl_cipher_list \u003d \u0022ECDHE-ECDSA-AES256-GCM-SHA384:\u0022\n-\t\t\t\u0022ECDHE-RSA-AES256-GCM-SHA384:\u0022\n-\t\t\t\u0022DHE-RSA-AES256-GCM-SHA384:\u0022\n-\t\t\t\u0022ECDHE-RSA-AES256-SHA384:\u0022\n-\t\t\t\u0022HIGH:!aNULL:!eNULL:!EXPORT:\u0022\n-\t\t\t\u0022!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:\u0022\n-\t\t\t\u0022!SHA1:!DHE-RSA-AES128-GCM-SHA256:\u0022\n-\t\t\t\u0022!DHE-RSA-AES128-SHA256:\u0022\n-\t\t\t\u0022!AES128-GCM-SHA256:\u0022\n-\t\t\t\u0022!AES128-SHA256:\u0022\n-\t\t\t\u0022!DHE-RSA-AES256-SHA256:\u0022\n-\t\t\t\u0022!AES256-GCM-SHA384:\u0022\n-\t\t\t\u0022!AES256-SHA256\u0022;\n-\t\ta-\u003einfo-\u003etimeout_secs \u003d 5;\n-\t\ta-\u003einfo-\u003essl_cipher_list \u003d \u0022ECDHE-ECDSA-AES256-GCM-SHA384:\u0022\n-\t\t\t\t \u0022ECDHE-RSA-AES256-GCM-SHA384:\u0022\n-\t\t\t\t \u0022DHE-RSA-AES256-GCM-SHA384:\u0022\n-\t\t\t\t \u0022ECDHE-RSA-AES256-SHA384:\u0022\n-\t\t\t\t \u0022HIGH:!aNULL:!eNULL:!EXPORT:\u0022\n-\t\t\t\t \u0022!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:\u0022\n-\t\t\t\t \u0022!SHA1:!DHE-RSA-AES128-GCM-SHA256:\u0022\n-\t\t\t\t \u0022!DHE-RSA-AES128-SHA256:\u0022\n-\t\t\t\t \u0022!AES128-GCM-SHA256:\u0022\n-\t\t\t\t \u0022!AES128-SHA256:\u0022\n-\t\t\t\t \u0022!DHE-RSA-AES256-SHA256:\u0022\n-\t\t\t\t \u0022!AES256-GCM-SHA384:\u0022\n-\t\t\t\t \u0022!AES256-SHA256\u0022;\n-\t\ta-\u003einfo-\u003epvo \u003d NULL;\n-\t\ta-\u003einfo-\u003eheaders \u003d NULL;\n-\t\ta-\u003einfo-\u003ekeepalive_timeout \u003d 5;\n-\t\ta-\u003einfo-\u003elog_filepath \u003d NULL;\n-\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_UNIX_SOCK |\n-\t\t\t\t LWS_SERVER_OPTION_STS | LWS_SERVER_OPTION_ONLY_RAW);\n-\t\ta-\u003eenable_client_ssl \u003d 0;\n-\t}\n-\n-\tif (reason \u003d\u003d LEJPCB_OBJECT_START \u0026\u0026\n-\t ctx-\u003epath_match \u003d\u003d LEJPVP_MOUNTS + 1) {\n-\t\ta-\u003efresh_mount \u003d 1;\n-\t\tmemset(\u0026a-\u003em, 0, sizeof(a-\u003em));\n-\t}\n-\n-\t/* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */\n-\tif (reason \u003d\u003d LEJPCB_OBJECT_START \u0026\u0026\n-\t ctx-\u003epath_match \u003d\u003d LEJPVP_PROTOCOL_NAME + 1) {\n-\t\ta-\u003epvo \u003d lwsws_align(a);\n-\t\ta-\u003ep +\u003d sizeof(*a-\u003epvo);\n-\n-\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n-\t\t/* ie, enable this protocol, no options yet */\n-\t\ta-\u003epvo-\u003enext \u003d a-\u003einfo-\u003epvo;\n-\t\ta-\u003einfo-\u003epvo \u003d a-\u003epvo;\n-\t\ta-\u003epvo-\u003ename \u003d a-\u003ep;\n-\t\tlwsl_notice(\u0022 adding protocol %s\u005cn\u0022, a-\u003ep);\n-\t\ta-\u003ep +\u003d n;\n-\t\ta-\u003epvo-\u003evalue \u003d a-\u003ep;\n-\t\ta-\u003epvo-\u003eoptions \u003d NULL;\n-\t\tgoto dostring;\n-\t}\n-\n-\t/* this catches, eg, vhosts[].headers[].xxx */\n-\tif (reason \u003d\u003d LEJPCB_VAL_STR_END \u0026\u0026\n-\t ctx-\u003epath_match \u003d\u003d LEJPVP_HEADERS_NAME + 1) {\n-\t\theaders \u003d lwsws_align(a);\n-\t\ta-\u003ep +\u003d sizeof(*headers);\n-\n-\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n-\t\t/* ie, enable this protocol, no options yet */\n-\t\theaders-\u003enext \u003d a-\u003einfo-\u003eheaders;\n-\t\ta-\u003einfo-\u003eheaders \u003d headers;\n-\t\theaders-\u003ename \u003d a-\u003ep;\n-\t\t// lwsl_notice(\u0022 adding header %s\u003d%s\u005cn\u0022, a-\u003ep, ctx-\u003ebuf);\n-\t\ta-\u003ep +\u003d n - 1;\n-\t\t*(a-\u003ep++) \u003d ':';\n-\t\tif (a-\u003ep \u003c a-\u003eend)\n-\t\t\t*(a-\u003ep++) \u003d '\u005c0';\n-\t\telse\n-\t\t\t*(a-\u003ep - 1) \u003d '\u005c0';\n-\t\theaders-\u003evalue \u003d a-\u003ep;\n-\t\theaders-\u003eoptions \u003d NULL;\n-\t\tgoto dostring;\n-\t}\n-\n-\tif (reason \u003d\u003d LEJPCB_OBJECT_END \u0026\u0026\n-\t (ctx-\u003epath_match \u003d\u003d LEJPVP + 1 || !ctx-\u003epath[0]) \u0026\u0026\n-\t a-\u003evalid) {\n-\n-\t\tstruct lws_vhost *vhost;\n-\n-\t\t//lwsl_notice(\u0022%s\u005cn\u0022, ctx-\u003epath);\n-\t\tif (!a-\u003einfo-\u003eport) {\n-\t\t\tlwsl_err(\u0022Port required (eg, 443)\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\t\ta-\u003evalid \u003d 0;\n-\t\ta-\u003einfo-\u003emounts \u003d a-\u003ehead;\n-\n-\t\tvhost \u003d lws_create_vhost(a-\u003econtext, a-\u003einfo);\n-\t\tif (!vhost) {\n-\t\t\tlwsl_err(\u0022Failed to create vhost %s\u005cn\u0022,\n-\t\t\t\t a-\u003einfo-\u003evhost_name);\n-\t\t\treturn 1;\n-\t\t}\n-\t\ta-\u003eany_vhosts \u003d 1;\n-\n-\t\tif (a-\u003eenable_client_ssl) {\n-\t\t\tconst char *cert_filepath \u003d a-\u003einfo-\u003eclient_ssl_cert_filepath;\n-\t\t\tconst char *private_key_filepath \u003d a-\u003einfo-\u003eclient_ssl_private_key_filepath;\n-\t\t\tconst char *ca_filepath \u003d a-\u003einfo-\u003eclient_ssl_ca_filepath;\n-\t\t\tconst char *cipher_list \u003d a-\u003einfo-\u003eclient_ssl_cipher_list;\n-\t\t\tmemset(a-\u003einfo, 0, sizeof(*a-\u003einfo));\n-\t\t\ta-\u003einfo-\u003eclient_ssl_cert_filepath \u003d cert_filepath;\n-\t\t\ta-\u003einfo-\u003eclient_ssl_private_key_filepath \u003d private_key_filepath;\n-\t\t\ta-\u003einfo-\u003eclient_ssl_ca_filepath \u003d ca_filepath;\n-\t\t\ta-\u003einfo-\u003eclient_ssl_cipher_list \u003d cipher_list;\n-\t\t\ta-\u003einfo-\u003eoptions \u003d LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n-\t\t\tlws_init_vhost_client_ssl(a-\u003einfo, vhost);\n-\t\t}\n-\n-\t\treturn 0;\n-\t}\n-\n-\tif (reason \u003d\u003d LEJPCB_OBJECT_END \u0026\u0026\n-\t ctx-\u003epath_match \u003d\u003d LEJPVP_MOUNTS + 1) {\n-\t\tstatic const char * const mount_protocols[] \u003d {\n-\t\t\t\u0022http://\u0022,\n-\t\t\t\u0022https://\u0022,\n-\t\t\t\u0022file://\u0022,\n-\t\t\t\u0022cgi://\u0022,\n-\t\t\t\u0022\u003ehttp://\u0022,\n-\t\t\t\u0022\u003ehttps://\u0022,\n-\t\t\t\u0022callback://\u0022,\n-\t\t\t\u0022gzip://\u0022,\n-\t\t};\n-\n-\t\tif (!a-\u003efresh_mount)\n-\t\t\treturn 0;\n-\n-\t\tif (!a-\u003em.mountpoint || !a-\u003em.origin) {\n-\t\t\tlwsl_err(\u0022mountpoint and origin required\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\t\tlwsl_debug(\u0022adding mount %s\u005cn\u0022, a-\u003em.mountpoint);\n-\t\tm \u003d lwsws_align(a);\n-\t\tmemcpy(m, \u0026a-\u003em, sizeof(*m));\n-\t\tif (a-\u003elast)\n-\t\t\ta-\u003elast-\u003emount_next \u003d m;\n-\n-\t\tfor (n \u003d 0; n \u003c ARRAY_SIZE(mount_protocols); n++)\n-\t\t\tif (!strncmp(a-\u003em.origin, mount_protocols[n],\n-\t\t\t strlen(mount_protocols[n]))) {\n-\t\t\t\tlwsl_info(\u0022----%s\u005cn\u0022, a-\u003em.origin);\n-\t\t\t\tm-\u003eorigin_protocol \u003d n;\n-\t\t\t\tm-\u003eorigin \u003d a-\u003em.origin +\n-\t\t\t\t\t strlen(mount_protocols[n]);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\tif (n \u003d\u003d ARRAY_SIZE(mount_protocols)) {\n-\t\t\tlwsl_err(\u0022unsupported protocol:// %s\u005cn\u0022, a-\u003em.origin);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\ta-\u003ep +\u003d sizeof(*m);\n-\t\tif (!a-\u003ehead)\n-\t\t\ta-\u003ehead \u003d m;\n-\n-\t\ta-\u003elast \u003d m;\n-\t\ta-\u003efresh_mount \u003d 0;\n-\t}\n-\n-\t/* we only match on the prepared path strings */\n-\tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n-\t\treturn 0;\n-\n-\tswitch (ctx-\u003epath_match - 1) {\n-\tcase LEJPVP_NAME:\n-\t\ta-\u003einfo-\u003evhost_name \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_PORT:\n-\t\ta-\u003einfo-\u003eport \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPVP_INTERFACE:\n-\t\ta-\u003einfo-\u003eiface \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_UNIXSKT:\n-\t\tif (arg_to_bool(ctx-\u003ebuf))\n-\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_UNIX_SOCK;\n-\t\telse\n-\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_UNIX_SOCK);\n-\t\treturn 0;\n-\tcase LEJPVP_STS:\n-\t\tif (arg_to_bool(ctx-\u003ebuf))\n-\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_STS;\n-\t\telse\n-\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_STS);\n-\t\treturn 0;\n-\tcase LEJPVP_HOST_SSL_KEY:\n-\t\ta-\u003einfo-\u003essl_private_key_filepath \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_HOST_SSL_CERT:\n-\t\ta-\u003einfo-\u003essl_cert_filepath \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_HOST_SSL_CA:\n-\t\ta-\u003einfo-\u003essl_ca_filepath \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_ACCESS_LOG:\n-\t\ta-\u003einfo-\u003elog_filepath \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_MOUNTPOINT:\n-\t\ta-\u003em.mountpoint \u003d a-\u003ep;\n-\t\ta-\u003em.mountpoint_len \u003d (unsigned char)strlen(ctx-\u003ebuf);\n-\t\tbreak;\n-\tcase LEJPVP_ORIGIN:\n-\t\tif (!strncmp(ctx-\u003ebuf, \u0022callback://\u0022, 11))\n-\t\t\ta-\u003em.protocol \u003d a-\u003ep + 11;\n-\n-\t\tif (!a-\u003em.origin)\n-\t\t\ta-\u003em.origin \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_DEFAULT:\n-\t\ta-\u003em.def \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_DEFAULT_AUTH_MASK:\n-\t\ta-\u003em.auth_mask \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPVP_MOUNT_CACHE_MAX_AGE:\n-\t\ta-\u003em.cache_max_age \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPVP_MOUNT_CACHE_REUSE:\n-\t\ta-\u003em.cache_reusable \u003d arg_to_bool(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPVP_MOUNT_CACHE_REVALIDATE:\n-\t\ta-\u003em.cache_revalidate \u003d arg_to_bool(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPVP_MOUNT_CACHE_INTERMEDIARIES:\n-\t\ta-\u003em.cache_intermediaries \u003d arg_to_bool(ctx-\u003ebuf);;\n-\t\treturn 0;\n-\tcase LEJPVP_MOUNT_BASIC_AUTH:\n-\t\ta-\u003em.basic_auth_login_file \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_CGI_TIMEOUT:\n-\t\ta-\u003em.cgi_timeout \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPVP_KEEPALIVE_TIMEOUT:\n-\t\ta-\u003einfo-\u003ekeepalive_timeout \u003d atoi(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPVP_CLIENT_CIPHERS:\n-\t\ta-\u003einfo-\u003eclient_ssl_cipher_list \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_CIPHERS:\n-\t\ta-\u003einfo-\u003essl_cipher_list \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_ECDH_CURVE:\n-\t\ta-\u003einfo-\u003eecdh_curve \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_PMO:\n-\tcase LEJPVP_CGI_ENV:\n-\t\tmp_cgienv \u003d lwsws_align(a);\n-\t\ta-\u003ep +\u003d sizeof(*a-\u003em.cgienv);\n-\n-\t\tmp_cgienv-\u003enext \u003d a-\u003em.cgienv;\n-\t\ta-\u003em.cgienv \u003d mp_cgienv;\n-\n-\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n-\t\tmp_cgienv-\u003ename \u003d a-\u003ep;\n-\t\ta-\u003ep +\u003d n;\n-\t\tmp_cgienv-\u003evalue \u003d a-\u003ep;\n-\t\tmp_cgienv-\u003eoptions \u003d NULL;\n-\t\t//lwsl_notice(\u0022 adding pmo / cgi-env '%s' \u003d '%s'\u005cn\u0022, mp_cgienv-\u003ename,\n-\t\t//\t\tmp_cgienv-\u003evalue);\n-\t\tgoto dostring;\n-\n-\tcase LEJPVP_PROTOCOL_NAME_OPT:\n-\t\t/* this catches, eg,\n-\t\t * vhosts[].ws-protocols[].xxx-protocol.yyy-option\n-\t\t * ie, these are options attached to a protocol with { }\n-\t\t */\n-\t\tpvo \u003d lwsws_align(a);\n-\t\ta-\u003ep +\u003d sizeof(*a-\u003epvo);\n-\n-\t\tn \u003d lejp_get_wildcard(ctx, 1, a-\u003ep, a-\u003eend - a-\u003ep);\n-\t\t/* ie, enable this protocol, no options yet */\n-\t\tpvo-\u003enext \u003d a-\u003epvo-\u003eoptions;\n-\t\ta-\u003epvo-\u003eoptions \u003d pvo;\n-\t\tpvo-\u003ename \u003d a-\u003ep;\n-\t\ta-\u003ep +\u003d n;\n-\t\tpvo-\u003evalue \u003d a-\u003ep;\n-\t\tpvo-\u003eoptions \u003d NULL;\n-\t\tbreak;\n-\n-\tcase LEJPVP_MOUNT_EXTRA_MIMETYPES:\n-\t\ta-\u003epvo_em \u003d lwsws_align(a);\n-\t\ta-\u003ep +\u003d sizeof(*a-\u003epvo_em);\n-\n-\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n-\t\t/* ie, enable this protocol, no options yet */\n-\t\ta-\u003epvo_em-\u003enext \u003d a-\u003em.extra_mimetypes;\n-\t\ta-\u003em.extra_mimetypes \u003d a-\u003epvo_em;\n-\t\ta-\u003epvo_em-\u003ename \u003d a-\u003ep;\n-\t\tlwsl_notice(\u0022 adding extra-mimetypes %s -\u003e %s\u005cn\u0022, a-\u003ep, ctx-\u003ebuf);\n-\t\ta-\u003ep +\u003d n;\n-\t\ta-\u003epvo_em-\u003evalue \u003d a-\u003ep;\n-\t\ta-\u003epvo_em-\u003eoptions \u003d NULL;\n-\t\tbreak;\n-\n-\tcase LEJPVP_MOUNT_INTERPRET:\n-\t\ta-\u003epvo_int \u003d lwsws_align(a);\n-\t\ta-\u003ep +\u003d sizeof(*a-\u003epvo_int);\n-\n-\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n-\t\t/* ie, enable this protocol, no options yet */\n-\t\ta-\u003epvo_int-\u003enext \u003d a-\u003em.interpret;\n-\t\ta-\u003em.interpret \u003d a-\u003epvo_int;\n-\t\ta-\u003epvo_int-\u003ename \u003d a-\u003ep;\n-\t\tlwsl_notice(\u0022 adding interpret %s -\u003e %s\u005cn\u0022, a-\u003ep,\n-\t\t\t ctx-\u003ebuf);\n-\t\ta-\u003ep +\u003d n;\n-\t\ta-\u003epvo_int-\u003evalue \u003d a-\u003ep;\n-\t\ta-\u003epvo_int-\u003eoptions \u003d NULL;\n-\t\tbreak;\n-\n-\tcase LEJPVP_ENABLE_CLIENT_SSL:\n-\t\ta-\u003eenable_client_ssl \u003d arg_to_bool(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPVP_CLIENT_SSL_KEY:\n-\t\ta-\u003einfo-\u003eclient_ssl_private_key_filepath \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_CLIENT_SSL_CERT:\n-\t\ta-\u003einfo-\u003eclient_ssl_cert_filepath \u003d a-\u003ep;\n-\t\tbreak;\n-\tcase LEJPVP_CLIENT_SSL_CA:\n-\t\ta-\u003einfo-\u003eclient_ssl_ca_filepath \u003d a-\u003ep;\n-\t\tbreak;\n-\n-\tcase LEJPVP_NOIPV6:\n-\t\tif (arg_to_bool(ctx-\u003ebuf))\n-\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_DISABLE_IPV6;\n-\t\telse\n-\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_DISABLE_IPV6);\n-\t\treturn 0;\n-\n-\tcase LEJPVP_FLAG_ONLYRAW:\n-\t\tif (arg_to_bool(ctx-\u003ebuf))\n-\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_ONLY_RAW;\n-\t\telse\n-\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_ONLY_RAW);\n-\t\treturn 0;\n-\n-\tcase LEJPVP_IPV6ONLY:\n-\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY;\n-\t\tif (arg_to_bool(ctx-\u003ebuf))\n-\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE;\n-\t\telse\n-\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);\n-\t\treturn 0;\n-\n-\tcase LEJPVP_SSL_OPTION_SET:\n-\t\ta-\u003einfo-\u003essl_options_set |\u003d atol(ctx-\u003ebuf);\n-\t\treturn 0;\n-\tcase LEJPVP_SSL_OPTION_CLEAR:\n-\t\ta-\u003einfo-\u003essl_options_clear |\u003d atol(ctx-\u003ebuf);\n-\t\treturn 0;\n-\n-\tdefault:\n-\t\treturn 0;\n-\t}\n-\n-dostring:\n-\tp \u003d ctx-\u003ebuf;\n-\tp1 \u003d strstr(p, ESC_INSTALL_DATADIR);\n-\tif (p1) {\n-\t\tn \u003d p1 - p;\n-\t\tif (n \u003e a-\u003eend - a-\u003ep)\n-\t\t\tn \u003d a-\u003eend - a-\u003ep;\n-\t\tstrncpy(a-\u003ep, p, n);\n-\t\ta-\u003ep +\u003d n;\n-\t\ta-\u003ep +\u003d lws_snprintf(a-\u003ep, a-\u003eend - a-\u003ep, \u0022%s\u0022, LWS_INSTALL_DATADIR);\n-\t\tp +\u003d n + strlen(ESC_INSTALL_DATADIR);\n-\t}\n-\n-\ta-\u003ep +\u003d lws_snprintf(a-\u003ep, a-\u003eend - a-\u003ep, \u0022%s\u0022, p);\n-\t*(a-\u003ep)++ \u003d '\u005c0';\n-\n-\treturn 0;\n-}\n-\n-/*\n- * returns 0 \u003d OK, 1 \u003d can't open, 2 \u003d parsing error\n- */\n-\n-static int\n-lwsws_get_config(void *user, const char *f, const char * const *paths,\n-\t\t int count_paths, lejp_callback cb)\n-{\n-\tunsigned char buf[128];\n-\tstruct lejp_ctx ctx;\n-\tint n, m, fd;\n-\n-\tfd \u003d open(f, O_RDONLY);\n-\tif (fd \u003c 0) {\n-\t\tlwsl_err(\u0022Cannot open %s\u005cn\u0022, f);\n-\t\treturn 2;\n-\t}\n-\tlwsl_info(\u0022%s: %s\u005cn\u0022, __func__, f);\n-\tlejp_construct(\u0026ctx, cb, user, paths, count_paths);\n-\n-\tdo {\n-\t\tn \u003d read(fd, buf, sizeof(buf));\n-\t\tif (!n)\n-\t\t\tbreak;\n-\n-\t\tm \u003d (int)(signed char)lejp_parse(\u0026ctx, buf, n);\n-\t} while (m \u003d\u003d LEJP_CONTINUE);\n-\n-\tclose(fd);\n-\tn \u003d ctx.line;\n-\tlejp_destruct(\u0026ctx);\n-\n-\tif (m \u003c 0) {\n-\t\tlwsl_err(\u0022%s(%u): parsing error %d: %s\u005cn\u0022, f, n, m,\n-\t\t\t parser_errs[-m]);\n-\t\treturn 2;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-#if defined(LWS_WITH_LIBUV) \u0026\u0026 UV_VERSION_MAJOR \u003e 0\n-\n-static int\n-lwsws_get_config_d(void *user, const char *d, const char * const *paths,\n-\t\t int count_paths, lejp_callback cb)\n-{\n-\tuv_dirent_t dent;\n-\tuv_fs_t req;\n-\tchar path[256];\n-\tint ret \u003d 0, ir;\n-\tuv_loop_t loop;\n-\n-\tir \u003d uv_loop_init(\u0026loop);\n-\tif (ir) {\n-\t\tlwsl_err(\u0022%s: loop init failed %d\u005cn\u0022, __func__, ir);\n-\t}\n-\n-\tif (!uv_fs_scandir(\u0026loop, \u0026req, d, 0, NULL)) {\n-\t\tlwsl_err(\u0022Scandir on %s failed\u005cn\u0022, d);\n-\t\treturn 2;\n-\t}\n-\n-\twhile (uv_fs_scandir_next(\u0026req, \u0026dent) !\u003d UV_EOF) {\n-\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, d, dent.name);\n-\t\tret \u003d lwsws_get_config(user, path, paths, count_paths, cb);\n-\t\tif (ret)\n-\t\t\tgoto bail;\n-\t}\n-\n-bail:\n-\tuv_fs_req_cleanup(\u0026req);\n-\twhile (uv_loop_close(\u0026loop))\n-\t\t;\n-\n-\treturn ret;\n-}\n-\n-#else\n-\n-#ifndef _WIN32\n-static int filter(const struct dirent *ent)\n-{\n-\tif (!strcmp(ent-\u003ed_name, \u0022.\u0022) || !strcmp(ent-\u003ed_name, \u0022..\u0022))\n-\t\treturn 0;\n-\n-\treturn 1;\n-}\n-#endif\n-\n-static int\n-lwsws_get_config_d(void *user, const char *d, const char * const *paths,\n-\t\t int count_paths, lejp_callback cb)\n-{\n-#ifndef _WIN32\n-\tstruct dirent **namelist;\n-\tchar path[256];\n-\tint n, i, ret \u003d 0;\n-\n-\tn \u003d scandir(d, \u0026namelist, filter, alphasort);\n-\tif (n \u003c 0) {\n-\t\tlwsl_err(\u0022Scandir on %s failed\u005cn\u0022, d);\n-\t\treturn 1;\n-\t}\n-\n-\tfor (i \u003d 0; i \u003c n; i++) {\n-\t\tif (strchr(namelist[i]-\u003ed_name, '~'))\n-\t\t\tgoto skip;\n-\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, d,\n-\t\t\t namelist[i]-\u003ed_name);\n-\t\tret \u003d lwsws_get_config(user, path, paths, count_paths, cb);\n-\t\tif (ret) {\n-\t\t\twhile (i++ \u003c n)\n-\t\t\t\tfree(namelist[i]);\n-\t\t\tgoto bail;\n-\t\t}\n-skip:\n-\t\tfree(namelist[i]);\n-\t}\n-\n-bail:\n-\tfree(namelist);\n-\n-\treturn ret;\n-#else\n-\treturn 0;\n-#endif\n-}\n-\n-#endif\n-\n-int\n-lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,\n-\t\t\t char **cs, int *len)\n-{\n-\tstruct jpargs a;\n-\tconst char * const *old \u003d info-\u003eplugin_dirs;\n-\tchar dd[128];\n-\n-\tmemset(\u0026a, 0, sizeof(a));\n-\n-\ta.info \u003d info;\n-\ta.p \u003d *cs;\n-\ta.end \u003d (a.p + *len) - 1;\n-\ta.valid \u003d 0;\n-\n-\tlwsws_align(\u0026a);\n-\tinfo-\u003eplugin_dirs \u003d (void *)a.p;\n-\ta.plugin_dirs \u003d (void *)a.p; /* writeable version */\n-\ta.p +\u003d MAX_PLUGIN_DIRS * sizeof(void *);\n-\n-\t/* copy any default paths */\n-\n-\twhile (old \u0026\u0026 *old) {\n-\t\ta.plugin_dirs[a.count_plugin_dirs++] \u003d *old;\n-\t\told++;\n-\t}\n-\n-\tlws_snprintf(dd, sizeof(dd) - 1, \u0022%s/conf\u0022, d);\n-\tif (lwsws_get_config(\u0026a, dd, paths_global,\n-\t\t\t ARRAY_SIZE(paths_global), lejp_globals_cb) \u003e 1)\n-\t\treturn 1;\n-\tlws_snprintf(dd, sizeof(dd) - 1, \u0022%s/conf.d\u0022, d);\n-\tif (lwsws_get_config_d(\u0026a, dd, paths_global,\n-\t\t\t ARRAY_SIZE(paths_global), lejp_globals_cb) \u003e 1)\n-\t\treturn 1;\n-\n-\ta.plugin_dirs[a.count_plugin_dirs] \u003d NULL;\n-\n-\t*cs \u003d a.p;\n-\t*len \u003d a.end - a.p;\n-\n-\treturn 0;\n-}\n-\n-int\n-lwsws_get_config_vhosts(struct lws_context *context,\n-\t\t\tstruct lws_context_creation_info *info, const char *d,\n-\t\t\tchar **cs, int *len)\n-{\n-\tstruct jpargs a;\n-\tchar dd[128];\n-\n-\tmemset(\u0026a, 0, sizeof(a));\n-\n-\ta.info \u003d info;\n-\ta.p \u003d *cs;\n-\ta.end \u003d a.p + *len;\n-\ta.valid \u003d 0;\n-\ta.context \u003d context;\n-\ta.protocols \u003d info-\u003eprotocols;\n-\ta.extensions \u003d info-\u003eextensions;\n-\n-\tlws_snprintf(dd, sizeof(dd) - 1, \u0022%s/conf\u0022, d);\n-\tif (lwsws_get_config(\u0026a, dd, paths_vhosts,\n-\t\t\t ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) \u003e 1)\n-\t\treturn 1;\n-\tlws_snprintf(dd, sizeof(dd) - 1, \u0022%s/conf.d\u0022, d);\n-\tif (lwsws_get_config_d(\u0026a, dd, paths_vhosts,\n-\t\t\t ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) \u003e 1)\n-\t\treturn 1;\n-\n-\t*cs \u003d a.p;\n-\t*len \u003d a.end - a.p;\n-\n-\tif (!a.any_vhosts) {\n-\t\tlwsl_err(\u0022Need at least one vhost\u005cn\u0022);\n-\t\treturn 1;\n-\t}\n-\n-//\tlws_finalize_startup(context);\n-\n-\treturn 0;\n-}\ndiff --git a/lib/lejp.c b/lib/lejp.c\ndeleted file mode 100644\nindex 50ff4b5..0000000\n--- a/lib/lejp.c\n+++ /dev/null\n@@ -1,709 +0,0 @@\n-/*\n- * Lightweight Embedded JSON Parser\n- *\n- * Copyright (C) 2013 Andy Green \u003candy@warmcat.com\u003e\n- * This code is licensed under LGPL 2.1\n- * http://www.gnu.org/licenses/lgpl-2.1.html\n- */\n-\n-#include \u003cstring.h\u003e\n-#include \u0022lejp.h\u0022\n-\n-#include \u003cstdio.h\u003e\n-\n-/**\n- * lejp_construct - prepare a struct lejp_ctx for use\n- *\n- * \u005cparam ctx:\tpointer to your struct lejp_ctx\n- * \u005cparam callback:\tyour user callback which will received parsed tokens\n- * \u005cparam user:\toptional user data pointer untouched by lejp\n- * \u005cparam paths:\tyour array of name elements you are interested in\n- * \u005cparam count_paths:\tARRAY_SIZE() of @paths\n- *\n- * Prepares your context struct for use with lejp\n- */\n-\n-void\n-lejp_construct(struct lejp_ctx *ctx,\n-\tchar (*callback)(struct lejp_ctx *ctx, char reason), void *user,\n-\t\t\tconst char * const *paths, unsigned char count_paths)\n-{\n-\tctx-\u003est[0].s \u003d 0;\n-\tctx-\u003est[0].p \u003d 0;\n-\tctx-\u003est[0].i \u003d 0;\n-\tctx-\u003est[0].b \u003d 0;\n-\tctx-\u003esp \u003d 0;\n-\tctx-\u003eipos \u003d 0;\n-\tctx-\u003eppos \u003d 0;\n-\tctx-\u003epath_match \u003d 0;\n-\tctx-\u003epath[0] \u003d '\u005c0';\n-\tctx-\u003ecallback \u003d callback;\n-\tctx-\u003euser \u003d user;\n-\tctx-\u003epaths \u003d paths;\n-\tctx-\u003ecount_paths \u003d count_paths;\n-\tctx-\u003eline \u003d 1;\n-\tctx-\u003ecallback(ctx, LEJPCB_CONSTRUCTED);\n-}\n-\n-/**\n- * lejp_destruct - retire a previously constructed struct lejp_ctx\n- *\n- * \u005cparam ctx:\tpointer to your struct lejp_ctx\n- *\n- * lejp does not perform any allocations, but since your user code might, this\n- * provides a one-time LEJPCB_DESTRUCTED callback at destruction time where\n- * you can clean up in your callback.\n- */\n-\n-void\n-lejp_destruct(struct lejp_ctx *ctx)\n-{\n-\t/* no allocations... just let callback know what it happening */\n-\tctx-\u003ecallback(ctx, LEJPCB_DESTRUCTED);\n-}\n-\n-/**\n- * lejp_change_callback - switch to a different callback from now on\n- *\n- * \u005cparam ctx:\tpointer to your struct lejp_ctx\n- * \u005cparam callback:\tyour user callback which will received parsed tokens\n- *\n- * This tells the old callback it was destroyed, in case you want to take any\n- * action because that callback \u0022lost focus\u0022, then changes to the new\n- * callback and tells it first that it was constructed, and then started.\n- *\n- * Changing callback is a cheap and powerful trick to split out handlers\n- * according to information earlier in the parse. For example you may have\n- * a JSON pair \u0022schema\u0022 whose value defines what can be expected for the rest\n- * of the JSON. Rather than having one huge callback for all cases, you can\n- * have an initial one looking for \u0022schema\u0022 which then calls\n- * lejp_change_callback() to a handler specific for the schema.\n- *\n- * Notice that afterwards, you need to construct the context again anyway to\n- * parse another JSON object, and the callback is reset then to the main,\n- * schema-interpreting one. The construction action is very lightweight.\n- */\n-\n-void\n-lejp_change_callback(struct lejp_ctx *ctx,\n-\t\t char (*callback)(struct lejp_ctx *ctx, char reason))\n-{\n-\tctx-\u003ecallback(ctx, LEJPCB_DESTRUCTED);\n-\tctx-\u003ecallback \u003d callback;\n-\tctx-\u003ecallback(ctx, LEJPCB_CONSTRUCTED);\n-\tctx-\u003ecallback(ctx, LEJPCB_START);\n-}\n-\n-static void\n-lejp_check_path_match(struct lejp_ctx *ctx)\n-{\n-\tconst char *p, *q;\n-\tint n;\n-\n-\t/* we only need to check if a match is not active */\n-\tfor (n \u003d 0; !ctx-\u003epath_match \u0026\u0026 n \u003c ctx-\u003ecount_paths; n++) {\n-\t\tctx-\u003ewildcount \u003d 0;\n-\t\tp \u003d ctx-\u003epath;\n-\t\tq \u003d ctx-\u003epaths[n];\n-\t\twhile (*p \u0026\u0026 *q) {\n-\t\t\tif (*q !\u003d '*') {\n-\t\t\t\tif (*p !\u003d *q)\n-\t\t\t\t\tbreak;\n-\t\t\t\tp++;\n-\t\t\t\tq++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tctx-\u003ewild[ctx-\u003ewildcount++] \u003d p - ctx-\u003epath;\n-\t\t\tq++;\n-\t\t\t/*\n-\t\t\t * if * has something after it, match to .\n-\t\t\t * if ends with *, eat everything.\n-\t\t\t * This implies match sequences must be ordered like\n-\t\t\t * x.*.*\n-\t\t\t * x.*\n-\t\t\t * if both options are possible\n-\t\t\t */\n-\t\t\twhile (*p \u0026\u0026 (*p !\u003d '.' || !*q))\n-\t\t\t\tp++;\n-\t\t}\n-\t\tif (*p || *q)\n-\t\t\tcontinue;\n-\n-\t\tctx-\u003epath_match \u003d n + 1;\n-\t\tctx-\u003epath_match_len \u003d ctx-\u003eppos;\n-\t\treturn;\n-\t}\n-\n-\tif (!ctx-\u003epath_match)\n-\t\tctx-\u003ewildcount \u003d 0;\n-}\n-\n-int\n-lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)\n-{\n-\tint n;\n-\n-\tif (wildcard \u003e\u003d ctx-\u003ewildcount || !len)\n-\t\treturn 0;\n-\n-\tn \u003d ctx-\u003ewild[wildcard];\n-\n-\twhile (--len \u0026\u0026 n \u003c ctx-\u003eppos \u0026\u0026 (n \u003d\u003d ctx-\u003ewild[wildcard] || ctx-\u003epath[n] !\u003d '.'))\n-\t\t*dest++ \u003d ctx-\u003epath[n++];\n-\n-\t*dest \u003d '\u005c0';\n-\tn++;\n-\n-\treturn n - ctx-\u003ewild[wildcard];\n-}\n-\n-/**\n- * lejp_parse - interpret some more incoming data incrementally\n- *\n- * \u005cparam ctx:\tpreviously constructed parsing context\n- * \u005cparam json:\tchar buffer with the new data to interpret\n- * \u005cparam len:\tamount of data in the buffer\n- *\n- * Because lejp is a stream parser, it incrementally parses as new data\n- * becomes available, maintaining all state in the context struct. So an\n- * incomplete JSON is a normal situation, getting you a LEJP_CONTINUE\n- * return, signalling there's no error but to call again with more data when\n- * it comes to complete the parsing. Successful parsing completes with a\n- * 0 or positive integer indicating how much of the last input buffer was\n- * unused.\n- */\n-\n-int\n-lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)\n-{\n-\tunsigned char c, n, s, ret \u003d LEJP_REJECT_UNKNOWN;\n-\tstatic const char esc_char[] \u003d \u0022\u005c\u0022\u005c\u005c/bfnrt\u0022;\n-\tstatic const char esc_tran[] \u003d \u0022\u005c\u0022\u005c\u005c/\u005cb\u005cf\u005cn\u005cr\u005ct\u0022;\n-\tstatic const char tokens[] \u003d \u0022rue alse ull \u0022;\n-\n-\tif (!ctx-\u003esp \u0026\u0026 !ctx-\u003eppos)\n-\t\tctx-\u003ecallback(ctx, LEJPCB_START);\n-\n-\twhile (len--) {\n-\t\tc \u003d *json++;\n-\n-\t\ts \u003d ctx-\u003est[ctx-\u003esp].s;\n-\n-\t\t/* skip whitespace unless we should care */\n-\t\tif (c \u003d\u003d ' ' || c \u003d\u003d '\u005ct' || c \u003d\u003d '\u005cn' || c \u003d\u003d '\u005cr' || c \u003d\u003d '#') {\n-\t\t\tif (c \u003d\u003d '\u005cn') {\n-\t\t\t\tctx-\u003eline++;\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u0026\u003d ~LEJP_FLAG_WS_COMMENTLINE;\n-\t\t\t}\n-\t\t\tif (!(s \u0026 LEJP_FLAG_WS_KEEP)) {\n-\t\t\t\tif (c \u003d\u003d '#')\n-\t\t\t\t\tctx-\u003est[ctx-\u003esp].s |\u003d\n-\t\t\t\t\t\tLEJP_FLAG_WS_COMMENTLINE;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (ctx-\u003est[ctx-\u003esp].s \u0026 LEJP_FLAG_WS_COMMENTLINE)\n-\t\t\tcontinue;\n-\n-\t\tswitch (s) {\n-\t\tcase LEJP_IDLE:\n-\t\t\tif (c !\u003d '{') {\n-\t\t\t\tret \u003d LEJP_REJECT_IDLE_NO_BRACE;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_OBJECT_START)) {\n-\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MEMBERS;\n-\t\t\tbreak;\n-\t\tcase LEJP_MEMBERS:\n-\t\t\tif (c \u003d\u003d '}') {\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_IDLE;\n-\t\t\t\tret \u003d LEJP_REJECT_MEMBERS_NO_CLOSE;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_M_P;\n-\t\t\tgoto redo_character;\n-\t\tcase LEJP_M_P:\n-\t\t\tif (c !\u003d '\u005c\u0022') {\n-\t\t\t\tret \u003d LEJP_REJECT_MP_NO_OPEN_QUOTE;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\t/* push */\n-\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_DELIM;\n-\t\t\tc \u003d LEJP_MP_STRING;\n-\t\t\tgoto add_stack_level;\n-\n-\t\tcase LEJP_MP_STRING:\n-\t\t\tif (c \u003d\u003d '\u005c\u0022') {\n-\t\t\t\tif (!ctx-\u003esp) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_MP_STRING_UNDERRUN;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tif (ctx-\u003est[ctx-\u003esp - 1].s !\u003d LEJP_MP_DELIM) {\n-\t\t\t\t\tctx-\u003ebuf[ctx-\u003enpos] \u003d '\u005c0';\n-\t\t\t\t\tif (ctx-\u003ecallback(ctx,\n-\t\t\t\t\t\t LEJPCB_VAL_STR_END) \u003c 0) {\n-\t\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\t\tgoto reject;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\t/* pop */\n-\t\t\t\tctx-\u003esp--;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (c \u003d\u003d '\u005c\u005c') {\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_STRING_ESC;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (c \u003c ' ') {/* \u0022control characters\u0022 not allowed */\n-\t\t\t\tret \u003d LEJP_REJECT_MP_ILLEGAL_CTRL;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\tgoto emit_string_char;\n-\n-\t\tcase LEJP_MP_STRING_ESC:\n-\t\t\tif (c \u003d\u003d 'u') {\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_STRING_ESC_U1;\n-\t\t\t\tctx-\u003euni \u003d 0;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tfor (n \u003d 0; n \u003c sizeof(esc_char); n++) {\n-\t\t\t\tif (c !\u003d esc_char[n])\n-\t\t\t\t\tcontinue;\n-\t\t\t\t/* found it */\n-\t\t\t\tc \u003d esc_tran[n];\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_STRING;\n-\t\t\t\tgoto emit_string_char;\n-\t\t\t}\n-\t\t\tret \u003d LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC;\n-\t\t\t/* illegal escape char */\n-\t\t\tgoto reject;\n-\n-\t\tcase LEJP_MP_STRING_ESC_U1:\n-\t\tcase LEJP_MP_STRING_ESC_U2:\n-\t\tcase LEJP_MP_STRING_ESC_U3:\n-\t\tcase LEJP_MP_STRING_ESC_U4:\n-\t\t\tctx-\u003euni \u003c\u003c\u003d 4;\n-\t\t\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')\n-\t\t\t\tctx-\u003euni |\u003d c - '0';\n-\t\t\telse\n-\t\t\t\tif (c \u003e\u003d 'a' \u0026\u0026 c \u003c\u003d 'f')\n-\t\t\t\t\tctx-\u003euni \u003d c - 'a' + 10;\n-\t\t\t\telse\n-\t\t\t\t\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'F')\n-\t\t\t\t\t\tctx-\u003euni \u003d c - 'A' + 10;\n-\t\t\t\t\telse {\n-\t\t\t\t\t\tret \u003d LEJP_REJECT_ILLEGAL_HEX;\n-\t\t\t\t\t\tgoto reject;\n-\t\t\t\t\t}\n-\t\t\tctx-\u003est[ctx-\u003esp].s++;\n-\t\t\tswitch (s) {\n-\t\t\tcase LEJP_MP_STRING_ESC_U2:\n-\t\t\t\tif (ctx-\u003euni \u003c 0x08)\n-\t\t\t\t\tbreak;\n-\t\t\t\t/*\n-\t\t\t\t * 0x08-0xff (0x0800 - 0xffff)\n-\t\t\t\t * emit 3-byte UTF-8\n-\t\t\t\t */\n-\t\t\t\tc \u003d 0xe0 | ((ctx-\u003euni \u003e\u003e 4) \u0026 0xf);\n-\t\t\t\tgoto emit_string_char;\n-\n-\t\t\tcase LEJP_MP_STRING_ESC_U3:\n-\t\t\t\tif (ctx-\u003euni \u003e\u003d 0x080) {\n-\t\t\t\t\t/*\n-\t\t\t\t\t * 0x080 - 0xfff (0x0800 - 0xffff)\n-\t\t\t\t\t * middle 3-byte seq\n-\t\t\t\t\t * send ....XXXXXX..\n-\t\t\t\t\t */\n-\t\t\t\t\tc \u003d 0x80 | ((ctx-\u003euni \u003e\u003e 2) \u0026 0x3f);\n-\t\t\t\t\tgoto emit_string_char;\n-\t\t\t\t}\n-\t\t\t\tif (ctx-\u003euni \u003c 0x008)\n-\t\t\t\t\tbreak;\n-\t\t\t\t/*\n-\t\t\t\t * 0x008 - 0x7f (0x0080 - 0x07ff)\n-\t\t\t\t * start 2-byte seq\n-\t\t\t\t */\n-\t\t\t\tc \u003d 0xc0 | (ctx-\u003euni \u003e\u003e 2);\n-\t\t\t\tgoto emit_string_char;\n-\n-\t\t\tcase LEJP_MP_STRING_ESC_U4:\n-\t\t\t\tif (ctx-\u003euni \u003e\u003d 0x0080)\n-\t\t\t\t\t/* end of 2 or 3-byte seq */\n-\t\t\t\t\tc \u003d 0x80 | (ctx-\u003euni \u0026 0x3f);\n-\t\t\t\telse\n-\t\t\t\t\t/* literal */\n-\t\t\t\t\tc \u003d (unsigned char)ctx-\u003euni;\n-\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_STRING;\n-\t\t\t\tgoto emit_string_char;\n-\t\t\tdefault:\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tcase LEJP_MP_DELIM:\n-\t\t\tif (c !\u003d ':') {\n-\t\t\t\tret \u003d LEJP_REJECT_MP_DELIM_MISSING_COLON;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE;\n-\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n-\n-\t\t\tlejp_check_path_match(ctx);\n-\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_PAIR_NAME)) {\n-\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tcase LEJP_MP_VALUE:\n-\t\t\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9') {\n-\t\t\t\tctx-\u003enpos \u003d 0;\n-\t\t\t\tctx-\u003edcount \u003d 0;\n-\t\t\t\tctx-\u003ef \u003d 0;\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_NUM_INT;\n-\t\t\t\tgoto redo_character;\n-\t\t\t}\n-\t\t\tswitch (c) {\n-\t\t\tcase'\u005c\u0022':\n-\t\t\t\t/* push */\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n-\t\t\t\tc \u003d LEJP_MP_STRING;\n-\t\t\t\tctx-\u003enpos \u003d 0;\n-\t\t\t\tctx-\u003ebuf[0] \u003d '\u005c0';\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_STR_START)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tgoto add_stack_level;\n-\n-\t\t\tcase '{':\n-\t\t\t\t/* push */\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n-\t\t\t\tc \u003d LEJP_MEMBERS;\n-\t\t\t\tlejp_check_path_match(ctx);\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_OBJECT_START)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tctx-\u003epath_match \u003d 0;\n-\t\t\t\tgoto add_stack_level;\n-\n-\t\t\tcase '[':\n-\t\t\t\t/* push */\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_ARRAY_END;\n-\t\t\t\tc \u003d LEJP_MP_VALUE;\n-\t\t\t\tctx-\u003epath[ctx-\u003eppos++] \u003d '[';\n-\t\t\t\tctx-\u003epath[ctx-\u003eppos++] \u003d ']';\n-\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_ARRAY_START)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tctx-\u003ei[ctx-\u003eipos++] \u003d 0;\n-\t\t\t\tif (ctx-\u003eipos \u003e ARRAY_SIZE(ctx-\u003ei)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_MP_DELIM_ISTACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tgoto add_stack_level;\n-\n-\t\t\tcase 't': /* true */\n-\t\t\t\tctx-\u003euni \u003d 0;\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_TOK;\n-\t\t\t\tbreak;\n-\n-\t\t\tcase 'f':\n-\t\t\t\tctx-\u003euni \u003d 4;\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_TOK;\n-\t\t\t\tbreak;\n-\n-\t\t\tcase 'n':\n-\t\t\t\tctx-\u003euni \u003d 4 + 5;\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_TOK;\n-\t\t\t\tbreak;\n-\t\t\tdefault:\n-\t\t\t\tret \u003d LEJP_REJECT_MP_DELIM_BAD_VALUE_START;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tcase LEJP_MP_VALUE_NUM_INT:\n-\t\t\tif (!ctx-\u003enpos \u0026\u0026 c \u003d\u003d '-') {\n-\t\t\t\tctx-\u003ef |\u003d LEJP_SEEN_MINUS;\n-\t\t\t\tgoto append_npos;\n-\t\t\t}\n-\n-\t\t\tif (ctx-\u003edcount \u003c 10 \u0026\u0026 c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9') {\n-\t\t\t\tif (ctx-\u003ef \u0026 LEJP_SEEN_POINT)\n-\t\t\t\t\tctx-\u003ef |\u003d LEJP_SEEN_POST_POINT;\n-\t\t\t\tctx-\u003edcount++;\n-\t\t\t\tgoto append_npos;\n-\t\t\t}\n-\t\t\tif (c \u003d\u003d '.') {\n-\t\t\t\tif (ctx-\u003edcount || (ctx-\u003ef \u0026 LEJP_SEEN_POINT)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_FORMAT;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tctx-\u003ef |\u003d LEJP_SEEN_POINT;\n-\t\t\t\tgoto append_npos;\n-\t\t\t}\n-\t\t\t/*\n-\t\t\t * before exponent, if we had . we must have had at\n-\t\t\t * least one more digit\n-\t\t\t */\n-\t\t\tif ((ctx-\u003ef \u0026\n-\t\t\t\t(LEJP_SEEN_POINT | LEJP_SEEN_POST_POINT)) \u003d\u003d\n-\t\t\t\t\t\t\t LEJP_SEEN_POINT) {\n-\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\tif (c \u003d\u003d 'e' || c \u003d\u003d 'E') {\n-\t\t\t\tif (ctx-\u003ef \u0026 LEJP_SEEN_EXP) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_FORMAT;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tctx-\u003ef |\u003d LEJP_SEEN_EXP;\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_NUM_EXP;\n-\t\t\t\tgoto append_npos;\n-\t\t\t}\n-\t\t\t/* if none of the above, did we even have a number? */\n-\t\t\tif (!ctx-\u003edcount) {\n-\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_FORMAT;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\n-\t\t\tctx-\u003ebuf[ctx-\u003enpos] \u003d '\u005c0';\n-\t\t\tif (ctx-\u003ef \u0026 LEJP_SEEN_POINT) {\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_NUM_FLOAT)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t} else {\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_NUM_INT)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t}\n-\n-\t\t\t/* then this is the post-number character, loop */\n-\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n-\t\t\tgoto redo_character;\n-\n-\t\tcase LEJP_MP_VALUE_NUM_EXP:\n-\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_NUM_INT;\n-\t\t\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')\n-\t\t\t\tgoto redo_character;\n-\t\t\tif (c \u003d\u003d '+' || c \u003d\u003d '-')\n-\t\t\t\tgoto append_npos;\n-\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP;\n-\t\t\tgoto reject;\n-\n-\t\tcase LEJP_MP_VALUE_TOK: /* true, false, null */\n-\t\t\tif (c !\u003d tokens[ctx-\u003euni]) {\n-\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_TOK_UNKNOWN;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\t\t\tctx-\u003euni++;\n-\t\t\tif (tokens[ctx-\u003euni] !\u003d ' ')\n-\t\t\t\tbreak;\n-\t\t\tswitch (ctx-\u003euni) {\n-\t\t\tcase 3:\n-\t\t\t\tctx-\u003ebuf[0] \u003d '1';\n-\t\t\t\tctx-\u003ebuf[1] \u003d '\u005c0';\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_TRUE)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\tcase 8:\n-\t\t\t\tctx-\u003ebuf[0] \u003d '0';\n-\t\t\t\tctx-\u003ebuf[1] \u003d '\u005c0';\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_FALSE)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\tcase 12:\n-\t\t\t\tctx-\u003ebuf[0] \u003d '\u005c0';\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_NULL)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n-\t\t\tbreak;\n-\n-\t\tcase LEJP_MP_COMMA_OR_END:\n-\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n-\t\t\tif (c \u003d\u003d ',') {\n-\t\t\t\t/* increment this stack level's index */\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_M_P;\n-\t\t\t\tif (!ctx-\u003esp) {\n-\t\t\t\t\tctx-\u003eppos \u003d 0;\n-\t\t\t\t\t/*\n-\t\t\t\t\t * since we came back to root level,\n-\t\t\t\t\t * no path can still match\n-\t\t\t\t\t */\n-\t\t\t\t\tctx-\u003epath_match \u003d 0;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\tctx-\u003eppos \u003d ctx-\u003est[ctx-\u003esp - 1].p;\n-\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n-\t\t\t\tif (ctx-\u003epath_match \u0026\u0026\n-\t\t\t\t\t ctx-\u003eppos \u003c\u003d ctx-\u003epath_match_len)\n-\t\t\t\t\t/*\n-\t\t\t\t\t * we shrank the path to be\n-\t\t\t\t\t * smaller than the matching point\n-\t\t\t\t\t */\n-\t\t\t\t\tctx-\u003epath_match \u003d 0;\n-\n-\t\t\t\tif (ctx-\u003est[ctx-\u003esp - 1].s !\u003d LEJP_MP_ARRAY_END)\n-\t\t\t\t\tbreak;\n-\t\t\t\t/* top level is definitely an array... */\n-\t\t\t\tif (ctx-\u003eipos)\n-\t\t\t\t\tctx-\u003ei[ctx-\u003eipos - 1]++;\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (c \u003d\u003d ']') {\n-\t\t\t\tif (!ctx-\u003esp) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_MP_C_OR_E_UNDERF;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\t/* pop */\n-\t\t\t\tctx-\u003esp--;\n-\t\t\t\tif (ctx-\u003est[ctx-\u003esp].s !\u003d LEJP_MP_ARRAY_END) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_MP_C_OR_E_NOTARRAY;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\t/* drop the path [n] bit */\n-\t\t\t\tctx-\u003eppos \u003d ctx-\u003est[ctx-\u003esp - 1].p;\n-\t\t\t\tctx-\u003eipos \u003d ctx-\u003est[ctx-\u003esp - 1].i;\n-\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n-\t\t\t\tif (ctx-\u003epath_match \u0026\u0026\n-\t\t\t\t\t ctx-\u003eppos \u003c\u003d ctx-\u003epath_match_len)\n-\t\t\t\t\t/*\n-\t\t\t\t\t * we shrank the path to be\n-\t\t\t\t\t * smaller than the matching point\n-\t\t\t\t\t */\n-\t\t\t\t\tctx-\u003epath_match \u003d 0;\n-\n-\t\t\t\t/* do LEJP_MP_ARRAY_END processing */\n-\t\t\t\tgoto redo_character;\n-\t\t\t}\n-\t\t\tif (c \u003d\u003d '}') {\n-\t\t\t\tif (ctx-\u003esp \u003d\u003d 0) {\n-\t\t\t\t\tlejp_check_path_match(ctx);\n-\t\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_OBJECT_END)) {\n-\t\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\t\tgoto reject;\n-\t\t\t\t\t}\n-\t\t\t\t\tctx-\u003ecallback(ctx, LEJPCB_COMPLETE);\n-\t\t\t\t\t/* done, return unused amount */\n-\t\t\t\t\treturn len;\n-\t\t\t\t}\n-\t\t\t\t/* pop */\n-\t\t\t\tctx-\u003esp--;\n-\t\t\t\tctx-\u003eppos \u003d ctx-\u003est[ctx-\u003esp - 1].p;\n-\t\t\t\tctx-\u003eipos \u003d ctx-\u003est[ctx-\u003esp - 1].i;\n-\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n-\t\t\t\tif (ctx-\u003epath_match \u0026\u0026\n-\t\t\t\t\t ctx-\u003eppos \u003c\u003d ctx-\u003epath_match_len)\n-\t\t\t\t\t/*\n-\t\t\t\t\t * we shrank the path to be\n-\t\t\t\t\t * smaller than the matching point\n-\t\t\t\t\t */\n-\t\t\t\t\tctx-\u003epath_match \u003d 0;\n-\t\t\t\tlejp_check_path_match(ctx);\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_OBJECT_END)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\t\tret \u003d LEJP_REJECT_MP_C_OR_E_NEITHER;\n-\t\t\tgoto reject;\n-\n-\t\tcase LEJP_MP_ARRAY_END:\n-\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n-\t\t\tif (c \u003d\u003d ',') {\n-\t\t\t\t/* increment this stack level's index */\n-\t\t\t\tif (ctx-\u003eipos)\n-\t\t\t\t\tctx-\u003ei[ctx-\u003eipos - 1]++;\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE;\n-\t\t\t\tif (ctx-\u003esp)\n-\t\t\t\t\tctx-\u003eppos \u003d ctx-\u003est[ctx-\u003esp - 1].p;\n-\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (c !\u003d ']') {\n-\t\t\t\tret \u003d LEJP_REJECT_MP_ARRAY_END_MISSING;\n-\t\t\t\tgoto reject;\n-\t\t\t}\n-\n-\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n-\t\t\tctx-\u003ecallback(ctx, LEJPCB_ARRAY_END);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tcontinue;\n-\n-emit_string_char:\n-\t\tif (!ctx-\u003esp || ctx-\u003est[ctx-\u003esp - 1].s !\u003d LEJP_MP_DELIM) {\n-\t\t\t/* assemble the string value into chunks */\n-\t\t\tctx-\u003ebuf[ctx-\u003enpos++] \u003d c;\n-\t\t\tif (ctx-\u003enpos \u003d\u003d sizeof(ctx-\u003ebuf) - 1) {\n-\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_STR_CHUNK)) {\n-\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n-\t\t\t\t\tgoto reject;\n-\t\t\t\t}\n-\t\t\t\tctx-\u003enpos \u003d 0;\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t}\n-\t\t/* name part of name:value pair */\n-\t\tctx-\u003epath[ctx-\u003eppos++] \u003d c;\n-\t\tcontinue;\n-\n-add_stack_level:\n-\t\t/* push on to the object stack */\n-\t\tif (ctx-\u003eppos \u0026\u0026 ctx-\u003est[ctx-\u003esp].s !\u003d LEJP_MP_COMMA_OR_END \u0026\u0026\n-\t\t\t\tctx-\u003est[ctx-\u003esp].s !\u003d LEJP_MP_ARRAY_END)\n-\t\t\tctx-\u003epath[ctx-\u003eppos++] \u003d '.';\n-\n-\t\tctx-\u003est[ctx-\u003esp].p \u003d ctx-\u003eppos;\n-\t\tctx-\u003est[ctx-\u003esp].i \u003d ctx-\u003eipos;\n-\t\tif (++ctx-\u003esp \u003d\u003d ARRAY_SIZE(ctx-\u003est)) {\n-\t\t\tret \u003d LEJP_REJECT_STACK_OVERFLOW;\n-\t\t\tgoto reject;\n-\t\t}\n-\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n-\t\tctx-\u003est[ctx-\u003esp].s \u003d c;\n-\t\tctx-\u003est[ctx-\u003esp].b \u003d 0;\n-\t\tcontinue;\n-\n-append_npos:\n-\t\tif (ctx-\u003enpos \u003e\u003d sizeof(ctx-\u003ebuf)) {\n-\t\t\tret \u003d LEJP_REJECT_NUM_TOO_LONG;\n-\t\t\tgoto reject;\n-\t\t}\n-\t\tctx-\u003ebuf[ctx-\u003enpos++] \u003d c;\n-\t\tcontinue;\n-\n-redo_character:\n-\t\tjson--;\n-\t\tlen++;\n-\t}\n-\n-\treturn LEJP_CONTINUE;\n-\n-reject:\n-\tctx-\u003ecallback(ctx, LEJPCB_FAILED);\n-\treturn ret;\n-}\ndiff --git a/lib/lejp.h b/lib/lejp.h\ndeleted file mode 100644\nindex 7bf7ba7..0000000\n--- a/lib/lejp.h\n+++ /dev/null\n@@ -1,232 +0,0 @@\n-#include \u0022libwebsockets.h\u0022\n-struct lejp_ctx;\n-\n-#ifndef ARRAY_SIZE\n-#define ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0]))\n-#endif\n-#define LEJP_FLAG_WS_KEEP 64\n-#define LEJP_FLAG_WS_COMMENTLINE 32\n-\n-enum lejp_states {\n-\tLEJP_IDLE \u003d 0,\n-\tLEJP_MEMBERS \u003d 1,\n-\tLEJP_M_P \u003d 2,\n-\tLEJP_MP_STRING \u003d LEJP_FLAG_WS_KEEP | 3,\n-\tLEJP_MP_STRING_ESC \u003d LEJP_FLAG_WS_KEEP | 4,\n-\tLEJP_MP_STRING_ESC_U1 \u003d LEJP_FLAG_WS_KEEP | 5,\n-\tLEJP_MP_STRING_ESC_U2 \u003d LEJP_FLAG_WS_KEEP | 6,\n-\tLEJP_MP_STRING_ESC_U3 \u003d LEJP_FLAG_WS_KEEP | 7,\n-\tLEJP_MP_STRING_ESC_U4 \u003d LEJP_FLAG_WS_KEEP | 8,\n-\tLEJP_MP_DELIM \u003d 9,\n-\tLEJP_MP_VALUE \u003d 10,\n-\tLEJP_MP_VALUE_NUM_INT \u003d LEJP_FLAG_WS_KEEP | 11,\n-\tLEJP_MP_VALUE_NUM_EXP \u003d LEJP_FLAG_WS_KEEP | 12,\n-\tLEJP_MP_VALUE_TOK \u003d LEJP_FLAG_WS_KEEP | 13,\n-\tLEJP_MP_COMMA_OR_END \u003d 14,\n-\tLEJP_MP_ARRAY_END \u003d 15,\n-};\n-\n-enum lejp_reasons {\n-\tLEJP_CONTINUE \u003d -1,\n-\tLEJP_REJECT_IDLE_NO_BRACE \u003d -2,\n-\tLEJP_REJECT_MEMBERS_NO_CLOSE \u003d -3,\n-\tLEJP_REJECT_MP_NO_OPEN_QUOTE \u003d -4,\n-\tLEJP_REJECT_MP_STRING_UNDERRUN \u003d -5,\n-\tLEJP_REJECT_MP_ILLEGAL_CTRL \u003d -6,\n-\tLEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC \u003d -7,\n-\tLEJP_REJECT_ILLEGAL_HEX \u003d -8,\n-\tLEJP_REJECT_MP_DELIM_MISSING_COLON \u003d -9,\n-\tLEJP_REJECT_MP_DELIM_BAD_VALUE_START \u003d -10,\n-\tLEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC \u003d -11,\n-\tLEJP_REJECT_MP_VAL_NUM_FORMAT \u003d -12,\n-\tLEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP \u003d -13,\n-\tLEJP_REJECT_MP_VAL_TOK_UNKNOWN \u003d -14,\n-\tLEJP_REJECT_MP_C_OR_E_UNDERF \u003d -15,\n-\tLEJP_REJECT_MP_C_OR_E_NOTARRAY \u003d -16,\n-\tLEJP_REJECT_MP_ARRAY_END_MISSING \u003d -17,\n-\tLEJP_REJECT_STACK_OVERFLOW \u003d -18,\n-\tLEJP_REJECT_MP_DELIM_ISTACK \u003d -19,\n-\tLEJP_REJECT_NUM_TOO_LONG \u003d -20,\n-\tLEJP_REJECT_MP_C_OR_E_NEITHER \u003d -21,\n-\tLEJP_REJECT_UNKNOWN \u003d -22,\n-\tLEJP_REJECT_CALLBACK \u003d -23\n-};\n-\n-#define LEJP_FLAG_CB_IS_VALUE 64\n-\n-enum lejp_callbacks {\n-\tLEJPCB_CONSTRUCTED\t\u003d 0,\n-\tLEJPCB_DESTRUCTED\t\u003d 1,\n-\n-\tLEJPCB_START\t\t\u003d 2,\n-\tLEJPCB_COMPLETE\t\t\u003d 3,\n-\tLEJPCB_FAILED\t\t\u003d 4,\n-\n-\tLEJPCB_PAIR_NAME\t\u003d 5,\n-\n-\tLEJPCB_VAL_TRUE\t\t\u003d LEJP_FLAG_CB_IS_VALUE | 6,\n-\tLEJPCB_VAL_FALSE\t\u003d LEJP_FLAG_CB_IS_VALUE | 7,\n-\tLEJPCB_VAL_NULL\t\t\u003d LEJP_FLAG_CB_IS_VALUE | 8,\n-\tLEJPCB_VAL_NUM_INT\t\u003d LEJP_FLAG_CB_IS_VALUE | 9,\n-\tLEJPCB_VAL_NUM_FLOAT\t\u003d LEJP_FLAG_CB_IS_VALUE | 10,\n-\tLEJPCB_VAL_STR_START\t\u003d 11, /* notice handle separately */\n-\tLEJPCB_VAL_STR_CHUNK\t\u003d LEJP_FLAG_CB_IS_VALUE | 12,\n-\tLEJPCB_VAL_STR_END\t\u003d LEJP_FLAG_CB_IS_VALUE | 13,\n-\n-\tLEJPCB_ARRAY_START\t\u003d 14,\n-\tLEJPCB_ARRAY_END\t\u003d 15,\n-\n-\tLEJPCB_OBJECT_START\t\u003d 16,\n-\tLEJPCB_OBJECT_END\t\u003d 17\n-};\n-\n-/**\n- * _lejp_callback() - User parser actions\n- * \u005cparam ctx:\tLEJP context\n- * \u005cparam reason:\tCallback reason\n- *\n- *\tYour user callback is associated with the context at construction time,\n- *\tand receives calls as the parsing progresses.\n- *\n- *\tAll of the callbacks may be ignored and just return 0.\n- *\n- *\tThe reasons it might get called, found in @reason, are:\n- *\n- * LEJPCB_CONSTRUCTED: The context was just constructed... you might want to\n- *\t\tperform one-time allocation for the life of the context.\n- *\n- * LEJPCB_DESTRUCTED:\tThe context is being destructed... if you made any\n- *\t\tallocations at construction-time, you can free them now\n- *\n- * LEJPCB_START:\tParsing is beginning at the first byte of input\n- *\n- * LEJPCB_COMPLETE:\tParsing has completed successfully. You'll get a 0 or\n- *\t\t\tpositive return code from lejp_parse indicating the\n- *\t\t\tamount of unused bytes left in the input buffer\n- *\n- * LEJPCB_FAILED:\tParsing failed. You'll get a negative error code\n- * \t\t\treturned from lejp_parse\n- *\n- * LEJPCB_PAIR_NAME:\tWhen a \u0022name\u0022:\u0022value\u0022 pair has had the name parsed,\n- *\t\t\tthis callback occurs. You can find the new name at\n- *\t\t\tthe end of ctx-\u003epath[]\n- *\n- * LEJPCB_VAL_TRUE:\tThe \u0022true\u0022 value appeared\n- *\n- * LEJPCB_VAL_FALSE:\tThe \u0022false\u0022 value appeared\n- *\n- * LEJPCB_VAL_NULL:\tThe \u0022null\u0022 value appeared\n- *\n- * LEJPCB_VAL_NUM_INT:\tA string representing an integer is in ctx-\u003ebuf\n- *\n- * LEJPCB_VAL_NUM_FLOAT: A string representing a float is in ctx-\u003ebuf\n- *\n- * LEJPCB_VAL_STR_START: We are starting to parse a string, no data yet\n- *\n- * LEJPCB_VAL_STR_CHUNK: We parsed LEJP_STRING_CHUNK -1 bytes of string data in\n- *\t\t\tctx-\u003ebuf, which is as much as we can buffer, so we are\n- *\t\t\tspilling it. If all your strings are less than\n- *\t\t\tLEJP_STRING_CHUNK - 1 bytes, you will never see this\n- *\t\t\tcallback.\n- *\n- * LEJPCB_VAL_STR_END:\tString parsing has completed, the last chunk of the\n- *\t\t\tstring is in ctx-\u003ebuf.\n- *\n- * LEJPCB_ARRAY_START:\tAn array started\n- *\n- * LEJPCB_ARRAY_END:\tAn array ended\n- *\n- * LEJPCB_OBJECT_START: An object started\n- *\n- * LEJPCB_OBJECT_END:\tAn object ended\n- */\n-LWS_EXTERN char _lejp_callback(struct lejp_ctx *ctx, char reason);\n-\n-typedef char (*lejp_callback)(struct lejp_ctx *ctx, char reason);\n-\n-#ifndef LEJP_MAX_DEPTH\n-#define LEJP_MAX_DEPTH 12\n-#endif\n-#ifndef LEJP_MAX_INDEX_DEPTH\n-#define LEJP_MAX_INDEX_DEPTH 5\n-#endif\n-#ifndef LEJP_MAX_PATH\n-#define LEJP_MAX_PATH 128\n-#endif\n-#ifndef LEJP_STRING_CHUNK\n-/* must be \u003e\u003d 30 to assemble floats */\n-#define LEJP_STRING_CHUNK 255\n-#endif\n-\n-enum num_flags {\n-\tLEJP_SEEN_MINUS \u003d (1 \u003c\u003c 0),\n-\tLEJP_SEEN_POINT \u003d (1 \u003c\u003c 1),\n-\tLEJP_SEEN_POST_POINT \u003d (1 \u003c\u003c 2),\n-\tLEJP_SEEN_EXP \u003d (1 \u003c\u003c 3)\n-};\n-\n-struct _lejp_stack {\n-\tchar s; /* lejp_state stack*/\n-\tchar p;\t/* path length */\n-\tchar i; /* index array length */\n-\tchar b; /* user bitfield */\n-};\n-\n-struct lejp_ctx {\n-\n-\t/* sorted by type for most compact alignment\n-\t *\n-\t * pointers\n-\t */\n-\n-\tchar (*callback)(struct lejp_ctx *ctx, char reason);\n-\tvoid *user;\n-\tconst char * const *paths;\n-\n-\t/* arrays */\n-\n-\tstruct _lejp_stack st[LEJP_MAX_DEPTH];\n-\tunsigned short i[LEJP_MAX_INDEX_DEPTH]; /* index array */\n-\tunsigned short wild[LEJP_MAX_INDEX_DEPTH]; /* index array */\n-\tchar path[LEJP_MAX_PATH];\n-\tchar buf[LEJP_STRING_CHUNK];\n-\n-\t/* int */\n-\n-\tunsigned int line;\n-\n-\t/* short */\n-\n-\tunsigned short uni;\n-\n-\t/* char */\n-\n-\tunsigned char npos;\n-\tunsigned char dcount;\n-\tunsigned char f;\n-\tunsigned char sp; /* stack head */\n-\tunsigned char ipos; /* index stack depth */\n-\tunsigned char ppos;\n-\tunsigned char count_paths;\n-\tunsigned char path_match;\n-\tunsigned char path_match_len;\n-\tunsigned char wildcount;\n-};\n-\n-LWS_VISIBLE LWS_EXTERN void\n-lejp_construct(struct lejp_ctx *ctx,\n-\t char (*callback)(struct lejp_ctx *ctx, char reason), void *user,\n-\t const char * const *paths, unsigned char paths_count);\n-\n-LWS_VISIBLE LWS_EXTERN void\n-lejp_destruct(struct lejp_ctx *ctx);\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len);\n-\n-LWS_VISIBLE LWS_EXTERN void\n-lejp_change_callback(struct lejp_ctx *ctx,\n-\t\t char (*callback)(struct lejp_ctx *ctx, char reason));\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len);\ndiff --git a/lib/libev.c b/lib/libev.c\ndeleted file mode 100644\nindex 2410488..0000000\n--- a/lib/libev.c\n+++ /dev/null\n@@ -1,236 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-void lws_feature_status_libev(struct lws_context_creation_info *info)\n-{\n-\tif (lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_LIBEV))\n-\t\tlwsl_info(\u0022libev support compiled in and enabled\u005cn\u0022);\n-\telse\n-\t\tlwsl_info(\u0022libev support compiled in but disabled\u005cn\u0022);\n-}\n-\n-static void\n-lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)\n-{\n-\tstruct lws_io_watcher *lws_io \u003d lws_container_of(watcher,\n-\t\t\t\t\tstruct lws_io_watcher, ev_watcher);\n-\tstruct lws_context *context \u003d lws_io-\u003econtext;\n-\tstruct lws_pollfd eventfd;\n-\n-\tif (revents \u0026 EV_ERROR)\n-\t\treturn;\n-\n-\teventfd.fd \u003d watcher-\u003efd;\n-\teventfd.events \u003d 0;\n-\teventfd.revents \u003d EV_NONE;\n-\n-\tif (revents \u0026 EV_READ) {\n-\t\teventfd.events |\u003d LWS_POLLIN;\n-\t\teventfd.revents |\u003d LWS_POLLIN;\n-\t}\n-\tif (revents \u0026 EV_WRITE) {\n-\t\teventfd.events |\u003d LWS_POLLOUT;\n-\t\teventfd.revents |\u003d LWS_POLLOUT;\n-\t}\n-\n-\tlws_service_fd(context, \u0026eventfd);\n-}\n-\n-LWS_VISIBLE void\n-lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)\n-{\n-\tev_break(loop, EVBREAK_ALL);\n-}\n-\n-LWS_VISIBLE int\n-lws_ev_sigint_cfg(struct lws_context *context, int use_ev_sigint,\n-\t\t lws_ev_signal_cb_t *cb)\n-{\n-\tcontext-\u003euse_ev_sigint \u003d use_ev_sigint;\n-\tif (cb)\n-\t\tcontext-\u003elws_ev_sigint_cb \u003d cb;\n-\telse\n-\t\tcontext-\u003elws_ev_sigint_cb \u003d \u0026lws_ev_sigint_cb;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)\n-{\n-\tstruct ev_signal *w_sigint \u003d \u0026context-\u003ept[tsi].w_sigint.ev_watcher;\n-\tstruct ev_io *w_accept \u003d \u0026context-\u003ept[tsi].w_accept.ev_watcher;\n-\tstruct lws_vhost *vh \u003d context-\u003evhost_list;\n-\tconst char *backend_name;\n-\tint status \u003d 0;\n-\tint backend;\n-\n-\tif (!loop)\n-\t\tloop \u003d ev_loop_new(0);\n-\telse\n-\t\tcontext-\u003ept[tsi].ev_loop_foreign \u003d 1;\n-\n-\tcontext-\u003ept[tsi].io_loop_ev \u003d loop;\n-\n-\t/*\n-\t * Initialize the accept w_accept with all the listening sockets\n-\t * and register a callback for read operations\n-\t */\n-\twhile (vh) {\n-\t\tif (vh-\u003elserv_wsi) {\n-\t\t\tvh-\u003elserv_wsi-\u003ew_read.context \u003d context;\n-\t\t\tev_io_init(w_accept, lws_accept_cb,\n-\t\t\t\t vh-\u003elserv_wsi-\u003edesc.sockfd, EV_READ);\n-\t\t}\n-\t\tvh \u003d vh-\u003evhost_next;\n-\t}\n-\tev_io_start(context-\u003ept[tsi].io_loop_ev, w_accept);\n-\n-\t/* Register the signal watcher unless the user says not to */\n-\tif (context-\u003euse_ev_sigint) {\n-\t\tev_signal_init(w_sigint, context-\u003elws_ev_sigint_cb, SIGINT);\n-\t\tev_signal_start(context-\u003ept[tsi].io_loop_ev, w_sigint);\n-\t}\n-\tbackend \u003d ev_backend(loop);\n-\n-\tswitch (backend) {\n-\tcase EVBACKEND_SELECT:\n-\t\tbackend_name \u003d \u0022select\u0022;\n-\t\tbreak;\n-\tcase EVBACKEND_POLL:\n-\t\tbackend_name \u003d \u0022poll\u0022;\n-\t\tbreak;\n-\tcase EVBACKEND_EPOLL:\n-\t\tbackend_name \u003d \u0022epoll\u0022;\n-\t\tbreak;\n-\tcase EVBACKEND_KQUEUE:\n-\t\tbackend_name \u003d \u0022kqueue\u0022;\n-\t\tbreak;\n-\tcase EVBACKEND_DEVPOLL:\n-\t\tbackend_name \u003d \u0022/dev/poll\u0022;\n-\t\tbreak;\n-\tcase EVBACKEND_PORT:\n-\t\tbackend_name \u003d \u0022Solaris 10 \u005c\u0022port\u005c\u0022\u0022;\n-\t\tbreak;\n-\tdefault:\n-\t\tbackend_name \u003d \u0022Unknown libev backend\u0022;\n-\t\tbreak;\n-\t}\n-\n-\tlwsl_info(\u0022 libev backend: %s\u005cn\u0022, backend_name);\n-\t(void)backend_name;\n-\n-\treturn status;\n-}\n-\n-void\n-lws_libev_destroyloop(struct lws_context *context, int tsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n-\n-\tif (!lws_check_opt(context-\u003eoptions, LWS_SERVER_OPTION_LIBEV))\n-\t\treturn;\n-\n-\tif (!pt-\u003eio_loop_ev)\n-\t\treturn;\n-\n-\tev_io_stop(pt-\u003eio_loop_ev, \u0026pt-\u003ew_accept.ev_watcher);\n-\tif (context-\u003euse_ev_sigint)\n-\t\tev_signal_stop(pt-\u003eio_loop_ev,\n-\t\t \u0026pt-\u003ew_sigint.ev_watcher);\n-\tif (!pt-\u003eev_loop_foreign)\n-\t\tev_loop_destroy(pt-\u003eio_loop_ev);\n-}\n-\n-LWS_VISIBLE void\n-lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)\n-{\n-\tstruct lws_context *context \u003d lws_get_context(new_wsi);\n-\tstruct ev_io *r \u003d \u0026new_wsi-\u003ew_read.ev_watcher;\n-\tstruct ev_io *w \u003d \u0026new_wsi-\u003ew_write.ev_watcher;\n-\tint fd;\n-\n-\tif (!LWS_LIBEV_ENABLED(context))\n-\t\treturn;\n-\n-\tif (new_wsi-\u003emode \u003d\u003d LWSCM_RAW_FILEDESC)\n-\t\tfd \u003d desc.filefd;\n-\telse\n-\t\tfd \u003d desc.sockfd;\n-\n-\tnew_wsi-\u003ew_read.context \u003d context;\n-\tnew_wsi-\u003ew_write.context \u003d context;\n-\tev_io_init(r, lws_accept_cb, fd, EV_READ);\n-\tev_io_init(w, lws_accept_cb, fd, EV_WRITE);\n-}\n-\n-LWS_VISIBLE void\n-lws_libev_io(struct lws *wsi, int flags)\n-{\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\n-\tif (!LWS_LIBEV_ENABLED(context))\n-\t\treturn;\n-\n-\tif (!pt-\u003eio_loop_ev)\n-\t\treturn;\n-\n-\tassert((flags \u0026 (LWS_EV_START | LWS_EV_STOP)) \u0026\u0026\n-\t (flags \u0026 (LWS_EV_READ | LWS_EV_WRITE)));\n-\n-\tif (flags \u0026 LWS_EV_START) {\n-\t\tif (flags \u0026 LWS_EV_WRITE)\n-\t\t\tev_io_start(pt-\u003eio_loop_ev, \u0026wsi-\u003ew_write.ev_watcher);\n-\t\tif (flags \u0026 LWS_EV_READ)\n-\t\t\tev_io_start(pt-\u003eio_loop_ev, \u0026wsi-\u003ew_read.ev_watcher);\n-\t} else {\n-\t\tif (flags \u0026 LWS_EV_WRITE)\n-\t\t\tev_io_stop(pt-\u003eio_loop_ev, \u0026wsi-\u003ew_write.ev_watcher);\n-\t\tif (flags \u0026 LWS_EV_READ)\n-\t\t\tev_io_stop(pt-\u003eio_loop_ev, \u0026wsi-\u003ew_read.ev_watcher);\n-\t}\n-}\n-\n-LWS_VISIBLE int\n-lws_libev_init_fd_table(struct lws_context *context)\n-{\n-\tint n;\n-\n-\tif (!LWS_LIBEV_ENABLED(context))\n-\t\treturn 0;\n-\n-\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++) {\n-\t\tcontext-\u003ept[n].w_accept.context \u003d context;\n-\t\tcontext-\u003ept[n].w_sigint.context \u003d context;\n-\t}\n-\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE void\n-lws_libev_run(const struct lws_context *context, int tsi)\n-{\n-\tif (context-\u003ept[tsi].io_loop_ev \u0026\u0026 LWS_LIBEV_ENABLED(context))\n-\t\tev_run(context-\u003ept[tsi].io_loop_ev, 0);\n-}\ndiff --git a/lib/libevent.c b/lib/libevent.c\ndeleted file mode 100644\nindex 08b5a8d..0000000\n--- a/lib/libevent.c\n+++ /dev/null\n@@ -1,235 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-void lws_feature_status_libevent(struct lws_context_creation_info *info)\n-{\n-\tif (lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_LIBEVENT))\n-\t\tlwsl_info(\u0022libevent support compiled in and enabled\u005cn\u0022);\n-\telse\n-\t\tlwsl_info(\u0022libevent support compiled in but disabled\u005cn\u0022);\n-}\n-\n-static void\n-lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx)\n-{\n-\tstruct lws_io_watcher *lws_io \u003d (struct lws_io_watcher *)ctx;\n-\tstruct lws_context *context \u003d lws_io-\u003econtext;\n-\tstruct lws_pollfd eventfd;\n-\n-\tif (revents \u0026 EV_TIMEOUT)\n-\t\treturn;\n-\n-\t/* !!! EV_CLOSED doesn't exist in libevent2 */\n-\t#if LIBEVENT_VERSION_NUMBER \u003c 0x02000000\n-\tif (revents \u0026 EV_CLOSED) {\n-\t\tevent_del(lws_io-\u003eevent_watcher);\n-\t\tevent_free(lws_io-\u003eevent_watcher);\n-\t\treturn;\n-\t}\n-\t#endif\n-\n-\teventfd.fd \u003d sock_fd;\n-\teventfd.events \u003d 0;\n-\teventfd.revents \u003d 0;\n-\tif (revents \u0026 EV_READ) {\n-\t\teventfd.events |\u003d LWS_POLLIN;\n-\t\teventfd.revents |\u003d LWS_POLLIN;\n-\t}\n-\tif (revents \u0026 EV_WRITE) {\n-\t\teventfd.events |\u003d LWS_POLLOUT;\n-\t\teventfd.revents |\u003d LWS_POLLOUT;\n-\t}\n-\n-\tlws_service_fd(context, \u0026eventfd);\n-}\n-\n-LWS_VISIBLE void\n-lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx)\n-{\n-\tstruct lws_context_per_thread *pt \u003d ctx;\n-\n-\tif (!pt-\u003eev_loop_foreign)\n-\t\tevent_base_loopbreak(pt-\u003eio_loop_event_base);\n-}\n-\n-LWS_VISIBLE int\n-lws_event_sigint_cfg(struct lws_context *context, int use_event_sigint,\n-lws_event_signal_cb_t *cb)\n-{\n-\tcontext-\u003euse_ev_sigint \u003d use_event_sigint;\n-\tif (cb)\n-\t\tcontext-\u003elws_event_sigint_cb \u003d cb;\n-\telse\n-\t\tcontext-\u003elws_event_sigint_cb \u003d \u0026lws_event_sigint_cb;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_event_initloop(struct lws_context *context, struct event_base *loop,\n-int tsi)\n-{\n-\tstruct lws_vhost *vh \u003d context-\u003evhost_list;\n-\n-\tif (!loop)\n-\t\tcontext-\u003ept[tsi].io_loop_event_base \u003d event_base_new();\n-\telse {\n-\t\tcontext-\u003ept[tsi].ev_loop_foreign \u003d 1;\n-\t\tcontext-\u003ept[tsi].io_loop_event_base \u003d loop;\n-\t}\n-\n-\t/*\n-\t* Initialize all events with the listening sockets\n-\t* and register a callback for read operations\n-\t*/\n-\n-\twhile (vh) {\n-\t\tif (vh-\u003elserv_wsi) {\n-\t\t\tvh-\u003elserv_wsi-\u003ew_read.context \u003d context;\n-\t\t\tvh-\u003elserv_wsi-\u003ew_read.event_watcher \u003d event_new(\n-\t\t\t\t\tloop, vh-\u003elserv_wsi-\u003edesc.sockfd,\n-\t\t\t\t\t(EV_READ | EV_PERSIST), lws_event_cb,\n-\t\t\t\t\t\u0026vh-\u003elserv_wsi-\u003ew_read);\n-\t\t\tevent_add(vh-\u003elserv_wsi-\u003ew_read.event_watcher, NULL);\n-\t\t}\n-\t\tvh \u003d vh-\u003evhost_next;\n-\t}\n-\n-\t/* Register the signal watcher unless the user says not to */\n-\tif (!context-\u003euse_ev_sigint)\n-\t\treturn 0;\n-\n-\tcontext-\u003ept[tsi].w_sigint.event_watcher \u003d evsignal_new(loop, SIGINT,\n-\t\t\tcontext-\u003elws_event_sigint_cb, \u0026context-\u003ept[tsi]);\n-\tevent_add(context-\u003ept[tsi].w_sigint.event_watcher, NULL);\n-\n-\treturn 0;\n-}\n-\n-void\n-lws_libevent_destroyloop(struct lws_context *context, int tsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n-\tstruct lws_vhost *vh \u003d context-\u003evhost_list;\n-\n-\tif (!lws_check_opt(context-\u003eoptions, LWS_SERVER_OPTION_LIBEVENT))\n-\t\treturn;\n-\n-\tif (!pt-\u003eio_loop_event_base)\n-\t\treturn;\n-\n-\t/*\n-\t * Free all events with the listening sockets\n-\t */\n-\twhile (vh) {\n-\t\tif (vh-\u003elserv_wsi) {\n-\t\t\tevent_free(vh-\u003elserv_wsi-\u003ew_read.event_watcher);\n-\t\t\tvh-\u003elserv_wsi-\u003ew_read.event_watcher \u003d NULL;\n-\t\t}\n-\t\tvh \u003d vh-\u003evhost_next;\n-\t}\n-\n-\tif (context-\u003euse_ev_sigint)\n-\t\tevent_free(pt-\u003ew_sigint.event_watcher);\n-\tif (!pt-\u003eev_loop_foreign)\n-\t\tevent_base_free(pt-\u003eio_loop_event_base);\n-}\n-\n-LWS_VISIBLE void\n-lws_libevent_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)\n-{\n-\tstruct lws_context *context \u003d lws_get_context(new_wsi);\n-\tstruct lws_context_per_thread *pt;\n-\tint fd;\n-\n-\tif (!LWS_LIBEVENT_ENABLED(context))\n-\t\treturn;\n-\n-\tnew_wsi-\u003ew_read.context \u003d context;\n-\tnew_wsi-\u003ew_write.context \u003d context;\n-\n-\t// Initialize the event\n-\tpt \u003d \u0026context-\u003ept[(int)new_wsi-\u003etsi];\n-\n-\tif (new_wsi-\u003emode \u003d\u003d LWSCM_RAW_FILEDESC)\n-\t\tfd \u003d desc.filefd;\n-\telse\n-\t\tfd \u003d desc.sockfd;\n-\n-\tnew_wsi-\u003ew_read.event_watcher \u003d event_new(pt-\u003eio_loop_event_base, fd,\n-\t\t(EV_READ | EV_PERSIST), lws_event_cb, \u0026new_wsi-\u003ew_read);\n-\tnew_wsi-\u003ew_write.event_watcher \u003d event_new(pt-\u003eio_loop_event_base, fd,\n-\t\t(EV_WRITE | EV_PERSIST), lws_event_cb, \u0026new_wsi-\u003ew_write);\n-}\n-\n-LWS_VISIBLE void\n-lws_libevent_io(struct lws *wsi, int flags)\n-{\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\n-\tif (!LWS_LIBEVENT_ENABLED(context))\n-\t\treturn;\n-\n-\tif (!pt-\u003eio_loop_event_base || context-\u003ebeing_destroyed)\n-\t\treturn;\n-\n-\tassert((flags \u0026 (LWS_EV_START | LWS_EV_STOP)) \u0026\u0026\n-\t (flags \u0026 (LWS_EV_READ | LWS_EV_WRITE)));\n-\n-\tif (flags \u0026 LWS_EV_START) {\n-\t\tif (flags \u0026 LWS_EV_WRITE)\n-\t\t\tevent_add(wsi-\u003ew_write.event_watcher, NULL);\n-\t\tif (flags \u0026 LWS_EV_READ)\n-\t\t\tevent_add(wsi-\u003ew_read.event_watcher, NULL);\n-\t} else {\n-\t\tif (flags \u0026 LWS_EV_WRITE)\n-\t\t\tevent_del(wsi-\u003ew_write.event_watcher);\n-\n-\t\tif (flags \u0026 LWS_EV_READ)\n-\t\t\tevent_del(wsi-\u003ew_read.event_watcher);\n-\t}\n-}\n-\n-LWS_VISIBLE int\n-lws_libevent_init_fd_table(struct lws_context *context)\n-{\n-\tint n;\n-\n-\tif (!LWS_LIBEVENT_ENABLED(context))\n-\t\treturn 0;\n-\n-\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++)\n-\t\tcontext-\u003ept[n].w_sigint.context \u003d context;\n-\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE void\n-lws_libevent_run(const struct lws_context *context, int tsi)\n-{\n-\t/* Run / Dispatch the event_base loop */\n-\tif (context-\u003ept[tsi].io_loop_event_base \u0026\u0026\n-\t LWS_LIBEVENT_ENABLED(context))\n-\t\tevent_base_dispatch(context-\u003ept[tsi].io_loop_event_base);\n-}\ndiff --git a/lib/libuv.c b/lib/libuv.c\ndeleted file mode 100644\nindex 28dd959..0000000\n--- a/lib/libuv.c\n+++ /dev/null\n@@ -1,706 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-void\n-lws_feature_status_libuv(struct lws_context_creation_info *info)\n-{\n-\tif (lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_LIBUV))\n-\t\tlwsl_info(\u0022libuv support compiled in and enabled\u005cn\u0022);\n-\telse\n-\t\tlwsl_info(\u0022libuv support compiled in but disabled\u005cn\u0022);\n-}\n-\n-static void\n-lws_uv_idle(uv_idle_t *handle\n-#if UV_VERSION_MAJOR \u003d\u003d 0\n-\t\t, int status\n-#endif\n-)\n-{\n-\tstruct lws_context_per_thread *pt \u003d lws_container_of(handle,\n-\t\t\t\t\tstruct lws_context_per_thread, uv_idle);\n-\n-\t/*\n-\t * is there anybody with pending stuff that needs service forcing?\n-\t */\n-\tif (!lws_service_adjust_timeout(pt-\u003econtext, 1, pt-\u003etid)) {\n-\t\t/* -1 timeout means just do forced service */\n-\t\t_lws_plat_service_tsi(pt-\u003econtext, -1, pt-\u003etid);\n-\t\t/* still somebody left who wants forced service? */\n-\t\tif (!lws_service_adjust_timeout(pt-\u003econtext, 1, pt-\u003etid))\n-\t\t\t/* yes... come back again later */\n-\t\treturn;\n-\t}\n-\n-\t/* there is nobody who needs service forcing, shut down idle */\n-\tuv_idle_stop(handle);\n-}\n-\n-static void\n-lws_io_cb(uv_poll_t *watcher, int status, int revents)\n-{\n-\tstruct lws_io_watcher *lws_io \u003d lws_container_of(watcher,\n-\t\t\t\t\tstruct lws_io_watcher, uv_watcher);\n-\tstruct lws *wsi \u003d lws_container_of(lws_io, struct lws, w_read);\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tstruct lws_pollfd eventfd;\n-\n-#if defined(WIN32) || defined(_WIN32)\n-\teventfd.fd \u003d watcher-\u003esocket;\n-#else\n-\teventfd.fd \u003d watcher-\u003eio_watcher.fd;\n-#endif\n-\teventfd.events \u003d 0;\n-\teventfd.revents \u003d 0;\n-\n-\tif (status \u003c 0) {\n-\t\t/*\n-\t\t * At this point status will be an UV error, like UV_EBADF,\n-\t\t * we treat all errors as LWS_POLLHUP\n-\t\t *\n-\t\t * You might want to return; instead of servicing the fd in\n-\t\t * some cases */\n-\t\tif (status \u003d\u003d UV_EAGAIN)\n-\t\t\treturn;\n-\n-\t\teventfd.events |\u003d LWS_POLLHUP;\n-\t\teventfd.revents |\u003d LWS_POLLHUP;\n-\t} else {\n-\t\tif (revents \u0026 UV_READABLE) {\n-\t\t\teventfd.events |\u003d LWS_POLLIN;\n-\t\t\teventfd.revents |\u003d LWS_POLLIN;\n-\t\t}\n-\t\tif (revents \u0026 UV_WRITABLE) {\n-\t\t\teventfd.events |\u003d LWS_POLLOUT;\n-\t\t\teventfd.revents |\u003d LWS_POLLOUT;\n-\t\t}\n-\t}\n-\tlws_service_fd(context, \u0026eventfd);\n-\n-\tuv_idle_start(\u0026context-\u003ept[(int)wsi-\u003etsi].uv_idle, lws_uv_idle);\n-}\n-\n-LWS_VISIBLE void\n-lws_uv_sigint_cb(uv_signal_t *watcher, int signum)\n-{\n-\tlwsl_err(\u0022internal signal handler caught signal %d\u005cn\u0022, signum);\n-\tlws_libuv_stop(watcher-\u003edata);\n-}\n-\n-LWS_VISIBLE int\n-lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,\n-\t\t uv_signal_cb cb)\n-{\n-\tcontext-\u003euse_ev_sigint \u003d use_uv_sigint;\n-\tif (cb)\n-\t\tcontext-\u003elws_uv_sigint_cb \u003d cb;\n-\telse\n-\t\tcontext-\u003elws_uv_sigint_cb \u003d \u0026lws_uv_sigint_cb;\n-\n-\treturn 0;\n-}\n-\n-static void\n-lws_uv_timeout_cb(uv_timer_t *timer\n-#if UV_VERSION_MAJOR \u003d\u003d 0\n-\t\t, int status\n-#endif\n-)\n-{\n-\tstruct lws_context_per_thread *pt \u003d lws_container_of(timer,\n-\t\t\tstruct lws_context_per_thread, uv_timeout_watcher);\n-\n-\tif (pt-\u003econtext-\u003erequested_kill)\n-\t\treturn;\n-\n-\tlwsl_debug(\u0022%s\u005cn\u0022, __func__);\n-\n-\tlws_service_fd_tsi(pt-\u003econtext, NULL, pt-\u003etid);\n-}\n-\n-static const int sigs[] \u003d { SIGINT, SIGTERM, SIGSEGV, SIGFPE, SIGHUP };\n-\n-int\n-lws_uv_initvhost(struct lws_vhost* vh, struct lws* wsi)\n-{\n-\tstruct lws_context_per_thread *pt;\n-\tint n;\n-\n-\tif (!LWS_LIBUV_ENABLED(vh-\u003econtext))\n-\t\treturn 0;\n-\tif (!wsi)\n-\t\twsi \u003d vh-\u003elserv_wsi;\n-\tif (!wsi)\n-\t\treturn 0;\n-\tif (wsi-\u003ew_read.context)\n-\t\treturn 0;\n-\n-\tpt \u003d \u0026vh-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tif (!pt-\u003eio_loop_uv)\n-\t\treturn 0;\n-\n-\twsi-\u003ew_read.context \u003d vh-\u003econtext;\n-\tn \u003d uv_poll_init_socket(pt-\u003eio_loop_uv,\n-\t\t\t\t\u0026wsi-\u003ew_read.uv_watcher, wsi-\u003edesc.sockfd);\n-\tif (n) {\n-\t\tlwsl_err(\u0022uv_poll_init failed %d, sockfd\u003d%p\u005cn\u0022,\n-\t\t\t\t n, (void *)(lws_intptr_t)wsi-\u003edesc.sockfd);\n-\n-\t\treturn -1;\n-\t}\n-\tlws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);\n-\n-\treturn 0;\n-}\n-\n-/*\n- * This needs to be called after vhosts have been defined.\n- *\n- * If later, after server start, another vhost is added, this must be\n- * called again to bind the vhost\n- */\n-\n-LWS_VISIBLE int\n-lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n-\tstruct lws_vhost *vh \u003d context-\u003evhost_list;\n-\tint status \u003d 0, n, ns, first \u003d 1;\n-\n-\tif (!pt-\u003eio_loop_uv) {\n-\t\tif (!loop) {\n-\t\t\tloop \u003d lws_malloc(sizeof(*loop), \u0022libuv loop\u0022);\n-\t\t\tif (!loop) {\n-\t\t\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t#if UV_VERSION_MAJOR \u003e 0\n-\t\t\tuv_loop_init(loop);\n-\t#else\n-\t\t\tlwsl_err(\u0022This libuv is too old to work...\u005cn\u0022);\n-\t\t\treturn 1;\n-\t#endif\n-\t\t\tpt-\u003eev_loop_foreign \u003d 0;\n-\t\t} else {\n-\t\t\tlwsl_notice(\u0022 Using foreign event loop...\u005cn\u0022);\n-\t\t\tpt-\u003eev_loop_foreign \u003d 1;\n-\t\t}\n-\n-\t\tpt-\u003eio_loop_uv \u003d loop;\n-\t\tuv_idle_init(loop, \u0026pt-\u003euv_idle);\n-\n-\t\tns \u003d ARRAY_SIZE(sigs);\n-\t\tif (lws_check_opt(context-\u003eoptions,\n-\t\t\t\t LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))\n-\t\t\tns \u003d 2;\n-\n-\t\tif (pt-\u003econtext-\u003euse_ev_sigint) {\n-\t\t\tassert(ns \u003c\u003d ARRAY_SIZE(pt-\u003esignals));\n-\t\t\tfor (n \u003d 0; n \u003c ns; n++) {\n-\t\t\t\tuv_signal_init(loop, \u0026pt-\u003esignals[n]);\n-\t\t\t\tpt-\u003esignals[n].data \u003d pt-\u003econtext;\n-\t\t\t\tuv_signal_start(\u0026pt-\u003esignals[n],\n-\t\t\t\t\t\tcontext-\u003elws_uv_sigint_cb,\n-\t\t\t\t\t\tsigs[n]);\n-\t\t\t}\n-\t\t}\n-\t} else\n-\t\tfirst \u003d 0;\n-\n-\t/*\n-\t * Initialize the accept wsi read watcher with all the listening sockets\n-\t * and register a callback for read operations\n-\t *\n-\t * We have to do it here because the uv loop(s) are not\n-\t * initialized until after context creation.\n-\t */\n-\twhile (vh) {\n-\t\tif (lws_uv_initvhost(vh, vh-\u003elserv_wsi) \u003d\u003d -1)\n-\t\t\treturn -1;\n-\t\tvh \u003d vh-\u003evhost_next;\n-\t}\n-\n-\tif (first) {\n-\t\tuv_timer_init(pt-\u003eio_loop_uv, \u0026pt-\u003euv_timeout_watcher);\n-\t\tuv_timer_start(\u0026pt-\u003euv_timeout_watcher, lws_uv_timeout_cb,\n-\t\t\t 10, 1000);\n-\t}\n-\n-\treturn status;\n-}\n-\n-static void lws_uv_close_cb(uv_handle_t *handle)\n-{\n-}\n-\n-static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)\n-{\n-\tif (!uv_is_closing(handle))\n-\t\tuv_close(handle, lws_uv_close_cb);\n-}\n-\n-LWS_VISIBLE void\n-lws_close_all_handles_in_loop(uv_loop_t *loop)\n-{\n-\tuv_walk(loop, lws_uv_walk_cb, NULL);\n-}\n-\n-void\n-lws_libuv_destroyloop(struct lws_context *context, int tsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n-\tint m, budget \u003d 100, ns;\n-\n-\tif (!lws_check_opt(context-\u003eoptions, LWS_SERVER_OPTION_LIBUV))\n-\t\treturn;\n-\n-\tif (!pt-\u003eio_loop_uv)\n-\t\treturn;\n-\n-\tif (context-\u003euse_ev_sigint) {\n-\t\tuv_signal_stop(\u0026pt-\u003ew_sigint.uv_watcher);\n-\n-\t\tns \u003d ARRAY_SIZE(sigs);\n-\t\tif (lws_check_opt(context-\u003eoptions,\n-\t\t\t\t LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))\n-\t\t\tns \u003d 2;\n-\n-\t\tfor (m \u003d 0; m \u003c ns; m++) {\n-\t\t\tuv_signal_stop(\u0026pt-\u003esignals[m]);\n-\t\t\tuv_close((uv_handle_t *)\u0026pt-\u003esignals[m], lws_uv_close_cb);\n-\t\t}\n-\t}\n-\n-\tuv_timer_stop(\u0026pt-\u003euv_timeout_watcher);\n-\tuv_close((uv_handle_t *)\u0026pt-\u003euv_timeout_watcher, lws_uv_close_cb);\n-\n-\tuv_idle_stop(\u0026pt-\u003euv_idle);\n-\tuv_close((uv_handle_t *)\u0026pt-\u003euv_idle, lws_uv_close_cb);\n-\n-\tif (pt-\u003eev_loop_foreign)\n-\t\treturn;\n-\n-\twhile (budget-- \u0026\u0026 uv_run(pt-\u003eio_loop_uv, UV_RUN_NOWAIT))\n-\t\t;\n-\n-\tuv_stop(pt-\u003eio_loop_uv);\n-\tuv_walk(pt-\u003eio_loop_uv, lws_uv_walk_cb, NULL);\n-\twhile (uv_run(pt-\u003eio_loop_uv, UV_RUN_NOWAIT))\n-\t\t;\n-#if UV_VERSION_MAJOR \u003e 0\n-\tm \u003d uv_loop_close(pt-\u003eio_loop_uv);\n-\tif (m \u003d\u003d UV_EBUSY)\n-\t\tlwsl_err(\u0022%s: uv_loop_close: UV_EBUSY\u005cn\u0022, __func__);\n-#endif\n-\tlws_free(pt-\u003eio_loop_uv);\n-}\n-\n-void\n-lws_libuv_accept(struct lws *wsi, lws_sock_file_fd_type desc)\n-{\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\n-\tif (!LWS_LIBUV_ENABLED(context))\n-\t\treturn;\n-\n-\twsi-\u003ew_read.context \u003d context;\n-\tif (wsi-\u003emode \u003d\u003d LWSCM_RAW_FILEDESC)\n-\t\tuv_poll_init(pt-\u003eio_loop_uv, \u0026wsi-\u003ew_read.uv_watcher,\n-\t\t\t (int)desc.filefd);\n-\telse\n-\t\tuv_poll_init_socket(pt-\u003eio_loop_uv, \u0026wsi-\u003ew_read.uv_watcher,\n-\t\t\t\t desc.sockfd);\n-}\n-\n-void\n-lws_libuv_io(struct lws *wsi, int flags)\n-{\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tstruct lws_io_watcher *w \u003d \u0026wsi-\u003ew_read;\n-//#if defined(WIN32) || defined(_WIN32)\n-//\tint current_events \u003d w-\u003euv_watcher.events \u0026\n-//\t\t\t (UV_READABLE | UV_WRITABLE);\n-//#else\n-\tint current_events \u003d w-\u003eactual_events \u0026 (UV_READABLE | UV_WRITABLE);\n-//#endif\n-\n-\tif (!LWS_LIBUV_ENABLED(context))\n-\t\treturn;\n-\n-\t// w-\u003econtext is set after the loop is initialized\n-\n-\tif (!pt-\u003eio_loop_uv || !w-\u003econtext) {\n-\t\tlwsl_info(\u0022%s: no io loop yet\u005cn\u0022, __func__);\n-\t\treturn;\n-\t}\n-\n-\tif (!((flags \u0026 (LWS_EV_START | LWS_EV_STOP)) \u0026\u0026\n-\t (flags \u0026 (LWS_EV_READ | LWS_EV_WRITE)))) {\n-\t\tlwsl_err(\u0022%s: assert: flags %d\u0022, __func__, flags);\n-\t\tassert(0);\n-\t}\n-\n-\tif (flags \u0026 LWS_EV_START) {\n-\t\tif (flags \u0026 LWS_EV_WRITE)\n-\t\t\tcurrent_events |\u003d UV_WRITABLE;\n-\n-\t\tif (flags \u0026 LWS_EV_READ)\n-\t\t\tcurrent_events |\u003d UV_READABLE;\n-\n-\t\tuv_poll_start(\u0026w-\u003euv_watcher, current_events, lws_io_cb);\n-\t} else {\n-\t\tif (flags \u0026 LWS_EV_WRITE)\n-\t\t\tcurrent_events \u0026\u003d ~UV_WRITABLE;\n-\n-\t\tif (flags \u0026 LWS_EV_READ)\n-\t\t\tcurrent_events \u0026\u003d ~UV_READABLE;\n-\n-\t\tif (!(current_events \u0026 (UV_READABLE | UV_WRITABLE)))\n-\t\t\tuv_poll_stop(\u0026w-\u003euv_watcher);\n-\t\telse\n-\t\t\tuv_poll_start(\u0026w-\u003euv_watcher, current_events,\n-\t\t\t\t lws_io_cb);\n-\t}\n-\n-\tw-\u003eactual_events \u003d current_events;\n-}\n-\n-int\n-lws_libuv_init_fd_table(struct lws_context *context)\n-{\n-\tint n;\n-\n-\tif (!LWS_LIBUV_ENABLED(context))\n-\t\treturn 0;\n-\n-\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++)\n-\t\tcontext-\u003ept[n].w_sigint.context \u003d context;\n-\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE void\n-lws_libuv_run(const struct lws_context *context, int tsi)\n-{\n-\tif (context-\u003ept[tsi].io_loop_uv \u0026\u0026 LWS_LIBUV_ENABLED(context))\n-\t\tuv_run(context-\u003ept[tsi].io_loop_uv, 0);\n-}\n-\n-LWS_VISIBLE void\n-lws_libuv_stop_without_kill(const struct lws_context *context, int tsi)\n-{\n-\tif (context-\u003ept[tsi].io_loop_uv \u0026\u0026 LWS_LIBUV_ENABLED(context))\n-\t\tuv_stop(context-\u003ept[tsi].io_loop_uv);\n-}\n-\n-static void\n-lws_libuv_kill(const struct lws_context *context)\n-{\n-\tint n;\n-\n-\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++)\n-\t\tif (context-\u003ept[n].io_loop_uv \u0026\u0026\n-\t\t LWS_LIBUV_ENABLED(context))\n-\t\t\tuv_stop(context-\u003ept[n].io_loop_uv);\n-}\n-\n-/*\n- * This does not actually stop the event loop. The reason is we have to pass\n- * libuv handle closures through its event loop. So this tries to close all\n- * wsi, and set a flag; when all the wsi closures are finalized then we\n- * actually stop the libuv event loops.\n- */\n-LWS_VISIBLE void\n-lws_libuv_stop(struct lws_context *context)\n-{\n-\tstruct lws_context_per_thread *pt;\n-\tint n, m;\n-\n-\tif (context-\u003erequested_kill)\n-\t\treturn;\n-\n-\tcontext-\u003erequested_kill \u003d 1;\n-\n-\tm \u003d context-\u003ecount_threads;\n-\tcontext-\u003ebeing_destroyed \u003d 1;\n-\n-\twhile (m--) {\n-\t\tpt \u003d \u0026context-\u003ept[m];\n-\n-\t\tfor (n \u003d 0; (unsigned int)n \u003c context-\u003ept[m].fds_count; n++) {\n-\t\t\tstruct lws *wsi \u003d wsi_from_fd(context, pt-\u003efds[n].fd);\n-\n-\t\t\tif (!wsi)\n-\t\t\t\tcontinue;\n-\t\t\tlws_close_free_wsi(wsi,\n-\t\t\t\tLWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY\n-\t\t\t\t/* no protocol close */);\n-\t\t\tn--;\n-\t\t}\n-\t}\n-\n-\tlwsl_info(\u0022%s: feels everything closed\u005cn\u0022, __func__);\n-\tif (context-\u003ecount_wsi_allocated \u003d\u003d 0)\n-\t\tlws_libuv_kill(context);\n-}\n-\n-LWS_VISIBLE uv_loop_t *\n-lws_uv_getloop(struct lws_context *context, int tsi)\n-{\n-\tif (context-\u003ept[tsi].io_loop_uv \u0026\u0026 LWS_LIBUV_ENABLED(context))\n-\t\treturn context-\u003ept[tsi].io_loop_uv;\n-\n-\treturn NULL;\n-}\n-\n-static void\n-lws_libuv_closewsi(uv_handle_t* handle)\n-{\n-\tstruct lws *n \u003d NULL, *wsi \u003d (struct lws *)(((char *)handle) -\n-\t\t\t (char *)(\u0026n-\u003ew_read.uv_watcher));\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\tint lspd \u003d 0;\n-\n-\tif (wsi-\u003emode \u003d\u003d LWSCM_SERVER_LISTENER \u0026\u0026\n-\t wsi-\u003econtext-\u003edeprecated) {\n-\t\tlspd \u003d 1;\n-\t\tcontext-\u003edeprecation_pending_listen_close_count--;\n-\t\tif (!context-\u003edeprecation_pending_listen_close_count)\n-\t\t\tlspd \u003d 2;\n-\t}\n-\n-\tlws_close_free_wsi_final(wsi);\n-\n-\tif (lspd \u003d\u003d 2 \u0026\u0026 context-\u003edeprecation_cb) {\n-\t\tlwsl_notice(\u0022calling deprecation callback\u005cn\u0022);\n-\t\tcontext-\u003edeprecation_cb();\n-\t}\n-\n-\tif (context-\u003erequested_kill \u0026\u0026 context-\u003ecount_wsi_allocated \u003d\u003d 0)\n-\t\tlws_libuv_kill(context);\n-}\n-\n-void\n-lws_libuv_closehandle(struct lws *wsi)\n-{\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\n-\t/* required to defer actual deletion until libuv has processed it */\n-\tuv_close((uv_handle_t*)\u0026wsi-\u003ew_read.uv_watcher, lws_libuv_closewsi);\n-\n-\tif (context-\u003erequested_kill \u0026\u0026 context-\u003ecount_wsi_allocated \u003d\u003d 0)\n-\t\tlws_libuv_kill(context);\n-}\n-\n-static void\n-lws_libuv_closewsi_m(uv_handle_t* handle)\n-{\n-\tlws_sockfd_type sockfd \u003d (lws_sockfd_type)(lws_intptr_t)handle-\u003edata;\n-\n-\tcompatible_close(sockfd);\n-}\n-\n-void\n-lws_libuv_closehandle_manually(struct lws *wsi)\n-{\n-\tuv_handle_t *h \u003d (void *)\u0026wsi-\u003ew_read.uv_watcher;\n-\n-\th-\u003edata \u003d (void *)(lws_intptr_t)wsi-\u003edesc.sockfd;\n-\t/* required to defer actual deletion until libuv has processed it */\n-\tuv_close((uv_handle_t*)\u0026wsi-\u003ew_read.uv_watcher, lws_libuv_closewsi_m);\n-}\n-\n-int\n-lws_libuv_check_watcher_active(struct lws *wsi)\n-{\n-\tuv_handle_t *h \u003d (void *)\u0026wsi-\u003ew_read.uv_watcher;\n-\n-\treturn uv_is_active(h);\n-}\n-\n-\n-#if defined(LWS_WITH_PLUGINS) \u0026\u0026 (UV_VERSION_MAJOR \u003e 0)\n-\n-LWS_VISIBLE int\n-lws_plat_plugins_init(struct lws_context *context, const char * const *d)\n-{\n-\tstruct lws_plugin_capability lcaps;\n-\tstruct lws_plugin *plugin;\n-\tlws_plugin_init_func initfunc;\n-\tint m, ret \u003d 0;\n-\tvoid *v;\n-\tuv_dirent_t dent;\n-\tuv_fs_t req;\n-\tchar path[256];\n-\tuv_lib_t lib;\n-\tint pofs \u003d 0;\n-\n-#if defined(__MINGW32__) || !defined(WIN32)\n-\tpofs \u003d 3;\n-#endif\n-\n-\tlib.errmsg \u003d NULL;\n-\tlib.handle \u003d NULL;\n-\n-\tuv_loop_init(\u0026context-\u003epu_loop);\n-\n-\tlwsl_notice(\u0022 Plugins:\u005cn\u0022);\n-\n-\twhile (d \u0026\u0026 *d) {\n-\n-\t\tlwsl_notice(\u0022 Scanning %s\u005cn\u0022, *d);\n-\t\tm \u003duv_fs_scandir(\u0026context-\u003epu_loop, \u0026req, *d, 0, NULL);\n-\t\tif (m \u003c 1) {\n-\t\t\tlwsl_err(\u0022Scandir on %s failed\u005cn\u0022, *d);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\twhile (uv_fs_scandir_next(\u0026req, \u0026dent) !\u003d UV_EOF) {\n-\t\t\tif (strlen(dent.name) \u003c 7)\n-\t\t\t\tcontinue;\n-\n-\t\t\tlwsl_notice(\u0022 %s\u005cn\u0022, dent.name);\n-\n-\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, *d,\n-\t\t\t\t dent.name);\n-\t\t\tif (uv_dlopen(path, \u0026lib)) {\n-\t\t\t\tuv_dlerror(\u0026lib);\n-\t\t\t\tlwsl_err(\u0022Error loading DSO: %s\u005cn\u0022, lib.errmsg);\n-\t\t\t\tuv_dlclose(\u0026lib);\n-\t\t\t\tgoto bail;\n-\t\t\t}\n-\n-\t\t\t/* we could open it, can we get his init function? */\n-\n-#if !defined(WIN32) \u0026\u0026 !defined(__MINGW32__)\n-\t\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022init_%s\u0022,\n-\t\t\t\t dent.name + pofs /* snip lib... */);\n-\t\t\tpath[m - 3] \u003d '\u005c0'; /* snip the .so */\n-#else\n-\t\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022init_%s\u0022,\n-\t\t\t\t dent.name + pofs);\n-\t\t\tpath[m - 4] \u003d '\u005c0'; /* snip the .dll */\n-#endif\n-\t\t\tif (uv_dlsym(\u0026lib, path, \u0026v)) {\n-\t\t\t\tuv_dlerror(\u0026lib);\n-\t\t\t\tlwsl_err(\u0022Failed to get %s on %s: %s\u0022, path,\n-\t\t\t\t\t\tdent.name, lib.errmsg);\n-\t\t\t\tuv_dlclose(\u0026lib);\n-\t\t\t\tgoto bail;\n-\t\t\t}\n-\t\t\tinitfunc \u003d (lws_plugin_init_func)v;\n-\t\t\tlcaps.api_magic \u003d LWS_PLUGIN_API_MAGIC;\n-\t\t\tm \u003d initfunc(context, \u0026lcaps);\n-\t\t\tif (m) {\n-\t\t\t\tlwsl_err(\u0022Init %s failed %d\u005cn\u0022, dent.name, m);\n-\t\t\t\tgoto skip;\n-\t\t\t}\n-\n-\t\t\tplugin \u003d lws_malloc(sizeof(*plugin), \u0022plugin\u0022);\n-\t\t\tif (!plugin) {\n-\t\t\t\tuv_dlclose(\u0026lib);\n-\t\t\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n-\t\t\t\tgoto bail;\n-\t\t\t}\n-\t\t\tplugin-\u003elist \u003d context-\u003eplugin_list;\n-\t\t\tcontext-\u003eplugin_list \u003d plugin;\n-\t\t\tstrncpy(plugin-\u003ename, dent.name, sizeof(plugin-\u003ename) - 1);\n-\t\t\tplugin-\u003ename[sizeof(plugin-\u003ename) - 1] \u003d '\u005c0';\n-\t\t\tplugin-\u003elib \u003d lib;\n-\t\t\tplugin-\u003ecaps \u003d lcaps;\n-\t\t\tcontext-\u003eplugin_protocol_count +\u003d lcaps.count_protocols;\n-\t\t\tcontext-\u003eplugin_extension_count +\u003d lcaps.count_extensions;\n-\n-\t\t\tcontinue;\n-\n-skip:\n-\t\t\tuv_dlclose(\u0026lib);\n-\t\t}\n-bail:\n-\t\tuv_fs_req_cleanup(\u0026req);\n-\t\td++;\n-\t}\n-\n-\treturn ret;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_plugins_destroy(struct lws_context *context)\n-{\n-\tstruct lws_plugin *plugin \u003d context-\u003eplugin_list, *p;\n-\tlws_plugin_destroy_func func;\n-\tchar path[256];\n-\tint pofs \u003d 0;\n-\tvoid *v;\n-\tint m;\n-\n-#if defined(__MINGW32__) || !defined(WIN32)\n-\tpofs \u003d 3;\n-#endif\n-\n-\tif (!plugin)\n-\t\treturn 0;\n-\n-\twhile (plugin) {\n-\t\tp \u003d plugin;\n-\n-#if !defined(WIN32) \u0026\u0026 !defined(__MINGW32__)\n-\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022destroy_%s\u0022,\n-\t\t\t\t plugin-\u003ename + pofs);\n-\t\tpath[m - 3] \u003d '\u005c0';\n-#else\n-\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022destroy_%s\u0022,\n-\t\t\t\t plugin-\u003ename + pofs);\n-\t\tpath[m - 4] \u003d '\u005c0';\n-#endif\n-\n-\t\tif (uv_dlsym(\u0026plugin-\u003elib, path, \u0026v)) {\n-\t\t\tuv_dlerror(\u0026plugin-\u003elib);\n-\t\t\tlwsl_err(\u0022Failed to get %s on %s: %s\u0022, path,\n-\t\t\t\t\tplugin-\u003ename, plugin-\u003elib.errmsg);\n-\t\t} else {\n-\t\t\tfunc \u003d (lws_plugin_destroy_func)v;\n-\t\t\tm \u003d func(context);\n-\t\t\tif (m)\n-\t\t\t\tlwsl_err(\u0022Destroying %s failed %d\u005cn\u0022,\n-\t\t\t\t\t\tplugin-\u003ename, m);\n-\t\t}\n-\n-\t\tuv_dlclose(\u0026p-\u003elib);\n-\t\tplugin \u003d p-\u003elist;\n-\t\tp-\u003elist \u003d NULL;\n-\t\tfree(p);\n-\t}\n-\n-\tcontext-\u003eplugin_list \u003d NULL;\n-\n-\twhile (uv_loop_close(\u0026context-\u003epu_loop))\n-\t\t;\n-\n-\treturn 0;\n-}\n-\n-#endif\n-\ndiff --git a/lib/libwebsockets.c b/lib/libwebsockets.c\nold mode 100755\nnew mode 100644\nindex 4fe4b2e..669f4ed\n--- a/lib/libwebsockets.c\n+++ b/lib/libwebsockets.c\n@@ -25,11 +25,6 @@\n #include \u003csys/types.h\u003e\n #endif\n \n-#if defined(WIN32) || defined(_WIN32)\n-#else\n-#include \u003csys/wait.h\u003e\n-#endif\n-\n #ifdef LWS_WITH_IPV6\n #if defined(WIN32) || defined(_WIN32)\n #include \u003cIphlpapi.h\u003e\n@@ -277,33 +272,6 @@ lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p)\n \treturn 0;\n }\n \n-#ifdef LWS_WITH_CGI\n-static void\n-lws_cgi_remove_and_kill(struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tstruct lws_cgi **pcgi \u003d \u0026pt-\u003ecgi_list;\n-\n-\t/* remove us from the cgi list */\n-\tlwsl_debug(\u0022%s: remove cgi %p from list\u005cn\u0022, __func__, wsi-\u003ecgi);\n-\twhile (*pcgi) {\n-\t\tif (*pcgi \u003d\u003d wsi-\u003ecgi) {\n-\t\t\t/* drop us from the pt cgi list */\n-\t\t\t*pcgi \u003d (*pcgi)-\u003ecgi_list;\n-\t\t\tbreak;\n-\t\t}\n-\t\tpcgi \u003d \u0026(*pcgi)-\u003ecgi_list;\n-\t}\n-\tif (wsi-\u003ecgi-\u003eheaders_buf) {\n-\t\tlwsl_debug(\u0022close: freed cgi headers\u005cn\u0022);\n-\t\tlws_free_set_NULL(wsi-\u003ecgi-\u003eheaders_buf);\n-\t}\n-\t/* we have a cgi going, we must kill it */\n-\twsi-\u003ecgi-\u003ebeing_closed \u003d 1;\n-\tlws_cgi_kill(wsi);\n-}\n-#endif\n-\n void\n lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)\n {\n@@ -1828,6 +1796,56 @@ LWS_VISIBLE int lwsl_visible(int level)\n \treturn log_level \u0026 level;\n }\n \n+LWS_VISIBLE void\n+lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)\n+{\n+\tunsigned char *buf \u003d (unsigned char *)vbuf;\n+\tunsigned int n, m, start;\n+\tchar line[80];\n+\tchar *p;\n+\n+\tif (!lwsl_visible(hexdump_level))\n+\t\treturn;\n+\n+\t_lws_log(hexdump_level, \u0022\u005cn\u0022);\n+\n+\tfor (n \u003d 0; n \u003c len;) {\n+\t\tstart \u003d n;\n+\t\tp \u003d line;\n+\n+\t\tp +\u003d sprintf(p, \u0022%04X: \u0022, start);\n+\n+\t\tfor (m \u003d 0; m \u003c 16 \u0026\u0026 n \u003c len; m++)\n+\t\t\tp +\u003d sprintf(p, \u0022%02X \u0022, buf[n++]);\n+\t\twhile (m++ \u003c 16)\n+\t\t\tp +\u003d sprintf(p, \u0022 \u0022);\n+\n+\t\tp +\u003d sprintf(p, \u0022 \u0022);\n+\n+\t\tfor (m \u003d 0; m \u003c 16 \u0026\u0026 (start + m) \u003c len; m++) {\n+\t\t\tif (buf[start + m] \u003e\u003d ' ' \u0026\u0026 buf[start + m] \u003c 127)\n+\t\t\t\t*p++ \u003d buf[start + m];\n+\t\t\telse\n+\t\t\t\t*p++ \u003d '.';\n+\t\t}\n+\t\twhile (m++ \u003c 16)\n+\t\t\t*p++ \u003d ' ';\n+\n+\t\t*p++ \u003d '\u005cn';\n+\t\t*p \u003d '\u005c0';\n+\t\t_lws_log(hexdump_level, \u0022%s\u0022, line);\n+\t\t(void)line;\n+\t}\n+\n+\t_lws_log(hexdump_level, \u0022\u005cn\u0022);\n+}\n+\n+LWS_VISIBLE void\n+lwsl_hexdump(const void *vbuf, size_t len)\n+{\n+\tlwsl_hexdump_level(LLL_DEBUG, vbuf, len);\n+}\n+\n LWS_VISIBLE int\n lws_is_ssl(struct lws *wsi)\n {\n@@ -2560,1020 +2578,7 @@ lws_is_cgi(struct lws *wsi) {\n #endif\n }\n \n-#ifdef LWS_WITH_CGI\n-\n-static int\n-urlencode(const char *in, int inlen, char *out, int outlen)\n-{\n-\tchar *start \u003d out, *end \u003d out + outlen;\n-\n-\twhile (inlen-- \u0026\u0026 out \u003c end - 4) {\n-\t\tif ((*in \u003e\u003d 'A' \u0026\u0026 *in \u003c\u003d 'Z') ||\n-\t\t (*in \u003e\u003d 'a' \u0026\u0026 *in \u003c\u003d 'z') ||\n-\t\t (*in \u003e\u003d '0' \u0026\u0026 *in \u003c\u003d '9') ||\n-\t\t *in \u003d\u003d '-' ||\n-\t\t *in \u003d\u003d '_' ||\n-\t\t *in \u003d\u003d '.' ||\n-\t\t *in \u003d\u003d '~') {\n-\t\t\t*out++ \u003d *in++;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (*in \u003d\u003d ' ') {\n-\t\t\t*out++ \u003d '+';\n-\t\t\tin++;\n-\t\t\tcontinue;\n-\t\t}\n-\t\t*out++ \u003d '%';\n-\t\t*out++ \u003d hex[(*in) \u003e\u003e 4];\n-\t\t*out++ \u003d hex[(*in++) \u0026 15];\n-\t}\n-\t*out \u003d '\u005c0';\n-\n-\tif (out \u003e\u003d end - 4)\n-\t\treturn -1;\n-\n-\treturn out - start;\n-}\n-\n-static struct lws *\n-lws_create_basic_wsi(struct lws_context *context, int tsi)\n-{\n-\tstruct lws *new_wsi;\n-\n-\tif (!context-\u003evhost_list)\n-\t\treturn NULL;\n-\n-\tif ((unsigned int)context-\u003ept[tsi].fds_count \u003d\u003d\n-\t context-\u003efd_limit_per_thread - 1) {\n-\t\tlwsl_err(\u0022no space for new conn\u005cn\u0022);\n-\t\treturn NULL;\n-\t}\n-\n-\tnew_wsi \u003d lws_zalloc(sizeof(struct lws), \u0022new wsi\u0022);\n-\tif (new_wsi \u003d\u003d NULL) {\n-\t\tlwsl_err(\u0022Out of memory for new connection\u005cn\u0022);\n-\t\treturn NULL;\n-\t}\n-\n-\tnew_wsi-\u003etsi \u003d tsi;\n-\tnew_wsi-\u003econtext \u003d context;\n-\tnew_wsi-\u003epending_timeout \u003d NO_PENDING_TIMEOUT;\n-\tnew_wsi-\u003erxflow_change_to \u003d LWS_RXFLOW_ALLOW;\n-\n-\t/* initialize the instance struct */\n-\n-\tnew_wsi-\u003estate \u003d LWSS_CGI;\n-\tnew_wsi-\u003emode \u003d LWSCM_CGI;\n-\tnew_wsi-\u003ehdr_parsing_completed \u003d 0;\n-\tnew_wsi-\u003eposition_in_fds_table \u003d -1;\n-\n-\t/*\n-\t * these can only be set once the protocol is known\n-\t * we set an unestablished connection's protocol pointer\n-\t * to the start of the defauly vhost supported list, so it can look\n-\t * for matching ones during the handshake\n-\t */\n-\tnew_wsi-\u003eprotocol \u003d context-\u003evhost_list-\u003eprotocols;\n-\tnew_wsi-\u003euser_space \u003d NULL;\n-\tnew_wsi-\u003eietf_spec_revision \u003d 0;\n-\tnew_wsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n-\tcontext-\u003ecount_wsi_allocated++;\n-\n-\treturn new_wsi;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len,\n-\tint timeout_secs, const struct lws_protocol_vhost_options *mp_cgienv)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tchar *env_array[30], cgi_path[400], e[1024], *p \u003d e,\n-\t *end \u003d p + sizeof(e) - 1, tok[256], *t;\n-\tstruct lws_cgi *cgi;\n-\tint n, m, i, uritok \u003d -1;\n-\n-\t/*\n-\t * give the master wsi a cgi struct\n-\t */\n-\n-\twsi-\u003ecgi \u003d lws_zalloc(sizeof(*wsi-\u003ecgi), \u0022new cgi\u0022);\n-\tif (!wsi-\u003ecgi) {\n-\t\tlwsl_err(\u0022%s: OOM\u005cn\u0022, __func__);\n-\t\treturn -1;\n-\t}\n-\n-\twsi-\u003ecgi-\u003eresponse_code \u003d HTTP_STATUS_OK;\n-\n-\tcgi \u003d wsi-\u003ecgi;\n-\tcgi-\u003ewsi \u003d wsi; /* set cgi's owning wsi */\n-\n-\t/* create pipes for [stdin|stdout] and [stderr] */\n-\n-\tfor (n \u003d 0; n \u003c 3; n++)\n-\t\tif (pipe(cgi-\u003epipe_fds[n]) \u003d\u003d -1)\n-\t\t\tgoto bail1;\n-\n-\t/* create cgi wsis for each stdin/out/err fd */\n-\n-\tfor (n \u003d 0; n \u003c 3; n++) {\n-\t\tcgi-\u003estdwsi[n] \u003d lws_create_basic_wsi(wsi-\u003econtext, wsi-\u003etsi);\n-\t\tif (!cgi-\u003estdwsi[n])\n-\t\t\tgoto bail2;\n-\t\tcgi-\u003estdwsi[n]-\u003ecgi_channel \u003d n;\n-\t\tcgi-\u003estdwsi[n]-\u003evhost \u003d wsi-\u003evhost;\n-\n-\t\tlwsl_debug(\u0022%s: cgi %p: pipe fd %d -\u003e fd %d / %d\u005cn\u0022, __func__,\n-\t\t\t cgi-\u003estdwsi[n], n, cgi-\u003epipe_fds[n][!!(n \u003d\u003d 0)],\n-\t\t\t cgi-\u003epipe_fds[n][!(n \u003d\u003d 0)]);\n-\n-\t\t/* read side is 0, stdin we want the write side, others read */\n-\t\tcgi-\u003estdwsi[n]-\u003edesc.sockfd \u003d cgi-\u003epipe_fds[n][!!(n \u003d\u003d 0)];\n-\t\tif (fcntl(cgi-\u003epipe_fds[n][!!(n \u003d\u003d 0)], F_SETFL, O_NONBLOCK) \u003c 0) {\n-\t\t\tlwsl_err(\u0022%s: setting NONBLOCK failed\u005cn\u0022, __func__);\n-\t\t\tgoto bail2;\n-\t\t}\n-\t}\n-\n-\tfor (n \u003d 0; n \u003c 3; n++) {\n-\t\tlws_libuv_accept(cgi-\u003estdwsi[n], cgi-\u003estdwsi[n]-\u003edesc);\n-\t\tif (insert_wsi_socket_into_fds(wsi-\u003econtext, cgi-\u003estdwsi[n]))\n-\t\t\tgoto bail3;\n-\t\tcgi-\u003estdwsi[n]-\u003eparent \u003d wsi;\n-\t\tcgi-\u003estdwsi[n]-\u003esibling_list \u003d wsi-\u003echild_list;\n-\t\twsi-\u003echild_list \u003d cgi-\u003estdwsi[n];\n-\t}\n-\n-\tlws_change_pollfd(cgi-\u003estdwsi[LWS_STDIN], LWS_POLLIN, LWS_POLLOUT);\n-\tlws_change_pollfd(cgi-\u003estdwsi[LWS_STDOUT], LWS_POLLOUT, LWS_POLLIN);\n-\tlws_change_pollfd(cgi-\u003estdwsi[LWS_STDERR], LWS_POLLOUT, LWS_POLLIN);\n-\n-\tlwsl_debug(\u0022%s: fds in %d, out %d, err %d\u005cn\u0022, __func__,\n-\t\t cgi-\u003estdwsi[LWS_STDIN]-\u003edesc.sockfd,\n-\t\t cgi-\u003estdwsi[LWS_STDOUT]-\u003edesc.sockfd,\n-\t\t cgi-\u003estdwsi[LWS_STDERR]-\u003edesc.sockfd);\n-\n-\tif (timeout_secs)\n-\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);\n-\n-\t/* the cgi stdout is always sending us http1.x header data first */\n-\twsi-\u003ehdr_state \u003d LCHS_HEADER;\n-\n-\t/* add us to the pt list of active cgis */\n-\tlwsl_debug(\u0022%s: adding cgi %p to list\u005cn\u0022, __func__, wsi-\u003ecgi);\n-\tcgi-\u003ecgi_list \u003d pt-\u003ecgi_list;\n-\tpt-\u003ecgi_list \u003d cgi;\n-\n-\t/* prepare his CGI env */\n-\n-\tn \u003d 0;\n-\n-\tif (lws_is_ssl(wsi))\n-\t\tenv_array[n++] \u003d \u0022HTTPS\u003dON\u0022;\n-\tif (wsi-\u003eu.hdr.ah) {\n-\t\tstatic const unsigned char meths[] \u003d {\n-\t\t\tWSI_TOKEN_GET_URI,\n-\t\t\tWSI_TOKEN_POST_URI,\n-\t\t\tWSI_TOKEN_OPTIONS_URI,\n-\t\t\tWSI_TOKEN_PUT_URI,\n-\t\t\tWSI_TOKEN_PATCH_URI,\n-\t\t\tWSI_TOKEN_DELETE_URI,\n-\t\t\tWSI_TOKEN_CONNECT,\n-\t\t\tWSI_TOKEN_HEAD_URI,\n-\t\t#ifdef LWS_WITH_HTTP2\n-\t\t\tWSI_TOKEN_HTTP_COLON_PATH,\n-\t\t#endif\n-\t\t};\n-\t\tstatic const char * const meth_names[] \u003d {\n-\t\t\t\u0022GET\u0022, \u0022POST\u0022, \u0022OPTIONS\u0022, \u0022PUT\u0022, \u0022PATCH\u0022, \u0022DELETE\u0022,\n-\t\t\t\u0022CONNECT\u0022, \u0022:path\u0022\n-\t\t};\n-\n-\t\tif (script_uri_path_len \u003e\u003d 0)\n-\t\t\tfor (m \u003d 0; m \u003c ARRAY_SIZE(meths); m++)\n-\t\t\t\tif (lws_hdr_total_length(wsi, meths[m]) \u003e\u003d\n-\t\t\t\t\t\tscript_uri_path_len) {\n-\t\t\t\t\turitok \u003d meths[m];\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\n-\t\tif (script_uri_path_len \u003c 0 \u0026\u0026 uritok \u003c 0)\n-\t\t\tgoto bail3;\n-//\t\tif (script_uri_path_len \u003c 0)\n-//\t\t\turitok \u003d 0;\n-\n-\t\tif (uritok \u003e\u003d 0) {\n-\t\t\tlws_snprintf(cgi_path, sizeof(cgi_path) - 1, \u0022REQUEST_URI\u003d%s\u0022,\n-\t\t\t\t lws_hdr_simple_ptr(wsi, uritok));\n-\t\t\tcgi_path[sizeof(cgi_path) - 1] \u003d '\u005c0';\n-\t\t\tenv_array[n++] \u003d cgi_path;\n-\t\t}\n-\n-\t\tif (m \u003e\u003d 0) {\n-\t\t\tenv_array[n++] \u003d p;\n-\t\t\tif (m \u003c 8)\n-\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022REQUEST_METHOD\u003d%s\u0022,\n-\t\t\t\t\t\tmeth_names[m]);\n-\t\t\telse\n-\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022REQUEST_METHOD\u003d%s\u0022,\n-\t\t\t\t\t\tlws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD));\n-\t\t\tp++;\n-\t\t}\n-\n-\t\tenv_array[n++] \u003d p;\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022QUERY_STRING\u003d\u0022);\n-\t\t/* dump the individual URI Arg parameters */\n-\t\tm \u003d 0;\n-\t\twhile (script_uri_path_len \u003e\u003d 0) {\n-\t\t\ti \u003d lws_hdr_copy_fragment(wsi, tok, sizeof(tok),\n-\t\t\t\t\t WSI_TOKEN_HTTP_URI_ARGS, m);\n-\t\t\tif (i \u003c 0)\n-\t\t\t\tbreak;\n-\t\t\tt \u003d tok;\n-\t\t\twhile (*t \u0026\u0026 *t !\u003d '\u003d' \u0026\u0026 p \u003c end - 4)\n-\t\t\t\t*p++ \u003d *t++;\n-\t\t\tif (*t \u003d\u003d '\u003d')\n-\t\t\t\t*p++ \u003d *t++;\n-\t\t\ti \u003d urlencode(t, i- (t - tok), p, end - p);\n-\t\t\tif (i \u003e 0) {\n-\t\t\t\tp +\u003d i;\n-\t\t\t\t*p++ \u003d '\u0026';\n-\t\t\t}\n-\t\t\tm++;\n-\t\t}\n-\t\tif (m)\n-\t\t\tp--;\n-\t\t*p++ \u003d '\u005c0';\n-\n-\t\tif (script_uri_path_len \u003e\u003d 0) {\n-\t\t\tenv_array[n++] \u003d p;\n-\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022PATH_INFO\u003d%s\u0022,\n-\t\t\t\t lws_hdr_simple_ptr(wsi, uritok) +\n-\t\t\t\t script_uri_path_len);\n-\t\t\tp++;\n-\t\t}\n-\t}\n-\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n-\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) {\n-\t\tenv_array[n++] \u003d p;\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022HTTP_REFERER\u003d%s\u0022,\n-\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_REFERER));\n-\t\tp++;\n-\t}\n-\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n-\t lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {\n-\t\tenv_array[n++] \u003d p;\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022HTTP_HOST\u003d%s\u0022,\n-\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));\n-\t\tp++;\n-\t}\n-\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n-\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {\n-\t\tenv_array[n++] \u003d p;\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022HTTP_COOKIE\u003d%s\u0022,\n-\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COOKIE));\n-\t\tp++;\n-\t}\n-\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n-\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) {\n-\t\tenv_array[n++] \u003d p;\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022USER_AGENT\u003d%s\u0022,\n-\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT));\n-\t\tp++;\n-\t}\n-\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n-\t uritok \u003d\u003d WSI_TOKEN_POST_URI) {\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {\n-\t\t\tenv_array[n++] \u003d p;\n-\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022CONTENT_TYPE\u003d%s\u0022,\n-\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE));\n-\t\t\tp++;\n-\t\t}\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n-\t\t\tenv_array[n++] \u003d p;\n-\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022CONTENT_LENGTH\u003d%s\u0022,\n-\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH));\n-\t\t\tp++;\n-\t\t}\n-\t}\n-\tenv_array[n++] \u003d \u0022PATH\u003d/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin\u0022;\n-\n-\tenv_array[n++] \u003d p;\n-\tp +\u003d lws_snprintf(p, end - p, \u0022SCRIPT_PATH\u003d%s\u0022, exec_array[0]) + 1;\n-\n-\twhile (mp_cgienv) {\n-\t\tenv_array[n++] \u003d p;\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022%s\u003d%s\u0022, mp_cgienv-\u003ename,\n-\t\t\t mp_cgienv-\u003evalue);\n-\t\tlwsl_debug(\u0022 Applying mount-specific cgi env '%s'\u005cn\u0022,\n-\t\t\t env_array[n - 1]);\n-\t\tp++;\n-\t\tmp_cgienv \u003d mp_cgienv-\u003enext;\n-\t}\n-\n-\tenv_array[n++] \u003d \u0022SERVER_SOFTWARE\u003dlibwebsockets\u0022;\n-\tenv_array[n] \u003d NULL;\n-\n-#if 0\n-\tfor (m \u003d 0; m \u003c n; m++)\n-\t\tlwsl_err(\u0022 %s\u005cn\u0022, env_array[m]);\n-#endif\n-\n-\t/*\n-\t * Actually having made the env, as a cgi we don't need the ah\n-\t * any more\n-\t */\n-\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n-\t lws_header_table_is_in_detachable_state(wsi))\n-\t\tlws_header_table_detach(wsi, 0);\n-\n-\t/* we are ready with the redirection pipes... run the thing */\n-#if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)\n-\tcgi-\u003epid \u003d fork();\n-#else\n-\tcgi-\u003epid \u003d vfork();\n-#endif\n-\tif (cgi-\u003epid \u003c 0) {\n-\t\tlwsl_err(\u0022fork failed, errno %d\u0022, errno);\n-\t\tgoto bail3;\n-\t}\n-\n-#if defined(__linux__)\n-\tprctl(PR_SET_PDEATHSIG, SIGTERM);\n-#endif\n-\tif (script_uri_path_len \u003e\u003d 0)\n-\t\t/* stops non-daemonized main processess getting SIGINT\n-\t\t * from TTY */\n-\t\tsetpgrp();\n-\n-\tif (cgi-\u003epid) {\n-\t\t/* we are the parent process */\n-\t\twsi-\u003econtext-\u003ecount_cgi_spawned++;\n-\t\tlwsl_debug(\u0022%s: cgi %p spawned PID %d\u005cn\u0022, __func__, cgi, cgi-\u003epid);\n-\n-\t\tfor (n \u003d 0; n \u003c 3; n++)\n-\t\t\tclose(cgi-\u003epipe_fds[n][!(n \u003d\u003d 0)]);\n-\n-\t\t/* inform cgi owner of the child PID */\n-\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback, wsi,\n-\t\t\t\t\t LWS_CALLBACK_CGI_PROCESS_ATTACH,\n-\t\t\t\t\t wsi-\u003euser_space, NULL, cgi-\u003epid);\n-\t\t(void)n;\n-\n-\t\treturn 0;\n-\t}\n-\n-\t/* somewhere we can at least read things and enter it */\n-\tif (chdir(\u0022/tmp\u0022))\n-\t\tlwsl_notice(\u0022%s: Failed to chdir\u005cn\u0022, __func__);\n-\n-\t/* We are the forked process, redirect and kill inherited things.\n-\t *\n-\t * Because of vfork(), we cannot do anything that changes pages in\n-\t * the parent environment. Stuff that changes kernel state for the\n-\t * process is OK. Stuff that happens after the execvpe() is OK.\n-\t */\n-\n-\tfor (n \u003d 0; n \u003c 3; n++) {\n-\t\tif (dup2(cgi-\u003epipe_fds[n][!(n \u003d\u003d 0)], n) \u003c 0) {\n-\t\t\tlwsl_err(\u0022%s: stdin dup2 failed\u005cn\u0022, __func__);\n-\t\t\tgoto bail3;\n-\t\t}\n-\t\tclose(cgi-\u003epipe_fds[n][!(n \u003d\u003d 0)]);\n-\t}\n-\n-#if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)\n-\tfor (m \u003d 0; m \u003c n; m++) {\n-\t\tp \u003d strchr(env_array[m], '\u003d');\n-\t\t*p++ \u003d '\u005c0';\n-\t\tsetenv(env_array[m], p, 1);\n-\t}\n-\texecvp(exec_array[0], (char * const *)\u0026exec_array[0]);\n-#else\n-\texecvpe(exec_array[0], (char * const *)\u0026exec_array[0], \u0026env_array[0]);\n-#endif\n-\n-\texit(1);\n-\n-bail3:\n-\t/* drop us from the pt cgi list */\n-\tpt-\u003ecgi_list \u003d cgi-\u003ecgi_list;\n-\n-\twhile (--n \u003e\u003d 0)\n-\t\tremove_wsi_socket_from_fds(wsi-\u003ecgi-\u003estdwsi[n]);\n-bail2:\n-\tfor (n \u003d 0; n \u003c 3; n++)\n-\t\tif (wsi-\u003ecgi-\u003estdwsi[n])\n-\t\t\tlws_free_wsi(cgi-\u003estdwsi[n]);\n-\n-bail1:\n-\tfor (n \u003d 0; n \u003c 3; n++) {\n-\t\tif (cgi-\u003epipe_fds[n][0])\n-\t\t\tclose(cgi-\u003epipe_fds[n][0]);\n-\t\tif (cgi-\u003epipe_fds[n][1])\n-\t\t\tclose(cgi-\u003epipe_fds[n][1]);\n-\t}\n-\n-\tlws_free_set_NULL(wsi-\u003ecgi);\n-\n-\tlwsl_err(\u0022%s: failed\u005cn\u0022, __func__);\n-\n-\treturn -1;\n-}\n-\n-/* we have to parse out these headers in the CGI output */\n-\n-static const char * const significant_hdr[SIGNIFICANT_HDR_COUNT] \u003d {\n-\t\u0022content-length: \u0022,\n-\t\u0022location: \u0022,\n-\t\u0022status: \u0022,\n-\t\u0022transfer-encoding: chunked\u0022,\n-};\n-\n-enum header_recode {\n-\tHR_NAME,\n-\tHR_WHITESPACE,\n-\tHR_ARG,\n-\tHR_CRLF,\n-};\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_cgi_write_split_stdout_headers(struct lws *wsi)\n-{\n-\tint n, m, cmd;\n-\tunsigned char buf[LWS_PRE + 1024], *start \u003d \u0026buf[LWS_PRE], *p \u003d start,\n-\t\t\t*end \u003d \u0026buf[sizeof(buf) - 1 - LWS_PRE], *name,\n-\t\t\t*value \u003d NULL;\n-\tchar c, hrs;\n-\n-\tif (!wsi-\u003ecgi)\n-\t\treturn -1;\n-\n-\twhile (wsi-\u003ehdr_state !\u003d LHCS_PAYLOAD) {\n-\t\t/*\n-\t\t * We have to separate header / finalize and payload chunks,\n-\t\t * since they need to be handled separately\n-\t\t */\n-\t\tswitch (wsi-\u003ehdr_state) {\n-\t\tcase LHCS_RESPONSE:\n-\t\t\tlwsl_debug(\u0022LHCS_RESPONSE: issuing response %d\u005cn\u0022,\n-\t\t\t\t wsi-\u003ecgi-\u003eresponse_code);\n-\t\t\tif (lws_add_http_header_status(wsi, wsi-\u003ecgi-\u003eresponse_code,\n-\t\t\t\t\t\t \u0026p, end))\n-\t\t\t\treturn 1;\n-\t\t\tif (!wsi-\u003ecgi-\u003eexplicitly_chunked \u0026\u0026\n-\t\t\t !wsi-\u003ecgi-\u003econtent_length \u0026\u0026\n-\t\t\t\tlws_add_http_header_by_token(wsi,\n-\t\t\t\t\tWSI_TOKEN_HTTP_TRANSFER_ENCODING,\n-\t\t\t\t\t(unsigned char *)\u0022chunked\u0022, 7, \u0026p, end))\n-\t\t\t\treturn 1;\n-\t\t\tif (!(wsi-\u003ehttp2_substream))\n-\t\t\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,\n-\t\t\t\t\t\t(unsigned char *)\u0022close\u0022, 5, \u0026p, end))\n-\t\t\t\t\treturn 1;\n-\t\t\tn \u003d lws_write(wsi, start, p - start,\n-\t\t\t\t LWS_WRITE_HTTP_HEADERS | LWS_WRITE_NO_FIN);\n-\n-\t\t\t/*\n-\t\t\t * so we have a bunch of http/1 style ascii headers\n-\t\t\t * starting from wsi-\u003ecgi-\u003eheaders_buf through\n-\t\t\t * wsi-\u003ecgi-\u003eheaders_pos. These are OK for http/1\n-\t\t\t * connections, but they're no good for http/2 conns.\n-\t\t\t *\n-\t\t\t * Let's redo them at headers_pos forward using the\n-\t\t\t * correct coding for http/1 or http/2\n-\t\t\t */\n-\t\t\tif (!wsi-\u003ehttp2_substream)\n-\t\t\t\tgoto post_hpack_recode;\n-\n-\t\t\tp \u003d wsi-\u003ecgi-\u003eheaders_start;\n-\t\t\twsi-\u003ecgi-\u003eheaders_start \u003d wsi-\u003ecgi-\u003eheaders_pos;\n-\t\t\twsi-\u003ecgi-\u003eheaders_dumped \u003d wsi-\u003ecgi-\u003eheaders_start;\n-\t\t\thrs \u003d HR_NAME;\n-\t\t\tname \u003d buf;\n-\n-\t\t\twhile (p \u003c wsi-\u003ecgi-\u003eheaders_start) {\n-\t\t\t\t//lwsl_notice(\u0022%c (%d)\u005cn\u0022, *p, (int)(wsi-\u003ecgi-\u003eheaders_start - p));\n-\t\t\t\tswitch (hrs) {\n-\t\t\t\tcase HR_NAME:\n-\t\t\t\t\t/*\n-\t\t\t\t\t * in http/2 upper-case header names\n-\t\t\t\t\t * are illegal. So convert to lower-\n-\t\t\t\t\t * case.\n-\t\t\t\t\t */\n-\t\t\t\t\tif (name - buf \u003e 64)\n-\t\t\t\t\t\treturn -1;\n-\t\t\t\t\tif (*p !\u003d ':') {\n-\t\t\t\t\t\tif (*p \u003e\u003d 'A' \u0026\u0026 *p \u003c\u003d 'Z')\n-\t\t\t\t\t\t\t*name++ \u003d (*p++) + ('a' - 'A');\n-\t\t\t\t\t\telse\n-\t\t\t\t\t\t\t*name++ \u003d *p++;\n-\t\t\t\t\t} else {\n-\t\t\t\t\t\tp++;\n-\t\t\t\t\t\t*name++ \u003d '\u005c0';\n-\t\t\t\t\t\tvalue \u003d name;\n-\t\t\t\t\t\thrs \u003d HR_WHITESPACE;\n-\t\t\t\t\t}\n-\t\t\t\t\tbreak;\n-\t\t\t\tcase HR_WHITESPACE:\n-\t\t\t\t\tif (*p \u003d\u003d ' ') {\n-\t\t\t\t\t\tp++;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t\thrs \u003d HR_ARG;\n-\t\t\t\t\t/* fallthru */\n-\t\t\t\tcase HR_ARG:\n-\t\t\t\t\tif (name \u003e end - 64)\n-\t\t\t\t\t\treturn -1;\n-\n-\t\t\t\t\tif (*p !\u003d '\u005cx0a' \u0026\u0026 *p !\u003d '\u005cx0d') {\n-\t\t\t\t\t\t*name++ \u003d *p++;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t\thrs \u003d HR_CRLF;\n-\t\t\t\t\t/* fallthru */\n-\t\t\t\tcase HR_CRLF:\n-\t\t\t\t\tif ((*p !\u003d '\u005cx0a' \u0026\u0026 *p !\u003d '\u005cx0d') ||\n-\t\t\t\t\t p + 1 \u003d\u003d wsi-\u003ecgi-\u003eheaders_start) {\n-\t\t\t\t\t\t*name \u003d '\u005c0';\n-\t\t\t\t\t\tif ((strcmp((const char *)buf, \u0022transfer-encoding\u0022)\n-\t\t\t\t\t\t)) {\n-\t\t\t\t\t\t\tlwsl_debug(\u0022adding header %s: %s\u005cn\u0022, buf, value);\n-\t\t\t\t\t\t\tif (lws_add_http_header_by_name(wsi, buf,\n-\t\t\t\t\t\t\t\t(unsigned char *)value, name - value,\n-\t\t\t\t\t\t\t\t(unsigned char **)\u0026wsi-\u003ecgi-\u003eheaders_pos,\n-\t\t\t\t\t\t\t\t(unsigned char *)wsi-\u003ecgi-\u003eheaders_end))\n-\t\t\t\t\t\t\t\treturn 1;\n-\t\t\t\t\t\t\thrs \u003d HR_NAME;\n-\t\t\t\t\t\t\tname \u003d buf;\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\t}\n-\t\t\t\t\t}\n-\t\t\t\t\tp++;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t}\n-post_hpack_recode:\n-\t\t\t/* finalize cached headers before dumping them */\n-\t\t\tif (lws_finalize_http_header(wsi,\n-\t\t\t\t\t(unsigned char **)\u0026wsi-\u003ecgi-\u003eheaders_pos,\n-\t\t\t\t\t(unsigned char *)wsi-\u003ecgi-\u003eheaders_end)) {\n-\n-\t\t\t\tlwsl_notice(\u0022finalize failed\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t\twsi-\u003ehdr_state \u003d LHCS_DUMP_HEADERS;\n-\t\t\twsi-\u003ereason_bf |\u003d LWS_CB_REASON_AUX_BF__CGI_HEADERS;\n-\t\t\tlws_callback_on_writable(wsi);\n-\t\t\t/* back to the loop for writeability again */\n-\t\t\treturn 0;\n-\n-\t\tcase LHCS_DUMP_HEADERS:\n-\n-\t\t\tn \u003d wsi-\u003ecgi-\u003eheaders_pos - wsi-\u003ecgi-\u003eheaders_dumped;\n-\t\t\tif (n \u003e 512)\n-\t\t\t\tn \u003d 512;\n-\n-\t\t\tlwsl_debug(\u0022LHCS_DUMP_HEADERS: %d\u005cn\u0022, n);\n-\n-\t\t\tcmd \u003d LWS_WRITE_HTTP_HEADERS_CONTINUATION;\n-\t\t\tif (wsi-\u003ecgi-\u003eheaders_dumped + n !\u003d wsi-\u003ecgi-\u003eheaders_pos) {\n-\t\t\t\tlwsl_notice(\u0022adding no fin flag\u005cn\u0022);\n-\t\t\t\tcmd |\u003d LWS_WRITE_NO_FIN;\n-\t\t\t}\n-\n-\t\t\tm \u003d lws_write(wsi, (unsigned char *)wsi-\u003ecgi-\u003eheaders_dumped,\n-\t\t\t\t n, cmd);\n-\t\t\tif (m \u003c 0) {\n-\t\t\t\tlwsl_debug(\u0022%s: write says %d\u005cn\u0022, __func__, m);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\twsi-\u003ecgi-\u003eheaders_dumped +\u003d n;\n-\t\t\tif (wsi-\u003ecgi-\u003eheaders_dumped \u003d\u003d wsi-\u003ecgi-\u003eheaders_pos) {\n-\t\t\t\twsi-\u003ehdr_state \u003d LHCS_PAYLOAD;\n-\t\t\t\tlws_free_set_NULL(wsi-\u003ecgi-\u003eheaders_buf);\n-\t\t\t\tlwsl_debug(\u0022freed cgi headers\u005cn\u0022);\n-\t\t\t} else {\n-\t\t\t\twsi-\u003ereason_bf |\u003d LWS_CB_REASON_AUX_BF__CGI_HEADERS;\n-\t\t\t\tlws_callback_on_writable(wsi);\n-\t\t\t}\n-\n-\t\t\t/* writeability becomes uncertain now we wrote\n-\t\t\t * something, we must return to the event loop\n-\t\t\t */\n-\t\t\treturn 0;\n-\t\t}\n-\n-\t\tif (!wsi-\u003ecgi-\u003eheaders_buf) {\n-\t\t\t/* if we don't already have a headers buf, cook one up */\n-\t\t\tn \u003d 2048;\n-\t\t\tif (wsi-\u003ehttp2_substream)\n-\t\t\t\tn \u003d 4096;\n-\t\t\twsi-\u003ecgi-\u003eheaders_buf \u003d lws_malloc(n + LWS_PRE,\n-\t\t\t\t\t\t\t \u0022cgi hdr buf\u0022);\n-\t\t\tif (!wsi-\u003ecgi-\u003eheaders_buf) {\n-\t\t\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t\tlwsl_debug(\u0022allocated cgi hdrs\u005cn\u0022);\n-\t\t\twsi-\u003ecgi-\u003eheaders_start \u003d wsi-\u003ecgi-\u003eheaders_buf + LWS_PRE;\n-\t\t\twsi-\u003ecgi-\u003eheaders_pos \u003d wsi-\u003ecgi-\u003eheaders_start;\n-\t\t\twsi-\u003ecgi-\u003eheaders_dumped \u003d wsi-\u003ecgi-\u003eheaders_pos;\n-\t\t\twsi-\u003ecgi-\u003eheaders_end \u003d wsi-\u003ecgi-\u003eheaders_buf + n - 1;\n-\n-\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++) {\n-\t\t\t\twsi-\u003ecgi-\u003ematch[n] \u003d 0;\n-\t\t\t\twsi-\u003ecgi-\u003elp \u003d 0;\n-\t\t\t}\n-\t\t}\n-\n-\t\tn \u003d lws_get_socket_fd(wsi-\u003ecgi-\u003estdwsi[LWS_STDOUT]);\n-\t\tif (n \u003c 0)\n-\t\t\treturn -1;\n-\t\tn \u003d read(n, \u0026c, 1);\n-\t\tif (n \u003c 0) {\n-\t\t\tif (errno !\u003d EAGAIN) {\n-\t\t\t\tlwsl_debug(\u0022%s: read says %d\u005cn\u0022, __func__, n);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\telse\n-\t\t\t\tn \u003d 0;\n-\n-\t\t\tif (wsi-\u003ecgi-\u003eheaders_pos \u003e\u003d wsi-\u003ecgi-\u003eheaders_end - 4) {\n-\t\t\t\tlwsl_notice(\u0022CGI headers larger than buffer size\u005cn\u0022);\n-\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t}\n-\t\tif (n) {\n-\t\t\tlwsl_debug(\u0022-- 0x%02X %c %d %d\u005cn\u0022, (unsigned char)c, c,\n-\t\t\t\t wsi-\u003ecgi-\u003ematch[1], wsi-\u003ehdr_state);\n-\t\t\tif (!c)\n-\t\t\t\treturn -1;\n-\t\t\tswitch (wsi-\u003ehdr_state) {\n-\t\t\tcase LCHS_HEADER:\n-\t\t\t\thdr:\n-\t\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++) {\n-\t\t\t\t\t/* significant headers with numeric decimal payloads */\n-\t\t\t\t\tif (!significant_hdr[n][wsi-\u003ecgi-\u003ematch[n]] \u0026\u0026\n-\t\t\t\t\t (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9') \u0026\u0026\n-\t\t\t\t\t wsi-\u003ecgi-\u003elp \u003c sizeof(wsi-\u003ecgi-\u003el) - 1) {\n-\t\t\t\t\t\twsi-\u003ecgi-\u003el[wsi-\u003ecgi-\u003elp++] \u003d c;\n-\t\t\t\t\t\twsi-\u003ecgi-\u003el[wsi-\u003ecgi-\u003elp] \u003d '\u005c0';\n-\t\t\t\t\t\tswitch (n) {\n-\t\t\t\t\t\tcase SIGNIFICANT_HDR_CONTENT_LENGTH:\n-\t\t\t\t\t\t\twsi-\u003ecgi-\u003econtent_length \u003d atoll(wsi-\u003ecgi-\u003el);\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\tcase SIGNIFICANT_HDR_STATUS:\n-\t\t\t\t\t\t\twsi-\u003ecgi-\u003eresponse_code \u003d atol(wsi-\u003ecgi-\u003el);\n-\t\t\t\t\t\t\tlwsl_debug(\u0022Status set to %d\u005cn\u0022, wsi-\u003ecgi-\u003eresponse_code);\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\tdefault:\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\t}\n-\t\t\t\t\t}\n-\t\t\t\t\t/* hits up to the NUL are sticky until next hdr */\n-\t\t\t\t\tif (significant_hdr[n][wsi-\u003ecgi-\u003ematch[n]]) {\n-\t\t\t\t\t\tif (tolower(c) \u003d\u003d significant_hdr[n][wsi-\u003ecgi-\u003ematch[n]])\n-\t\t\t\t\t\t\twsi-\u003ecgi-\u003ematch[n]++;\n-\t\t\t\t\t\telse\n-\t\t\t\t\t\t\twsi-\u003ecgi-\u003ematch[n] \u003d 0;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\n-\t\t\t\t/* some cgi only send us \u005cx0a for EOL */\n-\t\t\t\tif (c \u003d\u003d '\u005cx0a') {\n-\t\t\t\t\twsi-\u003ehdr_state \u003d LCHS_SINGLE_0A;\n-\t\t\t\t\t*wsi-\u003ecgi-\u003eheaders_pos++ \u003d '\u005cx0d';\n-\t\t\t\t}\n-\t\t\t\t*wsi-\u003ecgi-\u003eheaders_pos++ \u003d c;\n-\t\t\t\tif (c \u003d\u003d '\u005cx0d')\n-\t\t\t\t\twsi-\u003ehdr_state \u003d LCHS_LF1;\n-\n-\t\t\t\tif (wsi-\u003ehdr_state !\u003d LCHS_HEADER \u0026\u0026\n-\t\t\t\t !significant_hdr[SIGNIFICANT_HDR_TRANSFER_ENCODING][wsi-\u003ecgi-\u003ematch[SIGNIFICANT_HDR_TRANSFER_ENCODING]]) {\n-\t\t\t\t\tlwsl_debug(\u0022cgi produced chunked\u005cn\u0022);\n-\t\t\t\t\twsi-\u003ecgi-\u003eexplicitly_chunked \u003d 1;\n-\t\t\t\t}\n-\n-\t\t\t\t/* presence of Location: mandates 302 retcode */\n-\t\t\t\tif (wsi-\u003ehdr_state !\u003d LCHS_HEADER \u0026\u0026\n-\t\t\t\t !significant_hdr[SIGNIFICANT_HDR_LOCATION][wsi-\u003ecgi-\u003ematch[SIGNIFICANT_HDR_LOCATION]]) {\n-\t\t\t\t\tlwsl_debug(\u0022CGI: Location hdr seen\u005cn\u0022);\n-\t\t\t\t\twsi-\u003ecgi-\u003eresponse_code \u003d 302;\n-\t\t\t\t}\n-\n-\t\t\t\tbreak;\n-\t\t\tcase LCHS_LF1:\n-\t\t\t\t*wsi-\u003ecgi-\u003eheaders_pos++ \u003d c;\n-\t\t\t\tif (c \u003d\u003d '\u005cx0a') {\n-\t\t\t\t\twsi-\u003ehdr_state \u003d LCHS_CR2;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\t/* we got \u005cr[^\u005cn]... it's unreasonable */\n-\t\t\t\tlwsl_debug(\u0022%s: funny CRLF 0x%02X\u005cn\u0022, __func__, (unsigned char)c);\n-\t\t\t\treturn -1;\n-\n-\t\t\tcase LCHS_CR2:\n-\t\t\t\tif (c \u003d\u003d '\u005cx0d') {\n-\t\t\t\t\t/* drop the \u005cx0d */\n-\t\t\t\t\twsi-\u003ehdr_state \u003d LCHS_LF2;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\twsi-\u003ehdr_state \u003d LCHS_HEADER;\n-\t\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++)\n-\t\t\t\t\twsi-\u003ecgi-\u003ematch[n] \u003d 0;\n-\t\t\t\twsi-\u003ecgi-\u003elp \u003d 0;\n-\t\t\t\tgoto hdr;\n-\n-\t\t\tcase LCHS_LF2:\n-\t\t\tcase LCHS_SINGLE_0A:\n-\t\t\t\tm \u003d wsi-\u003ehdr_state;\n-\t\t\t\tif (c \u003d\u003d '\u005cx0a') {\n-\t\t\t\t\tlwsl_debug(\u0022Content-Length: %lld\u005cn\u0022, (unsigned long long)wsi-\u003ecgi-\u003econtent_length);\n-\t\t\t\t\twsi-\u003ehdr_state \u003d LHCS_RESPONSE;\n-\t\t\t\t\t/* drop the \u005c0xa ... finalize will add it if needed */\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\tif (m \u003d\u003d LCHS_LF2)\n-\t\t\t\t\t/* we got \u005cr\u005cn\u005cr[^\u005cn]... it's unreasonable */\n-\t\t\t\t\treturn -1;\n-\t\t\t\t/* we got \u005cx0anext header, it's reasonable */\n-\t\t\t\t*wsi-\u003ecgi-\u003eheaders_pos++ \u003d c;\n-\t\t\t\twsi-\u003ehdr_state \u003d LCHS_HEADER;\n-\t\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++)\n-\t\t\t\t\twsi-\u003ecgi-\u003ematch[n] \u003d 0;\n-\t\t\t\twsi-\u003ecgi-\u003elp \u003d 0;\n-\t\t\t\tbreak;\n-\t\t\tcase LHCS_PAYLOAD:\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\n-\t\t/* ran out of input, ended the headers, or filled up the headers buf */\n-\t\tif (!n || wsi-\u003ehdr_state \u003d\u003d LHCS_PAYLOAD)\n-\t\t\treturn 0;\n-\t}\n-\n-\t/* payload processing */\n-\n-\tm \u003d !wsi-\u003ecgi-\u003eexplicitly_chunked \u0026\u0026 !wsi-\u003ecgi-\u003econtent_length;\n-\tn \u003d lws_get_socket_fd(wsi-\u003ecgi-\u003estdwsi[LWS_STDOUT]);\n-\tif (n \u003c 0)\n-\t\treturn -1;\n-\tn \u003d read(n, start, sizeof(buf) - LWS_PRE - (m ? LWS_HTTP_CHUNK_HDR_SIZE : 0));\n-\n-\tif (n \u003c 0 \u0026\u0026 errno !\u003d EAGAIN) {\n-\t\tlwsl_debug(\u0022%s: stdout read says %d\u005cn\u0022, __func__, n);\n-\t\treturn -1;\n-\t}\n-\tif (n \u003e 0) {\n-\t\tif (!wsi-\u003ehttp2_substream \u0026\u0026 m) {\n-\t\t\tchar chdr[LWS_HTTP_CHUNK_HDR_SIZE];\n-\t\t\tm \u003d lws_snprintf(chdr, LWS_HTTP_CHUNK_HDR_SIZE - 3,\n-\t\t\t\t\t \u0022%X\u005cx0d\u005cx0a\u0022, n);\n-\t\t\tmemmove(start + m, start, n);\n-\t\t\tmemcpy(start, chdr, m);\n-\t\t\tmemcpy(start + m + n, \u0022\u005cx0d\u005cx0a\u0022, 2);\n-\t\t\tn +\u003d m + 2;\n-\t\t}\n-\t\tcmd \u003d LWS_WRITE_HTTP;\n-\t\tif (wsi-\u003ecgi-\u003econtent_length_seen + n \u003d\u003d wsi-\u003ecgi-\u003econtent_length)\n-\t\t\tcmd \u003d LWS_WRITE_HTTP_FINAL;\n-\t\tm \u003d lws_write(wsi, (unsigned char *)start, n, cmd);\n-\t\t//lwsl_notice(\u0022write %d\u005cn\u0022, m);\n-\t\tif (m \u003c 0) {\n-\t\t\tlwsl_debug(\u0022%s: stdout write says %d\u005cn\u0022, __func__, m);\n-\t\t\treturn -1;\n-\t\t}\n-\t\twsi-\u003ecgi-\u003econtent_length_seen +\u003d n;\n-\t} else {\n-\t\tif (wsi-\u003ecgi_stdout_zero_length) {\n-\t\t\tlwsl_debug(\u0022%s: stdout is POLLHUP'd\u005cn\u0022, __func__);\n-\t\t\tif (wsi-\u003ehttp2_substream)\n-\t\t\t\tm \u003d lws_write(wsi, (unsigned char *)start, 0,\n-\t\t\t\t\t LWS_WRITE_HTTP_FINAL);\n-\t\t\treturn 1;\n-\t\t}\n-\t\twsi-\u003ecgi_stdout_zero_length \u003d 1;\n-\t}\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_cgi_kill(struct lws *wsi)\n-{\n-\tstruct lws_cgi_args args;\n-\tint status, n;\n-\n-\tlwsl_debug(\u0022%s: %p\u005cn\u0022, __func__, wsi);\n-\n-\tif (!wsi-\u003ecgi)\n-\t\treturn 0;\n-\n-\tif (wsi-\u003ecgi-\u003epid \u003e 0) {\n-\t\tn \u003d waitpid(wsi-\u003ecgi-\u003epid, \u0026status, WNOHANG);\n-\t\tif (n \u003e 0) {\n-\t\t\tlwsl_debug(\u0022%s: PID %d reaped\u005cn\u0022, __func__,\n-\t\t\t\t wsi-\u003ecgi-\u003epid);\n-\t\t\tgoto handled;\n-\t\t}\n-\t\t/* kill the process group */\n-\t\tn \u003d kill(-wsi-\u003ecgi-\u003epid, SIGTERM);\n-\t\tlwsl_debug(\u0022%s: SIGTERM child PID %d says %d (errno %d)\u005cn\u0022,\n-\t\t\t __func__, wsi-\u003ecgi-\u003epid, n, errno);\n-\t\tif (n \u003c 0) {\n-\t\t\t/*\n-\t\t\t * hum seen errno\u003d3 when process is listed in ps,\n-\t\t\t * it seems we don't always retain process grouping\n-\t\t\t *\n-\t\t\t * Direct these fallback attempt to the exact child\n-\t\t\t */\n-\t\t\tn \u003d kill(wsi-\u003ecgi-\u003epid, SIGTERM);\n-\t\t\tif (n \u003c 0) {\n-\t\t\t\tn \u003d kill(wsi-\u003ecgi-\u003epid, SIGPIPE);\n-\t\t\t\tif (n \u003c 0) {\n-\t\t\t\t\tn \u003d kill(wsi-\u003ecgi-\u003epid, SIGKILL);\n-\t\t\t\t\tif (n \u003c 0)\n-\t\t\t\t\t\tlwsl_err(\u0022%s: SIGKILL PID %d failed errno %d (maybe zombie)\u005cn\u0022,\n-\t\t\t\t\t\t\t\t__func__, wsi-\u003ecgi-\u003epid, errno);\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\t\t/* He could be unkillable because he's a zombie */\n-\t\tn \u003d 1;\n-\t\twhile (n \u003e 0) {\n-\t\t\tn \u003d waitpid(-wsi-\u003ecgi-\u003epid, \u0026status, WNOHANG);\n-\t\t\tif (n \u003e 0)\n-\t\t\t\tlwsl_debug(\u0022%s: reaped PID %d\u005cn\u0022, __func__, n);\n-\t\t\tif (n \u003c\u003d 0) {\n-\t\t\t\tn \u003d waitpid(wsi-\u003ecgi-\u003epid, \u0026status, WNOHANG);\n-\t\t\t\tif (n \u003e 0)\n-\t\t\t\t\tlwsl_debug(\u0022%s: reaped PID %d\u005cn\u0022, __func__, n);\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-handled:\n-\targs.stdwsi \u003d \u0026wsi-\u003ecgi-\u003estdwsi[0];\n-\n-\tif (wsi-\u003ecgi-\u003epid !\u003d -1) {\n-\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback, wsi,\n-\t\t\t\t\t\tLWS_CALLBACK_CGI_TERMINATED,\n-\t\t\t\t\t\twsi-\u003euser_space,\n-\t\t\t\t\t\t(void *)\u0026args, wsi-\u003ecgi-\u003epid);\n-\t\twsi-\u003ecgi-\u003epid \u003d -1;\n-\t\tif (n \u0026\u0026 !wsi-\u003ecgi-\u003ebeing_closed)\n-\t\t\tlws_close_free_wsi(wsi, 0);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_EXTERN int\n-lws_cgi_kill_terminated(struct lws_context_per_thread *pt)\n-{\n-\tstruct lws_cgi **pcgi, *cgi \u003d NULL;\n-\tint status, n \u003d 1;\n-\n-\twhile (n \u003e 0) {\n-\t\t/* find finished guys but don't reap yet */\n-\t\tn \u003d waitpid(-1, \u0026status, WNOHANG);\n-\t\tif (n \u003c\u003d 0)\n-\t\t\tcontinue;\n-\t\tlwsl_debug(\u0022%s: observed PID %d terminated\u005cn\u0022, __func__, n);\n-\n-\t\tpcgi \u003d \u0026pt-\u003ecgi_list;\n-\n-\t\t/* check all the subprocesses on the cgi list */\n-\t\twhile (*pcgi) {\n-\t\t\t/* get the next one first as list may change */\n-\t\t\tcgi \u003d *pcgi;\n-\t\t\tpcgi \u003d \u0026(*pcgi)-\u003ecgi_list;\n-\n-\t\t\tif (cgi-\u003epid \u003c\u003d 0)\n-\t\t\t\tcontinue;\n-\n-\t\t\t/* finish sending cached headers */\n-\t\t\tif (cgi-\u003eheaders_buf)\n-\t\t\t\tcontinue;\n-\n-\t\t\t/* wait for stdout to be drained */\n-\t\t\tif (cgi-\u003econtent_length \u003e cgi-\u003econtent_length_seen)\n-\t\t\t\tcontinue;\n-\n-\t\t\tif (cgi-\u003econtent_length) {\n-\t\t\t\tlwsl_debug(\u0022%s: wsi %p: expected content length seen: %lld\u005cn\u0022,\n-\t\t\t\t\t__func__, cgi-\u003ewsi, (unsigned long long)cgi-\u003econtent_length_seen);\n-\t\t\t}\n-\n-\t\t\t/* reap it */\n-\t\t\twaitpid(n, \u0026status, WNOHANG);\n-\t\t\t/*\n-\t\t\t * he's already terminated so no need for kill()\n-\t\t\t * but we should do the terminated cgi callback\n-\t\t\t * and close him if he's not already closing\n-\t\t\t */\n-\t\t\tif (n \u003d\u003d cgi-\u003epid) {\n-\t\t\t\tlwsl_debug(\u0022%s: found PID %d on cgi list\u005cn\u0022,\n-\t\t\t\t\t __func__, n);\n-\n-\t\t\t\tif (!cgi-\u003econtent_length) {\n-\t\t\t\t\t/*\n-\t\t\t\t\t * well, if he sends chunked...\n-\t\t\t\t\t * give him 2s after the\n-\t\t\t\t\t * cgi terminated to send buffered\n-\t\t\t\t\t */\n-\t\t\t\t\tcgi-\u003echunked_grace++;\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\n-\t\t\t\t/* defeat kill() */\n-\t\t\t\tcgi-\u003epid \u003d 0;\n-\t\t\t\tlws_cgi_kill(cgi-\u003ewsi);\n-\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tcgi \u003d NULL;\n-\t\t}\n-\t\t/* if not found on the cgi list, as he's one of ours, reap */\n-\t\tif (!cgi) {\n-\t\t\tlwsl_debug(\u0022%s: reading PID %d although no cgi match\u005cn\u0022,\n-\t\t\t\t\t__func__, n);\n-\t\t\twaitpid(n, \u0026status, WNOHANG);\n-\t\t}\n-\t}\n-\n-\tpcgi \u003d \u0026pt-\u003ecgi_list;\n-\n-\t/* check all the subprocesses on the cgi list */\n-\twhile (*pcgi) {\n-\t\t/* get the next one first as list may change */\n-\t\tcgi \u003d *pcgi;\n-\t\tpcgi \u003d \u0026(*pcgi)-\u003ecgi_list;\n-\n-\t\tif (cgi-\u003epid \u003c\u003d 0)\n-\t\t\tcontinue;\n-\n-\t\t/* we deferred killing him after reaping his PID */\n-\t\tif (cgi-\u003echunked_grace) {\n-\t\t\tcgi-\u003echunked_grace++;\n-\t\t\tif (cgi-\u003echunked_grace \u003c 2)\n-\t\t\t\tcontinue;\n-\t\t\tgoto finish_him;\n-\t\t}\n-\n-\t\t/* finish sending cached headers */\n-\t\tif (cgi-\u003eheaders_buf)\n-\t\t\tcontinue;\n-\n-\t\t/* wait for stdout to be drained */\n-\t\tif (cgi-\u003econtent_length \u003e cgi-\u003econtent_length_seen)\n-\t\t\tcontinue;\n-\n-\t\tif (cgi-\u003econtent_length)\n-\t\t\tlwsl_debug(\u0022%s: wsi %p: expected content length seen: %lld\u005cn\u0022,\n-\t\t\t\t__func__, cgi-\u003ewsi,\n-\t\t\t\t(unsigned long long)cgi-\u003econtent_length_seen);\n-\n-\t\t/* reap it */\n-\t\tif (waitpid(cgi-\u003epid, \u0026status, WNOHANG) \u003e 0) {\n-\n-\t\t\tif (!cgi-\u003econtent_length) {\n-\t\t\t\t/*\n-\t\t\t\t * well, if he sends chunked...\n-\t\t\t\t * give him 2s after the\n-\t\t\t\t * cgi terminated to send buffered\n-\t\t\t\t */\n-\t\t\t\tcgi-\u003echunked_grace++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-finish_him:\n-\t\t\tlwsl_debug(\u0022%s: found PID %d on cgi list\u005cn\u0022,\n-\t\t\t\t __func__, cgi-\u003epid);\n-\n-\t\t\t/* defeat kill() */\n-\t\t\tcgi-\u003epid \u003d 0;\n-\t\t\tlws_cgi_kill(cgi-\u003ewsi);\n-\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN struct lws *\n-lws_cgi_get_stdwsi(struct lws *wsi, enum lws_enum_stdinouterr ch)\n-{\n-\tif (!wsi-\u003ecgi)\n-\t\treturn NULL;\n-\n-\treturn wsi-\u003ecgi-\u003estdwsi[ch];\n-}\n \n-#endif\n \n #ifdef LWS_NO_EXTENSIONS\n LWS_EXTERN int\n@@ -3584,61 +2589,6 @@ lws_set_extension_option(struct lws *wsi, const char *ext_name,\n }\n #endif\n \n-#ifdef LWS_WITH_ACCESS_LOG\n-int\n-lws_access_log(struct lws *wsi)\n-{\n-\tchar *p \u003d wsi-\u003eaccess_log.user_agent, ass[512],\n-\t *p1 \u003d wsi-\u003eaccess_log.referrer;\n-\tint l;\n-\n-\tif (!wsi-\u003eaccess_log_pending)\n-\t\treturn 0;\n-\n-\tif (!wsi-\u003eaccess_log.header_log)\n-\t\treturn 0;\n-\n-\tif (!p)\n-\t\tp \u003d \u0022\u0022;\n-\n-\tif (!p1)\n-\t\tp1 \u003d \u0022\u0022;\n-\n-\t/*\n-\t * We do this in two parts to restrict an oversize referrer such that\n-\t * we will always have space left to append an empty useragent, while\n-\t * maintaining the structure of the log text\n-\t */\n-\tl \u003d lws_snprintf(ass, sizeof(ass) - 7, \u0022%s %d %lu \u005c\u0022%s\u0022,\n-\t\t wsi-\u003eaccess_log.header_log,\n-\t\t wsi-\u003eaccess_log.response, wsi-\u003eaccess_log.sent, p1);\n-\tif (strlen(p) \u003e sizeof(ass) - 6 - l)\n-\t\tp[sizeof(ass) - 6 - l] \u003d '\u005c0';\n-\tl +\u003d lws_snprintf(ass + l, sizeof(ass) - 1 - l, \u0022\u005c\u0022 \u005c\u0022%s\u005c\u0022\u005cn\u0022, p);\n-\n-\tif (wsi-\u003evhost-\u003elog_fd !\u003d (int)LWS_INVALID_FILE) {\n-\t\tif (write(wsi-\u003evhost-\u003elog_fd, ass, l) !\u003d l)\n-\t\t\tlwsl_err(\u0022Failed to write log\u005cn\u0022);\n-\t} else\n-\t\tlwsl_err(\u0022%s\u0022, ass);\n-\n-\tif (wsi-\u003eaccess_log.header_log) {\n-\t\tlws_free(wsi-\u003eaccess_log.header_log);\n-\t\twsi-\u003eaccess_log.header_log \u003d NULL;\n-\t}\n-\tif (wsi-\u003eaccess_log.user_agent) {\n-\t\tlws_free(wsi-\u003eaccess_log.user_agent);\n-\t\twsi-\u003eaccess_log.user_agent \u003d NULL;\n-\t}\n-\tif (wsi-\u003eaccess_log.referrer) {\n-\t\tlws_free(wsi-\u003eaccess_log.referrer);\n-\t\twsi-\u003eaccess_log.referrer \u003d NULL;\n-\t}\n-\twsi-\u003eaccess_log_pending \u003d 0;\n-\n-\treturn 0;\n-}\n-#endif\n \n void\n lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs)\n@@ -4091,253 +3041,3 @@ lws_stats_atomic_max(struct lws_context * context,\n \n #endif\n \n-LWS_VISIBLE LWS_EXTERN struct lws_ring *\n-lws_ring_create(size_t element_len, size_t count, void (*destroy_element)(void *))\n-{\n-\tstruct lws_ring *ring \u003d lws_malloc(sizeof(*ring), \u0022ring create\u0022);\n-\n-\tif (!ring)\n-\t\treturn NULL;\n-\n-\tring-\u003ebuflen \u003d count * element_len;\n-\tring-\u003eelement_len \u003d element_len;\n-\tring-\u003ehead \u003d 0;\n-\tring-\u003eoldest_tail \u003d 0;\n-\tring-\u003edestroy_element \u003d destroy_element;\n-\n-\tring-\u003ebuf \u003d lws_malloc(ring-\u003ebuflen, \u0022ring buf\u0022);\n-\tif (!ring-\u003ebuf) {\n-\t\tlws_free(ring);\n-\n-\t\treturn NULL;\n-\t}\n-\n-\treturn ring;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN void\n-lws_ring_destroy(struct lws_ring *ring)\n-{\n-\tif (ring-\u003edestroy_element)\n-\t\twhile (ring-\u003eoldest_tail !\u003d ring-\u003ehead) {\n-\t\t\tring-\u003edestroy_element((uint8_t *)ring-\u003ebuf + ring-\u003eoldest_tail);\n-\t\t\tring-\u003eoldest_tail \u003d (ring-\u003eoldest_tail + ring-\u003eelement_len) %\n-\t\t\t\t\tring-\u003ebuflen;\n-\t\t}\n-\tif (ring-\u003ebuf)\n-\t\tlws_free_set_NULL(ring-\u003ebuf);\n-\n-\tlws_free(ring);\n-}\n-\n-LWS_VISIBLE LWS_EXTERN size_t\n-lws_ring_get_count_free_elements(struct lws_ring *ring)\n-{\n-\tint f;\n-\n-\t/*\n-\t * possible ringbuf patterns\n-\t *\n-\t * h \u003d\u003d t\n-\t * |--------t***h---|\n-\t * |**h-----------t*|\n-\t * |t**************h|\n-\t * |*****ht*********|\n-\t */\n-\tif (ring-\u003ehead \u003d\u003d ring-\u003eoldest_tail)\n-\t\tf \u003d ring-\u003ebuflen - ring-\u003eelement_len;\n-\telse\n-\t\tif (ring-\u003ehead \u003c ring-\u003eoldest_tail)\n-\t\t\tf \u003d (ring-\u003eoldest_tail - ring-\u003ehead) - ring-\u003eelement_len;\n-\t\telse\n-\t\t\tf \u003d (ring-\u003ebuflen - ring-\u003ehead) + ring-\u003eoldest_tail - ring-\u003eelement_len;\n-\n-\tif (f \u003c 2)\n-\t\treturn 0;\n-\n-\treturn f / ring-\u003eelement_len;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN size_t\n-lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail)\n-{\tint f;\n-\n-\tif (!tail)\n-\t\ttail \u003d \u0026ring-\u003eoldest_tail;\n-\t/*\n-\t * possible ringbuf patterns\n-\t *\n-\t * h \u003d\u003d t\n-\t * |--------t***h---|\n-\t * |**h-----------t*|\n-\t * |t**************h|\n-\t * |*****ht*********|\n-\t */\n-\tif (ring-\u003ehead \u003d\u003d *tail)\n-\t\tf \u003d 0;\n-\telse\n-\t\tif (ring-\u003ehead \u003e *tail)\n-\t\t\tf \u003d (ring-\u003ehead - *tail);\n-\t\telse\n-\t\t\tf \u003d (ring-\u003ebuflen - *tail) + ring-\u003ehead;\n-\n-\treturn f / ring-\u003eelement_len;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start, size_t *bytes)\n-{\n-\tint n;\n-\n-\t/* n is how many bytes the whole fifo can take */\n-\tn \u003d lws_ring_get_count_free_elements(ring) * ring-\u003eelement_len;\n-\n-\tif (!n)\n-\t\treturn 1;\n-\n-\tif (ring-\u003ehead + n \u003e ring-\u003ebuflen) {\n-\t\t*start \u003d (void *)(((uint8_t *)ring-\u003ebuf) + ring-\u003ehead);\n-\t\t*bytes \u003d ring-\u003ebuflen - ring-\u003ehead;\n-\n-\t\treturn 0;\n-\t}\n-\n-\t*start \u003d (void *)(((uint8_t *)ring-\u003ebuf) + ring-\u003ehead);\n-\t*bytes \u003d n;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN void\n-lws_ring_bump_head(struct lws_ring *ring, size_t bytes)\n-{\n-\tring-\u003ehead \u003d (ring-\u003ehead + bytes) % ring-\u003ebuflen;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN size_t\n-lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count)\n-{\n-\tconst uint8_t *osrc \u003d src;\n-\tint m, n;\n-\n-\t/* n is how many bytes the whole fifo can take */\n-\tn \u003d lws_ring_get_count_free_elements(ring) * ring-\u003eelement_len;\n-\n-\t/* restrict n to how much we want to insert */\n-\tif ((size_t)n \u003e max_count * ring-\u003eelement_len)\n-\t\tn \u003d max_count * ring-\u003eelement_len;\n-\n-\t/*\n-\t * n is legal to insert, but as an optimization we can cut the\n-\t * insert into one or two memcpys, depending on if it wraps\n-\t */\n-\tif (ring-\u003ehead + n \u003e ring-\u003ebuflen) {\n-\n-\t\t/*\n-\t\t * He does wrap. The first memcpy should take us up to\n-\t\t * the end of the buffer\n-\t\t */\n-\n-\t\tm \u003d ring-\u003ebuflen - ring-\u003ehead;\n-\t\tmemcpy(((uint8_t *)ring-\u003ebuf) + ring-\u003ehead, src, m);\n-\t\t/* we know it will wrap exactly back to zero */\n-\t\tring-\u003ehead \u003d 0;\n-\n-\t\t/* adapt the second memcpy for what we already did */\n-\n-\t\tsrc \u003d ((uint8_t *)src) + m;\n-\t\tn -\u003d m;\n-\t}\n-\n-\tmemcpy(((uint8_t *)ring-\u003ebuf) + ring-\u003ehead, src, n);\n-\tring-\u003ehead \u003d (ring-\u003ehead + n) % ring-\u003ebuflen;\n-\n-\treturn (((uint8_t *)src + n) - osrc) / ring-\u003eelement_len;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN size_t\n-lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,\n-\t\t size_t max_count)\n-{\n-\tuint8_t *odest \u003d dest;\n-\tvoid *orig_tail \u003d tail;\n-\tuint32_t fake_tail;\n-\tint m, n;\n-\n-\tif (!tail) {\n-\t\tfake_tail \u003d ring-\u003eoldest_tail;\n-\t\ttail \u003d \u0026fake_tail;\n-\t}\n-\n-\t/* n is how many bytes the whole fifo has for us */\n-\tn \u003d lws_ring_get_count_waiting_elements(ring, tail) * ring-\u003eelement_len;\n-\n-\t/* restrict n to how much we want to insert */\n-\tif ((size_t)n \u003e max_count * ring-\u003eelement_len)\n-\t\tn \u003d max_count * ring-\u003eelement_len;\n-\n-\tif (!dest) {\n-\t\t*tail \u003d ((*tail) + n) % ring-\u003ebuflen;\n-\t\tif (!orig_tail) /* single tail */\n-\t\t\tlws_ring_update_oldest_tail(ring, *tail);\n-\n-\t\treturn n / ring-\u003eelement_len;\n-\t}\n-\tif (*tail + n \u003e ring-\u003ebuflen) {\n-\n-\t\t/*\n-\t\t * He does wrap. The first memcpy should take us up to\n-\t\t * the end of the buffer\n-\t\t */\n-\n-\t\tm \u003d ring-\u003ebuflen - *tail;\n-\t\tmemcpy(dest, ((uint8_t *)ring-\u003ebuf) + *tail, m);\n-\t\t/* we know it will wrap exactly back to zero */\n-\t\t*tail \u003d 0;\n-\n-\t\t/* adapt the second memcpy for what we already did */\n-\n-\t\tdest \u003d ((uint8_t *)dest) + m;\n-\t\tn -\u003d m;\n-\t}\n-\n-\tmemcpy(dest, ((uint8_t *)ring-\u003ebuf) + *tail, n);\n-\n-\t*tail \u003d ((*tail) + n) % ring-\u003ebuflen;\n-\tif (!orig_tail) /* single tail */\n-\t\tlws_ring_update_oldest_tail(ring, *tail);\n-\n-\treturn (((uint8_t *)dest + n) - odest) / ring-\u003eelement_len;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN const void *\n-lws_ring_get_element(struct lws_ring *ring, uint32_t *tail)\n-{\n-\tif (!tail)\n-\t\ttail \u003d \u0026ring-\u003eoldest_tail;\n-\n-\tif (*tail \u003d\u003d ring-\u003ehead)\n-\t\treturn NULL;\n-\n-\treturn ((uint8_t *)ring-\u003ebuf) + *tail;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN void\n-lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail)\n-{\n-\tif (!ring-\u003edestroy_element) {\n-\t\tring-\u003eoldest_tail \u003d tail;\n-\t\treturn;\n-\t}\n-\n-\twhile (ring-\u003eoldest_tail !\u003d tail) {\n-\t\tring-\u003edestroy_element((uint8_t *)ring-\u003ebuf + ring-\u003eoldest_tail);\n-\t\tring-\u003eoldest_tail \u003d (ring-\u003eoldest_tail + ring-\u003eelement_len) % ring-\u003ebuflen;\n-\t}\n-}\n-\n-LWS_VISIBLE LWS_EXTERN uint32_t\n-lws_ring_get_oldest_tail(struct lws_ring *ring)\n-{\n-\treturn ring-\u003eoldest_tail;\n-}\ndiff --git a/lib/libwebsockets.h b/lib/libwebsockets.h\nindex 5d358fd..ef996c5 100644\n--- a/lib/libwebsockets.h\n+++ b/lib/libwebsockets.h\n@@ -314,13 +314,34 @@ lwsl_timestamp(int level, char *p, int len);\n #endif\n \n /**\n+ * lwsl_hexdump() - helper to hexdump a buffer\n+ *\n+ * \u005cparam level: one of LLL_ constants\n+ * \u005cparam buf: buffer start to dump\n+ * \u005cparam len: length of buffer to dump\n+ *\n+ * If \u005cp level is visible, does a nice hexdump -C style dump of \u005cp buf for\n+ * \u005cp len bytes. This can be extremely convenient while debugging.\n+ */\n+LWS_VISIBLE LWS_EXTERN void\n+lwsl_hexdump_level(int level, const void *vbuf, size_t len);\n+\n+/**\n * lwsl_hexdump() - helper to hexdump a buffer (DEBUG builds only)\n *\n * \u005cparam buf: buffer start to dump\n * \u005cparam len: length of buffer to dump\n+ *\n+ * Calls through to lwsl_hexdump_level(LLL_DEBUG, ... for compatability.\n+ * It's better to use lwsl_hexdump_level(level, ... directly so you can control\n+ * the visibility.\n */\n-LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(const void *buf, size_t len);\n+LWS_VISIBLE LWS_EXTERN void\n+lwsl_hexdump(const void *buf, size_t len);\n \n+/**\n+ * lws_is_be() - returns nonzero if the platform is Big Endian\n+ */\n static LWS_INLINE int lws_is_be(void) {\n \tconst int probe \u003d ~0xff;\n \n@@ -335,7 +356,8 @@ static LWS_INLINE int lws_is_be(void) {\n *\t\t\tthe default stderr one.\n *\n *\tlog level defaults to \u0022err\u0022, \u0022warn\u0022 and \u0022notice\u0022 contexts enabled and\n- *\temission on stderr.\n+ *\temission on stderr. If stderr is a tty (according to isatty()) then\n+ *\tthe output is coloured according to the log level using ANSI escapes.\n */\n LWS_VISIBLE LWS_EXTERN void\n lws_set_log_level(int level,\ndiff --git a/lib/lws-genhash.c b/lib/lws-genhash.c\ndeleted file mode 100644\nindex 26bdb31..0000000\n--- a/lib/lws-genhash.c\n+++ /dev/null\n@@ -1,149 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- *\n- * lws_genhash provides a hash abstraction api in lws that works the same\n- * whether you are using openssl or mbedtls hash functions underneath.\n- */\n-#include \u0022libwebsockets.h\u0022\n-\n-size_t\n-lws_genhash_size(int type)\n-{\n-\tswitch(type) {\n-\tcase LWS_GENHASH_TYPE_SHA1:\n-\t\treturn 20;\n-\tcase LWS_GENHASH_TYPE_SHA256:\n-\t\treturn 32;\n-\tcase LWS_GENHASH_TYPE_SHA512:\n-\t\treturn 64;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-int\n-lws_genhash_init(struct lws_genhash_ctx *ctx, int type)\n-{\n-\tctx-\u003etype \u003d type;\n-\n-#if defined(LWS_WITH_MBEDTLS)\n-\tswitch (ctx-\u003etype) {\n-\tcase LWS_GENHASH_TYPE_SHA1:\n-\t\tmbedtls_sha1_init(\u0026ctx-\u003eu.sha1);\n-\t\tmbedtls_sha1_starts(\u0026ctx-\u003eu.sha1);\n-\t\tbreak;\n-\tcase LWS_GENHASH_TYPE_SHA256:\n-\t\tmbedtls_sha256_init(\u0026ctx-\u003eu.sha256);\n-\t\tmbedtls_sha256_starts(\u0026ctx-\u003eu.sha256, 0);\n-\t\tbreak;\n-\tcase LWS_GENHASH_TYPE_SHA512:\n-\t\tmbedtls_sha512_init(\u0026ctx-\u003eu.sha512);\n-\t\tmbedtls_sha512_starts(\u0026ctx-\u003eu.sha512, 0);\n-\t\tbreak;\n-\tdefault:\n-\t\treturn 1;\n-\t}\n-#else\n-\tctx-\u003emdctx \u003d EVP_MD_CTX_create();\n-\tif (!ctx-\u003emdctx)\n-\t\treturn 1;\n-\n-\tswitch (ctx-\u003etype) {\n-\tcase LWS_GENHASH_TYPE_SHA1:\n-\t\tctx-\u003eevp_type \u003d EVP_sha1();\n-\t\tbreak;\n-\tcase LWS_GENHASH_TYPE_SHA256:\n-\t\tctx-\u003eevp_type \u003d EVP_sha256();\n-\t\tbreak;\n-\tcase LWS_GENHASH_TYPE_SHA512:\n-\t\tctx-\u003eevp_type \u003d EVP_sha512();\n-\t\tbreak;\n-\tdefault:\n-\t\treturn 1;\n-\t}\n-\n-\tif (EVP_DigestInit_ex(ctx-\u003emdctx, ctx-\u003eevp_type, NULL) !\u003d 1) {\n-\t\tEVP_MD_CTX_destroy(ctx-\u003emdctx);\n-\n-\t\treturn 1;\n-\t}\n-\n-#endif\n-\treturn 0;\n-}\n-\n-int\n-lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len)\n-{\n-#if defined(LWS_WITH_MBEDTLS)\n-\tswitch (ctx-\u003etype) {\n-\tcase LWS_GENHASH_TYPE_SHA1:\n-\t\tmbedtls_sha1_update(\u0026ctx-\u003eu.sha1, in, len);\n-\t\tbreak;\n-\tcase LWS_GENHASH_TYPE_SHA256:\n-\t\tmbedtls_sha256_update(\u0026ctx-\u003eu.sha256, in, len);\n-\t\tbreak;\n-\tcase LWS_GENHASH_TYPE_SHA512:\n-\t\tmbedtls_sha512_update(\u0026ctx-\u003eu.sha512, in, len);\n-\t\tbreak;\n-\t}\n-#else\n-\treturn EVP_DigestUpdate(ctx-\u003emdctx, in, len) !\u003d 1;\n-#endif\n-\n-\treturn 0;\n-}\n-\n-int\n-lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result)\n-{\n-#if defined(LWS_WITH_MBEDTLS)\n-\tswitch (ctx-\u003etype) {\n-\tcase LWS_GENHASH_TYPE_SHA1:\n-\t\tmbedtls_sha1_finish(\u0026ctx-\u003eu.sha1, result);\n-\t\tmbedtls_sha1_free(\u0026ctx-\u003eu.sha1);\n-\t\tbreak;\n-\tcase LWS_GENHASH_TYPE_SHA256:\n-\t\tmbedtls_sha256_finish(\u0026ctx-\u003eu.sha256, result);\n-\t\tmbedtls_sha256_free(\u0026ctx-\u003eu.sha256);\n-\t\tbreak;\n-\tcase LWS_GENHASH_TYPE_SHA512:\n-\t\tmbedtls_sha512_finish(\u0026ctx-\u003eu.sha512, result);\n-\t\tmbedtls_sha512_free(\u0026ctx-\u003eu.sha512);\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-#else\n-\tunsigned int len;\n-\tint ret \u003d 0;\n-\n-\tif (result)\n-\t\tret \u003d EVP_DigestFinal_ex(ctx-\u003emdctx, result, \u0026len) !\u003d 1;\n-\n-\t(void)len;\n-\n-\tEVP_MD_CTX_destroy(ctx-\u003emdctx);\n-\n-\treturn ret;\n-#endif\n-}\n-\n-\ndiff --git a/lib/lws-plat-esp32.c b/lib/lws-plat-esp32.c\ndeleted file mode 100644\nindex b5adabe..0000000\n--- a/lib/lws-plat-esp32.c\n+++ /dev/null\n@@ -1,1756 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-#include \u0022freertos/timers.h\u0022\n-#include \u003cesp_attr.h\u003e\n-#include \u003cesp_system.h\u003e\n-\n-/*\n- * included from libwebsockets.c for unix builds\n- */\n-\n-unsigned long long time_in_microseconds(void)\n-{\n-\tstruct timeval tv;\n-\tgettimeofday(\u0026tv, NULL);\n-\treturn ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;\n-}\n-\n-LWS_VISIBLE int\n-lws_get_random(struct lws_context *context, void *buf, int len)\n-{\n-\tuint8_t *pb \u003d buf;\n-\n-\twhile (len) {\n-\t\tuint32_t r \u003d esp_random();\n-\t\tuint8_t *p \u003d (uint8_t *)\u0026r;\n-\t\tint b \u003d 4;\n-\n-\t\tif (len \u003c b)\n-\t\t\tb \u003d len;\n-\n-\t\tlen -\u003d b;\n-\n-\t\twhile (b--)\n-\t\t\t*pb++ \u003d p[b];\n-\t}\n-\n-\treturn pb - (uint8_t *)buf;\n-}\n-\n-LWS_VISIBLE int\n-lws_send_pipe_choked(struct lws *wsi)\n-{\n-\tstruct lws *wsi_eff \u003d wsi;\n-\tfd_set writefds;\n-\tstruct timeval tv \u003d { 0, 0 };\n-#if defined(LWS_WITH_HTTP2)\n-\twsi_eff \u003d lws_get_network_wsi(wsi);\n-#endif\n-\n-\t/* treat the fact we got a truncated send pending as if we're choked */\n-\tif (wsi_eff-\u003etrunc_len)\n-\t\treturn 1;\n-\n-\tFD_ZERO(\u0026writefds);\n-\tFD_SET(wsi_eff-\u003edesc.sockfd, \u0026writefds);\n-\n-\tif (select(wsi_eff-\u003edesc.sockfd + 1, NULL, \u0026writefds, NULL, \u0026tv) \u003c 1)\n-\t\treturn 1;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_poll_listen_fd(struct lws_pollfd *fd)\n-{\n-\tfd_set readfds;\n-\tstruct timeval tv \u003d { 0, 0 };\n-\n-\tFD_ZERO(\u0026readfds);\n-\tFD_SET(fd-\u003efd, \u0026readfds);\n-\n-\treturn select(fd-\u003efd + 1, \u0026readfds, NULL, NULL, \u0026tv);\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service_pt(struct lws *wsi)\n-{\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n-{\n-\tprintf(\u0022%d: %s\u0022, level, line);\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n-{\n-\tstruct lws_context_per_thread *pt;\n-\tint n \u003d -1, m, c;\n-\n-\t/* stay dead once we are dead */\n-\n-\tif (!context || !context-\u003evhost_list)\n-\t\treturn 1;\n-\n-\tpt \u003d \u0026context-\u003ept[tsi];\n-\tlws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);\n-\n-\t{\n-\t\tunsigned long m \u003d lws_now_secs();\n-\n-\t\tif (m \u003e context-\u003etime_last_state_dump) {\n-\t\t\tcontext-\u003etime_last_state_dump \u003d m;\n-\t\t\tn \u003d esp_get_free_heap_size();\n-\t\t\tif (n !\u003d context-\u003elast_free_heap) {\n-\t\t\t\tif (n \u003e context-\u003elast_free_heap)\n-\t\t\t\t\tlwsl_notice(\u0022 heap :%d (+%d)\u005cn\u0022, n,\n-\t\t\t\t\t\t n - context-\u003elast_free_heap);\n-\t\t\t\telse\n-\t\t\t\t\tlwsl_notice(\u0022 heap :%d (-%d)\u005cn\u0022, n,\n-\t\t\t\t\t\t context-\u003elast_free_heap - n);\n-\t\t\t\tcontext-\u003elast_free_heap \u003d n;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\tif (timeout_ms \u003c 0)\n-\t\tgoto faked_service;\n-\n-\tif (!context-\u003eservice_tid_detected) {\n-\t\tstruct lws _lws;\n-\n-\t\tmemset(\u0026_lws, 0, sizeof(_lws));\n-\t\t_lws.context \u003d context;\n-\n-\t\tcontext-\u003eservice_tid_detected \u003d\n-\t\t\tcontext-\u003evhost_list-\u003eprotocols[0].callback(\n-\t\t\t\u0026_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);\n-\t}\n-\tcontext-\u003eservice_tid \u003d context-\u003eservice_tid_detected;\n-\n-\t/*\n-\t * is there anybody with pending stuff that needs service forcing?\n-\t */\n-\tif (!lws_service_adjust_timeout(context, 1, tsi)) {\n-\t\t/* -1 timeout means just do forced service */\n-\t\t_lws_plat_service_tsi(context, -1, pt-\u003etid);\n-\t\t/* still somebody left who wants forced service? */\n-\t\tif (!lws_service_adjust_timeout(context, 1, pt-\u003etid))\n-\t\t\t/* yes... come back again quickly */\n-\t\t\ttimeout_ms \u003d 0;\n-\t}\n-\n-//\tn \u003d poll(pt-\u003efds, pt-\u003efds_count, timeout_ms);\n-\t{\n-\t\tfd_set readfds, writefds, errfds;\n-\t\tstruct timeval tv \u003d { timeout_ms / 1000,\n-\t\t\t\t (timeout_ms % 1000) * 1000 }, *ptv \u003d \u0026tv;\n-\t\tint max_fd \u003d 0;\n-\t\tFD_ZERO(\u0026readfds);\n-\t\tFD_ZERO(\u0026writefds);\n-\t\tFD_ZERO(\u0026errfds);\n-\n-\t\tfor (n \u003d 0; n \u003c pt-\u003efds_count; n++) {\n-\t\t\tpt-\u003efds[n].revents \u003d 0;\n-\t\t\tif (pt-\u003efds[n].fd \u003e\u003d max_fd)\n-\t\t\t\tmax_fd \u003d pt-\u003efds[n].fd;\n-\t\t\tif (pt-\u003efds[n].events \u0026 LWS_POLLIN)\n-\t\t\t\tFD_SET(pt-\u003efds[n].fd, \u0026readfds);\n-\t\t\tif (pt-\u003efds[n].events \u0026 LWS_POLLOUT)\n-\t\t\t\tFD_SET(pt-\u003efds[n].fd, \u0026writefds);\n-\t\t\tFD_SET(pt-\u003efds[n].fd, \u0026errfds);\n-\t\t}\n-\n-\t\tn \u003d select(max_fd + 1, \u0026readfds, \u0026writefds, \u0026errfds, ptv);\n-\t\tfor (n \u003d 0; n \u003c pt-\u003efds_count; n++) {\n-\t\t\tif (FD_ISSET(pt-\u003efds[n].fd, \u0026readfds))\n-\t\t\t\tpt-\u003efds[n].revents |\u003d LWS_POLLIN;\n-\t\t\tif (FD_ISSET(pt-\u003efds[n].fd, \u0026writefds))\n-\t\t\t\tpt-\u003efds[n].revents |\u003d LWS_POLLOUT;\n-\t\t\tif (FD_ISSET(pt-\u003efds[n].fd, \u0026errfds))\n-\t\t\t\tpt-\u003efds[n].revents |\u003d LWS_POLLHUP;\n-\t\t}\n-\t}\n-\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\tif (!pt-\u003erx_draining_ext_list \u0026\u0026\n-\t !lws_ssl_anybody_has_buffered_read_tsi(context, tsi) \u0026\u0026 !n) {\n-#else\n-\tif (!pt-\u003erx_draining_ext_list \u0026\u0026 !n) /* poll timeout */ {\n-#endif\n-\t\tlws_service_fd_tsi(context, NULL, tsi);\n-\t\treturn 0;\n-\t}\n-\n-faked_service:\n-\tm \u003d lws_service_flag_pending(context, tsi);\n-\tif (m)\n-\t\tc \u003d -1; /* unknown limit */\n-\telse\n-\t\tif (n \u003c 0) {\n-\t\t\tif (LWS_ERRNO !\u003d LWS_EINTR)\n-\t\t\t\treturn -1;\n-\t\t\treturn 0;\n-\t\t} else\n-\t\t\tc \u003d n;\n-\n-\t/* any socket with events to service? */\n-\tfor (n \u003d 0; n \u003c pt-\u003efds_count \u0026\u0026 c; n++) {\n-\t\tif (!pt-\u003efds[n].revents)\n-\t\t\tcontinue;\n-\n-\t\tc--;\n-\n-\t\tm \u003d lws_service_fd_tsi(context, \u0026pt-\u003efds[n], tsi);\n-\t\tif (m \u003c 0)\n-\t\t\treturn -1;\n-\t\t/* if something closed, retry this slot */\n-\t\tif (m)\n-\t\t\tn--;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_check_connection_error(struct lws *wsi)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_service(struct lws_context *context, int timeout_ms)\n-{\n-\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)\n-{\n-\tint optval \u003d 1;\n-\tsocklen_t optlen \u003d sizeof(optval);\n-\n-#if defined(__APPLE__) || \u005c\n- defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \u005c\n- defined(__NetBSD__) || \u005c\n- defined(__OpenBSD__)\n-\tstruct protoent *tcp_proto;\n-#endif\n-\n-\tif (vhost-\u003eka_time) {\n-\t\t/* enable keepalive on this socket */\n-\t\toptval \u003d 1;\n-\t\tif (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,\n-\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n-\t\t\treturn 1;\n-\n-#if defined(__APPLE__) || \u005c\n- defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \u005c\n- defined(__NetBSD__) || \u005c\n- defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun)\n-\n-\t\t/*\n-\t\t * didn't find a way to set these per-socket, need to\n-\t\t * tune kernel systemwide values\n-\t\t */\n-#else\n-\t\t/* set the keepalive conditions we want on it too */\n-\t\toptval \u003d vhost-\u003eka_time;\n-\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,\n-\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n-\t\t\treturn 1;\n-\n-\t\toptval \u003d vhost-\u003eka_interval;\n-\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,\n-\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n-\t\t\treturn 1;\n-\n-\t\toptval \u003d vhost-\u003eka_probes;\n-\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,\n-\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n-\t\t\treturn 1;\n-#endif\n-\t}\n-\n-\t/* Disable Nagle */\n-\toptval \u003d 1;\n-\tif (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, \u0026optval, optlen) \u003c 0)\n-\t\treturn 1;\n-\n-\t/* We are nonblocking... */\n-\tif (fcntl(fd, F_SETFL, O_NONBLOCK) \u003c 0)\n-\t\treturn 1;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n-{\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_context_early_init(void)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_early_destroy(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_late_destroy(struct lws_context *context)\n-{\n-#ifdef LWS_WITH_PLUGINS\n-\tif (context-\u003eplugin_list)\n-\t\tlws_plat_plugins_destroy(context);\n-#endif\n-\n-\tif (context-\u003elws_lookup)\n-\t\tlws_free(context-\u003elws_lookup);\n-}\n-\n-/* cast a struct sockaddr_in6 * into addr for ipv6 */\n-\n-LWS_VISIBLE int\n-lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,\n-\t\t size_t addrlen)\n-{\n-#if 0\n-\tint rc \u003d -1;\n-\n-\tstruct ifaddrs *ifr;\n-\tstruct ifaddrs *ifc;\n-#ifdef LWS_WITH_IPV6\n-\tstruct sockaddr_in6 *addr6 \u003d (struct sockaddr_in6 *)addr;\n-#endif\n-\n-\tgetifaddrs(\u0026ifr);\n-\tfor (ifc \u003d ifr; ifc !\u003d NULL \u0026\u0026 rc; ifc \u003d ifc-\u003eifa_next) {\n-\t\tif (!ifc-\u003eifa_addr)\n-\t\t\tcontinue;\n-\n-\t\tlwsl_info(\u0022 interface %s vs %s\u005cn\u0022, ifc-\u003eifa_name, ifname);\n-\n-\t\tif (strcmp(ifc-\u003eifa_name, ifname))\n-\t\t\tcontinue;\n-\n-\t\tswitch (ifc-\u003eifa_addr-\u003esa_family) {\n-\t\tcase AF_INET:\n-#ifdef LWS_WITH_IPV6\n-\t\t\tif (ipv6) {\n-\t\t\t\t/* map IPv4 to IPv6 */\n-\t\t\t\tbzero((char *)\u0026addr6-\u003esin6_addr,\n-\t\t\t\t\t\tsizeof(struct in6_addr));\n-\t\t\t\taddr6-\u003esin6_addr.s6_addr[10] \u003d 0xff;\n-\t\t\t\taddr6-\u003esin6_addr.s6_addr[11] \u003d 0xff;\n-\t\t\t\tmemcpy(\u0026addr6-\u003esin6_addr.s6_addr[12],\n-\t\t\t\t\t\u0026((struct sockaddr_in *)ifc-\u003eifa_addr)-\u003esin_addr,\n-\t\t\t\t\t\t\tsizeof(struct in_addr));\n-\t\t\t} else\n-#endif\n-\t\t\t\tmemcpy(addr,\n-\t\t\t\t\t(struct sockaddr_in *)ifc-\u003eifa_addr,\n-\t\t\t\t\t\t sizeof(struct sockaddr_in));\n-\t\t\tbreak;\n-#ifdef LWS_WITH_IPV6\n-\t\tcase AF_INET6:\n-\t\t\tmemcpy(\u0026addr6-\u003esin6_addr,\n-\t\t\t \u0026((struct sockaddr_in6 *)ifc-\u003eifa_addr)-\u003esin6_addr,\n-\t\t\t\t\t\t sizeof(struct in6_addr));\n-\t\t\tbreak;\n-#endif\n-\t\tdefault:\n-\t\t\tcontinue;\n-\t\t}\n-\t\trc \u003d 0;\n-\t}\n-\n-\tfreeifaddrs(ifr);\n-\n-\tif (rc \u003d\u003d -1) {\n-\t\t/* check if bind to IP address */\n-#ifdef LWS_WITH_IPV6\n-\t\tif (inet_pton(AF_INET6, ifname, \u0026addr6-\u003esin6_addr) \u003d\u003d 1)\n-\t\t\trc \u003d 0;\n-\t\telse\n-#endif\n-\t\tif (inet_pton(AF_INET, ifname, \u0026addr-\u003esin_addr) \u003d\u003d 1)\n-\t\t\trc \u003d 0;\n-\t}\n-\n-\treturn rc;\n-#endif\n-\n-\treturn -1;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\n-\tpt-\u003efds[pt-\u003efds_count++].revents \u003d 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_delete_socket_from_fds(struct lws_context *context,\n-\t\t\t\t\t\tstruct lws *wsi, int m)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\n-\tpt-\u003efds_count--;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_service_periodic(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_change_pollfd(struct lws_context *context,\n-\t\t struct lws *wsi, struct lws_pollfd *pfd)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE const char *\n-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n-{\n-\treturn inet_ntop(af, src, dst, cnt);\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_inet_pton(int af, const char *src, void *dst)\n-{\n-\treturn 1; // inet_pton(af, src, dst);\n-}\n-\n-LWS_VISIBLE lws_fop_fd_t IRAM_ATTR\n-_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,\n-\t\t const char *vpath, lws_fop_flags_t *flags)\n-{\n-\tstruct stat stat_buf;\n-\tlws_fop_fd_t fop_fd;\n-\tint ret \u003d open(filename, *flags, 0664);\n-\n-\tif (ret \u003c 0)\n-\t\treturn NULL;\n-\n-\tif (fstat(ret, \u0026stat_buf) \u003c 0)\n-\t\tgoto bail;\n-\n-\tfop_fd \u003d lws_malloc(sizeof(*fop_fd), \u0022fops open\u0022);\n-\tif (!fop_fd)\n-\t\tgoto bail;\n-\n-\tfop_fd-\u003efops \u003d fops;\n-\tfop_fd-\u003efd \u003d ret;\n-\tfop_fd-\u003eflags \u003d *flags;\n-\tfop_fd-\u003efilesystem_priv \u003d NULL; /* we don't use it */\n-\tfop_fd-\u003epos \u003d 0;\n-\tfop_fd-\u003elen \u003d stat_buf.st_size;\n-\n-\treturn fop_fd;\n-\n-bail:\n-\tclose(ret);\n-\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE int IRAM_ATTR\n-_lws_plat_file_close(lws_fop_fd_t *fops_fd)\n-{\n-\tint fd \u003d (*fops_fd)-\u003efd;\n-\n-\tlws_free(*fops_fd);\n-\t*fops_fd \u003d NULL;\n-\n-\treturn close(fd);\n-}\n-\n-LWS_VISIBLE lws_fileofs_t IRAM_ATTR\n-_lws_plat_file_seek_cur(lws_fop_fd_t fops_fd, lws_fileofs_t offset)\n-{\n-\treturn lseek(fops_fd-\u003efd, offset, SEEK_CUR);\n-}\n-\n-LWS_VISIBLE int IRAM_ATTR\n-_lws_plat_file_read(lws_fop_fd_t fops_fd, lws_filepos_t *amount,\n-\t\t uint8_t *buf, lws_filepos_t len)\n-{\n-\tlong n;\n-\n-\tn \u003d read(fops_fd-\u003efd, buf, len);\n-\tif (n \u003d\u003d -1) {\n-\t\t*amount \u003d 0;\n-\t\treturn -1;\n-\t}\n-\tfops_fd-\u003epos +\u003d n;\n-\t*amount \u003d n;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int IRAM_ATTR\n-_lws_plat_file_write(lws_fop_fd_t fops_fd, lws_filepos_t *amount,\n-\t\t uint8_t *buf, lws_filepos_t len)\n-{\n-\tlong n;\n-\n-\tn \u003d write(fops_fd-\u003efd, buf, len);\n-\tif (n \u003d\u003d -1) {\n-\t\t*amount \u003d 0;\n-\t\treturn -1;\n-\t}\n-\tfops_fd-\u003epos +\u003d n;\n-\t*amount \u003d n;\n-\n-\treturn 0;\n-}\n-\n-#if defined(LWS_WITH_HTTP2)\n-/*\n- * These are the default SETTINGS used on this platform. The user\n- * can selectively modify them for a vhost during vhost creation.\n- */\n-const struct http2_settings const lws_h2_defaults_esp32 \u003d { {\n-\t1,\n-\t/* H2SET_HEADER_TABLE_SIZE */\t\t\t 512,\n-\t/* H2SET_ENABLE_PUSH */\t\t\t\t 0,\n-\t/* H2SET_MAX_CONCURRENT_STREAMS */\t\t 8,\n-\t/* H2SET_INITIAL_WINDOW_SIZE */\t\t 65535,\n-\t/* H2SET_MAX_FRAME_SIZE */\t\t 16384,\n-\t/* H2SET_MAX_HEADER_LIST_SIZE */\t \t 512,\n-}};\n-#endif\n-\n-LWS_VISIBLE int\n-lws_plat_init(struct lws_context *context,\n-\t struct lws_context_creation_info *info)\n-{\n-\t/* master context has the global fd lookup array */\n-\tcontext-\u003elws_lookup \u003d lws_zalloc(sizeof(struct lws *) *\n-\t\t\t\t\t context-\u003emax_fds, \u0022esp32 lws_lookup\u0022);\n-\tif (context-\u003elws_lookup \u003d\u003d NULL) {\n-\t\tlwsl_err(\u0022OOM on lws_lookup array for %d connections\u005cn\u0022,\n-\t\t\t context-\u003emax_fds);\n-\t\treturn 1;\n-\t}\n-\n-\tlwsl_notice(\u0022 mem: platform fd map: %5lu bytes\u005cn\u0022,\n-\t\t (unsigned long)(sizeof(struct lws *) * context-\u003emax_fds));\n-\n-#ifdef LWS_WITH_PLUGINS\n-\tif (info-\u003eplugin_dirs)\n-\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n-#endif\n-#if defined(LWS_WITH_HTTP2)\n-\t/* override settings */\n-\tcontext-\u003eset \u003d lws_h2_defaults_esp32;\n-#endif\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void esp32_uvtimer_cb(TimerHandle_t t)\n-{\n-\tstruct timer_mapping *p \u003d pvTimerGetTimerID(t);\n-\n-\tp-\u003ecb(p-\u003et);\n-}\n-\n-/* helper functionality */\n-\n-#include \u0022romfs.h\u0022\n-#include \u003cesp_ota_ops.h\u003e\n-#include \u003ctcpip_adapter.h\u003e\n-#include \u003cesp_image_format.h\u003e\n-#include \u003cesp_task_wdt.h\u003e\n-#include \u0022soc/ledc_reg.h\u0022\n-#include \u0022driver/ledc.h\u0022\n-\n-struct lws_esp32 lws_esp32 \u003d {\n-\t.model \u003d CONFIG_LWS_MODEL_NAME,\n-\t.serial \u003d \u0022unknown\u0022,\n-\t.region \u003d WIFI_COUNTRY_US, // default to safest option\n-};\n-\n-/*\n- * Group AP / Station State\n- */\n-\n-enum lws_gapss {\n-\tLWS_GAPSS_INITIAL,\t/* just started up, init and move to LWS_GAPSS_SCAN */\n-\tLWS_GAPSS_SCAN,\t\t/*\n-\t\t\t\t * Unconnected, scanning: AP known in one of the config\n-\t\t\t\t * slots -\u003e configure it, start timeout + LWS_GAPSS_STAT,\n-\t\t\t\t * if no AP already up in same group with lower MAC,\n-\t\t\t\t * after a random period start up our AP (LWS_GAPSS_AP)\n-\t\t\t\t */\n-\tLWS_GAPSS_AP,\t\t/*\n-\t\t\t\t * Trying to be the group AP... periodically do a scan\n-\t\t\t\t * LWS_GAPSS_AP_SCAN, faster and then slower\n- \t\t\t\t */\n-\tLWS_GAPSS_AP_SCAN,\t/*\n-\t\t\t\t * doing a scan while trying to be the group AP... if\n-\t\t\t\t * we see a lower MAC being the AP for the same group\n-\t\t\t\t * AP, abandon being an AP and join that AP as a\n-\t\t\t\t * station\n-\t\t\t\t */\n-\tLWS_GAPSS_STAT_GRP_AP,\t/*\n-\t\t\t\t * We have decided to join another group member who is\n-\t\t\t\t * being the AP, as its MAC is lower than ours. This\n-\t\t\t\t * is a stable state, but we still do periodic scans\n-\t\t\t\t * (LWS_GAPSS_STAT_GRP_AP_SCAN) and will always prefer\n-\t\t\t\t * an AP configured in a slot.\n-\t\t\t\t */\n-\tLWS_GAPSS_STAT_GRP_AP_SCAN,\n-\t\t\t\t/*\n-\t\t\t\t * We have joined a group member who is doing the AP\n-\t\t\t\t * job... we want to check every now and then if a\n-\t\t\t\t * configured AP has appeared that we should better\n-\t\t\t\t * use instead. Otherwise stay in LWS_GAPSS_STAT_GRP_AP\n-\t\t\t\t */\n-\tLWS_GAPSS_STAT,\t\t/*\n-\t\t\t\t * trying to connect to another non-group AP. If we\n-\t\t\t\t * don't get an IP within a timeout and retries,\n-\t\t\t\t * blacklist it and go back \n-\t\t\t\t */\n-\tLWS_GAPSS_STAT_HAPPY,\n-};\n-\n-static const char *gapss_str[] \u003d {\n-\t\u0022LWS_GAPSS_INITIAL\u0022,\n- \u0022LWS_GAPSS_SCAN\u0022,\n- \u0022LWS_GAPSS_AP\u0022,\n- \u0022LWS_GAPSS_AP_SCAN\u0022,\n- \u0022LWS_GAPSS_STAT_GRP_AP\u0022,\n- \u0022LWS_GAPSS_STAT_GRP_AP_SCAN\u0022,\n- \u0022LWS_GAPSS_STAT\u0022,\n-\t\u0022LWS_GAPSS_STAT_HAPPY\u0022,\n-};\n-\n-static romfs_t lws_esp32_romfs;\n-static TimerHandle_t leds_timer, scan_timer, debounce_timer\n-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n-, mdns_timer\n-#endif\n-;\n-static enum lws_gapss gapss \u003d LWS_GAPSS_INITIAL;\n-static char bdown;\n-\n-#define GPIO_SW 14\n-\n-struct esp32_file {\n-\tconst struct inode *i;\n-};\n-\n-static void lws_gapss_to(enum lws_gapss to)\n-{\n-\tlwsl_notice(\u0022gapss from %s to %s\u005cn\u0022, gapss_str[gapss], gapss_str[to]);\n-\tgapss \u003d to;\n-}\n-\n-uint32_t lws_esp32_get_reboot_type(void)\n-{\n-\tuint32_t *p \u003d (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS, val \u003d *p;\n-\tnvs_handle nvh;\n-\tsize_t s \u003d 0;\n-\tint n \u003d 0;\n-\n-\tESP_ERROR_CHECK(nvs_open(\u0022lws-station\u0022, NVS_READWRITE, \u0026nvh));\n-\tif (nvs_get_blob(nvh, \u0022ssl-pub.pem\u0022, NULL, \u0026s) \u003d\u003d ESP_OK)\n-\t\tn \u003d 1;\n-\tif (nvs_get_blob(nvh, \u0022ssl-pri.pem\u0022, NULL, \u0026s) \u003d\u003d ESP_OK)\n-\t\tn |\u003d 2;\n-\tnvs_close(nvh);\n-\n-\t/*\n-\t * in the case the SSL certs are not there, don't require\n-\t * the button to be down to access all features.\n-\t */\n-\tif (n !\u003d 3)\n-\t\tval \u003d LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON;\n-\n-\treturn val;\n-}\n-\n-static void render_ip(char *dest, int len, uint8_t *ip)\n-{\n-\tsnprintf(dest, len, \u0022%u.%u.%u.%u\u0022, ip[0], ip[1], ip[2], ip[3]);\n-}\n-\n-void lws_esp32_restart_guided(uint32_t type)\n-{\n- uint32_t *p_force_factory_magic \u003d (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;\n-\n-\tlwsl_notice(\u0022%s: %x\u005cn\u0022, __func__, type);\n- *p_force_factory_magic \u003d type;\n-\n-\tesp_restart();\n-}\n-\n-/*\n- * esp-idf goes crazy with zero length str nvs. Use this as a workaround\n- * to delete the key in that case.\n- */\n-\n-esp_err_t lws_nvs_set_str(nvs_handle handle, const char* key, const char* value)\n-{\n-\tif (*value)\n-\t\treturn nvs_set_str(handle, key, value);\n-\n-\treturn nvs_erase_key(handle, key);\n-}\n-\n-static wifi_scan_config_t scan_config \u003d {\n- .ssid \u003d 0,\n- .bssid \u003d 0,\n- .channel \u003d 0,\n- .show_hidden \u003d true\n-};\n-\n-static char scan_ongoing \u003d 0, scan_timer_exists \u003d 0;\n-static int try_slot \u003d -1;\n-\n-static wifi_config_t config \u003d {\n-\t.ap \u003d {\n-\t .channel \u003d 6,\n-\t .authmode \u003d WIFI_AUTH_OPEN,\n-\t .max_connection \u003d 1,\n-\t} }, sta_config \u003d {\n-\t.sta \u003d {\n-\t\t.bssid_set \u003d 0,\n-\t} };\n-\n-static void lws_esp32_scan_timer_cb(TimerHandle_t th)\n-{\n-\tint n;\n-\n-\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n-\tscan_ongoing \u003d 0;\n-\tn \u003d esp_wifi_scan_start(\u0026scan_config, false);\n-\tif (n !\u003d ESP_OK)\n-\t\tlwsl_err(\u0022scan start failed %d\u005cn\u0022, n);\n-}\n-\n-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n-\n-void __attribute__(( weak ))\n-lws_group_member_event(int e, void *p)\n-{\n-}\n-\n-void __attribute__(( weak ))\n-lws_get_iframe_size(int *w, int *h)\n-{\n-\t*w \u003d 320;\n-\t*h \u003d 160;\n-}\n-\n-void lws_group_member_event_call(int e, void *p)\n-{\n-\tlws_group_member_event(e, p);\n-}\n-\n-static int\n-get_txt_param(const char *txt, const char *param, char *result, int len)\n-{\n-\tconst char *p;\n-\n-again:\n-\tp \u003d strstr(txt, param);\n-\tif (!p) {\n-\t\t*result \u003d '\u005c0';\n-\t\treturn 1;\n-\t}\n-\n-\tp +\u003d strlen(param);\n-\tif (*p !\u003d '\u003d') {\n-\t\ttxt \u003d p;\n-\t\tgoto again;\n-\t}\n-\tp++;\n-\twhile (*p \u0026\u0026 *p !\u003d '\u0026' \u0026\u0026 --len)\n-\t\t*result++ \u003d *p++;\n-\n-\t*result \u003d '\u005c0';\n-\n-\treturn 0;\n-}\n-\n-static void lws_esp32_mdns_timer_cb(TimerHandle_t th)\n-{\n-\tuint64_t now \u003d time_in_microseconds(); \n-\tstruct lws_group_member *p, **p1;\n-\tconst mdns_result_t *r;\n-\tint n, m;\n-\n-\tif (!lws_esp32.mdns)\n-\t\treturn;\n-\tn \u003d mdns_query_end(lws_esp32.mdns);\n-\n-\tfor (m \u003d 0; m \u003c n; m++) {\n-\t\tchar ch \u003d 0, group[16];\n-\n-\t\tr \u003d mdns_result_get(lws_esp32.mdns, m);\n-\n-\t\tget_txt_param(r-\u003etxt, \u0022group\u0022, group, sizeof(group));\n-\t\tif (strcmp(group, lws_esp32.group)) /* not our group */ {\n-\t\t\tlwsl_notice(\u0022group %s vs %s %s\u005cn\u0022,\n-\t\t\t\t\tgroup, lws_esp32.group, r-\u003etxt);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tp \u003d lws_esp32.first;\n-\t\twhile (p) {\n-\t\t\tif (strcmp(r-\u003ehost, p-\u003ehost))\n-\t\t\t\tgoto next;\n-\t\t\tif (memcmp(\u0026r-\u003eaddr, \u0026p-\u003eaddr, sizeof(r-\u003eaddr)))\n-\t\t\t\tgoto next;\n-\n-\t\t\tp-\u003elast_seen \u003d now;\n-\t\t\tbreak;\n-next:\n-\t\t\tp \u003d p-\u003enext;\n-\t\t}\n-\t\tif (!p) { /* did not find */\n-\t\t\tchar temp[8];\n-\n-\t\t\tp \u003d lws_malloc(sizeof(*p), \u0022group\u0022);\n-\t\t\tif (!p)\n-\t\t\t\tcontinue;\n-\t\t\tstrncpy(p-\u003ehost, r-\u003ehost, sizeof(p-\u003ehost) - 1);\n-\t\t\tp-\u003ehost[sizeof(p-\u003ehost) - 1] \u003d '\u005c0';\n-\n-\t\t\tget_txt_param(r-\u003etxt, \u0022model\u0022, p-\u003emodel, sizeof(p-\u003emodel));\n-\t\t\tget_txt_param(r-\u003etxt, \u0022role\u0022, p-\u003erole, sizeof(p-\u003erole));\n-\t\t\tget_txt_param(r-\u003etxt, \u0022mac\u0022, p-\u003emac, sizeof(p-\u003emac));\n-\t\t\tget_txt_param(r-\u003etxt, \u0022width\u0022, temp, sizeof(temp));\n-\t\t\tp-\u003ewidth \u003d atoi(temp);\n-\t\t\tget_txt_param(r-\u003etxt, \u0022height\u0022, temp, sizeof(temp));\n-\t\t\tp-\u003eheight \u003d atoi(temp);\n-\n-\t\t\tmemcpy(\u0026p-\u003eaddr, \u0026r-\u003eaddr, sizeof(p-\u003eaddr));\n-\t\t\tmemcpy(\u0026p-\u003eaddrv6, \u0026r-\u003eaddrv6, sizeof(p-\u003eaddrv6));\n-\t\t\tp-\u003elast_seen \u003d now;\n-\t\t\tp-\u003eflags \u003d 0;\n-\t\t\tp-\u003enext \u003d lws_esp32.first;\n-\t\t\tlws_esp32.first \u003d p;\n-\t\t\tlws_esp32.extant_group_members++;\n-\n-\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_ADD, p);\n-\t\t} else {\n-\t\t\tif (memcmp(\u0026p-\u003eaddr, \u0026r-\u003eaddr, sizeof(p-\u003eaddr))) {\n-\t\t\t\tmemcpy(\u0026p-\u003eaddr, \u0026r-\u003eaddr, sizeof(p-\u003eaddr));\n-\t\t\t\tch \u003d 1;\n-\t\t\t}\n-\t\t\tif (memcmp(\u0026p-\u003eaddrv6, \u0026r-\u003eaddrv6, sizeof(p-\u003eaddrv6))) {\n-\t\t\t\tmemcpy(\u0026p-\u003eaddrv6, \u0026r-\u003eaddrv6, sizeof(p-\u003eaddrv6));\n-\t\t\t\tch \u003d 1;\n-\t\t\t}\n-\t\t\tif (ch)\n-\t\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_CHANGE, p);\n-\t\t}\n-\t}\n-\n-\tmdns_result_free(lws_esp32.mdns);\n-\n-\t/* garbage-collect group members not seen for too long */\n-\tp1 \u003d \u0026lws_esp32.first;\n-\twhile (*p1) {\n-\t\tp \u003d *p1;\n-\t\tif (!(p-\u003eflags \u0026 LWS_GROUP_FLAG_SELF) \u0026\u0026\n-\t\t\t\tnow - p-\u003elast_seen \u003e 60000000) {\n-\t\t\tlws_esp32.extant_group_members--;\n-\t\t\t*p1 \u003d p-\u003enext;\n-\n-\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_REMOVE, p);\n-\t\t\tlws_free(p);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tp1 \u003d \u0026(*p1)-\u003enext;\n-\t}\n-\n-\tmdns_query(lws_esp32.mdns, \u0022_lwsgrmem\u0022, \u0022_tcp\u0022, 0);\n-\txTimerStart(mdns_timer, 0);\n-}\n-#endif\n-\n-void __attribute__(( weak ))\n-lws_esp32_button(int down)\n-{\n-}\n-\n-void IRAM_ATTR\n-gpio_irq(void *arg)\n-{\n-\tbdown ^\u003d 1;\n-\tgpio_set_intr_type(GPIO_SW, GPIO_INTR_DISABLE);\n-\txTimerStart(debounce_timer, 0);\n-\n-\tlws_esp32_button(bdown);\n-}\n-\n-static void lws_esp32_debounce_timer_cb(TimerHandle_t th)\n-{\n-\tif (bdown)\n-\t\tgpio_set_intr_type(GPIO_SW, GPIO_INTR_POSEDGE);\n-\telse\n-\t\tgpio_set_intr_type(GPIO_SW, GPIO_INTR_NEGEDGE);\n-}\n-\n-\n-static int\n-start_scan()\n-{\n-\t/* if no APs configured, no point... */\n-\n-\tif (!lws_esp32.ssid[0][0] \u0026\u0026\n-\t !lws_esp32.ssid[1][0] \u0026\u0026\n-\t !lws_esp32.ssid[2][0] \u0026\u0026\n-\t !lws_esp32.ssid[3][0])\n-\t\treturn 0;\n-\n-\tif (scan_timer_exists \u0026\u0026 !scan_ongoing) {\n-\t\t// lwsl_notice(\u0022Starting scan timer...\u005cn\u0022);\n-\t\tscan_ongoing \u003d 1;\n-\t\txTimerStart(scan_timer, 0);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-\n-\n-static void\n-end_scan()\n-{\n-\twifi_ap_record_t ap_records[10];\n-\tuint16_t count_ap_records;\n-\tint n, m;\n-\n-\tcount_ap_records \u003d ARRAY_SIZE(ap_records);\n-\tif (esp_wifi_scan_get_ap_records(\u0026count_ap_records, ap_records) !\u003d ESP_OK) {\n-\t\tlwsl_err(\u0022%s: failed\u005cn\u0022, __func__);\n-\t\treturn;\n-\t}\n-\n-\tif (!count_ap_records)\n-\t\tgoto passthru;\n-\n-\tif (gapss !\u003d LWS_GAPSS_SCAN) {\n-\t\tlwsl_notice(\u0022ignoring scan as gapss %s\u005cn\u0022, gapss_str[gapss]);\n-\t\tgoto passthru;\n-\t}\n-\n-\t/* no point if no APs set up */\n-\tif (!lws_esp32.ssid[0][0] \u0026\u0026\n-\t !lws_esp32.ssid[1][0] \u0026\u0026\n-\t !lws_esp32.ssid[2][0] \u0026\u0026\n-\t !lws_esp32.ssid[3][0])\n-\t\tgoto passthru;\n-\n-\tlwsl_notice(\u0022checking %d scan records\u005cn\u0022, count_ap_records);\n-\n-\tfor (n \u003d 0; n \u003c 4; n++) {\n-\n-\t\tif (!lws_esp32.ssid[(n + try_slot + 1) \u0026 3][0])\n-\t\t\tcontinue;\n-\n-\t\tlwsl_notice(\u0022looking for %s\u005cn\u0022, lws_esp32.ssid[(n + try_slot + 1) \u0026 3]);\n-\n-\t\t/* this ssid appears in scan results? */\n-\n-\t\tfor (m \u003d 0; m \u003c count_ap_records; m++) {\n-\t\t\t// lwsl_notice(\u0022 %s\u005cn\u0022, ap_records[m].ssid);\n-\t\t\tif (strcmp((char *)ap_records[m].ssid, lws_esp32.ssid[(n + try_slot + 1) \u0026 3]) \u003d\u003d 0)\n-\t\t\t\tgoto hit;\n-\t\t}\n-\n-\t\tcontinue;\n-\n-hit:\n-\t\tm \u003d (n + try_slot + 1) \u0026 3;\n-\t\ttry_slot \u003d m;\n-\t\tlwsl_notice(\u0022Attempting connection with slot %d: %s:\u005cn\u0022, m,\n-\t\t\t\tlws_esp32.ssid[m]);\n-\t\t/* set the ssid we last tried to connect to */\n-\t\tstrncpy(lws_esp32.active_ssid, lws_esp32.ssid[m],\n-\t\t\t\tsizeof(lws_esp32.active_ssid) - 1);\n-\t\tlws_esp32.active_ssid[sizeof(lws_esp32.active_ssid) - 1] \u003d '\u005c0';\n-\n-\t\tstrncpy((char *)sta_config.sta.ssid, lws_esp32.ssid[m], sizeof(sta_config.sta.ssid) - 1);\n-\t\tstrncpy((char *)sta_config.sta.password, lws_esp32.password[m], sizeof(sta_config.sta.password) - 1);\n-\n-\t\ttcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, (const char *)\u0026config.ap.ssid[7]);\n-\t\tlws_gapss_to(LWS_GAPSS_STAT);\n-\n-\t\tesp_wifi_set_config(WIFI_IF_STA, \u0026sta_config);\n-\t\tesp_wifi_connect();\n-\t\tbreak;\n-\t}\n-\n-\tif (n \u003d\u003d 4)\n-\t\tstart_scan();\n-\n-passthru:\n-\tif (lws_esp32.scan_consumer)\n-\t\tlws_esp32.scan_consumer(count_ap_records, ap_records, lws_esp32.scan_consumer_arg);\n-\n-}\n-\n-static void\n-lws_set_genled(int n)\n-{\n-\tlws_esp32.genled_t \u003d time_in_microseconds();\n-\tlws_esp32.genled \u003d n;\n-}\n-\n-int\n-lws_esp32_leds_network_indication(void)\n-{\n-\tuint64_t us, r;\n-\tint n, fadein \u003d 100, speed \u003d 1199, div \u003d 1, base \u003d 0;\n-\n-\tr \u003d time_in_microseconds();\n-\tus \u003d r - lws_esp32.genled_t;\n-\n-\tswitch (lws_esp32.genled) {\n-\tcase LWSESP32_GENLED__INIT:\n-\t\tlws_esp32.genled \u003d LWSESP32_GENLED__LOST_NETWORK;\n-\t\t/* fallthru */\n-\tcase LWSESP32_GENLED__LOST_NETWORK:\n-\t\tfadein \u003d us / 10000; /* 100 steps in 1s */\n-\t\tif (fadein \u003e 100) {\n-\t\t\tfadein \u003d 100;\n-\t\t\tlws_esp32.genled \u003d LWSESP32_GENLED__NO_NETWORK;\n-\t\t}\n-\t\t/* fallthru */\n-\tcase LWSESP32_GENLED__NO_NETWORK:\n-\t\tbreak;\n-\tcase LWSESP32_GENLED__CONN_AP:\n-\t\tbase \u003d 4096;\n-\t\tspeed \u003d 933;\n-\t\tdiv \u003d 2;\n-\t\tbreak;\n-\tcase LWSESP32_GENLED__GOT_IP:\n-\t\tfadein \u003d us / 10000; /* 100 steps in 1s */\n-\t\tif (fadein \u003e 100) {\n-\t\t\tfadein \u003d 100;\n-\t\t\tlws_esp32.genled \u003d LWSESP32_GENLED__OK;\n-\t\t}\n-\t\tfadein \u003d 100 - fadein; /* we are fading out */\n-\t\t/* fallthru */\n-\tcase LWSESP32_GENLED__OK:\n-\t\tif (lws_esp32.genled \u003d\u003d LWSESP32_GENLED__OK)\n-\t\t\treturn 0;\n-\n-\t\tbase \u003d 4096;\n-\t\tspeed \u003d 766;\n-\t\tdiv \u003d 3;\n-\t\tbreak;\n-\t}\n-\n-\tn \u003d base + (lws_esp32_sine_interp(r / speed) / div);\n-\treturn (n * fadein) / 100;\n-}\n-\n-esp_err_t lws_esp32_event_passthru(void *ctx, system_event_t *event)\n-{\n-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n-\tstruct lws_group_member *mem;\n-\tint n;\n-#endif\n-\tchar slot[8];\n-\tnvs_handle nvh;\n-\tuint32_t use;\n-\n-\tswitch((int)event-\u003eevent_id) {\n-\tcase SYSTEM_EVENT_STA_START:\n-\t\t//esp_wifi_connect();\n-//\t\tbreak;\n-\t\t/* fallthru */\n-\tcase SYSTEM_EVENT_STA_DISCONNECTED:\n-\t\tlwsl_notice(\u0022SYSTEM_EVENT_STA_DISCONNECTED\u005cn\u0022);\n-\t\tlws_esp32.conn_ap \u003d 0;\n-\t\tlws_esp32.inet \u003d 0;\n-\t\tlws_esp32.sta_ip[0] \u003d '\u005c0';\n-\t\tlws_esp32.sta_mask[0] \u003d '\u005c0';\n-\t\tlws_esp32.sta_gw[0] \u003d '\u005c0';\n-\t\tlws_gapss_to(LWS_GAPSS_SCAN);\n-\t\tif (lws_esp32.mdns)\n-\t\t\tmdns_service_remove_all(lws_esp32.mdns);\n-\t\tmdns_free(lws_esp32.mdns);\n-\t\tlws_esp32.mdns \u003d NULL;\n-\t\tlws_set_genled(LWSESP32_GENLED__LOST_NETWORK);\n-\t\tstart_scan();\n-\t\tesp_wifi_connect();\n-\t\tbreak;\n-\n-\tcase SYSTEM_EVENT_STA_CONNECTED:\n-\t\tlws_esp32.conn_ap \u003d 1;\n-\t\tlws_set_genled(LWSESP32_GENLED__CONN_AP);\n-\t\tbreak;\n-\n-\tcase SYSTEM_EVENT_STA_GOT_IP:\n-\t\tlwsl_notice(\u0022SYSTEM_EVENT_STA_GOT_IP\u005cn\u0022);\n-\n-\t\tlws_esp32.inet \u003d 1;\n-\t\tlws_set_genled(LWSESP32_GENLED__GOT_IP);\n-\n-\t\trender_ip(lws_esp32.sta_ip, sizeof(lws_esp32.sta_ip) - 1,\n-\t\t\t\t(uint8_t *)\u0026event-\u003eevent_info.got_ip.ip_info.ip);\n-\t\trender_ip(lws_esp32.sta_mask, sizeof(lws_esp32.sta_mask) - 1,\n-\t\t\t\t(uint8_t *)\u0026event-\u003eevent_info.got_ip.ip_info.netmask);\n-\t\trender_ip(lws_esp32.sta_gw, sizeof(lws_esp32.sta_gw) - 1,\n-\t\t\t\t(uint8_t *)\u0026event-\u003eevent_info.got_ip.ip_info.gw);\n-\n-\t\tif (!nvs_open(\u0022lws-station\u0022, NVS_READWRITE, \u0026nvh)) {\n-\t\t\tlws_snprintf(slot, sizeof(slot) - 1, \u0022%duse\u0022, try_slot);\n-\t\t\tuse \u003d 0;\n-\t\t\tnvs_get_u32(nvh, slot, \u0026use);\n-\t\t\tnvs_set_u32(nvh, slot, use + 1);\n-\t\t\tnvs_commit(nvh);\n-\t\t\tnvs_close(nvh);\n-\t\t}\n-\n-\t\tlws_gapss_to(LWS_GAPSS_STAT_HAPPY);\n-\n-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n-\t\tn \u003d mdns_init(TCPIP_ADAPTER_IF_STA, \u0026lws_esp32.mdns);\n-\t\tif (!n) {\n-\t\t\tstatic char *txta[6];\n-\t\t\tint w, h;\n-\n-\t\t\tmdns_set_hostname(lws_esp32.mdns, lws_esp32.hostname);\n-\t\t\tmdns_set_instance(lws_esp32.mdns, lws_esp32.group);\n-\t\t\tmdns_service_add(lws_esp32.mdns, \u0022_lwsgrmem\u0022, \u0022_tcp\u0022, 443);\n-\t\t\tif (txta[0])\n-\t\t\t\tlws_free(txta[0]);\n-\t\t\ttxta[0] \u003d lws_malloc(32 * ARRAY_SIZE(txta), \u0022group\u0022);\n-\t\t\tif (!txta[0]) {\n-\t\t\t\tlwsl_notice(\u0022mdns OOM\u005cn\u0022);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\ttxta[1] \u003d \u0026txta[0][32];\n-\t\t\ttxta[2] \u003d \u0026txta[1][32];\n-\t\t\ttxta[3] \u003d \u0026txta[2][32];\n-\t\t\ttxta[4] \u003d \u0026txta[3][32];\n-\t\t\ttxta[5] \u003d \u0026txta[4][32];\n-\n-\t\t\tlws_get_iframe_size(\u0026w, \u0026h);\n-\n-\t\t\tlws_snprintf(txta[0], 31, \u0022model\u003d%s\u0022, lws_esp32.model);\n-\t\t\tlws_snprintf(txta[1], 31, \u0022group\u003d%s\u0022, lws_esp32.group);\n-\t\t\tlws_snprintf(txta[2], 31, \u0022role\u003d%s\u0022, lws_esp32.role);\n-\t\t\tlws_snprintf(txta[3], 31, \u0022mac\u003d%s\u0022, lws_esp32.mac);\n-\t\t\tlws_snprintf(txta[4], 31, \u0022width\u003d%d\u0022, w);\n-\t\t\tlws_snprintf(txta[5], 31, \u0022height\u003d%d\u0022, h);\n-\n-\t\t\tmem \u003d lws_esp32.first;\n-\t\t\twhile (mem) {\n-\t\t\t\tif (mem-\u003eflags \u0026 1)\n-\t\t\t\t\tbreak;\n-\t\t\t\tmem \u003d mem-\u003enext;\n-\t\t\t}\n-\n-\t\t\tif (!mem) {\n-\t\t\t\tstruct lws_group_member *mem \u003d lws_malloc(sizeof(*mem), \u0022group\u0022);\n-\t\t\t\tif (mem) {\n-\t\t\t\t\tmem-\u003elast_seen \u003d ~(uint64_t)0;\n-\t\t\t\t\tstrcpy(mem-\u003emodel, lws_esp32.model);\n-\t\t\t\t\tstrcpy(mem-\u003erole, lws_esp32.role);\n-\t\t\t\t\tstrcpy(mem-\u003ehost, lws_esp32.hostname);\n-\t\t\t\t\tstrcpy(mem-\u003emac, lws_esp32.mac);\n-\t\t\t\t\tmem-\u003eflags \u003d LWS_GROUP_FLAG_SELF;\n-\t\t\t\t\tlws_get_iframe_size(\u0026mem-\u003ewidth, \u0026mem-\u003eheight);\n-\t\t\t\t\tmemcpy(\u0026mem-\u003eaddr, \u0026event-\u003eevent_info.got_ip.ip_info.ip,\n-\t\t\t\t\t\t\tsizeof(mem-\u003eaddr));\n-\t\t\t\t\tmemcpy(\u0026mem-\u003eaddrv6, \u0026event-\u003eevent_info.got_ip6.ip6_info.ip,\n-\t\t\t\t\t\t\tsizeof(mem-\u003eaddrv6));\n-\t\t\t\t\tmem-\u003enext \u003d lws_esp32.first;\n-\t\t\t\t\tlws_esp32.first \u003d mem;\n-\t\t\t\t\tlws_esp32.extant_group_members++;\n-\n-\t\t\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_ADD, mem);\n-\t\t\t\t}\n-\t\t\t} else { /* update our IP */\n-\t\t\t\t\tmemcpy(\u0026mem-\u003eaddr, \u0026event-\u003eevent_info.got_ip.ip_info.ip,\n-\t\t\t\t\t\t\tsizeof(mem-\u003eaddr));\n-\t\t\t\t\tmemcpy(\u0026mem-\u003eaddrv6, \u0026event-\u003eevent_info.got_ip6.ip6_info.ip,\n-\t\t\t\t\t\t\tsizeof(mem-\u003eaddrv6));\n-\t\t\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_CHANGE, mem);\n-\t\t\t}\n-\n-\n-\t\t\tif (mdns_service_txt_set(lws_esp32.mdns, \u0022_lwsgrmem\u0022, \u0022_tcp\u0022, ARRAY_SIZE(txta),\n-\t\t\t\t\t\t (const char **)txta))\n-\t\t\t\tlwsl_notice(\u0022txt set failed\u005cn\u0022);\n-\t\t} else\n-\t\t\tlwsl_err(\u0022unable to init mdns on STA: %d\u005cn\u0022, n);\n-\n-\t\tmdns_query(lws_esp32.mdns, \u0022_lwsgrmem\u0022, \u0022_tcp\u0022, 0);\n-\t\txTimerStart(mdns_timer, 0);\n-#endif\n-\n-\t\tlwsl_notice(\u0022 --- Got IP %s\u005cn\u0022, lws_esp32.sta_ip);\n-\t\tbreak;\n-\n-\tcase SYSTEM_EVENT_SCAN_DONE:\n-\t\tlwsl_notice(\u0022SYSTEM_EVENT_SCAN_DONE\u005cn\u0022);\n-\t\tend_scan();\n-\t\tbreak;\n-\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\n-\treturn ESP_OK;\n-}\n-\n-static lws_fop_fd_t IRAM_ATTR\n-esp32_lws_fops_open(const struct lws_plat_file_ops *fops, const char *filename,\n- const char *vfs_path, lws_fop_flags_t *flags)\n-{\n-\tstruct esp32_file *f \u003d malloc(sizeof(*f));\n-\tlws_fop_fd_t fop_fd;\n-\tsize_t len, csum;\n-\n-\tlwsl_notice(\u0022%s: %s\u005cn\u0022, __func__, filename);\n-\n-\tif (!f)\n-\t\treturn NULL;\n-\tf-\u003ei \u003d romfs_get_info(lws_esp32_romfs, filename, \u0026len, \u0026csum);\n-\tif (!f-\u003ei)\n-\t\tgoto bail;\n-\n- fop_fd \u003d malloc(sizeof(*fop_fd));\n- if (!fop_fd)\n- goto bail;\n-\n- fop_fd-\u003efops \u003d fops;\n- fop_fd-\u003efilesystem_priv \u003d f;\n-\tfop_fd-\u003emod_time \u003d csum;\n-\t*flags |\u003d LWS_FOP_FLAG_MOD_TIME_VALID;\n-\tfop_fd-\u003eflags \u003d *flags;\n-\t\n-\tfop_fd-\u003elen \u003d len;\n-\tfop_fd-\u003epos \u003d 0;\n-\n-\treturn fop_fd;\n-\n-bail:\n-\tfree(f);\n-\n-\treturn NULL;\n-}\n-\n-static int IRAM_ATTR\n-esp32_lws_fops_close(lws_fop_fd_t *fop_fd)\n-{\n-\tfree((*fop_fd)-\u003efilesystem_priv);\n-\tfree(*fop_fd);\n-\n-\t*fop_fd \u003d NULL;\n-\n-\treturn 0;\n-}\n-static lws_fileofs_t IRAM_ATTR\n-esp32_lws_fops_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset_from_cur_pos)\n-{\n-\tfop_fd-\u003epos +\u003d offset_from_cur_pos;\n-\t\n-\tif (fop_fd-\u003epos \u003e fop_fd-\u003elen)\n-\t\tfop_fd-\u003epos \u003d fop_fd-\u003elen;\n-\n- return 0;\n-}\n-\n-static int IRAM_ATTR\n-esp32_lws_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount, uint8_t *buf,\n- lws_filepos_t len)\n-{\n- struct esp32_file *f \u003d fop_fd-\u003efilesystem_priv;\n-#if 0\n- if ((long)buf \u0026 3) {\n- lwsl_err(\u0022misaligned buf\u005cn\u0022);\n-\n- return -1;\n- }\n-#endif\n- if (fop_fd-\u003epos \u003e\u003d fop_fd-\u003elen)\n- return 0;\n-\n- if (len \u003e fop_fd-\u003elen - fop_fd-\u003epos)\n- len \u003d fop_fd-\u003elen - fop_fd-\u003epos;\n-\n- spi_flash_read((uint32_t)(char *)f-\u003ei + fop_fd-\u003epos, buf, len);\n-\n- *amount \u003d len;\n- fop_fd-\u003epos +\u003d len;\n-\n- return 0;\n-}\n-\n-static const struct lws_plat_file_ops fops \u003d {\n-\t.next \u003d \u0026fops_zip,\n-\t.LWS_FOP_OPEN \u003d esp32_lws_fops_open,\n-\t.LWS_FOP_CLOSE \u003d esp32_lws_fops_close,\n-\t.LWS_FOP_READ \u003d esp32_lws_fops_read,\n-\t.LWS_FOP_SEEK_CUR \u003d esp32_lws_fops_seek_cur,\n-};\n-\n-int\n-lws_esp32_wlan_nvs_get(int retry)\n-{\n-\tnvs_handle nvh;\n-\tchar r[2], lws_esp32_force_ap \u003d 0, slot[12];\n-\tsize_t s;\n-\tuint8_t mac[6];\n-\tint n;\n-\n-\tesp_efuse_mac_get_default(mac);\n-\tmac[5] |\u003d 1; /* match the AP MAC */\n-\tsnprintf(lws_esp32.serial, sizeof(lws_esp32.serial) - 1, \u0022%02X%02X%02X\u0022, mac[3], mac[4], mac[5]);\n-\tsnprintf(lws_esp32.mac, sizeof(lws_esp32.mac) - 1, \u0022%02X%02X%02X%02X%02X%02X\u0022, mac[0],\n-\t\t\tmac[1], mac[2], mac[3], mac[4], mac[5]);\n-\n-\tESP_ERROR_CHECK(nvs_open(\u0022lws-station\u0022, NVS_READWRITE, \u0026nvh));\n-\n-\tconfig.sta.ssid[0] \u003d '\u005c0';\n-\tconfig.sta.password[0] \u003d '\u005c0';\n-\n-\tfor (n \u003d 0; n \u003c 4; n++) {\n-\t\tlws_snprintf(slot, sizeof(slot) - 1, \u0022%dssid\u0022, n);\n-\t\ts \u003d sizeof(lws_esp32.ssid[0]) - 1;\n-\t\tlws_esp32.ssid[n][0] \u003d '\u005c0';\n-\t\tnvs_get_str(nvh, slot, lws_esp32.ssid[n], \u0026s);\n-\n-\t\tlws_snprintf(slot, sizeof(slot) - 1, \u0022%dpassword\u0022, n);\n-\t\ts \u003d sizeof(lws_esp32.password[0]) - 1;\n-\t\tlws_esp32.password[n][0] \u003d '\u005c0';\n-\t\tnvs_get_str(nvh, slot, lws_esp32.password[n], \u0026s);\n-\t}\n-\n-\ts \u003d sizeof(lws_esp32.serial) - 1;\n-\tif (nvs_get_str(nvh, \u0022serial\u0022, lws_esp32.serial, \u0026s) !\u003d ESP_OK)\n-\t\tlws_esp32_force_ap \u003d 1;\n-\telse\n-\t\tsnprintf((char *)config.ap.ssid, sizeof(config.ap.ssid) - 1,\n-\t\t\t \u0022config-%s-%s\u0022, lws_esp32.model, lws_esp32.serial);\n-\ts \u003d sizeof(lws_esp32.opts) - 1;\n-\tif (nvs_get_str(nvh, \u0022opts\u0022, lws_esp32.opts, \u0026s) !\u003d ESP_OK)\n-\t\tlws_esp32_force_ap \u003d 1;\n-\n-\ts \u003d sizeof(r);\n-\tif (nvs_get_str(nvh, \u0022region\u0022, r, \u0026s) !\u003d ESP_OK)\n-\t\tlws_esp32_force_ap \u003d 1;\n-\telse\n-\t\tlws_esp32.region \u003d atoi(r);\n-\tlws_esp32.access_pw[0] \u003d '\u005c0';\n-\tnvs_get_str(nvh, \u0022access_pw\u0022, lws_esp32.access_pw, \u0026s);\n-\n-\tlws_esp32.group[0] \u003d '\u005c0';\n-\ts \u003d sizeof(lws_esp32.group);\n-\tnvs_get_str(nvh, \u0022group\u0022, lws_esp32.group, \u0026s);\n-\n-\tlws_esp32.role[0] \u003d '\u005c0';\n-\ts \u003d sizeof(lws_esp32.role);\n-\tnvs_get_str(nvh, \u0022role\u0022, lws_esp32.role, \u0026s);\n-\n-\t/* if group and role defined: group-role */\n-\tif (lws_esp32.group[0] \u0026\u0026 lws_esp32.role[0])\n-\t\tlws_snprintf(lws_esp32.hostname, sizeof(lws_esp32.hostname) - 1,\n-\t\t\t\t\u0022%s-%s\u0022, lws_esp32.group, lws_esp32.role);\n-\telse /* otherwise model-serial */\n-\t\tlws_snprintf(lws_esp32.hostname, sizeof(lws_esp32.hostname) - 1,\n-\t\t\t\t\u0022%s-%s\u0022, lws_esp32.model, lws_esp32.serial);\n-\n-\tnvs_close(nvh);\n-\n-\tlws_gapss_to(LWS_GAPSS_SCAN);\n-\tstart_scan();\n-\n-\treturn lws_esp32_force_ap;\n-}\n-\n-\n-void\n-lws_esp32_wlan_config(void)\n-{\n-\tledc_timer_config_t ledc_timer \u003d {\n-\t .bit_num \u003d LEDC_TIMER_13_BIT,\n-\t .freq_hz \u003d 5000,\n-\t .speed_mode \u003d LEDC_HIGH_SPEED_MODE,\n-\t .timer_num \u003d LEDC_TIMER_0\n-\t};\n-\tint n;\n-\n-\tledc_timer_config(\u0026ledc_timer);\n-\n-\tlws_set_genled(LWSESP32_GENLED__INIT);\n-\n-\t/* user code needs to provide lws_esp32_leds_timer_cb */\n-\n- leds_timer \u003d xTimerCreate(\u0022lws_leds\u0022, pdMS_TO_TICKS(25), 1, NULL,\n- (TimerCallbackFunction_t)lws_esp32_leds_timer_cb);\n- scan_timer \u003d xTimerCreate(\u0022lws_scan\u0022, pdMS_TO_TICKS(10000), 0, NULL,\n- (TimerCallbackFunction_t)lws_esp32_scan_timer_cb);\n- debounce_timer \u003d xTimerCreate(\u0022lws_db\u0022, pdMS_TO_TICKS(100), 0, NULL,\n- (TimerCallbackFunction_t)lws_esp32_debounce_timer_cb);\n-\n-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n- mdns_timer \u003d xTimerCreate(\u0022lws_mdns\u0022, pdMS_TO_TICKS(5000), 0, NULL,\n- (TimerCallbackFunction_t)lws_esp32_mdns_timer_cb);\n-#endif\n-\tscan_timer_exists \u003d 1;\n- xTimerStart(leds_timer, 0);\n-\n-\t*(volatile uint32_t *)PERIPHS_IO_MUX_MTMS_U \u003d FUNC_MTMS_GPIO14;\n-\n-\tgpio_output_set(0, 0, 0, (1 \u003c\u003c GPIO_SW));\n-\n-\tn \u003d gpio_install_isr_service(0);\n-\tif (!n) {\n-\t\tgpio_config_t c;\n-\n-\t\tc.intr_type \u003d GPIO_INTR_NEGEDGE;\n-\t\tc.mode \u003d GPIO_MODE_INPUT;\n-\t\tc.pin_bit_mask \u003d 1 \u003c\u003c GPIO_SW;\n-\t\tc.pull_down_en \u003d 0;\n-\t\tc.pull_up_en \u003d 0;\n-\t\tgpio_config(\u0026c);\n-\n-\t\tif (gpio_isr_handler_add(GPIO_SW, gpio_irq, NULL))\n-\t\t\tlwsl_notice(\u0022isr handler add for 14 failed\u005cn\u0022);\n-\t} else\n-\t\tlwsl_notice(\u0022failed to install gpio isr service: %d\u005cn\u0022, n);\n-\n-\tlws_esp32_wlan_nvs_get(0);\n-\ttcpip_adapter_init();\n-}\n-\n-void\n-lws_esp32_wlan_start_ap(void)\n-{\n-\twifi_init_config_t cfg \u003d WIFI_INIT_CONFIG_DEFAULT();\n-\n-\tESP_ERROR_CHECK( esp_wifi_init(\u0026cfg));\n-\tESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));\n-\tesp_wifi_set_country(lws_esp32.region);\n-\n-\tESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_APSTA) );\n-\tESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_AP, \u0026config) );\n-\tESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, \u0026sta_config));\n-\tESP_ERROR_CHECK( esp_wifi_start());\n-\n-\tesp_wifi_scan_start(\u0026scan_config, false);\n-\n-\tif (sta_config.sta.ssid[0]) {\n-\t\ttcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, (const char *)\u0026config.ap.ssid[7]);\n-\t\tesp_wifi_set_auto_connect(1);\n-\t\tESP_ERROR_CHECK( esp_wifi_connect());\n-\t\tESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, \u0026sta_config));\n-\t\tESP_ERROR_CHECK( esp_wifi_connect());\n-\t}\n-}\n-\n-void\n-lws_esp32_wlan_start_station(void)\n-{\n-\twifi_init_config_t cfg \u003d WIFI_INIT_CONFIG_DEFAULT();\n-\n-\tESP_ERROR_CHECK( esp_wifi_init(\u0026cfg));\n-\tESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));\n-\tesp_wifi_set_country(lws_esp32.region);\n-\n-\tESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA));\n-\tESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, \u0026sta_config));\n-\n-\tESP_ERROR_CHECK( esp_wifi_start());\n-\n-\ttcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, (const char *)\u0026config.ap.ssid[7]);\n-\tesp_wifi_set_auto_connect(1);\n-\t//ESP_ERROR_CHECK( esp_wifi_connect());\n-\n-\tlws_esp32_scan_timer_cb(NULL);\n-}\n-\n-const esp_partition_t *\n-lws_esp_ota_get_boot_partition(void)\n-{\n-\tconst esp_partition_t *part \u003d esp_ota_get_boot_partition(), *factory_part, *ota;\n-\tesp_image_header_t eih, ota_eih;\n-\tuint32_t *p_force_factory_magic \u003d (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;\n-\n-\t/* confirm what we are told is the boot part is sane */\n-\tspi_flash_read(part-\u003eaddress , \u0026eih, sizeof(eih));\n-\tfactory_part \u003d esp_partition_find_first(ESP_PARTITION_TYPE_APP,\n-\t\t\tESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);\n- \tota \u003d esp_partition_find_first(ESP_PARTITION_TYPE_APP,\n-\t\t\tESP_PARTITION_SUBTYPE_APP_OTA_0, NULL);\n-\tspi_flash_read(ota-\u003eaddress , \u0026ota_eih, sizeof(ota_eih));\n-\n-\tif (eih.spi_mode \u003d\u003d 0xff ||\n-\t *p_force_factory_magic \u003d\u003d LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY ||\n-\t *p_force_factory_magic \u003d\u003d LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON\n-\t ) {\n-\t\t/*\n-\t\t * we believed we were going to boot OTA, but we fell\n-\t\t * back to FACTORY in the bootloader when we saw it\n-\t\t * had been erased. esp_ota_get_boot_partition() still\n-\t\t * says the OTA partition then even if we are in the\n-\t\t * factory partition right now.\n-\t\t */\n-\t\tpart \u003d factory_part;\n-\t} \n-\t\n-#ifdef CONFIG_LWS_IS_FACTORY_APPLICATION\n-\telse\n-\t\tif (ota_eih.spi_mode !\u003d 0xff \u0026\u0026\n-\t\t part-\u003eaddress !\u003d factory_part-\u003eaddress) {\n-\t\t\tuint8_t buf[4096];\n-\t\t\tuint32_t n;\n-\t\t\t/*\n-\t\t\t * we are a FACTORY image running in an OTA slot...\n-\t\t\t * it means we were just written and need to copy\n-\t\t\t * ourselves into the FACTORY slot.\n-\t\t\t */\n-\t\t\tlwsl_notice(\u0022Copying FACTORY update into place 0x%x len 0x%x\u005cn\u0022,\n-\t\t\t\t factory_part-\u003eaddress, factory_part-\u003esize);\n-\t\t\tesp_task_wdt_feed();\n-\t\t\tif (spi_flash_erase_range(factory_part-\u003eaddress, factory_part-\u003esize) !\u003d ESP_OK) {\n-\t \t lwsl_err(\u0022spi: Failed to erase\u005cn\u0022);\n-\t \t goto retry;\n-\t \t}\n-\n-\t\t\tfor (n \u003d 0; n \u003c factory_part-\u003esize; n +\u003d sizeof(buf)) {\n-\t\t\t\tesp_task_wdt_feed();\n-\t\t\t\tspi_flash_read(part-\u003eaddress + n , buf, sizeof(buf));\n-\t \tif (spi_flash_write(factory_part-\u003eaddress + n, buf, sizeof(buf)) !\u003d ESP_OK) {\n-\t \t lwsl_err(\u0022spi: Failed to write\u005cn\u0022);\n-\t \t goto retry;\n-\t \t}\n-\t\t\t}\n-\n-\t\t\t/* destroy our OTA image header */\n-\t\t\tspi_flash_erase_range(ota-\u003eaddress, 4096);\n-\n-\t\t\t/*\n-\t\t\t * with no viable OTA image, we will come back up in factory\n-\t\t\t * where the user can reload the OTA image\n-\t\t\t */\n-\t\t\tlwsl_notice(\u0022 FACTORY copy successful, rebooting\u005cn\u0022);\n-retry:\n-\t\t\tesp_restart();\n-\t\t}\n-#endif\n-\n-\treturn part;\n-}\n-\n-\n-void\n-lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)\n-{\n-\tconst esp_partition_t *part;\n-\n-\tmemset(info, 0, sizeof(*info));\n-\n-\tlws_set_log_level(63, lwsl_emit_syslog);\n-\n-\tpart \u003d lws_esp_ota_get_boot_partition();\n-\t(void)part;\n-\n-\tinfo-\u003eport \u003d 443;\n-\tinfo-\u003efd_limit_per_thread \u003d 10;\n-\tinfo-\u003emax_http_header_pool \u003d 16;\n-\tinfo-\u003emax_http_header_data \u003d 512;\n-\tinfo-\u003ept_serv_buf_size \u003d 2048;\n-\tinfo-\u003ekeepalive_timeout \u003d 30;\n-\tinfo-\u003etimeout_secs \u003d 30;\n-\tinfo-\u003esimultaneous_ssl_restriction \u003d 4;\n-\tinfo-\u003eoptions \u003d LWS_SERVER_OPTION_EXPLICIT_VHOSTS |\n-\t\t LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n-\n-\tinfo-\u003essl_cert_filepath \u003d \u0022ssl-pub.pem\u0022;\n-\tinfo-\u003essl_private_key_filepath \u003d \u0022ssl-pri.pem\u0022;\n-}\n-\n-int\n-lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,\n-\t\t\t char *json, int json_len)\n-{\n-\tesp_image_segment_header_t eis;\n-\tesp_image_header_t eih;\n-\tuint32_t hdr;\n-\n-\tspi_flash_read(part-\u003eaddress , \u0026eih, sizeof(eih));\n-\thdr \u003d part-\u003eaddress + sizeof(eih);\n-\n-\tif (eih.magic !\u003d ESP_IMAGE_HEADER_MAGIC)\n-\t\treturn 1;\n-\n-\teis.data_len \u003d 0;\n-\twhile (eih.segment_count-- \u0026\u0026 eis.data_len !\u003d 0xffffffff) {\n-\t\tspi_flash_read(hdr, \u0026eis, sizeof(eis));\n-\t\thdr +\u003d sizeof(eis) + eis.data_len;\n-\t}\n-\thdr +\u003d (~hdr \u0026 15) + 1;\n-\n-\tif (eih.hash_appended)\n-\t\thdr +\u003d 0x20;\n-\n-//\tlwsl_notice(\u0022romfs estimated at 0x%x\u005cn\u0022, hdr);\n-\n-\ti-\u003eromfs \u003d hdr + 0x4;\n-\tspi_flash_read(hdr, \u0026i-\u003eromfs_len, sizeof(i-\u003eromfs_len));\n-\ti-\u003ejson \u003d i-\u003eromfs + i-\u003eromfs_len + 4;\n-\tspi_flash_read(i-\u003ejson - 4, \u0026i-\u003ejson_len, sizeof(i-\u003ejson_len));\n-\n-\tif (i-\u003ejson_len \u003c json_len - 1)\n-\t\tjson_len \u003d i-\u003ejson_len;\n-\tspi_flash_read(i-\u003ejson, json, json_len);\n-\tjson[json_len] \u003d '\u005c0';\n-\n-\treturn 0;\n-}\n-\n-struct lws_context *\n-lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)\n-{\n-\tconst esp_partition_t *part \u003d lws_esp_ota_get_boot_partition();\n-\tstruct lws_context *context;\n-\tstruct lws_esp32_image i;\n-\tstruct lws_vhost *vhost;\n-\tnvs_handle nvh;\n-\tchar buf[512];\n-\tsize_t s;\n-\tint n;\n-\n-\tESP_ERROR_CHECK(nvs_open(\u0022lws-station\u0022, NVS_READWRITE, \u0026nvh));\n-\tn \u003d 0;\n-\ts \u003d 1;\n-\tif (nvs_get_blob(nvh, \u0022ssl-pub.pem\u0022, NULL, \u0026s) \u003d\u003d ESP_OK)\n-\t\tn \u003d 1;\n-\ts \u003d 1;\n-\tif (nvs_get_blob(nvh, \u0022ssl-pri.pem\u0022, NULL, \u0026s) \u003d\u003d ESP_OK)\n-\t\tn |\u003d 2;\n-\tnvs_close(nvh);\n-\n-\tif (n !\u003d 3) {\n-\t\t/* we are not configured for SSL yet... fall back to port 80 / http */\n-\t\tinfo-\u003eport \u003d 80;\n-\t\tinfo-\u003eoptions \u0026\u003d ~LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n-\t\tlwsl_notice(\u0022No SSL certs... using port 80\u005cn\u0022);\n-\t}\n-\n-\tcontext \u003d lws_create_context(info);\n-\tif (context \u003d\u003d NULL) {\n-\t\tlwsl_err(\u0022Failed to create context\u005cn\u0022);\n-\t\treturn NULL;\n-\t}\n-\n-\tlws_esp32_get_image_info(part, \u0026i, buf, sizeof(buf) - 1);\n-\t\n-\tlws_esp32_romfs \u003d (romfs_t)i.romfs;\n-\tif (!romfs_mount_check(lws_esp32_romfs)) {\n-\t\tlwsl_err(\u0022Failed to mount ROMFS at %p 0x%x\u005cn\u0022, lws_esp32_romfs, i.romfs);\n-\t\treturn NULL;\n-\t}\n-\n-\tlwsl_notice(\u0022ROMFS length %uKiB\u005cn\u0022, i.romfs_len \u003e\u003e 10);\n-\n-\tputs(buf);\n-\n-\t/* set the lws vfs to use our romfs */\n-\n-\tlws_set_fops(context, \u0026fops);\n-\n-\tvhost \u003d lws_create_vhost(context, info);\n-\tif (!vhost)\n-\t\tlwsl_err(\u0022Failed to create vhost\u005cn\u0022);\n-\telse\n-\t\tlws_init_vhost_client_ssl(info, vhost); \n-\n-\tif (pvh)\n-\t\t*pvh \u003d vhost;\n-\n-\tlws_protocol_init(context);\n-\n-\treturn context;\n-}\n-\n-static const uint16_t sineq16[] \u003d {\n- 0x0000, 0x0191, 0x031e, 0x04a4, 0x061e, 0x0789, 0x08e2, 0x0a24,\n- 0x0b4e, 0x0c5c, 0x0d4b, 0x0e1a, 0x0ec6, 0x0f4d, 0x0faf, 0x0fea,\n-};\n-\n-static uint16_t sine_lu(int n)\n-{\n- switch ((n \u003e\u003e 4) \u0026 3) {\n- case 1:\n- return 4096 + sineq16[n \u0026 15];\n- case 2:\n- return 4096 + sineq16[15 - (n \u0026 15)];\n- case 3:\n- return 4096 - sineq16[n \u0026 15];\n- default:\n- return 4096 - sineq16[15 - (n \u0026 15)];\n- }\n-}\n-\n-/* useful for sine led fade patterns */\n-\n-uint16_t lws_esp32_sine_interp(int n)\n-{\n- /*\n- * 2: quadrant\n- * 4: table entry in quadrant\n- * 4: interp (LSB)\n- *\n- * total 10 bits / 1024 steps per cycle\n-\t *\n-\t * + 0: 0\n-\t * + 256: 4096\n-\t * + 512: 8192\n-\t * + 768: 4096\n-\t * +1023: 0\n- */\n-\n- return (sine_lu(n \u003e\u003e 4) * (15 - (n \u0026 15)) +\n- sine_lu((n \u003e\u003e 4) + 1) * (n \u0026 15)) / 15;\n-}\n-\ndiff --git a/lib/lws-plat-esp8266.c b/lib/lws-plat-esp8266.c\ndeleted file mode 100644\nindex 90ddbdf..0000000\n--- a/lib/lws-plat-esp8266.c\n+++ /dev/null\n@@ -1,700 +0,0 @@\n-#include \u0022private-libwebsockets.h\u0022\n-\n-#include \u0022ip_addr.h\u0022\n-\n-/* forced into this because new espconn accepted callbacks carry no context ptr */\n-static struct lws_context *hacky_context;\n-static unsigned int time_high, ot;\n-\n-/*\n- * included from libwebsockets.c for esp8266 builds\n- */\n-\n-unsigned long long time_in_microseconds(void)\n-{\n-\tunsigned int t \u003d system_get_time();\n-\t\n-\tif (ot \u003e t)\n-\t\ttime_high++;\n-\tot \u003d t;\n-\t\n-\treturn (((long long)time_high) \u003c\u003c 32) | t;\n-}\n-\n-int gettimeofday(struct timeval *tv, void *tz)\n-{\n-\tunsigned long long t \u003d time_in_microseconds();\n-\t\n-\ttv-\u003etv_sec \u003d t / 1000000;\n-\ttv-\u003etv_usec \u003d t % 1000000;\n-\n-\treturn 0;\n-}\n-\n-time_t time(time_t *tloc)\n-{\n-\tunsigned long long t \u003d time_in_microseconds();\n-\n-\tif (tloc)\n-\t\t*tloc \u003d t / 1000000;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_get_random(struct lws_context *context, void *buf, int len)\n-{\n-//\treturn read(context-\u003efd_random, (char *)buf, len);\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_send_pipe_choked(struct lws *wsi)\n-{\n-\treturn wsi-\u003epending_send_completion;\n-}\n-\n-LWS_VISIBLE struct lws *\n-wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)\n-{\n-\tint n;\n-\n-\tfor (n \u003d 0; n \u003c context-\u003emax_fds; n++)\n-\t\tif (context-\u003econnpool[n] \u003d\u003d fd)\n-\t\t\treturn (struct lws *)context-\u003econnpool[n + context-\u003emax_fds];\n-\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE int\n-lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)\n-{\n-\t//lwsl_notice(\u0022%s: wsi %p: len %d\u005cn\u0022, __func__, wsi, len);\t\n-\t\n-\twsi-\u003epending_send_completion++;\n-\tespconn_send(wsi-\u003edesc.sockfd, buf, len);\n-\t\n-\treturn len;\n-}\n-\n-void abort(void)\n-{\n-\twhile(1) ;\n-}\n-\n-void exit(int n)\n-{\n-\tabort();\n-}\n-\n-void _sint(void *s)\n-{\n-}\n-\n-LWS_VISIBLE int\n-insert_wsi(struct lws_context *context, struct lws *wsi)\n-{\n-\t(void)context;\n-\t(void)wsi;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-delete_from_fd(struct lws_context *context, lws_sockfd_type fd)\n-{\n-\t(void)context;\n-\t(void)fd;\n-\n-\treturn 1;\n-}\n-\n-struct tm *localtime(const time_t *timep)\n-{\n-\treturn NULL;\n-}\n-struct tm *localtime_r(const time_t *timep, struct tm *t)\n-{\n-\treturn NULL;\n-}\n-\n-int atoi(const char *s)\n-{\n-\tint n \u003d 0;\n-\n-\twhile (*s \u0026\u0026 (*s \u003e\u003d '0' \u0026\u0026 *s \u003c\u003d '9'))\n-\t\tn \u003d (n * 10) + ((*s++) - '0');\n-\n-\treturn n;\n-}\n-\n-#undef isxdigit\n-int isxdigit(int c)\n-{\n-\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'F')\n-\t\treturn 1;\n-\n-\tif (c \u003e\u003d 'a' \u0026\u0026 c \u003c\u003d 'f')\n-\t\treturn 1;\n-\n-\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')\n-\t\treturn 1;\n-\n-\treturn 0;\n-}\n-\n-int strcasecmp(const char *s1, const char *s2)\n-{\n-\tchar a, b;\n-\twhile (*s1 \u0026\u0026 *s2) {\n-\t\ta \u003d *s1++;\n-\t\tb \u003d *s2++;\n-\n-\t\tif (a \u003d\u003d b)\n-\t\t\tcontinue;\n-\n-\t\tif (a \u003e\u003d 'a' \u0026\u0026 a \u003c\u003d 'z')\n-\t\t\ta -\u003d 'a' - 'A';\n-\t\tif (b \u003e\u003d 'a' \u0026\u0026 b \u003c\u003d 'z')\n-\t\t\tb -\u003d 'a' - 'A';\n-\n-\t\tif (a !\u003d b)\n-\t\t\treturn 1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_poll_listen_fd(struct lws_pollfd *fd)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service_pt(struct lws *wsi)\n-{\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n-{\n-\textern void output_redirect(const char *str);\n-\toutput_redirect(line);\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_check_connection_error(struct lws *wsi)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_service(struct lws_context *context, int timeout_ms)\n-{\n-//\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n-\treturn 0;\n-}\n-\n-static int\n-esp8266_find_free_conn(struct lws_context *context)\n-{\n-\tint n;\n-\n-\tfor (n \u003d 0; n \u003c context-\u003emax_fds; n++)\n-\t\tif (!context-\u003econnpool[n]) {\n-\t\t\tlwsl_info(\u0022 using connpool %d\u005cn\u0022, n);\n-\t\t\treturn n;\n-\t\t}\n-\t\n-\tlwsl_err(\u0022%s: no free conns\u005cn\u0022, __func__);\n-\t\n-\treturn -1;\n-}\n-\n-lws_sockfd_type\n-esp8266_create_tcp_listen_socket(struct lws_vhost *vh)\n-{\n-\tint n \u003d esp8266_find_free_conn(vh-\u003econtext);\n-\tstruct espconn *conn;\n-\t\n-\tif (n \u003c 0)\n-\t\treturn NULL;\n-\t\n-\tconn \u003d lws_zalloc(sizeof *conn, \u0022listen skt\u0022);\n-\tif (!conn)\n-\t\treturn NULL;\n-\t\n-\tvh-\u003econtext-\u003econnpool[n] \u003d conn;\n-\t\n-\tconn-\u003etype \u003d ESPCONN_TCP;\n-\tconn-\u003estate \u003d ESPCONN_NONE;\n-\tconn-\u003eproto.tcp \u003d \u0026vh-\u003etcp;\n-\t\n-\treturn conn;\n-}\n-\n-const char *\n-lws_plat_get_peer_simple(struct lws *wsi, char *name, int namelen)\n-{\n-\tunsigned char *p \u003d wsi-\u003edesc.sockfd-\u003eproto.tcp-\u003eremote_ip;\n-\n-\tlws_snprintf(name, namelen, \u0022%u.%u.%u.%u\u0022, p[0], p[1], p[2], p[3]);\n-\n-\treturn name;\n-}\n-\n-LWS_VISIBLE int\n-lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)\n-{\n-\t//lwsl_notice(\u0022%s\u005cn\u0022, __func__);\n-\t\n-\tif (!wsi-\u003econtext-\u003erxd)\n-\t\treturn 0;\n-\n-\tif (len \u003c wsi-\u003econtext-\u003erxd_len)\n-\t\tlwsl_err(\u0022trunc read (%d vs %d)\u005cn\u0022, len, wsi-\u003econtext-\u003erxd_len);\n-\telse\n-\t\tlen \u003d wsi-\u003econtext-\u003erxd_len;\n-\t\n-\tets_memcpy(buf, wsi-\u003econtext-\u003erxd, len);\n-\t\n-\twsi-\u003econtext-\u003erxd \u003d NULL;\n-\t\n-\treturn len;\n-}\n-\n-static void\n-cb_1Hz(void *arg)\n-{\n-\tstruct lws_context *context \u003d arg;\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-\tstruct lws *wsi;\n-\tstruct lws_pollfd *pollfd;\n-\tint n;\n-\n-\t/* Service any ah that has pending rx */\n-\tfor (n \u003d 0; n \u003c context-\u003emax_http_header_pool; n++)\n-\t\tif (pt-\u003eah_pool[n].rxpos !\u003d pt-\u003eah_pool[n].rxlen) {\n-\t\t\twsi \u003d pt-\u003eah_pool[n].wsi;\n-\t\t\tpollfd \u003d \u0026pt-\u003efds[wsi-\u003eposition_in_fds_table];\n-\t\t\tif (pollfd-\u003eevents \u0026 LWS_POLLIN) {\n-\t\t\t\tpollfd-\u003erevents |\u003d LWS_POLLIN;\n-\t\t\t\tlws_service_fd(context, pollfd);\n-\t\t\t}\n-\t\t}\n-\n-\t/* handle timeouts */\n-\n-\tlws_service_fd(context, NULL);\n-}\n-\n-static void\n-esp8266_cb_rx(void *arg, char *data, unsigned short len)\n-{\n-\tstruct espconn *conn \u003d arg;\n-\tstruct lws *wsi \u003d conn-\u003ereverse;\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[0];\n-\tstruct lws_pollfd pollfd;\n-\tint n \u003d 0;\n-\n-\t/*\n-\t * if we're doing HTTP headers, and we have no ah, check if there is\n-\t * a free ah, if not, have to buffer it\n-\t */\n-\tif (!wsi-\u003ehdr_parsing_completed \u0026\u0026 !wsi-\u003eu.hdr.ah) {\n-\t\tfor (n \u003d 0; n \u003c wsi-\u003econtext-\u003emax_http_header_pool; n++)\n-\t\t\tif (!pt-\u003eah_pool[n].in_use)\n-\t\t\t\tbreak;\n-\n-\t\tn \u003d n \u003d\u003d wsi-\u003econtext-\u003emax_http_header_pool;\n-\t}\n-\n-\tif (!(pt-\u003efds[wsi-\u003eposition_in_fds_table].events \u0026 LWS_POLLIN) || n) {\n-\t\twsi-\u003epremature_rx \u003d realloc(wsi-\u003epremature_rx,\n-\t\t\t\t\t wsi-\u003eprem_rx_size + len);\n-\t\tif (!wsi-\u003epremature_rx)\n-\t\t\treturn;\n-\t\tos_memcpy((char *)wsi-\u003epremature_rx + wsi-\u003eprem_rx_size, data, len);\n-\t\twsi-\u003eprem_rx_size +\u003d len;\n-\t//\tlwsl_notice(\u0022%s: wsi %p: len %d BUFFERING\u005cn\u0022, __func__, wsi, len);\n-\n-\t\tif (n) /* we know it will fail, but we will get on the wait list */\n-\t\t\tn \u003d lws_header_table_attach(wsi, 0);\n-\n-\t\t(void)n;\n-\t\treturn;\n-\t}\n-\n-\t//lwsl_err(\u0022%s: wsi %p. len %d\u005cn\u0022, __func__, wsi, len);\n-\n- pollfd.fd \u003d arg;\n- pollfd.events \u003d LWS_POLLIN;\n- pollfd.revents \u003d LWS_POLLIN;\n- \n- wsi-\u003econtext-\u003erxd \u003d data;\n- wsi-\u003econtext-\u003erxd_len \u003d len;\n-\n- lws_service_fd(lws_get_context(wsi), \u0026pollfd);\n-\n-}\n-\n-static void\n-esp8266_cb_sent(void *arg)\n-{\n-\tstruct espconn *conn \u003d arg;\n-\tstruct lws *wsi \u003d conn-\u003ereverse;\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\t\n-//\tlwsl_err(\u0022%s: wsi %p (psc %d) wsi-\u003eposition_in_fds_table\u003d%d\u005cn\u0022, __func__, wsi, wsi-\u003epending_send_completion, wsi-\u003eposition_in_fds_table);\n-\t\n-\twsi-\u003epending_send_completion--;\n-\tif (wsi-\u003eclose_is_pending_send_completion \u0026\u0026\n-\t !wsi-\u003epending_send_completion \u0026\u0026\n-\t !lws_partial_buffered(wsi)) {\n-\t\tlwsl_notice(\u0022doing delayed close\u005cn\u0022);\n-\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\t}\n-\t\n-\tif (pt-\u003efds[wsi-\u003eposition_in_fds_table].events \u0026 LWS_POLLOUT) {\n-\t\tstruct lws_pollfd pollfd;\n-\n-\t pollfd.fd \u003d arg;\n-\t pollfd.events \u003d LWS_POLLOUT;\n-\t pollfd.revents \u003d LWS_POLLOUT;\n-\n-//\t lwsl_notice(\u0022informing POLLOUT\u005cn\u0022);\n-\t \n-\t lws_service_fd(lws_get_context(wsi), \u0026pollfd);\n-\t}\n-}\n-\n-static void\n-esp8266_cb_disconnected(void *arg)\n-{\n-\tstruct espconn *conn \u003d arg;\n-\tstruct lws *wsi \u003d conn-\u003ereverse;\n-\tint n;\n-\n-\tlwsl_notice(\u0022%s: %p\u005cn\u0022, __func__, wsi);\n-\t\n-\tfor (n \u003d 0; n \u003c hacky_context-\u003emax_fds; n++)\n-\t\tif (hacky_context-\u003econnpool[n] \u003d\u003d arg) {\n-\t\t\thacky_context-\u003econnpool[n] \u003d NULL;\n-\t\t\tlwsl_info(\u0022 freed connpool %d\u005cn\u0022, n);\n-\t\t}\n-\t\n-\tif (wsi) {\n-\t\tconn-\u003ereverse \u003d NULL;\n-\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\t\tlwsl_notice(\u0022closed ok\u005cn\u0022);\n-\t}\n-}\n-\n-static void\n-esp8266_cb_recon(void *arg, signed char err)\n-{\n-\tstruct espconn *conn \u003d arg;\n-\n-\tlwsl_err(\u0022%s: wsi %p. err %d\u005cn\u0022, __func__, conn-\u003ereverse, err);\n-\n-\tconn-\u003estate \u003d ESPCONN_CLOSE;\t\t\n-\n-\tesp8266_cb_disconnected(arg);\t\n-}\n-\n-/*\n- * there is no reliable indication of which listen socket we were accepted on.\n- */\n-\n-static void\n-esp8266_cb_connect(void *arg)\n-{\n-\tstruct espconn *cs \u003d arg;\n-//\tstruct ip_addr *ipa \u003d (struct ip_addr *)cs-\u003eproto.tcp-\u003eremote_ip;\n-\tstruct lws_vhost *vh \u003d hacky_context-\u003evhost_list;\n-//\tstruct ip_info info;\n-\tstruct lws *wsi;\n-\tint n;\n-\n-\tlwsl_notice(\u0022%s: (wsi coming): %p\u005cn\u0022, __func__, cs-\u003ereverse);\n-#if 0\n-\twifi_get_ip_info(0, \u0026info);\n-\tif (ip_addr_netcmp(ipa, \u0026info.ip, \u0026info.netmask)) {\n-\t\t/* we are on the same subnet as the AP, ie, connected to AP */\n-\t\twhile (vh \u0026\u0026 strcmp(vh-\u003ename, \u0022ap\u0022))\n-\t\t\tvh \u003d vh-\u003evhost_next;\n-\t} else\n-\t\twhile (vh \u0026\u0026 !strcmp(vh-\u003ename, \u0022ap\u0022))\n-\t\t\tvh \u003d vh-\u003evhost_next;\n-\n-\tif (!vh)\n-\t\tgoto bail;\n-#endif\n-\tn \u003d esp8266_find_free_conn(hacky_context);\n-\tif (n \u003c 0)\n-\t\tgoto bail;\n-\t\n-\thacky_context-\u003econnpool[n] \u003d cs;\n-\t\n-\tespconn_recv_hold(cs);\n-\n-\twsi \u003d lws_adopt_socket_vhost(vh, cs);\n-\tif (!wsi)\n-\t\tgoto bail;\n-\t\n-\tlwsl_err(\u0022%s: wsi %p (using free_conn %d): vh %s\u005cn\u0022, __func__, wsi, n, vh-\u003ename);\n-\n-\tespconn_regist_recvcb(cs, esp8266_cb_rx);\n-\tespconn_regist_reconcb(cs, esp8266_cb_recon);\n-\tespconn_regist_disconcb(cs, esp8266_cb_disconnected);\n-\tespconn_regist_sentcb(cs, esp8266_cb_sent);\n-\t\n-\tespconn_set_opt(cs, ESPCONN_NODELAY | ESPCONN_REUSEADDR);\n-\tespconn_regist_time(cs, 7200, 1);\n-\n-\treturn;\n-\n-bail:\n-\tlwsl_err(\u0022%s: bailed]n\u0022, __func__);\n-\tespconn_disconnect(cs);\n-}\n-\n-void\n-esp8266_tcp_stream_bind(lws_sockfd_type fd, int port, struct lws *wsi)\n-{\n-\tfd-\u003eproto.tcp-\u003elocal_port \u003d port;\n-\tfd-\u003ereverse \u003d wsi;\n-\t\n-\thacky_context \u003d wsi-\u003econtext;\n-\t\n-\tespconn_regist_connectcb(fd, esp8266_cb_connect);\n-\t/* hmmm it means, listen() + accept() */\n-\tespconn_accept(fd);\n-\n-\tespconn_tcp_set_max_con_allow(fd, 10);\n-}\n-\n-void\n-esp8266_tcp_stream_accept(lws_sockfd_type fd, struct lws *wsi)\n-{\n-\tint n;\n-\n-\tfd-\u003ereverse \u003d wsi;\n-\n-\tfor (n \u003d 0; n \u003c wsi-\u003econtext-\u003emax_fds ; n++)\n-\t\tif (wsi-\u003econtext-\u003econnpool[n] \u003d\u003d wsi-\u003edesc.sockfd)\n-\t\t\twsi-\u003eposition_in_fds_table \u003d n;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n-{\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_context_early_init(void)\n-{\n-\tespconn_tcp_set_max_con(12);\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_early_destroy(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_late_destroy(struct lws_context *context)\n-{\n-#if 0\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-\tint m \u003d context-\u003ecount_threads;\n-\n-\tif (context-\u003elws_lookup)\n-\t\tlws_free(context-\u003elws_lookup);\n-\n-\twhile (m--) {\n-\t\tclose(pt-\u003edummy_pipe_fds[0]);\n-\t\tclose(pt-\u003edummy_pipe_fds[1]);\n-\t\tpt++;\n-\t}\n-#endif\n-//\tclose(context-\u003efd_random);\n-}\n-\n-/* cast a struct sockaddr_in6 * into addr for ipv6 */\n-\n-LWS_VISIBLE int\n-lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,\n-\t\t size_t addrlen)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\n-\tcontext-\u003econnpool[wsi-\u003eposition_in_fds_table + context-\u003emax_fds] \u003d (lws_sockfd_type)wsi;\n-\twsi-\u003edesc.sockfd-\u003ereverse \u003d wsi;\n-\tpt-\u003efds_count++;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_delete_socket_from_fds(struct lws_context *context,\n-\t\t\t\t\t\tstruct lws *wsi, int m)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\t\n-\tint n;\n-\t\n-\tfor (n \u003d 0; n \u003c wsi-\u003econtext-\u003emax_fds; n++)\n-\t\tif (wsi-\u003econtext-\u003econnpool[n] \u003d\u003d wsi-\u003edesc.sockfd) {\n-\t\t\twsi-\u003econtext-\u003econnpool[n] \u003d NULL;\n-\t\t\twsi-\u003econtext-\u003econnpool[n + wsi-\u003econtext-\u003emax_fds] \u003d NULL;\n-\t\t\tlwsl_notice(\u0022 freed connpool %d\u005cn\u0022, n);\n-\t\t}\n-\t\n-\twsi-\u003edesc.sockfd-\u003ereverse \u003d NULL;\n-\tpt-\u003efds_count--;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_service_periodic(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_change_pollfd(struct lws_context *context,\n-\t\t struct lws *wsi, struct lws_pollfd *pfd)\n-{\n-\tvoid *p;\n-\n-\t//lwsl_notice(\u0022%s: %p: wsi-\u003epift\u003d%d, events %d\u005cn\u0022,\n-\t//\t\t__func__, wsi, wsi-\u003eposition_in_fds_table, pfd-\u003eevents);\n-\t\n-\tif (pfd-\u003eevents \u0026 LWS_POLLIN) {\n-\t\tif (wsi-\u003epremature_rx) {\n-\t\t\tlwsl_notice(\u0022replaying buffered rx: wsi %p\u005cn\u0022, wsi);\n-\t\t\tp \u003d wsi-\u003epremature_rx;\n-\t\t\twsi-\u003epremature_rx \u003d NULL;\n-\t\t\tesp8266_cb_rx(wsi-\u003edesc.sockfd,\n-\t\t\t\t (char *)p + wsi-\u003eprem_rx_pos,\n-\t\t\t\t wsi-\u003eprem_rx_size - wsi-\u003eprem_rx_pos);\n-\t\t\twsi-\u003eprem_rx_size \u003d 0;\n-\t\t\twsi-\u003eprem_rx_pos \u003d 0;\n-\t\t\tlws_free(p);\n-\t\t}\n-\t\tif (espconn_recv_unhold(wsi-\u003edesc.sockfd) \u003c 0)\n-\t\t\treturn -1;\n-\t} else\n-\t\tif (espconn_recv_hold(wsi-\u003edesc.sockfd) \u003c 0)\n-\t\t\treturn -1;\n-\t\n-\tif (!(pfd-\u003eevents \u0026 LWS_POLLOUT))\n-\t\treturn 0;\n-\t\n-\tif (!wsi-\u003epending_send_completion) {\n-\t\tpfd-\u003erevents |\u003d LWS_POLLOUT;\n-\n-//\t\tlwsl_notice(\u0022doing POLLOUT\u005cn\u0022);\n-\t\tlws_service_fd(lws_get_context(wsi), pfd);\n-\t} //else\n-\t\t//lwsl_notice(\u0022pending sc\u005cn\u0022);\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE const char *\n-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n-{\n-//\treturn inet_ntop(af, src, dst, cnt);\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_inet_pton(int af, const char *src, void *dst)\n-{\n-\t//return inet_pton(af, src, dst);\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_init(struct lws_context *context,\n-\t struct lws_context_creation_info *info)\n-{\n-//\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-//\tint n \u003d context-\u003ecount_threads, fd;\n-\n-\t/* master context has the global fd lookup array */\n-\tcontext-\u003econnpool \u003d lws_zalloc(sizeof(struct espconn *) *\n-\t\t\t\t\t context-\u003emax_fds * 2, \u0022connpool\u0022);\n-\tif (context-\u003econnpool \u003d\u003d NULL) {\n-\t\tlwsl_err(\u0022OOM on lws_lookup array for %d connections\u005cn\u0022,\n-\t\t\t context-\u003emax_fds);\n-\t\treturn 1;\n-\t}\n-\n-\tlwsl_notice(\u0022 mem: platform fd map: %5u bytes\u005cn\u0022,\n-\t\t sizeof(struct espconn *) * context-\u003emax_fds);\n-//\tfd \u003d open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);\n-\n-//\tcontext-\u003efd_random \u003d fd;\n-//\tif (context-\u003efd_random \u003c 0) {\n-//\t\tlwsl_err(\u0022Unable to open random device %s %d\u005cn\u0022,\n-//\t\t\t SYSTEM_RANDOM_FILEPATH, context-\u003efd_random);\n-//\t\treturn 1;\n-//\t}\n-\n- os_memset(\u0026context-\u003eto_timer, 0, sizeof(os_timer_t));\n- os_timer_disarm(\u0026context-\u003eto_timer);\n- os_timer_setfn(\u0026context-\u003eto_timer, (os_timer_func_t *)cb_1Hz, context);\n- os_timer_arm(\u0026context-\u003eto_timer, 1000, 1);\n-\n-\tif (!lws_libev_init_fd_table(context) \u0026\u0026\n-\t !lws_libuv_init_fd_table(context) \u0026\u0026\n-\t !lws_libevent_init_fd_table(context)) {\n-\t\t/* otherwise libev handled it instead */\n-#if 0\n-\t\twhile (n--) {\n-\t\t\tif (pipe(pt-\u003edummy_pipe_fds)) {\n-\t\t\t\tlwsl_err(\u0022Unable to create pipe\u005cn\u0022);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\n-\t\t\t/* use the read end of pipe as first item */\n-\t\t\tpt-\u003efds[0].fd \u003d pt-\u003edummy_pipe_fds[0];\n-\t\t\tpt-\u003efds[0].events \u003d LWS_POLLIN;\n-\t\t\tpt-\u003efds[0].revents \u003d 0;\n-\t\t\tpt-\u003efds_count \u003d 1;\n-\t\t\tpt++;\n-\t\t}\n-#endif\n-\t}\n-\n-\n-#ifdef LWS_WITH_PLUGINS\n-\tif (info-\u003eplugin_dirs)\n-\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n-#endif\n-\n-\treturn 0;\n-}\ndiff --git a/lib/lws-plat-optee.c b/lib/lws-plat-optee.c\ndeleted file mode 100644\nindex fcd7763..0000000\n--- a/lib/lws-plat-optee.c\n+++ /dev/null\n@@ -1,329 +0,0 @@\n-#include \u0022private-libwebsockets.h\u0022\n-\n-/*\n- * included from libwebsockets.c for OPTEE builds\n- */\n-\n-void TEE_GenerateRandom(void *randomBuffer, uint32_t randomBufferLen);\n-\n-unsigned long long time_in_microseconds(void)\n-{\n-\treturn ((unsigned long long)time(NULL)) * 1000000;\n-}\n-#if 0\n-LWS_VISIBLE int\n-lws_get_random(struct lws_context *context, void *buf, int len)\n-{\n-\tTEE_GenerateRandom(buf, len);\n-\n-\treturn len;\n-}\n-#endif\n-LWS_VISIBLE int\n-lws_send_pipe_choked(struct lws *wsi)\n-{\n-#if 0\n-\tstruct lws_pollfd fds;\n-\n-\t/* treat the fact we got a truncated send pending as if we're choked */\n-\tif (wsi-\u003etrunc_len)\n-\t\treturn 1;\n-\n-\tfds.fd \u003d wsi-\u003edesc.sockfd;\n-\tfds.events \u003d POLLOUT;\n-\tfds.revents \u003d 0;\n-\n-\tif (poll(\u0026fds, 1, 0) !\u003d 1)\n-\t\treturn 1;\n-\n-\tif ((fds.revents \u0026 POLLOUT) \u003d\u003d 0)\n-\t\treturn 1;\n-#endif\n-\t/* okay to send another packet without blocking */\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_poll_listen_fd(struct lws_pollfd *fd)\n-{\n-//\treturn poll(fd, 1, 0);\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service_pt(struct lws *wsi)\n-{\n-#if 0\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tchar buf \u003d 0;\n-\n-\tif (write(pt-\u003edummy_pipe_fds[1], \u0026buf, sizeof(buf)) !\u003d 1)\n-\t\tlwsl_err(\u0022Cannot write to dummy pipe\u0022);\n-#endif\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service(struct lws_context *context)\n-{\n-#if 0\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-\tchar buf \u003d 0, m \u003d context-\u003ecount_threads;\n-\n-\twhile (m--) {\n-\t\tif (write(pt-\u003edummy_pipe_fds[1], \u0026buf, sizeof(buf)) !\u003d 1)\n-\t\t\tlwsl_err(\u0022Cannot write to dummy pipe\u0022);\n-\t\tpt++;\n-\t}\n-#endif\n-}\n-#if 0\n-LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n-{\n-\tIMSG(\u0022%d: %s\u005cn\u0022, level, line);\n-}\n-#endif\n-\n-LWS_VISIBLE LWS_EXTERN int\n-_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n-{\n-\tstruct lws_context_per_thread *pt;\n-\tint n \u003d -1, m, c;\n-\t//char buf;\n-\n-\t/* stay dead once we are dead */\n-\n-\tif (!context || !context-\u003evhost_list)\n-\t\treturn 1;\n-\n-\tpt \u003d \u0026context-\u003ept[tsi];\n-\n-\tif (timeout_ms \u003c 0)\n-\t\tgoto faked_service;\n-\n-\tif (!context-\u003eservice_tid_detected) {\n-\t\tstruct lws _lws;\n-\n-\t\tmemset(\u0026_lws, 0, sizeof(_lws));\n-\t\t_lws.context \u003d context;\n-\n-\t\tcontext-\u003eservice_tid_detected \u003d\n-\t\t\tcontext-\u003evhost_list-\u003eprotocols[0].callback(\n-\t\t\t\u0026_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);\n-\t}\n-\tcontext-\u003eservice_tid \u003d context-\u003eservice_tid_detected;\n-\n-\t/*\n-\t * is there anybody with pending stuff that needs service forcing?\n-\t */\n-\tif (!lws_service_adjust_timeout(context, 1, tsi)) {\n-\t\tlwsl_notice(\u0022%s: doing forced service\u005cn\u0022, __func__);\n-\t\t/* -1 timeout means just do forced service */\n-\t\t_lws_plat_service_tsi(context, -1, pt-\u003etid);\n-\t\t/* still somebody left who wants forced service? */\n-\t\tif (!lws_service_adjust_timeout(context, 1, pt-\u003etid))\n-\t\t\t/* yes... come back again quickly */\n-\t\t\ttimeout_ms \u003d 0;\n-\t}\n-#if 1\n-\tn \u003d poll(pt-\u003efds, pt-\u003efds_count, timeout_ms);\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\tif (!pt-\u003erx_draining_ext_list \u0026\u0026\n-\t !lws_ssl_anybody_has_buffered_read_tsi(context, tsi) \u0026\u0026 !n) {\n-#else\n-\tif (!pt-\u003erx_draining_ext_list \u0026\u0026 !n) /* poll timeout */ {\n-#endif\n-\t\tlws_service_fd_tsi(context, NULL, tsi);\n-\t\treturn 0;\n-\t}\n-#endif\n-faked_service:\n-\tm \u003d lws_service_flag_pending(context, tsi);\n-\tif (m)\n-\t\tc \u003d -1; /* unknown limit */\n-\telse\n-\t\tif (n \u003c 0) {\n-\t\t\tif (LWS_ERRNO !\u003d LWS_EINTR)\n-\t\t\t\treturn -1;\n-\t\t\treturn 0;\n-\t\t} else\n-\t\t\tc \u003d n;\n-\n-\t/* any socket with events to service? */\n-\tfor (n \u003d 0; n \u003c pt-\u003efds_count \u0026\u0026 c; n++) {\n-\t\tif (!pt-\u003efds[n].revents)\n-\t\t\tcontinue;\n-\n-\t\tc--;\n-#if 0\n-\t\tif (pt-\u003efds[n].fd \u003d\u003d pt-\u003edummy_pipe_fds[0]) {\n-\t\t\tif (read(pt-\u003efds[n].fd, \u0026buf, 1) !\u003d 1)\n-\t\t\t\tlwsl_err(\u0022Cannot read from dummy pipe.\u0022);\n-\t\t\tcontinue;\n-\t\t}\n-#endif\n-\t\tm \u003d lws_service_fd_tsi(context, \u0026pt-\u003efds[n], tsi);\n-\t\tif (m \u003c 0)\n-\t\t\treturn -1;\n-\t\t/* if something closed, retry this slot */\n-\t\tif (m)\n-\t\t\tn--;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_check_connection_error(struct lws *wsi)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_service(struct lws_context *context, int timeout_ms)\n-{\n-\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n-{\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_context_early_init(void)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_early_destroy(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_late_destroy(struct lws_context *context)\n-{\n-\tif (context-\u003elws_lookup)\n-\t\tlws_free(context-\u003elws_lookup);\n-}\n-\n-/* cast a struct sockaddr_in6 * into addr for ipv6 */\n-\n-LWS_VISIBLE int\n-lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,\n-\t\t size_t addrlen)\n-{\n-\treturn -1;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\n-\tpt-\u003efds[pt-\u003efds_count++].revents \u003d 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_delete_socket_from_fds(struct lws_context *context,\n-\t\t\t\t\t\tstruct lws *wsi, int m)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\n-\tpt-\u003efds_count--;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_service_periodic(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_change_pollfd(struct lws_context *context,\n-\t\t struct lws *wsi, struct lws_pollfd *pfd)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE const char *\n-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n-{\n-\t//return inet_ntop(af, src, dst, cnt);\n-\treturn \u0022lws_plat_inet_ntop\u0022;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_inet_pton(int af, const char *src, void *dst)\n-{\n-\t//return inet_pton(af, src, dst);\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE lws_fop_fd_t\n-_lws_plat_file_open(lws_plat_file_open(struct lws_plat_file_ops *fops,\n-\t\t const char *filename, lws_fop_flags_t *flags)\n-{\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE int\n-_lws_plat_file_close(lws_fop_fd_t *fop_fd)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE lws_fileofs_t\n-_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n-\t\t uint8_t *buf, lws_filepos_t len)\n-{\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n-\t\t uint8_t *buf, lws_filepos_t len)\n-{\n-\n-\treturn 0;\n-}\n-\n-\n-LWS_VISIBLE int\n-lws_plat_init(struct lws_context *context,\n-\t struct lws_context_creation_info *info)\n-{\n-\t/* master context has the global fd lookup array */\n-\tcontext-\u003elws_lookup \u003d lws_zalloc(sizeof(struct lws *) *\n-\t\t\t\t\t context-\u003emax_fds, \u0022lws_lookup\u0022);\n-\tif (context-\u003elws_lookup \u003d\u003d NULL) {\n-\t\tlwsl_err(\u0022OOM on lws_lookup array for %d connections\u005cn\u0022,\n-\t\t\t context-\u003emax_fds);\n-\t\treturn 1;\n-\t}\n-\n-\tlwsl_notice(\u0022 mem: platform fd map: %5lu bytes\u005cn\u0022,\n-\t\t (long)sizeof(struct lws *) * context-\u003emax_fds);\n-\n-#ifdef LWS_WITH_PLUGINS\n-\tif (info-\u003eplugin_dirs)\n-\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n-#endif\n-\n-\treturn 0;\n-}\ndiff --git a/lib/lws-plat-unix.c b/lib/lws-plat-unix.c\ndeleted file mode 100644\nindex f553691..0000000\n--- a/lib/lws-plat-unix.c\n+++ /dev/null\n@@ -1,849 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-#include \u003cpwd.h\u003e\n-#include \u003cgrp.h\u003e\n-\n-#ifdef LWS_WITH_PLUGINS\n-#include \u003cdlfcn.h\u003e\n-#endif\n-#include \u003cdirent.h\u003e\n-\n-unsigned long long time_in_microseconds(void)\n-{\n-\tstruct timeval tv;\n-\n-\tgettimeofday(\u0026tv, NULL);\n-\treturn ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;\n-}\n-\n-LWS_VISIBLE int\n-lws_get_random(struct lws_context *context, void *buf, int len)\n-{\n-\treturn read(context-\u003efd_random, (char *)buf, len);\n-}\n-\n-LWS_VISIBLE int\n-lws_send_pipe_choked(struct lws *wsi)\n-{\n-\tstruct lws_pollfd fds;\n-\tstruct lws *wsi_eff \u003d wsi;\n-\n-#if defined(LWS_WITH_HTTP2)\n-\twsi_eff \u003d lws_get_network_wsi(wsi);\n-#endif\n-\t/* treat the fact we got a truncated send pending as if we're choked */\n-\tif (wsi_eff-\u003etrunc_len)\n-\t\treturn 1;\n-\n-\tfds.fd \u003d wsi_eff-\u003edesc.sockfd;\n-\tfds.events \u003d POLLOUT;\n-\tfds.revents \u003d 0;\n-\n-\tif (poll(\u0026fds, 1, 0) !\u003d 1)\n-\t\treturn 1;\n-\n-\tif ((fds.revents \u0026 POLLOUT) \u003d\u003d 0)\n-\t\treturn 1;\n-\n-\t/* okay to send another packet without blocking */\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_poll_listen_fd(struct lws_pollfd *fd)\n-{\n-\treturn poll(fd, 1, 0);\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service_pt(struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tchar buf \u003d 0;\n-\n-\tif (write(pt-\u003edummy_pipe_fds[1], \u0026buf, sizeof(buf)) !\u003d 1)\n-\t\tlwsl_err(\u0022Cannot write to dummy pipe\u0022);\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service(struct lws_context *context)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-\tchar buf \u003d 0, m \u003d context-\u003ecount_threads;\n-\n-\twhile (m--) {\n-\t\tif (write(pt-\u003edummy_pipe_fds[1], \u0026buf, sizeof(buf)) !\u003d 1)\n-\t\t\tlwsl_err(\u0022Cannot write to dummy pipe\u0022);\n-\t\tpt++;\n-\t}\n-}\n-\n-LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n-{\n-\tint syslog_level \u003d LOG_DEBUG;\n-\n-\tswitch (level) {\n-\tcase LLL_ERR:\n-\t\tsyslog_level \u003d LOG_ERR;\n-\t\tbreak;\n-\tcase LLL_WARN:\n-\t\tsyslog_level \u003d LOG_WARNING;\n-\t\tbreak;\n-\tcase LLL_NOTICE:\n-\t\tsyslog_level \u003d LOG_NOTICE;\n-\t\tbreak;\n-\tcase LLL_INFO:\n-\t\tsyslog_level \u003d LOG_INFO;\n-\t\tbreak;\n-\t}\n-\tsyslog(syslog_level, \u0022%s\u0022, line);\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n-{\n-\tstruct lws_context_per_thread *pt;\n-\tint n \u003d -1, m, c;\n-\tchar buf;\n-\n-\t/* stay dead once we are dead */\n-\n-\tif (!context || !context-\u003evhost_list)\n-\t\treturn 1;\n-\n-\tpt \u003d \u0026context-\u003ept[tsi];\n-\n-\tlws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);\n-\n-\tif (timeout_ms \u003c 0)\n-\t\tgoto faked_service;\n-\n-\tlws_libev_run(context, tsi);\n-\tlws_libuv_run(context, tsi);\n-\tlws_libevent_run(context, tsi);\n-\n-\tif (!context-\u003eservice_tid_detected) {\n-\t\tstruct lws _lws;\n-\n-\t\tmemset(\u0026_lws, 0, sizeof(_lws));\n-\t\t_lws.context \u003d context;\n-\n-\t\tcontext-\u003eservice_tid_detected \u003d\n-\t\t\tcontext-\u003evhost_list-\u003eprotocols[0].callback(\n-\t\t\t\u0026_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);\n-\t}\n-\tcontext-\u003eservice_tid \u003d context-\u003eservice_tid_detected;\n-\n-\t/*\n-\t * is there anybody with pending stuff that needs service forcing?\n-\t */\n-\tif (!lws_service_adjust_timeout(context, 1, tsi)) {\n-\t\t/* -1 timeout means just do forced service */\n-\t\t_lws_plat_service_tsi(context, -1, pt-\u003etid);\n-\t\t/* still somebody left who wants forced service? */\n-\t\tif (!lws_service_adjust_timeout(context, 1, pt-\u003etid))\n-\t\t\t/* yes... come back again quickly */\n-\t\t\ttimeout_ms \u003d 0;\n-\t}\n-\n-\tn \u003d poll(pt-\u003efds, pt-\u003efds_count, timeout_ms);\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\tif (!pt-\u003erx_draining_ext_list \u0026\u0026\n-\t !lws_ssl_anybody_has_buffered_read_tsi(context, tsi) \u0026\u0026 !n) {\n-#else\n-\tif (!pt-\u003erx_draining_ext_list \u0026\u0026 !n) /* poll timeout */ {\n-#endif\n-\t\tlws_service_fd_tsi(context, NULL, tsi);\n-\t\treturn 0;\n-\t}\n-\n-faked_service:\n-\tm \u003d lws_service_flag_pending(context, tsi);\n-\tif (m)\n-\t\tc \u003d -1; /* unknown limit */\n-\telse\n-\t\tif (n \u003c 0) {\n-\t\t\tif (LWS_ERRNO !\u003d LWS_EINTR)\n-\t\t\t\treturn -1;\n-\t\t\treturn 0;\n-\t\t} else\n-\t\t\tc \u003d n;\n-\n-\t/* any socket with events to service? */\n-\tfor (n \u003d 0; n \u003c pt-\u003efds_count \u0026\u0026 c; n++) {\n-\t\tif (!pt-\u003efds[n].revents)\n-\t\t\tcontinue;\n-\n-\t\tc--;\n-\n-\t\tif (pt-\u003efds[n].fd \u003d\u003d pt-\u003edummy_pipe_fds[0]) {\n-\t\t\tif (read(pt-\u003efds[n].fd, \u0026buf, 1) !\u003d 1)\n-\t\t\t\tlwsl_err(\u0022Cannot read from dummy pipe.\u0022);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tm \u003d lws_service_fd_tsi(context, \u0026pt-\u003efds[n], tsi);\n-\t\tif (m \u003c 0)\n-\t\t\treturn -1;\n-\t\t/* if something closed, retry this slot */\n-\t\tif (m)\n-\t\t\tn--;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_check_connection_error(struct lws *wsi)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_service(struct lws_context *context, int timeout_ms)\n-{\n-\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)\n-{\n-\tint optval \u003d 1;\n-\tsocklen_t optlen \u003d sizeof(optval);\n-\n-#if defined(__APPLE__) || \u005c\n- defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \u005c\n- defined(__NetBSD__) || \u005c\n- defined(__OpenBSD__) || \u005c\n- defined(__HAIKU__)\n-\tstruct protoent *tcp_proto;\n-#endif\n-\n-\tif (vhost-\u003eka_time) {\n-\t\t/* enable keepalive on this socket */\n-\t\toptval \u003d 1;\n-\t\tif (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,\n-\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n-\t\t\treturn 1;\n-\n-#if defined(__APPLE__) || \u005c\n- defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \u005c\n- defined(__NetBSD__) || \u005c\n- defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun) || \u005c\n- defined(__HAIKU__)\n-\n-\t\t/*\n-\t\t * didn't find a way to set these per-socket, need to\n-\t\t * tune kernel systemwide values\n-\t\t */\n-#else\n-\t\t/* set the keepalive conditions we want on it too */\n-\t\toptval \u003d vhost-\u003eka_time;\n-\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,\n-\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n-\t\t\treturn 1;\n-\n-\t\toptval \u003d vhost-\u003eka_interval;\n-\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,\n-\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n-\t\t\treturn 1;\n-\n-\t\toptval \u003d vhost-\u003eka_probes;\n-\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,\n-\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n-\t\t\treturn 1;\n-#endif\n-\t}\n-\n-#if defined(SO_BINDTODEVICE)\n-\tif (vhost-\u003ebind_iface \u0026\u0026 vhost-\u003eiface) {\n-\t\tlwsl_info(\u0022binding listen skt to %s using SO_BINDTODEVICE\u005cn\u0022, vhost-\u003eiface);\n-\t\tif (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost-\u003eiface,\n-\t\t\t\tstrlen(vhost-\u003eiface)) \u003c 0) {\n-\t\t\tlwsl_warn(\u0022Failed to bind to device %s\u005cn\u0022, vhost-\u003eiface);\n-\t\t\treturn 1;\n-\t\t}\n-\t}\n-#endif\n-\n-\t/* Disable Nagle */\n-\toptval \u003d 1;\n-#if defined (__sun)\n-\tif (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)\u0026optval, optlen) \u003c 0)\n-\t\treturn 1;\n-#elif !defined(__APPLE__) \u0026\u0026 \u005c\n- !defined(__FreeBSD__) \u0026\u0026 !defined(__FreeBSD_kernel__) \u0026\u0026 \u005c\n- !defined(__NetBSD__) \u0026\u0026 \u005c\n- !defined(__OpenBSD__) \u0026\u0026 \u005c\n- !defined(__HAIKU__)\n-\tif (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)\u0026optval, optlen) \u003c 0)\n-\t\treturn 1;\n-#else\n-\ttcp_proto \u003d getprotobyname(\u0022TCP\u0022);\n-\tif (setsockopt(fd, tcp_proto-\u003ep_proto, TCP_NODELAY, \u0026optval, optlen) \u003c 0)\n-\t\treturn 1;\n-#endif\n-\n-\t/* We are nonblocking... */\n-\tif (fcntl(fd, F_SETFL, O_NONBLOCK) \u003c 0)\n-\t\treturn 1;\n-\n-\treturn 0;\n-}\n-\n-#if defined(LWS_HAVE_SYS_CAPABILITY_H) \u0026\u0026 defined(LWS_HAVE_LIBCAP)\n-static void\n-_lws_plat_apply_caps(int mode, cap_value_t *cv, int count)\n-{\n-\tcap_t caps;\n-\n-\tif (!count)\n-\t\treturn;\n-\n-\tcaps \u003d cap_get_proc();\n-\n-\tcap_set_flag(caps, mode, count, cv, CAP_SET);\n-\tcap_set_proc(caps);\n-\tprctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);\n-\tcap_free(caps);\n-}\n-#endif\n-\n-LWS_VISIBLE void\n-lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n-{\n-#if defined(LWS_HAVE_SYS_CAPABILITY_H) \u0026\u0026 defined(LWS_HAVE_LIBCAP)\n-\tint n;\n-#endif\n-\n-\tif (info-\u003egid \u0026\u0026 info-\u003egid !\u003d -1)\n-\t\tif (setgid(info-\u003egid))\n-\t\t\tlwsl_warn(\u0022setgid: %s\u005cn\u0022, strerror(LWS_ERRNO));\n-\n-\tif (info-\u003euid \u0026\u0026 info-\u003euid !\u003d -1) {\n-\t\tstruct passwd *p \u003d getpwuid(info-\u003euid);\n-\n-\t\tif (p) {\n-\n-#if defined(LWS_HAVE_SYS_CAPABILITY_H) \u0026\u0026 defined(LWS_HAVE_LIBCAP)\n-\t\t\t_lws_plat_apply_caps(CAP_PERMITTED, info-\u003ecaps, info-\u003ecount_caps);\n-#endif\n-\n-\t\t\tinitgroups(p-\u003epw_name, info-\u003egid);\n-\t\t\tif (setuid(info-\u003euid))\n-\t\t\t\tlwsl_warn(\u0022setuid: %s\u005cn\u0022, strerror(LWS_ERRNO));\n-\t\t\telse\n-\t\t\t\tlwsl_notice(\u0022Set privs to user '%s'\u005cn\u0022, p-\u003epw_name);\n-\n-#if defined(LWS_HAVE_SYS_CAPABILITY_H) \u0026\u0026 defined(LWS_HAVE_LIBCAP)\n-\t\t\t_lws_plat_apply_caps(CAP_EFFECTIVE, info-\u003ecaps, info-\u003ecount_caps);\n-\n-\t\t\tif (info-\u003ecount_caps)\n-\t\t\t\tfor (n \u003d 0; n \u003c info-\u003ecount_caps; n++)\n-\t\t\t\t\tlwsl_notice(\u0022 RETAINING CAPABILITY %d\u005cn\u0022, (int)info-\u003ecaps[n]);\n-#endif\n-\n-\t\t} else\n-\t\t\tlwsl_warn(\u0022getpwuid: unable to find uid %d\u0022, info-\u003euid);\n-\t}\n-}\n-\n-#ifdef LWS_WITH_PLUGINS\n-\n-#if defined(LWS_WITH_LIBUV) \u0026\u0026 UV_VERSION_MAJOR \u003e 0\n-\n-/* libuv.c implements these in a cross-platform way */\n-\n-#else\n-\n-static int filter(const struct dirent *ent)\n-{\n-\tif (!strcmp(ent-\u003ed_name, \u0022.\u0022) || !strcmp(ent-\u003ed_name, \u0022..\u0022))\n-\t\treturn 0;\n-\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_plugins_init(struct lws_context * context, const char * const *d)\n-{\n-\tstruct lws_plugin_capability lcaps;\n-\tstruct lws_plugin *plugin;\n-\tlws_plugin_init_func initfunc;\n-\tstruct dirent **namelist;\n-\tint n, i, m, ret \u003d 0;\n-\tchar path[256];\n-\tvoid *l;\n-\n-\tlwsl_notice(\u0022 Plugins:\u005cn\u0022);\n-\n-\twhile (d \u0026\u0026 *d) {\n-\t\tn \u003d scandir(*d, \u0026namelist, filter, alphasort);\n-\t\tif (n \u003c 0) {\n-\t\t\tlwsl_err(\u0022Scandir on %s failed\u005cn\u0022, *d);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\tfor (i \u003d 0; i \u003c n; i++) {\n-\t\t\tif (strlen(namelist[i]-\u003ed_name) \u003c 7)\n-\t\t\t\tgoto inval;\n-\n-\t\t\tlwsl_notice(\u0022 %s\u005cn\u0022, namelist[i]-\u003ed_name);\n-\n-\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, *d,\n-\t\t\t\t namelist[i]-\u003ed_name);\n-\t\t\tl \u003d dlopen(path, RTLD_NOW);\n-\t\t\tif (!l) {\n-\t\t\t\tlwsl_err(\u0022Error loading DSO: %s\u005cn\u0022, dlerror());\n-\t\t\t\twhile (i++ \u003c n)\n-\t\t\t\t\tfree(namelist[i]);\n-\t\t\t\tgoto bail;\n-\t\t\t}\n-\t\t\t/* we could open it, can we get his init function? */\n-\t\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022init_%s\u0022,\n-\t\t\t\t namelist[i]-\u003ed_name + 3 /* snip lib... */);\n-\t\t\tpath[m - 3] \u003d '\u005c0'; /* snip the .so */\n-\t\t\tinitfunc \u003d dlsym(l, path);\n-\t\t\tif (!initfunc) {\n-\t\t\t\tlwsl_err(\u0022Failed to get init on %s: %s\u0022,\n-\t\t\t\t\t\tnamelist[i]-\u003ed_name, dlerror());\n-\t\t\t\tdlclose(l);\n-\t\t\t}\n-\t\t\tlcaps.api_magic \u003d LWS_PLUGIN_API_MAGIC;\n-\t\t\tm \u003d initfunc(context, \u0026lcaps);\n-\t\t\tif (m) {\n-\t\t\t\tlwsl_err(\u0022Initializing %s failed %d\u005cn\u0022,\n-\t\t\t\t\tnamelist[i]-\u003ed_name, m);\n-\t\t\t\tdlclose(l);\n-\t\t\t\tgoto skip;\n-\t\t\t}\n-\n-\t\t\tplugin \u003d lws_malloc(sizeof(*plugin), \u0022plugin\u0022);\n-\t\t\tif (!plugin) {\n-\t\t\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n-\t\t\t\tgoto bail;\n-\t\t\t}\n-\t\t\tplugin-\u003elist \u003d context-\u003eplugin_list;\n-\t\t\tcontext-\u003eplugin_list \u003d plugin;\n-\t\t\tstrncpy(plugin-\u003ename, namelist[i]-\u003ed_name, sizeof(plugin-\u003ename) - 1);\n-\t\t\tplugin-\u003ename[sizeof(plugin-\u003ename) - 1] \u003d '\u005c0';\n-\t\t\tplugin-\u003el \u003d l;\n-\t\t\tplugin-\u003ecaps \u003d lcaps;\n-\t\t\tcontext-\u003eplugin_protocol_count +\u003d lcaps.count_protocols;\n-\t\t\tcontext-\u003eplugin_extension_count +\u003d lcaps.count_extensions;\n-\n-\t\t\tfree(namelist[i]);\n-\t\t\tcontinue;\n-\n-\tskip:\n-\t\t\tdlclose(l);\n-\tinval:\n-\t\t\tfree(namelist[i]);\n-\t\t}\n-\t\tfree(namelist);\n-\t\td++;\n-\t}\n-\n-bail:\n-\tfree(namelist);\n-\n-\treturn ret;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_plugins_destroy(struct lws_context * context)\n-{\n-\tstruct lws_plugin *plugin \u003d context-\u003eplugin_list, *p;\n-\tlws_plugin_destroy_func func;\n-\tchar path[256];\n-\tint m;\n-\n-\tif (!plugin)\n-\t\treturn 0;\n-\n-\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n-\n-\twhile (plugin) {\n-\t\tp \u003d plugin;\n-\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022destroy_%s\u0022, plugin-\u003ename + 3);\n-\t\tpath[m - 3] \u003d '\u005c0';\n-\t\tfunc \u003d dlsym(plugin-\u003el, path);\n-\t\tif (!func) {\n-\t\t\tlwsl_err(\u0022Failed to get destroy on %s: %s\u0022,\n-\t\t\t\t\tplugin-\u003ename, dlerror());\n-\t\t\tgoto next;\n-\t\t}\n-\t\tm \u003d func(context);\n-\t\tif (m)\n-\t\t\tlwsl_err(\u0022Initializing %s failed %d\u005cn\u0022,\n-\t\t\t\tplugin-\u003ename, m);\n-next:\n-\t\tdlclose(p-\u003el);\n-\t\tplugin \u003d p-\u003elist;\n-\t\tp-\u003elist \u003d NULL;\n-\t\tfree(p);\n-\t}\n-\n-\tcontext-\u003eplugin_list \u003d NULL;\n-\n-\treturn 0;\n-}\n-\n-#endif\n-#endif\n-\n-\n-#if 0\n-static void\n-sigabrt_handler(int x)\n-{\n-\tprintf(\u0022%s\u005cn\u0022, __func__);\n-}\n-#endif\n-\n-LWS_VISIBLE int\n-lws_plat_context_early_init(void)\n-{\n-#if !defined(LWS_AVOID_SIGPIPE_IGN)\n-\tsignal(SIGPIPE, SIG_IGN);\n-#endif\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_early_destroy(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_late_destroy(struct lws_context *context)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-\tint m \u003d context-\u003ecount_threads;\n-\n-#ifdef LWS_WITH_PLUGINS\n-\tif (context-\u003eplugin_list)\n-\t\tlws_plat_plugins_destroy(context);\n-#endif\n-\n-\tif (context-\u003elws_lookup)\n-\t\tlws_free(context-\u003elws_lookup);\n-\n-\twhile (m--) {\n-\t\tif (pt-\u003edummy_pipe_fds[0])\n-\t\t\tclose(pt-\u003edummy_pipe_fds[0]);\n-\t\tif (pt-\u003edummy_pipe_fds[1])\n-\t\t\tclose(pt-\u003edummy_pipe_fds[1]);\n-\t\tpt++;\n-\t}\n-\tif (!context-\u003efd_random)\n-\t\tlwsl_err(\u0022ZERO RANDOM FD\u005cn\u0022);\n-\tif (context-\u003efd_random !\u003d LWS_INVALID_FILE)\n-\t\tclose(context-\u003efd_random);\n-}\n-\n-/* cast a struct sockaddr_in6 * into addr for ipv6 */\n-\n-LWS_VISIBLE int\n-lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,\n-\t\t size_t addrlen)\n-{\n-\tint rc \u003d -1;\n-\n-\tstruct ifaddrs *ifr;\n-\tstruct ifaddrs *ifc;\n-#ifdef LWS_WITH_IPV6\n-\tstruct sockaddr_in6 *addr6 \u003d (struct sockaddr_in6 *)addr;\n-#endif\n-\n-\tgetifaddrs(\u0026ifr);\n-\tfor (ifc \u003d ifr; ifc !\u003d NULL \u0026\u0026 rc; ifc \u003d ifc-\u003eifa_next) {\n-\t\tif (!ifc-\u003eifa_addr)\n-\t\t\tcontinue;\n-\n-\t\tlwsl_info(\u0022 interface %s vs %s\u005cn\u0022, ifc-\u003eifa_name, ifname);\n-\n-\t\tif (strcmp(ifc-\u003eifa_name, ifname))\n-\t\t\tcontinue;\n-\n-\t\tswitch (ifc-\u003eifa_addr-\u003esa_family) {\n-\t\tcase AF_INET:\n-#ifdef LWS_WITH_IPV6\n-\t\t\tif (ipv6) {\n-\t\t\t\t/* map IPv4 to IPv6 */\n-\t\t\t\tbzero((char *)\u0026addr6-\u003esin6_addr,\n-\t\t\t\t\t\tsizeof(struct in6_addr));\n-\t\t\t\taddr6-\u003esin6_addr.s6_addr[10] \u003d 0xff;\n-\t\t\t\taddr6-\u003esin6_addr.s6_addr[11] \u003d 0xff;\n-\t\t\t\tmemcpy(\u0026addr6-\u003esin6_addr.s6_addr[12],\n-\t\t\t\t\t\u0026((struct sockaddr_in *)ifc-\u003eifa_addr)-\u003esin_addr,\n-\t\t\t\t\t\t\tsizeof(struct in_addr));\n-\t\t\t} else\n-#endif\n-\t\t\t\tmemcpy(addr,\n-\t\t\t\t\t(struct sockaddr_in *)ifc-\u003eifa_addr,\n-\t\t\t\t\t\t sizeof(struct sockaddr_in));\n-\t\t\tbreak;\n-#ifdef LWS_WITH_IPV6\n-\t\tcase AF_INET6:\n-\t\t\tmemcpy(\u0026addr6-\u003esin6_addr,\n-\t\t\t \u0026((struct sockaddr_in6 *)ifc-\u003eifa_addr)-\u003esin6_addr,\n-\t\t\t\t\t\t sizeof(struct in6_addr));\n-\t\t\tbreak;\n-#endif\n-\t\tdefault:\n-\t\t\tcontinue;\n-\t\t}\n-\t\trc \u003d 0;\n-\t}\n-\n-\tfreeifaddrs(ifr);\n-\n-\tif (rc \u003d\u003d -1) {\n-\t\t/* check if bind to IP address */\n-#ifdef LWS_WITH_IPV6\n-\t\tif (inet_pton(AF_INET6, ifname, \u0026addr6-\u003esin6_addr) \u003d\u003d 1)\n-\t\t\trc \u003d 0;\n-\t\telse\n-#endif\n-\t\tif (inet_pton(AF_INET, ifname, \u0026addr-\u003esin_addr) \u003d\u003d 1)\n-\t\t\trc \u003d 0;\n-\t}\n-\n-\treturn rc;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\n-\tlws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);\n-\tlws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);\n-\tlws_libevent_io(wsi, LWS_EV_START | LWS_EV_READ);\n-\n-\tpt-\u003efds[pt-\u003efds_count++].revents \u003d 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_delete_socket_from_fds(struct lws_context *context,\n-\t\t\t\t\t\tstruct lws *wsi, int m)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\n-\tlws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);\n-\tlws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);\n-\tlws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);\n-\n-\tpt-\u003efds_count--;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_service_periodic(struct lws_context *context)\n-{\n-\t/* if our parent went down, don't linger around */\n-\tif (context-\u003estarted_with_parent \u0026\u0026\n-\t kill(context-\u003estarted_with_parent, 0) \u003c 0)\n-\t\tkill(getpid(), SIGTERM);\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_change_pollfd(struct lws_context *context,\n-\t\t struct lws *wsi, struct lws_pollfd *pfd)\n-{\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE const char *\n-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n-{\n-\treturn inet_ntop(af, src, dst, cnt);\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_inet_pton(int af, const char *src, void *dst)\n-{\n-\treturn inet_pton(af, src, dst);\n-}\n-\n-LWS_VISIBLE lws_fop_fd_t\n-_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,\n-\t\t const char *vpath, lws_fop_flags_t *flags)\n-{\n-\tstruct stat stat_buf;\n-\tint ret \u003d open(filename, (*flags) \u0026 LWS_FOP_FLAGS_MASK, 0664);\n-\tlws_fop_fd_t fop_fd;\n-\n-\tif (ret \u003c 0)\n-\t\treturn NULL;\n-\n-\tif (fstat(ret, \u0026stat_buf) \u003c 0)\n-\t\tgoto bail;\n-\n-\tfop_fd \u003d malloc(sizeof(*fop_fd));\n-\tif (!fop_fd)\n-\t\tgoto bail;\n-\n-\tfop_fd-\u003efops \u003d fops;\n-\tfop_fd-\u003eflags \u003d *flags;\n-\tfop_fd-\u003efd \u003d ret;\n-\tfop_fd-\u003efilesystem_priv \u003d NULL; /* we don't use it */\n-\tfop_fd-\u003elen \u003d stat_buf.st_size;\n-\tfop_fd-\u003epos \u003d 0;\n-\n-\treturn fop_fd;\n-\n-bail:\n-\tclose(ret);\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE int\n-_lws_plat_file_close(lws_fop_fd_t *fop_fd)\n-{\n-\tint fd \u003d (*fop_fd)-\u003efd;\n-\n-\tfree(*fop_fd);\n-\t*fop_fd \u003d NULL;\n-\n-\treturn close(fd);\n-}\n-\n-LWS_VISIBLE lws_fileofs_t\n-_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)\n-{\n-\tlws_fileofs_t r;\n-\n-\tif (offset \u003e 0 \u0026\u0026 offset \u003e fop_fd-\u003elen - fop_fd-\u003epos)\n-\t\toffset \u003d fop_fd-\u003elen - fop_fd-\u003epos;\n-\n-\tif ((lws_fileofs_t)fop_fd-\u003epos + offset \u003c 0)\n-\t\toffset \u003d -fop_fd-\u003epos;\n-\n-\tr \u003d lseek(fop_fd-\u003efd, offset, SEEK_CUR);\n-\n-\tif (r \u003e\u003d 0)\n-\t\tfop_fd-\u003epos \u003d r;\n-\telse\n-\t\tlwsl_err(\u0022error seeking from cur %ld, offset %ld\u005cn\u0022,\n- (long)fop_fd-\u003epos, (long)offset);\n-\n-\treturn r;\n-}\n-\n-LWS_VISIBLE int\n-_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n-\t\t uint8_t *buf, lws_filepos_t len)\n-{\n-\tlong n;\n-\n-\tn \u003d read((int)fop_fd-\u003efd, buf, len);\n-\tif (n \u003d\u003d -1) {\n-\t\t*amount \u003d 0;\n-\t\treturn -1;\n-\t}\n-\tfop_fd-\u003epos +\u003d n;\n-\tlwsl_debug(\u0022%s: read %ld of req %ld, pos %ld, len %ld\u005cn\u0022, __func__, n,\n- (long)len, (long)fop_fd-\u003epos, (long)fop_fd-\u003elen);\n-\t*amount \u003d n;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n-\t\t uint8_t *buf, lws_filepos_t len)\n-{\n-\tlong n;\n-\n-\tn \u003d write((int)fop_fd-\u003efd, buf, len);\n-\tif (n \u003d\u003d -1) {\n-\t\t*amount \u003d 0;\n-\t\treturn -1;\n-\t}\n-\n-\tfop_fd-\u003epos +\u003d n;\n-\t*amount \u003d n;\n-\n-\treturn 0;\n-}\n-\n-\n-LWS_VISIBLE int\n-lws_plat_init(struct lws_context *context,\n-\t struct lws_context_creation_info *info)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-\tint n \u003d context-\u003ecount_threads, fd;\n-\n-\t/* master context has the global fd lookup array */\n-\tcontext-\u003elws_lookup \u003d lws_zalloc(sizeof(struct lws *) *\n-\t\t\t\t\t context-\u003emax_fds, \u0022lws_lookup\u0022);\n-\tif (context-\u003elws_lookup \u003d\u003d NULL) {\n-\t\tlwsl_err(\u0022OOM on lws_lookup array for %d connections\u005cn\u0022,\n-\t\t\t context-\u003emax_fds);\n-\t\treturn 1;\n-\t}\n-\n-\tlwsl_info(\u0022 mem: platform fd map: %5lu bytes\u005cn\u0022,\n-\t\t (unsigned long)(sizeof(struct lws *) * context-\u003emax_fds));\n-\tfd \u003d open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);\n-\n-\tcontext-\u003efd_random \u003d fd;\n-\tif (context-\u003efd_random \u003c 0) {\n-\t\tlwsl_err(\u0022Unable to open random device %s %d\u005cn\u0022,\n-\t\t\t SYSTEM_RANDOM_FILEPATH, context-\u003efd_random);\n-\t\treturn 1;\n-\t}\n-\n-\tif (!lws_libev_init_fd_table(context) \u0026\u0026\n-\t !lws_libuv_init_fd_table(context) \u0026\u0026\n-\t !lws_libevent_init_fd_table(context)) {\n-\t\t/* otherwise libev/uv/event handled it instead */\n-\n-\t\twhile (n--) {\n-\t\t\tif (pipe(pt-\u003edummy_pipe_fds)) {\n-\t\t\t\tlwsl_err(\u0022Unable to create pipe\u005cn\u0022);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\n-\t\t\t/* use the read end of pipe as first item */\n-\t\t\tpt-\u003efds[0].fd \u003d pt-\u003edummy_pipe_fds[0];\n-\t\t\tpt-\u003efds[0].events \u003d LWS_POLLIN;\n-\t\t\tpt-\u003efds[0].revents \u003d 0;\n-\t\t\tpt-\u003efds_count \u003d 1;\n-\t\t\tpt++;\n-\t\t}\n-\t}\n-\n-#ifdef LWS_WITH_PLUGINS\n-\tif (info-\u003eplugin_dirs)\n-\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n-#endif\n-\n-\treturn 0;\n-}\ndiff --git a/lib/lws-plat-win.c b/lib/lws-plat-win.c\ndeleted file mode 100644\nindex ed1c92e..0000000\n--- a/lib/lws-plat-win.c\n+++ /dev/null\n@@ -1,745 +0,0 @@\n-#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS\n-#define _WINSOCK_DEPRECATED_NO_WARNINGS\n-#endif\n-#include \u0022private-libwebsockets.h\u0022\n-\n-unsigned long long\n-time_in_microseconds()\n-{\n-#ifndef DELTA_EPOCH_IN_MICROSECS\n-#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL\n-#endif\n-\tFILETIME filetime;\n-\tULARGE_INTEGER datetime;\n-\n-#ifdef _WIN32_WCE\n-\tGetCurrentFT(\u0026filetime);\n-#else\n-\tGetSystemTimeAsFileTime(\u0026filetime);\n-#endif\n-\n-\t/*\n-\t * As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a\n-\t * ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can\n-\t * prevent alignment faults on 64-bit Windows).\n-\t */\n-\tmemcpy(\u0026datetime, \u0026filetime, sizeof(datetime));\n-\n-\t/* Windows file times are in 100s of nanoseconds. */\n-\treturn (datetime.QuadPart - DELTA_EPOCH_IN_MICROSECS) / 10;\n-}\n-\n-#ifdef _WIN32_WCE\n-time_t time(time_t *t)\n-{\n-\ttime_t ret \u003d time_in_microseconds() / 1000000;\n-\n-\tif(t !\u003d NULL)\n-\t\t*t \u003d ret;\n-\n-\treturn ret;\n-}\n-#endif\n-\n-/* file descriptor hash management */\n-\n-struct lws *\n-wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)\n-{\n-\tint h \u003d LWS_FD_HASH(fd);\n-\tint n \u003d 0;\n-\n-\tfor (n \u003d 0; n \u003c context-\u003efd_hashtable[h].length; n++)\n-\t\tif (context-\u003efd_hashtable[h].wsi[n]-\u003edesc.sockfd \u003d\u003d fd)\n-\t\t\treturn context-\u003efd_hashtable[h].wsi[n];\n-\n-\treturn NULL;\n-}\n-\n-int\n-insert_wsi(struct lws_context *context, struct lws *wsi)\n-{\n-\tint h \u003d LWS_FD_HASH(wsi-\u003edesc.sockfd);\n-\n-\tif (context-\u003efd_hashtable[h].length \u003d\u003d (getdtablesize() - 1)) {\n-\t\tlwsl_err(\u0022hash table overflow\u005cn\u0022);\n-\t\treturn 1;\n-\t}\n-\n-\tcontext-\u003efd_hashtable[h].wsi[context-\u003efd_hashtable[h].length++] \u003d wsi;\n-\n-\treturn 0;\n-}\n-\n-int\n-delete_from_fd(struct lws_context *context, lws_sockfd_type fd)\n-{\n-\tint h \u003d LWS_FD_HASH(fd);\n-\tint n \u003d 0;\n-\n-\tfor (n \u003d 0; n \u003c context-\u003efd_hashtable[h].length; n++)\n-\t\tif (context-\u003efd_hashtable[h].wsi[n]-\u003edesc.sockfd \u003d\u003d fd) {\n-\t\t\twhile (n \u003c context-\u003efd_hashtable[h].length) {\n-\t\t\t\tcontext-\u003efd_hashtable[h].wsi[n] \u003d\n-\t\t\t\t\t\tcontext-\u003efd_hashtable[h].wsi[n + 1];\n-\t\t\t\tn++;\n-\t\t\t}\n-\t\t\tcontext-\u003efd_hashtable[h].length--;\n-\n-\t\t\treturn 0;\n-\t\t}\n-\n-\tlwsl_err(\u0022Failed to find fd %d requested for \u0022\n-\t\t \u0022delete in hashtable\u005cn\u0022, fd);\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE int lws_get_random(struct lws_context *context,\n-\t\t\t\t\t\t\t\t void *buf, int len)\n-{\n-\tint n;\n-\tchar *p \u003d (char *)buf;\n-\n-\tfor (n \u003d 0; n \u003c len; n++)\n-\t\tp[n] \u003d (unsigned char)rand();\n-\n-\treturn n;\n-}\n-\n-LWS_VISIBLE int lws_send_pipe_choked(struct lws *wsi)\n-{\n-\t/* treat the fact we got a truncated send pending as if we're choked */\n-\tif (wsi-\u003etrunc_len)\n-\t\treturn 1;\n-\n-\treturn (int)wsi-\u003esock_send_blocking;\n-}\n-\n-LWS_VISIBLE int lws_poll_listen_fd(struct lws_pollfd *fd)\n-{\n-\tfd_set readfds;\n-\tstruct timeval tv \u003d { 0, 0 };\n-\n-\tassert((fd-\u003eevents \u0026 LWS_POLLIN) \u003d\u003d LWS_POLLIN);\n-\n-\tFD_ZERO(\u0026readfds);\n-\tFD_SET(fd-\u003efd, \u0026readfds);\n-\n-\treturn select(fd-\u003efd + 1, \u0026readfds, NULL, NULL, \u0026tv);\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service(struct lws_context *context)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-\tint n \u003d context-\u003ecount_threads;\n-\n-\twhile (n--) {\n-\t\tWSASetEvent(pt-\u003eevents[0]);\n-\t\tpt++;\n-\t}\n-}\n-\n-LWS_VISIBLE void\n-lws_cancel_service_pt(struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tWSASetEvent(pt-\u003eevents[0]);\n-}\n-\n-LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n-{\n-\tlwsl_emit_stderr(level, line);\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n-{\n-\tstruct lws_context_per_thread *pt;\n-\tWSANETWORKEVENTS networkevents;\n-\tstruct lws_pollfd *pfd;\n-\tstruct lws *wsi;\n-\tunsigned int i;\n-\tDWORD ev;\n-\tint n, m;\n-\n-\t/* stay dead once we are dead */\n-\tif (context \u003d\u003d NULL || !context-\u003evhost_list)\n-\t\treturn 1;\n-\n-\tpt \u003d \u0026context-\u003ept[tsi];\n-\n-\tif (!context-\u003eservice_tid_detected) {\n-\t\tstruct lws _lws;\n-\n-\t\tmemset(\u0026_lws, 0, sizeof(_lws));\n-\t\t_lws.context \u003d context;\n-\n-\t\tcontext-\u003eservice_tid_detected \u003d context-\u003evhost_list-\u003e\n-\t\t\tprotocols[0].callback(\u0026_lws, LWS_CALLBACK_GET_THREAD_ID,\n-\t\t\t\t\t\t NULL, NULL, 0);\n-\t}\n-\tcontext-\u003eservice_tid \u003d context-\u003eservice_tid_detected;\n-\n-\tif (timeout_ms \u003c 0)\n-\t{\n-\t\t\tif (lws_service_flag_pending(context, tsi)) {\n-\t\t\t/* any socket with events to service? */\n-\t\t\tfor (n \u003d 0; n \u003c (int)pt-\u003efds_count; n++) {\n-\t\t\t\tif (!pt-\u003efds[n].revents)\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\tm \u003d lws_service_fd_tsi(context, \u0026pt-\u003efds[n], tsi);\n-\t\t\t\tif (m \u003c 0)\n-\t\t\t\t\treturn -1;\n-\t\t\t\t/* if something closed, retry this slot */\n-\t\t\t\tif (m)\n-\t\t\t\t\tn--;\n-\t\t\t}\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\n-\tfor (i \u003d 0; i \u003c pt-\u003efds_count; ++i) {\n-\t\tpfd \u003d \u0026pt-\u003efds[i];\n-\n-\t\tif (!(pfd-\u003eevents \u0026 LWS_POLLOUT))\n-\t\t\tcontinue;\n-\n-\t\twsi \u003d wsi_from_fd(context, pfd-\u003efd);\n-\t\tif (wsi-\u003elistener)\n-\t\t\tcontinue;\n-\t\tif (!wsi || wsi-\u003esock_send_blocking)\n-\t\t\tcontinue;\n-\t\tpfd-\u003erevents \u003d LWS_POLLOUT;\n-\t\tn \u003d lws_service_fd(context, pfd);\n-\t\tif (n \u003c 0)\n-\t\t\treturn -1;\n-\t\t/* if something closed, retry this slot */\n-\t\tif (n)\n-\t\t\ti--;\n-\n-\t\tif (wsi-\u003etrunc_len)\n-\t\t\tWSASetEvent(pt-\u003eevents[0]);\n-\t}\n-\n-\t/*\n-\t * is there anybody with pending stuff that needs service forcing?\n-\t */\n-\tif (!lws_service_adjust_timeout(context, 1, tsi)) {\n-\t\t/* -1 timeout means just do forced service */\n-\t\t_lws_plat_service_tsi(context, -1, pt-\u003etid);\n-\t\t/* still somebody left who wants forced service? */\n-\t\tif (!lws_service_adjust_timeout(context, 1, pt-\u003etid))\n-\t\t\t/* yes... come back again quickly */\n-\t\t\ttimeout_ms \u003d 0;\n-\t}\n-\n-\tev \u003d WSAWaitForMultipleEvents( 1, pt-\u003eevents , FALSE, timeout_ms, FALSE);\n-\tif (ev \u003d\u003d WSA_WAIT_EVENT_0) {\n-\t\tunsigned int eIdx;\n-\n-\t\tWSAResetEvent(pt-\u003eevents[0]);\n-\n-\t\tfor (eIdx \u003d 0; eIdx \u003c pt-\u003efds_count; ++eIdx) {\n-\t\t\tif (WSAEnumNetworkEvents(pt-\u003efds[eIdx].fd, 0, \u0026networkevents) \u003d\u003d SOCKET_ERROR) {\n-\t\t\t\tlwsl_err(\u0022WSAEnumNetworkEvents() failed with error %d\u005cn\u0022, LWS_ERRNO);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t\tpfd \u003d \u0026pt-\u003efds[eIdx];\n-\t\t\tpfd-\u003erevents \u003d (short)networkevents.lNetworkEvents;\n-\n-\t\t\tif ((networkevents.lNetworkEvents \u0026 FD_CONNECT) \u0026\u0026\n-\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] \u0026\u0026\n-\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] !\u003d LWS_EALREADY \u0026\u0026\n-\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] !\u003d LWS_EINPROGRESS \u0026\u0026\n-\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] !\u003d LWS_EWOULDBLOCK \u0026\u0026\n-\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] !\u003d WSAEINVAL) {\n-\t\t\t\tlwsl_debug(\u0022Unable to connect errno\u003d%d\u005cn\u0022,\n-\t\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT]);\n-\t\t\t\tpfd-\u003erevents \u003d LWS_POLLHUP;\n-\t\t\t} else\n-\t\t\t\tpfd-\u003erevents \u003d (short)networkevents.lNetworkEvents;\n-\n-\t\t\tif (pfd-\u003erevents \u0026 LWS_POLLOUT) {\n-\t\t\t\twsi \u003d wsi_from_fd(context, pfd-\u003efd);\n-\t\t\t\tif (wsi)\n-\t\t\t\t\twsi-\u003esock_send_blocking \u003d 0;\n-\t\t\t}\n-\t\t\t /* if something closed, retry this slot */\n-\t\t\tif (pfd-\u003erevents \u0026 LWS_POLLHUP)\n-\t\t\t\t\t--eIdx;\n-\n-\t\t\tif( pfd-\u003erevents !\u003d 0 ) {\n-\t\t\t\tlws_service_fd_tsi(context, pfd, tsi);\n-\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\tcontext-\u003eservice_tid \u003d 0;\n-\n-\tif (ev \u003d\u003d WSA_WAIT_TIMEOUT) {\n-\t\tlws_service_fd(context, NULL);\n-\t}\n-\treturn 0;;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_service(struct lws_context *context, int timeout_ms)\n-{\n-\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)\n-{\n-\tint optval \u003d 1;\n-\tint optlen \u003d sizeof(optval);\n-\tu_long optl \u003d 1;\n-\tDWORD dwBytesRet;\n-\tstruct tcp_keepalive alive;\n-\tint protonbr;\n-#ifndef _WIN32_WCE\n-\tstruct protoent *tcp_proto;\n-#endif\n-\n-\tif (vhost-\u003eka_time) {\n-\t\t/* enable keepalive on this socket */\n-\t\toptval \u003d 1;\n-\t\tif (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,\n-\t\t\t\t\t\t (const char *)\u0026optval, optlen) \u003c 0)\n-\t\t\treturn 1;\n-\n-\t\talive.onoff \u003d TRUE;\n-\t\talive.keepalivetime \u003d vhost-\u003eka_time;\n-\t\talive.keepaliveinterval \u003d vhost-\u003eka_interval;\n-\n-\t\tif (WSAIoctl(fd, SIO_KEEPALIVE_VALS, \u0026alive, sizeof(alive),\n-\t\t\t\t\t\t NULL, 0, \u0026dwBytesRet, NULL, NULL))\n-\t\t\treturn 1;\n-\t}\n-\n-\t/* Disable Nagle */\n-\toptval \u003d 1;\n-#ifndef _WIN32_WCE\n-\ttcp_proto \u003d getprotobyname(\u0022TCP\u0022);\n-\tif (!tcp_proto) {\n-\t\tlwsl_err(\u0022getprotobyname() failed with error %d\u005cn\u0022, LWS_ERRNO);\n-\t\treturn 1;\n-\t}\n-\tprotonbr \u003d tcp_proto-\u003ep_proto;\n-#else\n-\tprotonbr \u003d 6;\n-#endif\n-\n-\tsetsockopt(fd, protonbr, TCP_NODELAY, (const char *)\u0026optval, optlen);\n-\n-\t/* We are nonblocking... */\n-\tioctlsocket(fd, FIONBIO, \u0026optl);\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n-{\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_context_early_init(void)\n-{\n-\tWORD wVersionRequested;\n-\tWSADATA wsaData;\n-\tint err;\n-\n-\t/* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */\n-\twVersionRequested \u003d MAKEWORD(2, 2);\n-\n-\terr \u003d WSAStartup(wVersionRequested, \u0026wsaData);\n-\tif (!err)\n-\t\treturn 0;\n-\t/*\n-\t * Tell the user that we could not find a usable\n-\t * Winsock DLL\n-\t */\n-\tlwsl_err(\u0022WSAStartup failed with error: %d\u005cn\u0022, err);\n-\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_early_destroy(struct lws_context *context)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-\tint n \u003d context-\u003ecount_threads;\n-\n-\twhile (n--) {\n-\t\tif (pt-\u003eevents) {\n-\t\t\tWSACloseEvent(pt-\u003eevents[0]);\n-\t\t\tlws_free(pt-\u003eevents);\n-\t\t}\n-\t\tpt++;\n-\t}\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_context_late_destroy(struct lws_context *context)\n-{\n-\tint n;\n-\n-\tfor (n \u003d 0; n \u003c FD_HASHTABLE_MODULUS; n++) {\n-\t\tif (context-\u003efd_hashtable[n].wsi)\n-\t\t\tlws_free(context-\u003efd_hashtable[n].wsi);\n-\t}\n-\n-\tWSACleanup();\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_interface_to_sa(int ipv6,\n-\t\tconst char *ifname, struct sockaddr_in *addr, size_t addrlen)\n-{\n-#ifdef LWS_WITH_IPV6\n-\tstruct sockaddr_in6 *addr6 \u003d (struct sockaddr_in6 *)addr;\n-\n-\tif (ipv6) {\n-\t\tif (lws_plat_inet_pton(AF_INET6, ifname, \u0026addr6-\u003esin6_addr) \u003d\u003d 1) {\n-\t\t\treturn 0;\n-\t\t}\n-\t}\n-#endif\n-\n-\tlong long address \u003d inet_addr(ifname);\n-\n-\tif (address \u003d\u003d INADDR_NONE) {\n-\t\tstruct hostent *entry \u003d gethostbyname(ifname);\n-\t\tif (entry)\n-\t\t\taddress \u003d ((struct in_addr *)entry-\u003eh_addr_list[0])-\u003es_addr;\n-\t}\n-\n-\tif (address \u003d\u003d INADDR_NONE)\n-\t\treturn -1;\n-\n-\taddr-\u003esin_addr.s_addr \u003d (lws_intptr_t)address;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\n-\tpt-\u003efds[pt-\u003efds_count++].revents \u003d 0;\n-\tpt-\u003eevents[pt-\u003efds_count] \u003d pt-\u003eevents[0];\n-\tWSAEventSelect(wsi-\u003edesc.sockfd, pt-\u003eevents[0],\n-\t\t\t LWS_POLLIN | LWS_POLLHUP | FD_CONNECT);\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_delete_socket_from_fds(struct lws_context *context,\n-\t\t\t\t\t\tstruct lws *wsi, int m)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\n-\tpt-\u003eevents[m + 1] \u003d pt-\u003eevents[pt-\u003efds_count--];\n-}\n-\n-LWS_VISIBLE void\n-lws_plat_service_periodic(struct lws_context *context)\n-{\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_check_connection_error(struct lws *wsi)\n-{\n-\tint optVal;\n-\tint optLen \u003d sizeof(int);\n-\n-\tif (getsockopt(wsi-\u003edesc.sockfd, SOL_SOCKET, SO_ERROR,\n-\t\t\t (char*)\u0026optVal, \u0026optLen) !\u003d SOCKET_ERROR \u0026\u0026 optVal \u0026\u0026\n-\t\toptVal !\u003d LWS_EALREADY \u0026\u0026 optVal !\u003d LWS_EINPROGRESS \u0026\u0026\n-\t\toptVal !\u003d LWS_EWOULDBLOCK \u0026\u0026 optVal !\u003d WSAEINVAL) {\n-\t\t lwsl_debug(\u0022Connect failed SO_ERROR\u003d%d\u005cn\u0022, optVal);\n-\t\t return 1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_change_pollfd(struct lws_context *context,\n-\t\t\t struct lws *wsi, struct lws_pollfd *pfd)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tlong networkevents \u003d LWS_POLLHUP | FD_CONNECT;\n-\n-\tif ((pfd-\u003eevents \u0026 LWS_POLLIN))\n-\t\tnetworkevents |\u003d LWS_POLLIN;\n-\n-\tif ((pfd-\u003eevents \u0026 LWS_POLLOUT))\n-\t\tnetworkevents |\u003d LWS_POLLOUT;\n-\n-\tif (WSAEventSelect(wsi-\u003edesc.sockfd,\n-\t\t\tpt-\u003eevents[0],\n-\t\t\t\t\t\t networkevents) !\u003d SOCKET_ERROR)\n-\t\treturn 0;\n-\n-\tlwsl_err(\u0022WSAEventSelect() failed with error %d\u005cn\u0022, LWS_ERRNO);\n-\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE const char *\n-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n-{\n-\tWCHAR *buffer;\n-\tDWORD bufferlen \u003d cnt;\n-\tBOOL ok \u003d FALSE;\n-\n-\tbuffer \u003d lws_malloc(bufferlen * 2, \u0022inet_ntop\u0022);\n-\tif (!buffer) {\n-\t\tlwsl_err(\u0022Out of memory\u005cn\u0022);\n-\t\treturn NULL;\n-\t}\n-\n-\tif (af \u003d\u003d AF_INET) {\n-\t\tstruct sockaddr_in srcaddr;\n-\t\tbzero(\u0026srcaddr, sizeof(srcaddr));\n-\t\tsrcaddr.sin_family \u003d AF_INET;\n-\t\tmemcpy(\u0026(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));\n-\n-\t\tif (!WSAAddressToStringW((struct sockaddr*)\u0026srcaddr, sizeof(srcaddr), 0, buffer, \u0026bufferlen))\n-\t\t\tok \u003d TRUE;\n-#ifdef LWS_WITH_IPV6\n-\t} else if (af \u003d\u003d AF_INET6) {\n-\t\tstruct sockaddr_in6 srcaddr;\n-\t\tbzero(\u0026srcaddr, sizeof(srcaddr));\n-\t\tsrcaddr.sin6_family \u003d AF_INET6;\n-\t\tmemcpy(\u0026(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));\n-\n-\t\tif (!WSAAddressToStringW((struct sockaddr*)\u0026srcaddr, sizeof(srcaddr), 0, buffer, \u0026bufferlen))\n-\t\t\tok \u003d TRUE;\n-#endif\n-\t} else\n-\t\tlwsl_err(\u0022Unsupported type\u005cn\u0022);\n-\n-\tif (!ok) {\n-\t\tint rv \u003d WSAGetLastError();\n-\t\tlwsl_err(\u0022WSAAddressToString() : %d\u005cn\u0022, rv);\n-\t} else {\n-\t\tif (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) \u003c\u003d 0)\n-\t\t\tok \u003d FALSE;\n-\t}\n-\n-\tlws_free(buffer);\n-\treturn ok ? dst : NULL;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_inet_pton(int af, const char *src, void *dst)\n-{\n-\tWCHAR *buffer;\n-\tDWORD bufferlen \u003d strlen(src) + 1;\n-\tBOOL ok \u003d FALSE;\n-\n-\tbuffer \u003d lws_malloc(bufferlen * 2, \u0022inet_pton\u0022);\n-\tif (!buffer) {\n-\t\tlwsl_err(\u0022Out of memory\u005cn\u0022);\n-\t\treturn -1;\n-\t}\n-\n-\tif (MultiByteToWideChar(CP_ACP, 0, src, bufferlen, buffer, bufferlen) \u003c\u003d 0) {\n-\t\tlwsl_err(\u0022Failed to convert multi byte to wide char\u005cn\u0022);\n-\t\tlws_free(buffer);\n-\t\treturn -1;\n-\t}\n-\n-\tif (af \u003d\u003d AF_INET) {\n-\t\tstruct sockaddr_in dstaddr;\n-\t\tint dstaddrlen \u003d sizeof(dstaddr);\n-\t\tbzero(\u0026dstaddr, sizeof(dstaddr));\n-\t\tdstaddr.sin_family \u003d AF_INET;\n-\n-\t\tif (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) \u0026dstaddr, \u0026dstaddrlen)) {\n-\t\t\tok \u003d TRUE;\n-\t\t\tmemcpy(dst, \u0026dstaddr.sin_addr, sizeof(dstaddr.sin_addr));\n-\t\t}\n-#ifdef LWS_WITH_IPV6\n-\t} else if (af \u003d\u003d AF_INET6) {\n-\t\tstruct sockaddr_in6 dstaddr;\n-\t\tint dstaddrlen \u003d sizeof(dstaddr);\n-\t\tbzero(\u0026dstaddr, sizeof(dstaddr));\n-\t\tdstaddr.sin6_family \u003d AF_INET6;\n-\n-\t\tif (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) \u0026dstaddr, \u0026dstaddrlen)) {\n-\t\t\tok \u003d TRUE;\n-\t\t\tmemcpy(dst, \u0026dstaddr.sin6_addr, sizeof(dstaddr.sin6_addr));\n-\t\t}\n-#endif\n-\t} else\n-\t\tlwsl_err(\u0022Unsupported type\u005cn\u0022);\n-\n-\tif (!ok) {\n-\t\tint rv \u003d WSAGetLastError();\n-\t\tlwsl_err(\u0022WSAAddressToString() : %d\u005cn\u0022, rv);\n-\t}\n-\n-\tlws_free(buffer);\n-\treturn ok ? 1 : -1;\n-}\n-\n-LWS_VISIBLE lws_fop_fd_t\n-_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,\n-\t\t const char *vpath, lws_fop_flags_t *flags)\n-{\n-\tHANDLE ret;\n-\tWCHAR buf[MAX_PATH];\n-\tlws_fop_fd_t fop_fd;\n-\tLARGE_INTEGER llFileSize \u003d {0};\n-\n-\tMultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));\n-\tif (((*flags) \u0026 7) \u003d\u003d _O_RDONLY) {\n-\t\tret \u003d CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,\n-\t\t\t NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\n-\t} else {\n-\t\tret \u003d CreateFileW(buf, GENERIC_WRITE, 0, NULL,\n-\t\t\t CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\n-\t}\n-\n-\tif (ret \u003d\u003d LWS_INVALID_FILE)\n-\t\tgoto bail;\n-\n-\tfop_fd \u003d malloc(sizeof(*fop_fd));\n-\tif (!fop_fd)\n-\t\tgoto bail;\n-\n-\tfop_fd-\u003efops \u003d fops;\n-\tfop_fd-\u003efd \u003d ret;\n-\tfop_fd-\u003efilesystem_priv \u003d NULL; /* we don't use it */\n-\tfop_fd-\u003eflags \u003d *flags;\n-\tfop_fd-\u003elen \u003d GetFileSize(ret, NULL);\n-\tif(GetFileSizeEx(ret, \u0026llFileSize))\n-\t\tfop_fd-\u003elen \u003d llFileSize.QuadPart;\n-\n-\tfop_fd-\u003epos \u003d 0;\n-\n-\treturn fop_fd;\n-\n-bail:\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE int\n-_lws_plat_file_close(lws_fop_fd_t *fop_fd)\n-{\n-\tHANDLE fd \u003d (*fop_fd)-\u003efd;\n-\n-\tfree(*fop_fd);\n-\t*fop_fd \u003d NULL;\n-\n-\tCloseHandle((HANDLE)fd);\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE lws_fileofs_t\n-_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)\n-{\n-\tLARGE_INTEGER l;\n-\n-\tl.QuadPart \u003d offset;\n-\treturn SetFilePointerEx((HANDLE)fop_fd-\u003efd, l, NULL, FILE_CURRENT);\n-}\n-\n-LWS_VISIBLE int\n-_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n-\t\t uint8_t *buf, lws_filepos_t len)\n-{\n-\tDWORD _amount;\n-\n-\tif (!ReadFile((HANDLE)fop_fd-\u003efd, buf, (DWORD)len, \u0026_amount, NULL)) {\n-\t\t*amount \u003d 0;\n-\n-\t\treturn 1;\n-\t}\n-\n-\tfop_fd-\u003epos +\u003d _amount;\n-\t*amount \u003d (unsigned long)_amount;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n-\t\t\t uint8_t* buf, lws_filepos_t len)\n-{\n-\tDWORD _amount;\n-\n-\tif (!WriteFile((HANDLE)fop_fd-\u003efd, buf, (DWORD)len, \u0026_amount, NULL)) {\n-\t\t*amount \u003d 0;\n-\n-\t\treturn 1;\n-\t}\n-\n-\tfop_fd-\u003epos +\u003d _amount;\n-\t*amount \u003d (unsigned long)_amount;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_plat_init(struct lws_context *context,\n-\t\t struct lws_context_creation_info *info)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n-\tint i, n \u003d context-\u003ecount_threads;\n-\n-\tfor (i \u003d 0; i \u003c FD_HASHTABLE_MODULUS; i++) {\n-\t\tcontext-\u003efd_hashtable[i].wsi \u003d\n-\t\t\tlws_zalloc(sizeof(struct lws*) * context-\u003emax_fds, \u0022win hashtable\u0022);\n-\n-\t\tif (!context-\u003efd_hashtable[i].wsi)\n-\t\t\treturn -1;\n-\t}\n-\n-\twhile (n--) {\n-\t\tpt-\u003eevents \u003d lws_malloc(sizeof(WSAEVENT) *\n-\t\t\t\t\t(context-\u003efd_limit_per_thread + 1), \u0022event table\u0022);\n-\t\tif (pt-\u003eevents \u003d\u003d NULL) {\n-\t\t\tlwsl_err(\u0022Unable to allocate events array for %d connections\u005cn\u0022,\n-\t\t\t\t\tcontext-\u003efd_limit_per_thread + 1);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\tpt-\u003efds_count \u003d 0;\n-\t\tpt-\u003eevents[0] \u003d WSACreateEvent();\n-\n-\t\tpt++;\n-\t}\n-\n-\tcontext-\u003efd_random \u003d 0;\n-\n-#ifdef LWS_WITH_PLUGINS\n-\tif (info-\u003eplugin_dirs)\n-\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n-#endif\n-\n-\treturn 0;\n-}\n-\n-\n-int kill(int pid, int sig)\n-{\n-\tlwsl_err(\u0022Sorry Windows doesn't support kill().\u0022);\n-\texit(0);\n-}\n-\n-int fork(void)\n-{\n-\tlwsl_err(\u0022Sorry Windows doesn't support fork().\u0022);\n-\texit(0);\n-}\n-\ndiff --git a/lib/minihuf.c b/lib/minihuf.c\ndeleted file mode 100644\nindex eaf84e5..0000000\n--- a/lib/minihuf.c\n+++ /dev/null\n@@ -1,518 +0,0 @@\n-/*\n- * minilex.c\n- *\n- * High efficiency lexical state parser\n- *\n- * Copyright (C)2011-2014 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * Licensed under LGPL2\n- *\n- * Usage: gcc minihuf.c -o minihuf \u0026\u0026 ./minihuf \u003e huftable.h\n- *\n- * Run it twice to test parsing on the generated table on stderr\n- */\n-\n-#include \u003cstdio.h\u003e\n-#include \u003cstdlib.h\u003e\n-#include \u003cstring.h\u003e\n-\n-#define ARRAY_SIZE(n) (sizeof(n) / sizeof(n[0]))\n-\n-struct huf {\n-\tunsigned int code;\n-\tunsigned char len;\n-};\n-\n-static struct huf huf_literal[] \u003d {\n-\t/* 0x00 */ { 0x1ff8, 13 },\n-\t/* 0x01 */ { 0x7fffd8, 23 },\n-\t/* 0x02 */ { 0xfffffe2, 28 },\n-\t/* 0x03 */ { 0xfffffe3, 28 },\n-\t/* 0x04 */ { 0xfffffe4, 28 },\n-\t/* 0x05 */ { 0xfffffe5, 28 },\n-\t/* 0x06 */ { 0xfffffe6, 28 },\n-\t/* 0x07 */ { 0xfffffe7, 28 },\n-\t/* 0x08 */ { 0xfffffe8, 28 },\n-\t/* 0x09 */ { 0xffffea, 24 },\n-\t/* 0x0a */ { 0x3ffffffc, 30 },\n-\t/* 0x0b */ { 0xfffffe9, 28 },\n-\n-\t/* 0x0c */ { 0xfffffea, 28 },\n-\t/* 0x0d */ { 0x3ffffffd, 30 },\n-\t/* 0x0e */ { 0xfffffeb, 28 },\n-\t/* 0x0f */ { 0xfffffec, 28 },\n-\t/* 0x10 */ { 0xfffffed, 28 },\n-\t/* 0x11 */ { 0xfffffee, 28 },\n-\t/* 0x12 */ { 0xfffffef, 28 },\n-\t/* 0x13 */ { 0xffffff0, 28 },\n-\t/* 0x14 */ { 0xffffff1, 28 },\n-\t/* 0x15 */ { 0xffffff2, 28 },\n-\t/* 0x16 */ { 0x3ffffffe, 30 },\n-\t/* 0x17 */ { 0xffffff3, 28 },\n-\t/* 0x18 */ { 0xffffff4, 28 },\n-\t/* 0x19 */ { 0xffffff5, 28 },\n-\t/* 0x1a */ { 0xffffff6, 28 },\n-\t/* 0x1b */ { 0xffffff7, 28 },\n-\t/* 0x1c */ { 0xffffff8, 28 },\n-\t/* 0x1d */ { 0xffffff9, 28 },\n-\t/* 0x1e */ { 0xffffffa, 28 },\n-\t/* 0x1f */ { 0xffffffb, 28 },\n-\t/* 0x20 */ { 0x14, 6 },\n-\t/* 0x21 */ { 0x3f8, 10 },\n-\t/* 0x22 */ { 0x3f9, 10 },\n-\t/* 0x23 */ { 0xffa, 12 },\n-\t/* 0x24 */ { 0x1ff9, 13 },\n-\t/* 0x25 */ { 0x15, 6 },\n-\t/* 0x26 */ { 0xf8, 8 },\n-\t/* 0x27 */ { 0x7fa, 11 },\n-\t/* 0x28 */ { 0x3fa, 10 },\n-\t/* 0x29 */ { 0x3fb, 10 },\n-\t/* 0x2a */ { 0xf9, 8 },\n-\t/* 0x2b */ { 0x7fb, 11 },\n-\t/* 0x2c */ { 0xfa, 8 },\n-\t/* 0x2d */ { 0x16, 6 },\n-\t/* 0x2e */ { 0x17, 6 },\n-\t/* 0x2f */ { 0x18, 6 },\n-\t/* 0x30 */ { 0x0, 5 },\n-\t/* 0x31 */ { 0x1, 5 },\n-\t/* 0x32 */ { 0x2, 5 },\n-\t/* 0x33 */ { 0x19, 6 },\n-\t/* 0x34 */ { 0x1a, 6 },\n-\t/* 0x35 */ { 0x1b, 6 },\n-\t/* 0x36 */ { 0x1c, 6 },\n-\t/* 0x37 */ { 0x1d, 6 },\n-\t/* 0x38 */ { 0x1e, 6 },\n-\t/* 0x39 */ { 0x1f, 6 },\n-\t/* 0x3a */ { 0x5c, 7 },\n-\t/* 0x3b */ { 0xfb, 8 },\n-\n-\t/* 0x3c */ { 0x7ffc, 15 },\n-\t/* 0x3d */ { 0x20, 6 },\n-\t/* 0x3e */ { 0xffb, 12 },\n-\t/* 0x3f */ { 0x3fc, 10 },\n-\t/* 0x40 */ { 0x1ffa, 13 },\n-\t/* 0x41 */ { 0x21, 6 },\n-\t/* 0x42 */ { 0x5d, 7 },\n-\t/* 0x43 */ { 0x5e, 7 },\n-\t/* 0x44 */ { 0x5f, 7 },\n-\t/* 0x45 */ { 0x60, 7 },\n-\t/* 0x46 */ { 0x61, 7 },\n-\t/* 0x47 */ { 0x62, 7 },\n-\t/* 0x48 */ { 0x63, 7 },\n-\t/* 0x49 */ { 0x64, 7 },\n-\t/* 0x4a */ { 0x65, 7 },\n-\t/* 0x4b */ { 0x66, 7 },\n-\t/* 0x4c */ { 0x67, 7 },\n-\t/* 0x4d */ { 0x68, 7 },\n-\t/* 0x4e */ { 0x69, 7 },\n-\t/* 0x4f */ { 0x6a, 7 },\n-\t/* 0x50 */ { 0x6b, 7 },\n-\t/* 0x51 */ { 0x6c, 7 },\n-\t/* 0x52 */ { 0x6d, 7 },\n-\t/* 0x53 */ { 0x6e, 7 },\n-\t/* 0x54 */ { 0x6f, 7 },\n-\t/* 0x55 */ { 0x70, 7 },\n-\t/* 0x56 */ { 0x71, 7 },\n-\t/* 0x57 */ { 0x72, 7 },\n-\t/* 0x58 */ { 0xfc, 8 },\n-\t/* 0x59 */ { 0x73, 7 },\n-\t/* 0x5a */ { 0xfd, 8 },\n-\t/* 0x5b */ { 0x1ffb, 13 },\n-\t/* 0x5c */ { 0x7fff0, 19 },\n-\t/* 0x5d */ { 0x1ffc, 13 },\n-\t/* 0x5e */ { 0x3ffc, 14 },\n-\t/* 0x5f */ { 0x22, 6 },\n-\t/* 0x60 */ { 0x7ffd, 15 },\n-\t/* 0x61 */ { 0x3, 5 },\n-\t/* 0x62 */ { 0x23, 6 },\n-\t/* 0x63 */ { 0x4, 5 },\n-\t/* 0x64 */ { 0x24, 6 },\n-\t/* 0x65 */ { 0x5, 5 },\n-\t/* 0x66 */ { 0x25, 6 },\n-\t/* 0x67 */ { 0x26, 6 },\n-\t/* 0x68 */ { 0x27, 6 },\n-\t/* 0x69 */ { 0x6, 5 },\n-\t/* 0x6a */ { 0x74, 7 },\n-\t/* 0x6b */ { 0x75, 7 },\n-\n-\n-\t/* 0x6c */ { 0x28, 6 },\n-\t/* 0x6d */ { 0x29, 6 },\n-\t/* 0x6e */ { 0x2a, 6 },\n-\t/* 0x6f */ { 0x7, 5 },\n-\t/* 0x70 */ { 0x2b, 6 },\n-\t/* 0x71 */ { 0x76, 7 },\n-\t/* 0x72 */ { 0x2c, 6 },\n-\t/* 0x73 */ { 0x8, 5 },\n-\t/* 0x74 */ { 0x9, 5 },\n-\t/* 0x75 */ { 0x2d, 6 },\n-\t/* 0x76 */ { 0x77, 7 },\n-\t/* 0x77 */ { 0x78, 7 },\n-\t/* 0x78 */ { 0x79, 7 },\n-\t/* 0x79 */ { 0x7a, 7 },\n-\t/* 0x7a */ { 0x7b, 7 },\n-\t/* 0x7b */ { 0x7ffe, 15 },\n-\t/* 0x7c */ { 0x7fc, 11 },\n-\t/* 0x7d */ { 0x3ffd, 14 },\n-\t/* 0x7e */ { 0x1ffd, 13 },\n-\t/* 0x7f */ { 0xffffffc, 28 },\n-\t/* 0x80 */ { 0xfffe6, 20 },\n-\t/* 0x81 */ { 0x3fffd2, 22 },\n-\t/* 0x82 */ { 0xfffe7, 20 },\n-\t/* 0x83 */ { 0xfffe8, 20 },\n-\t/* 0x84 */ { 0x3fffd3, 22 },\n-\t/* 0x85 */ { 0x3fffd4, 22 },\n-\t/* 0x86 */ { 0x3fffd5, 22 },\n-\t/* 0x87 */ { 0x7fffd9, 23 },\n-\t/* 0x88 */ { 0x3fffd6, 22 },\n-\t/* 0x89 */ { 0x7fffda, 23 },\n-\t/* 0x8a */ { 0x7fffdb, 23 },\n-\t/* 0x8b */ { 0x7fffdc, 23 },\n-\t/* 0x8c */ { 0x7fffdd, 23 },\n-\t/* 0x8d */ { 0x7fffde, 23 },\n-\t/* 0x8e */ { 0xffffeb, 24 },\n-\t/* 0x8f */ { 0x7fffdf, 23 },\n-\t/* 0x90 */ { 0xffffec, 24 },\n-\t/* 0x91 */ { 0xffffed, 24 },\n-\t/* 0x92 */ { 0x3fffd7, 22 },\n-\t/* 0x93 */ { 0x7fffe0, 23 },\n-\t/* 0x94 */ { 0xffffee, 24 },\n-\t/* 0x95 */ { 0x7fffe1, 23 },\n-\t/* 0x96 */ { 0x7fffe2, 23 },\n-\t/* 0x97 */ { 0x7fffe3, 23 },\n-\t/* 0x98 */ { 0x7fffe4, 23 },\n-\t/* 0x99 */ { 0x1fffdc, 21 },\n-\t/* 0x9a */ { 0x3fffd8, 22 },\n-\t/* 0x9b */ { 0x7fffe5, 23 },\n-\n-\t/* 0x9c */ { 0x3fffd9, 22 },\n-\t/* 0x9d */ { 0x7fffe6, 23 },\n-\t/* 0x9e */ { 0x7fffe7, 23 },\n-\t/* 0x9f */ { 0xffffef, 24 },\n-\t/* 0xa0 */ { 0x3fffda, 22 },\n-\t/* 0xa1 */ { 0x1fffdd, 21 },\n-\t/* 0xa2 */ { 0xfffe9, 20 },\n-\t/* 0xa3 */ { 0x3fffdb, 22 },\n-\t/* 0xa4 */ { 0x3fffdc, 22 },\n-\t/* 0xa5 */ { 0x7fffe8, 23 },\n-\t/* 0xa6 */ { 0x7fffe9, 23 },\n-\t/* 0xa7 */ { 0x1fffde, 21 },\n-\t/* 0xa8 */ { 0x7fffea, 23 },\n-\t/* 0xa9 */ { 0x3fffdd, 22 },\n-\t/* 0xaa */ { 0x3fffde, 22 },\n-\t/* 0xab */ { 0xfffff0, 24 },\n-\t/* 0xac */ { 0x1fffdf, 21 },\n-\t/* 0xad */ { 0x3fffdf, 22 },\n-\t/* 0xae */ { 0x7fffeb, 23 },\n-\t/* 0xaf */ { 0x7fffec, 23 },\n-\t/* 0xb0 */ { 0x1fffe0, 21 },\n-\t/* 0xb1 */ { 0x1fffe1, 21 },\n-\t/* 0xb2 */ { 0x3fffe0, 22 },\n-\t/* 0xb3 */ { 0x1fffe2, 21 },\n-\t/* 0xb4 */ { 0x7fffed, 23 },\n-\t/* 0xb5 */ { 0x3fffe1, 22 },\n-\t/* 0xb6 */ { 0x7fffee, 23 },\n-\t/* 0xb7 */ { 0x7fffef, 23 },\n-\t/* 0xb8 */ { 0xfffea, 20 },\n-\t/* 0xb9 */ { 0x3fffe2, 22 },\n-\t/* 0xba */ { 0x3fffe3, 22 },\n-\t/* 0xbb */ { 0x3fffe4, 22 },\n-\t/* 0xbc */ { 0x7ffff0, 23 },\n-\t/* 0xbd */ { 0x3fffe5, 22 },\n-\t/* 0xbe */ { 0x3fffe6, 22 },\n-\t/* 0xbf */ { 0x7ffff1, 23 },\n-\t/* 0xc0 */ { 0x3ffffe0, 26 },\n-\t/* 0xc1 */ { 0x3ffffe1, 26 },\n-\t/* 0xc2 */ { 0xfffeb, 20 },\n-\t/* 0xc3 */ { 0x7fff1, 19 },\n-\t/* 0xc4 */ { 0x3fffe7, 22 },\n-\t/* 0xc5 */ { 0x7ffff2, 23 },\n-\t/* 0xc6 */ { 0x3fffe8, 22 },\n-\t/* 0xc7 */ { 0x1ffffec, 25 },\n-\t/* 0xc8 */ { 0x3ffffe2, 26 },\n-\t/* 0xc9 */ { 0x3ffffe3, 26 },\n-\t/* 0xca */ { 0x3ffffe4, 26 },\n-\t/* 0xcb */ { 0x7ffffde, 27 },\n-\n-\t/* 0xcc */ { 0x7ffffdf, 27 },\n-\t/* 0xcd */ { 0x3ffffe5, 26 },\n-\t/* 0xce */ { 0xfffff1, 24 },\n-\t/* 0xcf */ { 0x1ffffed, 25 },\n-\t/* 0xd0 */ { 0x7fff2, 19 },\n-\t/* 0xd1 */ { 0x1fffe3, 21 },\n-\t/* 0xd2 */ { 0x3ffffe6, 26 },\n-\t/* 0xd3 */ { 0x7ffffe0, 27 },\n-\t/* 0xd4 */ { 0x7ffffe1, 27 },\n-\t/* 0xd5 */ { 0x3ffffe7, 26 },\n-\t/* 0xd6 */ { 0x7ffffe2, 27 },\n-\t/* 0xd7 */ { 0xfffff2, 24 },\n-\t/* 0xd8 */ { 0x1fffe4, 21 },\n-\t/* 0xd9 */ { 0x1fffe5, 21 },\n-\t/* 0xda */ { 0x3ffffe8, 26 },\n-\t/* 0xdb */ { 0x3ffffe9, 26 },\n-\t/* 0xdc */ { 0xffffffd, 28 },\n-\t/* 0xdd */ { 0x7ffffe3, 27 },\n-\t/* 0xde */ { 0x7ffffe4, 27 },\n-\t/* 0xdf */ { 0x7ffffe5, 27 },\n-\t/* 0xe0 */ { 0xfffec, 20 },\n-\t/* 0xe1 */ { 0xfffff3, 24 },\n-\t/* 0xe2 */ { 0xfffed, 20 },\n-\t/* 0xe3 */ { 0x1fffe6, 21 },\n-\t/* 0xe4 */ { 0x3fffe9, 22 },\n-\t/* 0xe5 */ { 0x1fffe7, 21 },\n-\t/* 0xe6 */ { 0x1fffe8, 21 },\n-\t/* 0xe7 */ { 0x7ffff3, 23 },\n-\t/* 0xe8 */ { 0x3fffea, 22 },\n-\t/* 0xe9 */ { 0x3fffeb, 22 },\n-\t/* 0xea */ { 0x1ffffee, 25 },\n-\t/* 0xeb */ { 0x1ffffef, 25 },\n-\t/* 0xec */ { 0xfffff4, 24 },\n-\t/* 0xed */ { 0xfffff5, 24 },\n-\t/* 0xee */ { 0x3ffffea, 26 },\n-\t/* 0xef */ { 0x7ffff4, 23 },\n-\t/* 0xf0 */ { 0x3ffffeb, 26 },\n-\t/* 0xf1 */ { 0x7ffffe6, 27 },\n-\t/* 0xf2 */ { 0x3ffffec, 26 },\n-\t/* 0xf3 */ { 0x3ffffed, 26 },\n-\t/* 0xf4 */ { 0x7ffffe7, 27 },\n-\t/* 0xf5 */ { 0x7ffffe8, 27 },\n-\t/* 0xf6 */ { 0x7ffffe9, 27 },\n-\t/* 0xf7 */ { 0x7ffffea, 27 },\n-\t/* 0xf8 */ { 0x7ffffeb, 27 },\n-\t/* 0xf9 */ { 0xffffffe, 28 },\n-\t/* 0xfa */ { 0x7ffffec, 27 },\n-\t/* 0xfb */ { 0x7ffffed, 27 },\n-\n-\t/* 0xfc */ { 0x7ffffee, 27 },\n-\t/* 0xfd */ { 0x7ffffef, 27 },\n-\t/* 0xfe */ { 0x7fffff0, 27 },\n-\t/* 0xff */ { 0x3ffffee, 26 },\n-\t/* 0x100 */ { 0x3fffffff, 30 },\n-};\n-\n-int code_bit(int idx, int bit)\n-{\n-\tif (bit \u003c huf_literal[idx].len)\n-\t\treturn !!(huf_literal[idx].code \u0026 (1 \u003c\u003c (huf_literal[idx].len - 1 - bit)));\n-\n-\treturn -1;\n-}\n-\n-#include \u0022huftable.h\u0022\n-\n-#define PARALLEL 2\n-\n-struct state {\n-\tint terminal;\n-\tint state[PARALLEL];\n-\tint bytepos;\n-\n-\tint real_pos;\n-};\n-\n-struct state state[2000];\n-unsigned char terms[2000];\n-int next \u003d 1;\n-\n-int lextable_decode(int pos, char c)\n-{\n-\tint q \u003d pos + !!c;\n-\n-\tif (lextable_terms[q \u003e\u003e 3] \u0026 (1 \u003c\u003c (q \u0026 7))) /* terminal */\n-\t\treturn lextable[q] | 0x8000;\n-\n-\treturn pos + (lextable[q] \u003c\u003c 1);\n-}\n-\n-int main(void)\n-{\n-\tint n \u003d 0;\n-\tint m \u003d 0;\n-\tint prev;\n-\tchar c;\n-\tint walk;\n-\tint saw;\n-\tint y;\n-\tint j;\n-\tint q;\n-\tint pos \u003d 0;\n-\tint biggest \u003d 0;\n-\tint fails \u003d 0;\n-\n-\tm \u003d 0;\n-\twhile (m \u003c ARRAY_SIZE(state)) {\n-\t\tfor (j \u003d 0; j \u003c PARALLEL; j++) {\n-\t\t\tstate[m].state[j] \u003d 0xffff;\n-\t\t\tstate[m].terminal \u003d 0;\n-\t\t}\n-\t\tm++;\n-\t}\n-\n-\twhile (n \u003c ARRAY_SIZE(huf_literal)) {\n-\n-\t\tm \u003d 0;\n-\t\twalk \u003d 0;\n-\t\tprev \u003d 0;\n-\n-\t\twhile (m \u003c huf_literal[n].len) {\n-\n-\t\t\tsaw \u003d 0;\n-\t\t\tif (state[walk].state[code_bit(n, m)] !\u003d 0xffff) {\n-\t\t\t\t/* exists -- go forward */\n-\t\t\t\twalk \u003d state[walk].state[code_bit(n, m)];\n-\t\t\t\tgoto again;\n-\t\t\t}\n-\n-\t\t\t/* something we didn't see before */\n-\n-\t\t\tstate[walk].state[code_bit(n, m)] \u003d next;\n-\t\t\twalk \u003d next++;\n-again:\n-\t\t\tm++;\n-\t\t}\n-\n-\t\tstate[walk].terminal \u003d n++;\n-\t\tstate[walk].state[0] \u003d 0; /* terminal marker */\n-\t}\n-\n-\twalk \u003d 0;\n-\tfor (n \u003d 0; n \u003c next; n++) {\n-\t\tstate[n].bytepos \u003d walk;\n-\t\twalk +\u003d (2 * 2);\n-\t}\n-\n-\t/* compute everyone's position first */\n-\n-\tpos \u003d 0;\n-\twalk \u003d 0;\n-\tfor (n \u003d 0; n \u003c next; n++) {\n-\n-\t\tstate[n].real_pos \u003d pos;\n-\n-\t\tif (state[n].state[0]) /* nonterminal */\n-\t\t\tpos +\u003d 2;\n-\n-\t\twalk ++;\n-\t}\n-\n-\tfprintf(stdout, \u0022static unsigned char lextable[] \u003d {\u005cn\u0022);\n-\n-#define TERMINAL_MASK 0x8000\n-\n-\twalk \u003d 0;\n-\tpos \u003d 0;\n-\tq \u003d 0;\n-\tfor (n \u003d 0; n \u003c next; n++) {\n-\t\tq \u003d pos;\n-\t\tfor (m \u003d 0; m \u003c 2; m++) {\n-\t\t\tsaw \u003d state[n].state[m];\n-\n-\t\t\tif (saw \u003d\u003d 0) { // c is a terminal then\n-\t\t\t\tm \u003d 2;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!m)\n-\t\t\t\tfprintf(stdout, \u0022/* pos %04x: %3d */ \u0022,\n-\t\t\t\t\t\t\t state[n].real_pos, n);\n-\t\t\telse\n-\t\t\t\tfprintf(stdout, \u0022 \u0022);\n-\n-\t\t\tif (saw \u003d\u003d 0xffff) {\n-\t\t\t\tfprintf(stdout,\n-\t\t\t\t \u0022 0xff, 0xff, /* 0 \u003d fail */\u005cn \u0022);\n-\t\t\t\tpos ++; /* fail */\n-\t\t\t\tfails++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\n-\t\t\tif (state[saw].state[0] \u003d\u003d 0) { /* points to terminal */\n-\t\t\t\tfprintf(stdout, \u0022 /* terminal %d */ 0x%02X,\u005cn\u0022,\n-\t\t\t\t\tstate[saw].terminal,\n-\t\t\t\t\tstate[saw].terminal \u0026 0xff);\n-\t\t\t\tterms[(state[n].real_pos + m) \u003e\u003e 3] |\u003d\n-\t\t\t\t\t1 \u003c\u003c ((state[n].real_pos + m) \u0026 7);\n-\t\t\t\tpos++;\n-\t\t\t\twalk++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\n-\t\t\tj \u003d (state[saw].real_pos - q) \u003e\u003e 1;\n-\n-\t\t\tif (j \u003e biggest)\n-\t\t\t\tbiggest \u003d j;\n-\n-\t\t\tif (j \u003e 0xffff) {\n-\t\t\t\tfprintf(stderr,\n-\t\t\t\t \u0022Jump \u003e 64K bytes ahead (%d to %d)\u005cn\u0022,\n-\t\t\t\t\tstate[n].real_pos, state[saw].real_pos);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\n-\t\t\tfprintf(stdout, \u0022 /* %d */ 0x%02X \u0022\n-\t\t\t\t\u0022/* (to 0x%04X state %3d) */,\u005cn\u0022,\n-\t\t\t\tm,\n-\t\t\t\tj \u0026 0xff,\n-\t\t\t\tstate[saw].real_pos, saw);\n-\t\t\tpos++;\n-\n-\t\t\twalk++;\n-\t\t}\n-\t}\n-\n-\tfprintf(stdout, \u0022/* total size %d bytes, biggest jump %d/256, fails\u003d%d */\u005cn};\u005cn\u0022\n-\t\t\t\u0022\u005cn static unsigned char lextable_terms[] \u003d {\u005cn\u0022,\n-\t \t\tpos, biggest, fails);\n-\n-\tfor (n \u003d 0; n \u003c (walk + 7) / 8; n++) {\n-\t\tif (!(n \u0026 7))\n-\t\t\tfprintf(stdout, \u0022\u005cn\u005ct\u0022);\n-\t\tfprintf(stdout, \u00220x%02x, \u0022, terms[n]);\n-\t}\n-\tfprintf(stdout, \u0022\u005cn};\u005cn\u0022);\n-\n-\t/*\n-\t * Try to parse every legal input string\n-\t */\n-\n-\tfor (n \u003d 0; n \u003c ARRAY_SIZE(huf_literal); n++) {\n-\t\twalk \u003d 0;\n-\t\tm \u003d 0;\n-\t\ty \u003d -1;\n-\n-\t\tfprintf(stderr, \u0022 trying %d\u005cn\u0022, n);\n-\n-\t\twhile (m \u003c huf_literal[n].len) {\n-\t\t\tprev \u003d walk;\n-\t\t\twalk \u003d lextable_decode(walk, code_bit(n, m));\n-\n-\t\t\tif (walk \u003d\u003d 0xffff) {\n-\t\t\t\tfprintf(stderr, \u0022failed\u005cn\u0022);\n-\t\t\t\treturn 3;\n-\t\t\t}\n-\n-\t\t\tif (walk \u0026 0x8000) {\n-\t\t\t\ty \u003d walk \u0026 0x7fff;\n-\t\t\t\tif (y \u003d\u003d 0 \u0026\u0026 m \u003d\u003d 29) {\n-\t\t\t\t\ty |\u003d 0x100;\n-\t\t\t\t\tfprintf(stdout,\n-\t\t\t\t\t\t\u0022\u005cn/* state that points to \u0022\n-\t\t\t\t\t\t\u00220x100 for disambiguation with \u0022\n-\t\t\t\t\t\t\u00220x0 */\u005cn\u0022\n-\t\t\t\t\t\t\u0022#define HUFTABLE_0x100_PREV \u0022\n-\t\t\t\t\t\t\u0022%d\u005cn\u0022, prev);\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tm++;\n-\t\t}\n-\n-\t\tif (y !\u003d n) {\n-\t\t\tfprintf(stderr, \u0022decode failed %d got %d (0x%x)\u005cn\u0022, n, y, y);\n-\t\t\treturn 4;\n-\t\t}\n-\t}\n-\n-\tfprintf(stderr, \u0022All decode OK\u005cn\u0022);\n-\n-\treturn 0;\n-}\ndiff --git a/lib/misc/base64-decode.c b/lib/misc/base64-decode.c\nnew file mode 100644\nindex 0000000..c8f11d2\n--- /dev/null\n+++ b/lib/misc/base64-decode.c\n@@ -0,0 +1,206 @@\n+/*\n+ * This code originally came from here\n+ *\n+ * http://base64.sourceforge.net/b64.c\n+ *\n+ * with the following license:\n+ *\n+ * LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.\n+ *\n+ * Permission is hereby granted, free of charge, to any person\n+ * obtaining a copy of this software and associated\n+ * documentation files (the \u0022Software\u0022), to deal in the\n+ * Software without restriction, including without limitation\n+ * the rights to use, copy, modify, merge, publish, distribute,\n+ * sublicense, and/or sell copies of the Software, and to\n+ * permit persons to whom the Software is furnished to do so,\n+ * subject to the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall\n+ * be included in all copies or substantial portions of the\n+ * Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \u0022AS IS\u0022, WITHOUT WARRANTY OF ANY\n+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n+ * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+ *\n+ * VERSION HISTORY:\n+ * Bob Trower 08/04/01 -- Create Version 0.00.00B\n+ *\n+ * I cleaned it up quite a bit to match the (linux kernel) style of the rest\n+ * of libwebsockets; this version is under LGPL2.1 + SLE like the rest of lws\n+ * since he explicitly allows sublicensing, but I give the URL above so you can\n+ * get the original with Bob's super-liberal terms directly if you prefer.\n+ */\n+\n+#include \u003cstdio.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u0022private-libwebsockets.h\u0022\n+\n+static const char encode[] \u003d \u0022ABCDEFGHIJKLMNOPQRSTUVWXYZ\u0022\n+\t\t\t \u0022abcdefghijklmnopqrstuvwxyz0123456789+/\u0022;\n+static const char decode[] \u003d \u0022|$$$}rstuvwxyz{$$$$$$$\u003e?@ABCDEFGHIJKLMNOPQRSTUVW\u0022\n+\t\t\t \u0022$$$$$$XYZ[\u005c\u005c]^_`abcdefghijklmnopq\u0022;\n+\n+LWS_VISIBLE int\n+lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)\n+{\n+\tunsigned char triple[3];\n+\tint i;\n+\tint len;\n+\tint line \u003d 0;\n+\tint done \u003d 0;\n+\n+\twhile (in_len) {\n+\t\tlen \u003d 0;\n+\t\tfor (i \u003d 0; i \u003c 3; i++) {\n+\t\t\tif (in_len) {\n+\t\t\t\ttriple[i] \u003d *in++;\n+\t\t\t\tlen++;\n+\t\t\t\tin_len--;\n+\t\t\t} else\n+\t\t\t\ttriple[i] \u003d 0;\n+\t\t}\n+\n+\t\tif (done + 4 \u003e\u003d out_size)\n+\t\t\treturn -1;\n+\n+\t\t*out++ \u003d encode[triple[0] \u003e\u003e 2];\n+\t\t*out++ \u003d encode[((triple[0] \u0026 0x03) \u003c\u003c 4) |\n+\t\t\t\t\t ((triple[1] \u0026 0xf0) \u003e\u003e 4)];\n+\t\t*out++ \u003d (len \u003e 1 ? encode[((triple[1] \u0026 0x0f) \u003c\u003c 2) |\n+\t\t\t\t\t ((triple[2] \u0026 0xc0) \u003e\u003e 6)] : '\u003d');\n+\t\t*out++ \u003d (len \u003e 2 ? encode[triple[2] \u0026 0x3f] : '\u003d');\n+\n+\t\tdone +\u003d 4;\n+\t\tline +\u003d 4;\n+\t}\n+\n+\tif (done + 1 \u003e\u003d out_size)\n+\t\treturn -1;\n+\n+\t*out++ \u003d '\u005c0';\n+\n+\treturn done;\n+}\n+\n+/*\n+ * returns length of decoded string in out, or -1 if out was too small\n+ * according to out_size\n+ */\n+\n+LWS_VISIBLE int\n+lws_b64_decode_string(const char *in, char *out, int out_size)\n+{\n+\tint len, i, c \u003d 0, done \u003d 0;\n+\tunsigned char v, quad[4];\n+\n+\twhile (*in) {\n+\n+\t\tlen \u003d 0;\n+\t\tfor (i \u003d 0; i \u003c 4 \u0026\u0026 *in; i++) {\n+\n+\t\t\tv \u003d 0;\n+\t\t\tc \u003d 0;\n+\t\t\twhile (*in \u0026\u0026 !v) {\n+\t\t\t\tc \u003d v \u003d *in++;\n+\t\t\t\tv \u003d (v \u003c 43 || v \u003e 122) ? 0 : decode[v - 43];\n+\t\t\t\tif (v)\n+\t\t\t\t\tv \u003d (v \u003d\u003d '$') ? 0 : v - 61;\n+\t\t\t}\n+\t\t\tif (c) {\n+\t\t\t\tlen++;\n+\t\t\t\tif (v)\n+\t\t\t\t\tquad[i] \u003d v - 1;\n+\t\t\t} else\n+\t\t\t\tquad[i] \u003d 0;\n+\t\t}\n+\n+\t\tif (out_size \u003c (done + len - 1))\n+\t\t\t/* out buffer is too small */\n+\t\t\treturn -1;\n+\n+\t\t/*\n+\t\t * \u0022The '\u003d\u003d' sequence indicates that the last group contained\n+\t\t * only one byte, and '\u003d' indicates that it contained two\n+\t\t * bytes.\u0022 (wikipedia)\n+\t\t */\n+\n+\t\tif (!*in \u0026\u0026 c \u003d\u003d '\u003d')\n+\t\t\tlen--;\n+\n+\t\tif (len \u003e\u003d 2)\n+\t\t\t*out++ \u003d quad[0] \u003c\u003c 2 | quad[1] \u003e\u003e 4;\n+\t\tif (len \u003e\u003d 3)\n+\t\t\t*out++ \u003d quad[1] \u003c\u003c 4 | quad[2] \u003e\u003e 2;\n+\t\tif (len \u003e\u003d 4)\n+\t\t\t*out++ \u003d ((quad[2] \u003c\u003c 6) \u0026 0xc0) | quad[3];\n+\n+\t\tdone +\u003d len - 1;\n+\t}\n+\n+\tif (done + 1 \u003e\u003d out_size)\n+\t\treturn -1;\n+\n+\t*out \u003d '\u005c0';\n+\n+\treturn done;\n+}\n+\n+#if 0\n+int\n+lws_b64_selftest(void)\n+{\n+\tchar buf[64];\n+\tunsigned int n, r \u003d 0;\n+\tunsigned int test;\n+\t/* examples from https://en.wikipedia.org/wiki/Base64 */\n+\tstatic const char * const plaintext[] \u003d {\n+\t\t\u0022any carnal pleasure.\u0022,\n+\t\t\u0022any carnal pleasure\u0022,\n+\t\t\u0022any carnal pleasur\u0022,\n+\t\t\u0022any carnal pleasu\u0022,\n+\t\t\u0022any carnal pleas\u0022,\n+\t\t\u0022Admin:kloikloi\u0022\n+\t};\n+\tstatic const char * const coded[] \u003d {\n+\t\t\u0022YW55IGNhcm5hbCBwbGVhc3VyZS4\u003d\u0022,\n+\t\t\u0022YW55IGNhcm5hbCBwbGVhc3VyZQ\u003d\u003d\u0022,\n+\t\t\u0022YW55IGNhcm5hbCBwbGVhc3Vy\u0022,\n+\t\t\u0022YW55IGNhcm5hbCBwbGVhc3U\u003d\u0022,\n+\t\t\u0022YW55IGNhcm5hbCBwbGVhcw\u003d\u003d\u0022,\n+\t\t\u0022QWRtaW46a2xvaWtsb2k\u003d\u0022\n+\t};\n+\n+\tfor (test \u003d 0; test \u003c sizeof plaintext / sizeof(plaintext[0]); test++) {\n+\n+\t\tbuf[sizeof(buf) - 1] \u003d '\u005c0';\n+\t\tn \u003d lws_b64_encode_string(plaintext[test],\n+\t\t\t\t strlen(plaintext[test]), buf, sizeof buf);\n+\t\tif (n !\u003d strlen(coded[test]) || strcmp(buf, coded[test])) {\n+\t\t\tlwsl_err(\u0022Failed lws_b64 encode selftest \u0022\n+\t\t\t\t\t \u0022%d result '%s' %d\u005cn\u0022, test, buf, n);\n+\t\t\tr \u003d -1;\n+\t\t}\n+\n+\t\tbuf[sizeof(buf) - 1] \u003d '\u005c0';\n+\t\tn \u003d lws_b64_decode_string(coded[test], buf, sizeof buf);\n+\t\tif (n !\u003d strlen(plaintext[test]) ||\n+\t\t\t\t\t\t strcmp(buf, plaintext[test])) {\n+\t\t\tlwsl_err(\u0022Failed lws_b64 decode selftest \u0022\n+\t\t\t\t \u0022%d result '%s' / '%s', %d / %d\u005cn\u0022,\n+\t\t\t\t test, buf, plaintext[test], n, strlen(plaintext[test]));\n+\t\t\tr \u003d -1;\n+\t\t}\n+\t}\n+\n+\tlwsl_notice(\u0022Base 64 selftests passed\u005cn\u0022);\n+\n+\treturn r;\n+}\n+#endif\ndiff --git a/lib/misc/getifaddrs.c b/lib/misc/getifaddrs.c\nnew file mode 100644\nindex 0000000..beecad9\n--- /dev/null\n+++ b/lib/misc/getifaddrs.c\n@@ -0,0 +1,272 @@\n+/*\n+ * downloaded from\n+ * http://ftp.uninett.no/pub/OpenBSD/src/kerberosV/src/lib/roken/getifaddrs.c\n+ */\n+#if !LWS_HAVE_GETIFADDRS\n+/*\n+ * Copyright (c) 2000 - 2001 Kungliga Tekniska H�gskolan\n+ * (Royal Institute of Technology, Stockholm, Sweden).\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions\n+ * are met:\n+ *\n+ * 1. Redistributions of source code must retain the above copyright\n+ * notice, this list of conditions and the following disclaimer.\n+ *\n+ * 2. Redistributions in binary form must reproduce the above copyright\n+ * notice, this list of conditions and the following disclaimer in the\n+ * documentation and/or other materials provided with the distribution.\n+ *\n+ * 3. Neither the name of the Institute nor the names of its contributors\n+ * may be used to endorse or promote products derived from this software\n+ * without specific prior written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND\n+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE\n+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n+ * SUCH DAMAGE.\n+ */\n+\n+#include \u003cerrno.h\u003e\n+#include \u003csys/types.h\u003e\n+#include \u003csys/socket.h\u003e\n+#include \u003cnet/if.h\u003e\n+#include \u003cstdlib.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u003csys/ioctl.h\u003e\n+#include \u003cunistd.h\u003e\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#ifdef LWS_HAVE_SYS_SOCKIO_H\n+#include \u003csys/sockio.h\u003e\n+#endif\n+\n+#ifdef LWS_HAVE_NETINET_IN6_VAR_H\n+#include \u003cnetinet/in6_var.h\u003e\n+#endif\n+\n+#ifndef max\n+#define max(a, b) ((a) \u003e (b) ? (a) : (b))\n+#endif\n+\n+#include \u0022getifaddrs.h\u0022\n+\n+static int\n+getifaddrs2(struct ifaddrs **ifap, int af, int siocgifconf, int siocgifflags,\n+\t size_t ifreq_sz)\n+{\n+\tint ret;\n+\tint fd;\n+\tsize_t buf_size;\n+\tchar *buf;\n+\tstruct ifconf ifconf;\n+\tchar *p;\n+\tsize_t sz;\n+\tstruct sockaddr sa_zero;\n+\tstruct ifreq *ifr;\n+\tstruct ifaddrs *start, **end \u003d \u0026start;\n+\n+\tbuf \u003d NULL;\n+\n+\tmemset(\u0026sa_zero, 0, sizeof(sa_zero));\n+\tfd \u003d socket(af, SOCK_DGRAM, 0);\n+\tif (fd \u003c 0)\n+\t\treturn -1;\n+\n+\tbuf_size \u003d 8192;\n+\tfor (;;) {\n+\t\tbuf \u003d lws_zalloc(buf_size, \u0022getifaddrs2\u0022);\n+\t\tif (buf \u003d\u003d NULL) {\n+\t\t\tret \u003d ENOMEM;\n+\t\t\tgoto error_out;\n+\t\t}\n+\t\tifconf.ifc_len \u003d buf_size;\n+\t\tifconf.ifc_buf \u003d buf;\n+\n+\t\t/*\n+\t\t * Solaris returns EINVAL when the buffer is too small.\n+\t\t */\n+\t\tif (ioctl(fd, siocgifconf, \u0026ifconf) \u003c 0 \u0026\u0026 errno !\u003d EINVAL) {\n+\t\t\tret \u003d errno;\n+\t\t\tgoto error_out;\n+\t\t}\n+\t\t/*\n+\t\t * Can the difference between a full and a overfull buf\n+\t\t * be determined?\n+\t\t */\n+\n+\t\tif (ifconf.ifc_len \u003c (int)buf_size)\n+\t\t\tbreak;\n+\t\tlws_free(buf);\n+\t\tbuf_size *\u003d 2;\n+\t}\n+\n+\tfor (p \u003d ifconf.ifc_buf; p \u003c ifconf.ifc_buf + ifconf.ifc_len; p +\u003d sz) {\n+\t\tstruct ifreq ifreq;\n+\t\tstruct sockaddr *sa;\n+\t\tsize_t salen;\n+\n+\t\tifr \u003d (struct ifreq *)p;\n+\t\tsa \u003d \u0026ifr-\u003eifr_addr;\n+\n+\t\tsz \u003d ifreq_sz;\n+\t\tsalen \u003d sizeof(struct sockaddr);\n+#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN\n+\t\tsalen \u003d sa-\u003esa_len;\n+\t\tsz \u003d max(sz, sizeof(ifr-\u003eifr_name) + sa-\u003esa_len);\n+#endif\n+#ifdef SA_LEN\n+\t\tsalen \u003d SA_LEN(sa);\n+\t\tsz \u003d max(sz, sizeof(ifr-\u003eifr_name) + SA_LEN(sa));\n+#endif\n+\t\tmemset(\u0026ifreq, 0, sizeof(ifreq));\n+\t\tmemcpy(ifreq.ifr_name, ifr-\u003eifr_name, sizeof(ifr-\u003eifr_name));\n+\n+\t\tif (ioctl(fd, siocgifflags, \u0026ifreq) \u003c 0) {\n+\t\t\tret \u003d errno;\n+\t\t\tgoto error_out;\n+\t\t}\n+\n+\t\t*end \u003d lws_malloc(sizeof(**end), \u0022getifaddrs\u0022);\n+\n+\t\t(*end)-\u003eifa_next \u003d NULL;\n+\t\t(*end)-\u003eifa_name \u003d strdup(ifr-\u003eifr_name);\n+\t\t(*end)-\u003eifa_flags \u003d ifreq.ifr_flags;\n+\t\t(*end)-\u003eifa_addr \u003d lws_malloc(salen);\n+\t\tmemcpy((*end)-\u003eifa_addr, sa, salen);\n+\t\t(*end)-\u003eifa_netmask \u003d NULL;\n+\n+#if 0\n+\t\t/* fix these when we actually need them */\n+\t\tif (ifreq.ifr_flags \u0026 IFF_BROADCAST) {\n+\t\t\t(*end)-\u003eifa_broadaddr \u003d\n+\t\t\t\tlws_malloc(sizeof(ifr-\u003eifr_broadaddr), \u0022getifaddrs\u0022);\n+\t\t\tmemcpy((*end)-\u003eifa_broadaddr, \u0026ifr-\u003eifr_broadaddr,\n+\t\t\t\t\t\t sizeof(ifr-\u003eifr_broadaddr));\n+\t\t} else if (ifreq.ifr_flags \u0026 IFF_POINTOPOINT) {\n+\t\t\t(*end)-\u003eifa_dstaddr \u003d\n+\t\t\t\tlws_malloc(sizeof(ifr-\u003eifr_dstaddr), \u0022getifaddrs\u0022);\n+\t\t\tmemcpy((*end)-\u003eifa_dstaddr, \u0026ifr-\u003eifr_dstaddr,\n+\t\t\t\t\t\t sizeof(ifr-\u003eifr_dstaddr));\n+\t\t} else\n+\t\t\t(*end)-\u003eifa_dstaddr \u003d NULL;\n+#else\n+\t\t(*end)-\u003eifa_dstaddr \u003d NULL;\n+#endif\n+\t\t(*end)-\u003eifa_data \u003d NULL;\n+\n+\t\tend \u003d \u0026(*end)-\u003eifa_next;\n+\n+\t}\n+\t*ifap \u003d start;\n+\tclose(fd);\n+\tlws_free(buf);\n+\treturn 0;\n+\n+error_out:\n+\tclose(fd);\n+\tlws_free(buf);\n+\terrno \u003d ret;\n+\n+\treturn -1;\n+}\n+\n+int\n+getifaddrs(struct ifaddrs **ifap)\n+{\n+\tint ret \u003d -1;\n+\terrno \u003d ENXIO;\n+#if defined(AF_INET6) \u0026\u0026 defined(SIOCGIF6CONF) \u0026\u0026 defined(SIOCGIF6FLAGS)\n+\tif (ret)\n+\t\tret \u003d getifaddrs2(ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,\n+\t\t\t sizeof(struct in6_ifreq));\n+#endif\n+#if defined(LWS_HAVE_IPV6) \u0026\u0026 defined(SIOCGIFCONF)\n+\tif (ret)\n+\t\tret \u003d getifaddrs2(ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,\n+\t\t\t sizeof(struct ifreq));\n+#endif\n+#if defined(AF_INET) \u0026\u0026 defined(SIOCGIFCONF) \u0026\u0026 defined(SIOCGIFFLAGS)\n+\tif (ret)\n+\t\tret \u003d getifaddrs2(ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,\n+\t\t\t sizeof(struct ifreq));\n+#endif\n+\treturn ret;\n+}\n+\n+void\n+freeifaddrs(struct ifaddrs *ifp)\n+{\n+\tstruct ifaddrs *p, *q;\n+\n+\tfor (p \u003d ifp; p; ) {\n+\t\tlws_free(p-\u003eifa_name);\n+\t\tlws_free(p-\u003eifa_addr);\n+\t\tlws_free(p-\u003eifa_dstaddr);\n+\t\tlws_free(p-\u003eifa_netmask);\n+\t\tlws_free(p-\u003eifa_data);\n+\t\tq \u003d p;\n+\t\tp \u003d p-\u003eifa_next;\n+\t\tlws_free(q);\n+\t}\n+}\n+\n+#ifdef TEST\n+\n+void\n+print_addr(const char *s, struct sockaddr *sa)\n+{\n+\tint i;\n+\tprintf(\u0022 %s\u003d%d/\u0022, s, sa-\u003esa_family);\n+#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN\n+\tfor (i \u003d 0;\n+\t i \u003c sa-\u003esa_len - ((lws_intptr_t)sa-\u003esa_data - (lws_intptr_t)\u0026sa-\u003esa_family); i++)\n+\t\tprintf(\u0022%02x\u0022, ((unsigned char *)sa-\u003esa_data)[i]);\n+#else\n+\tfor (i \u003d 0; i \u003c sizeof(sa-\u003esa_data); i++)\n+\t\tprintf(\u0022%02x\u0022, ((unsigned char *)sa-\u003esa_data)[i]);\n+#endif\n+\tprintf(\u0022\u005cn\u0022);\n+}\n+\n+void\n+print_ifaddrs(struct ifaddrs *x)\n+{\n+\tstruct ifaddrs *p;\n+\n+\tfor (p \u003d x; p; p \u003d p-\u003eifa_next) {\n+\t\tprintf(\u0022%s\u005cn\u0022, p-\u003eifa_name);\n+\t\tprintf(\u0022 flags\u003d%x\u005cn\u0022, p-\u003eifa_flags);\n+\t\tif (p-\u003eifa_addr)\n+\t\t\tprint_addr(\u0022addr\u0022, p-\u003eifa_addr);\n+\t\tif (p-\u003eifa_dstaddr)\n+\t\t\tprint_addr(\u0022dstaddr\u0022, p-\u003eifa_dstaddr);\n+\t\tif (p-\u003eifa_netmask)\n+\t\t\tprint_addr(\u0022netmask\u0022, p-\u003eifa_netmask);\n+\t\tprintf(\u0022 %p\u005cn\u0022, p-\u003eifa_data);\n+\t}\n+}\n+\n+int\n+main()\n+{\n+\tstruct ifaddrs *a \u003d NULL, *b;\n+\tgetifaddrs2(\u0026a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,\n+\t\t sizeof(struct ifreq));\n+\tprint_ifaddrs(a);\n+\tprintf(\u0022---\u005cn\u0022);\n+\tgetifaddrs(\u0026b);\n+\tprint_ifaddrs(b);\n+\treturn 0;\n+}\n+#endif\n+#endif\ndiff --git a/lib/misc/getifaddrs.h b/lib/misc/getifaddrs.h\nnew file mode 100644\nindex 0000000..d26670c\n--- /dev/null\n+++ b/lib/misc/getifaddrs.h\n@@ -0,0 +1,80 @@\n+#ifndef LWS_HAVE_GETIFADDRS\n+#define LWS_HAVE_GETIFADDRS 0\n+#endif\n+\n+#if LWS_HAVE_GETIFADDRS\n+#include \u003csys/types.h\u003e\n+#include \u003cifaddrs.h\u003e\n+#else\n+#ifdef __cplusplus\n+extern \u0022C\u0022 {\n+#endif\n+/*\n+ * Copyright (c) 2000 Kungliga Tekniska H�gskolan\n+ * (Royal Institute of Technology, Stockholm, Sweden).\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions\n+ * are met:\n+ *\n+ * 1. Redistributions of source code must retain the above copyright\n+ * notice, this list of conditions and the following disclaimer.\n+ *\n+ * 2. Redistributions in binary form must reproduce the above copyright\n+ * notice, this list of conditions and the following disclaimer in the\n+ * documentation and/or other materials provided with the distribution.\n+ *\n+ * 3. Neither the name of the Institute nor the names of its contributors\n+ * may be used to endorse or promote products derived from this software\n+ * without specific prior written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND\n+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE\n+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n+ * SUCH DAMAGE.\n+ */\n+\n+/* $KTH: ifaddrs.hin,v 1.3 2000/12/11 00:01:13 assar Exp $ */\n+\n+#ifndef ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791\n+#define ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791\n+\n+/*\n+ * the interface is defined in terms of the fields below, and this is\n+ * sometimes #define'd, so there seems to be no simple way of solving\n+ * this and this seemed the best. */\n+\n+#undef ifa_dstaddr\n+\n+struct ifaddrs {\n+\tstruct ifaddrs *ifa_next;\n+\tchar *ifa_name;\n+\tunsigned int ifa_flags;\n+\tstruct sockaddr *ifa_addr;\n+\tstruct sockaddr *ifa_netmask;\n+\tstruct sockaddr *ifa_dstaddr;\n+\tvoid *ifa_data;\n+};\n+\n+#ifndef ifa_broadaddr\n+#define ifa_broadaddr ifa_dstaddr\n+#endif\n+\n+int getifaddrs(struct ifaddrs **);\n+\n+void freeifaddrs(struct ifaddrs *);\n+\n+#endif /* __ifaddrs_h__ */\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+#endif\ndiff --git a/lib/misc/lejp.c b/lib/misc/lejp.c\nnew file mode 100644\nindex 0000000..50ff4b5\n--- /dev/null\n+++ b/lib/misc/lejp.c\n@@ -0,0 +1,709 @@\n+/*\n+ * Lightweight Embedded JSON Parser\n+ *\n+ * Copyright (C) 2013 Andy Green \u003candy@warmcat.com\u003e\n+ * This code is licensed under LGPL 2.1\n+ * http://www.gnu.org/licenses/lgpl-2.1.html\n+ */\n+\n+#include \u003cstring.h\u003e\n+#include \u0022lejp.h\u0022\n+\n+#include \u003cstdio.h\u003e\n+\n+/**\n+ * lejp_construct - prepare a struct lejp_ctx for use\n+ *\n+ * \u005cparam ctx:\tpointer to your struct lejp_ctx\n+ * \u005cparam callback:\tyour user callback which will received parsed tokens\n+ * \u005cparam user:\toptional user data pointer untouched by lejp\n+ * \u005cparam paths:\tyour array of name elements you are interested in\n+ * \u005cparam count_paths:\tARRAY_SIZE() of @paths\n+ *\n+ * Prepares your context struct for use with lejp\n+ */\n+\n+void\n+lejp_construct(struct lejp_ctx *ctx,\n+\tchar (*callback)(struct lejp_ctx *ctx, char reason), void *user,\n+\t\t\tconst char * const *paths, unsigned char count_paths)\n+{\n+\tctx-\u003est[0].s \u003d 0;\n+\tctx-\u003est[0].p \u003d 0;\n+\tctx-\u003est[0].i \u003d 0;\n+\tctx-\u003est[0].b \u003d 0;\n+\tctx-\u003esp \u003d 0;\n+\tctx-\u003eipos \u003d 0;\n+\tctx-\u003eppos \u003d 0;\n+\tctx-\u003epath_match \u003d 0;\n+\tctx-\u003epath[0] \u003d '\u005c0';\n+\tctx-\u003ecallback \u003d callback;\n+\tctx-\u003euser \u003d user;\n+\tctx-\u003epaths \u003d paths;\n+\tctx-\u003ecount_paths \u003d count_paths;\n+\tctx-\u003eline \u003d 1;\n+\tctx-\u003ecallback(ctx, LEJPCB_CONSTRUCTED);\n+}\n+\n+/**\n+ * lejp_destruct - retire a previously constructed struct lejp_ctx\n+ *\n+ * \u005cparam ctx:\tpointer to your struct lejp_ctx\n+ *\n+ * lejp does not perform any allocations, but since your user code might, this\n+ * provides a one-time LEJPCB_DESTRUCTED callback at destruction time where\n+ * you can clean up in your callback.\n+ */\n+\n+void\n+lejp_destruct(struct lejp_ctx *ctx)\n+{\n+\t/* no allocations... just let callback know what it happening */\n+\tctx-\u003ecallback(ctx, LEJPCB_DESTRUCTED);\n+}\n+\n+/**\n+ * lejp_change_callback - switch to a different callback from now on\n+ *\n+ * \u005cparam ctx:\tpointer to your struct lejp_ctx\n+ * \u005cparam callback:\tyour user callback which will received parsed tokens\n+ *\n+ * This tells the old callback it was destroyed, in case you want to take any\n+ * action because that callback \u0022lost focus\u0022, then changes to the new\n+ * callback and tells it first that it was constructed, and then started.\n+ *\n+ * Changing callback is a cheap and powerful trick to split out handlers\n+ * according to information earlier in the parse. For example you may have\n+ * a JSON pair \u0022schema\u0022 whose value defines what can be expected for the rest\n+ * of the JSON. Rather than having one huge callback for all cases, you can\n+ * have an initial one looking for \u0022schema\u0022 which then calls\n+ * lejp_change_callback() to a handler specific for the schema.\n+ *\n+ * Notice that afterwards, you need to construct the context again anyway to\n+ * parse another JSON object, and the callback is reset then to the main,\n+ * schema-interpreting one. The construction action is very lightweight.\n+ */\n+\n+void\n+lejp_change_callback(struct lejp_ctx *ctx,\n+\t\t char (*callback)(struct lejp_ctx *ctx, char reason))\n+{\n+\tctx-\u003ecallback(ctx, LEJPCB_DESTRUCTED);\n+\tctx-\u003ecallback \u003d callback;\n+\tctx-\u003ecallback(ctx, LEJPCB_CONSTRUCTED);\n+\tctx-\u003ecallback(ctx, LEJPCB_START);\n+}\n+\n+static void\n+lejp_check_path_match(struct lejp_ctx *ctx)\n+{\n+\tconst char *p, *q;\n+\tint n;\n+\n+\t/* we only need to check if a match is not active */\n+\tfor (n \u003d 0; !ctx-\u003epath_match \u0026\u0026 n \u003c ctx-\u003ecount_paths; n++) {\n+\t\tctx-\u003ewildcount \u003d 0;\n+\t\tp \u003d ctx-\u003epath;\n+\t\tq \u003d ctx-\u003epaths[n];\n+\t\twhile (*p \u0026\u0026 *q) {\n+\t\t\tif (*q !\u003d '*') {\n+\t\t\t\tif (*p !\u003d *q)\n+\t\t\t\t\tbreak;\n+\t\t\t\tp++;\n+\t\t\t\tq++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tctx-\u003ewild[ctx-\u003ewildcount++] \u003d p - ctx-\u003epath;\n+\t\t\tq++;\n+\t\t\t/*\n+\t\t\t * if * has something after it, match to .\n+\t\t\t * if ends with *, eat everything.\n+\t\t\t * This implies match sequences must be ordered like\n+\t\t\t * x.*.*\n+\t\t\t * x.*\n+\t\t\t * if both options are possible\n+\t\t\t */\n+\t\t\twhile (*p \u0026\u0026 (*p !\u003d '.' || !*q))\n+\t\t\t\tp++;\n+\t\t}\n+\t\tif (*p || *q)\n+\t\t\tcontinue;\n+\n+\t\tctx-\u003epath_match \u003d n + 1;\n+\t\tctx-\u003epath_match_len \u003d ctx-\u003eppos;\n+\t\treturn;\n+\t}\n+\n+\tif (!ctx-\u003epath_match)\n+\t\tctx-\u003ewildcount \u003d 0;\n+}\n+\n+int\n+lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)\n+{\n+\tint n;\n+\n+\tif (wildcard \u003e\u003d ctx-\u003ewildcount || !len)\n+\t\treturn 0;\n+\n+\tn \u003d ctx-\u003ewild[wildcard];\n+\n+\twhile (--len \u0026\u0026 n \u003c ctx-\u003eppos \u0026\u0026 (n \u003d\u003d ctx-\u003ewild[wildcard] || ctx-\u003epath[n] !\u003d '.'))\n+\t\t*dest++ \u003d ctx-\u003epath[n++];\n+\n+\t*dest \u003d '\u005c0';\n+\tn++;\n+\n+\treturn n - ctx-\u003ewild[wildcard];\n+}\n+\n+/**\n+ * lejp_parse - interpret some more incoming data incrementally\n+ *\n+ * \u005cparam ctx:\tpreviously constructed parsing context\n+ * \u005cparam json:\tchar buffer with the new data to interpret\n+ * \u005cparam len:\tamount of data in the buffer\n+ *\n+ * Because lejp is a stream parser, it incrementally parses as new data\n+ * becomes available, maintaining all state in the context struct. So an\n+ * incomplete JSON is a normal situation, getting you a LEJP_CONTINUE\n+ * return, signalling there's no error but to call again with more data when\n+ * it comes to complete the parsing. Successful parsing completes with a\n+ * 0 or positive integer indicating how much of the last input buffer was\n+ * unused.\n+ */\n+\n+int\n+lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)\n+{\n+\tunsigned char c, n, s, ret \u003d LEJP_REJECT_UNKNOWN;\n+\tstatic const char esc_char[] \u003d \u0022\u005c\u0022\u005c\u005c/bfnrt\u0022;\n+\tstatic const char esc_tran[] \u003d \u0022\u005c\u0022\u005c\u005c/\u005cb\u005cf\u005cn\u005cr\u005ct\u0022;\n+\tstatic const char tokens[] \u003d \u0022rue alse ull \u0022;\n+\n+\tif (!ctx-\u003esp \u0026\u0026 !ctx-\u003eppos)\n+\t\tctx-\u003ecallback(ctx, LEJPCB_START);\n+\n+\twhile (len--) {\n+\t\tc \u003d *json++;\n+\n+\t\ts \u003d ctx-\u003est[ctx-\u003esp].s;\n+\n+\t\t/* skip whitespace unless we should care */\n+\t\tif (c \u003d\u003d ' ' || c \u003d\u003d '\u005ct' || c \u003d\u003d '\u005cn' || c \u003d\u003d '\u005cr' || c \u003d\u003d '#') {\n+\t\t\tif (c \u003d\u003d '\u005cn') {\n+\t\t\t\tctx-\u003eline++;\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u0026\u003d ~LEJP_FLAG_WS_COMMENTLINE;\n+\t\t\t}\n+\t\t\tif (!(s \u0026 LEJP_FLAG_WS_KEEP)) {\n+\t\t\t\tif (c \u003d\u003d '#')\n+\t\t\t\t\tctx-\u003est[ctx-\u003esp].s |\u003d\n+\t\t\t\t\t\tLEJP_FLAG_WS_COMMENTLINE;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ctx-\u003est[ctx-\u003esp].s \u0026 LEJP_FLAG_WS_COMMENTLINE)\n+\t\t\tcontinue;\n+\n+\t\tswitch (s) {\n+\t\tcase LEJP_IDLE:\n+\t\t\tif (c !\u003d '{') {\n+\t\t\t\tret \u003d LEJP_REJECT_IDLE_NO_BRACE;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_OBJECT_START)) {\n+\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MEMBERS;\n+\t\t\tbreak;\n+\t\tcase LEJP_MEMBERS:\n+\t\t\tif (c \u003d\u003d '}') {\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_IDLE;\n+\t\t\t\tret \u003d LEJP_REJECT_MEMBERS_NO_CLOSE;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_M_P;\n+\t\t\tgoto redo_character;\n+\t\tcase LEJP_M_P:\n+\t\t\tif (c !\u003d '\u005c\u0022') {\n+\t\t\t\tret \u003d LEJP_REJECT_MP_NO_OPEN_QUOTE;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\t/* push */\n+\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_DELIM;\n+\t\t\tc \u003d LEJP_MP_STRING;\n+\t\t\tgoto add_stack_level;\n+\n+\t\tcase LEJP_MP_STRING:\n+\t\t\tif (c \u003d\u003d '\u005c\u0022') {\n+\t\t\t\tif (!ctx-\u003esp) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_MP_STRING_UNDERRUN;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tif (ctx-\u003est[ctx-\u003esp - 1].s !\u003d LEJP_MP_DELIM) {\n+\t\t\t\t\tctx-\u003ebuf[ctx-\u003enpos] \u003d '\u005c0';\n+\t\t\t\t\tif (ctx-\u003ecallback(ctx,\n+\t\t\t\t\t\t LEJPCB_VAL_STR_END) \u003c 0) {\n+\t\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\t\tgoto reject;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\t/* pop */\n+\t\t\t\tctx-\u003esp--;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (c \u003d\u003d '\u005c\u005c') {\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_STRING_ESC;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (c \u003c ' ') {/* \u0022control characters\u0022 not allowed */\n+\t\t\t\tret \u003d LEJP_REJECT_MP_ILLEGAL_CTRL;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\tgoto emit_string_char;\n+\n+\t\tcase LEJP_MP_STRING_ESC:\n+\t\t\tif (c \u003d\u003d 'u') {\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_STRING_ESC_U1;\n+\t\t\t\tctx-\u003euni \u003d 0;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tfor (n \u003d 0; n \u003c sizeof(esc_char); n++) {\n+\t\t\t\tif (c !\u003d esc_char[n])\n+\t\t\t\t\tcontinue;\n+\t\t\t\t/* found it */\n+\t\t\t\tc \u003d esc_tran[n];\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_STRING;\n+\t\t\t\tgoto emit_string_char;\n+\t\t\t}\n+\t\t\tret \u003d LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC;\n+\t\t\t/* illegal escape char */\n+\t\t\tgoto reject;\n+\n+\t\tcase LEJP_MP_STRING_ESC_U1:\n+\t\tcase LEJP_MP_STRING_ESC_U2:\n+\t\tcase LEJP_MP_STRING_ESC_U3:\n+\t\tcase LEJP_MP_STRING_ESC_U4:\n+\t\t\tctx-\u003euni \u003c\u003c\u003d 4;\n+\t\t\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')\n+\t\t\t\tctx-\u003euni |\u003d c - '0';\n+\t\t\telse\n+\t\t\t\tif (c \u003e\u003d 'a' \u0026\u0026 c \u003c\u003d 'f')\n+\t\t\t\t\tctx-\u003euni \u003d c - 'a' + 10;\n+\t\t\t\telse\n+\t\t\t\t\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'F')\n+\t\t\t\t\t\tctx-\u003euni \u003d c - 'A' + 10;\n+\t\t\t\t\telse {\n+\t\t\t\t\t\tret \u003d LEJP_REJECT_ILLEGAL_HEX;\n+\t\t\t\t\t\tgoto reject;\n+\t\t\t\t\t}\n+\t\t\tctx-\u003est[ctx-\u003esp].s++;\n+\t\t\tswitch (s) {\n+\t\t\tcase LEJP_MP_STRING_ESC_U2:\n+\t\t\t\tif (ctx-\u003euni \u003c 0x08)\n+\t\t\t\t\tbreak;\n+\t\t\t\t/*\n+\t\t\t\t * 0x08-0xff (0x0800 - 0xffff)\n+\t\t\t\t * emit 3-byte UTF-8\n+\t\t\t\t */\n+\t\t\t\tc \u003d 0xe0 | ((ctx-\u003euni \u003e\u003e 4) \u0026 0xf);\n+\t\t\t\tgoto emit_string_char;\n+\n+\t\t\tcase LEJP_MP_STRING_ESC_U3:\n+\t\t\t\tif (ctx-\u003euni \u003e\u003d 0x080) {\n+\t\t\t\t\t/*\n+\t\t\t\t\t * 0x080 - 0xfff (0x0800 - 0xffff)\n+\t\t\t\t\t * middle 3-byte seq\n+\t\t\t\t\t * send ....XXXXXX..\n+\t\t\t\t\t */\n+\t\t\t\t\tc \u003d 0x80 | ((ctx-\u003euni \u003e\u003e 2) \u0026 0x3f);\n+\t\t\t\t\tgoto emit_string_char;\n+\t\t\t\t}\n+\t\t\t\tif (ctx-\u003euni \u003c 0x008)\n+\t\t\t\t\tbreak;\n+\t\t\t\t/*\n+\t\t\t\t * 0x008 - 0x7f (0x0080 - 0x07ff)\n+\t\t\t\t * start 2-byte seq\n+\t\t\t\t */\n+\t\t\t\tc \u003d 0xc0 | (ctx-\u003euni \u003e\u003e 2);\n+\t\t\t\tgoto emit_string_char;\n+\n+\t\t\tcase LEJP_MP_STRING_ESC_U4:\n+\t\t\t\tif (ctx-\u003euni \u003e\u003d 0x0080)\n+\t\t\t\t\t/* end of 2 or 3-byte seq */\n+\t\t\t\t\tc \u003d 0x80 | (ctx-\u003euni \u0026 0x3f);\n+\t\t\t\telse\n+\t\t\t\t\t/* literal */\n+\t\t\t\t\tc \u003d (unsigned char)ctx-\u003euni;\n+\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_STRING;\n+\t\t\t\tgoto emit_string_char;\n+\t\t\tdefault:\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase LEJP_MP_DELIM:\n+\t\t\tif (c !\u003d ':') {\n+\t\t\t\tret \u003d LEJP_REJECT_MP_DELIM_MISSING_COLON;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE;\n+\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n+\n+\t\t\tlejp_check_path_match(ctx);\n+\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_PAIR_NAME)) {\n+\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase LEJP_MP_VALUE:\n+\t\t\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9') {\n+\t\t\t\tctx-\u003enpos \u003d 0;\n+\t\t\t\tctx-\u003edcount \u003d 0;\n+\t\t\t\tctx-\u003ef \u003d 0;\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_NUM_INT;\n+\t\t\t\tgoto redo_character;\n+\t\t\t}\n+\t\t\tswitch (c) {\n+\t\t\tcase'\u005c\u0022':\n+\t\t\t\t/* push */\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n+\t\t\t\tc \u003d LEJP_MP_STRING;\n+\t\t\t\tctx-\u003enpos \u003d 0;\n+\t\t\t\tctx-\u003ebuf[0] \u003d '\u005c0';\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_STR_START)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tgoto add_stack_level;\n+\n+\t\t\tcase '{':\n+\t\t\t\t/* push */\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n+\t\t\t\tc \u003d LEJP_MEMBERS;\n+\t\t\t\tlejp_check_path_match(ctx);\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_OBJECT_START)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tctx-\u003epath_match \u003d 0;\n+\t\t\t\tgoto add_stack_level;\n+\n+\t\t\tcase '[':\n+\t\t\t\t/* push */\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_ARRAY_END;\n+\t\t\t\tc \u003d LEJP_MP_VALUE;\n+\t\t\t\tctx-\u003epath[ctx-\u003eppos++] \u003d '[';\n+\t\t\t\tctx-\u003epath[ctx-\u003eppos++] \u003d ']';\n+\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_ARRAY_START)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tctx-\u003ei[ctx-\u003eipos++] \u003d 0;\n+\t\t\t\tif (ctx-\u003eipos \u003e ARRAY_SIZE(ctx-\u003ei)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_MP_DELIM_ISTACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tgoto add_stack_level;\n+\n+\t\t\tcase 't': /* true */\n+\t\t\t\tctx-\u003euni \u003d 0;\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_TOK;\n+\t\t\t\tbreak;\n+\n+\t\t\tcase 'f':\n+\t\t\t\tctx-\u003euni \u003d 4;\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_TOK;\n+\t\t\t\tbreak;\n+\n+\t\t\tcase 'n':\n+\t\t\t\tctx-\u003euni \u003d 4 + 5;\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_TOK;\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tret \u003d LEJP_REJECT_MP_DELIM_BAD_VALUE_START;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase LEJP_MP_VALUE_NUM_INT:\n+\t\t\tif (!ctx-\u003enpos \u0026\u0026 c \u003d\u003d '-') {\n+\t\t\t\tctx-\u003ef |\u003d LEJP_SEEN_MINUS;\n+\t\t\t\tgoto append_npos;\n+\t\t\t}\n+\n+\t\t\tif (ctx-\u003edcount \u003c 10 \u0026\u0026 c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9') {\n+\t\t\t\tif (ctx-\u003ef \u0026 LEJP_SEEN_POINT)\n+\t\t\t\t\tctx-\u003ef |\u003d LEJP_SEEN_POST_POINT;\n+\t\t\t\tctx-\u003edcount++;\n+\t\t\t\tgoto append_npos;\n+\t\t\t}\n+\t\t\tif (c \u003d\u003d '.') {\n+\t\t\t\tif (ctx-\u003edcount || (ctx-\u003ef \u0026 LEJP_SEEN_POINT)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_FORMAT;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tctx-\u003ef |\u003d LEJP_SEEN_POINT;\n+\t\t\t\tgoto append_npos;\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t * before exponent, if we had . we must have had at\n+\t\t\t * least one more digit\n+\t\t\t */\n+\t\t\tif ((ctx-\u003ef \u0026\n+\t\t\t\t(LEJP_SEEN_POINT | LEJP_SEEN_POST_POINT)) \u003d\u003d\n+\t\t\t\t\t\t\t LEJP_SEEN_POINT) {\n+\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\tif (c \u003d\u003d 'e' || c \u003d\u003d 'E') {\n+\t\t\t\tif (ctx-\u003ef \u0026 LEJP_SEEN_EXP) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_FORMAT;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tctx-\u003ef |\u003d LEJP_SEEN_EXP;\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_NUM_EXP;\n+\t\t\t\tgoto append_npos;\n+\t\t\t}\n+\t\t\t/* if none of the above, did we even have a number? */\n+\t\t\tif (!ctx-\u003edcount) {\n+\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_FORMAT;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\n+\t\t\tctx-\u003ebuf[ctx-\u003enpos] \u003d '\u005c0';\n+\t\t\tif (ctx-\u003ef \u0026 LEJP_SEEN_POINT) {\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_NUM_FLOAT)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_NUM_INT)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\t/* then this is the post-number character, loop */\n+\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n+\t\t\tgoto redo_character;\n+\n+\t\tcase LEJP_MP_VALUE_NUM_EXP:\n+\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE_NUM_INT;\n+\t\t\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')\n+\t\t\t\tgoto redo_character;\n+\t\t\tif (c \u003d\u003d '+' || c \u003d\u003d '-')\n+\t\t\t\tgoto append_npos;\n+\t\t\tret \u003d LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP;\n+\t\t\tgoto reject;\n+\n+\t\tcase LEJP_MP_VALUE_TOK: /* true, false, null */\n+\t\t\tif (c !\u003d tokens[ctx-\u003euni]) {\n+\t\t\t\tret \u003d LEJP_REJECT_MP_VAL_TOK_UNKNOWN;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\t\t\tctx-\u003euni++;\n+\t\t\tif (tokens[ctx-\u003euni] !\u003d ' ')\n+\t\t\t\tbreak;\n+\t\t\tswitch (ctx-\u003euni) {\n+\t\t\tcase 3:\n+\t\t\t\tctx-\u003ebuf[0] \u003d '1';\n+\t\t\t\tctx-\u003ebuf[1] \u003d '\u005c0';\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_TRUE)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\tcase 8:\n+\t\t\t\tctx-\u003ebuf[0] \u003d '0';\n+\t\t\t\tctx-\u003ebuf[1] \u003d '\u005c0';\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_FALSE)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\tcase 12:\n+\t\t\t\tctx-\u003ebuf[0] \u003d '\u005c0';\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_NULL)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n+\t\t\tbreak;\n+\n+\t\tcase LEJP_MP_COMMA_OR_END:\n+\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n+\t\t\tif (c \u003d\u003d ',') {\n+\t\t\t\t/* increment this stack level's index */\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_M_P;\n+\t\t\t\tif (!ctx-\u003esp) {\n+\t\t\t\t\tctx-\u003eppos \u003d 0;\n+\t\t\t\t\t/*\n+\t\t\t\t\t * since we came back to root level,\n+\t\t\t\t\t * no path can still match\n+\t\t\t\t\t */\n+\t\t\t\t\tctx-\u003epath_match \u003d 0;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\tctx-\u003eppos \u003d ctx-\u003est[ctx-\u003esp - 1].p;\n+\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n+\t\t\t\tif (ctx-\u003epath_match \u0026\u0026\n+\t\t\t\t\t ctx-\u003eppos \u003c\u003d ctx-\u003epath_match_len)\n+\t\t\t\t\t/*\n+\t\t\t\t\t * we shrank the path to be\n+\t\t\t\t\t * smaller than the matching point\n+\t\t\t\t\t */\n+\t\t\t\t\tctx-\u003epath_match \u003d 0;\n+\n+\t\t\t\tif (ctx-\u003est[ctx-\u003esp - 1].s !\u003d LEJP_MP_ARRAY_END)\n+\t\t\t\t\tbreak;\n+\t\t\t\t/* top level is definitely an array... */\n+\t\t\t\tif (ctx-\u003eipos)\n+\t\t\t\t\tctx-\u003ei[ctx-\u003eipos - 1]++;\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (c \u003d\u003d ']') {\n+\t\t\t\tif (!ctx-\u003esp) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_MP_C_OR_E_UNDERF;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\t/* pop */\n+\t\t\t\tctx-\u003esp--;\n+\t\t\t\tif (ctx-\u003est[ctx-\u003esp].s !\u003d LEJP_MP_ARRAY_END) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_MP_C_OR_E_NOTARRAY;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\t/* drop the path [n] bit */\n+\t\t\t\tctx-\u003eppos \u003d ctx-\u003est[ctx-\u003esp - 1].p;\n+\t\t\t\tctx-\u003eipos \u003d ctx-\u003est[ctx-\u003esp - 1].i;\n+\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n+\t\t\t\tif (ctx-\u003epath_match \u0026\u0026\n+\t\t\t\t\t ctx-\u003eppos \u003c\u003d ctx-\u003epath_match_len)\n+\t\t\t\t\t/*\n+\t\t\t\t\t * we shrank the path to be\n+\t\t\t\t\t * smaller than the matching point\n+\t\t\t\t\t */\n+\t\t\t\t\tctx-\u003epath_match \u003d 0;\n+\n+\t\t\t\t/* do LEJP_MP_ARRAY_END processing */\n+\t\t\t\tgoto redo_character;\n+\t\t\t}\n+\t\t\tif (c \u003d\u003d '}') {\n+\t\t\t\tif (ctx-\u003esp \u003d\u003d 0) {\n+\t\t\t\t\tlejp_check_path_match(ctx);\n+\t\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_OBJECT_END)) {\n+\t\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\t\tgoto reject;\n+\t\t\t\t\t}\n+\t\t\t\t\tctx-\u003ecallback(ctx, LEJPCB_COMPLETE);\n+\t\t\t\t\t/* done, return unused amount */\n+\t\t\t\t\treturn len;\n+\t\t\t\t}\n+\t\t\t\t/* pop */\n+\t\t\t\tctx-\u003esp--;\n+\t\t\t\tctx-\u003eppos \u003d ctx-\u003est[ctx-\u003esp - 1].p;\n+\t\t\t\tctx-\u003eipos \u003d ctx-\u003est[ctx-\u003esp - 1].i;\n+\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n+\t\t\t\tif (ctx-\u003epath_match \u0026\u0026\n+\t\t\t\t\t ctx-\u003eppos \u003c\u003d ctx-\u003epath_match_len)\n+\t\t\t\t\t/*\n+\t\t\t\t\t * we shrank the path to be\n+\t\t\t\t\t * smaller than the matching point\n+\t\t\t\t\t */\n+\t\t\t\t\tctx-\u003epath_match \u003d 0;\n+\t\t\t\tlejp_check_path_match(ctx);\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_OBJECT_END)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tret \u003d LEJP_REJECT_MP_C_OR_E_NEITHER;\n+\t\t\tgoto reject;\n+\n+\t\tcase LEJP_MP_ARRAY_END:\n+\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n+\t\t\tif (c \u003d\u003d ',') {\n+\t\t\t\t/* increment this stack level's index */\n+\t\t\t\tif (ctx-\u003eipos)\n+\t\t\t\t\tctx-\u003ei[ctx-\u003eipos - 1]++;\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_VALUE;\n+\t\t\t\tif (ctx-\u003esp)\n+\t\t\t\t\tctx-\u003eppos \u003d ctx-\u003est[ctx-\u003esp - 1].p;\n+\t\t\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (c !\u003d ']') {\n+\t\t\t\tret \u003d LEJP_REJECT_MP_ARRAY_END_MISSING;\n+\t\t\t\tgoto reject;\n+\t\t\t}\n+\n+\t\t\tctx-\u003est[ctx-\u003esp].s \u003d LEJP_MP_COMMA_OR_END;\n+\t\t\tctx-\u003ecallback(ctx, LEJPCB_ARRAY_END);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tcontinue;\n+\n+emit_string_char:\n+\t\tif (!ctx-\u003esp || ctx-\u003est[ctx-\u003esp - 1].s !\u003d LEJP_MP_DELIM) {\n+\t\t\t/* assemble the string value into chunks */\n+\t\t\tctx-\u003ebuf[ctx-\u003enpos++] \u003d c;\n+\t\t\tif (ctx-\u003enpos \u003d\u003d sizeof(ctx-\u003ebuf) - 1) {\n+\t\t\t\tif (ctx-\u003ecallback(ctx, LEJPCB_VAL_STR_CHUNK)) {\n+\t\t\t\t\tret \u003d LEJP_REJECT_CALLBACK;\n+\t\t\t\t\tgoto reject;\n+\t\t\t\t}\n+\t\t\t\tctx-\u003enpos \u003d 0;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\t\t/* name part of name:value pair */\n+\t\tctx-\u003epath[ctx-\u003eppos++] \u003d c;\n+\t\tcontinue;\n+\n+add_stack_level:\n+\t\t/* push on to the object stack */\n+\t\tif (ctx-\u003eppos \u0026\u0026 ctx-\u003est[ctx-\u003esp].s !\u003d LEJP_MP_COMMA_OR_END \u0026\u0026\n+\t\t\t\tctx-\u003est[ctx-\u003esp].s !\u003d LEJP_MP_ARRAY_END)\n+\t\t\tctx-\u003epath[ctx-\u003eppos++] \u003d '.';\n+\n+\t\tctx-\u003est[ctx-\u003esp].p \u003d ctx-\u003eppos;\n+\t\tctx-\u003est[ctx-\u003esp].i \u003d ctx-\u003eipos;\n+\t\tif (++ctx-\u003esp \u003d\u003d ARRAY_SIZE(ctx-\u003est)) {\n+\t\t\tret \u003d LEJP_REJECT_STACK_OVERFLOW;\n+\t\t\tgoto reject;\n+\t\t}\n+\t\tctx-\u003epath[ctx-\u003eppos] \u003d '\u005c0';\n+\t\tctx-\u003est[ctx-\u003esp].s \u003d c;\n+\t\tctx-\u003est[ctx-\u003esp].b \u003d 0;\n+\t\tcontinue;\n+\n+append_npos:\n+\t\tif (ctx-\u003enpos \u003e\u003d sizeof(ctx-\u003ebuf)) {\n+\t\t\tret \u003d LEJP_REJECT_NUM_TOO_LONG;\n+\t\t\tgoto reject;\n+\t\t}\n+\t\tctx-\u003ebuf[ctx-\u003enpos++] \u003d c;\n+\t\tcontinue;\n+\n+redo_character:\n+\t\tjson--;\n+\t\tlen++;\n+\t}\n+\n+\treturn LEJP_CONTINUE;\n+\n+reject:\n+\tctx-\u003ecallback(ctx, LEJPCB_FAILED);\n+\treturn ret;\n+}\ndiff --git a/lib/misc/lejp.h b/lib/misc/lejp.h\nnew file mode 100644\nindex 0000000..7bf7ba7\n--- /dev/null\n+++ b/lib/misc/lejp.h\n@@ -0,0 +1,232 @@\n+#include \u0022libwebsockets.h\u0022\n+struct lejp_ctx;\n+\n+#ifndef ARRAY_SIZE\n+#define ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0]))\n+#endif\n+#define LEJP_FLAG_WS_KEEP 64\n+#define LEJP_FLAG_WS_COMMENTLINE 32\n+\n+enum lejp_states {\n+\tLEJP_IDLE \u003d 0,\n+\tLEJP_MEMBERS \u003d 1,\n+\tLEJP_M_P \u003d 2,\n+\tLEJP_MP_STRING \u003d LEJP_FLAG_WS_KEEP | 3,\n+\tLEJP_MP_STRING_ESC \u003d LEJP_FLAG_WS_KEEP | 4,\n+\tLEJP_MP_STRING_ESC_U1 \u003d LEJP_FLAG_WS_KEEP | 5,\n+\tLEJP_MP_STRING_ESC_U2 \u003d LEJP_FLAG_WS_KEEP | 6,\n+\tLEJP_MP_STRING_ESC_U3 \u003d LEJP_FLAG_WS_KEEP | 7,\n+\tLEJP_MP_STRING_ESC_U4 \u003d LEJP_FLAG_WS_KEEP | 8,\n+\tLEJP_MP_DELIM \u003d 9,\n+\tLEJP_MP_VALUE \u003d 10,\n+\tLEJP_MP_VALUE_NUM_INT \u003d LEJP_FLAG_WS_KEEP | 11,\n+\tLEJP_MP_VALUE_NUM_EXP \u003d LEJP_FLAG_WS_KEEP | 12,\n+\tLEJP_MP_VALUE_TOK \u003d LEJP_FLAG_WS_KEEP | 13,\n+\tLEJP_MP_COMMA_OR_END \u003d 14,\n+\tLEJP_MP_ARRAY_END \u003d 15,\n+};\n+\n+enum lejp_reasons {\n+\tLEJP_CONTINUE \u003d -1,\n+\tLEJP_REJECT_IDLE_NO_BRACE \u003d -2,\n+\tLEJP_REJECT_MEMBERS_NO_CLOSE \u003d -3,\n+\tLEJP_REJECT_MP_NO_OPEN_QUOTE \u003d -4,\n+\tLEJP_REJECT_MP_STRING_UNDERRUN \u003d -5,\n+\tLEJP_REJECT_MP_ILLEGAL_CTRL \u003d -6,\n+\tLEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC \u003d -7,\n+\tLEJP_REJECT_ILLEGAL_HEX \u003d -8,\n+\tLEJP_REJECT_MP_DELIM_MISSING_COLON \u003d -9,\n+\tLEJP_REJECT_MP_DELIM_BAD_VALUE_START \u003d -10,\n+\tLEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC \u003d -11,\n+\tLEJP_REJECT_MP_VAL_NUM_FORMAT \u003d -12,\n+\tLEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP \u003d -13,\n+\tLEJP_REJECT_MP_VAL_TOK_UNKNOWN \u003d -14,\n+\tLEJP_REJECT_MP_C_OR_E_UNDERF \u003d -15,\n+\tLEJP_REJECT_MP_C_OR_E_NOTARRAY \u003d -16,\n+\tLEJP_REJECT_MP_ARRAY_END_MISSING \u003d -17,\n+\tLEJP_REJECT_STACK_OVERFLOW \u003d -18,\n+\tLEJP_REJECT_MP_DELIM_ISTACK \u003d -19,\n+\tLEJP_REJECT_NUM_TOO_LONG \u003d -20,\n+\tLEJP_REJECT_MP_C_OR_E_NEITHER \u003d -21,\n+\tLEJP_REJECT_UNKNOWN \u003d -22,\n+\tLEJP_REJECT_CALLBACK \u003d -23\n+};\n+\n+#define LEJP_FLAG_CB_IS_VALUE 64\n+\n+enum lejp_callbacks {\n+\tLEJPCB_CONSTRUCTED\t\u003d 0,\n+\tLEJPCB_DESTRUCTED\t\u003d 1,\n+\n+\tLEJPCB_START\t\t\u003d 2,\n+\tLEJPCB_COMPLETE\t\t\u003d 3,\n+\tLEJPCB_FAILED\t\t\u003d 4,\n+\n+\tLEJPCB_PAIR_NAME\t\u003d 5,\n+\n+\tLEJPCB_VAL_TRUE\t\t\u003d LEJP_FLAG_CB_IS_VALUE | 6,\n+\tLEJPCB_VAL_FALSE\t\u003d LEJP_FLAG_CB_IS_VALUE | 7,\n+\tLEJPCB_VAL_NULL\t\t\u003d LEJP_FLAG_CB_IS_VALUE | 8,\n+\tLEJPCB_VAL_NUM_INT\t\u003d LEJP_FLAG_CB_IS_VALUE | 9,\n+\tLEJPCB_VAL_NUM_FLOAT\t\u003d LEJP_FLAG_CB_IS_VALUE | 10,\n+\tLEJPCB_VAL_STR_START\t\u003d 11, /* notice handle separately */\n+\tLEJPCB_VAL_STR_CHUNK\t\u003d LEJP_FLAG_CB_IS_VALUE | 12,\n+\tLEJPCB_VAL_STR_END\t\u003d LEJP_FLAG_CB_IS_VALUE | 13,\n+\n+\tLEJPCB_ARRAY_START\t\u003d 14,\n+\tLEJPCB_ARRAY_END\t\u003d 15,\n+\n+\tLEJPCB_OBJECT_START\t\u003d 16,\n+\tLEJPCB_OBJECT_END\t\u003d 17\n+};\n+\n+/**\n+ * _lejp_callback() - User parser actions\n+ * \u005cparam ctx:\tLEJP context\n+ * \u005cparam reason:\tCallback reason\n+ *\n+ *\tYour user callback is associated with the context at construction time,\n+ *\tand receives calls as the parsing progresses.\n+ *\n+ *\tAll of the callbacks may be ignored and just return 0.\n+ *\n+ *\tThe reasons it might get called, found in @reason, are:\n+ *\n+ * LEJPCB_CONSTRUCTED: The context was just constructed... you might want to\n+ *\t\tperform one-time allocation for the life of the context.\n+ *\n+ * LEJPCB_DESTRUCTED:\tThe context is being destructed... if you made any\n+ *\t\tallocations at construction-time, you can free them now\n+ *\n+ * LEJPCB_START:\tParsing is beginning at the first byte of input\n+ *\n+ * LEJPCB_COMPLETE:\tParsing has completed successfully. You'll get a 0 or\n+ *\t\t\tpositive return code from lejp_parse indicating the\n+ *\t\t\tamount of unused bytes left in the input buffer\n+ *\n+ * LEJPCB_FAILED:\tParsing failed. You'll get a negative error code\n+ * \t\t\treturned from lejp_parse\n+ *\n+ * LEJPCB_PAIR_NAME:\tWhen a \u0022name\u0022:\u0022value\u0022 pair has had the name parsed,\n+ *\t\t\tthis callback occurs. You can find the new name at\n+ *\t\t\tthe end of ctx-\u003epath[]\n+ *\n+ * LEJPCB_VAL_TRUE:\tThe \u0022true\u0022 value appeared\n+ *\n+ * LEJPCB_VAL_FALSE:\tThe \u0022false\u0022 value appeared\n+ *\n+ * LEJPCB_VAL_NULL:\tThe \u0022null\u0022 value appeared\n+ *\n+ * LEJPCB_VAL_NUM_INT:\tA string representing an integer is in ctx-\u003ebuf\n+ *\n+ * LEJPCB_VAL_NUM_FLOAT: A string representing a float is in ctx-\u003ebuf\n+ *\n+ * LEJPCB_VAL_STR_START: We are starting to parse a string, no data yet\n+ *\n+ * LEJPCB_VAL_STR_CHUNK: We parsed LEJP_STRING_CHUNK -1 bytes of string data in\n+ *\t\t\tctx-\u003ebuf, which is as much as we can buffer, so we are\n+ *\t\t\tspilling it. If all your strings are less than\n+ *\t\t\tLEJP_STRING_CHUNK - 1 bytes, you will never see this\n+ *\t\t\tcallback.\n+ *\n+ * LEJPCB_VAL_STR_END:\tString parsing has completed, the last chunk of the\n+ *\t\t\tstring is in ctx-\u003ebuf.\n+ *\n+ * LEJPCB_ARRAY_START:\tAn array started\n+ *\n+ * LEJPCB_ARRAY_END:\tAn array ended\n+ *\n+ * LEJPCB_OBJECT_START: An object started\n+ *\n+ * LEJPCB_OBJECT_END:\tAn object ended\n+ */\n+LWS_EXTERN char _lejp_callback(struct lejp_ctx *ctx, char reason);\n+\n+typedef char (*lejp_callback)(struct lejp_ctx *ctx, char reason);\n+\n+#ifndef LEJP_MAX_DEPTH\n+#define LEJP_MAX_DEPTH 12\n+#endif\n+#ifndef LEJP_MAX_INDEX_DEPTH\n+#define LEJP_MAX_INDEX_DEPTH 5\n+#endif\n+#ifndef LEJP_MAX_PATH\n+#define LEJP_MAX_PATH 128\n+#endif\n+#ifndef LEJP_STRING_CHUNK\n+/* must be \u003e\u003d 30 to assemble floats */\n+#define LEJP_STRING_CHUNK 255\n+#endif\n+\n+enum num_flags {\n+\tLEJP_SEEN_MINUS \u003d (1 \u003c\u003c 0),\n+\tLEJP_SEEN_POINT \u003d (1 \u003c\u003c 1),\n+\tLEJP_SEEN_POST_POINT \u003d (1 \u003c\u003c 2),\n+\tLEJP_SEEN_EXP \u003d (1 \u003c\u003c 3)\n+};\n+\n+struct _lejp_stack {\n+\tchar s; /* lejp_state stack*/\n+\tchar p;\t/* path length */\n+\tchar i; /* index array length */\n+\tchar b; /* user bitfield */\n+};\n+\n+struct lejp_ctx {\n+\n+\t/* sorted by type for most compact alignment\n+\t *\n+\t * pointers\n+\t */\n+\n+\tchar (*callback)(struct lejp_ctx *ctx, char reason);\n+\tvoid *user;\n+\tconst char * const *paths;\n+\n+\t/* arrays */\n+\n+\tstruct _lejp_stack st[LEJP_MAX_DEPTH];\n+\tunsigned short i[LEJP_MAX_INDEX_DEPTH]; /* index array */\n+\tunsigned short wild[LEJP_MAX_INDEX_DEPTH]; /* index array */\n+\tchar path[LEJP_MAX_PATH];\n+\tchar buf[LEJP_STRING_CHUNK];\n+\n+\t/* int */\n+\n+\tunsigned int line;\n+\n+\t/* short */\n+\n+\tunsigned short uni;\n+\n+\t/* char */\n+\n+\tunsigned char npos;\n+\tunsigned char dcount;\n+\tunsigned char f;\n+\tunsigned char sp; /* stack head */\n+\tunsigned char ipos; /* index stack depth */\n+\tunsigned char ppos;\n+\tunsigned char count_paths;\n+\tunsigned char path_match;\n+\tunsigned char path_match_len;\n+\tunsigned char wildcount;\n+};\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lejp_construct(struct lejp_ctx *ctx,\n+\t char (*callback)(struct lejp_ctx *ctx, char reason), void *user,\n+\t const char * const *paths, unsigned char paths_count);\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lejp_destruct(struct lejp_ctx *ctx);\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len);\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lejp_change_callback(struct lejp_ctx *ctx,\n+\t\t char (*callback)(struct lejp_ctx *ctx, char reason));\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len);\ndiff --git a/lib/misc/lws-genhash.c b/lib/misc/lws-genhash.c\nnew file mode 100644\nindex 0000000..26bdb31\n--- /dev/null\n+++ b/lib/misc/lws-genhash.c\n@@ -0,0 +1,149 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ *\n+ * lws_genhash provides a hash abstraction api in lws that works the same\n+ * whether you are using openssl or mbedtls hash functions underneath.\n+ */\n+#include \u0022libwebsockets.h\u0022\n+\n+size_t\n+lws_genhash_size(int type)\n+{\n+\tswitch(type) {\n+\tcase LWS_GENHASH_TYPE_SHA1:\n+\t\treturn 20;\n+\tcase LWS_GENHASH_TYPE_SHA256:\n+\t\treturn 32;\n+\tcase LWS_GENHASH_TYPE_SHA512:\n+\t\treturn 64;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_genhash_init(struct lws_genhash_ctx *ctx, int type)\n+{\n+\tctx-\u003etype \u003d type;\n+\n+#if defined(LWS_WITH_MBEDTLS)\n+\tswitch (ctx-\u003etype) {\n+\tcase LWS_GENHASH_TYPE_SHA1:\n+\t\tmbedtls_sha1_init(\u0026ctx-\u003eu.sha1);\n+\t\tmbedtls_sha1_starts(\u0026ctx-\u003eu.sha1);\n+\t\tbreak;\n+\tcase LWS_GENHASH_TYPE_SHA256:\n+\t\tmbedtls_sha256_init(\u0026ctx-\u003eu.sha256);\n+\t\tmbedtls_sha256_starts(\u0026ctx-\u003eu.sha256, 0);\n+\t\tbreak;\n+\tcase LWS_GENHASH_TYPE_SHA512:\n+\t\tmbedtls_sha512_init(\u0026ctx-\u003eu.sha512);\n+\t\tmbedtls_sha512_starts(\u0026ctx-\u003eu.sha512, 0);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn 1;\n+\t}\n+#else\n+\tctx-\u003emdctx \u003d EVP_MD_CTX_create();\n+\tif (!ctx-\u003emdctx)\n+\t\treturn 1;\n+\n+\tswitch (ctx-\u003etype) {\n+\tcase LWS_GENHASH_TYPE_SHA1:\n+\t\tctx-\u003eevp_type \u003d EVP_sha1();\n+\t\tbreak;\n+\tcase LWS_GENHASH_TYPE_SHA256:\n+\t\tctx-\u003eevp_type \u003d EVP_sha256();\n+\t\tbreak;\n+\tcase LWS_GENHASH_TYPE_SHA512:\n+\t\tctx-\u003eevp_type \u003d EVP_sha512();\n+\t\tbreak;\n+\tdefault:\n+\t\treturn 1;\n+\t}\n+\n+\tif (EVP_DigestInit_ex(ctx-\u003emdctx, ctx-\u003eevp_type, NULL) !\u003d 1) {\n+\t\tEVP_MD_CTX_destroy(ctx-\u003emdctx);\n+\n+\t\treturn 1;\n+\t}\n+\n+#endif\n+\treturn 0;\n+}\n+\n+int\n+lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len)\n+{\n+#if defined(LWS_WITH_MBEDTLS)\n+\tswitch (ctx-\u003etype) {\n+\tcase LWS_GENHASH_TYPE_SHA1:\n+\t\tmbedtls_sha1_update(\u0026ctx-\u003eu.sha1, in, len);\n+\t\tbreak;\n+\tcase LWS_GENHASH_TYPE_SHA256:\n+\t\tmbedtls_sha256_update(\u0026ctx-\u003eu.sha256, in, len);\n+\t\tbreak;\n+\tcase LWS_GENHASH_TYPE_SHA512:\n+\t\tmbedtls_sha512_update(\u0026ctx-\u003eu.sha512, in, len);\n+\t\tbreak;\n+\t}\n+#else\n+\treturn EVP_DigestUpdate(ctx-\u003emdctx, in, len) !\u003d 1;\n+#endif\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result)\n+{\n+#if defined(LWS_WITH_MBEDTLS)\n+\tswitch (ctx-\u003etype) {\n+\tcase LWS_GENHASH_TYPE_SHA1:\n+\t\tmbedtls_sha1_finish(\u0026ctx-\u003eu.sha1, result);\n+\t\tmbedtls_sha1_free(\u0026ctx-\u003eu.sha1);\n+\t\tbreak;\n+\tcase LWS_GENHASH_TYPE_SHA256:\n+\t\tmbedtls_sha256_finish(\u0026ctx-\u003eu.sha256, result);\n+\t\tmbedtls_sha256_free(\u0026ctx-\u003eu.sha256);\n+\t\tbreak;\n+\tcase LWS_GENHASH_TYPE_SHA512:\n+\t\tmbedtls_sha512_finish(\u0026ctx-\u003eu.sha512, result);\n+\t\tmbedtls_sha512_free(\u0026ctx-\u003eu.sha512);\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+#else\n+\tunsigned int len;\n+\tint ret \u003d 0;\n+\n+\tif (result)\n+\t\tret \u003d EVP_DigestFinal_ex(ctx-\u003emdctx, result, \u0026len) !\u003d 1;\n+\n+\t(void)len;\n+\n+\tEVP_MD_CTX_destroy(ctx-\u003emdctx);\n+\n+\treturn ret;\n+#endif\n+}\n+\n+\ndiff --git a/lib/misc/lws-ring.c b/lib/misc/lws-ring.c\nnew file mode 100644\nindex 0000000..c2f86ee\n--- /dev/null\n+++ b/lib/misc/lws-ring.c\n@@ -0,0 +1,280 @@\n+/*\n+ * libwebsockets - lws-ring multi-tail abstract ringbuffer api\n+ *\n+ * Copyright (C) 2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+LWS_VISIBLE LWS_EXTERN struct lws_ring *\n+lws_ring_create(size_t element_len, size_t count,\n+\t\tvoid (*destroy_element)(void *))\n+{\n+\tstruct lws_ring *ring \u003d lws_malloc(sizeof(*ring), \u0022ring create\u0022);\n+\n+\tif (!ring)\n+\t\treturn NULL;\n+\n+\tring-\u003ebuflen \u003d count * element_len;\n+\tring-\u003eelement_len \u003d element_len;\n+\tring-\u003ehead \u003d 0;\n+\tring-\u003eoldest_tail \u003d 0;\n+\tring-\u003edestroy_element \u003d destroy_element;\n+\n+\tring-\u003ebuf \u003d lws_malloc(ring-\u003ebuflen, \u0022ring buf\u0022);\n+\tif (!ring-\u003ebuf) {\n+\t\tlws_free(ring);\n+\n+\t\treturn NULL;\n+\t}\n+\n+\treturn ring;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lws_ring_destroy(struct lws_ring *ring)\n+{\n+\tif (ring-\u003edestroy_element)\n+\t\twhile (ring-\u003eoldest_tail !\u003d ring-\u003ehead) {\n+\t\t\tring-\u003edestroy_element((uint8_t *)ring-\u003ebuf +\n+\t\t\t\t\t ring-\u003eoldest_tail);\n+\t\t\tring-\u003eoldest_tail \u003d\n+\t\t\t\t(ring-\u003eoldest_tail + ring-\u003eelement_len) %\n+\t\t\t\tring-\u003ebuflen;\n+\t\t}\n+\tif (ring-\u003ebuf)\n+\t\tlws_free_set_NULL(ring-\u003ebuf);\n+\n+\tlws_free(ring);\n+}\n+\n+LWS_VISIBLE LWS_EXTERN size_t\n+lws_ring_get_count_free_elements(struct lws_ring *ring)\n+{\n+\tint f;\n+\n+\t/*\n+\t * possible ringbuf patterns\n+\t *\n+\t * h \u003d\u003d t\n+\t * |--------t***h---|\n+\t * |**h-----------t*|\n+\t * |t**************h|\n+\t * |*****ht*********|\n+\t */\n+\tif (ring-\u003ehead \u003d\u003d ring-\u003eoldest_tail)\n+\t\tf \u003d ring-\u003ebuflen - ring-\u003eelement_len;\n+\telse\n+\t\tif (ring-\u003ehead \u003c ring-\u003eoldest_tail)\n+\t\t\tf \u003d (ring-\u003eoldest_tail - ring-\u003ehead) -\n+\t\t\t ring-\u003eelement_len;\n+\t\telse\n+\t\t\tf \u003d (ring-\u003ebuflen - ring-\u003ehead) + ring-\u003eoldest_tail -\n+\t\t\t ring-\u003eelement_len;\n+\n+\tif (f \u003c 2)\n+\t\treturn 0;\n+\n+\treturn f / ring-\u003eelement_len;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN size_t\n+lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail)\n+{\tint f;\n+\n+\tif (!tail)\n+\t\ttail \u003d \u0026ring-\u003eoldest_tail;\n+\t/*\n+\t * possible ringbuf patterns\n+\t *\n+\t * h \u003d\u003d t\n+\t * |--------t***h---|\n+\t * |**h-----------t*|\n+\t * |t**************h|\n+\t * |*****ht*********|\n+\t */\n+\tif (ring-\u003ehead \u003d\u003d *tail)\n+\t\tf \u003d 0;\n+\telse\n+\t\tif (ring-\u003ehead \u003e *tail)\n+\t\t\tf \u003d (ring-\u003ehead - *tail);\n+\t\telse\n+\t\t\tf \u003d (ring-\u003ebuflen - *tail) + ring-\u003ehead;\n+\n+\treturn f / ring-\u003eelement_len;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,\n+\t\t\t\t size_t *bytes)\n+{\n+\tint n;\n+\n+\t/* n is how many bytes the whole fifo can take */\n+\tn \u003d lws_ring_get_count_free_elements(ring) * ring-\u003eelement_len;\n+\n+\tif (!n)\n+\t\treturn 1;\n+\n+\tif (ring-\u003ehead + n \u003e ring-\u003ebuflen) {\n+\t\t*start \u003d (void *)(((uint8_t *)ring-\u003ebuf) + ring-\u003ehead);\n+\t\t*bytes \u003d ring-\u003ebuflen - ring-\u003ehead;\n+\n+\t\treturn 0;\n+\t}\n+\n+\t*start \u003d (void *)(((uint8_t *)ring-\u003ebuf) + ring-\u003ehead);\n+\t*bytes \u003d n;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lws_ring_bump_head(struct lws_ring *ring, size_t bytes)\n+{\n+\tring-\u003ehead \u003d (ring-\u003ehead + bytes) % ring-\u003ebuflen;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN size_t\n+lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count)\n+{\n+\tconst uint8_t *osrc \u003d src;\n+\tint m, n;\n+\n+\t/* n is how many bytes the whole fifo can take */\n+\tn \u003d lws_ring_get_count_free_elements(ring) * ring-\u003eelement_len;\n+\n+\t/* restrict n to how much we want to insert */\n+\tif ((size_t)n \u003e max_count * ring-\u003eelement_len)\n+\t\tn \u003d max_count * ring-\u003eelement_len;\n+\n+\t/*\n+\t * n is legal to insert, but as an optimization we can cut the\n+\t * insert into one or two memcpys, depending on if it wraps\n+\t */\n+\tif (ring-\u003ehead + n \u003e ring-\u003ebuflen) {\n+\n+\t\t/*\n+\t\t * He does wrap. The first memcpy should take us up to\n+\t\t * the end of the buffer\n+\t\t */\n+\n+\t\tm \u003d ring-\u003ebuflen - ring-\u003ehead;\n+\t\tmemcpy(((uint8_t *)ring-\u003ebuf) + ring-\u003ehead, src, m);\n+\t\t/* we know it will wrap exactly back to zero */\n+\t\tring-\u003ehead \u003d 0;\n+\n+\t\t/* adapt the second memcpy for what we already did */\n+\n+\t\tsrc \u003d ((uint8_t *)src) + m;\n+\t\tn -\u003d m;\n+\t}\n+\n+\tmemcpy(((uint8_t *)ring-\u003ebuf) + ring-\u003ehead, src, n);\n+\tring-\u003ehead \u003d (ring-\u003ehead + n) % ring-\u003ebuflen;\n+\n+\treturn (((uint8_t *)src + n) - osrc) / ring-\u003eelement_len;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN size_t\n+lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,\n+\t\t size_t max_count)\n+{\n+\tuint8_t *odest \u003d dest;\n+\tvoid *orig_tail \u003d tail;\n+\tuint32_t fake_tail;\n+\tint m, n;\n+\n+\tif (!tail) {\n+\t\tfake_tail \u003d ring-\u003eoldest_tail;\n+\t\ttail \u003d \u0026fake_tail;\n+\t}\n+\n+\t/* n is how many bytes the whole fifo has for us */\n+\tn \u003d lws_ring_get_count_waiting_elements(ring, tail) * ring-\u003eelement_len;\n+\n+\t/* restrict n to how much we want to insert */\n+\tif ((size_t)n \u003e max_count * ring-\u003eelement_len)\n+\t\tn \u003d max_count * ring-\u003eelement_len;\n+\n+\tif (!dest) {\n+\t\t*tail \u003d ((*tail) + n) % ring-\u003ebuflen;\n+\t\tif (!orig_tail) /* single tail */\n+\t\t\tlws_ring_update_oldest_tail(ring, *tail);\n+\n+\t\treturn n / ring-\u003eelement_len;\n+\t}\n+\tif (*tail + n \u003e ring-\u003ebuflen) {\n+\n+\t\t/*\n+\t\t * He does wrap. The first memcpy should take us up to\n+\t\t * the end of the buffer\n+\t\t */\n+\n+\t\tm \u003d ring-\u003ebuflen - *tail;\n+\t\tmemcpy(dest, ((uint8_t *)ring-\u003ebuf) + *tail, m);\n+\t\t/* we know it will wrap exactly back to zero */\n+\t\t*tail \u003d 0;\n+\n+\t\t/* adapt the second memcpy for what we already did */\n+\n+\t\tdest \u003d ((uint8_t *)dest) + m;\n+\t\tn -\u003d m;\n+\t}\n+\n+\tmemcpy(dest, ((uint8_t *)ring-\u003ebuf) + *tail, n);\n+\n+\t*tail \u003d ((*tail) + n) % ring-\u003ebuflen;\n+\tif (!orig_tail) /* single tail */\n+\t\tlws_ring_update_oldest_tail(ring, *tail);\n+\n+\treturn (((uint8_t *)dest + n) - odest) / ring-\u003eelement_len;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN const void *\n+lws_ring_get_element(struct lws_ring *ring, uint32_t *tail)\n+{\n+\tif (!tail)\n+\t\ttail \u003d \u0026ring-\u003eoldest_tail;\n+\n+\tif (*tail \u003d\u003d ring-\u003ehead)\n+\t\treturn NULL;\n+\n+\treturn ((uint8_t *)ring-\u003ebuf) + *tail;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail)\n+{\n+\tif (!ring-\u003edestroy_element) {\n+\t\tring-\u003eoldest_tail \u003d tail;\n+\t\treturn;\n+\t}\n+\n+\twhile (ring-\u003eoldest_tail !\u003d tail) {\n+\t\tring-\u003edestroy_element((uint8_t *)ring-\u003ebuf + ring-\u003eoldest_tail);\n+\t\tring-\u003eoldest_tail \u003d (ring-\u003eoldest_tail + ring-\u003eelement_len) %\n+\t\t\t\t ring-\u003ebuflen;\n+\t}\n+}\n+\n+LWS_VISIBLE LWS_EXTERN uint32_t\n+lws_ring_get_oldest_tail(struct lws_ring *ring)\n+{\n+\treturn ring-\u003eoldest_tail;\n+}\ndiff --git a/lib/misc/romfs.c b/lib/misc/romfs.c\nnew file mode 100644\nindex 0000000..540382e\n--- /dev/null\n+++ b/lib/misc/romfs.c\n@@ -0,0 +1,224 @@\n+/*\n+ * Copyright (C) 2017 National Institute of Advanced Industrial Science\n+ * and Technology (AIST)\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ *\n+ * Redistributions of source code must retain the above copyright notice, this\n+ * list of conditions and the following disclaimer.\n+ *\n+ * Redistributions in binary form must reproduce the above copyright notice,\n+ * this list of conditions and the following disclaimer in the documentation\n+ * and/or other materials provided with the distribution.\n+ *\n+ * Neither the name of AIST nor the names of its contributors may be used\n+ * to endorse or promote products derived from this software without specific\n+ * prior written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \u0022AS IS\u0022\n+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n+ * POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include \u003cstring.h\u003e\n+#include \u003cstdint.h\u003e\n+#include \u003cstdio.h\u003e\n+#include \u0022romfs.h\u0022\n+#include \u0022esp_spi_flash.h\u0022\n+\n+#define RFS_STRING_MAX 96\n+\n+static u32_be_t cache[(RFS_STRING_MAX + 32) / 4];\n+static romfs_inode_t ci \u003d (romfs_inode_t)cache;\n+static romfs_t cr \u003d (romfs_t)cache;\n+\n+static void\n+set_cache(romfs_inode_t inode, size_t len)\n+{\n+\tspi_flash_read((uint32_t)inode, cache, len);\n+}\n+\n+static uint32_t\n+ntohl(const u32_be_t be)\n+{\n+\treturn ((be \u003e\u003e 24) \u0026 0xff) |\n+\t ((be \u003e\u003e 16) \u0026 0xff) \u003c\u003c 8 |\n+\t ((be \u003e\u003e 8) \u0026 0xff) \u003c\u003c 16 |\n+\t (be \u0026 0xff) \u003c\u003c 24;\n+}\n+static romfs_inode_t\n+romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path);\n+\n+static int\n+plus_padding(const uint8_t *s)\n+{\n+\tint n;\n+ \n+\tset_cache((romfs_inode_t)s, RFS_STRING_MAX);\n+\tn \u003d strlen((const char *)cache);\n+\n+\tif (!(n \u0026 15))\n+\t\tn +\u003d 0x10;\n+\n+\treturn (n + 15) \u0026 ~15;\n+}\n+\n+static romfs_inode_t\n+skip_and_pad(romfs_inode_t ri)\n+{\n+\tconst uint8_t *p \u003d ((const uint8_t *)ri) + sizeof(*ri);\n+\n+\treturn (romfs_inode_t)(p + plus_padding(p));\n+}\n+\n+size_t\n+romfs_mount_check(romfs_t romfs)\n+{\n+\tset_cache((romfs_inode_t)romfs, sizeof(*romfs));\n+\n+\tif (cr-\u003emagic1 !\u003d 0x6d6f722d ||\n+\t cr-\u003emagic2 !\u003d 0x2d736631)\n+\t\treturn 0;\n+\n+\treturn ntohl(cr-\u003esize);\n+}\n+\n+static romfs_inode_t\n+romfs_symlink(romfs_t romfs, romfs_inode_t level, romfs_inode_t i)\n+{\n+\tconst char *p \u003d (const char *)skip_and_pad(i);\n+\n+\tif (*p \u003d\u003d '/') {\n+\t\tlevel \u003d skip_and_pad((romfs_inode_t)romfs);\n+\t\tp++;\n+\t}\n+\n+\treturn romfs_lookup(romfs, level, p);\n+}\n+\n+static romfs_inode_t\n+dir_link(romfs_t romfs, romfs_inode_t i)\n+{\n+\tset_cache(i, sizeof(*i));\n+\treturn (romfs_inode_t)((const uint8_t *)romfs +\n+\t\t\t\t\t\tntohl(ci-\u003edir_start));\n+}\n+\n+static romfs_inode_t\n+romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)\n+{\n+\tromfs_inode_t level, i \u003d start, i_in;\n+\tconst char *p, *n, *cp;\n+\tuint32_t next_be;\n+\n+\tif (start \u003d\u003d (romfs_inode_t)romfs)\n+\t\ti \u003d skip_and_pad((romfs_inode_t)romfs);\n+\tlevel \u003d i;\n+\twhile (i !\u003d (romfs_inode_t)romfs) {\n+\t\tp \u003d path;\n+\t\tn \u003d ((const char *)i) + sizeof(*i);\n+\t\ti_in \u003d i;\n+\n+\t\tset_cache(i, sizeof(*i));\n+\t\tnext_be \u003d ci-\u003enext;\n+\n+\t\tcp \u003d (const char *)cache;\n+\t\tset_cache((romfs_inode_t)n, RFS_STRING_MAX);\n+\n+\t\twhile (*p \u0026\u0026 *p !\u003d '/' \u0026\u0026 *cp \u0026\u0026 *p \u003d\u003d *cp \u0026\u0026 (p - path) \u003c RFS_STRING_MAX) {\n+\t\t\tp++;\n+\t\t\tn++;\n+\t\t\tcp++;\n+\t\t}\n+\n+\t\tif (!*cp \u0026\u0026 (!*p || *p \u003d\u003d '/') \u0026\u0026\n+\t\t (ntohl(next_be) \u0026 7) \u003d\u003d RFST_HARDLINK) {\n+\t\t\tset_cache(i, sizeof(*i));\n+\t\t\treturn (romfs_inode_t)\n+\t\t\t ((const uint8_t *)romfs +\n+\t\t\t (ntohl(ci-\u003edir_start) \u0026 ~15));\n+\t\t}\n+\n+\t\tif (!*p \u0026\u0026 !*cp) {\n+\t\t\tset_cache(i, sizeof(*i));\n+\t\t\tif ((ntohl(ci-\u003enext) \u0026 7) \u003d\u003d RFST_SYMLINK) {\n+\t\t\t\ti \u003d romfs_symlink(romfs, level, i);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\treturn i;\n+\t\t}\n+\n+\t\tif (!*p \u0026\u0026 *cp \u003d\u003d '/')\n+\t\t\treturn NULL;\n+\n+\t\tif (*p \u003d\u003d '/' \u0026\u0026 !*cp) {\n+\t\t\tset_cache(i, sizeof(*i));\n+\t\t\tswitch (ntohl(ci-\u003enext) \u0026 7) {\n+\t\t\tcase RFST_SYMLINK:\n+\t\t\t\ti \u003d romfs_symlink(romfs, level, i);\n+\t\t\t\tif (!i)\n+\t\t\t\t\treturn NULL;\n+\t\t\t\ti \u003d dir_link(romfs, i);\n+\t\t\t\twhile (*path !\u003d '/' \u0026\u0026 *path)\n+\t\t\t\t\tpath++;\n+\t\t\t\tif (!*path)\n+\t\t\t\t\treturn NULL;\n+\t\t\t\tpath++;\n+\t\t\t\tcontinue;\n+\t\t\tcase RFST_DIR:\n+\t\t\t\tpath \u003d p + 1;\n+\t\t\t\ti \u003d dir_link(romfs, i);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tpath \u003d p + 1;\n+\t\t\t\ti \u003d skip_and_pad(i);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tlevel \u003d i;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tset_cache(i, sizeof(*i));\n+\t\tif (!(ntohl(ci-\u003enext) \u0026 ~15))\n+\t\t\treturn NULL;\n+\n+\t\ti \u003d (romfs_inode_t)((const uint8_t *)romfs +\n+\t\t\t\t (ntohl(ci-\u003enext) \u0026 ~15));\n+\t\tif (i \u003d\u003d i_in)\n+\t\t\treturn NULL;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+const void *\n+romfs_get_info(romfs_t romfs, const char *path, size_t *len, size_t *csum)\n+{\n+\tromfs_inode_t i;\n+ \n+\tif (*path \u003d\u003d '/')\n+\t\tpath++;\n+\n+\ti \u003d romfs_lookup(romfs, (romfs_inode_t)romfs, path);\n+\n+\tif (!i)\n+\t\treturn NULL;\n+\n+\tset_cache(i, sizeof(*i));\n+\t*len \u003d ntohl(ci-\u003esize);\n+\tif (csum)\n+\t\t*csum \u003d ntohl(ci-\u003echecksum);\n+\n+\treturn (void *)skip_and_pad(i);\n+}\ndiff --git a/lib/misc/romfs.h b/lib/misc/romfs.h\nnew file mode 100644\nindex 0000000..dab932b\n--- /dev/null\n+++ b/lib/misc/romfs.h\n@@ -0,0 +1,63 @@\n+/*\n+ * Copyright (C) 2017 National Institute of Advanced Industrial Science\n+ * and Technology (AIST)\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ *\n+ * Redistributions of source code must retain the above copyright notice, this\n+ * list of conditions and the following disclaimer.\n+ *\n+ * Redistributions in binary form must reproduce the above copyright notice,\n+ * this list of conditions and the following disclaimer in the documentation\n+ * and/or other materials provided with the distribution.\n+ *\n+ * Neither the name of AIST nor the names of its contributors may be used\n+ * to endorse or promote products derived from this software without specific\n+ * prior written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \u0022AS IS\u0022\n+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n+ * POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+typedef uint32_t u32_be_t;\n+\n+struct romfs_superblock {\n+\tu32_be_t magic1;\n+\tu32_be_t magic2;\n+\tu32_be_t size;\n+\tu32_be_t checksum;\n+};\n+\n+struct romfs_i {\n+\tu32_be_t next;\n+\tu32_be_t dir_start;\n+\tu32_be_t size;\n+\tu32_be_t checksum;\n+};\n+\n+enum {\n+\tRFST_HARDLINK\t\u003d 0,\n+\tRFST_DIR\t\u003d 1,\n+\tRFST_SYMLINK\t\u003d 3,\n+};\n+\n+typedef const struct romfs_i *romfs_inode_t;\n+typedef const struct romfs_superblock *romfs_t;\n+\n+const void *\n+romfs_get_info(romfs_t romfs, const char *path, size_t *len, size_t *csum);\n+size_t\n+romfs_mount_check(romfs_t romfs);\n+\ndiff --git a/lib/misc/sha-1.c b/lib/misc/sha-1.c\nnew file mode 100644\nindex 0000000..9353fbe\n--- /dev/null\n+++ b/lib/misc/sha-1.c\n@@ -0,0 +1,300 @@\n+/*\n+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions\n+ * are met:\n+ * 1. Redistributions of source code must retain the above copyright\n+ * notice, this list of conditions and the following disclaimer.\n+ * 2. Redistributions in binary form must reproduce the above copyright\n+ * notice, this list of conditions and the following disclaimer in the\n+ * documentation and/or other materials provided with the distribution.\n+ * 3. Neither the name of the project nor the names of its contributors\n+ * may be used to endorse or promote products derived from this software\n+ * without specific prior written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND\n+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE\n+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n+ * SUCH DAMAGE.\n+ */\n+/*\n+ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)\n+ * based on: http://csrc.nist.gov/fips/fip180-1.txt\n+ * implemented by Jun-ichiro itojun Itoh \u003citojun@itojun.org\u003e\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#ifdef LWS_HAVE_SYS_TYPES_H\n+#include \u003csys/types.h\u003e\n+#endif\n+\n+struct sha1_ctxt {\n+\tunion {\n+\t\tunsigned char\t\tb8[20];\n+\t\tunsigned int\t\tb32[5];\n+\t} h;\n+\tunion {\n+\t\tunsigned char\t\tb8[8];\n+\t\tu_int64_t\t\tb64[1];\n+\t} c;\n+\tunion {\n+\t\tunsigned char\t\tb8[64];\n+\t\tunsigned int\t\tb32[16];\n+\t} m;\n+\tunsigned char\t\t\tcount;\n+};\n+\n+/* sanity check */\n+#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)\n+# define unsupported 1\n+#elif BYTE_ORDER !\u003d BIG_ENDIAN\n+# if BYTE_ORDER !\u003d LITTLE_ENDIAN\n+# define unsupported 1\n+# endif\n+#endif\n+\n+#ifndef unsupported\n+\n+/* constant table */\n+static const unsigned int _K[] \u003d\n+\t\t\t{ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };\n+#define\tK(t)\t_K[(t) / 20]\n+\n+#define\tF0(b, c, d)\t(((b) \u0026 (c)) | ((~(b)) \u0026 (d)))\n+#define\tF1(b, c, d)\t(((b) ^ (c)) ^ (d))\n+#define\tF2(b, c, d)\t(((b) \u0026 (c)) | ((b) \u0026 (d)) | ((c) \u0026 (d)))\n+#define\tF3(b, c, d)\t(((b) ^ (c)) ^ (d))\n+\n+#define\tS(n, x)\t\t(((x) \u003c\u003c (n)) | ((x) \u003e\u003e (32 - n)))\n+\n+#define\tH(n)\t(ctxt-\u003eh.b32[(n)])\n+#define\tCOUNT\t(ctxt-\u003ecount)\n+#define\tBCOUNT\t(ctxt-\u003ec.b64[0] / 8)\n+#define\tW(n)\t(ctxt-\u003em.b32[(n)])\n+\n+#define\tPUTBYTE(x)\t{ \u005c\n+\tctxt-\u003em.b8[(COUNT % 64)] \u003d (x);\t\t\u005c\n+\tCOUNT++;\t\t\t\t\u005c\n+\tCOUNT %\u003d 64;\t\t\t\t\u005c\n+\tctxt-\u003ec.b64[0] +\u003d 8;\t\t\t\u005c\n+\tif (COUNT % 64 \u003d\u003d 0)\t\t\t\u005c\n+\t\tsha1_step(ctxt);\t\t\u005c\n+\t}\n+\n+#define\tPUTPAD(x)\t{ \u005c\n+\tctxt-\u003em.b8[(COUNT % 64)] \u003d (x);\t\t\u005c\n+\tCOUNT++;\t\t\t\t\u005c\n+\tCOUNT %\u003d 64;\t\t\t\t\u005c\n+\tif (COUNT % 64 \u003d\u003d 0)\t\t\t\u005c\n+\t\tsha1_step(ctxt);\t\t\u005c\n+\t}\n+\n+\n+static void\n+sha1_step(struct sha1_ctxt *ctxt)\n+{\n+\tunsigned int\ta, b, c, d, e, tmp;\n+\tsize_t t, s;\n+\n+#if BYTE_ORDER \u003d\u003d LITTLE_ENDIAN\n+\tstruct sha1_ctxt tctxt;\n+\n+\tmemcpy(\u0026tctxt.m.b8[0], \u0026ctxt-\u003em.b8[0], 64);\n+\tctxt-\u003em.b8[0] \u003d tctxt.m.b8[3]; ctxt-\u003em.b8[1] \u003d tctxt.m.b8[2];\n+\tctxt-\u003em.b8[2] \u003d tctxt.m.b8[1]; ctxt-\u003em.b8[3] \u003d tctxt.m.b8[0];\n+\tctxt-\u003em.b8[4] \u003d tctxt.m.b8[7]; ctxt-\u003em.b8[5] \u003d tctxt.m.b8[6];\n+\tctxt-\u003em.b8[6] \u003d tctxt.m.b8[5]; ctxt-\u003em.b8[7] \u003d tctxt.m.b8[4];\n+\tctxt-\u003em.b8[8] \u003d tctxt.m.b8[11]; ctxt-\u003em.b8[9] \u003d tctxt.m.b8[10];\n+\tctxt-\u003em.b8[10] \u003d tctxt.m.b8[9]; ctxt-\u003em.b8[11] \u003d tctxt.m.b8[8];\n+\tctxt-\u003em.b8[12] \u003d tctxt.m.b8[15]; ctxt-\u003em.b8[13] \u003d tctxt.m.b8[14];\n+\tctxt-\u003em.b8[14] \u003d tctxt.m.b8[13]; ctxt-\u003em.b8[15] \u003d tctxt.m.b8[12];\n+\tctxt-\u003em.b8[16] \u003d tctxt.m.b8[19]; ctxt-\u003em.b8[17] \u003d tctxt.m.b8[18];\n+\tctxt-\u003em.b8[18] \u003d tctxt.m.b8[17]; ctxt-\u003em.b8[19] \u003d tctxt.m.b8[16];\n+\tctxt-\u003em.b8[20] \u003d tctxt.m.b8[23]; ctxt-\u003em.b8[21] \u003d tctxt.m.b8[22];\n+\tctxt-\u003em.b8[22] \u003d tctxt.m.b8[21]; ctxt-\u003em.b8[23] \u003d tctxt.m.b8[20];\n+\tctxt-\u003em.b8[24] \u003d tctxt.m.b8[27]; ctxt-\u003em.b8[25] \u003d tctxt.m.b8[26];\n+\tctxt-\u003em.b8[26] \u003d tctxt.m.b8[25]; ctxt-\u003em.b8[27] \u003d tctxt.m.b8[24];\n+\tctxt-\u003em.b8[28] \u003d tctxt.m.b8[31]; ctxt-\u003em.b8[29] \u003d tctxt.m.b8[30];\n+\tctxt-\u003em.b8[30] \u003d tctxt.m.b8[29]; ctxt-\u003em.b8[31] \u003d tctxt.m.b8[28];\n+\tctxt-\u003em.b8[32] \u003d tctxt.m.b8[35]; ctxt-\u003em.b8[33] \u003d tctxt.m.b8[34];\n+\tctxt-\u003em.b8[34] \u003d tctxt.m.b8[33]; ctxt-\u003em.b8[35] \u003d tctxt.m.b8[32];\n+\tctxt-\u003em.b8[36] \u003d tctxt.m.b8[39]; ctxt-\u003em.b8[37] \u003d tctxt.m.b8[38];\n+\tctxt-\u003em.b8[38] \u003d tctxt.m.b8[37]; ctxt-\u003em.b8[39] \u003d tctxt.m.b8[36];\n+\tctxt-\u003em.b8[40] \u003d tctxt.m.b8[43]; ctxt-\u003em.b8[41] \u003d tctxt.m.b8[42];\n+\tctxt-\u003em.b8[42] \u003d tctxt.m.b8[41]; ctxt-\u003em.b8[43] \u003d tctxt.m.b8[40];\n+\tctxt-\u003em.b8[44] \u003d tctxt.m.b8[47]; ctxt-\u003em.b8[45] \u003d tctxt.m.b8[46];\n+\tctxt-\u003em.b8[46] \u003d tctxt.m.b8[45]; ctxt-\u003em.b8[47] \u003d tctxt.m.b8[44];\n+\tctxt-\u003em.b8[48] \u003d tctxt.m.b8[51]; ctxt-\u003em.b8[49] \u003d tctxt.m.b8[50];\n+\tctxt-\u003em.b8[50] \u003d tctxt.m.b8[49]; ctxt-\u003em.b8[51] \u003d tctxt.m.b8[48];\n+\tctxt-\u003em.b8[52] \u003d tctxt.m.b8[55]; ctxt-\u003em.b8[53] \u003d tctxt.m.b8[54];\n+\tctxt-\u003em.b8[54] \u003d tctxt.m.b8[53]; ctxt-\u003em.b8[55] \u003d tctxt.m.b8[52];\n+\tctxt-\u003em.b8[56] \u003d tctxt.m.b8[59]; ctxt-\u003em.b8[57] \u003d tctxt.m.b8[58];\n+\tctxt-\u003em.b8[58] \u003d tctxt.m.b8[57]; ctxt-\u003em.b8[59] \u003d tctxt.m.b8[56];\n+\tctxt-\u003em.b8[60] \u003d tctxt.m.b8[63]; ctxt-\u003em.b8[61] \u003d tctxt.m.b8[62];\n+\tctxt-\u003em.b8[62] \u003d tctxt.m.b8[61]; ctxt-\u003em.b8[63] \u003d tctxt.m.b8[60];\n+#endif\n+\n+\ta \u003d H(0); b \u003d H(1); c \u003d H(2); d \u003d H(3); e \u003d H(4);\n+\n+\tfor (t \u003d 0; t \u003c 20; t++) {\n+\t\ts \u003d t \u0026 0x0f;\n+\t\tif (t \u003e\u003d 16)\n+\t\t\tW(s) \u003d S(1, W((s+13) \u0026 0x0f) ^ W((s+8) \u0026 0x0f) ^\n+\t\t\t\t\t\t\tW((s+2) \u0026 0x0f) ^ W(s));\n+\n+\t\ttmp \u003d S(5, a) + F0(b, c, d) + e + W(s) + K(t);\n+\t\te \u003d d; d \u003d c; c \u003d S(30, b); b \u003d a; a \u003d tmp;\n+\t}\n+\tfor (t \u003d 20; t \u003c 40; t++) {\n+\t\ts \u003d t \u0026 0x0f;\n+\t\tW(s) \u003d S(1, W((s+13) \u0026 0x0f) ^ W((s+8) \u0026 0x0f) ^\n+\t\t\t\t\t\t\tW((s+2) \u0026 0x0f) ^ W(s));\n+\t\ttmp \u003d S(5, a) + F1(b, c, d) + e + W(s) + K(t);\n+\t\te \u003d d; d \u003d c; c \u003d S(30, b); b \u003d a; a \u003d tmp;\n+\t}\n+\tfor (t \u003d 40; t \u003c 60; t++) {\n+\t\ts \u003d t \u0026 0x0f;\n+\t\tW(s) \u003d S(1, W((s+13) \u0026 0x0f) ^ W((s+8) \u0026 0x0f) ^\n+\t\t\t\t\t\t\tW((s+2) \u0026 0x0f) ^ W(s));\n+\t\ttmp \u003d S(5, a) + F2(b, c, d) + e + W(s) + K(t);\n+\t\te \u003d d; d \u003d c; c \u003d S(30, b); b \u003d a; a \u003d tmp;\n+\t}\n+\tfor (t \u003d 60; t \u003c 80; t++) {\n+\t\ts \u003d t \u0026 0x0f;\n+\t\tW(s) \u003d S(1, W((s+13) \u0026 0x0f) ^ W((s+8) \u0026 0x0f) ^\n+\t\t\t\t\t\t\tW((s+2) \u0026 0x0f) ^ W(s));\n+\t\ttmp \u003d S(5, a) + F3(b, c, d) + e + W(s) + K(t);\n+\t\te \u003d d; d \u003d c; c \u003d S(30, b); b \u003d a; a \u003d tmp;\n+\t}\n+\n+\tH(0) \u003d H(0) + a;\n+\tH(1) \u003d H(1) + b;\n+\tH(2) \u003d H(2) + c;\n+\tH(3) \u003d H(3) + d;\n+\tH(4) \u003d H(4) + e;\n+\n+\tbzero(\u0026ctxt-\u003em.b8[0], 64);\n+}\n+\n+/*------------------------------------------------------------*/\n+\n+static void\n+_sha1_init(struct sha1_ctxt *ctxt)\n+{\n+\tbzero(ctxt, sizeof(struct sha1_ctxt));\n+\tH(0) \u003d 0x67452301;\n+\tH(1) \u003d 0xefcdab89;\n+\tH(2) \u003d 0x98badcfe;\n+\tH(3) \u003d 0x10325476;\n+\tH(4) \u003d 0xc3d2e1f0;\n+}\n+\n+void\n+sha1_pad(struct sha1_ctxt *ctxt)\n+{\n+\tsize_t padlen;\t\t/*pad length in bytes*/\n+\tsize_t padstart;\n+\n+\tPUTPAD(0x80);\n+\n+\tpadstart \u003d COUNT % 64;\n+\tpadlen \u003d 64 - padstart;\n+\tif (padlen \u003c 8) {\n+\t\tbzero(\u0026ctxt-\u003em.b8[padstart], padlen);\n+\t\tCOUNT +\u003d (unsigned char)padlen;\n+\t\tCOUNT %\u003d 64;\n+\t\tsha1_step(ctxt);\n+\t\tpadstart \u003d COUNT % 64;\t/* should be 0 */\n+\t\tpadlen \u003d 64 - padstart;\t/* should be 64 */\n+\t}\n+\tbzero(\u0026ctxt-\u003em.b8[padstart], padlen - 8);\n+\tCOUNT +\u003d ((unsigned char)padlen - 8);\n+\tCOUNT %\u003d 64;\n+#if BYTE_ORDER \u003d\u003d BIG_ENDIAN\n+\tPUTPAD(ctxt-\u003ec.b8[0]); PUTPAD(ctxt-\u003ec.b8[1]);\n+\tPUTPAD(ctxt-\u003ec.b8[2]); PUTPAD(ctxt-\u003ec.b8[3]);\n+\tPUTPAD(ctxt-\u003ec.b8[4]); PUTPAD(ctxt-\u003ec.b8[5]);\n+\tPUTPAD(ctxt-\u003ec.b8[6]); PUTPAD(ctxt-\u003ec.b8[7]);\n+#else\n+\tPUTPAD(ctxt-\u003ec.b8[7]); PUTPAD(ctxt-\u003ec.b8[6]);\n+\tPUTPAD(ctxt-\u003ec.b8[5]); PUTPAD(ctxt-\u003ec.b8[4]);\n+\tPUTPAD(ctxt-\u003ec.b8[3]); PUTPAD(ctxt-\u003ec.b8[2]);\n+\tPUTPAD(ctxt-\u003ec.b8[1]); PUTPAD(ctxt-\u003ec.b8[0]);\n+#endif\n+}\n+\n+void\n+sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len)\n+{\n+\tsize_t gaplen;\n+\tsize_t gapstart;\n+\tsize_t off;\n+\tsize_t copysiz;\n+\n+\toff \u003d 0;\n+\n+\twhile (off \u003c len) {\n+\t\tgapstart \u003d COUNT % 64;\n+\t\tgaplen \u003d 64 - gapstart;\n+\n+\t\tcopysiz \u003d (gaplen \u003c len - off) ? gaplen : len - off;\n+\t\tmemcpy(\u0026ctxt-\u003em.b8[gapstart], \u0026input[off], copysiz);\n+\t\tCOUNT +\u003d (unsigned char)copysiz;\n+\t\tCOUNT %\u003d 64;\n+\t\tctxt-\u003ec.b64[0] +\u003d copysiz * 8;\n+\t\tif (COUNT % 64 \u003d\u003d 0)\n+\t\t\tsha1_step(ctxt);\n+\t\toff +\u003d copysiz;\n+\t}\n+}\n+\n+void\n+sha1_result(struct sha1_ctxt *ctxt, void *digest0)\n+{\n+\tunsigned char *digest;\n+\n+\tdigest \u003d (unsigned char *)digest0;\n+\tsha1_pad(ctxt);\n+#if BYTE_ORDER \u003d\u003d BIG_ENDIAN\n+\tmemcpy(digest, \u0026ctxt-\u003eh.b8[0], 20);\n+#else\n+\tdigest[0] \u003d ctxt-\u003eh.b8[3]; digest[1] \u003d ctxt-\u003eh.b8[2];\n+\tdigest[2] \u003d ctxt-\u003eh.b8[1]; digest[3] \u003d ctxt-\u003eh.b8[0];\n+\tdigest[4] \u003d ctxt-\u003eh.b8[7]; digest[5] \u003d ctxt-\u003eh.b8[6];\n+\tdigest[6] \u003d ctxt-\u003eh.b8[5]; digest[7] \u003d ctxt-\u003eh.b8[4];\n+\tdigest[8] \u003d ctxt-\u003eh.b8[11]; digest[9] \u003d ctxt-\u003eh.b8[10];\n+\tdigest[10] \u003d ctxt-\u003eh.b8[9]; digest[11] \u003d ctxt-\u003eh.b8[8];\n+\tdigest[12] \u003d ctxt-\u003eh.b8[15]; digest[13] \u003d ctxt-\u003eh.b8[14];\n+\tdigest[14] \u003d ctxt-\u003eh.b8[13]; digest[15] \u003d ctxt-\u003eh.b8[12];\n+\tdigest[16] \u003d ctxt-\u003eh.b8[19]; digest[17] \u003d ctxt-\u003eh.b8[18];\n+\tdigest[18] \u003d ctxt-\u003eh.b8[17]; digest[19] \u003d ctxt-\u003eh.b8[16];\n+#endif\n+}\n+\n+/*\n+ * This should look and work like the libcrypto implementation\n+ */\n+\n+LWS_VISIBLE unsigned char *\n+lws_SHA1(const unsigned char *d, size_t n, unsigned char *md)\n+{\n+\tstruct sha1_ctxt ctx;\n+\n+\t_sha1_init(\u0026ctx);\n+\tsha1_loop(\u0026ctx, d, n);\n+\tsha1_result(\u0026ctx, (void *)md);\n+\n+\treturn md;\n+}\n+\n+#endif /*unsupported*/\ndiff --git a/lib/misc/smtp.c b/lib/misc/smtp.c\nnew file mode 100644\nindex 0000000..dc76360\n--- /dev/null\n+++ b/lib/misc/smtp.c\n@@ -0,0 +1,242 @@\n+/*\n+ * SMTP support for libwebsockets\n+ *\n+ * Copyright (C) 2016-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This program is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+static unsigned int\n+lwsgs_now_secs(void)\n+{\n+\tstruct timeval tv;\n+\n+\tgettimeofday(\u0026tv, NULL);\n+\n+\treturn tv.tv_sec;\n+}\n+\n+static void\n+ccb(uv_handle_t* handle)\n+{\n+\n+}\n+\n+static void\n+alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)\n+{\n+\tstruct lws_email *email \u003d (struct lws_email *)handle-\u003edata;\n+\n+\t*buf \u003d uv_buf_init(email-\u003eemail_buf, sizeof(email-\u003eemail_buf) - 1);\n+}\n+\n+static void\n+on_write_end(uv_write_t *req, int status) {\n+\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n+\tif (status \u003d\u003d -1) {\n+\t\tfprintf(stderr, \u0022error on_write_end\u0022);\n+\t\treturn;\n+\t}\n+}\n+\n+static void\n+lwsgs_email_read(struct uv_stream_s *s, ssize_t nread, const uv_buf_t *buf)\n+{\n+\tstruct lws_email *email \u003d (struct lws_email *)s-\u003edata;\n+\tstatic const short retcodes[] \u003d {\n+\t\t0,\t/* idle */\n+\t\t0,\t/* connecting */\n+\t\t220,\t/* connected */\n+\t\t250,\t/* helo */\n+\t\t250,\t/* from */\n+\t\t250,\t/* to */\n+\t\t354,\t/* data */\n+\t\t250,\t/* body */\n+\t\t221,\t/* quit */\n+\t};\n+\tuv_write_t write_req;\n+\tuv_buf_t wbuf;\n+\tint n;\n+\n+\tif (nread \u003e\u003d 0)\n+\t\temail-\u003eemail_buf[nread] \u003d '\u005c0';\n+\tlwsl_notice(\u0022%s: %s\u005cn\u0022, __func__, buf-\u003ebase);\n+\tif (nread \u003d\u003d -1) {\n+\t\tlwsl_err(\u0022%s: failed\u005cn\u0022, __func__);\n+\t\treturn;\n+\t}\n+\n+\tn \u003d atoi(buf-\u003ebase);\n+\tif (n !\u003d retcodes[email-\u003eestate]) {\n+\t\tlwsl_err(\u0022%s: bad response from server\u005cn\u0022, __func__);\n+\t\tgoto close_conn;\n+\t}\n+\n+\tswitch (email-\u003eestate) {\n+\tcase LGSSMTP_CONNECTED:\n+\t\tn \u003d sprintf(email-\u003econtent, \u0022HELO %s\u005cn\u0022, email-\u003eemail_helo);\n+\t\temail-\u003eestate \u003d LGSSMTP_SENT_HELO;\n+\t\tbreak;\n+\tcase LGSSMTP_SENT_HELO:\n+\t\tn \u003d sprintf(email-\u003econtent, \u0022MAIL FROM: \u003c%s\u003e\u005cn\u0022,\n+\t\t\t email-\u003eemail_from);\n+\t\temail-\u003eestate \u003d LGSSMTP_SENT_FROM;\n+\t\tbreak;\n+\tcase LGSSMTP_SENT_FROM:\n+\t\tn \u003d sprintf(email-\u003econtent, \u0022RCPT TO: \u003c%s\u003e\u005cn\u0022, email-\u003eemail_to);\n+\t\temail-\u003eestate \u003d LGSSMTP_SENT_TO;\n+\t\tbreak;\n+\tcase LGSSMTP_SENT_TO:\n+\t\tn \u003d sprintf(email-\u003econtent, \u0022DATA\u005cn\u0022);\n+\t\temail-\u003eestate \u003d LGSSMTP_SENT_DATA;\n+\t\tbreak;\n+\tcase LGSSMTP_SENT_DATA:\n+\t\tif (email-\u003eon_get_body(email, email-\u003econtent,\n+\t\t\t\t email-\u003emax_content_size))\n+\t\t\treturn;\n+\t\tn \u003d strlen(email-\u003econtent);\n+\t\temail-\u003eestate \u003d LGSSMTP_SENT_BODY;\n+\t\tbreak;\n+\tcase LGSSMTP_SENT_BODY:\n+\t\tn \u003d sprintf(email-\u003econtent, \u0022quit\u005cn\u0022);\n+\t\temail-\u003eestate \u003d LGSSMTP_SENT_QUIT;\n+\t\tbreak;\n+\tcase LGSSMTP_SENT_QUIT:\n+\t\tlwsl_notice(\u0022%s: done\u005cn\u0022, __func__);\n+\t\temail-\u003eon_sent(email);\n+\t\temail-\u003eestate \u003d LGSSMTP_IDLE;\n+\t\tgoto close_conn;\n+\tdefault:\n+\t\treturn;\n+\t}\n+\n+\tputs(email-\u003econtent);\n+\twbuf \u003d uv_buf_init(email-\u003econtent, n);\n+\tuv_write(\u0026write_req, s, \u0026wbuf, 1, on_write_end);\n+\n+\treturn;\n+\n+close_conn:\n+\n+\tuv_close((uv_handle_t *)s, ccb);\n+}\n+\n+static void\n+lwsgs_email_on_connect(uv_connect_t *req, int status)\n+{\n+\tstruct lws_email *email \u003d (struct lws_email *)req-\u003edata;\n+\n+\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n+\n+\tif (status \u003d\u003d -1) {\n+\t\tlwsl_err(\u0022%s: failed\u005cn\u0022, __func__);\n+\t\treturn;\n+\t}\n+\n+\tuv_read_start(req-\u003ehandle, alloc_buffer, lwsgs_email_read);\n+\temail-\u003eestate \u003d LGSSMTP_CONNECTED;\n+}\n+\n+\n+static void\n+uv_timeout_cb_email(uv_timer_t *w\n+#if UV_VERSION_MAJOR \u003d\u003d 0\n+\t\t, int status\n+#endif\n+)\n+{\n+\tstruct lws_email *email \u003d lws_container_of(w, struct lws_email,\n+\t\t\t\t\t\t timeout_email);\n+\ttime_t now \u003d lwsgs_now_secs();\n+\tstruct sockaddr_in req_addr;\n+\n+\tswitch (email-\u003eestate) {\n+\tcase LGSSMTP_IDLE:\n+\n+\t\tif (email-\u003eon_next(email))\n+\t\t\tbreak;\n+\n+\t\temail-\u003eestate \u003d LGSSMTP_CONNECTING;\n+\n+\t\tuv_tcp_init(email-\u003eloop, \u0026email-\u003eemail_client);\n+\t\tif (uv_ip4_addr(email-\u003eemail_smtp_ip, 25, \u0026req_addr)) {\n+\t\t\tlwsl_err(\u0022Unable to convert mailserver ads\u005cn\u0022);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tlwsl_notice(\u0022LGSSMTP_IDLE: connecting\u005cn\u0022);\n+\n+\t\temail-\u003eemail_connect_started \u003d now;\n+\t\temail-\u003eemail_connect_req.data \u003d email;\n+\t\temail-\u003eemail_client.data \u003d email;\n+\t\tuv_tcp_connect(\u0026email-\u003eemail_connect_req, \u0026email-\u003eemail_client,\n+\t\t\t (struct sockaddr *)\u0026req_addr,\n+\t\t\t lwsgs_email_on_connect);\n+\n+\t\tuv_timer_start(\u0026email-\u003etimeout_email,\n+\t\t\t uv_timeout_cb_email, 5000, 0);\n+\n+\t\tbreak;\n+\n+\tcase LGSSMTP_CONNECTING:\n+\t\tif (email-\u003eemail_connect_started - now \u003e 5) {\n+\t\t\tlwsl_err(\u0022mail session timed out\u005cn\u0022);\n+\t\t\t/* !!! kill the connection */\n+\t\t\tuv_close((uv_handle_t *) \u0026email-\u003eemail_connect_req, ccb);\n+\t\t\temail-\u003eestate \u003d LGSSMTP_IDLE;\n+\t\t}\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_email_init(struct lws_email *email, uv_loop_t *loop, int max_content)\n+{\n+\temail-\u003econtent \u003d lws_malloc(max_content, \u0022email content\u0022);\n+\tif (!email-\u003econtent)\n+\t\treturn 1;\n+\n+\temail-\u003emax_content_size \u003d max_content;\n+\tuv_timer_init(loop, \u0026email-\u003etimeout_email);\n+\n+\temail-\u003eloop \u003d loop;\n+\n+\t/* trigger him one time in a bit */\n+\tuv_timer_start(\u0026email-\u003etimeout_email, uv_timeout_cb_email, 2000, 0);\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lws_email_check(struct lws_email *email)\n+{\n+\tuv_timer_start(\u0026email-\u003etimeout_email, uv_timeout_cb_email, 1000, 0);\n+}\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lws_email_destroy(struct lws_email *email)\n+{\n+\tif (email-\u003econtent)\n+\t\tlws_free_set_NULL(email-\u003econtent);\n+\n+\tuv_timer_stop(\u0026email-\u003etimeout_email);\n+\tuv_close((uv_handle_t *)\u0026email-\u003etimeout_email, NULL);\n+}\ndiff --git a/lib/output.c b/lib/output.c\nindex 0c5f41c..ed47524 100644\n--- a/lib/output.c\n+++ b/lib/output.c\n@@ -46,49 +46,9 @@ lws_0405_frame_mask_generate(struct lws *wsi)\n \treturn 0;\n }\n \n-LWS_VISIBLE void lwsl_hexdump(const void *vbuf, size_t len)\n-{\n-\tunsigned char *buf \u003d (unsigned char *)vbuf;\n-\tunsigned int n, m, start;\n-\tchar line[80];\n-\tchar *p;\n-\n-\tlwsl_debug(\u0022\u005cn\u0022);\n-\n-\tfor (n \u003d 0; n \u003c len;) {\n-\t\tstart \u003d n;\n-\t\tp \u003d line;\n-\n-\t\tp +\u003d sprintf(p, \u0022%04X: \u0022, start);\n-\n-\t\tfor (m \u003d 0; m \u003c 16 \u0026\u0026 n \u003c len; m++)\n-\t\t\tp +\u003d sprintf(p, \u0022%02X \u0022, buf[n++]);\n-\t\twhile (m++ \u003c 16)\n-\t\t\tp +\u003d sprintf(p, \u0022 \u0022);\n-\n-\t\tp +\u003d sprintf(p, \u0022 \u0022);\n-\n-\t\tfor (m \u003d 0; m \u003c 16 \u0026\u0026 (start + m) \u003c len; m++) {\n-\t\t\tif (buf[start + m] \u003e\u003d ' ' \u0026\u0026 buf[start + m] \u003c 127)\n-\t\t\t\t*p++ \u003d buf[start + m];\n-\t\t\telse\n-\t\t\t\t*p++ \u003d '.';\n-\t\t}\n-\t\twhile (m++ \u003c 16)\n-\t\t\t*p++ \u003d ' ';\n-\n-\t\t*p++ \u003d '\u005cn';\n-\t\t*p \u003d '\u005c0';\n-\t\tlwsl_debug(\u0022%s\u0022, line);\n-\t\t(void)line;\n-\t}\n-\tlwsl_debug(\u0022\u005cn\u0022);\n-}\n-\n /*\n * notice this returns number of bytes consumed, or -1\n */\n-\n int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)\n {\n \tstruct lws_context *context \u003d lws_get_context(wsi);\ndiff --git a/lib/parsers.c b/lib/parsers.c\ndeleted file mode 100644\nindex f4c412d..0000000\n--- a/lib/parsers.c\n+++ /dev/null\n@@ -1,1781 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-const unsigned char lextable[] \u003d {\n-\t#include \u0022lextable.h\u0022\n-};\n-\n-#define FAIL_CHAR 0x08\n-\n-int LWS_WARN_UNUSED_RESULT\n-lextable_decode(int pos, char c)\n-{\n-\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'Z')\n-\t\tc +\u003d 'a' - 'A';\n-\n-\twhile (1) {\n-\t\tif (lextable[pos] \u0026 (1 \u003c\u003c 7)) { /* 1-byte, fail on mismatch */\n-\t\t\tif ((lextable[pos] \u0026 0x7f) !\u003d c)\n-\t\t\t\treturn -1;\n-\t\t\t/* fall thru */\n-\t\t\tpos++;\n-\t\t\tif (lextable[pos] \u003d\u003d FAIL_CHAR)\n-\t\t\t\treturn -1;\n-\t\t\treturn pos;\n-\t\t}\n-\n-\t\tif (lextable[pos] \u003d\u003d FAIL_CHAR)\n-\t\t\treturn -1;\n-\n-\t\t/* b7 \u003d 0, end or 3-byte */\n-\t\tif (lextable[pos] \u003c FAIL_CHAR) /* terminal marker */\n-\t\t\treturn pos;\n-\n-\t\tif (lextable[pos] \u003d\u003d c) /* goto */\n-\t\t\treturn pos + (lextable[pos + 1]) +\n-\t\t\t\t\t\t(lextable[pos + 2] \u003c\u003c 8);\n-\t\t/* fall thru goto */\n-\t\tpos +\u003d 3;\n-\t\t/* continue */\n-\t}\n-}\n-\n-static struct allocated_headers *\n-_lws_create_ah(struct lws_context_per_thread *pt, ah_data_idx_t data_size)\n-{\n-\tstruct allocated_headers *ah \u003d lws_zalloc(sizeof(*ah), \u0022ah struct\u0022);\n-\n-\tif (!ah)\n-\t\treturn NULL;\n-\n-\tah-\u003edata \u003d lws_malloc(data_size, \u0022ah data\u0022);\n-\tif (!ah-\u003edata) {\n-\t\tlws_free(ah);\n-\n-\t\treturn NULL;\n-\t}\n-\tah-\u003enext \u003d pt-\u003eah_list;\n-\tpt-\u003eah_list \u003d ah;\n-\tah-\u003edata_length \u003d data_size;\n-\tpt-\u003eah_pool_length++;\n-\n-\tlwsl_info(\u0022%s: created ah %p (size %d): pool length %d\u005cn\u0022, __func__,\n-\t\t ah, (int)data_size, pt-\u003eah_pool_length);\n-\n-\treturn ah;\n-}\n-\n-int\n-_lws_destroy_ah(struct lws_context_per_thread *pt, struct allocated_headers *ah)\n-{\n-\tlws_start_foreach_llp(struct allocated_headers **, a, pt-\u003eah_list) {\n-\t\tif ((*a) \u003d\u003d ah) {\n-\t\t\t*a \u003d ah-\u003enext;\n-\t\t\tpt-\u003eah_pool_length--;\n-\t\t\tlwsl_info(\u0022%s: freed ah %p : pool length %d\u005cn\u0022,\n-\t\t\t\t __func__, ah, pt-\u003eah_pool_length);\n-\t\t\tif (ah-\u003edata)\n-\t\t\t\tlws_free(ah-\u003edata);\n-\t\t\tlws_free(ah);\n-\n-\t\t\treturn 0;\n-\t\t}\n-\t} lws_end_foreach_llp(a, next);\n-\n-\treturn 1;\n-}\n-\n-void\n-_lws_header_table_reset(struct allocated_headers *ah)\n-{\n-\t/* init the ah to reflect no headers or data have appeared yet */\n-\tmemset(ah-\u003efrag_index, 0, sizeof(ah-\u003efrag_index));\n-\tmemset(ah-\u003efrags, 0, sizeof(ah-\u003efrags));\n-\tah-\u003enfrag \u003d 0;\n-\tah-\u003epos \u003d 0;\n-\tah-\u003ehttp_response \u003d 0;\n-}\n-\n-// doesn't scrub the ah rxbuffer by default, parent must do if needed\n-\n-void\n-lws_header_table_reset(struct lws *wsi, int autoservice)\n-{\n-\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n-\tstruct lws_context_per_thread *pt;\n-\tstruct lws_pollfd *pfd;\n-\n-\t/* if we have the idea we're resetting 'our' ah, must be bound to one */\n-\tassert(ah);\n-\t/* ah also concurs with ownership */\n-\tassert(ah-\u003ewsi \u003d\u003d wsi);\n-\n-\t_lws_header_table_reset(ah);\n-\n- wsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_NAME_PART;\n- wsi-\u003eu.hdr.lextable_pos \u003d 0;\n-\n-\t/* since we will restart the ah, our new headers are not completed */\n-\twsi-\u003ehdr_parsing_completed \u003d 0;\n-\n-\t/* while we hold the ah, keep a timeout on the wsi */\n-\tlws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,\n-\t\t\twsi-\u003evhost-\u003etimeout_secs_ah_idle);\n-\n-\ttime(\u0026ah-\u003eassigned);\n-\n-\t/*\n-\t * if we inherited pending rx (from socket adoption deferred\n-\t * processing), apply and free it.\n-\t */\n-\tif (wsi-\u003eu.hdr.preamble_rx) {\n-\t\tmemcpy(ah-\u003erx, wsi-\u003eu.hdr.preamble_rx,\n-\t\t wsi-\u003eu.hdr.preamble_rx_len);\n-\t\tah-\u003erxlen \u003d wsi-\u003eu.hdr.preamble_rx_len;\n-\t\tlws_free_set_NULL(wsi-\u003eu.hdr.preamble_rx);\n-\n-\t\tif (autoservice) {\n-\t\t\tlwsl_debug(\u0022%s: service on readbuf ah\u005cn\u0022, __func__);\n-\n-\t\t\tpt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\t\t\t/*\n-\t\t\t * Unlike a normal connect, we have the headers already\n-\t\t\t * (or the first part of them anyway)\n-\t\t\t */\n-\t\t\tpfd \u003d \u0026pt-\u003efds[wsi-\u003eposition_in_fds_table];\n-\t\t\tpfd-\u003erevents |\u003d LWS_POLLIN;\n-\t\t\tlwsl_err(\u0022%s: calling service\u005cn\u0022, __func__);\n-\t\t\tlws_service_fd_tsi(wsi-\u003econtext, pfd, wsi-\u003etsi);\n-\t\t}\n-\t}\n-}\n-\n-static void\n-_lws_header_ensure_we_are_on_waiting_list(struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tstruct lws_pollargs pa;\n-\tstruct lws **pwsi \u003d \u0026pt-\u003eah_wait_list;\n-\n-\twhile (*pwsi) {\n-\t\tif (*pwsi \u003d\u003d wsi)\n-\t\t\treturn;\n-\t\tpwsi \u003d \u0026(*pwsi)-\u003eu.hdr.ah_wait_list;\n-\t}\n-\n-\tlwsl_info(\u0022%s: wsi: %p\u005cn\u0022, __func__, wsi);\n-\twsi-\u003eu.hdr.ah_wait_list \u003d pt-\u003eah_wait_list;\n-\tpt-\u003eah_wait_list \u003d wsi;\n-\tpt-\u003eah_wait_list_length++;\n-\n-\t/* we cannot accept input then */\n-\n-\t_lws_change_pollfd(wsi, LWS_POLLIN, 0, \u0026pa);\n-}\n-\n-static int\n-__lws_remove_from_ah_waiting_list(struct lws *wsi)\n-{\n- struct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tstruct lws **pwsi \u003d\u0026pt-\u003eah_wait_list;\n-\n-\twhile (*pwsi) {\n-\t\tif (*pwsi \u003d\u003d wsi) {\n-\t\t\tlwsl_info(\u0022%s: wsi %p\u005cn\u0022, __func__, wsi);\n-\t\t\t/* point prev guy to our next */\n-\t\t\t*pwsi \u003d wsi-\u003eu.hdr.ah_wait_list;\n-\t\t\t/* we shouldn't point anywhere now */\n-\t\t\twsi-\u003eu.hdr.ah_wait_list \u003d NULL;\n-\t\t\tpt-\u003eah_wait_list_length--;\n-\n-\t\t\treturn 1;\n-\t\t}\n-\t\tpwsi \u003d \u0026(*pwsi)-\u003eu.hdr.ah_wait_list;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-int LWS_WARN_UNUSED_RESULT\n-lws_header_table_attach(struct lws *wsi, int autoservice)\n-{\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tstruct lws_pollargs pa;\n-\tint n;\n-\n-\tlwsl_info(\u0022%s: wsi %p: ah %p (tsi %d, count \u003d %d) in\u005cn\u0022, __func__,\n-\t\t (void *)wsi, (void *)wsi-\u003eu.hdr.ah, wsi-\u003etsi,\n-\t\t pt-\u003eah_count_in_use);\n-\n-\t/* if we are already bound to one, just clear it down */\n-\tif (wsi-\u003eu.hdr.ah) {\n-\t\tlwsl_info(\u0022%s: cleardown\u005cn\u0022, __func__);\n-\t\tgoto reset;\n-\t}\n-\n-\tlws_pt_lock(pt);\n-\n-\tn \u003d pt-\u003eah_count_in_use \u003d\u003d context-\u003emax_http_header_pool;\n-#if defined(LWS_WITH_PEER_LIMITS)\n-\tif (!n) {\n-\t\tn \u003d lws_peer_confirm_ah_attach_ok(context, wsi-\u003epeer);\n-\t\tif (n)\n-\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt,\n-\t\t\t\tLWSSTATS_C_PEER_LIMIT_AH_DENIED, 1);\n-\t}\n-#endif\n-\tif (n) {\n-\t\t/*\n-\t\t * Pool is either all busy, or we don't want to give this\n-\t\t * particular guy an ah right now...\n-\t\t *\n-\t\t * Make sure we are on the waiting list, and return that we\n-\t\t * weren't able to provide the ah\n-\t\t */\n-\t\t_lws_header_ensure_we_are_on_waiting_list(wsi);\n-\n-\t\tgoto bail;\n-\t}\n-\n-\t__lws_remove_from_ah_waiting_list(wsi);\n-\n-\twsi-\u003eu.hdr.ah \u003d _lws_create_ah(pt, context-\u003emax_http_header_data);\n-\tif (!wsi-\u003eu.hdr.ah) { /* we could not create an ah */\n-\t\t_lws_header_ensure_we_are_on_waiting_list(wsi);\n-\n-\t\tgoto bail;\n-\t}\n-\n-\twsi-\u003eu.hdr.ah-\u003ein_use \u003d 1;\n-\twsi-\u003eu.hdr.ah-\u003ewsi \u003d wsi; /* mark our owner */\n-\tpt-\u003eah_count_in_use++;\n-\n-#if defined(LWS_WITH_PEER_LIMITS)\n-\tif (wsi-\u003epeer)\n-\t\twsi-\u003epeer-\u003ecount_ah++;\n-#endif\n-\n-\t_lws_change_pollfd(wsi, 0, LWS_POLLIN, \u0026pa);\n-\n-\tlwsl_info(\u0022%s: did attach wsi %p: ah %p: count %d (on exit)\u005cn\u0022, __func__,\n-\t\t (void *)wsi, (void *)wsi-\u003eu.hdr.ah, pt-\u003eah_count_in_use);\n-\n-\tlws_pt_unlock(pt);\n-\n-reset:\n-\n-\t/* and reset the rx state */\n-\twsi-\u003eu.hdr.ah-\u003erxpos \u003d 0;\n-\twsi-\u003eu.hdr.ah-\u003erxlen \u003d 0;\n-\n-\tlws_header_table_reset(wsi, autoservice);\n-\n-#ifndef LWS_NO_CLIENT\n-\tif (wsi-\u003estate \u003d\u003d LWSS_CLIENT_UNCONNECTED)\n-\t\tif (!lws_client_connect_via_info2(wsi))\n-\t\t\t/* our client connect has failed, the wsi\n-\t\t\t * has been closed\n-\t\t\t */\n-\t\t\treturn -1;\n-#endif\n-\n-\treturn 0;\n-\n-bail:\n-\tlws_pt_unlock(pt);\n-\n-\treturn 1;\n-}\n-\n-void\n-lws_header_table_force_to_detachable_state(struct lws *wsi)\n-{\n-\tif (wsi-\u003eu.hdr.ah) {\n-\t\twsi-\u003eu.hdr.ah-\u003erxpos \u003d -1;\n-\t\twsi-\u003eu.hdr.ah-\u003erxlen \u003d -1;\n-\t\twsi-\u003ehdr_parsing_completed \u003d 1;\n-\t}\n-}\n-\n-int\n-lws_header_table_is_in_detachable_state(struct lws *wsi)\n-{\n-\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n-\n-\treturn ah \u0026\u0026 ah-\u003erxpos \u003d\u003d ah-\u003erxlen \u0026\u0026 wsi-\u003ehdr_parsing_completed;\n-}\n-\n-int lws_header_table_detach(struct lws *wsi, int autoservice)\n-{\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tstruct lws_pollargs pa;\n-\tstruct lws **pwsi, **pwsi_eligible;\n-\ttime_t now;\n-\n-\tlws_pt_lock(pt);\n-\t__lws_remove_from_ah_waiting_list(wsi);\n-\tlws_pt_unlock(pt);\n-\n-\tif (!ah)\n-\t\treturn 0;\n-\n-\tlwsl_info(\u0022%s: wsi %p: ah %p (tsi\u003d%d, count \u003d %d)\u005cn\u0022, __func__,\n-\t\t (void *)wsi, (void *)ah, wsi-\u003etsi,\n-\t\t pt-\u003eah_count_in_use);\n-\n-\tif (wsi-\u003eu.hdr.preamble_rx)\n-\t\tlws_free_set_NULL(wsi-\u003eu.hdr.preamble_rx);\n-\n-\t/* may not be detached while he still has unprocessed rx */\n-\tif (!lws_header_table_is_in_detachable_state(wsi)) {\n-\t\tlwsl_err(\u0022%s: %p: CANNOT DETACH rxpos:%d, rxlen:%d, \u0022\n-\t\t\t \u0022wsi-\u003ehdr_parsing_completed \u003d %d\u005cn\u0022, __func__, wsi,\n-\t\t\t ah-\u003erxpos, ah-\u003erxlen, wsi-\u003ehdr_parsing_completed);\n-\t\treturn 0;\n-\t}\n-\n-\tlws_pt_lock(pt);\n-\n-\t/* we did have an ah attached */\n-\ttime(\u0026now);\n-\tif (ah-\u003eassigned \u0026\u0026 now - ah-\u003eassigned \u003e 3) {\n-\t\t/*\n-\t\t * we're detaching the ah, but it was held an\n-\t\t * unreasonably long time\n-\t\t */\n-\t\tlwsl_debug(\u0022%s: wsi %p: ah held %ds, \u0022\n-\t\t\t \u0022ah.rxpos %d, ah.rxlen %d, mode/state %d %d,\u0022\n-\t\t\t \u0022wsi-\u003emore_rx_waiting %d\u005cn\u0022, __func__, wsi,\n-\t\t\t (int)(now - ah-\u003eassigned),\n-\t\t\t ah-\u003erxpos, ah-\u003erxlen, wsi-\u003emode, wsi-\u003estate,\n-\t\t\t wsi-\u003emore_rx_waiting);\n-\t}\n-\n-\tah-\u003eassigned \u003d 0;\n-\n-\t/* if we think we're detaching one, there should be one in use */\n-\tassert(pt-\u003eah_count_in_use \u003e 0);\n-\t/* and this specific one should have been in use */\n-\tassert(ah-\u003ein_use);\n-\twsi-\u003eu.hdr.ah \u003d NULL;\n-\tah-\u003ewsi \u003d NULL; /* no owner */\n-#if defined(LWS_WITH_PEER_LIMITS)\n-\tlws_peer_track_ah_detach(context, wsi-\u003epeer);\n-#endif\n-\n-\tpwsi \u003d \u0026pt-\u003eah_wait_list;\n-\n-\t/* oh there is nobody on the waiting list... leave the ah unattached */\n-\tif (!*pwsi)\n-\t\tgoto nobody_usable_waiting;\n-\n-\t/*\n-\t * at least one wsi on the same tsi is waiting, give it to oldest guy\n-\t * who is allowed to take it (if any)\n-\t */\n-\tlwsl_info(\u0022pt wait list %p\u005cn\u0022, *pwsi);\n-\twsi \u003d NULL;\n-\tpwsi_eligible \u003d NULL;\n-\n-\twhile (*pwsi) {\n-#if defined(LWS_WITH_PEER_LIMITS)\n-\t\t/* are we willing to give this guy an ah? */\n-\t\tif (!lws_peer_confirm_ah_attach_ok(context, (*pwsi)-\u003epeer))\n-#endif\n-\t\t{\n-\t\t\twsi \u003d *pwsi;\n-\t\t\tpwsi_eligible \u003d pwsi;\n-\t\t}\n-#if defined(LWS_WITH_PEER_LIMITS)\n-\t\telse\n-\t\t\tif (!(*pwsi)-\u003eu.hdr.ah_wait_list)\n-\t\t\t\tlws_stats_atomic_bump(context, pt,\n-\t\t\t\t\tLWSSTATS_C_PEER_LIMIT_AH_DENIED, 1);\n-#endif\n-\t\tpwsi \u003d \u0026(*pwsi)-\u003eu.hdr.ah_wait_list;\n-\t}\n-\n-\tif (!wsi) /* everybody waiting already has too many ah... */\n-\t\tgoto nobody_usable_waiting;\n-\n-\tlwsl_info(\u0022%s: last eligible wsi in wait list %p\u005cn\u0022, __func__, wsi);\n-\n-\twsi-\u003eu.hdr.ah \u003d ah;\n-\tah-\u003ewsi \u003d wsi; /* new owner */\n-\n-\t/* and reset the rx state */\n-\tah-\u003erxpos \u003d 0;\n-\tah-\u003erxlen \u003d 0;\n-\tlws_header_table_reset(wsi, autoservice);\n-#if defined(LWS_WITH_PEER_LIMITS)\n-\tif (wsi-\u003epeer)\n-\t\twsi-\u003epeer-\u003ecount_ah++;\n-#endif\n-\n-\t/* clients acquire the ah and then insert themselves in fds table... */\n-\tif (wsi-\u003eposition_in_fds_table !\u003d -1) {\n-\t\tlwsl_info(\u0022%s: Enabling %p POLLIN\u005cn\u0022, __func__, wsi);\n-\n-\t\t/* he has been stuck waiting for an ah, but now his wait is\n-\t\t * over, let him progress */\n-\n-\t\t_lws_change_pollfd(wsi, 0, LWS_POLLIN, \u0026pa);\n-\t}\n-\n-\t/* point prev guy to next guy in list instead */\n-\t*pwsi_eligible \u003d wsi-\u003eu.hdr.ah_wait_list;\n-\t/* the guy who got one is out of the list */\n-\twsi-\u003eu.hdr.ah_wait_list \u003d NULL;\n-\tpt-\u003eah_wait_list_length--;\n-\n-#ifndef LWS_NO_CLIENT\n-\tif (wsi-\u003estate \u003d\u003d LWSS_CLIENT_UNCONNECTED) {\n-\t\tlws_pt_unlock(pt);\n-\n-\t\tif (!lws_client_connect_via_info2(wsi)) {\n-\t\t\t/* our client connect has failed, the wsi\n-\t\t\t * has been closed\n-\t\t\t */\n-\n-\t\t\treturn -1;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-#endif\n-\n-\tassert(!!pt-\u003eah_wait_list_length \u003d\u003d !!(lws_intptr_t)pt-\u003eah_wait_list);\n-bail:\n-\tlwsl_info(\u0022%s: wsi %p: ah %p (tsi\u003d%d, count \u003d %d)\u005cn\u0022, __func__,\n-\t\t (void *)wsi, (void *)ah, pt-\u003etid, pt-\u003eah_count_in_use);\n-\n-\tlws_pt_unlock(pt);\n-\n-\treturn 0;\n-\n-nobody_usable_waiting:\n-\tlwsl_info(\u0022%s: nobody usable waiting\u005cn\u0022, __func__);\n-\t_lws_destroy_ah(pt, ah);\n-\tpt-\u003eah_count_in_use--;\n-\n-\tgoto bail;\n-}\n-\n-LWS_VISIBLE int\n-lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)\n-{\n-\tint n;\n-\n-\tif (!wsi-\u003eu.hdr.ah)\n-\t\treturn 0;\n-\n-\tn \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n-\tif (!n)\n-\t\treturn 0;\n-\tdo {\n-\t\tif (!frag_idx)\n-\t\t\treturn wsi-\u003eu.hdr.ah-\u003efrags[n].len;\n-\t\tn \u003d wsi-\u003eu.hdr.ah-\u003efrags[n].nfrag;\n-\t} while (frag_idx-- \u0026\u0026 n);\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)\n-{\n-\tint n;\n-\tint len \u003d 0;\n-\n-\tif (!wsi-\u003eu.hdr.ah)\n-\t\treturn 0;\n-\n-\tn \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n-\tif (!n)\n-\t\treturn 0;\n-\tdo {\n-\t\tlen +\u003d wsi-\u003eu.hdr.ah-\u003efrags[n].len;\n-\t\tn \u003d wsi-\u003eu.hdr.ah-\u003efrags[n].nfrag;\n-\t} while (n);\n-\n-\treturn len;\n-}\n-\n-LWS_VISIBLE int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,\n-\t\t\t\t enum lws_token_indexes h, int frag_idx)\n-{\n-\tint n \u003d 0;\n-\tint f;\n-\n-\tif (!wsi-\u003eu.hdr.ah)\n-\t\treturn -1;\n-\n-\tf \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n-\n-\tif (!f)\n-\t\treturn -1;\n-\n-\twhile (n \u003c frag_idx) {\n-\t\tf \u003d wsi-\u003eu.hdr.ah-\u003efrags[f].nfrag;\n-\t\tif (!f)\n-\t\t\treturn -1;\n-\t\tn++;\n-\t}\n-\n-\tif (wsi-\u003eu.hdr.ah-\u003efrags[f].len \u003e\u003d len)\n-\t\treturn -1;\n-\n-\tmemcpy(dst, wsi-\u003eu.hdr.ah-\u003edata + wsi-\u003eu.hdr.ah-\u003efrags[f].offset,\n-\t wsi-\u003eu.hdr.ah-\u003efrags[f].len);\n-\tdst[wsi-\u003eu.hdr.ah-\u003efrags[f].len] \u003d '\u005c0';\n-\n-\treturn wsi-\u003eu.hdr.ah-\u003efrags[f].len;\n-}\n-\n-LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len,\n-\t\t\t enum lws_token_indexes h)\n-{\n-\tint toklen \u003d lws_hdr_total_length(wsi, h);\n-\tint n;\n-\n-\tif (toklen \u003e\u003d len)\n-\t\treturn -1;\n-\n-\tif (!wsi-\u003eu.hdr.ah)\n-\t\treturn -1;\n-\n-\tn \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n-\tif (!n)\n-\t\treturn 0;\n-\n-\tdo {\n-\t\tstrcpy(dst,\n-\t\t \u0026wsi-\u003eu.hdr.ah-\u003edata[wsi-\u003eu.hdr.ah-\u003efrags[n].offset]);\n-\t\tdst +\u003d wsi-\u003eu.hdr.ah-\u003efrags[n].len;\n-\t\tn \u003d wsi-\u003eu.hdr.ah-\u003efrags[n].nfrag;\n-\t} while (n);\n-\n-\treturn toklen;\n-}\n-\n-char *lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h)\n-{\n-\tint n;\n-\n-\tn \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n-\tif (!n)\n-\t\treturn NULL;\n-\n-\treturn wsi-\u003eu.hdr.ah-\u003edata + wsi-\u003eu.hdr.ah-\u003efrags[n].offset;\n-}\n-\n-int LWS_WARN_UNUSED_RESULT\n-lws_pos_in_bounds(struct lws *wsi)\n-{\n-\tif (wsi-\u003eu.hdr.ah-\u003epos \u003c\n-\t (unsigned int)wsi-\u003econtext-\u003emax_http_header_data)\n-\t\treturn 0;\n-\n-\tif (wsi-\u003eu.hdr.ah-\u003epos \u003d\u003d wsi-\u003econtext-\u003emax_http_header_data) {\n-\t\tlwsl_err(\u0022Ran out of header data space\u005cn\u0022);\n-\t\treturn 1;\n-\t}\n-\n-\t/*\n-\t * with these tests everywhere, it should never be able to exceed\n-\t * the limit, only meet it\n-\t */\n-\tlwsl_err(\u0022%s: pos %d, limit %d\u005cn\u0022, __func__, wsi-\u003eu.hdr.ah-\u003epos,\n-\t\t wsi-\u003econtext-\u003emax_http_header_data);\n-\tassert(0);\n-\n-\treturn 1;\n-}\n-\n-int LWS_WARN_UNUSED_RESULT\n-lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s)\n-{\n-\twsi-\u003eu.hdr.ah-\u003enfrag++;\n-\tif (wsi-\u003eu.hdr.ah-\u003enfrag \u003d\u003d ARRAY_SIZE(wsi-\u003eu.hdr.ah-\u003efrags)) {\n-\t\tlwsl_warn(\u0022More hdr frags than we can deal with, dropping\u005cn\u0022);\n-\t\treturn -1;\n-\t}\n-\n-\twsi-\u003eu.hdr.ah-\u003efrag_index[h] \u003d wsi-\u003eu.hdr.ah-\u003enfrag;\n-\n-\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].offset \u003d wsi-\u003eu.hdr.ah-\u003epos;\n-\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].len \u003d 0;\n-\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].nfrag \u003d 0;\n-\n-\tdo {\n-\t\tif (lws_pos_in_bounds(wsi))\n-\t\t\treturn -1;\n-\n-\t\twsi-\u003eu.hdr.ah-\u003edata[wsi-\u003eu.hdr.ah-\u003epos++] \u003d *s;\n-\t\tif (*s)\n-\t\t\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].len++;\n-\t} while (*s++);\n-\n-\treturn 0;\n-}\n-\n-signed char char_to_hex(const char c)\n-{\n-\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')\n-\t\treturn c - '0';\n-\n-\tif (c \u003e\u003d 'a' \u0026\u0026 c \u003c\u003d 'f')\n-\t\treturn c - 'a' + 10;\n-\n-\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'F')\n-\t\treturn c - 'A' + 10;\n-\n-\treturn -1;\n-}\n-\n-static int LWS_WARN_UNUSED_RESULT\n-issue_char(struct lws *wsi, unsigned char c)\n-{\n-\tunsigned short frag_len;\n-\n-\tif (lws_pos_in_bounds(wsi))\n-\t\treturn -1;\n-\n-\tfrag_len \u003d wsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].len;\n-\t/*\n-\t * If we haven't hit the token limit, just copy the character into\n-\t * the header\n-\t */\n-\tif (frag_len \u003c wsi-\u003eu.hdr.current_token_limit) {\n-\t\twsi-\u003eu.hdr.ah-\u003edata[wsi-\u003eu.hdr.ah-\u003epos++] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].len++;\n-\t\treturn 0;\n-\t}\n-\n-\t/* Insert a null character when we *hit* the limit: */\n-\tif (frag_len \u003d\u003d wsi-\u003eu.hdr.current_token_limit) {\n-\t\tif (lws_pos_in_bounds(wsi))\n-\t\t\treturn -1;\n-\n-\t\twsi-\u003eu.hdr.ah-\u003edata[wsi-\u003eu.hdr.ah-\u003epos++] \u003d '\u005c0';\n-\t\tlwsl_warn(\u0022header %i exceeds limit %d\u005cn\u0022,\n-\t\t\t wsi-\u003eu.hdr.parser_state,\n-\t\t\t wsi-\u003eu.hdr.current_token_limit);\n-\t}\n-\n-\treturn 1;\n-}\n-\n-int\n-lws_parse_urldecode(struct lws *wsi, uint8_t *_c)\n-{\n-\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n-\tunsigned int enc \u003d 0;\n-\tuint8_t c \u003d *_c;\n-\n-\t/*\n-\t * PRIORITY 1\n-\t * special URI processing... convert %xx\n-\t */\n-\tswitch (wsi-\u003eu.hdr.ues) {\n-\tcase URIES_IDLE:\n-\t\tif (c \u003d\u003d '%') {\n-\t\t\twsi-\u003eu.hdr.ues \u003d URIES_SEEN_PERCENT;\n-\t\t\tgoto swallow;\n-\t\t}\n-\t\tbreak;\n-\tcase URIES_SEEN_PERCENT:\n-\t\tif (char_to_hex(c) \u003c 0)\n-\t\t\t/* illegal post-% char */\n-\t\t\tgoto forbid;\n-\n-\t\twsi-\u003eu.hdr.esc_stash \u003d c;\n-\t\twsi-\u003eu.hdr.ues \u003d URIES_SEEN_PERCENT_H1;\n-\t\tgoto swallow;\n-\n-\tcase URIES_SEEN_PERCENT_H1:\n-\t\tif (char_to_hex(c) \u003c 0)\n-\t\t\t/* illegal post-% char */\n-\t\t\tgoto forbid;\n-\n-\t\t*_c \u003d (char_to_hex(wsi-\u003eu.hdr.esc_stash) \u003c\u003c 4) |\n-\t\t\t\tchar_to_hex(c);\n-\t\tc \u003d *_c;\n-\t\tenc \u003d 1;\n-\t\twsi-\u003eu.hdr.ues \u003d URIES_IDLE;\n-\t\tbreak;\n-\t}\n-\n-\t/*\n-\t * PRIORITY 2\n-\t * special URI processing...\n-\t * convert /.. or /... or /../ etc to /\n-\t * convert /./ to /\n-\t * convert // or /// etc to /\n-\t * leave /.dir or whatever alone\n-\t */\n-\n-\tswitch (wsi-\u003eu.hdr.ups) {\n-\tcase URIPS_IDLE:\n-\t\tif (!c)\n-\t\t\treturn -1;\n-\t\t/* genuine delimiter */\n-\t\tif ((c \u003d\u003d '\u0026' || c \u003d\u003d ';') \u0026\u0026 !enc) {\n-\t\t\tif (issue_char(wsi, c) \u003c 0)\n-\t\t\t\treturn -1;\n-\t\t\t/* swallow the terminator */\n-\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n-\t\t\t/* link to next fragment */\n-\t\t\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d ah-\u003enfrag + 1;\n-\t\t\tah-\u003enfrag++;\n-\t\t\tif (ah-\u003enfrag \u003e\u003d ARRAY_SIZE(ah-\u003efrags))\n-\t\t\t\tgoto excessive;\n-\t\t\t/* start next fragment after the \u0026 */\n-\t\t\twsi-\u003eu.hdr.post_literal_equal \u003d 0;\n-\t\t\tah-\u003efrags[ah-\u003enfrag].offset \u003d ah-\u003epos;\n-\t\t\tah-\u003efrags[ah-\u003enfrag].len \u003d 0;\n-\t\t\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d 0;\n-\t\t\tgoto swallow;\n-\t\t}\n-\t\t/* uriencoded \u003d in the name part, disallow */\n-\t\tif (c \u003d\u003d '\u003d' \u0026\u0026 enc \u0026\u0026\n-\t\t ah-\u003efrag_index[WSI_TOKEN_HTTP_URI_ARGS] \u0026\u0026\n-\t\t !wsi-\u003eu.hdr.post_literal_equal) {\n-\t\t\tc \u003d '_';\n-\t\t\t*_c \u003dc;\n-\t\t}\n-\n-\t\t/* after the real \u003d, we don't care how many \u003d */\n-\t\tif (c \u003d\u003d '\u003d' \u0026\u0026 !enc)\n-\t\t\twsi-\u003eu.hdr.post_literal_equal \u003d 1;\n-\n-\t\t/* + to space */\n-\t\tif (c \u003d\u003d '+' \u0026\u0026 !enc) {\n-\t\t\tc \u003d ' ';\n-\t\t\t*_c \u003d c;\n-\t\t}\n-\t\t/* issue the first / always */\n-\t\tif (c \u003d\u003d '/' \u0026\u0026 !ah-\u003efrag_index[WSI_TOKEN_HTTP_URI_ARGS])\n-\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH;\n-\t\tbreak;\n-\tcase URIPS_SEEN_SLASH:\n-\t\t/* swallow subsequent slashes */\n-\t\tif (c \u003d\u003d '/')\n-\t\t\tgoto swallow;\n-\t\t/* track and swallow the first . after / */\n-\t\tif (c \u003d\u003d '.') {\n-\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH_DOT;\n-\t\t\tgoto swallow;\n-\t\t}\n-\t\twsi-\u003eu.hdr.ups \u003d URIPS_IDLE;\n-\t\tbreak;\n-\tcase URIPS_SEEN_SLASH_DOT:\n-\t\t/* swallow second . */\n-\t\tif (c \u003d\u003d '.') {\n-\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH_DOT_DOT;\n-\t\t\tgoto swallow;\n-\t\t}\n-\t\t/* change /./ to / */\n-\t\tif (c \u003d\u003d '/') {\n-\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH;\n-\t\t\tgoto swallow;\n-\t\t}\n-\t\t/* it was like /.dir ... regurgitate the . */\n-\t\twsi-\u003eu.hdr.ups \u003d URIPS_IDLE;\n-\t\tif (issue_char(wsi, '.') \u003c 0)\n-\t\t\treturn -1;\n-\t\tbreak;\n-\n-\tcase URIPS_SEEN_SLASH_DOT_DOT:\n-\n-\t\t/* /../ or /..[End of URI] --\u003e backup to last / */\n-\t\tif (c \u003d\u003d '/' || c \u003d\u003d '?') {\n-\t\t\t/*\n-\t\t\t * back up one dir level if possible\n-\t\t\t * safe against header fragmentation because\n-\t\t\t * the method URI can only be in 1 fragment\n-\t\t\t */\n-\t\t\tif (ah-\u003efrags[ah-\u003enfrag].len \u003e 2) {\n-\t\t\t\tah-\u003epos--;\n-\t\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n-\t\t\t\tdo {\n-\t\t\t\t\tah-\u003epos--;\n-\t\t\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n-\t\t\t\t} while (ah-\u003efrags[ah-\u003enfrag].len \u003e 1 \u0026\u0026\n-\t\t\t\t\t ah-\u003edata[ah-\u003epos] !\u003d '/');\n-\t\t\t}\n-\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH;\n-\t\t\tif (ah-\u003efrags[ah-\u003enfrag].len \u003e 1)\n-\t\t\t\tbreak;\n-\t\t\tgoto swallow;\n-\t\t}\n-\n-\t\t/* /..[^/] ... regurgitate and allow */\n-\n-\t\tif (issue_char(wsi, '.') \u003c 0)\n-\t\t\treturn -1;\n-\t\tif (issue_char(wsi, '.') \u003c 0)\n-\t\t\treturn -1;\n-\t\twsi-\u003eu.hdr.ups \u003d URIPS_IDLE;\n-\t\tbreak;\n-\t}\n-\n-\tif (c \u003d\u003d '?' \u0026\u0026 !enc \u0026\u0026\n-\t !ah-\u003efrag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI arguments */\n-\t\tif (wsi-\u003eu.hdr.ues !\u003d URIES_IDLE)\n-\t\t\tgoto forbid;\n-\n-\t\t/* seal off uri header */\n-\t\tif (issue_char(wsi, '\u005c0') \u003c 0)\n-\t\t\treturn -1;\n-\n-\t\t/* move to using WSI_TOKEN_HTTP_URI_ARGS */\n-\t\tah-\u003enfrag++;\n-\t\tif (ah-\u003enfrag \u003e\u003d ARRAY_SIZE(ah-\u003efrags))\n-\t\t\tgoto excessive;\n-\t\tah-\u003efrags[ah-\u003enfrag].offset \u003d ah-\u003epos;\n-\t\tah-\u003efrags[ah-\u003enfrag].len \u003d 0;\n-\t\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d 0;\n-\n-\t\twsi-\u003eu.hdr.post_literal_equal \u003d 0;\n-\t\tah-\u003efrag_index[WSI_TOKEN_HTTP_URI_ARGS] \u003d ah-\u003enfrag;\n-\t\twsi-\u003eu.hdr.ups \u003d URIPS_IDLE;\n-\t\tgoto swallow;\n-\t}\n-\n-\treturn LPUR_CONTINUE;\n-\n-swallow:\n-\treturn LPUR_SWALLOW;\n-\n-forbid:\n-\treturn LPUR_FORBID;\n-\n-excessive:\n-\treturn LPUR_EXCESSIVE;\n-}\n-\n-static const unsigned char methods[] \u003d {\n-\tWSI_TOKEN_GET_URI,\n-\tWSI_TOKEN_POST_URI,\n-\tWSI_TOKEN_OPTIONS_URI,\n-\tWSI_TOKEN_PUT_URI,\n-\tWSI_TOKEN_PATCH_URI,\n-\tWSI_TOKEN_DELETE_URI,\n-\tWSI_TOKEN_CONNECT,\n-\tWSI_TOKEN_HEAD_URI,\n-};\n-\n-int LWS_WARN_UNUSED_RESULT\n-lws_parse(struct lws *wsi, unsigned char c)\n-{\n-\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tunsigned int n, m;\n-\tint r;\n-\n-\tassert(wsi-\u003eu.hdr.ah);\n-\n-\tswitch (wsi-\u003eu.hdr.parser_state) {\n-\tdefault:\n-\n-\t\tlwsl_parser(\u0022WSI_TOK_(%d) '%c'\u005cn\u0022, wsi-\u003eu.hdr.parser_state, c);\n-\n-\t\t/* collect into malloc'd buffers */\n-\t\t/* optional initial space swallow */\n-\t\tif (!ah-\u003efrags[ah-\u003efrag_index[wsi-\u003eu.hdr.parser_state]].len \u0026\u0026\n-\t\t c \u003d\u003d ' ')\n-\t\t\tbreak;\n-\n-\t\tfor (m \u003d 0; m \u003c ARRAY_SIZE(methods); m++)\n-\t\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d methods[m])\n-\t\t\t\tbreak;\n-\t\tif (m \u003d\u003d ARRAY_SIZE(methods))\n-\t\t\t/* it was not any of the methods */\n-\t\t\tgoto check_eol;\n-\n-\t\t/* special URI processing... end at space */\n-\n-\t\tif (c \u003d\u003d ' ') {\n-\t\t\t/* enforce starting with / */\n-\t\t\tif (!ah-\u003efrags[ah-\u003enfrag].len)\n-\t\t\t\tif (issue_char(wsi, '/') \u003c 0)\n-\t\t\t\t\treturn -1;\n-\n-\t\t\tif (wsi-\u003eu.hdr.ups \u003d\u003d URIPS_SEEN_SLASH_DOT_DOT) {\n-\t\t\t\t/*\n-\t\t\t\t * back up one dir level if possible\n-\t\t\t\t * safe against header fragmentation because\n-\t\t\t\t * the method URI can only be in 1 fragment\n-\t\t\t\t */\n-\t\t\t\tif (ah-\u003efrags[ah-\u003enfrag].len \u003e 2) {\n-\t\t\t\t\tah-\u003epos--;\n-\t\t\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n-\t\t\t\t\tdo {\n-\t\t\t\t\t\tah-\u003epos--;\n-\t\t\t\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n-\t\t\t\t\t} while (ah-\u003efrags[ah-\u003enfrag].len \u003e 1 \u0026\u0026\n-\t\t\t\t\t\t ah-\u003edata[ah-\u003epos] !\u003d '/');\n-\t\t\t\t}\n-\t\t\t}\n-\n-\t\t\t/* begin parsing HTTP version: */\n-\t\t\tif (issue_char(wsi, '\u005c0') \u003c 0)\n-\t\t\t\treturn -1;\n-\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_HTTP;\n-\t\t\tgoto start_fragment;\n-\t\t}\n-\n-\t\tr \u003d lws_parse_urldecode(wsi, \u0026c);\n-\t\tswitch (r) {\n-\t\tcase LPUR_CONTINUE:\n-\t\t\tbreak;\n-\t\tcase LPUR_SWALLOW:\n-\t\t\tgoto swallow;\n-\t\tcase LPUR_FORBID:\n-\t\t\tgoto forbid;\n-\t\tcase LPUR_EXCESSIVE:\n-\t\t\tgoto excessive;\n-\t\tdefault:\n-\t\t\treturn -1;\n-\t\t}\n-check_eol:\n-\t\t/* bail at EOL */\n-\t\tif (wsi-\u003eu.hdr.parser_state !\u003d WSI_TOKEN_CHALLENGE \u0026\u0026\n-\t\t c \u003d\u003d '\u005cx0d') {\n-\t\t\tif (wsi-\u003eu.hdr.ues !\u003d URIES_IDLE)\n-\t\t\t\tgoto forbid;\n-\n-\t\t\tc \u003d '\u005c0';\n-\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING_SAW_CR;\n-\t\t\tlwsl_parser(\u0022*\u005cn\u0022);\n-\t\t}\n-\n-\t\tn \u003d issue_char(wsi, c);\n-\t\tif ((int)n \u003c 0)\n-\t\t\treturn -1;\n-\t\tif (n \u003e 0)\n-\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING;\n-\n-swallow:\n-\t\t/* per-protocol end of headers management */\n-\n-\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_CHALLENGE)\n-\t\t\tgoto set_parsing_complete;\n-\t\tbreak;\n-\n-\t\t/* collecting and checking a name part */\n-\tcase WSI_TOKEN_NAME_PART:\n-\t\tlwsl_parser(\u0022WSI_TOKEN_NAME_PART '%c' 0x%02X (mode\u003d%d) wsi-\u003eu.hdr.lextable_pos\u003d%d\u005cn\u0022, c, c, wsi-\u003emode, wsi-\u003eu.hdr.lextable_pos);\n-\n-\t\twsi-\u003eu.hdr.lextable_pos \u003d\n-\t\t\t\tlextable_decode(wsi-\u003eu.hdr.lextable_pos, c);\n-\t\t/*\n-\t\t * Server needs to look out for unknown methods...\n-\t\t */\n-\t\tif (wsi-\u003eu.hdr.lextable_pos \u003c 0 \u0026\u0026\n-\t\t (wsi-\u003emode \u003d\u003d LWSCM_HTTP_SERVING)) {\n-\t\t\t/* this is not a header we know about */\n-\t\t\tfor (m \u003d 0; m \u003c ARRAY_SIZE(methods); m++)\n-\t\t\t\tif (ah-\u003efrag_index[methods[m]]) {\n-\t\t\t\t\t/*\n-\t\t\t\t\t * already had the method, no idea what\n-\t\t\t\t\t * this crap from the client is, ignore\n-\t\t\t\t\t */\n-\t\t\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t/*\n-\t\t\t * hm it's an unknown http method from a client in fact,\n-\t\t\t * it cannot be valid http\n-\t\t\t */\n-\t\t\tif (m \u003d\u003d ARRAY_SIZE(methods)) {\n-\t\t\t\t/*\n-\t\t\t\t * are we set up to accept raw in these cases?\n-\t\t\t\t */\n-\t\t\t\tif (lws_check_opt(wsi-\u003evhost-\u003eoptions,\n-\t\t\t\t\t LWS_SERVER_OPTION_FALLBACK_TO_RAW))\n-\t\t\t\t\treturn 2; /* transition to raw */\n-\n-\t\t\t\tlwsl_info(\u0022Unknown method - dropping\u005cn\u0022);\n-\t\t\t\tgoto forbid;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\t}\n-\t\t/*\n-\t\t * ...otherwise for a client, let him ignore unknown headers\n-\t\t * coming from the server\n-\t\t */\n-\t\tif (wsi-\u003eu.hdr.lextable_pos \u003c 0) {\n-\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING;\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (lextable[wsi-\u003eu.hdr.lextable_pos] \u003c FAIL_CHAR) {\n-\t\t\t/* terminal state */\n-\n-\t\t\tn \u003d ((unsigned int)lextable[wsi-\u003eu.hdr.lextable_pos] \u003c\u003c 8) |\n-\t\t\t\t\tlextable[wsi-\u003eu.hdr.lextable_pos + 1];\n-\n-\t\t\tlwsl_parser(\u0022known hdr %d\u005cn\u0022, n);\n-\t\t\tfor (m \u003d 0; m \u003c ARRAY_SIZE(methods); m++)\n-\t\t\t\tif (n \u003d\u003d methods[m] \u0026\u0026\n-\t\t\t\t ah-\u003efrag_index[methods[m]]) {\n-\t\t\t\t\tlwsl_warn(\u0022Duplicated method\u005cn\u0022);\n-\t\t\t\t\treturn -1;\n-\t\t\t\t}\n-\n-\t\t\t/*\n-\t\t\t * WSORIGIN is protocol equiv to ORIGIN,\n-\t\t\t * JWebSocket likes to send it, map to ORIGIN\n-\t\t\t */\n-\t\t\tif (n \u003d\u003d WSI_TOKEN_SWORIGIN)\n-\t\t\t\tn \u003d WSI_TOKEN_ORIGIN;\n-\n-\t\t\twsi-\u003eu.hdr.parser_state \u003d (enum lws_token_indexes)\n-\t\t\t\t\t\t\t(WSI_TOKEN_GET_URI + n);\n-\n-\t\t\tif (context-\u003etoken_limits)\n-\t\t\t\twsi-\u003eu.hdr.current_token_limit \u003d\n-\t\t\t\t\tcontext-\u003etoken_limits-\u003etoken_limit[\n-\t\t\t\t\t\t wsi-\u003eu.hdr.parser_state];\n-\t\t\telse\n-\t\t\t\twsi-\u003eu.hdr.current_token_limit \u003d\n-\t\t\t\t\twsi-\u003econtext-\u003emax_http_header_data;\n-\n-\t\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_CHALLENGE)\n-\t\t\t\tgoto set_parsing_complete;\n-\n-\t\t\tgoto start_fragment;\n-\t\t}\n-\t\tbreak;\n-\n-start_fragment:\n-\t\tah-\u003enfrag++;\n-excessive:\n-\t\tif (ah-\u003enfrag \u003d\u003d ARRAY_SIZE(ah-\u003efrags)) {\n-\t\t\tlwsl_warn(\u0022More hdr frags than we can deal with\u005cn\u0022);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tah-\u003efrags[ah-\u003enfrag].offset \u003d ah-\u003epos;\n-\t\tah-\u003efrags[ah-\u003enfrag].len \u003d 0;\n-\t\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d 0;\n-\t\tah-\u003efrags[ah-\u003enfrag].flags \u003d 2;\n-\n-\t\tn \u003d ah-\u003efrag_index[wsi-\u003eu.hdr.parser_state];\n-\t\tif (!n) { /* first fragment */\n-\t\t\tah-\u003efrag_index[wsi-\u003eu.hdr.parser_state] \u003d ah-\u003enfrag;\n-\t\t\tah-\u003ehdr_token_idx \u003d wsi-\u003eu.hdr.parser_state;\n-\t\t\tbreak;\n-\t\t}\n-\t\t/* continuation */\n-\t\twhile (ah-\u003efrags[n].nfrag)\n-\t\t\tn \u003d ah-\u003efrags[n].nfrag;\n-\t\tah-\u003efrags[n].nfrag \u003d ah-\u003enfrag;\n-\n-\t\tif (issue_char(wsi, ' ') \u003c 0)\n-\t\t\treturn -1;\n-\t\tbreak;\n-\n-\t\t/* skipping arg part of a name we didn't recognize */\n-\tcase WSI_TOKEN_SKIPPING:\n-\t\tlwsl_parser(\u0022WSI_TOKEN_SKIPPING '%c'\u005cn\u0022, c);\n-\n-\t\tif (c \u003d\u003d '\u005cx0d')\n-\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING_SAW_CR;\n-\t\tbreak;\n-\n-\tcase WSI_TOKEN_SKIPPING_SAW_CR:\n-\t\tlwsl_parser(\u0022WSI_TOKEN_SKIPPING_SAW_CR '%c'\u005cn\u0022, c);\n-\t\tif (wsi-\u003eu.hdr.ues !\u003d URIES_IDLE)\n-\t\t\tgoto forbid;\n-\t\tif (c \u003d\u003d '\u005cx0a') {\n-\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_NAME_PART;\n-\t\t\twsi-\u003eu.hdr.lextable_pos \u003d 0;\n-\t\t} else\n-\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING;\n-\t\tbreak;\n-\t\t/* we're done, ignore anything else */\n-\n-\tcase WSI_PARSING_COMPLETE:\n-\t\tlwsl_parser(\u0022WSI_PARSING_COMPLETE '%c'\u005cn\u0022, c);\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-\n-set_parsing_complete:\n-\tif (wsi-\u003eu.hdr.ues !\u003d URIES_IDLE)\n-\t\tgoto forbid;\n-\tif (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))\n-\t\t\twsi-\u003eietf_spec_revision \u003d\n-\t\t\t atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));\n-\n-\t\tlwsl_parser(\u0022v%02d hdrs completed\u005cn\u0022, wsi-\u003eietf_spec_revision);\n-\t}\n-\twsi-\u003eu.hdr.parser_state \u003d WSI_PARSING_COMPLETE;\n-\twsi-\u003ehdr_parsing_completed \u003d 1;\n-\n-\treturn 0;\n-\n-forbid:\n-\tlwsl_notice(\u0022 forbidding on uri sanitation\u005cn\u0022);\n-\tlws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);\n-\n-\treturn -1;\n-}\n-\n-LWS_VISIBLE int lws_frame_is_binary(struct lws *wsi)\n-{\n-\treturn wsi-\u003eu.ws.frame_is_binary;\n-}\n-\n-void\n-lws_add_wsi_to_draining_ext_list(struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\n-\tif (wsi-\u003eu.ws.rx_draining_ext)\n-\t\treturn;\n-\n-\tlwsl_ext(\u0022%s: RX EXT DRAINING: Adding to list\u005cn\u0022, __func__);\n-\n-\twsi-\u003eu.ws.rx_draining_ext \u003d 1;\n-\twsi-\u003eu.ws.rx_draining_ext_list \u003d pt-\u003erx_draining_ext_list;\n-\tpt-\u003erx_draining_ext_list \u003d wsi;\n-}\n-\n-void\n-lws_remove_wsi_from_draining_ext_list(struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tstruct lws **w \u003d \u0026pt-\u003erx_draining_ext_list;\n-\n-\tif (!wsi-\u003eu.ws.rx_draining_ext)\n-\t\treturn;\n-\n-\tlwsl_ext(\u0022%s: RX EXT DRAINING: Removing from list\u005cn\u0022, __func__);\n-\n-\twsi-\u003eu.ws.rx_draining_ext \u003d 0;\n-\n-\t/* remove us from context draining ext list */\n-\twhile (*w) {\n-\t\tif (*w \u003d\u003d wsi) {\n-\t\t\t/* if us, point it instead to who we were pointing to */\n-\t\t\t*w \u003d wsi-\u003eu.ws.rx_draining_ext_list;\n-\t\t\tbreak;\n-\t\t}\n-\t\tw \u003d \u0026((*w)-\u003eu.ws.rx_draining_ext_list);\n-\t}\n-\twsi-\u003eu.ws.rx_draining_ext_list \u003d NULL;\n-}\n-\n-/*\n- * client-parser.c: lws_client_rx_sm() needs to be roughly kept in\n- * sync with changes here, esp related to ext draining\n- */\n-\n-int\n-lws_rx_sm(struct lws *wsi, unsigned char c)\n-{\n-\tint callback_action \u003d LWS_CALLBACK_RECEIVE;\n-\tint ret \u003d 0, n, rx_draining_ext \u003d 0;\n-\tstruct lws_tokens eff_buf;\n-\n-\teff_buf.token \u003d NULL;\n-\teff_buf.token_len \u003d 0;\n-\tif (wsi-\u003esocket_is_permanently_unusable)\n-\t\treturn -1;\n-\n-\tswitch (wsi-\u003elws_rx_parse_state) {\n-\tcase LWS_RXPS_NEW:\n-\t\tif (wsi-\u003eu.ws.rx_draining_ext) {\n-\t\t\teff_buf.token \u003d NULL;\n-\t\t\teff_buf.token_len \u003d 0;\n-\t\t\tlws_remove_wsi_from_draining_ext_list(wsi);\n-\t\t\trx_draining_ext \u003d 1;\n-\t\t\tlwsl_debug(\u0022%s: doing draining flow\u005cn\u0022, __func__);\n-\n-\t\t\tgoto drain_extension;\n-\t\t}\n-\t\tswitch (wsi-\u003eietf_spec_revision) {\n-\t\tcase 13:\n-\t\t\t/*\n-\t\t\t * no prepended frame key any more\n-\t\t\t */\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 1;\n-\t\t\tgoto handle_first;\n-\n-\t\tdefault:\n-\t\t\tlwsl_warn(\u0022lws_rx_sm: unknown spec version %d\u005cn\u0022,\n-\t\t\t\t\t\t wsi-\u003eietf_spec_revision);\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\tcase LWS_RXPS_04_mask_1:\n-\t\twsi-\u003eu.ws.mask[1] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_mask_2;\n-\t\tbreak;\n-\tcase LWS_RXPS_04_mask_2:\n-\t\twsi-\u003eu.ws.mask[2] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_mask_3;\n-\t\tbreak;\n-\tcase LWS_RXPS_04_mask_3:\n-\t\twsi-\u003eu.ws.mask[3] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\n-\t\t/*\n-\t\t * start from the zero'th byte in the XOR key buffer since\n-\t\t * this is the start of a frame with a new key\n-\t\t */\n-\n-\t\twsi-\u003eu.ws.mask_idx \u003d 0;\n-\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_1;\n-\t\tbreak;\n-\n-\t/*\n-\t * 04 logical framing from the spec (all this is masked when incoming\n-\t * and has to be unmasked)\n-\t *\n-\t * We ignore the possibility of extension data because we don't\n-\t * negotiate any extensions at the moment.\n-\t *\n-\t * 0 1 2 3\n-\t * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n-\t * +-+-+-+-+-------+-+-------------+-------------------------------+\n-\t * |F|R|R|R| opcode|R| Payload len | Extended payload length |\n-\t * |I|S|S|S| (4) |S| (7) | (16/63) |\n-\t * |N|V|V|V| |V| | (if payload len\u003d\u003d126/127) |\n-\t * | |1|2|3| |4| | |\n-\t * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +\n-\t * | Extended payload length continued, if payload len \u003d\u003d 127 |\n-\t * + - - - - - - - - - - - - - - - +-------------------------------+\n-\t * | | Extension data |\n-\t * +-------------------------------+ - - - - - - - - - - - - - - - +\n-\t * : :\n-\t * +---------------------------------------------------------------+\n-\t * : Application data :\n-\t * +---------------------------------------------------------------+\n-\t *\n-\t * We pass payload through to userland as soon as we get it, ignoring\n-\t * FIN. It's up to userland to buffer it up if it wants to see a\n-\t * whole unfragmented block of the original size (which may be up to\n-\t * 2^63 long!)\n-\t */\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_1:\n-handle_first:\n-\n-\t\twsi-\u003eu.ws.opcode \u003d c \u0026 0xf;\n-\t\twsi-\u003eu.ws.rsv \u003d c \u0026 0x70;\n-\t\twsi-\u003eu.ws.final \u003d !!((c \u003e\u003e 7) \u0026 1);\n-\n-\t\tswitch (wsi-\u003eu.ws.opcode) {\n-\t\tcase LWSWSOPC_TEXT_FRAME:\n-\t\tcase LWSWSOPC_BINARY_FRAME:\n-\t\t\twsi-\u003eu.ws.rsv_first_msg \u003d (c \u0026 0x70);\n-\t\t\twsi-\u003eu.ws.frame_is_binary \u003d\n-\t\t\t wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_BINARY_FRAME;\n-\t\t\twsi-\u003eu.ws.first_fragment \u003d 1;\n-\t\t\tbreak;\n-\t\tcase 3:\n-\t\tcase 4:\n-\t\tcase 5:\n-\t\tcase 6:\n-\t\tcase 7:\n-\t\tcase 0xb:\n-\t\tcase 0xc:\n-\t\tcase 0xd:\n-\t\tcase 0xe:\n-\t\tcase 0xf:\n-\t\t\tlwsl_info(\u0022illegal opcode\u005cn\u0022);\n-\t\t\treturn -1;\n-\t\t}\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN:\n-\n-\t\twsi-\u003eu.ws.this_frame_masked \u003d !!(c \u0026 0x80);\n-\n-\t\tswitch (c \u0026 0x7f) {\n-\t\tcase 126:\n-\t\t\t/* control frames are not allowed to have big lengths */\n-\t\t\tif (wsi-\u003eu.ws.opcode \u0026 8)\n-\t\t\t\tgoto illegal_ctl_length;\n-\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN16_2;\n-\t\t\tbreak;\n-\t\tcase 127:\n-\t\t\t/* control frames are not allowed to have big lengths */\n-\t\t\tif (wsi-\u003eu.ws.opcode \u0026 8)\n-\t\t\t\tgoto illegal_ctl_length;\n-\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_8;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\twsi-\u003eu.ws.rx_packet_length \u003d c \u0026 0x7f;\n-\t\t\tif (wsi-\u003eu.ws.this_frame_masked)\n-\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n-\t\t\telse\n-\t\t\t\tif (wsi-\u003eu.ws.rx_packet_length)\n-\t\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n-\t\t\t\telse {\n-\t\t\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n-\t\t\t\t\tgoto spill;\n-\t\t\t\t}\n-\t\t\tbreak;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN16_2:\n-\t\twsi-\u003eu.ws.rx_packet_length \u003d c \u003c\u003c 8;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN16_1;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN16_1:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d c;\n-\t\tif (wsi-\u003eu.ws.this_frame_masked)\n-\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n-\t\telse\n-\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_8:\n-\t\tif (c \u0026 0x80) {\n-\t\t\tlwsl_warn(\u0022b63 of length must be zero\u005cn\u0022);\n-\t\t\t/* kill the connection */\n-\t\t\treturn -1;\n-\t\t}\n-#if defined __LP64__\n-\t\twsi-\u003eu.ws.rx_packet_length \u003d ((size_t)c) \u003c\u003c 56;\n-#else\n-\t\twsi-\u003eu.ws.rx_packet_length \u003d 0;\n-#endif\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_7;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_7:\n-#if defined __LP64__\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 48;\n-#endif\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_6;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_6:\n-#if defined __LP64__\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 40;\n-#endif\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_5;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_5:\n-#if defined __LP64__\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 32;\n-#endif\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_4;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_4:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 24;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_3;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_3:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 16;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_2;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_2:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 8;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_1;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_04_FRAME_HDR_LEN64_1:\n-\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c);\n-\t\tif (wsi-\u003eu.ws.this_frame_masked)\n-\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n-\t\telse\n-\t\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_1:\n-\t\twsi-\u003eu.ws.mask[0] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_2;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_2:\n-\t\twsi-\u003eu.ws.mask[1] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_3;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_3:\n-\t\twsi-\u003eu.ws.mask[2] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_4;\n-\t\tbreak;\n-\n-\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_4:\n-\t\twsi-\u003eu.ws.mask[3] \u003d c;\n-\t\tif (c)\n-\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n-\t\twsi-\u003elws_rx_parse_state \u003d\n-\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n-\t\twsi-\u003eu.ws.mask_idx \u003d 0;\n-\t\tif (wsi-\u003eu.ws.rx_packet_length \u003d\u003d 0) {\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n-\t\t\tgoto spill;\n-\t\t}\n-\t\tbreak;\n-\n-\n-\tcase LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:\n-\t\tassert(wsi-\u003eu.ws.rx_ubuf);\n-\n-\t\tif (wsi-\u003eu.ws.rx_draining_ext)\n-\t\t\tgoto drain_extension;\n-\n-\t\tif (wsi-\u003eu.ws.rx_ubuf_head + LWS_PRE \u003e\u003d\n-\t\t wsi-\u003eu.ws.rx_ubuf_alloc) {\n-\t\t\tlwsl_err(\u0022Attempted overflow \u005cn\u0022);\n-\t\t\treturn -1;\n-\t\t}\n-\t\tif (wsi-\u003eu.ws.all_zero_nonce)\n-\t\t\twsi-\u003eu.ws.rx_ubuf[LWS_PRE +\n-\t\t\t\t\t (wsi-\u003eu.ws.rx_ubuf_head++)] \u003d c;\n-\t\telse\n-\t\t\twsi-\u003eu.ws.rx_ubuf[LWS_PRE +\n-\t\t\t (wsi-\u003eu.ws.rx_ubuf_head++)] \u003d\n-\t\t\t\t c ^ wsi-\u003eu.ws.mask[\n-\t\t\t\t\t (wsi-\u003eu.ws.mask_idx++) \u0026 3];\n-\n-\t\tif (--wsi-\u003eu.ws.rx_packet_length \u003d\u003d 0) {\n-\t\t\t/* spill because we have the whole frame */\n-\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n-\t\t\tgoto spill;\n-\t\t}\n-\n-\t\t/*\n-\t\t * if there's no protocol max frame size given, we are\n-\t\t * supposed to default to context-\u003ept_serv_buf_size\n-\t\t */\n-\n-\t\tif (!wsi-\u003eprotocol-\u003erx_buffer_size \u0026\u0026\n-\t\t wsi-\u003eu.ws.rx_ubuf_head !\u003d wsi-\u003econtext-\u003ept_serv_buf_size)\n-\t\t\tbreak;\n-\t\telse\n-\t\t\tif (wsi-\u003eprotocol-\u003erx_buffer_size \u0026\u0026\n-\t\t\t\t\twsi-\u003eu.ws.rx_ubuf_head !\u003d\n-\t\t\t\t\t\t wsi-\u003eprotocol-\u003erx_buffer_size)\n-\t\t\tbreak;\n-\n-\t\t/* spill because we filled our rx buffer */\n-spill:\n-\t\t/*\n-\t\t * is this frame a control packet we should take care of at this\n-\t\t * layer? If so service it and hide it from the user callback\n-\t\t */\n-\n-\t\tlwsl_parser(\u0022spill on %s\u005cn\u0022, wsi-\u003eprotocol-\u003ename);\n-\n-\t\tswitch (wsi-\u003eu.ws.opcode) {\n-\t\tcase LWSWSOPC_CLOSE:\n-\n-\t\t\t/* is this an acknowledgement of our close? */\n-\t\t\tif (wsi-\u003estate \u003d\u003d LWSS_AWAITING_CLOSE_ACK) {\n-\t\t\t\t/*\n-\t\t\t\t * fine he has told us he is closing too, let's\n-\t\t\t\t * finish our close\n-\t\t\t\t */\n-\t\t\t\tlwsl_parser(\u0022seen client close ack\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\tif (wsi-\u003estate \u003d\u003d LWSS_RETURNED_CLOSE_ALREADY)\n-\t\t\t\t/* if he sends us 2 CLOSE, kill him */\n-\t\t\t\treturn -1;\n-\n-\t\t\tif (lws_partial_buffered(wsi)) {\n-\t\t\t\t/*\n-\t\t\t\t * if we're in the middle of something,\n-\t\t\t\t * we can't do a normal close response and\n-\t\t\t\t * have to just close our end.\n-\t\t\t\t */\n-\t\t\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n-\t\t\t\tlwsl_parser(\u0022Closing on peer close due to Pending tx\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t\tif (user_callback_handle_rxflow(\n-\t\t\t\t\twsi-\u003eprotocol-\u003ecallback, wsi,\n-\t\t\t\t\tLWS_CALLBACK_WS_PEER_INITIATED_CLOSE,\n-\t\t\t\t\twsi-\u003euser_space,\n-\t\t\t\t\t\u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n-\t\t\t\t\twsi-\u003eu.ws.rx_ubuf_head))\n-\t\t\t\treturn -1;\n-\n-\t\t\tlwsl_parser(\u0022server sees client close packet\u005cn\u0022);\n-\t\t\twsi-\u003estate \u003d LWSS_RETURNED_CLOSE_ALREADY;\n-\t\t\t/* deal with the close packet contents as a PONG */\n-\t\t\twsi-\u003eu.ws.payload_is_close \u003d 1;\n-\t\t\tgoto process_as_ping;\n-\n-\t\tcase LWSWSOPC_PING:\n-\t\t\tlwsl_info(\u0022received %d byte ping, sending pong\u005cn\u0022,\n-\t\t\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n-\n-\t\t\tif (wsi-\u003eu.ws.ping_pending_flag) {\n-\t\t\t\t/*\n-\t\t\t\t * there is already a pending ping payload\n-\t\t\t\t * we should just log and drop\n-\t\t\t\t */\n-\t\t\t\tlwsl_parser(\u0022DROP PING since one pending\u005cn\u0022);\n-\t\t\t\tgoto ping_drop;\n-\t\t\t}\n-process_as_ping:\n-\t\t\t/* control packets can only be \u003c 128 bytes long */\n-\t\t\tif (wsi-\u003eu.ws.rx_ubuf_head \u003e 128 - 3) {\n-\t\t\t\tlwsl_parser(\u0022DROP PING payload too large\u005cn\u0022);\n-\t\t\t\tgoto ping_drop;\n-\t\t\t}\n-\n-\t\t\t/* stash the pong payload */\n-\t\t\tmemcpy(wsi-\u003eu.ws.ping_payload_buf + LWS_PRE,\n-\t\t\t \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n-\t\t\t\twsi-\u003eu.ws.rx_ubuf_head);\n-\n-\t\t\twsi-\u003eu.ws.ping_payload_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n-\t\t\twsi-\u003eu.ws.ping_pending_flag \u003d 1;\n-\n-\t\t\t/* get it sent as soon as possible */\n-\t\t\tlws_callback_on_writable(wsi);\n-ping_drop:\n-\t\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n-\t\t\treturn 0;\n-\n-\t\tcase LWSWSOPC_PONG:\n-\t\t\tlwsl_info(\u0022received pong\u005cn\u0022);\n-\t\t\tlwsl_hexdump(\u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n-\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n-\n-\t\t\tif (wsi-\u003epending_timeout \u003d\u003d PENDING_TIMEOUT_WS_PONG_CHECK_GET_PONG) {\n-\t\t\t\tlwsl_info(\u0022received expected PONG on wsi %p\u005cn\u0022, wsi);\n-\t\t\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\t\t\t}\n-\n-\t\t\t/* issue it */\n-\t\t\tcallback_action \u003d LWS_CALLBACK_RECEIVE_PONG;\n-\t\t\tbreak;\n-\n-\t\tcase LWSWSOPC_TEXT_FRAME:\n-\t\tcase LWSWSOPC_BINARY_FRAME:\n-\t\tcase LWSWSOPC_CONTINUATION:\n-\t\t\tbreak;\n-\n-\t\tdefault:\n-\t\t\tlwsl_parser(\u0022passing opc %x up to exts\u005cn\u0022,\n-\t\t\t\t wsi-\u003eu.ws.opcode);\n-\t\t\t/*\n-\t\t\t * It's something special we can't understand here.\n-\t\t\t * Pass the payload up to the extension's parsing\n-\t\t\t * state machine.\n-\t\t\t */\n-\n-\t\t\teff_buf.token \u003d \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n-\t\t\teff_buf.token_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n-\n-\t\t\tif (lws_ext_cb_active(wsi, LWS_EXT_CB_EXTENDED_PAYLOAD_RX,\n-\t\t\t\t\t \u0026eff_buf, 0) \u003c\u003d 0)\n-\t\t\t\t/* not handle or fail */\n-\t\t\t\tlwsl_ext(\u0022ext opc opcode 0x%x unknown\u005cn\u0022,\n-\t\t\t\t\t wsi-\u003eu.ws.opcode);\n-\n-\t\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n-\t\t\treturn 0;\n-\t\t}\n-\n-\t\t/*\n-\t\t * No it's real payload, pass it up to the user callback.\n-\t\t * It's nicely buffered with the pre-padding taken care of\n-\t\t * so it can be sent straight out again using lws_write\n-\t\t */\n-\n-\t\teff_buf.token \u003d \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n-\t\teff_buf.token_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n-\n-\t\tif (wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_PONG \u0026\u0026 !eff_buf.token_len)\n-\t\t\tgoto already_done;\n-\n-drain_extension:\n-\t\tlwsl_ext(\u0022%s: passing %d to ext\u005cn\u0022, __func__, eff_buf.token_len);\n-\n-\t\tif (wsi-\u003estate \u003d\u003d LWSS_RETURNED_CLOSE_ALREADY ||\n-\t\t wsi-\u003estate \u003d\u003d LWSS_AWAITING_CLOSE_ACK)\n-\t\t\tgoto already_done;\n-\n-\t\tn \u003d lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, \u0026eff_buf, 0);\n-\t\t/*\n-\t\t * eff_buf may be pointing somewhere completely different now,\n-\t\t * it's the output\n-\t\t */\n-\t\twsi-\u003eu.ws.first_fragment \u003d 0;\n-\t\tif (n \u003c 0) {\n-\t\t\t/*\n-\t\t\t * we may rely on this to get RX, just drop connection\n-\t\t\t */\n-\t\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tif (rx_draining_ext \u0026\u0026 eff_buf.token_len \u003d\u003d 0)\n-\t\t\tgoto already_done;\n-\n-\t\tif (n \u0026\u0026 eff_buf.token_len)\n-\t\t\t/* extension had more... main loop will come back */\n-\t\t\tlws_add_wsi_to_draining_ext_list(wsi);\n-\t\telse\n-\t\t\tlws_remove_wsi_from_draining_ext_list(wsi);\n-\n-\t\tif (eff_buf.token_len \u003e 0 ||\n-\t\t callback_action \u003d\u003d LWS_CALLBACK_RECEIVE_PONG) {\n-\t\t\teff_buf.token[eff_buf.token_len] \u003d '\u005c0';\n-\n-\t\t\tif (wsi-\u003eprotocol-\u003ecallback) {\n-\n-\t\t\t\tif (callback_action \u003d\u003d LWS_CALLBACK_RECEIVE_PONG)\n-\t\t\t\t\tlwsl_info(\u0022Doing pong callback\u005cn\u0022);\n-\n-\t\t\t\tret \u003d user_callback_handle_rxflow(\n-\t\t\t\t\t\twsi-\u003eprotocol-\u003ecallback,\n-\t\t\t\t\t\twsi,\n-\t\t\t\t\t\t(enum lws_callback_reasons)callback_action,\n-\t\t\t\t\t\twsi-\u003euser_space,\n-\t\t\t\t\t\teff_buf.token,\n-\t\t\t\t\t\teff_buf.token_len);\n-\t\t\t}\n-\t\t\telse\n-\t\t\t\tlwsl_err(\u0022No callback on payload spill!\u005cn\u0022);\n-\t\t}\n-\n-already_done:\n-\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n-\t\tbreak;\n-\t}\n-\n-\treturn ret;\n-\n-illegal_ctl_length:\n-\n-\tlwsl_warn(\u0022Control frame with xtended length is illegal\u005cn\u0022);\n-\t/* kill the connection */\n-\treturn -1;\n-}\n-\n-LWS_VISIBLE size_t\n-lws_remaining_packet_payload(struct lws *wsi)\n-{\n-\treturn wsi-\u003eu.ws.rx_packet_length;\n-}\n-\n-/* Once we reach LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED, we know how much\n- * to expect in that state and can deal with it in bulk more efficiently.\n- */\n-\n-int\n-lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf,\n-\t\t\t\t size_t *len)\n-{\n-\tunsigned char *buffer \u003d *buf, mask[4];\n-\tint buffer_size, n;\n-\tunsigned int avail;\n-\tchar *rx_ubuf;\n-\n-\tif (wsi-\u003eprotocol-\u003erx_buffer_size)\n-\t\tbuffer_size \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n-\telse\n-\t\tbuffer_size \u003d wsi-\u003econtext-\u003ept_serv_buf_size;\n-\tavail \u003d buffer_size - wsi-\u003eu.ws.rx_ubuf_head;\n-\n-\t/* do not consume more than we should */\n-\tif (avail \u003e wsi-\u003eu.ws.rx_packet_length)\n-\t\tavail \u003d wsi-\u003eu.ws.rx_packet_length;\n-\n-\t/* do not consume more than what is in the buffer */\n-\tif (avail \u003e *len)\n-\t\tavail \u003d *len;\n-\n-\t/* we want to leave 1 byte for the parser to handle properly */\n-\tif (avail \u003c\u003d 1)\n-\t\treturn 0;\n-\n-\tavail--;\n-\trx_ubuf \u003d wsi-\u003eu.ws.rx_ubuf + LWS_PRE + wsi-\u003eu.ws.rx_ubuf_head;\n-\tif (wsi-\u003eu.ws.all_zero_nonce)\n-\t\tmemcpy(rx_ubuf, buffer, avail);\n-\telse {\n-\n-\t\tfor (n \u003d 0; n \u003c 4; n++)\n-\t\t\tmask[n] \u003d wsi-\u003eu.ws.mask[(wsi-\u003eu.ws.mask_idx + n) \u0026 3];\n-\n-\t\t/* deal with 4-byte chunks using unwrapped loop */\n-\t\tn \u003d avail \u003e\u003e 2;\n-\t\twhile (n--) {\n-\t\t\t*(rx_ubuf++) \u003d *(buffer++) ^ mask[0];\n-\t\t\t*(rx_ubuf++) \u003d *(buffer++) ^ mask[1];\n-\t\t\t*(rx_ubuf++) \u003d *(buffer++) ^ mask[2];\n-\t\t\t*(rx_ubuf++) \u003d *(buffer++) ^ mask[3];\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*(rx_ubuf++) \u003d *(buffer++) ^ mask[n];\n-\n-\t\twsi-\u003eu.ws.mask_idx \u003d (wsi-\u003eu.ws.mask_idx + avail) \u0026 3;\n-\t}\n-\n-\t(*buf) +\u003d avail;\n-\twsi-\u003eu.ws.rx_ubuf_head +\u003d avail;\n-\twsi-\u003eu.ws.rx_packet_length -\u003d avail;\n-\t*len -\u003d avail;\n-\n-\treturn avail;\n-}\ndiff --git a/lib/plat/lws-plat-esp32.c b/lib/plat/lws-plat-esp32.c\nnew file mode 100644\nindex 0000000..b5adabe\n--- /dev/null\n+++ b/lib/plat/lws-plat-esp32.c\n@@ -0,0 +1,1756 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+#include \u0022freertos/timers.h\u0022\n+#include \u003cesp_attr.h\u003e\n+#include \u003cesp_system.h\u003e\n+\n+/*\n+ * included from libwebsockets.c for unix builds\n+ */\n+\n+unsigned long long time_in_microseconds(void)\n+{\n+\tstruct timeval tv;\n+\tgettimeofday(\u0026tv, NULL);\n+\treturn ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;\n+}\n+\n+LWS_VISIBLE int\n+lws_get_random(struct lws_context *context, void *buf, int len)\n+{\n+\tuint8_t *pb \u003d buf;\n+\n+\twhile (len) {\n+\t\tuint32_t r \u003d esp_random();\n+\t\tuint8_t *p \u003d (uint8_t *)\u0026r;\n+\t\tint b \u003d 4;\n+\n+\t\tif (len \u003c b)\n+\t\t\tb \u003d len;\n+\n+\t\tlen -\u003d b;\n+\n+\t\twhile (b--)\n+\t\t\t*pb++ \u003d p[b];\n+\t}\n+\n+\treturn pb - (uint8_t *)buf;\n+}\n+\n+LWS_VISIBLE int\n+lws_send_pipe_choked(struct lws *wsi)\n+{\n+\tstruct lws *wsi_eff \u003d wsi;\n+\tfd_set writefds;\n+\tstruct timeval tv \u003d { 0, 0 };\n+#if defined(LWS_WITH_HTTP2)\n+\twsi_eff \u003d lws_get_network_wsi(wsi);\n+#endif\n+\n+\t/* treat the fact we got a truncated send pending as if we're choked */\n+\tif (wsi_eff-\u003etrunc_len)\n+\t\treturn 1;\n+\n+\tFD_ZERO(\u0026writefds);\n+\tFD_SET(wsi_eff-\u003edesc.sockfd, \u0026writefds);\n+\n+\tif (select(wsi_eff-\u003edesc.sockfd + 1, NULL, \u0026writefds, NULL, \u0026tv) \u003c 1)\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_poll_listen_fd(struct lws_pollfd *fd)\n+{\n+\tfd_set readfds;\n+\tstruct timeval tv \u003d { 0, 0 };\n+\n+\tFD_ZERO(\u0026readfds);\n+\tFD_SET(fd-\u003efd, \u0026readfds);\n+\n+\treturn select(fd-\u003efd + 1, \u0026readfds, NULL, NULL, \u0026tv);\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service_pt(struct lws *wsi)\n+{\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n+{\n+\tprintf(\u0022%d: %s\u0022, level, line);\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n+{\n+\tstruct lws_context_per_thread *pt;\n+\tint n \u003d -1, m, c;\n+\n+\t/* stay dead once we are dead */\n+\n+\tif (!context || !context-\u003evhost_list)\n+\t\treturn 1;\n+\n+\tpt \u003d \u0026context-\u003ept[tsi];\n+\tlws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);\n+\n+\t{\n+\t\tunsigned long m \u003d lws_now_secs();\n+\n+\t\tif (m \u003e context-\u003etime_last_state_dump) {\n+\t\t\tcontext-\u003etime_last_state_dump \u003d m;\n+\t\t\tn \u003d esp_get_free_heap_size();\n+\t\t\tif (n !\u003d context-\u003elast_free_heap) {\n+\t\t\t\tif (n \u003e context-\u003elast_free_heap)\n+\t\t\t\t\tlwsl_notice(\u0022 heap :%d (+%d)\u005cn\u0022, n,\n+\t\t\t\t\t\t n - context-\u003elast_free_heap);\n+\t\t\t\telse\n+\t\t\t\t\tlwsl_notice(\u0022 heap :%d (-%d)\u005cn\u0022, n,\n+\t\t\t\t\t\t context-\u003elast_free_heap - n);\n+\t\t\t\tcontext-\u003elast_free_heap \u003d n;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (timeout_ms \u003c 0)\n+\t\tgoto faked_service;\n+\n+\tif (!context-\u003eservice_tid_detected) {\n+\t\tstruct lws _lws;\n+\n+\t\tmemset(\u0026_lws, 0, sizeof(_lws));\n+\t\t_lws.context \u003d context;\n+\n+\t\tcontext-\u003eservice_tid_detected \u003d\n+\t\t\tcontext-\u003evhost_list-\u003eprotocols[0].callback(\n+\t\t\t\u0026_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);\n+\t}\n+\tcontext-\u003eservice_tid \u003d context-\u003eservice_tid_detected;\n+\n+\t/*\n+\t * is there anybody with pending stuff that needs service forcing?\n+\t */\n+\tif (!lws_service_adjust_timeout(context, 1, tsi)) {\n+\t\t/* -1 timeout means just do forced service */\n+\t\t_lws_plat_service_tsi(context, -1, pt-\u003etid);\n+\t\t/* still somebody left who wants forced service? */\n+\t\tif (!lws_service_adjust_timeout(context, 1, pt-\u003etid))\n+\t\t\t/* yes... come back again quickly */\n+\t\t\ttimeout_ms \u003d 0;\n+\t}\n+\n+//\tn \u003d poll(pt-\u003efds, pt-\u003efds_count, timeout_ms);\n+\t{\n+\t\tfd_set readfds, writefds, errfds;\n+\t\tstruct timeval tv \u003d { timeout_ms / 1000,\n+\t\t\t\t (timeout_ms % 1000) * 1000 }, *ptv \u003d \u0026tv;\n+\t\tint max_fd \u003d 0;\n+\t\tFD_ZERO(\u0026readfds);\n+\t\tFD_ZERO(\u0026writefds);\n+\t\tFD_ZERO(\u0026errfds);\n+\n+\t\tfor (n \u003d 0; n \u003c pt-\u003efds_count; n++) {\n+\t\t\tpt-\u003efds[n].revents \u003d 0;\n+\t\t\tif (pt-\u003efds[n].fd \u003e\u003d max_fd)\n+\t\t\t\tmax_fd \u003d pt-\u003efds[n].fd;\n+\t\t\tif (pt-\u003efds[n].events \u0026 LWS_POLLIN)\n+\t\t\t\tFD_SET(pt-\u003efds[n].fd, \u0026readfds);\n+\t\t\tif (pt-\u003efds[n].events \u0026 LWS_POLLOUT)\n+\t\t\t\tFD_SET(pt-\u003efds[n].fd, \u0026writefds);\n+\t\t\tFD_SET(pt-\u003efds[n].fd, \u0026errfds);\n+\t\t}\n+\n+\t\tn \u003d select(max_fd + 1, \u0026readfds, \u0026writefds, \u0026errfds, ptv);\n+\t\tfor (n \u003d 0; n \u003c pt-\u003efds_count; n++) {\n+\t\t\tif (FD_ISSET(pt-\u003efds[n].fd, \u0026readfds))\n+\t\t\t\tpt-\u003efds[n].revents |\u003d LWS_POLLIN;\n+\t\t\tif (FD_ISSET(pt-\u003efds[n].fd, \u0026writefds))\n+\t\t\t\tpt-\u003efds[n].revents |\u003d LWS_POLLOUT;\n+\t\t\tif (FD_ISSET(pt-\u003efds[n].fd, \u0026errfds))\n+\t\t\t\tpt-\u003efds[n].revents |\u003d LWS_POLLHUP;\n+\t\t}\n+\t}\n+\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\tif (!pt-\u003erx_draining_ext_list \u0026\u0026\n+\t !lws_ssl_anybody_has_buffered_read_tsi(context, tsi) \u0026\u0026 !n) {\n+#else\n+\tif (!pt-\u003erx_draining_ext_list \u0026\u0026 !n) /* poll timeout */ {\n+#endif\n+\t\tlws_service_fd_tsi(context, NULL, tsi);\n+\t\treturn 0;\n+\t}\n+\n+faked_service:\n+\tm \u003d lws_service_flag_pending(context, tsi);\n+\tif (m)\n+\t\tc \u003d -1; /* unknown limit */\n+\telse\n+\t\tif (n \u003c 0) {\n+\t\t\tif (LWS_ERRNO !\u003d LWS_EINTR)\n+\t\t\t\treturn -1;\n+\t\t\treturn 0;\n+\t\t} else\n+\t\t\tc \u003d n;\n+\n+\t/* any socket with events to service? */\n+\tfor (n \u003d 0; n \u003c pt-\u003efds_count \u0026\u0026 c; n++) {\n+\t\tif (!pt-\u003efds[n].revents)\n+\t\t\tcontinue;\n+\n+\t\tc--;\n+\n+\t\tm \u003d lws_service_fd_tsi(context, \u0026pt-\u003efds[n], tsi);\n+\t\tif (m \u003c 0)\n+\t\t\treturn -1;\n+\t\t/* if something closed, retry this slot */\n+\t\tif (m)\n+\t\t\tn--;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_check_connection_error(struct lws *wsi)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_service(struct lws_context *context, int timeout_ms)\n+{\n+\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)\n+{\n+\tint optval \u003d 1;\n+\tsocklen_t optlen \u003d sizeof(optval);\n+\n+#if defined(__APPLE__) || \u005c\n+ defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \u005c\n+ defined(__NetBSD__) || \u005c\n+ defined(__OpenBSD__)\n+\tstruct protoent *tcp_proto;\n+#endif\n+\n+\tif (vhost-\u003eka_time) {\n+\t\t/* enable keepalive on this socket */\n+\t\toptval \u003d 1;\n+\t\tif (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,\n+\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n+\t\t\treturn 1;\n+\n+#if defined(__APPLE__) || \u005c\n+ defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \u005c\n+ defined(__NetBSD__) || \u005c\n+ defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun)\n+\n+\t\t/*\n+\t\t * didn't find a way to set these per-socket, need to\n+\t\t * tune kernel systemwide values\n+\t\t */\n+#else\n+\t\t/* set the keepalive conditions we want on it too */\n+\t\toptval \u003d vhost-\u003eka_time;\n+\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,\n+\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n+\t\t\treturn 1;\n+\n+\t\toptval \u003d vhost-\u003eka_interval;\n+\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,\n+\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n+\t\t\treturn 1;\n+\n+\t\toptval \u003d vhost-\u003eka_probes;\n+\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,\n+\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n+\t\t\treturn 1;\n+#endif\n+\t}\n+\n+\t/* Disable Nagle */\n+\toptval \u003d 1;\n+\tif (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, \u0026optval, optlen) \u003c 0)\n+\t\treturn 1;\n+\n+\t/* We are nonblocking... */\n+\tif (fcntl(fd, F_SETFL, O_NONBLOCK) \u003c 0)\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n+{\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_context_early_init(void)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_early_destroy(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_late_destroy(struct lws_context *context)\n+{\n+#ifdef LWS_WITH_PLUGINS\n+\tif (context-\u003eplugin_list)\n+\t\tlws_plat_plugins_destroy(context);\n+#endif\n+\n+\tif (context-\u003elws_lookup)\n+\t\tlws_free(context-\u003elws_lookup);\n+}\n+\n+/* cast a struct sockaddr_in6 * into addr for ipv6 */\n+\n+LWS_VISIBLE int\n+lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,\n+\t\t size_t addrlen)\n+{\n+#if 0\n+\tint rc \u003d -1;\n+\n+\tstruct ifaddrs *ifr;\n+\tstruct ifaddrs *ifc;\n+#ifdef LWS_WITH_IPV6\n+\tstruct sockaddr_in6 *addr6 \u003d (struct sockaddr_in6 *)addr;\n+#endif\n+\n+\tgetifaddrs(\u0026ifr);\n+\tfor (ifc \u003d ifr; ifc !\u003d NULL \u0026\u0026 rc; ifc \u003d ifc-\u003eifa_next) {\n+\t\tif (!ifc-\u003eifa_addr)\n+\t\t\tcontinue;\n+\n+\t\tlwsl_info(\u0022 interface %s vs %s\u005cn\u0022, ifc-\u003eifa_name, ifname);\n+\n+\t\tif (strcmp(ifc-\u003eifa_name, ifname))\n+\t\t\tcontinue;\n+\n+\t\tswitch (ifc-\u003eifa_addr-\u003esa_family) {\n+\t\tcase AF_INET:\n+#ifdef LWS_WITH_IPV6\n+\t\t\tif (ipv6) {\n+\t\t\t\t/* map IPv4 to IPv6 */\n+\t\t\t\tbzero((char *)\u0026addr6-\u003esin6_addr,\n+\t\t\t\t\t\tsizeof(struct in6_addr));\n+\t\t\t\taddr6-\u003esin6_addr.s6_addr[10] \u003d 0xff;\n+\t\t\t\taddr6-\u003esin6_addr.s6_addr[11] \u003d 0xff;\n+\t\t\t\tmemcpy(\u0026addr6-\u003esin6_addr.s6_addr[12],\n+\t\t\t\t\t\u0026((struct sockaddr_in *)ifc-\u003eifa_addr)-\u003esin_addr,\n+\t\t\t\t\t\t\tsizeof(struct in_addr));\n+\t\t\t} else\n+#endif\n+\t\t\t\tmemcpy(addr,\n+\t\t\t\t\t(struct sockaddr_in *)ifc-\u003eifa_addr,\n+\t\t\t\t\t\t sizeof(struct sockaddr_in));\n+\t\t\tbreak;\n+#ifdef LWS_WITH_IPV6\n+\t\tcase AF_INET6:\n+\t\t\tmemcpy(\u0026addr6-\u003esin6_addr,\n+\t\t\t \u0026((struct sockaddr_in6 *)ifc-\u003eifa_addr)-\u003esin6_addr,\n+\t\t\t\t\t\t sizeof(struct in6_addr));\n+\t\t\tbreak;\n+#endif\n+\t\tdefault:\n+\t\t\tcontinue;\n+\t\t}\n+\t\trc \u003d 0;\n+\t}\n+\n+\tfreeifaddrs(ifr);\n+\n+\tif (rc \u003d\u003d -1) {\n+\t\t/* check if bind to IP address */\n+#ifdef LWS_WITH_IPV6\n+\t\tif (inet_pton(AF_INET6, ifname, \u0026addr6-\u003esin6_addr) \u003d\u003d 1)\n+\t\t\trc \u003d 0;\n+\t\telse\n+#endif\n+\t\tif (inet_pton(AF_INET, ifname, \u0026addr-\u003esin_addr) \u003d\u003d 1)\n+\t\t\trc \u003d 0;\n+\t}\n+\n+\treturn rc;\n+#endif\n+\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\n+\tpt-\u003efds[pt-\u003efds_count++].revents \u003d 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_delete_socket_from_fds(struct lws_context *context,\n+\t\t\t\t\t\tstruct lws *wsi, int m)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\n+\tpt-\u003efds_count--;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_service_periodic(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_change_pollfd(struct lws_context *context,\n+\t\t struct lws *wsi, struct lws_pollfd *pfd)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE const char *\n+lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n+{\n+\treturn inet_ntop(af, src, dst, cnt);\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_inet_pton(int af, const char *src, void *dst)\n+{\n+\treturn 1; // inet_pton(af, src, dst);\n+}\n+\n+LWS_VISIBLE lws_fop_fd_t IRAM_ATTR\n+_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,\n+\t\t const char *vpath, lws_fop_flags_t *flags)\n+{\n+\tstruct stat stat_buf;\n+\tlws_fop_fd_t fop_fd;\n+\tint ret \u003d open(filename, *flags, 0664);\n+\n+\tif (ret \u003c 0)\n+\t\treturn NULL;\n+\n+\tif (fstat(ret, \u0026stat_buf) \u003c 0)\n+\t\tgoto bail;\n+\n+\tfop_fd \u003d lws_malloc(sizeof(*fop_fd), \u0022fops open\u0022);\n+\tif (!fop_fd)\n+\t\tgoto bail;\n+\n+\tfop_fd-\u003efops \u003d fops;\n+\tfop_fd-\u003efd \u003d ret;\n+\tfop_fd-\u003eflags \u003d *flags;\n+\tfop_fd-\u003efilesystem_priv \u003d NULL; /* we don't use it */\n+\tfop_fd-\u003epos \u003d 0;\n+\tfop_fd-\u003elen \u003d stat_buf.st_size;\n+\n+\treturn fop_fd;\n+\n+bail:\n+\tclose(ret);\n+\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE int IRAM_ATTR\n+_lws_plat_file_close(lws_fop_fd_t *fops_fd)\n+{\n+\tint fd \u003d (*fops_fd)-\u003efd;\n+\n+\tlws_free(*fops_fd);\n+\t*fops_fd \u003d NULL;\n+\n+\treturn close(fd);\n+}\n+\n+LWS_VISIBLE lws_fileofs_t IRAM_ATTR\n+_lws_plat_file_seek_cur(lws_fop_fd_t fops_fd, lws_fileofs_t offset)\n+{\n+\treturn lseek(fops_fd-\u003efd, offset, SEEK_CUR);\n+}\n+\n+LWS_VISIBLE int IRAM_ATTR\n+_lws_plat_file_read(lws_fop_fd_t fops_fd, lws_filepos_t *amount,\n+\t\t uint8_t *buf, lws_filepos_t len)\n+{\n+\tlong n;\n+\n+\tn \u003d read(fops_fd-\u003efd, buf, len);\n+\tif (n \u003d\u003d -1) {\n+\t\t*amount \u003d 0;\n+\t\treturn -1;\n+\t}\n+\tfops_fd-\u003epos +\u003d n;\n+\t*amount \u003d n;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int IRAM_ATTR\n+_lws_plat_file_write(lws_fop_fd_t fops_fd, lws_filepos_t *amount,\n+\t\t uint8_t *buf, lws_filepos_t len)\n+{\n+\tlong n;\n+\n+\tn \u003d write(fops_fd-\u003efd, buf, len);\n+\tif (n \u003d\u003d -1) {\n+\t\t*amount \u003d 0;\n+\t\treturn -1;\n+\t}\n+\tfops_fd-\u003epos +\u003d n;\n+\t*amount \u003d n;\n+\n+\treturn 0;\n+}\n+\n+#if defined(LWS_WITH_HTTP2)\n+/*\n+ * These are the default SETTINGS used on this platform. The user\n+ * can selectively modify them for a vhost during vhost creation.\n+ */\n+const struct http2_settings const lws_h2_defaults_esp32 \u003d { {\n+\t1,\n+\t/* H2SET_HEADER_TABLE_SIZE */\t\t\t 512,\n+\t/* H2SET_ENABLE_PUSH */\t\t\t\t 0,\n+\t/* H2SET_MAX_CONCURRENT_STREAMS */\t\t 8,\n+\t/* H2SET_INITIAL_WINDOW_SIZE */\t\t 65535,\n+\t/* H2SET_MAX_FRAME_SIZE */\t\t 16384,\n+\t/* H2SET_MAX_HEADER_LIST_SIZE */\t \t 512,\n+}};\n+#endif\n+\n+LWS_VISIBLE int\n+lws_plat_init(struct lws_context *context,\n+\t struct lws_context_creation_info *info)\n+{\n+\t/* master context has the global fd lookup array */\n+\tcontext-\u003elws_lookup \u003d lws_zalloc(sizeof(struct lws *) *\n+\t\t\t\t\t context-\u003emax_fds, \u0022esp32 lws_lookup\u0022);\n+\tif (context-\u003elws_lookup \u003d\u003d NULL) {\n+\t\tlwsl_err(\u0022OOM on lws_lookup array for %d connections\u005cn\u0022,\n+\t\t\t context-\u003emax_fds);\n+\t\treturn 1;\n+\t}\n+\n+\tlwsl_notice(\u0022 mem: platform fd map: %5lu bytes\u005cn\u0022,\n+\t\t (unsigned long)(sizeof(struct lws *) * context-\u003emax_fds));\n+\n+#ifdef LWS_WITH_PLUGINS\n+\tif (info-\u003eplugin_dirs)\n+\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n+#endif\n+#if defined(LWS_WITH_HTTP2)\n+\t/* override settings */\n+\tcontext-\u003eset \u003d lws_h2_defaults_esp32;\n+#endif\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void esp32_uvtimer_cb(TimerHandle_t t)\n+{\n+\tstruct timer_mapping *p \u003d pvTimerGetTimerID(t);\n+\n+\tp-\u003ecb(p-\u003et);\n+}\n+\n+/* helper functionality */\n+\n+#include \u0022romfs.h\u0022\n+#include \u003cesp_ota_ops.h\u003e\n+#include \u003ctcpip_adapter.h\u003e\n+#include \u003cesp_image_format.h\u003e\n+#include \u003cesp_task_wdt.h\u003e\n+#include \u0022soc/ledc_reg.h\u0022\n+#include \u0022driver/ledc.h\u0022\n+\n+struct lws_esp32 lws_esp32 \u003d {\n+\t.model \u003d CONFIG_LWS_MODEL_NAME,\n+\t.serial \u003d \u0022unknown\u0022,\n+\t.region \u003d WIFI_COUNTRY_US, // default to safest option\n+};\n+\n+/*\n+ * Group AP / Station State\n+ */\n+\n+enum lws_gapss {\n+\tLWS_GAPSS_INITIAL,\t/* just started up, init and move to LWS_GAPSS_SCAN */\n+\tLWS_GAPSS_SCAN,\t\t/*\n+\t\t\t\t * Unconnected, scanning: AP known in one of the config\n+\t\t\t\t * slots -\u003e configure it, start timeout + LWS_GAPSS_STAT,\n+\t\t\t\t * if no AP already up in same group with lower MAC,\n+\t\t\t\t * after a random period start up our AP (LWS_GAPSS_AP)\n+\t\t\t\t */\n+\tLWS_GAPSS_AP,\t\t/*\n+\t\t\t\t * Trying to be the group AP... periodically do a scan\n+\t\t\t\t * LWS_GAPSS_AP_SCAN, faster and then slower\n+ \t\t\t\t */\n+\tLWS_GAPSS_AP_SCAN,\t/*\n+\t\t\t\t * doing a scan while trying to be the group AP... if\n+\t\t\t\t * we see a lower MAC being the AP for the same group\n+\t\t\t\t * AP, abandon being an AP and join that AP as a\n+\t\t\t\t * station\n+\t\t\t\t */\n+\tLWS_GAPSS_STAT_GRP_AP,\t/*\n+\t\t\t\t * We have decided to join another group member who is\n+\t\t\t\t * being the AP, as its MAC is lower than ours. This\n+\t\t\t\t * is a stable state, but we still do periodic scans\n+\t\t\t\t * (LWS_GAPSS_STAT_GRP_AP_SCAN) and will always prefer\n+\t\t\t\t * an AP configured in a slot.\n+\t\t\t\t */\n+\tLWS_GAPSS_STAT_GRP_AP_SCAN,\n+\t\t\t\t/*\n+\t\t\t\t * We have joined a group member who is doing the AP\n+\t\t\t\t * job... we want to check every now and then if a\n+\t\t\t\t * configured AP has appeared that we should better\n+\t\t\t\t * use instead. Otherwise stay in LWS_GAPSS_STAT_GRP_AP\n+\t\t\t\t */\n+\tLWS_GAPSS_STAT,\t\t/*\n+\t\t\t\t * trying to connect to another non-group AP. If we\n+\t\t\t\t * don't get an IP within a timeout and retries,\n+\t\t\t\t * blacklist it and go back \n+\t\t\t\t */\n+\tLWS_GAPSS_STAT_HAPPY,\n+};\n+\n+static const char *gapss_str[] \u003d {\n+\t\u0022LWS_GAPSS_INITIAL\u0022,\n+ \u0022LWS_GAPSS_SCAN\u0022,\n+ \u0022LWS_GAPSS_AP\u0022,\n+ \u0022LWS_GAPSS_AP_SCAN\u0022,\n+ \u0022LWS_GAPSS_STAT_GRP_AP\u0022,\n+ \u0022LWS_GAPSS_STAT_GRP_AP_SCAN\u0022,\n+ \u0022LWS_GAPSS_STAT\u0022,\n+\t\u0022LWS_GAPSS_STAT_HAPPY\u0022,\n+};\n+\n+static romfs_t lws_esp32_romfs;\n+static TimerHandle_t leds_timer, scan_timer, debounce_timer\n+#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n+, mdns_timer\n+#endif\n+;\n+static enum lws_gapss gapss \u003d LWS_GAPSS_INITIAL;\n+static char bdown;\n+\n+#define GPIO_SW 14\n+\n+struct esp32_file {\n+\tconst struct inode *i;\n+};\n+\n+static void lws_gapss_to(enum lws_gapss to)\n+{\n+\tlwsl_notice(\u0022gapss from %s to %s\u005cn\u0022, gapss_str[gapss], gapss_str[to]);\n+\tgapss \u003d to;\n+}\n+\n+uint32_t lws_esp32_get_reboot_type(void)\n+{\n+\tuint32_t *p \u003d (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS, val \u003d *p;\n+\tnvs_handle nvh;\n+\tsize_t s \u003d 0;\n+\tint n \u003d 0;\n+\n+\tESP_ERROR_CHECK(nvs_open(\u0022lws-station\u0022, NVS_READWRITE, \u0026nvh));\n+\tif (nvs_get_blob(nvh, \u0022ssl-pub.pem\u0022, NULL, \u0026s) \u003d\u003d ESP_OK)\n+\t\tn \u003d 1;\n+\tif (nvs_get_blob(nvh, \u0022ssl-pri.pem\u0022, NULL, \u0026s) \u003d\u003d ESP_OK)\n+\t\tn |\u003d 2;\n+\tnvs_close(nvh);\n+\n+\t/*\n+\t * in the case the SSL certs are not there, don't require\n+\t * the button to be down to access all features.\n+\t */\n+\tif (n !\u003d 3)\n+\t\tval \u003d LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON;\n+\n+\treturn val;\n+}\n+\n+static void render_ip(char *dest, int len, uint8_t *ip)\n+{\n+\tsnprintf(dest, len, \u0022%u.%u.%u.%u\u0022, ip[0], ip[1], ip[2], ip[3]);\n+}\n+\n+void lws_esp32_restart_guided(uint32_t type)\n+{\n+ uint32_t *p_force_factory_magic \u003d (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;\n+\n+\tlwsl_notice(\u0022%s: %x\u005cn\u0022, __func__, type);\n+ *p_force_factory_magic \u003d type;\n+\n+\tesp_restart();\n+}\n+\n+/*\n+ * esp-idf goes crazy with zero length str nvs. Use this as a workaround\n+ * to delete the key in that case.\n+ */\n+\n+esp_err_t lws_nvs_set_str(nvs_handle handle, const char* key, const char* value)\n+{\n+\tif (*value)\n+\t\treturn nvs_set_str(handle, key, value);\n+\n+\treturn nvs_erase_key(handle, key);\n+}\n+\n+static wifi_scan_config_t scan_config \u003d {\n+ .ssid \u003d 0,\n+ .bssid \u003d 0,\n+ .channel \u003d 0,\n+ .show_hidden \u003d true\n+};\n+\n+static char scan_ongoing \u003d 0, scan_timer_exists \u003d 0;\n+static int try_slot \u003d -1;\n+\n+static wifi_config_t config \u003d {\n+\t.ap \u003d {\n+\t .channel \u003d 6,\n+\t .authmode \u003d WIFI_AUTH_OPEN,\n+\t .max_connection \u003d 1,\n+\t} }, sta_config \u003d {\n+\t.sta \u003d {\n+\t\t.bssid_set \u003d 0,\n+\t} };\n+\n+static void lws_esp32_scan_timer_cb(TimerHandle_t th)\n+{\n+\tint n;\n+\n+\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n+\tscan_ongoing \u003d 0;\n+\tn \u003d esp_wifi_scan_start(\u0026scan_config, false);\n+\tif (n !\u003d ESP_OK)\n+\t\tlwsl_err(\u0022scan start failed %d\u005cn\u0022, n);\n+}\n+\n+#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n+\n+void __attribute__(( weak ))\n+lws_group_member_event(int e, void *p)\n+{\n+}\n+\n+void __attribute__(( weak ))\n+lws_get_iframe_size(int *w, int *h)\n+{\n+\t*w \u003d 320;\n+\t*h \u003d 160;\n+}\n+\n+void lws_group_member_event_call(int e, void *p)\n+{\n+\tlws_group_member_event(e, p);\n+}\n+\n+static int\n+get_txt_param(const char *txt, const char *param, char *result, int len)\n+{\n+\tconst char *p;\n+\n+again:\n+\tp \u003d strstr(txt, param);\n+\tif (!p) {\n+\t\t*result \u003d '\u005c0';\n+\t\treturn 1;\n+\t}\n+\n+\tp +\u003d strlen(param);\n+\tif (*p !\u003d '\u003d') {\n+\t\ttxt \u003d p;\n+\t\tgoto again;\n+\t}\n+\tp++;\n+\twhile (*p \u0026\u0026 *p !\u003d '\u0026' \u0026\u0026 --len)\n+\t\t*result++ \u003d *p++;\n+\n+\t*result \u003d '\u005c0';\n+\n+\treturn 0;\n+}\n+\n+static void lws_esp32_mdns_timer_cb(TimerHandle_t th)\n+{\n+\tuint64_t now \u003d time_in_microseconds(); \n+\tstruct lws_group_member *p, **p1;\n+\tconst mdns_result_t *r;\n+\tint n, m;\n+\n+\tif (!lws_esp32.mdns)\n+\t\treturn;\n+\tn \u003d mdns_query_end(lws_esp32.mdns);\n+\n+\tfor (m \u003d 0; m \u003c n; m++) {\n+\t\tchar ch \u003d 0, group[16];\n+\n+\t\tr \u003d mdns_result_get(lws_esp32.mdns, m);\n+\n+\t\tget_txt_param(r-\u003etxt, \u0022group\u0022, group, sizeof(group));\n+\t\tif (strcmp(group, lws_esp32.group)) /* not our group */ {\n+\t\t\tlwsl_notice(\u0022group %s vs %s %s\u005cn\u0022,\n+\t\t\t\t\tgroup, lws_esp32.group, r-\u003etxt);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tp \u003d lws_esp32.first;\n+\t\twhile (p) {\n+\t\t\tif (strcmp(r-\u003ehost, p-\u003ehost))\n+\t\t\t\tgoto next;\n+\t\t\tif (memcmp(\u0026r-\u003eaddr, \u0026p-\u003eaddr, sizeof(r-\u003eaddr)))\n+\t\t\t\tgoto next;\n+\n+\t\t\tp-\u003elast_seen \u003d now;\n+\t\t\tbreak;\n+next:\n+\t\t\tp \u003d p-\u003enext;\n+\t\t}\n+\t\tif (!p) { /* did not find */\n+\t\t\tchar temp[8];\n+\n+\t\t\tp \u003d lws_malloc(sizeof(*p), \u0022group\u0022);\n+\t\t\tif (!p)\n+\t\t\t\tcontinue;\n+\t\t\tstrncpy(p-\u003ehost, r-\u003ehost, sizeof(p-\u003ehost) - 1);\n+\t\t\tp-\u003ehost[sizeof(p-\u003ehost) - 1] \u003d '\u005c0';\n+\n+\t\t\tget_txt_param(r-\u003etxt, \u0022model\u0022, p-\u003emodel, sizeof(p-\u003emodel));\n+\t\t\tget_txt_param(r-\u003etxt, \u0022role\u0022, p-\u003erole, sizeof(p-\u003erole));\n+\t\t\tget_txt_param(r-\u003etxt, \u0022mac\u0022, p-\u003emac, sizeof(p-\u003emac));\n+\t\t\tget_txt_param(r-\u003etxt, \u0022width\u0022, temp, sizeof(temp));\n+\t\t\tp-\u003ewidth \u003d atoi(temp);\n+\t\t\tget_txt_param(r-\u003etxt, \u0022height\u0022, temp, sizeof(temp));\n+\t\t\tp-\u003eheight \u003d atoi(temp);\n+\n+\t\t\tmemcpy(\u0026p-\u003eaddr, \u0026r-\u003eaddr, sizeof(p-\u003eaddr));\n+\t\t\tmemcpy(\u0026p-\u003eaddrv6, \u0026r-\u003eaddrv6, sizeof(p-\u003eaddrv6));\n+\t\t\tp-\u003elast_seen \u003d now;\n+\t\t\tp-\u003eflags \u003d 0;\n+\t\t\tp-\u003enext \u003d lws_esp32.first;\n+\t\t\tlws_esp32.first \u003d p;\n+\t\t\tlws_esp32.extant_group_members++;\n+\n+\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_ADD, p);\n+\t\t} else {\n+\t\t\tif (memcmp(\u0026p-\u003eaddr, \u0026r-\u003eaddr, sizeof(p-\u003eaddr))) {\n+\t\t\t\tmemcpy(\u0026p-\u003eaddr, \u0026r-\u003eaddr, sizeof(p-\u003eaddr));\n+\t\t\t\tch \u003d 1;\n+\t\t\t}\n+\t\t\tif (memcmp(\u0026p-\u003eaddrv6, \u0026r-\u003eaddrv6, sizeof(p-\u003eaddrv6))) {\n+\t\t\t\tmemcpy(\u0026p-\u003eaddrv6, \u0026r-\u003eaddrv6, sizeof(p-\u003eaddrv6));\n+\t\t\t\tch \u003d 1;\n+\t\t\t}\n+\t\t\tif (ch)\n+\t\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_CHANGE, p);\n+\t\t}\n+\t}\n+\n+\tmdns_result_free(lws_esp32.mdns);\n+\n+\t/* garbage-collect group members not seen for too long */\n+\tp1 \u003d \u0026lws_esp32.first;\n+\twhile (*p1) {\n+\t\tp \u003d *p1;\n+\t\tif (!(p-\u003eflags \u0026 LWS_GROUP_FLAG_SELF) \u0026\u0026\n+\t\t\t\tnow - p-\u003elast_seen \u003e 60000000) {\n+\t\t\tlws_esp32.extant_group_members--;\n+\t\t\t*p1 \u003d p-\u003enext;\n+\n+\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_REMOVE, p);\n+\t\t\tlws_free(p);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tp1 \u003d \u0026(*p1)-\u003enext;\n+\t}\n+\n+\tmdns_query(lws_esp32.mdns, \u0022_lwsgrmem\u0022, \u0022_tcp\u0022, 0);\n+\txTimerStart(mdns_timer, 0);\n+}\n+#endif\n+\n+void __attribute__(( weak ))\n+lws_esp32_button(int down)\n+{\n+}\n+\n+void IRAM_ATTR\n+gpio_irq(void *arg)\n+{\n+\tbdown ^\u003d 1;\n+\tgpio_set_intr_type(GPIO_SW, GPIO_INTR_DISABLE);\n+\txTimerStart(debounce_timer, 0);\n+\n+\tlws_esp32_button(bdown);\n+}\n+\n+static void lws_esp32_debounce_timer_cb(TimerHandle_t th)\n+{\n+\tif (bdown)\n+\t\tgpio_set_intr_type(GPIO_SW, GPIO_INTR_POSEDGE);\n+\telse\n+\t\tgpio_set_intr_type(GPIO_SW, GPIO_INTR_NEGEDGE);\n+}\n+\n+\n+static int\n+start_scan()\n+{\n+\t/* if no APs configured, no point... */\n+\n+\tif (!lws_esp32.ssid[0][0] \u0026\u0026\n+\t !lws_esp32.ssid[1][0] \u0026\u0026\n+\t !lws_esp32.ssid[2][0] \u0026\u0026\n+\t !lws_esp32.ssid[3][0])\n+\t\treturn 0;\n+\n+\tif (scan_timer_exists \u0026\u0026 !scan_ongoing) {\n+\t\t// lwsl_notice(\u0022Starting scan timer...\u005cn\u0022);\n+\t\tscan_ongoing \u003d 1;\n+\t\txTimerStart(scan_timer, 0);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+\n+static void\n+end_scan()\n+{\n+\twifi_ap_record_t ap_records[10];\n+\tuint16_t count_ap_records;\n+\tint n, m;\n+\n+\tcount_ap_records \u003d ARRAY_SIZE(ap_records);\n+\tif (esp_wifi_scan_get_ap_records(\u0026count_ap_records, ap_records) !\u003d ESP_OK) {\n+\t\tlwsl_err(\u0022%s: failed\u005cn\u0022, __func__);\n+\t\treturn;\n+\t}\n+\n+\tif (!count_ap_records)\n+\t\tgoto passthru;\n+\n+\tif (gapss !\u003d LWS_GAPSS_SCAN) {\n+\t\tlwsl_notice(\u0022ignoring scan as gapss %s\u005cn\u0022, gapss_str[gapss]);\n+\t\tgoto passthru;\n+\t}\n+\n+\t/* no point if no APs set up */\n+\tif (!lws_esp32.ssid[0][0] \u0026\u0026\n+\t !lws_esp32.ssid[1][0] \u0026\u0026\n+\t !lws_esp32.ssid[2][0] \u0026\u0026\n+\t !lws_esp32.ssid[3][0])\n+\t\tgoto passthru;\n+\n+\tlwsl_notice(\u0022checking %d scan records\u005cn\u0022, count_ap_records);\n+\n+\tfor (n \u003d 0; n \u003c 4; n++) {\n+\n+\t\tif (!lws_esp32.ssid[(n + try_slot + 1) \u0026 3][0])\n+\t\t\tcontinue;\n+\n+\t\tlwsl_notice(\u0022looking for %s\u005cn\u0022, lws_esp32.ssid[(n + try_slot + 1) \u0026 3]);\n+\n+\t\t/* this ssid appears in scan results? */\n+\n+\t\tfor (m \u003d 0; m \u003c count_ap_records; m++) {\n+\t\t\t// lwsl_notice(\u0022 %s\u005cn\u0022, ap_records[m].ssid);\n+\t\t\tif (strcmp((char *)ap_records[m].ssid, lws_esp32.ssid[(n + try_slot + 1) \u0026 3]) \u003d\u003d 0)\n+\t\t\t\tgoto hit;\n+\t\t}\n+\n+\t\tcontinue;\n+\n+hit:\n+\t\tm \u003d (n + try_slot + 1) \u0026 3;\n+\t\ttry_slot \u003d m;\n+\t\tlwsl_notice(\u0022Attempting connection with slot %d: %s:\u005cn\u0022, m,\n+\t\t\t\tlws_esp32.ssid[m]);\n+\t\t/* set the ssid we last tried to connect to */\n+\t\tstrncpy(lws_esp32.active_ssid, lws_esp32.ssid[m],\n+\t\t\t\tsizeof(lws_esp32.active_ssid) - 1);\n+\t\tlws_esp32.active_ssid[sizeof(lws_esp32.active_ssid) - 1] \u003d '\u005c0';\n+\n+\t\tstrncpy((char *)sta_config.sta.ssid, lws_esp32.ssid[m], sizeof(sta_config.sta.ssid) - 1);\n+\t\tstrncpy((char *)sta_config.sta.password, lws_esp32.password[m], sizeof(sta_config.sta.password) - 1);\n+\n+\t\ttcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, (const char *)\u0026config.ap.ssid[7]);\n+\t\tlws_gapss_to(LWS_GAPSS_STAT);\n+\n+\t\tesp_wifi_set_config(WIFI_IF_STA, \u0026sta_config);\n+\t\tesp_wifi_connect();\n+\t\tbreak;\n+\t}\n+\n+\tif (n \u003d\u003d 4)\n+\t\tstart_scan();\n+\n+passthru:\n+\tif (lws_esp32.scan_consumer)\n+\t\tlws_esp32.scan_consumer(count_ap_records, ap_records, lws_esp32.scan_consumer_arg);\n+\n+}\n+\n+static void\n+lws_set_genled(int n)\n+{\n+\tlws_esp32.genled_t \u003d time_in_microseconds();\n+\tlws_esp32.genled \u003d n;\n+}\n+\n+int\n+lws_esp32_leds_network_indication(void)\n+{\n+\tuint64_t us, r;\n+\tint n, fadein \u003d 100, speed \u003d 1199, div \u003d 1, base \u003d 0;\n+\n+\tr \u003d time_in_microseconds();\n+\tus \u003d r - lws_esp32.genled_t;\n+\n+\tswitch (lws_esp32.genled) {\n+\tcase LWSESP32_GENLED__INIT:\n+\t\tlws_esp32.genled \u003d LWSESP32_GENLED__LOST_NETWORK;\n+\t\t/* fallthru */\n+\tcase LWSESP32_GENLED__LOST_NETWORK:\n+\t\tfadein \u003d us / 10000; /* 100 steps in 1s */\n+\t\tif (fadein \u003e 100) {\n+\t\t\tfadein \u003d 100;\n+\t\t\tlws_esp32.genled \u003d LWSESP32_GENLED__NO_NETWORK;\n+\t\t}\n+\t\t/* fallthru */\n+\tcase LWSESP32_GENLED__NO_NETWORK:\n+\t\tbreak;\n+\tcase LWSESP32_GENLED__CONN_AP:\n+\t\tbase \u003d 4096;\n+\t\tspeed \u003d 933;\n+\t\tdiv \u003d 2;\n+\t\tbreak;\n+\tcase LWSESP32_GENLED__GOT_IP:\n+\t\tfadein \u003d us / 10000; /* 100 steps in 1s */\n+\t\tif (fadein \u003e 100) {\n+\t\t\tfadein \u003d 100;\n+\t\t\tlws_esp32.genled \u003d LWSESP32_GENLED__OK;\n+\t\t}\n+\t\tfadein \u003d 100 - fadein; /* we are fading out */\n+\t\t/* fallthru */\n+\tcase LWSESP32_GENLED__OK:\n+\t\tif (lws_esp32.genled \u003d\u003d LWSESP32_GENLED__OK)\n+\t\t\treturn 0;\n+\n+\t\tbase \u003d 4096;\n+\t\tspeed \u003d 766;\n+\t\tdiv \u003d 3;\n+\t\tbreak;\n+\t}\n+\n+\tn \u003d base + (lws_esp32_sine_interp(r / speed) / div);\n+\treturn (n * fadein) / 100;\n+}\n+\n+esp_err_t lws_esp32_event_passthru(void *ctx, system_event_t *event)\n+{\n+#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n+\tstruct lws_group_member *mem;\n+\tint n;\n+#endif\n+\tchar slot[8];\n+\tnvs_handle nvh;\n+\tuint32_t use;\n+\n+\tswitch((int)event-\u003eevent_id) {\n+\tcase SYSTEM_EVENT_STA_START:\n+\t\t//esp_wifi_connect();\n+//\t\tbreak;\n+\t\t/* fallthru */\n+\tcase SYSTEM_EVENT_STA_DISCONNECTED:\n+\t\tlwsl_notice(\u0022SYSTEM_EVENT_STA_DISCONNECTED\u005cn\u0022);\n+\t\tlws_esp32.conn_ap \u003d 0;\n+\t\tlws_esp32.inet \u003d 0;\n+\t\tlws_esp32.sta_ip[0] \u003d '\u005c0';\n+\t\tlws_esp32.sta_mask[0] \u003d '\u005c0';\n+\t\tlws_esp32.sta_gw[0] \u003d '\u005c0';\n+\t\tlws_gapss_to(LWS_GAPSS_SCAN);\n+\t\tif (lws_esp32.mdns)\n+\t\t\tmdns_service_remove_all(lws_esp32.mdns);\n+\t\tmdns_free(lws_esp32.mdns);\n+\t\tlws_esp32.mdns \u003d NULL;\n+\t\tlws_set_genled(LWSESP32_GENLED__LOST_NETWORK);\n+\t\tstart_scan();\n+\t\tesp_wifi_connect();\n+\t\tbreak;\n+\n+\tcase SYSTEM_EVENT_STA_CONNECTED:\n+\t\tlws_esp32.conn_ap \u003d 1;\n+\t\tlws_set_genled(LWSESP32_GENLED__CONN_AP);\n+\t\tbreak;\n+\n+\tcase SYSTEM_EVENT_STA_GOT_IP:\n+\t\tlwsl_notice(\u0022SYSTEM_EVENT_STA_GOT_IP\u005cn\u0022);\n+\n+\t\tlws_esp32.inet \u003d 1;\n+\t\tlws_set_genled(LWSESP32_GENLED__GOT_IP);\n+\n+\t\trender_ip(lws_esp32.sta_ip, sizeof(lws_esp32.sta_ip) - 1,\n+\t\t\t\t(uint8_t *)\u0026event-\u003eevent_info.got_ip.ip_info.ip);\n+\t\trender_ip(lws_esp32.sta_mask, sizeof(lws_esp32.sta_mask) - 1,\n+\t\t\t\t(uint8_t *)\u0026event-\u003eevent_info.got_ip.ip_info.netmask);\n+\t\trender_ip(lws_esp32.sta_gw, sizeof(lws_esp32.sta_gw) - 1,\n+\t\t\t\t(uint8_t *)\u0026event-\u003eevent_info.got_ip.ip_info.gw);\n+\n+\t\tif (!nvs_open(\u0022lws-station\u0022, NVS_READWRITE, \u0026nvh)) {\n+\t\t\tlws_snprintf(slot, sizeof(slot) - 1, \u0022%duse\u0022, try_slot);\n+\t\t\tuse \u003d 0;\n+\t\t\tnvs_get_u32(nvh, slot, \u0026use);\n+\t\t\tnvs_set_u32(nvh, slot, use + 1);\n+\t\t\tnvs_commit(nvh);\n+\t\t\tnvs_close(nvh);\n+\t\t}\n+\n+\t\tlws_gapss_to(LWS_GAPSS_STAT_HAPPY);\n+\n+#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n+\t\tn \u003d mdns_init(TCPIP_ADAPTER_IF_STA, \u0026lws_esp32.mdns);\n+\t\tif (!n) {\n+\t\t\tstatic char *txta[6];\n+\t\t\tint w, h;\n+\n+\t\t\tmdns_set_hostname(lws_esp32.mdns, lws_esp32.hostname);\n+\t\t\tmdns_set_instance(lws_esp32.mdns, lws_esp32.group);\n+\t\t\tmdns_service_add(lws_esp32.mdns, \u0022_lwsgrmem\u0022, \u0022_tcp\u0022, 443);\n+\t\t\tif (txta[0])\n+\t\t\t\tlws_free(txta[0]);\n+\t\t\ttxta[0] \u003d lws_malloc(32 * ARRAY_SIZE(txta), \u0022group\u0022);\n+\t\t\tif (!txta[0]) {\n+\t\t\t\tlwsl_notice(\u0022mdns OOM\u005cn\u0022);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\ttxta[1] \u003d \u0026txta[0][32];\n+\t\t\ttxta[2] \u003d \u0026txta[1][32];\n+\t\t\ttxta[3] \u003d \u0026txta[2][32];\n+\t\t\ttxta[4] \u003d \u0026txta[3][32];\n+\t\t\ttxta[5] \u003d \u0026txta[4][32];\n+\n+\t\t\tlws_get_iframe_size(\u0026w, \u0026h);\n+\n+\t\t\tlws_snprintf(txta[0], 31, \u0022model\u003d%s\u0022, lws_esp32.model);\n+\t\t\tlws_snprintf(txta[1], 31, \u0022group\u003d%s\u0022, lws_esp32.group);\n+\t\t\tlws_snprintf(txta[2], 31, \u0022role\u003d%s\u0022, lws_esp32.role);\n+\t\t\tlws_snprintf(txta[3], 31, \u0022mac\u003d%s\u0022, lws_esp32.mac);\n+\t\t\tlws_snprintf(txta[4], 31, \u0022width\u003d%d\u0022, w);\n+\t\t\tlws_snprintf(txta[5], 31, \u0022height\u003d%d\u0022, h);\n+\n+\t\t\tmem \u003d lws_esp32.first;\n+\t\t\twhile (mem) {\n+\t\t\t\tif (mem-\u003eflags \u0026 1)\n+\t\t\t\t\tbreak;\n+\t\t\t\tmem \u003d mem-\u003enext;\n+\t\t\t}\n+\n+\t\t\tif (!mem) {\n+\t\t\t\tstruct lws_group_member *mem \u003d lws_malloc(sizeof(*mem), \u0022group\u0022);\n+\t\t\t\tif (mem) {\n+\t\t\t\t\tmem-\u003elast_seen \u003d ~(uint64_t)0;\n+\t\t\t\t\tstrcpy(mem-\u003emodel, lws_esp32.model);\n+\t\t\t\t\tstrcpy(mem-\u003erole, lws_esp32.role);\n+\t\t\t\t\tstrcpy(mem-\u003ehost, lws_esp32.hostname);\n+\t\t\t\t\tstrcpy(mem-\u003emac, lws_esp32.mac);\n+\t\t\t\t\tmem-\u003eflags \u003d LWS_GROUP_FLAG_SELF;\n+\t\t\t\t\tlws_get_iframe_size(\u0026mem-\u003ewidth, \u0026mem-\u003eheight);\n+\t\t\t\t\tmemcpy(\u0026mem-\u003eaddr, \u0026event-\u003eevent_info.got_ip.ip_info.ip,\n+\t\t\t\t\t\t\tsizeof(mem-\u003eaddr));\n+\t\t\t\t\tmemcpy(\u0026mem-\u003eaddrv6, \u0026event-\u003eevent_info.got_ip6.ip6_info.ip,\n+\t\t\t\t\t\t\tsizeof(mem-\u003eaddrv6));\n+\t\t\t\t\tmem-\u003enext \u003d lws_esp32.first;\n+\t\t\t\t\tlws_esp32.first \u003d mem;\n+\t\t\t\t\tlws_esp32.extant_group_members++;\n+\n+\t\t\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_ADD, mem);\n+\t\t\t\t}\n+\t\t\t} else { /* update our IP */\n+\t\t\t\t\tmemcpy(\u0026mem-\u003eaddr, \u0026event-\u003eevent_info.got_ip.ip_info.ip,\n+\t\t\t\t\t\t\tsizeof(mem-\u003eaddr));\n+\t\t\t\t\tmemcpy(\u0026mem-\u003eaddrv6, \u0026event-\u003eevent_info.got_ip6.ip6_info.ip,\n+\t\t\t\t\t\t\tsizeof(mem-\u003eaddrv6));\n+\t\t\t\t\tlws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_CHANGE, mem);\n+\t\t\t}\n+\n+\n+\t\t\tif (mdns_service_txt_set(lws_esp32.mdns, \u0022_lwsgrmem\u0022, \u0022_tcp\u0022, ARRAY_SIZE(txta),\n+\t\t\t\t\t\t (const char **)txta))\n+\t\t\t\tlwsl_notice(\u0022txt set failed\u005cn\u0022);\n+\t\t} else\n+\t\t\tlwsl_err(\u0022unable to init mdns on STA: %d\u005cn\u0022, n);\n+\n+\t\tmdns_query(lws_esp32.mdns, \u0022_lwsgrmem\u0022, \u0022_tcp\u0022, 0);\n+\t\txTimerStart(mdns_timer, 0);\n+#endif\n+\n+\t\tlwsl_notice(\u0022 --- Got IP %s\u005cn\u0022, lws_esp32.sta_ip);\n+\t\tbreak;\n+\n+\tcase SYSTEM_EVENT_SCAN_DONE:\n+\t\tlwsl_notice(\u0022SYSTEM_EVENT_SCAN_DONE\u005cn\u0022);\n+\t\tend_scan();\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn ESP_OK;\n+}\n+\n+static lws_fop_fd_t IRAM_ATTR\n+esp32_lws_fops_open(const struct lws_plat_file_ops *fops, const char *filename,\n+ const char *vfs_path, lws_fop_flags_t *flags)\n+{\n+\tstruct esp32_file *f \u003d malloc(sizeof(*f));\n+\tlws_fop_fd_t fop_fd;\n+\tsize_t len, csum;\n+\n+\tlwsl_notice(\u0022%s: %s\u005cn\u0022, __func__, filename);\n+\n+\tif (!f)\n+\t\treturn NULL;\n+\tf-\u003ei \u003d romfs_get_info(lws_esp32_romfs, filename, \u0026len, \u0026csum);\n+\tif (!f-\u003ei)\n+\t\tgoto bail;\n+\n+ fop_fd \u003d malloc(sizeof(*fop_fd));\n+ if (!fop_fd)\n+ goto bail;\n+\n+ fop_fd-\u003efops \u003d fops;\n+ fop_fd-\u003efilesystem_priv \u003d f;\n+\tfop_fd-\u003emod_time \u003d csum;\n+\t*flags |\u003d LWS_FOP_FLAG_MOD_TIME_VALID;\n+\tfop_fd-\u003eflags \u003d *flags;\n+\t\n+\tfop_fd-\u003elen \u003d len;\n+\tfop_fd-\u003epos \u003d 0;\n+\n+\treturn fop_fd;\n+\n+bail:\n+\tfree(f);\n+\n+\treturn NULL;\n+}\n+\n+static int IRAM_ATTR\n+esp32_lws_fops_close(lws_fop_fd_t *fop_fd)\n+{\n+\tfree((*fop_fd)-\u003efilesystem_priv);\n+\tfree(*fop_fd);\n+\n+\t*fop_fd \u003d NULL;\n+\n+\treturn 0;\n+}\n+static lws_fileofs_t IRAM_ATTR\n+esp32_lws_fops_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset_from_cur_pos)\n+{\n+\tfop_fd-\u003epos +\u003d offset_from_cur_pos;\n+\t\n+\tif (fop_fd-\u003epos \u003e fop_fd-\u003elen)\n+\t\tfop_fd-\u003epos \u003d fop_fd-\u003elen;\n+\n+ return 0;\n+}\n+\n+static int IRAM_ATTR\n+esp32_lws_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount, uint8_t *buf,\n+ lws_filepos_t len)\n+{\n+ struct esp32_file *f \u003d fop_fd-\u003efilesystem_priv;\n+#if 0\n+ if ((long)buf \u0026 3) {\n+ lwsl_err(\u0022misaligned buf\u005cn\u0022);\n+\n+ return -1;\n+ }\n+#endif\n+ if (fop_fd-\u003epos \u003e\u003d fop_fd-\u003elen)\n+ return 0;\n+\n+ if (len \u003e fop_fd-\u003elen - fop_fd-\u003epos)\n+ len \u003d fop_fd-\u003elen - fop_fd-\u003epos;\n+\n+ spi_flash_read((uint32_t)(char *)f-\u003ei + fop_fd-\u003epos, buf, len);\n+\n+ *amount \u003d len;\n+ fop_fd-\u003epos +\u003d len;\n+\n+ return 0;\n+}\n+\n+static const struct lws_plat_file_ops fops \u003d {\n+\t.next \u003d \u0026fops_zip,\n+\t.LWS_FOP_OPEN \u003d esp32_lws_fops_open,\n+\t.LWS_FOP_CLOSE \u003d esp32_lws_fops_close,\n+\t.LWS_FOP_READ \u003d esp32_lws_fops_read,\n+\t.LWS_FOP_SEEK_CUR \u003d esp32_lws_fops_seek_cur,\n+};\n+\n+int\n+lws_esp32_wlan_nvs_get(int retry)\n+{\n+\tnvs_handle nvh;\n+\tchar r[2], lws_esp32_force_ap \u003d 0, slot[12];\n+\tsize_t s;\n+\tuint8_t mac[6];\n+\tint n;\n+\n+\tesp_efuse_mac_get_default(mac);\n+\tmac[5] |\u003d 1; /* match the AP MAC */\n+\tsnprintf(lws_esp32.serial, sizeof(lws_esp32.serial) - 1, \u0022%02X%02X%02X\u0022, mac[3], mac[4], mac[5]);\n+\tsnprintf(lws_esp32.mac, sizeof(lws_esp32.mac) - 1, \u0022%02X%02X%02X%02X%02X%02X\u0022, mac[0],\n+\t\t\tmac[1], mac[2], mac[3], mac[4], mac[5]);\n+\n+\tESP_ERROR_CHECK(nvs_open(\u0022lws-station\u0022, NVS_READWRITE, \u0026nvh));\n+\n+\tconfig.sta.ssid[0] \u003d '\u005c0';\n+\tconfig.sta.password[0] \u003d '\u005c0';\n+\n+\tfor (n \u003d 0; n \u003c 4; n++) {\n+\t\tlws_snprintf(slot, sizeof(slot) - 1, \u0022%dssid\u0022, n);\n+\t\ts \u003d sizeof(lws_esp32.ssid[0]) - 1;\n+\t\tlws_esp32.ssid[n][0] \u003d '\u005c0';\n+\t\tnvs_get_str(nvh, slot, lws_esp32.ssid[n], \u0026s);\n+\n+\t\tlws_snprintf(slot, sizeof(slot) - 1, \u0022%dpassword\u0022, n);\n+\t\ts \u003d sizeof(lws_esp32.password[0]) - 1;\n+\t\tlws_esp32.password[n][0] \u003d '\u005c0';\n+\t\tnvs_get_str(nvh, slot, lws_esp32.password[n], \u0026s);\n+\t}\n+\n+\ts \u003d sizeof(lws_esp32.serial) - 1;\n+\tif (nvs_get_str(nvh, \u0022serial\u0022, lws_esp32.serial, \u0026s) !\u003d ESP_OK)\n+\t\tlws_esp32_force_ap \u003d 1;\n+\telse\n+\t\tsnprintf((char *)config.ap.ssid, sizeof(config.ap.ssid) - 1,\n+\t\t\t \u0022config-%s-%s\u0022, lws_esp32.model, lws_esp32.serial);\n+\ts \u003d sizeof(lws_esp32.opts) - 1;\n+\tif (nvs_get_str(nvh, \u0022opts\u0022, lws_esp32.opts, \u0026s) !\u003d ESP_OK)\n+\t\tlws_esp32_force_ap \u003d 1;\n+\n+\ts \u003d sizeof(r);\n+\tif (nvs_get_str(nvh, \u0022region\u0022, r, \u0026s) !\u003d ESP_OK)\n+\t\tlws_esp32_force_ap \u003d 1;\n+\telse\n+\t\tlws_esp32.region \u003d atoi(r);\n+\tlws_esp32.access_pw[0] \u003d '\u005c0';\n+\tnvs_get_str(nvh, \u0022access_pw\u0022, lws_esp32.access_pw, \u0026s);\n+\n+\tlws_esp32.group[0] \u003d '\u005c0';\n+\ts \u003d sizeof(lws_esp32.group);\n+\tnvs_get_str(nvh, \u0022group\u0022, lws_esp32.group, \u0026s);\n+\n+\tlws_esp32.role[0] \u003d '\u005c0';\n+\ts \u003d sizeof(lws_esp32.role);\n+\tnvs_get_str(nvh, \u0022role\u0022, lws_esp32.role, \u0026s);\n+\n+\t/* if group and role defined: group-role */\n+\tif (lws_esp32.group[0] \u0026\u0026 lws_esp32.role[0])\n+\t\tlws_snprintf(lws_esp32.hostname, sizeof(lws_esp32.hostname) - 1,\n+\t\t\t\t\u0022%s-%s\u0022, lws_esp32.group, lws_esp32.role);\n+\telse /* otherwise model-serial */\n+\t\tlws_snprintf(lws_esp32.hostname, sizeof(lws_esp32.hostname) - 1,\n+\t\t\t\t\u0022%s-%s\u0022, lws_esp32.model, lws_esp32.serial);\n+\n+\tnvs_close(nvh);\n+\n+\tlws_gapss_to(LWS_GAPSS_SCAN);\n+\tstart_scan();\n+\n+\treturn lws_esp32_force_ap;\n+}\n+\n+\n+void\n+lws_esp32_wlan_config(void)\n+{\n+\tledc_timer_config_t ledc_timer \u003d {\n+\t .bit_num \u003d LEDC_TIMER_13_BIT,\n+\t .freq_hz \u003d 5000,\n+\t .speed_mode \u003d LEDC_HIGH_SPEED_MODE,\n+\t .timer_num \u003d LEDC_TIMER_0\n+\t};\n+\tint n;\n+\n+\tledc_timer_config(\u0026ledc_timer);\n+\n+\tlws_set_genled(LWSESP32_GENLED__INIT);\n+\n+\t/* user code needs to provide lws_esp32_leds_timer_cb */\n+\n+ leds_timer \u003d xTimerCreate(\u0022lws_leds\u0022, pdMS_TO_TICKS(25), 1, NULL,\n+ (TimerCallbackFunction_t)lws_esp32_leds_timer_cb);\n+ scan_timer \u003d xTimerCreate(\u0022lws_scan\u0022, pdMS_TO_TICKS(10000), 0, NULL,\n+ (TimerCallbackFunction_t)lws_esp32_scan_timer_cb);\n+ debounce_timer \u003d xTimerCreate(\u0022lws_db\u0022, pdMS_TO_TICKS(100), 0, NULL,\n+ (TimerCallbackFunction_t)lws_esp32_debounce_timer_cb);\n+\n+#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)\n+ mdns_timer \u003d xTimerCreate(\u0022lws_mdns\u0022, pdMS_TO_TICKS(5000), 0, NULL,\n+ (TimerCallbackFunction_t)lws_esp32_mdns_timer_cb);\n+#endif\n+\tscan_timer_exists \u003d 1;\n+ xTimerStart(leds_timer, 0);\n+\n+\t*(volatile uint32_t *)PERIPHS_IO_MUX_MTMS_U \u003d FUNC_MTMS_GPIO14;\n+\n+\tgpio_output_set(0, 0, 0, (1 \u003c\u003c GPIO_SW));\n+\n+\tn \u003d gpio_install_isr_service(0);\n+\tif (!n) {\n+\t\tgpio_config_t c;\n+\n+\t\tc.intr_type \u003d GPIO_INTR_NEGEDGE;\n+\t\tc.mode \u003d GPIO_MODE_INPUT;\n+\t\tc.pin_bit_mask \u003d 1 \u003c\u003c GPIO_SW;\n+\t\tc.pull_down_en \u003d 0;\n+\t\tc.pull_up_en \u003d 0;\n+\t\tgpio_config(\u0026c);\n+\n+\t\tif (gpio_isr_handler_add(GPIO_SW, gpio_irq, NULL))\n+\t\t\tlwsl_notice(\u0022isr handler add for 14 failed\u005cn\u0022);\n+\t} else\n+\t\tlwsl_notice(\u0022failed to install gpio isr service: %d\u005cn\u0022, n);\n+\n+\tlws_esp32_wlan_nvs_get(0);\n+\ttcpip_adapter_init();\n+}\n+\n+void\n+lws_esp32_wlan_start_ap(void)\n+{\n+\twifi_init_config_t cfg \u003d WIFI_INIT_CONFIG_DEFAULT();\n+\n+\tESP_ERROR_CHECK( esp_wifi_init(\u0026cfg));\n+\tESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));\n+\tesp_wifi_set_country(lws_esp32.region);\n+\n+\tESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_APSTA) );\n+\tESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_AP, \u0026config) );\n+\tESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, \u0026sta_config));\n+\tESP_ERROR_CHECK( esp_wifi_start());\n+\n+\tesp_wifi_scan_start(\u0026scan_config, false);\n+\n+\tif (sta_config.sta.ssid[0]) {\n+\t\ttcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, (const char *)\u0026config.ap.ssid[7]);\n+\t\tesp_wifi_set_auto_connect(1);\n+\t\tESP_ERROR_CHECK( esp_wifi_connect());\n+\t\tESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, \u0026sta_config));\n+\t\tESP_ERROR_CHECK( esp_wifi_connect());\n+\t}\n+}\n+\n+void\n+lws_esp32_wlan_start_station(void)\n+{\n+\twifi_init_config_t cfg \u003d WIFI_INIT_CONFIG_DEFAULT();\n+\n+\tESP_ERROR_CHECK( esp_wifi_init(\u0026cfg));\n+\tESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));\n+\tesp_wifi_set_country(lws_esp32.region);\n+\n+\tESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA));\n+\tESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, \u0026sta_config));\n+\n+\tESP_ERROR_CHECK( esp_wifi_start());\n+\n+\ttcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, (const char *)\u0026config.ap.ssid[7]);\n+\tesp_wifi_set_auto_connect(1);\n+\t//ESP_ERROR_CHECK( esp_wifi_connect());\n+\n+\tlws_esp32_scan_timer_cb(NULL);\n+}\n+\n+const esp_partition_t *\n+lws_esp_ota_get_boot_partition(void)\n+{\n+\tconst esp_partition_t *part \u003d esp_ota_get_boot_partition(), *factory_part, *ota;\n+\tesp_image_header_t eih, ota_eih;\n+\tuint32_t *p_force_factory_magic \u003d (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;\n+\n+\t/* confirm what we are told is the boot part is sane */\n+\tspi_flash_read(part-\u003eaddress , \u0026eih, sizeof(eih));\n+\tfactory_part \u003d esp_partition_find_first(ESP_PARTITION_TYPE_APP,\n+\t\t\tESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);\n+ \tota \u003d esp_partition_find_first(ESP_PARTITION_TYPE_APP,\n+\t\t\tESP_PARTITION_SUBTYPE_APP_OTA_0, NULL);\n+\tspi_flash_read(ota-\u003eaddress , \u0026ota_eih, sizeof(ota_eih));\n+\n+\tif (eih.spi_mode \u003d\u003d 0xff ||\n+\t *p_force_factory_magic \u003d\u003d LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY ||\n+\t *p_force_factory_magic \u003d\u003d LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON\n+\t ) {\n+\t\t/*\n+\t\t * we believed we were going to boot OTA, but we fell\n+\t\t * back to FACTORY in the bootloader when we saw it\n+\t\t * had been erased. esp_ota_get_boot_partition() still\n+\t\t * says the OTA partition then even if we are in the\n+\t\t * factory partition right now.\n+\t\t */\n+\t\tpart \u003d factory_part;\n+\t} \n+\t\n+#ifdef CONFIG_LWS_IS_FACTORY_APPLICATION\n+\telse\n+\t\tif (ota_eih.spi_mode !\u003d 0xff \u0026\u0026\n+\t\t part-\u003eaddress !\u003d factory_part-\u003eaddress) {\n+\t\t\tuint8_t buf[4096];\n+\t\t\tuint32_t n;\n+\t\t\t/*\n+\t\t\t * we are a FACTORY image running in an OTA slot...\n+\t\t\t * it means we were just written and need to copy\n+\t\t\t * ourselves into the FACTORY slot.\n+\t\t\t */\n+\t\t\tlwsl_notice(\u0022Copying FACTORY update into place 0x%x len 0x%x\u005cn\u0022,\n+\t\t\t\t factory_part-\u003eaddress, factory_part-\u003esize);\n+\t\t\tesp_task_wdt_feed();\n+\t\t\tif (spi_flash_erase_range(factory_part-\u003eaddress, factory_part-\u003esize) !\u003d ESP_OK) {\n+\t \t lwsl_err(\u0022spi: Failed to erase\u005cn\u0022);\n+\t \t goto retry;\n+\t \t}\n+\n+\t\t\tfor (n \u003d 0; n \u003c factory_part-\u003esize; n +\u003d sizeof(buf)) {\n+\t\t\t\tesp_task_wdt_feed();\n+\t\t\t\tspi_flash_read(part-\u003eaddress + n , buf, sizeof(buf));\n+\t \tif (spi_flash_write(factory_part-\u003eaddress + n, buf, sizeof(buf)) !\u003d ESP_OK) {\n+\t \t lwsl_err(\u0022spi: Failed to write\u005cn\u0022);\n+\t \t goto retry;\n+\t \t}\n+\t\t\t}\n+\n+\t\t\t/* destroy our OTA image header */\n+\t\t\tspi_flash_erase_range(ota-\u003eaddress, 4096);\n+\n+\t\t\t/*\n+\t\t\t * with no viable OTA image, we will come back up in factory\n+\t\t\t * where the user can reload the OTA image\n+\t\t\t */\n+\t\t\tlwsl_notice(\u0022 FACTORY copy successful, rebooting\u005cn\u0022);\n+retry:\n+\t\t\tesp_restart();\n+\t\t}\n+#endif\n+\n+\treturn part;\n+}\n+\n+\n+void\n+lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)\n+{\n+\tconst esp_partition_t *part;\n+\n+\tmemset(info, 0, sizeof(*info));\n+\n+\tlws_set_log_level(63, lwsl_emit_syslog);\n+\n+\tpart \u003d lws_esp_ota_get_boot_partition();\n+\t(void)part;\n+\n+\tinfo-\u003eport \u003d 443;\n+\tinfo-\u003efd_limit_per_thread \u003d 10;\n+\tinfo-\u003emax_http_header_pool \u003d 16;\n+\tinfo-\u003emax_http_header_data \u003d 512;\n+\tinfo-\u003ept_serv_buf_size \u003d 2048;\n+\tinfo-\u003ekeepalive_timeout \u003d 30;\n+\tinfo-\u003etimeout_secs \u003d 30;\n+\tinfo-\u003esimultaneous_ssl_restriction \u003d 4;\n+\tinfo-\u003eoptions \u003d LWS_SERVER_OPTION_EXPLICIT_VHOSTS |\n+\t\t LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n+\n+\tinfo-\u003essl_cert_filepath \u003d \u0022ssl-pub.pem\u0022;\n+\tinfo-\u003essl_private_key_filepath \u003d \u0022ssl-pri.pem\u0022;\n+}\n+\n+int\n+lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,\n+\t\t\t char *json, int json_len)\n+{\n+\tesp_image_segment_header_t eis;\n+\tesp_image_header_t eih;\n+\tuint32_t hdr;\n+\n+\tspi_flash_read(part-\u003eaddress , \u0026eih, sizeof(eih));\n+\thdr \u003d part-\u003eaddress + sizeof(eih);\n+\n+\tif (eih.magic !\u003d ESP_IMAGE_HEADER_MAGIC)\n+\t\treturn 1;\n+\n+\teis.data_len \u003d 0;\n+\twhile (eih.segment_count-- \u0026\u0026 eis.data_len !\u003d 0xffffffff) {\n+\t\tspi_flash_read(hdr, \u0026eis, sizeof(eis));\n+\t\thdr +\u003d sizeof(eis) + eis.data_len;\n+\t}\n+\thdr +\u003d (~hdr \u0026 15) + 1;\n+\n+\tif (eih.hash_appended)\n+\t\thdr +\u003d 0x20;\n+\n+//\tlwsl_notice(\u0022romfs estimated at 0x%x\u005cn\u0022, hdr);\n+\n+\ti-\u003eromfs \u003d hdr + 0x4;\n+\tspi_flash_read(hdr, \u0026i-\u003eromfs_len, sizeof(i-\u003eromfs_len));\n+\ti-\u003ejson \u003d i-\u003eromfs + i-\u003eromfs_len + 4;\n+\tspi_flash_read(i-\u003ejson - 4, \u0026i-\u003ejson_len, sizeof(i-\u003ejson_len));\n+\n+\tif (i-\u003ejson_len \u003c json_len - 1)\n+\t\tjson_len \u003d i-\u003ejson_len;\n+\tspi_flash_read(i-\u003ejson, json, json_len);\n+\tjson[json_len] \u003d '\u005c0';\n+\n+\treturn 0;\n+}\n+\n+struct lws_context *\n+lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)\n+{\n+\tconst esp_partition_t *part \u003d lws_esp_ota_get_boot_partition();\n+\tstruct lws_context *context;\n+\tstruct lws_esp32_image i;\n+\tstruct lws_vhost *vhost;\n+\tnvs_handle nvh;\n+\tchar buf[512];\n+\tsize_t s;\n+\tint n;\n+\n+\tESP_ERROR_CHECK(nvs_open(\u0022lws-station\u0022, NVS_READWRITE, \u0026nvh));\n+\tn \u003d 0;\n+\ts \u003d 1;\n+\tif (nvs_get_blob(nvh, \u0022ssl-pub.pem\u0022, NULL, \u0026s) \u003d\u003d ESP_OK)\n+\t\tn \u003d 1;\n+\ts \u003d 1;\n+\tif (nvs_get_blob(nvh, \u0022ssl-pri.pem\u0022, NULL, \u0026s) \u003d\u003d ESP_OK)\n+\t\tn |\u003d 2;\n+\tnvs_close(nvh);\n+\n+\tif (n !\u003d 3) {\n+\t\t/* we are not configured for SSL yet... fall back to port 80 / http */\n+\t\tinfo-\u003eport \u003d 80;\n+\t\tinfo-\u003eoptions \u0026\u003d ~LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n+\t\tlwsl_notice(\u0022No SSL certs... using port 80\u005cn\u0022);\n+\t}\n+\n+\tcontext \u003d lws_create_context(info);\n+\tif (context \u003d\u003d NULL) {\n+\t\tlwsl_err(\u0022Failed to create context\u005cn\u0022);\n+\t\treturn NULL;\n+\t}\n+\n+\tlws_esp32_get_image_info(part, \u0026i, buf, sizeof(buf) - 1);\n+\t\n+\tlws_esp32_romfs \u003d (romfs_t)i.romfs;\n+\tif (!romfs_mount_check(lws_esp32_romfs)) {\n+\t\tlwsl_err(\u0022Failed to mount ROMFS at %p 0x%x\u005cn\u0022, lws_esp32_romfs, i.romfs);\n+\t\treturn NULL;\n+\t}\n+\n+\tlwsl_notice(\u0022ROMFS length %uKiB\u005cn\u0022, i.romfs_len \u003e\u003e 10);\n+\n+\tputs(buf);\n+\n+\t/* set the lws vfs to use our romfs */\n+\n+\tlws_set_fops(context, \u0026fops);\n+\n+\tvhost \u003d lws_create_vhost(context, info);\n+\tif (!vhost)\n+\t\tlwsl_err(\u0022Failed to create vhost\u005cn\u0022);\n+\telse\n+\t\tlws_init_vhost_client_ssl(info, vhost); \n+\n+\tif (pvh)\n+\t\t*pvh \u003d vhost;\n+\n+\tlws_protocol_init(context);\n+\n+\treturn context;\n+}\n+\n+static const uint16_t sineq16[] \u003d {\n+ 0x0000, 0x0191, 0x031e, 0x04a4, 0x061e, 0x0789, 0x08e2, 0x0a24,\n+ 0x0b4e, 0x0c5c, 0x0d4b, 0x0e1a, 0x0ec6, 0x0f4d, 0x0faf, 0x0fea,\n+};\n+\n+static uint16_t sine_lu(int n)\n+{\n+ switch ((n \u003e\u003e 4) \u0026 3) {\n+ case 1:\n+ return 4096 + sineq16[n \u0026 15];\n+ case 2:\n+ return 4096 + sineq16[15 - (n \u0026 15)];\n+ case 3:\n+ return 4096 - sineq16[n \u0026 15];\n+ default:\n+ return 4096 - sineq16[15 - (n \u0026 15)];\n+ }\n+}\n+\n+/* useful for sine led fade patterns */\n+\n+uint16_t lws_esp32_sine_interp(int n)\n+{\n+ /*\n+ * 2: quadrant\n+ * 4: table entry in quadrant\n+ * 4: interp (LSB)\n+ *\n+ * total 10 bits / 1024 steps per cycle\n+\t *\n+\t * + 0: 0\n+\t * + 256: 4096\n+\t * + 512: 8192\n+\t * + 768: 4096\n+\t * +1023: 0\n+ */\n+\n+ return (sine_lu(n \u003e\u003e 4) * (15 - (n \u0026 15)) +\n+ sine_lu((n \u003e\u003e 4) + 1) * (n \u0026 15)) / 15;\n+}\n+\ndiff --git a/lib/plat/lws-plat-esp8266.c b/lib/plat/lws-plat-esp8266.c\nnew file mode 100644\nindex 0000000..90ddbdf\n--- /dev/null\n+++ b/lib/plat/lws-plat-esp8266.c\n@@ -0,0 +1,700 @@\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#include \u0022ip_addr.h\u0022\n+\n+/* forced into this because new espconn accepted callbacks carry no context ptr */\n+static struct lws_context *hacky_context;\n+static unsigned int time_high, ot;\n+\n+/*\n+ * included from libwebsockets.c for esp8266 builds\n+ */\n+\n+unsigned long long time_in_microseconds(void)\n+{\n+\tunsigned int t \u003d system_get_time();\n+\t\n+\tif (ot \u003e t)\n+\t\ttime_high++;\n+\tot \u003d t;\n+\t\n+\treturn (((long long)time_high) \u003c\u003c 32) | t;\n+}\n+\n+int gettimeofday(struct timeval *tv, void *tz)\n+{\n+\tunsigned long long t \u003d time_in_microseconds();\n+\t\n+\ttv-\u003etv_sec \u003d t / 1000000;\n+\ttv-\u003etv_usec \u003d t % 1000000;\n+\n+\treturn 0;\n+}\n+\n+time_t time(time_t *tloc)\n+{\n+\tunsigned long long t \u003d time_in_microseconds();\n+\n+\tif (tloc)\n+\t\t*tloc \u003d t / 1000000;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_get_random(struct lws_context *context, void *buf, int len)\n+{\n+//\treturn read(context-\u003efd_random, (char *)buf, len);\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_send_pipe_choked(struct lws *wsi)\n+{\n+\treturn wsi-\u003epending_send_completion;\n+}\n+\n+LWS_VISIBLE struct lws *\n+wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)\n+{\n+\tint n;\n+\n+\tfor (n \u003d 0; n \u003c context-\u003emax_fds; n++)\n+\t\tif (context-\u003econnpool[n] \u003d\u003d fd)\n+\t\t\treturn (struct lws *)context-\u003econnpool[n + context-\u003emax_fds];\n+\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE int\n+lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)\n+{\n+\t//lwsl_notice(\u0022%s: wsi %p: len %d\u005cn\u0022, __func__, wsi, len);\t\n+\t\n+\twsi-\u003epending_send_completion++;\n+\tespconn_send(wsi-\u003edesc.sockfd, buf, len);\n+\t\n+\treturn len;\n+}\n+\n+void abort(void)\n+{\n+\twhile(1) ;\n+}\n+\n+void exit(int n)\n+{\n+\tabort();\n+}\n+\n+void _sint(void *s)\n+{\n+}\n+\n+LWS_VISIBLE int\n+insert_wsi(struct lws_context *context, struct lws *wsi)\n+{\n+\t(void)context;\n+\t(void)wsi;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+delete_from_fd(struct lws_context *context, lws_sockfd_type fd)\n+{\n+\t(void)context;\n+\t(void)fd;\n+\n+\treturn 1;\n+}\n+\n+struct tm *localtime(const time_t *timep)\n+{\n+\treturn NULL;\n+}\n+struct tm *localtime_r(const time_t *timep, struct tm *t)\n+{\n+\treturn NULL;\n+}\n+\n+int atoi(const char *s)\n+{\n+\tint n \u003d 0;\n+\n+\twhile (*s \u0026\u0026 (*s \u003e\u003d '0' \u0026\u0026 *s \u003c\u003d '9'))\n+\t\tn \u003d (n * 10) + ((*s++) - '0');\n+\n+\treturn n;\n+}\n+\n+#undef isxdigit\n+int isxdigit(int c)\n+{\n+\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'F')\n+\t\treturn 1;\n+\n+\tif (c \u003e\u003d 'a' \u0026\u0026 c \u003c\u003d 'f')\n+\t\treturn 1;\n+\n+\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+int strcasecmp(const char *s1, const char *s2)\n+{\n+\tchar a, b;\n+\twhile (*s1 \u0026\u0026 *s2) {\n+\t\ta \u003d *s1++;\n+\t\tb \u003d *s2++;\n+\n+\t\tif (a \u003d\u003d b)\n+\t\t\tcontinue;\n+\n+\t\tif (a \u003e\u003d 'a' \u0026\u0026 a \u003c\u003d 'z')\n+\t\t\ta -\u003d 'a' - 'A';\n+\t\tif (b \u003e\u003d 'a' \u0026\u0026 b \u003c\u003d 'z')\n+\t\t\tb -\u003d 'a' - 'A';\n+\n+\t\tif (a !\u003d b)\n+\t\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_poll_listen_fd(struct lws_pollfd *fd)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service_pt(struct lws *wsi)\n+{\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n+{\n+\textern void output_redirect(const char *str);\n+\toutput_redirect(line);\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_check_connection_error(struct lws *wsi)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_service(struct lws_context *context, int timeout_ms)\n+{\n+//\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n+\treturn 0;\n+}\n+\n+static int\n+esp8266_find_free_conn(struct lws_context *context)\n+{\n+\tint n;\n+\n+\tfor (n \u003d 0; n \u003c context-\u003emax_fds; n++)\n+\t\tif (!context-\u003econnpool[n]) {\n+\t\t\tlwsl_info(\u0022 using connpool %d\u005cn\u0022, n);\n+\t\t\treturn n;\n+\t\t}\n+\t\n+\tlwsl_err(\u0022%s: no free conns\u005cn\u0022, __func__);\n+\t\n+\treturn -1;\n+}\n+\n+lws_sockfd_type\n+esp8266_create_tcp_listen_socket(struct lws_vhost *vh)\n+{\n+\tint n \u003d esp8266_find_free_conn(vh-\u003econtext);\n+\tstruct espconn *conn;\n+\t\n+\tif (n \u003c 0)\n+\t\treturn NULL;\n+\t\n+\tconn \u003d lws_zalloc(sizeof *conn, \u0022listen skt\u0022);\n+\tif (!conn)\n+\t\treturn NULL;\n+\t\n+\tvh-\u003econtext-\u003econnpool[n] \u003d conn;\n+\t\n+\tconn-\u003etype \u003d ESPCONN_TCP;\n+\tconn-\u003estate \u003d ESPCONN_NONE;\n+\tconn-\u003eproto.tcp \u003d \u0026vh-\u003etcp;\n+\t\n+\treturn conn;\n+}\n+\n+const char *\n+lws_plat_get_peer_simple(struct lws *wsi, char *name, int namelen)\n+{\n+\tunsigned char *p \u003d wsi-\u003edesc.sockfd-\u003eproto.tcp-\u003eremote_ip;\n+\n+\tlws_snprintf(name, namelen, \u0022%u.%u.%u.%u\u0022, p[0], p[1], p[2], p[3]);\n+\n+\treturn name;\n+}\n+\n+LWS_VISIBLE int\n+lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)\n+{\n+\t//lwsl_notice(\u0022%s\u005cn\u0022, __func__);\n+\t\n+\tif (!wsi-\u003econtext-\u003erxd)\n+\t\treturn 0;\n+\n+\tif (len \u003c wsi-\u003econtext-\u003erxd_len)\n+\t\tlwsl_err(\u0022trunc read (%d vs %d)\u005cn\u0022, len, wsi-\u003econtext-\u003erxd_len);\n+\telse\n+\t\tlen \u003d wsi-\u003econtext-\u003erxd_len;\n+\t\n+\tets_memcpy(buf, wsi-\u003econtext-\u003erxd, len);\n+\t\n+\twsi-\u003econtext-\u003erxd \u003d NULL;\n+\t\n+\treturn len;\n+}\n+\n+static void\n+cb_1Hz(void *arg)\n+{\n+\tstruct lws_context *context \u003d arg;\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+\tstruct lws *wsi;\n+\tstruct lws_pollfd *pollfd;\n+\tint n;\n+\n+\t/* Service any ah that has pending rx */\n+\tfor (n \u003d 0; n \u003c context-\u003emax_http_header_pool; n++)\n+\t\tif (pt-\u003eah_pool[n].rxpos !\u003d pt-\u003eah_pool[n].rxlen) {\n+\t\t\twsi \u003d pt-\u003eah_pool[n].wsi;\n+\t\t\tpollfd \u003d \u0026pt-\u003efds[wsi-\u003eposition_in_fds_table];\n+\t\t\tif (pollfd-\u003eevents \u0026 LWS_POLLIN) {\n+\t\t\t\tpollfd-\u003erevents |\u003d LWS_POLLIN;\n+\t\t\t\tlws_service_fd(context, pollfd);\n+\t\t\t}\n+\t\t}\n+\n+\t/* handle timeouts */\n+\n+\tlws_service_fd(context, NULL);\n+}\n+\n+static void\n+esp8266_cb_rx(void *arg, char *data, unsigned short len)\n+{\n+\tstruct espconn *conn \u003d arg;\n+\tstruct lws *wsi \u003d conn-\u003ereverse;\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[0];\n+\tstruct lws_pollfd pollfd;\n+\tint n \u003d 0;\n+\n+\t/*\n+\t * if we're doing HTTP headers, and we have no ah, check if there is\n+\t * a free ah, if not, have to buffer it\n+\t */\n+\tif (!wsi-\u003ehdr_parsing_completed \u0026\u0026 !wsi-\u003eu.hdr.ah) {\n+\t\tfor (n \u003d 0; n \u003c wsi-\u003econtext-\u003emax_http_header_pool; n++)\n+\t\t\tif (!pt-\u003eah_pool[n].in_use)\n+\t\t\t\tbreak;\n+\n+\t\tn \u003d n \u003d\u003d wsi-\u003econtext-\u003emax_http_header_pool;\n+\t}\n+\n+\tif (!(pt-\u003efds[wsi-\u003eposition_in_fds_table].events \u0026 LWS_POLLIN) || n) {\n+\t\twsi-\u003epremature_rx \u003d realloc(wsi-\u003epremature_rx,\n+\t\t\t\t\t wsi-\u003eprem_rx_size + len);\n+\t\tif (!wsi-\u003epremature_rx)\n+\t\t\treturn;\n+\t\tos_memcpy((char *)wsi-\u003epremature_rx + wsi-\u003eprem_rx_size, data, len);\n+\t\twsi-\u003eprem_rx_size +\u003d len;\n+\t//\tlwsl_notice(\u0022%s: wsi %p: len %d BUFFERING\u005cn\u0022, __func__, wsi, len);\n+\n+\t\tif (n) /* we know it will fail, but we will get on the wait list */\n+\t\t\tn \u003d lws_header_table_attach(wsi, 0);\n+\n+\t\t(void)n;\n+\t\treturn;\n+\t}\n+\n+\t//lwsl_err(\u0022%s: wsi %p. len %d\u005cn\u0022, __func__, wsi, len);\n+\n+ pollfd.fd \u003d arg;\n+ pollfd.events \u003d LWS_POLLIN;\n+ pollfd.revents \u003d LWS_POLLIN;\n+ \n+ wsi-\u003econtext-\u003erxd \u003d data;\n+ wsi-\u003econtext-\u003erxd_len \u003d len;\n+\n+ lws_service_fd(lws_get_context(wsi), \u0026pollfd);\n+\n+}\n+\n+static void\n+esp8266_cb_sent(void *arg)\n+{\n+\tstruct espconn *conn \u003d arg;\n+\tstruct lws *wsi \u003d conn-\u003ereverse;\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\t\n+//\tlwsl_err(\u0022%s: wsi %p (psc %d) wsi-\u003eposition_in_fds_table\u003d%d\u005cn\u0022, __func__, wsi, wsi-\u003epending_send_completion, wsi-\u003eposition_in_fds_table);\n+\t\n+\twsi-\u003epending_send_completion--;\n+\tif (wsi-\u003eclose_is_pending_send_completion \u0026\u0026\n+\t !wsi-\u003epending_send_completion \u0026\u0026\n+\t !lws_partial_buffered(wsi)) {\n+\t\tlwsl_notice(\u0022doing delayed close\u005cn\u0022);\n+\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\t}\n+\t\n+\tif (pt-\u003efds[wsi-\u003eposition_in_fds_table].events \u0026 LWS_POLLOUT) {\n+\t\tstruct lws_pollfd pollfd;\n+\n+\t pollfd.fd \u003d arg;\n+\t pollfd.events \u003d LWS_POLLOUT;\n+\t pollfd.revents \u003d LWS_POLLOUT;\n+\n+//\t lwsl_notice(\u0022informing POLLOUT\u005cn\u0022);\n+\t \n+\t lws_service_fd(lws_get_context(wsi), \u0026pollfd);\n+\t}\n+}\n+\n+static void\n+esp8266_cb_disconnected(void *arg)\n+{\n+\tstruct espconn *conn \u003d arg;\n+\tstruct lws *wsi \u003d conn-\u003ereverse;\n+\tint n;\n+\n+\tlwsl_notice(\u0022%s: %p\u005cn\u0022, __func__, wsi);\n+\t\n+\tfor (n \u003d 0; n \u003c hacky_context-\u003emax_fds; n++)\n+\t\tif (hacky_context-\u003econnpool[n] \u003d\u003d arg) {\n+\t\t\thacky_context-\u003econnpool[n] \u003d NULL;\n+\t\t\tlwsl_info(\u0022 freed connpool %d\u005cn\u0022, n);\n+\t\t}\n+\t\n+\tif (wsi) {\n+\t\tconn-\u003ereverse \u003d NULL;\n+\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\t\tlwsl_notice(\u0022closed ok\u005cn\u0022);\n+\t}\n+}\n+\n+static void\n+esp8266_cb_recon(void *arg, signed char err)\n+{\n+\tstruct espconn *conn \u003d arg;\n+\n+\tlwsl_err(\u0022%s: wsi %p. err %d\u005cn\u0022, __func__, conn-\u003ereverse, err);\n+\n+\tconn-\u003estate \u003d ESPCONN_CLOSE;\t\t\n+\n+\tesp8266_cb_disconnected(arg);\t\n+}\n+\n+/*\n+ * there is no reliable indication of which listen socket we were accepted on.\n+ */\n+\n+static void\n+esp8266_cb_connect(void *arg)\n+{\n+\tstruct espconn *cs \u003d arg;\n+//\tstruct ip_addr *ipa \u003d (struct ip_addr *)cs-\u003eproto.tcp-\u003eremote_ip;\n+\tstruct lws_vhost *vh \u003d hacky_context-\u003evhost_list;\n+//\tstruct ip_info info;\n+\tstruct lws *wsi;\n+\tint n;\n+\n+\tlwsl_notice(\u0022%s: (wsi coming): %p\u005cn\u0022, __func__, cs-\u003ereverse);\n+#if 0\n+\twifi_get_ip_info(0, \u0026info);\n+\tif (ip_addr_netcmp(ipa, \u0026info.ip, \u0026info.netmask)) {\n+\t\t/* we are on the same subnet as the AP, ie, connected to AP */\n+\t\twhile (vh \u0026\u0026 strcmp(vh-\u003ename, \u0022ap\u0022))\n+\t\t\tvh \u003d vh-\u003evhost_next;\n+\t} else\n+\t\twhile (vh \u0026\u0026 !strcmp(vh-\u003ename, \u0022ap\u0022))\n+\t\t\tvh \u003d vh-\u003evhost_next;\n+\n+\tif (!vh)\n+\t\tgoto bail;\n+#endif\n+\tn \u003d esp8266_find_free_conn(hacky_context);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\t\n+\thacky_context-\u003econnpool[n] \u003d cs;\n+\t\n+\tespconn_recv_hold(cs);\n+\n+\twsi \u003d lws_adopt_socket_vhost(vh, cs);\n+\tif (!wsi)\n+\t\tgoto bail;\n+\t\n+\tlwsl_err(\u0022%s: wsi %p (using free_conn %d): vh %s\u005cn\u0022, __func__, wsi, n, vh-\u003ename);\n+\n+\tespconn_regist_recvcb(cs, esp8266_cb_rx);\n+\tespconn_regist_reconcb(cs, esp8266_cb_recon);\n+\tespconn_regist_disconcb(cs, esp8266_cb_disconnected);\n+\tespconn_regist_sentcb(cs, esp8266_cb_sent);\n+\t\n+\tespconn_set_opt(cs, ESPCONN_NODELAY | ESPCONN_REUSEADDR);\n+\tespconn_regist_time(cs, 7200, 1);\n+\n+\treturn;\n+\n+bail:\n+\tlwsl_err(\u0022%s: bailed]n\u0022, __func__);\n+\tespconn_disconnect(cs);\n+}\n+\n+void\n+esp8266_tcp_stream_bind(lws_sockfd_type fd, int port, struct lws *wsi)\n+{\n+\tfd-\u003eproto.tcp-\u003elocal_port \u003d port;\n+\tfd-\u003ereverse \u003d wsi;\n+\t\n+\thacky_context \u003d wsi-\u003econtext;\n+\t\n+\tespconn_regist_connectcb(fd, esp8266_cb_connect);\n+\t/* hmmm it means, listen() + accept() */\n+\tespconn_accept(fd);\n+\n+\tespconn_tcp_set_max_con_allow(fd, 10);\n+}\n+\n+void\n+esp8266_tcp_stream_accept(lws_sockfd_type fd, struct lws *wsi)\n+{\n+\tint n;\n+\n+\tfd-\u003ereverse \u003d wsi;\n+\n+\tfor (n \u003d 0; n \u003c wsi-\u003econtext-\u003emax_fds ; n++)\n+\t\tif (wsi-\u003econtext-\u003econnpool[n] \u003d\u003d wsi-\u003edesc.sockfd)\n+\t\t\twsi-\u003eposition_in_fds_table \u003d n;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n+{\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_context_early_init(void)\n+{\n+\tespconn_tcp_set_max_con(12);\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_early_destroy(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_late_destroy(struct lws_context *context)\n+{\n+#if 0\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+\tint m \u003d context-\u003ecount_threads;\n+\n+\tif (context-\u003elws_lookup)\n+\t\tlws_free(context-\u003elws_lookup);\n+\n+\twhile (m--) {\n+\t\tclose(pt-\u003edummy_pipe_fds[0]);\n+\t\tclose(pt-\u003edummy_pipe_fds[1]);\n+\t\tpt++;\n+\t}\n+#endif\n+//\tclose(context-\u003efd_random);\n+}\n+\n+/* cast a struct sockaddr_in6 * into addr for ipv6 */\n+\n+LWS_VISIBLE int\n+lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,\n+\t\t size_t addrlen)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\n+\tcontext-\u003econnpool[wsi-\u003eposition_in_fds_table + context-\u003emax_fds] \u003d (lws_sockfd_type)wsi;\n+\twsi-\u003edesc.sockfd-\u003ereverse \u003d wsi;\n+\tpt-\u003efds_count++;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_delete_socket_from_fds(struct lws_context *context,\n+\t\t\t\t\t\tstruct lws *wsi, int m)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\t\n+\tint n;\n+\t\n+\tfor (n \u003d 0; n \u003c wsi-\u003econtext-\u003emax_fds; n++)\n+\t\tif (wsi-\u003econtext-\u003econnpool[n] \u003d\u003d wsi-\u003edesc.sockfd) {\n+\t\t\twsi-\u003econtext-\u003econnpool[n] \u003d NULL;\n+\t\t\twsi-\u003econtext-\u003econnpool[n + wsi-\u003econtext-\u003emax_fds] \u003d NULL;\n+\t\t\tlwsl_notice(\u0022 freed connpool %d\u005cn\u0022, n);\n+\t\t}\n+\t\n+\twsi-\u003edesc.sockfd-\u003ereverse \u003d NULL;\n+\tpt-\u003efds_count--;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_service_periodic(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_change_pollfd(struct lws_context *context,\n+\t\t struct lws *wsi, struct lws_pollfd *pfd)\n+{\n+\tvoid *p;\n+\n+\t//lwsl_notice(\u0022%s: %p: wsi-\u003epift\u003d%d, events %d\u005cn\u0022,\n+\t//\t\t__func__, wsi, wsi-\u003eposition_in_fds_table, pfd-\u003eevents);\n+\t\n+\tif (pfd-\u003eevents \u0026 LWS_POLLIN) {\n+\t\tif (wsi-\u003epremature_rx) {\n+\t\t\tlwsl_notice(\u0022replaying buffered rx: wsi %p\u005cn\u0022, wsi);\n+\t\t\tp \u003d wsi-\u003epremature_rx;\n+\t\t\twsi-\u003epremature_rx \u003d NULL;\n+\t\t\tesp8266_cb_rx(wsi-\u003edesc.sockfd,\n+\t\t\t\t (char *)p + wsi-\u003eprem_rx_pos,\n+\t\t\t\t wsi-\u003eprem_rx_size - wsi-\u003eprem_rx_pos);\n+\t\t\twsi-\u003eprem_rx_size \u003d 0;\n+\t\t\twsi-\u003eprem_rx_pos \u003d 0;\n+\t\t\tlws_free(p);\n+\t\t}\n+\t\tif (espconn_recv_unhold(wsi-\u003edesc.sockfd) \u003c 0)\n+\t\t\treturn -1;\n+\t} else\n+\t\tif (espconn_recv_hold(wsi-\u003edesc.sockfd) \u003c 0)\n+\t\t\treturn -1;\n+\t\n+\tif (!(pfd-\u003eevents \u0026 LWS_POLLOUT))\n+\t\treturn 0;\n+\t\n+\tif (!wsi-\u003epending_send_completion) {\n+\t\tpfd-\u003erevents |\u003d LWS_POLLOUT;\n+\n+//\t\tlwsl_notice(\u0022doing POLLOUT\u005cn\u0022);\n+\t\tlws_service_fd(lws_get_context(wsi), pfd);\n+\t} //else\n+\t\t//lwsl_notice(\u0022pending sc\u005cn\u0022);\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE const char *\n+lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n+{\n+//\treturn inet_ntop(af, src, dst, cnt);\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_inet_pton(int af, const char *src, void *dst)\n+{\n+\t//return inet_pton(af, src, dst);\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_init(struct lws_context *context,\n+\t struct lws_context_creation_info *info)\n+{\n+//\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+//\tint n \u003d context-\u003ecount_threads, fd;\n+\n+\t/* master context has the global fd lookup array */\n+\tcontext-\u003econnpool \u003d lws_zalloc(sizeof(struct espconn *) *\n+\t\t\t\t\t context-\u003emax_fds * 2, \u0022connpool\u0022);\n+\tif (context-\u003econnpool \u003d\u003d NULL) {\n+\t\tlwsl_err(\u0022OOM on lws_lookup array for %d connections\u005cn\u0022,\n+\t\t\t context-\u003emax_fds);\n+\t\treturn 1;\n+\t}\n+\n+\tlwsl_notice(\u0022 mem: platform fd map: %5u bytes\u005cn\u0022,\n+\t\t sizeof(struct espconn *) * context-\u003emax_fds);\n+//\tfd \u003d open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);\n+\n+//\tcontext-\u003efd_random \u003d fd;\n+//\tif (context-\u003efd_random \u003c 0) {\n+//\t\tlwsl_err(\u0022Unable to open random device %s %d\u005cn\u0022,\n+//\t\t\t SYSTEM_RANDOM_FILEPATH, context-\u003efd_random);\n+//\t\treturn 1;\n+//\t}\n+\n+ os_memset(\u0026context-\u003eto_timer, 0, sizeof(os_timer_t));\n+ os_timer_disarm(\u0026context-\u003eto_timer);\n+ os_timer_setfn(\u0026context-\u003eto_timer, (os_timer_func_t *)cb_1Hz, context);\n+ os_timer_arm(\u0026context-\u003eto_timer, 1000, 1);\n+\n+\tif (!lws_libev_init_fd_table(context) \u0026\u0026\n+\t !lws_libuv_init_fd_table(context) \u0026\u0026\n+\t !lws_libevent_init_fd_table(context)) {\n+\t\t/* otherwise libev handled it instead */\n+#if 0\n+\t\twhile (n--) {\n+\t\t\tif (pipe(pt-\u003edummy_pipe_fds)) {\n+\t\t\t\tlwsl_err(\u0022Unable to create pipe\u005cn\u0022);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n+\t\t\t/* use the read end of pipe as first item */\n+\t\t\tpt-\u003efds[0].fd \u003d pt-\u003edummy_pipe_fds[0];\n+\t\t\tpt-\u003efds[0].events \u003d LWS_POLLIN;\n+\t\t\tpt-\u003efds[0].revents \u003d 0;\n+\t\t\tpt-\u003efds_count \u003d 1;\n+\t\t\tpt++;\n+\t\t}\n+#endif\n+\t}\n+\n+\n+#ifdef LWS_WITH_PLUGINS\n+\tif (info-\u003eplugin_dirs)\n+\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n+#endif\n+\n+\treturn 0;\n+}\ndiff --git a/lib/plat/lws-plat-optee.c b/lib/plat/lws-plat-optee.c\nnew file mode 100644\nindex 0000000..fcd7763\n--- /dev/null\n+++ b/lib/plat/lws-plat-optee.c\n@@ -0,0 +1,329 @@\n+#include \u0022private-libwebsockets.h\u0022\n+\n+/*\n+ * included from libwebsockets.c for OPTEE builds\n+ */\n+\n+void TEE_GenerateRandom(void *randomBuffer, uint32_t randomBufferLen);\n+\n+unsigned long long time_in_microseconds(void)\n+{\n+\treturn ((unsigned long long)time(NULL)) * 1000000;\n+}\n+#if 0\n+LWS_VISIBLE int\n+lws_get_random(struct lws_context *context, void *buf, int len)\n+{\n+\tTEE_GenerateRandom(buf, len);\n+\n+\treturn len;\n+}\n+#endif\n+LWS_VISIBLE int\n+lws_send_pipe_choked(struct lws *wsi)\n+{\n+#if 0\n+\tstruct lws_pollfd fds;\n+\n+\t/* treat the fact we got a truncated send pending as if we're choked */\n+\tif (wsi-\u003etrunc_len)\n+\t\treturn 1;\n+\n+\tfds.fd \u003d wsi-\u003edesc.sockfd;\n+\tfds.events \u003d POLLOUT;\n+\tfds.revents \u003d 0;\n+\n+\tif (poll(\u0026fds, 1, 0) !\u003d 1)\n+\t\treturn 1;\n+\n+\tif ((fds.revents \u0026 POLLOUT) \u003d\u003d 0)\n+\t\treturn 1;\n+#endif\n+\t/* okay to send another packet without blocking */\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_poll_listen_fd(struct lws_pollfd *fd)\n+{\n+//\treturn poll(fd, 1, 0);\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service_pt(struct lws *wsi)\n+{\n+#if 0\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tchar buf \u003d 0;\n+\n+\tif (write(pt-\u003edummy_pipe_fds[1], \u0026buf, sizeof(buf)) !\u003d 1)\n+\t\tlwsl_err(\u0022Cannot write to dummy pipe\u0022);\n+#endif\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service(struct lws_context *context)\n+{\n+#if 0\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+\tchar buf \u003d 0, m \u003d context-\u003ecount_threads;\n+\n+\twhile (m--) {\n+\t\tif (write(pt-\u003edummy_pipe_fds[1], \u0026buf, sizeof(buf)) !\u003d 1)\n+\t\t\tlwsl_err(\u0022Cannot write to dummy pipe\u0022);\n+\t\tpt++;\n+\t}\n+#endif\n+}\n+#if 0\n+LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n+{\n+\tIMSG(\u0022%d: %s\u005cn\u0022, level, line);\n+}\n+#endif\n+\n+LWS_VISIBLE LWS_EXTERN int\n+_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n+{\n+\tstruct lws_context_per_thread *pt;\n+\tint n \u003d -1, m, c;\n+\t//char buf;\n+\n+\t/* stay dead once we are dead */\n+\n+\tif (!context || !context-\u003evhost_list)\n+\t\treturn 1;\n+\n+\tpt \u003d \u0026context-\u003ept[tsi];\n+\n+\tif (timeout_ms \u003c 0)\n+\t\tgoto faked_service;\n+\n+\tif (!context-\u003eservice_tid_detected) {\n+\t\tstruct lws _lws;\n+\n+\t\tmemset(\u0026_lws, 0, sizeof(_lws));\n+\t\t_lws.context \u003d context;\n+\n+\t\tcontext-\u003eservice_tid_detected \u003d\n+\t\t\tcontext-\u003evhost_list-\u003eprotocols[0].callback(\n+\t\t\t\u0026_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);\n+\t}\n+\tcontext-\u003eservice_tid \u003d context-\u003eservice_tid_detected;\n+\n+\t/*\n+\t * is there anybody with pending stuff that needs service forcing?\n+\t */\n+\tif (!lws_service_adjust_timeout(context, 1, tsi)) {\n+\t\tlwsl_notice(\u0022%s: doing forced service\u005cn\u0022, __func__);\n+\t\t/* -1 timeout means just do forced service */\n+\t\t_lws_plat_service_tsi(context, -1, pt-\u003etid);\n+\t\t/* still somebody left who wants forced service? */\n+\t\tif (!lws_service_adjust_timeout(context, 1, pt-\u003etid))\n+\t\t\t/* yes... come back again quickly */\n+\t\t\ttimeout_ms \u003d 0;\n+\t}\n+#if 1\n+\tn \u003d poll(pt-\u003efds, pt-\u003efds_count, timeout_ms);\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\tif (!pt-\u003erx_draining_ext_list \u0026\u0026\n+\t !lws_ssl_anybody_has_buffered_read_tsi(context, tsi) \u0026\u0026 !n) {\n+#else\n+\tif (!pt-\u003erx_draining_ext_list \u0026\u0026 !n) /* poll timeout */ {\n+#endif\n+\t\tlws_service_fd_tsi(context, NULL, tsi);\n+\t\treturn 0;\n+\t}\n+#endif\n+faked_service:\n+\tm \u003d lws_service_flag_pending(context, tsi);\n+\tif (m)\n+\t\tc \u003d -1; /* unknown limit */\n+\telse\n+\t\tif (n \u003c 0) {\n+\t\t\tif (LWS_ERRNO !\u003d LWS_EINTR)\n+\t\t\t\treturn -1;\n+\t\t\treturn 0;\n+\t\t} else\n+\t\t\tc \u003d n;\n+\n+\t/* any socket with events to service? */\n+\tfor (n \u003d 0; n \u003c pt-\u003efds_count \u0026\u0026 c; n++) {\n+\t\tif (!pt-\u003efds[n].revents)\n+\t\t\tcontinue;\n+\n+\t\tc--;\n+#if 0\n+\t\tif (pt-\u003efds[n].fd \u003d\u003d pt-\u003edummy_pipe_fds[0]) {\n+\t\t\tif (read(pt-\u003efds[n].fd, \u0026buf, 1) !\u003d 1)\n+\t\t\t\tlwsl_err(\u0022Cannot read from dummy pipe.\u0022);\n+\t\t\tcontinue;\n+\t\t}\n+#endif\n+\t\tm \u003d lws_service_fd_tsi(context, \u0026pt-\u003efds[n], tsi);\n+\t\tif (m \u003c 0)\n+\t\t\treturn -1;\n+\t\t/* if something closed, retry this slot */\n+\t\tif (m)\n+\t\t\tn--;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_check_connection_error(struct lws *wsi)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_service(struct lws_context *context, int timeout_ms)\n+{\n+\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n+{\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_context_early_init(void)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_early_destroy(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_late_destroy(struct lws_context *context)\n+{\n+\tif (context-\u003elws_lookup)\n+\t\tlws_free(context-\u003elws_lookup);\n+}\n+\n+/* cast a struct sockaddr_in6 * into addr for ipv6 */\n+\n+LWS_VISIBLE int\n+lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,\n+\t\t size_t addrlen)\n+{\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\n+\tpt-\u003efds[pt-\u003efds_count++].revents \u003d 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_delete_socket_from_fds(struct lws_context *context,\n+\t\t\t\t\t\tstruct lws *wsi, int m)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\n+\tpt-\u003efds_count--;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_service_periodic(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_change_pollfd(struct lws_context *context,\n+\t\t struct lws *wsi, struct lws_pollfd *pfd)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE const char *\n+lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n+{\n+\t//return inet_ntop(af, src, dst, cnt);\n+\treturn \u0022lws_plat_inet_ntop\u0022;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_inet_pton(int af, const char *src, void *dst)\n+{\n+\t//return inet_pton(af, src, dst);\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE lws_fop_fd_t\n+_lws_plat_file_open(lws_plat_file_open(struct lws_plat_file_ops *fops,\n+\t\t const char *filename, lws_fop_flags_t *flags)\n+{\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE int\n+_lws_plat_file_close(lws_fop_fd_t *fop_fd)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE lws_fileofs_t\n+_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n+\t\t uint8_t *buf, lws_filepos_t len)\n+{\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n+\t\t uint8_t *buf, lws_filepos_t len)\n+{\n+\n+\treturn 0;\n+}\n+\n+\n+LWS_VISIBLE int\n+lws_plat_init(struct lws_context *context,\n+\t struct lws_context_creation_info *info)\n+{\n+\t/* master context has the global fd lookup array */\n+\tcontext-\u003elws_lookup \u003d lws_zalloc(sizeof(struct lws *) *\n+\t\t\t\t\t context-\u003emax_fds, \u0022lws_lookup\u0022);\n+\tif (context-\u003elws_lookup \u003d\u003d NULL) {\n+\t\tlwsl_err(\u0022OOM on lws_lookup array for %d connections\u005cn\u0022,\n+\t\t\t context-\u003emax_fds);\n+\t\treturn 1;\n+\t}\n+\n+\tlwsl_notice(\u0022 mem: platform fd map: %5lu bytes\u005cn\u0022,\n+\t\t (long)sizeof(struct lws *) * context-\u003emax_fds);\n+\n+#ifdef LWS_WITH_PLUGINS\n+\tif (info-\u003eplugin_dirs)\n+\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n+#endif\n+\n+\treturn 0;\n+}\ndiff --git a/lib/plat/lws-plat-unix.c b/lib/plat/lws-plat-unix.c\nnew file mode 100644\nindex 0000000..f553691\n--- /dev/null\n+++ b/lib/plat/lws-plat-unix.c\n@@ -0,0 +1,849 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#include \u003cpwd.h\u003e\n+#include \u003cgrp.h\u003e\n+\n+#ifdef LWS_WITH_PLUGINS\n+#include \u003cdlfcn.h\u003e\n+#endif\n+#include \u003cdirent.h\u003e\n+\n+unsigned long long time_in_microseconds(void)\n+{\n+\tstruct timeval tv;\n+\n+\tgettimeofday(\u0026tv, NULL);\n+\treturn ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;\n+}\n+\n+LWS_VISIBLE int\n+lws_get_random(struct lws_context *context, void *buf, int len)\n+{\n+\treturn read(context-\u003efd_random, (char *)buf, len);\n+}\n+\n+LWS_VISIBLE int\n+lws_send_pipe_choked(struct lws *wsi)\n+{\n+\tstruct lws_pollfd fds;\n+\tstruct lws *wsi_eff \u003d wsi;\n+\n+#if defined(LWS_WITH_HTTP2)\n+\twsi_eff \u003d lws_get_network_wsi(wsi);\n+#endif\n+\t/* treat the fact we got a truncated send pending as if we're choked */\n+\tif (wsi_eff-\u003etrunc_len)\n+\t\treturn 1;\n+\n+\tfds.fd \u003d wsi_eff-\u003edesc.sockfd;\n+\tfds.events \u003d POLLOUT;\n+\tfds.revents \u003d 0;\n+\n+\tif (poll(\u0026fds, 1, 0) !\u003d 1)\n+\t\treturn 1;\n+\n+\tif ((fds.revents \u0026 POLLOUT) \u003d\u003d 0)\n+\t\treturn 1;\n+\n+\t/* okay to send another packet without blocking */\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_poll_listen_fd(struct lws_pollfd *fd)\n+{\n+\treturn poll(fd, 1, 0);\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service_pt(struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tchar buf \u003d 0;\n+\n+\tif (write(pt-\u003edummy_pipe_fds[1], \u0026buf, sizeof(buf)) !\u003d 1)\n+\t\tlwsl_err(\u0022Cannot write to dummy pipe\u0022);\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service(struct lws_context *context)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+\tchar buf \u003d 0, m \u003d context-\u003ecount_threads;\n+\n+\twhile (m--) {\n+\t\tif (write(pt-\u003edummy_pipe_fds[1], \u0026buf, sizeof(buf)) !\u003d 1)\n+\t\t\tlwsl_err(\u0022Cannot write to dummy pipe\u0022);\n+\t\tpt++;\n+\t}\n+}\n+\n+LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n+{\n+\tint syslog_level \u003d LOG_DEBUG;\n+\n+\tswitch (level) {\n+\tcase LLL_ERR:\n+\t\tsyslog_level \u003d LOG_ERR;\n+\t\tbreak;\n+\tcase LLL_WARN:\n+\t\tsyslog_level \u003d LOG_WARNING;\n+\t\tbreak;\n+\tcase LLL_NOTICE:\n+\t\tsyslog_level \u003d LOG_NOTICE;\n+\t\tbreak;\n+\tcase LLL_INFO:\n+\t\tsyslog_level \u003d LOG_INFO;\n+\t\tbreak;\n+\t}\n+\tsyslog(syslog_level, \u0022%s\u0022, line);\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n+{\n+\tstruct lws_context_per_thread *pt;\n+\tint n \u003d -1, m, c;\n+\tchar buf;\n+\n+\t/* stay dead once we are dead */\n+\n+\tif (!context || !context-\u003evhost_list)\n+\t\treturn 1;\n+\n+\tpt \u003d \u0026context-\u003ept[tsi];\n+\n+\tlws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);\n+\n+\tif (timeout_ms \u003c 0)\n+\t\tgoto faked_service;\n+\n+\tlws_libev_run(context, tsi);\n+\tlws_libuv_run(context, tsi);\n+\tlws_libevent_run(context, tsi);\n+\n+\tif (!context-\u003eservice_tid_detected) {\n+\t\tstruct lws _lws;\n+\n+\t\tmemset(\u0026_lws, 0, sizeof(_lws));\n+\t\t_lws.context \u003d context;\n+\n+\t\tcontext-\u003eservice_tid_detected \u003d\n+\t\t\tcontext-\u003evhost_list-\u003eprotocols[0].callback(\n+\t\t\t\u0026_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);\n+\t}\n+\tcontext-\u003eservice_tid \u003d context-\u003eservice_tid_detected;\n+\n+\t/*\n+\t * is there anybody with pending stuff that needs service forcing?\n+\t */\n+\tif (!lws_service_adjust_timeout(context, 1, tsi)) {\n+\t\t/* -1 timeout means just do forced service */\n+\t\t_lws_plat_service_tsi(context, -1, pt-\u003etid);\n+\t\t/* still somebody left who wants forced service? */\n+\t\tif (!lws_service_adjust_timeout(context, 1, pt-\u003etid))\n+\t\t\t/* yes... come back again quickly */\n+\t\t\ttimeout_ms \u003d 0;\n+\t}\n+\n+\tn \u003d poll(pt-\u003efds, pt-\u003efds_count, timeout_ms);\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\tif (!pt-\u003erx_draining_ext_list \u0026\u0026\n+\t !lws_ssl_anybody_has_buffered_read_tsi(context, tsi) \u0026\u0026 !n) {\n+#else\n+\tif (!pt-\u003erx_draining_ext_list \u0026\u0026 !n) /* poll timeout */ {\n+#endif\n+\t\tlws_service_fd_tsi(context, NULL, tsi);\n+\t\treturn 0;\n+\t}\n+\n+faked_service:\n+\tm \u003d lws_service_flag_pending(context, tsi);\n+\tif (m)\n+\t\tc \u003d -1; /* unknown limit */\n+\telse\n+\t\tif (n \u003c 0) {\n+\t\t\tif (LWS_ERRNO !\u003d LWS_EINTR)\n+\t\t\t\treturn -1;\n+\t\t\treturn 0;\n+\t\t} else\n+\t\t\tc \u003d n;\n+\n+\t/* any socket with events to service? */\n+\tfor (n \u003d 0; n \u003c pt-\u003efds_count \u0026\u0026 c; n++) {\n+\t\tif (!pt-\u003efds[n].revents)\n+\t\t\tcontinue;\n+\n+\t\tc--;\n+\n+\t\tif (pt-\u003efds[n].fd \u003d\u003d pt-\u003edummy_pipe_fds[0]) {\n+\t\t\tif (read(pt-\u003efds[n].fd, \u0026buf, 1) !\u003d 1)\n+\t\t\t\tlwsl_err(\u0022Cannot read from dummy pipe.\u0022);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tm \u003d lws_service_fd_tsi(context, \u0026pt-\u003efds[n], tsi);\n+\t\tif (m \u003c 0)\n+\t\t\treturn -1;\n+\t\t/* if something closed, retry this slot */\n+\t\tif (m)\n+\t\t\tn--;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_check_connection_error(struct lws *wsi)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_service(struct lws_context *context, int timeout_ms)\n+{\n+\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)\n+{\n+\tint optval \u003d 1;\n+\tsocklen_t optlen \u003d sizeof(optval);\n+\n+#if defined(__APPLE__) || \u005c\n+ defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \u005c\n+ defined(__NetBSD__) || \u005c\n+ defined(__OpenBSD__) || \u005c\n+ defined(__HAIKU__)\n+\tstruct protoent *tcp_proto;\n+#endif\n+\n+\tif (vhost-\u003eka_time) {\n+\t\t/* enable keepalive on this socket */\n+\t\toptval \u003d 1;\n+\t\tif (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,\n+\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n+\t\t\treturn 1;\n+\n+#if defined(__APPLE__) || \u005c\n+ defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \u005c\n+ defined(__NetBSD__) || \u005c\n+ defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun) || \u005c\n+ defined(__HAIKU__)\n+\n+\t\t/*\n+\t\t * didn't find a way to set these per-socket, need to\n+\t\t * tune kernel systemwide values\n+\t\t */\n+#else\n+\t\t/* set the keepalive conditions we want on it too */\n+\t\toptval \u003d vhost-\u003eka_time;\n+\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,\n+\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n+\t\t\treturn 1;\n+\n+\t\toptval \u003d vhost-\u003eka_interval;\n+\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,\n+\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n+\t\t\treturn 1;\n+\n+\t\toptval \u003d vhost-\u003eka_probes;\n+\t\tif (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,\n+\t\t\t (const void *)\u0026optval, optlen) \u003c 0)\n+\t\t\treturn 1;\n+#endif\n+\t}\n+\n+#if defined(SO_BINDTODEVICE)\n+\tif (vhost-\u003ebind_iface \u0026\u0026 vhost-\u003eiface) {\n+\t\tlwsl_info(\u0022binding listen skt to %s using SO_BINDTODEVICE\u005cn\u0022, vhost-\u003eiface);\n+\t\tif (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost-\u003eiface,\n+\t\t\t\tstrlen(vhost-\u003eiface)) \u003c 0) {\n+\t\t\tlwsl_warn(\u0022Failed to bind to device %s\u005cn\u0022, vhost-\u003eiface);\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+#endif\n+\n+\t/* Disable Nagle */\n+\toptval \u003d 1;\n+#if defined (__sun)\n+\tif (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)\u0026optval, optlen) \u003c 0)\n+\t\treturn 1;\n+#elif !defined(__APPLE__) \u0026\u0026 \u005c\n+ !defined(__FreeBSD__) \u0026\u0026 !defined(__FreeBSD_kernel__) \u0026\u0026 \u005c\n+ !defined(__NetBSD__) \u0026\u0026 \u005c\n+ !defined(__OpenBSD__) \u0026\u0026 \u005c\n+ !defined(__HAIKU__)\n+\tif (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)\u0026optval, optlen) \u003c 0)\n+\t\treturn 1;\n+#else\n+\ttcp_proto \u003d getprotobyname(\u0022TCP\u0022);\n+\tif (setsockopt(fd, tcp_proto-\u003ep_proto, TCP_NODELAY, \u0026optval, optlen) \u003c 0)\n+\t\treturn 1;\n+#endif\n+\n+\t/* We are nonblocking... */\n+\tif (fcntl(fd, F_SETFL, O_NONBLOCK) \u003c 0)\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+#if defined(LWS_HAVE_SYS_CAPABILITY_H) \u0026\u0026 defined(LWS_HAVE_LIBCAP)\n+static void\n+_lws_plat_apply_caps(int mode, cap_value_t *cv, int count)\n+{\n+\tcap_t caps;\n+\n+\tif (!count)\n+\t\treturn;\n+\n+\tcaps \u003d cap_get_proc();\n+\n+\tcap_set_flag(caps, mode, count, cv, CAP_SET);\n+\tcap_set_proc(caps);\n+\tprctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);\n+\tcap_free(caps);\n+}\n+#endif\n+\n+LWS_VISIBLE void\n+lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n+{\n+#if defined(LWS_HAVE_SYS_CAPABILITY_H) \u0026\u0026 defined(LWS_HAVE_LIBCAP)\n+\tint n;\n+#endif\n+\n+\tif (info-\u003egid \u0026\u0026 info-\u003egid !\u003d -1)\n+\t\tif (setgid(info-\u003egid))\n+\t\t\tlwsl_warn(\u0022setgid: %s\u005cn\u0022, strerror(LWS_ERRNO));\n+\n+\tif (info-\u003euid \u0026\u0026 info-\u003euid !\u003d -1) {\n+\t\tstruct passwd *p \u003d getpwuid(info-\u003euid);\n+\n+\t\tif (p) {\n+\n+#if defined(LWS_HAVE_SYS_CAPABILITY_H) \u0026\u0026 defined(LWS_HAVE_LIBCAP)\n+\t\t\t_lws_plat_apply_caps(CAP_PERMITTED, info-\u003ecaps, info-\u003ecount_caps);\n+#endif\n+\n+\t\t\tinitgroups(p-\u003epw_name, info-\u003egid);\n+\t\t\tif (setuid(info-\u003euid))\n+\t\t\t\tlwsl_warn(\u0022setuid: %s\u005cn\u0022, strerror(LWS_ERRNO));\n+\t\t\telse\n+\t\t\t\tlwsl_notice(\u0022Set privs to user '%s'\u005cn\u0022, p-\u003epw_name);\n+\n+#if defined(LWS_HAVE_SYS_CAPABILITY_H) \u0026\u0026 defined(LWS_HAVE_LIBCAP)\n+\t\t\t_lws_plat_apply_caps(CAP_EFFECTIVE, info-\u003ecaps, info-\u003ecount_caps);\n+\n+\t\t\tif (info-\u003ecount_caps)\n+\t\t\t\tfor (n \u003d 0; n \u003c info-\u003ecount_caps; n++)\n+\t\t\t\t\tlwsl_notice(\u0022 RETAINING CAPABILITY %d\u005cn\u0022, (int)info-\u003ecaps[n]);\n+#endif\n+\n+\t\t} else\n+\t\t\tlwsl_warn(\u0022getpwuid: unable to find uid %d\u0022, info-\u003euid);\n+\t}\n+}\n+\n+#ifdef LWS_WITH_PLUGINS\n+\n+#if defined(LWS_WITH_LIBUV) \u0026\u0026 UV_VERSION_MAJOR \u003e 0\n+\n+/* libuv.c implements these in a cross-platform way */\n+\n+#else\n+\n+static int filter(const struct dirent *ent)\n+{\n+\tif (!strcmp(ent-\u003ed_name, \u0022.\u0022) || !strcmp(ent-\u003ed_name, \u0022..\u0022))\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_plugins_init(struct lws_context * context, const char * const *d)\n+{\n+\tstruct lws_plugin_capability lcaps;\n+\tstruct lws_plugin *plugin;\n+\tlws_plugin_init_func initfunc;\n+\tstruct dirent **namelist;\n+\tint n, i, m, ret \u003d 0;\n+\tchar path[256];\n+\tvoid *l;\n+\n+\tlwsl_notice(\u0022 Plugins:\u005cn\u0022);\n+\n+\twhile (d \u0026\u0026 *d) {\n+\t\tn \u003d scandir(*d, \u0026namelist, filter, alphasort);\n+\t\tif (n \u003c 0) {\n+\t\t\tlwsl_err(\u0022Scandir on %s failed\u005cn\u0022, *d);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tfor (i \u003d 0; i \u003c n; i++) {\n+\t\t\tif (strlen(namelist[i]-\u003ed_name) \u003c 7)\n+\t\t\t\tgoto inval;\n+\n+\t\t\tlwsl_notice(\u0022 %s\u005cn\u0022, namelist[i]-\u003ed_name);\n+\n+\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, *d,\n+\t\t\t\t namelist[i]-\u003ed_name);\n+\t\t\tl \u003d dlopen(path, RTLD_NOW);\n+\t\t\tif (!l) {\n+\t\t\t\tlwsl_err(\u0022Error loading DSO: %s\u005cn\u0022, dlerror());\n+\t\t\t\twhile (i++ \u003c n)\n+\t\t\t\t\tfree(namelist[i]);\n+\t\t\t\tgoto bail;\n+\t\t\t}\n+\t\t\t/* we could open it, can we get his init function? */\n+\t\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022init_%s\u0022,\n+\t\t\t\t namelist[i]-\u003ed_name + 3 /* snip lib... */);\n+\t\t\tpath[m - 3] \u003d '\u005c0'; /* snip the .so */\n+\t\t\tinitfunc \u003d dlsym(l, path);\n+\t\t\tif (!initfunc) {\n+\t\t\t\tlwsl_err(\u0022Failed to get init on %s: %s\u0022,\n+\t\t\t\t\t\tnamelist[i]-\u003ed_name, dlerror());\n+\t\t\t\tdlclose(l);\n+\t\t\t}\n+\t\t\tlcaps.api_magic \u003d LWS_PLUGIN_API_MAGIC;\n+\t\t\tm \u003d initfunc(context, \u0026lcaps);\n+\t\t\tif (m) {\n+\t\t\t\tlwsl_err(\u0022Initializing %s failed %d\u005cn\u0022,\n+\t\t\t\t\tnamelist[i]-\u003ed_name, m);\n+\t\t\t\tdlclose(l);\n+\t\t\t\tgoto skip;\n+\t\t\t}\n+\n+\t\t\tplugin \u003d lws_malloc(sizeof(*plugin), \u0022plugin\u0022);\n+\t\t\tif (!plugin) {\n+\t\t\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n+\t\t\t\tgoto bail;\n+\t\t\t}\n+\t\t\tplugin-\u003elist \u003d context-\u003eplugin_list;\n+\t\t\tcontext-\u003eplugin_list \u003d plugin;\n+\t\t\tstrncpy(plugin-\u003ename, namelist[i]-\u003ed_name, sizeof(plugin-\u003ename) - 1);\n+\t\t\tplugin-\u003ename[sizeof(plugin-\u003ename) - 1] \u003d '\u005c0';\n+\t\t\tplugin-\u003el \u003d l;\n+\t\t\tplugin-\u003ecaps \u003d lcaps;\n+\t\t\tcontext-\u003eplugin_protocol_count +\u003d lcaps.count_protocols;\n+\t\t\tcontext-\u003eplugin_extension_count +\u003d lcaps.count_extensions;\n+\n+\t\t\tfree(namelist[i]);\n+\t\t\tcontinue;\n+\n+\tskip:\n+\t\t\tdlclose(l);\n+\tinval:\n+\t\t\tfree(namelist[i]);\n+\t\t}\n+\t\tfree(namelist);\n+\t\td++;\n+\t}\n+\n+bail:\n+\tfree(namelist);\n+\n+\treturn ret;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_plugins_destroy(struct lws_context * context)\n+{\n+\tstruct lws_plugin *plugin \u003d context-\u003eplugin_list, *p;\n+\tlws_plugin_destroy_func func;\n+\tchar path[256];\n+\tint m;\n+\n+\tif (!plugin)\n+\t\treturn 0;\n+\n+\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n+\n+\twhile (plugin) {\n+\t\tp \u003d plugin;\n+\t\tm \u003d lws_snprintf(path, sizeof(path) - 1, \u0022destroy_%s\u0022, plugin-\u003ename + 3);\n+\t\tpath[m - 3] \u003d '\u005c0';\n+\t\tfunc \u003d dlsym(plugin-\u003el, path);\n+\t\tif (!func) {\n+\t\t\tlwsl_err(\u0022Failed to get destroy on %s: %s\u0022,\n+\t\t\t\t\tplugin-\u003ename, dlerror());\n+\t\t\tgoto next;\n+\t\t}\n+\t\tm \u003d func(context);\n+\t\tif (m)\n+\t\t\tlwsl_err(\u0022Initializing %s failed %d\u005cn\u0022,\n+\t\t\t\tplugin-\u003ename, m);\n+next:\n+\t\tdlclose(p-\u003el);\n+\t\tplugin \u003d p-\u003elist;\n+\t\tp-\u003elist \u003d NULL;\n+\t\tfree(p);\n+\t}\n+\n+\tcontext-\u003eplugin_list \u003d NULL;\n+\n+\treturn 0;\n+}\n+\n+#endif\n+#endif\n+\n+\n+#if 0\n+static void\n+sigabrt_handler(int x)\n+{\n+\tprintf(\u0022%s\u005cn\u0022, __func__);\n+}\n+#endif\n+\n+LWS_VISIBLE int\n+lws_plat_context_early_init(void)\n+{\n+#if !defined(LWS_AVOID_SIGPIPE_IGN)\n+\tsignal(SIGPIPE, SIG_IGN);\n+#endif\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_early_destroy(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_late_destroy(struct lws_context *context)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+\tint m \u003d context-\u003ecount_threads;\n+\n+#ifdef LWS_WITH_PLUGINS\n+\tif (context-\u003eplugin_list)\n+\t\tlws_plat_plugins_destroy(context);\n+#endif\n+\n+\tif (context-\u003elws_lookup)\n+\t\tlws_free(context-\u003elws_lookup);\n+\n+\twhile (m--) {\n+\t\tif (pt-\u003edummy_pipe_fds[0])\n+\t\t\tclose(pt-\u003edummy_pipe_fds[0]);\n+\t\tif (pt-\u003edummy_pipe_fds[1])\n+\t\t\tclose(pt-\u003edummy_pipe_fds[1]);\n+\t\tpt++;\n+\t}\n+\tif (!context-\u003efd_random)\n+\t\tlwsl_err(\u0022ZERO RANDOM FD\u005cn\u0022);\n+\tif (context-\u003efd_random !\u003d LWS_INVALID_FILE)\n+\t\tclose(context-\u003efd_random);\n+}\n+\n+/* cast a struct sockaddr_in6 * into addr for ipv6 */\n+\n+LWS_VISIBLE int\n+lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,\n+\t\t size_t addrlen)\n+{\n+\tint rc \u003d -1;\n+\n+\tstruct ifaddrs *ifr;\n+\tstruct ifaddrs *ifc;\n+#ifdef LWS_WITH_IPV6\n+\tstruct sockaddr_in6 *addr6 \u003d (struct sockaddr_in6 *)addr;\n+#endif\n+\n+\tgetifaddrs(\u0026ifr);\n+\tfor (ifc \u003d ifr; ifc !\u003d NULL \u0026\u0026 rc; ifc \u003d ifc-\u003eifa_next) {\n+\t\tif (!ifc-\u003eifa_addr)\n+\t\t\tcontinue;\n+\n+\t\tlwsl_info(\u0022 interface %s vs %s\u005cn\u0022, ifc-\u003eifa_name, ifname);\n+\n+\t\tif (strcmp(ifc-\u003eifa_name, ifname))\n+\t\t\tcontinue;\n+\n+\t\tswitch (ifc-\u003eifa_addr-\u003esa_family) {\n+\t\tcase AF_INET:\n+#ifdef LWS_WITH_IPV6\n+\t\t\tif (ipv6) {\n+\t\t\t\t/* map IPv4 to IPv6 */\n+\t\t\t\tbzero((char *)\u0026addr6-\u003esin6_addr,\n+\t\t\t\t\t\tsizeof(struct in6_addr));\n+\t\t\t\taddr6-\u003esin6_addr.s6_addr[10] \u003d 0xff;\n+\t\t\t\taddr6-\u003esin6_addr.s6_addr[11] \u003d 0xff;\n+\t\t\t\tmemcpy(\u0026addr6-\u003esin6_addr.s6_addr[12],\n+\t\t\t\t\t\u0026((struct sockaddr_in *)ifc-\u003eifa_addr)-\u003esin_addr,\n+\t\t\t\t\t\t\tsizeof(struct in_addr));\n+\t\t\t} else\n+#endif\n+\t\t\t\tmemcpy(addr,\n+\t\t\t\t\t(struct sockaddr_in *)ifc-\u003eifa_addr,\n+\t\t\t\t\t\t sizeof(struct sockaddr_in));\n+\t\t\tbreak;\n+#ifdef LWS_WITH_IPV6\n+\t\tcase AF_INET6:\n+\t\t\tmemcpy(\u0026addr6-\u003esin6_addr,\n+\t\t\t \u0026((struct sockaddr_in6 *)ifc-\u003eifa_addr)-\u003esin6_addr,\n+\t\t\t\t\t\t sizeof(struct in6_addr));\n+\t\t\tbreak;\n+#endif\n+\t\tdefault:\n+\t\t\tcontinue;\n+\t\t}\n+\t\trc \u003d 0;\n+\t}\n+\n+\tfreeifaddrs(ifr);\n+\n+\tif (rc \u003d\u003d -1) {\n+\t\t/* check if bind to IP address */\n+#ifdef LWS_WITH_IPV6\n+\t\tif (inet_pton(AF_INET6, ifname, \u0026addr6-\u003esin6_addr) \u003d\u003d 1)\n+\t\t\trc \u003d 0;\n+\t\telse\n+#endif\n+\t\tif (inet_pton(AF_INET, ifname, \u0026addr-\u003esin_addr) \u003d\u003d 1)\n+\t\t\trc \u003d 0;\n+\t}\n+\n+\treturn rc;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\n+\tlws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);\n+\tlws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);\n+\tlws_libevent_io(wsi, LWS_EV_START | LWS_EV_READ);\n+\n+\tpt-\u003efds[pt-\u003efds_count++].revents \u003d 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_delete_socket_from_fds(struct lws_context *context,\n+\t\t\t\t\t\tstruct lws *wsi, int m)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\n+\tlws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);\n+\tlws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);\n+\tlws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);\n+\n+\tpt-\u003efds_count--;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_service_periodic(struct lws_context *context)\n+{\n+\t/* if our parent went down, don't linger around */\n+\tif (context-\u003estarted_with_parent \u0026\u0026\n+\t kill(context-\u003estarted_with_parent, 0) \u003c 0)\n+\t\tkill(getpid(), SIGTERM);\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_change_pollfd(struct lws_context *context,\n+\t\t struct lws *wsi, struct lws_pollfd *pfd)\n+{\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE const char *\n+lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n+{\n+\treturn inet_ntop(af, src, dst, cnt);\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_inet_pton(int af, const char *src, void *dst)\n+{\n+\treturn inet_pton(af, src, dst);\n+}\n+\n+LWS_VISIBLE lws_fop_fd_t\n+_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,\n+\t\t const char *vpath, lws_fop_flags_t *flags)\n+{\n+\tstruct stat stat_buf;\n+\tint ret \u003d open(filename, (*flags) \u0026 LWS_FOP_FLAGS_MASK, 0664);\n+\tlws_fop_fd_t fop_fd;\n+\n+\tif (ret \u003c 0)\n+\t\treturn NULL;\n+\n+\tif (fstat(ret, \u0026stat_buf) \u003c 0)\n+\t\tgoto bail;\n+\n+\tfop_fd \u003d malloc(sizeof(*fop_fd));\n+\tif (!fop_fd)\n+\t\tgoto bail;\n+\n+\tfop_fd-\u003efops \u003d fops;\n+\tfop_fd-\u003eflags \u003d *flags;\n+\tfop_fd-\u003efd \u003d ret;\n+\tfop_fd-\u003efilesystem_priv \u003d NULL; /* we don't use it */\n+\tfop_fd-\u003elen \u003d stat_buf.st_size;\n+\tfop_fd-\u003epos \u003d 0;\n+\n+\treturn fop_fd;\n+\n+bail:\n+\tclose(ret);\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE int\n+_lws_plat_file_close(lws_fop_fd_t *fop_fd)\n+{\n+\tint fd \u003d (*fop_fd)-\u003efd;\n+\n+\tfree(*fop_fd);\n+\t*fop_fd \u003d NULL;\n+\n+\treturn close(fd);\n+}\n+\n+LWS_VISIBLE lws_fileofs_t\n+_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)\n+{\n+\tlws_fileofs_t r;\n+\n+\tif (offset \u003e 0 \u0026\u0026 offset \u003e fop_fd-\u003elen - fop_fd-\u003epos)\n+\t\toffset \u003d fop_fd-\u003elen - fop_fd-\u003epos;\n+\n+\tif ((lws_fileofs_t)fop_fd-\u003epos + offset \u003c 0)\n+\t\toffset \u003d -fop_fd-\u003epos;\n+\n+\tr \u003d lseek(fop_fd-\u003efd, offset, SEEK_CUR);\n+\n+\tif (r \u003e\u003d 0)\n+\t\tfop_fd-\u003epos \u003d r;\n+\telse\n+\t\tlwsl_err(\u0022error seeking from cur %ld, offset %ld\u005cn\u0022,\n+ (long)fop_fd-\u003epos, (long)offset);\n+\n+\treturn r;\n+}\n+\n+LWS_VISIBLE int\n+_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n+\t\t uint8_t *buf, lws_filepos_t len)\n+{\n+\tlong n;\n+\n+\tn \u003d read((int)fop_fd-\u003efd, buf, len);\n+\tif (n \u003d\u003d -1) {\n+\t\t*amount \u003d 0;\n+\t\treturn -1;\n+\t}\n+\tfop_fd-\u003epos +\u003d n;\n+\tlwsl_debug(\u0022%s: read %ld of req %ld, pos %ld, len %ld\u005cn\u0022, __func__, n,\n+ (long)len, (long)fop_fd-\u003epos, (long)fop_fd-\u003elen);\n+\t*amount \u003d n;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n+\t\t uint8_t *buf, lws_filepos_t len)\n+{\n+\tlong n;\n+\n+\tn \u003d write((int)fop_fd-\u003efd, buf, len);\n+\tif (n \u003d\u003d -1) {\n+\t\t*amount \u003d 0;\n+\t\treturn -1;\n+\t}\n+\n+\tfop_fd-\u003epos +\u003d n;\n+\t*amount \u003d n;\n+\n+\treturn 0;\n+}\n+\n+\n+LWS_VISIBLE int\n+lws_plat_init(struct lws_context *context,\n+\t struct lws_context_creation_info *info)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+\tint n \u003d context-\u003ecount_threads, fd;\n+\n+\t/* master context has the global fd lookup array */\n+\tcontext-\u003elws_lookup \u003d lws_zalloc(sizeof(struct lws *) *\n+\t\t\t\t\t context-\u003emax_fds, \u0022lws_lookup\u0022);\n+\tif (context-\u003elws_lookup \u003d\u003d NULL) {\n+\t\tlwsl_err(\u0022OOM on lws_lookup array for %d connections\u005cn\u0022,\n+\t\t\t context-\u003emax_fds);\n+\t\treturn 1;\n+\t}\n+\n+\tlwsl_info(\u0022 mem: platform fd map: %5lu bytes\u005cn\u0022,\n+\t\t (unsigned long)(sizeof(struct lws *) * context-\u003emax_fds));\n+\tfd \u003d open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);\n+\n+\tcontext-\u003efd_random \u003d fd;\n+\tif (context-\u003efd_random \u003c 0) {\n+\t\tlwsl_err(\u0022Unable to open random device %s %d\u005cn\u0022,\n+\t\t\t SYSTEM_RANDOM_FILEPATH, context-\u003efd_random);\n+\t\treturn 1;\n+\t}\n+\n+\tif (!lws_libev_init_fd_table(context) \u0026\u0026\n+\t !lws_libuv_init_fd_table(context) \u0026\u0026\n+\t !lws_libevent_init_fd_table(context)) {\n+\t\t/* otherwise libev/uv/event handled it instead */\n+\n+\t\twhile (n--) {\n+\t\t\tif (pipe(pt-\u003edummy_pipe_fds)) {\n+\t\t\t\tlwsl_err(\u0022Unable to create pipe\u005cn\u0022);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n+\t\t\t/* use the read end of pipe as first item */\n+\t\t\tpt-\u003efds[0].fd \u003d pt-\u003edummy_pipe_fds[0];\n+\t\t\tpt-\u003efds[0].events \u003d LWS_POLLIN;\n+\t\t\tpt-\u003efds[0].revents \u003d 0;\n+\t\t\tpt-\u003efds_count \u003d 1;\n+\t\t\tpt++;\n+\t\t}\n+\t}\n+\n+#ifdef LWS_WITH_PLUGINS\n+\tif (info-\u003eplugin_dirs)\n+\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n+#endif\n+\n+\treturn 0;\n+}\ndiff --git a/lib/plat/lws-plat-win.c b/lib/plat/lws-plat-win.c\nnew file mode 100644\nindex 0000000..ed1c92e\n--- /dev/null\n+++ b/lib/plat/lws-plat-win.c\n@@ -0,0 +1,745 @@\n+#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS\n+#define _WINSOCK_DEPRECATED_NO_WARNINGS\n+#endif\n+#include \u0022private-libwebsockets.h\u0022\n+\n+unsigned long long\n+time_in_microseconds()\n+{\n+#ifndef DELTA_EPOCH_IN_MICROSECS\n+#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL\n+#endif\n+\tFILETIME filetime;\n+\tULARGE_INTEGER datetime;\n+\n+#ifdef _WIN32_WCE\n+\tGetCurrentFT(\u0026filetime);\n+#else\n+\tGetSystemTimeAsFileTime(\u0026filetime);\n+#endif\n+\n+\t/*\n+\t * As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a\n+\t * ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can\n+\t * prevent alignment faults on 64-bit Windows).\n+\t */\n+\tmemcpy(\u0026datetime, \u0026filetime, sizeof(datetime));\n+\n+\t/* Windows file times are in 100s of nanoseconds. */\n+\treturn (datetime.QuadPart - DELTA_EPOCH_IN_MICROSECS) / 10;\n+}\n+\n+#ifdef _WIN32_WCE\n+time_t time(time_t *t)\n+{\n+\ttime_t ret \u003d time_in_microseconds() / 1000000;\n+\n+\tif(t !\u003d NULL)\n+\t\t*t \u003d ret;\n+\n+\treturn ret;\n+}\n+#endif\n+\n+/* file descriptor hash management */\n+\n+struct lws *\n+wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)\n+{\n+\tint h \u003d LWS_FD_HASH(fd);\n+\tint n \u003d 0;\n+\n+\tfor (n \u003d 0; n \u003c context-\u003efd_hashtable[h].length; n++)\n+\t\tif (context-\u003efd_hashtable[h].wsi[n]-\u003edesc.sockfd \u003d\u003d fd)\n+\t\t\treturn context-\u003efd_hashtable[h].wsi[n];\n+\n+\treturn NULL;\n+}\n+\n+int\n+insert_wsi(struct lws_context *context, struct lws *wsi)\n+{\n+\tint h \u003d LWS_FD_HASH(wsi-\u003edesc.sockfd);\n+\n+\tif (context-\u003efd_hashtable[h].length \u003d\u003d (getdtablesize() - 1)) {\n+\t\tlwsl_err(\u0022hash table overflow\u005cn\u0022);\n+\t\treturn 1;\n+\t}\n+\n+\tcontext-\u003efd_hashtable[h].wsi[context-\u003efd_hashtable[h].length++] \u003d wsi;\n+\n+\treturn 0;\n+}\n+\n+int\n+delete_from_fd(struct lws_context *context, lws_sockfd_type fd)\n+{\n+\tint h \u003d LWS_FD_HASH(fd);\n+\tint n \u003d 0;\n+\n+\tfor (n \u003d 0; n \u003c context-\u003efd_hashtable[h].length; n++)\n+\t\tif (context-\u003efd_hashtable[h].wsi[n]-\u003edesc.sockfd \u003d\u003d fd) {\n+\t\t\twhile (n \u003c context-\u003efd_hashtable[h].length) {\n+\t\t\t\tcontext-\u003efd_hashtable[h].wsi[n] \u003d\n+\t\t\t\t\t\tcontext-\u003efd_hashtable[h].wsi[n + 1];\n+\t\t\t\tn++;\n+\t\t\t}\n+\t\t\tcontext-\u003efd_hashtable[h].length--;\n+\n+\t\t\treturn 0;\n+\t\t}\n+\n+\tlwsl_err(\u0022Failed to find fd %d requested for \u0022\n+\t\t \u0022delete in hashtable\u005cn\u0022, fd);\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE int lws_get_random(struct lws_context *context,\n+\t\t\t\t\t\t\t\t void *buf, int len)\n+{\n+\tint n;\n+\tchar *p \u003d (char *)buf;\n+\n+\tfor (n \u003d 0; n \u003c len; n++)\n+\t\tp[n] \u003d (unsigned char)rand();\n+\n+\treturn n;\n+}\n+\n+LWS_VISIBLE int lws_send_pipe_choked(struct lws *wsi)\n+{\n+\t/* treat the fact we got a truncated send pending as if we're choked */\n+\tif (wsi-\u003etrunc_len)\n+\t\treturn 1;\n+\n+\treturn (int)wsi-\u003esock_send_blocking;\n+}\n+\n+LWS_VISIBLE int lws_poll_listen_fd(struct lws_pollfd *fd)\n+{\n+\tfd_set readfds;\n+\tstruct timeval tv \u003d { 0, 0 };\n+\n+\tassert((fd-\u003eevents \u0026 LWS_POLLIN) \u003d\u003d LWS_POLLIN);\n+\n+\tFD_ZERO(\u0026readfds);\n+\tFD_SET(fd-\u003efd, \u0026readfds);\n+\n+\treturn select(fd-\u003efd + 1, \u0026readfds, NULL, NULL, \u0026tv);\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service(struct lws_context *context)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+\tint n \u003d context-\u003ecount_threads;\n+\n+\twhile (n--) {\n+\t\tWSASetEvent(pt-\u003eevents[0]);\n+\t\tpt++;\n+\t}\n+}\n+\n+LWS_VISIBLE void\n+lws_cancel_service_pt(struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tWSASetEvent(pt-\u003eevents[0]);\n+}\n+\n+LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)\n+{\n+\tlwsl_emit_stderr(level, line);\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)\n+{\n+\tstruct lws_context_per_thread *pt;\n+\tWSANETWORKEVENTS networkevents;\n+\tstruct lws_pollfd *pfd;\n+\tstruct lws *wsi;\n+\tunsigned int i;\n+\tDWORD ev;\n+\tint n, m;\n+\n+\t/* stay dead once we are dead */\n+\tif (context \u003d\u003d NULL || !context-\u003evhost_list)\n+\t\treturn 1;\n+\n+\tpt \u003d \u0026context-\u003ept[tsi];\n+\n+\tif (!context-\u003eservice_tid_detected) {\n+\t\tstruct lws _lws;\n+\n+\t\tmemset(\u0026_lws, 0, sizeof(_lws));\n+\t\t_lws.context \u003d context;\n+\n+\t\tcontext-\u003eservice_tid_detected \u003d context-\u003evhost_list-\u003e\n+\t\t\tprotocols[0].callback(\u0026_lws, LWS_CALLBACK_GET_THREAD_ID,\n+\t\t\t\t\t\t NULL, NULL, 0);\n+\t}\n+\tcontext-\u003eservice_tid \u003d context-\u003eservice_tid_detected;\n+\n+\tif (timeout_ms \u003c 0)\n+\t{\n+\t\t\tif (lws_service_flag_pending(context, tsi)) {\n+\t\t\t/* any socket with events to service? */\n+\t\t\tfor (n \u003d 0; n \u003c (int)pt-\u003efds_count; n++) {\n+\t\t\t\tif (!pt-\u003efds[n].revents)\n+\t\t\t\t\tcontinue;\n+\n+\t\t\t\tm \u003d lws_service_fd_tsi(context, \u0026pt-\u003efds[n], tsi);\n+\t\t\t\tif (m \u003c 0)\n+\t\t\t\t\treturn -1;\n+\t\t\t\t/* if something closed, retry this slot */\n+\t\t\t\tif (m)\n+\t\t\t\t\tn--;\n+\t\t\t}\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\n+\tfor (i \u003d 0; i \u003c pt-\u003efds_count; ++i) {\n+\t\tpfd \u003d \u0026pt-\u003efds[i];\n+\n+\t\tif (!(pfd-\u003eevents \u0026 LWS_POLLOUT))\n+\t\t\tcontinue;\n+\n+\t\twsi \u003d wsi_from_fd(context, pfd-\u003efd);\n+\t\tif (wsi-\u003elistener)\n+\t\t\tcontinue;\n+\t\tif (!wsi || wsi-\u003esock_send_blocking)\n+\t\t\tcontinue;\n+\t\tpfd-\u003erevents \u003d LWS_POLLOUT;\n+\t\tn \u003d lws_service_fd(context, pfd);\n+\t\tif (n \u003c 0)\n+\t\t\treturn -1;\n+\t\t/* if something closed, retry this slot */\n+\t\tif (n)\n+\t\t\ti--;\n+\n+\t\tif (wsi-\u003etrunc_len)\n+\t\t\tWSASetEvent(pt-\u003eevents[0]);\n+\t}\n+\n+\t/*\n+\t * is there anybody with pending stuff that needs service forcing?\n+\t */\n+\tif (!lws_service_adjust_timeout(context, 1, tsi)) {\n+\t\t/* -1 timeout means just do forced service */\n+\t\t_lws_plat_service_tsi(context, -1, pt-\u003etid);\n+\t\t/* still somebody left who wants forced service? */\n+\t\tif (!lws_service_adjust_timeout(context, 1, pt-\u003etid))\n+\t\t\t/* yes... come back again quickly */\n+\t\t\ttimeout_ms \u003d 0;\n+\t}\n+\n+\tev \u003d WSAWaitForMultipleEvents( 1, pt-\u003eevents , FALSE, timeout_ms, FALSE);\n+\tif (ev \u003d\u003d WSA_WAIT_EVENT_0) {\n+\t\tunsigned int eIdx;\n+\n+\t\tWSAResetEvent(pt-\u003eevents[0]);\n+\n+\t\tfor (eIdx \u003d 0; eIdx \u003c pt-\u003efds_count; ++eIdx) {\n+\t\t\tif (WSAEnumNetworkEvents(pt-\u003efds[eIdx].fd, 0, \u0026networkevents) \u003d\u003d SOCKET_ERROR) {\n+\t\t\t\tlwsl_err(\u0022WSAEnumNetworkEvents() failed with error %d\u005cn\u0022, LWS_ERRNO);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\n+\t\t\tpfd \u003d \u0026pt-\u003efds[eIdx];\n+\t\t\tpfd-\u003erevents \u003d (short)networkevents.lNetworkEvents;\n+\n+\t\t\tif ((networkevents.lNetworkEvents \u0026 FD_CONNECT) \u0026\u0026\n+\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] \u0026\u0026\n+\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] !\u003d LWS_EALREADY \u0026\u0026\n+\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] !\u003d LWS_EINPROGRESS \u0026\u0026\n+\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] !\u003d LWS_EWOULDBLOCK \u0026\u0026\n+\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT] !\u003d WSAEINVAL) {\n+\t\t\t\tlwsl_debug(\u0022Unable to connect errno\u003d%d\u005cn\u0022,\n+\t\t\t\t\t networkevents.iErrorCode[FD_CONNECT_BIT]);\n+\t\t\t\tpfd-\u003erevents \u003d LWS_POLLHUP;\n+\t\t\t} else\n+\t\t\t\tpfd-\u003erevents \u003d (short)networkevents.lNetworkEvents;\n+\n+\t\t\tif (pfd-\u003erevents \u0026 LWS_POLLOUT) {\n+\t\t\t\twsi \u003d wsi_from_fd(context, pfd-\u003efd);\n+\t\t\t\tif (wsi)\n+\t\t\t\t\twsi-\u003esock_send_blocking \u003d 0;\n+\t\t\t}\n+\t\t\t /* if something closed, retry this slot */\n+\t\t\tif (pfd-\u003erevents \u0026 LWS_POLLHUP)\n+\t\t\t\t\t--eIdx;\n+\n+\t\t\tif( pfd-\u003erevents !\u003d 0 ) {\n+\t\t\t\tlws_service_fd_tsi(context, pfd, tsi);\n+\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tcontext-\u003eservice_tid \u003d 0;\n+\n+\tif (ev \u003d\u003d WSA_WAIT_TIMEOUT) {\n+\t\tlws_service_fd(context, NULL);\n+\t}\n+\treturn 0;;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_service(struct lws_context *context, int timeout_ms)\n+{\n+\treturn _lws_plat_service_tsi(context, timeout_ms, 0);\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)\n+{\n+\tint optval \u003d 1;\n+\tint optlen \u003d sizeof(optval);\n+\tu_long optl \u003d 1;\n+\tDWORD dwBytesRet;\n+\tstruct tcp_keepalive alive;\n+\tint protonbr;\n+#ifndef _WIN32_WCE\n+\tstruct protoent *tcp_proto;\n+#endif\n+\n+\tif (vhost-\u003eka_time) {\n+\t\t/* enable keepalive on this socket */\n+\t\toptval \u003d 1;\n+\t\tif (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,\n+\t\t\t\t\t\t (const char *)\u0026optval, optlen) \u003c 0)\n+\t\t\treturn 1;\n+\n+\t\talive.onoff \u003d TRUE;\n+\t\talive.keepalivetime \u003d vhost-\u003eka_time;\n+\t\talive.keepaliveinterval \u003d vhost-\u003eka_interval;\n+\n+\t\tif (WSAIoctl(fd, SIO_KEEPALIVE_VALS, \u0026alive, sizeof(alive),\n+\t\t\t\t\t\t NULL, 0, \u0026dwBytesRet, NULL, NULL))\n+\t\t\treturn 1;\n+\t}\n+\n+\t/* Disable Nagle */\n+\toptval \u003d 1;\n+#ifndef _WIN32_WCE\n+\ttcp_proto \u003d getprotobyname(\u0022TCP\u0022);\n+\tif (!tcp_proto) {\n+\t\tlwsl_err(\u0022getprotobyname() failed with error %d\u005cn\u0022, LWS_ERRNO);\n+\t\treturn 1;\n+\t}\n+\tprotonbr \u003d tcp_proto-\u003ep_proto;\n+#else\n+\tprotonbr \u003d 6;\n+#endif\n+\n+\tsetsockopt(fd, protonbr, TCP_NODELAY, (const char *)\u0026optval, optlen);\n+\n+\t/* We are nonblocking... */\n+\tioctlsocket(fd, FIONBIO, \u0026optl);\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_drop_app_privileges(struct lws_context_creation_info *info)\n+{\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_context_early_init(void)\n+{\n+\tWORD wVersionRequested;\n+\tWSADATA wsaData;\n+\tint err;\n+\n+\t/* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */\n+\twVersionRequested \u003d MAKEWORD(2, 2);\n+\n+\terr \u003d WSAStartup(wVersionRequested, \u0026wsaData);\n+\tif (!err)\n+\t\treturn 0;\n+\t/*\n+\t * Tell the user that we could not find a usable\n+\t * Winsock DLL\n+\t */\n+\tlwsl_err(\u0022WSAStartup failed with error: %d\u005cn\u0022, err);\n+\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_early_destroy(struct lws_context *context)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+\tint n \u003d context-\u003ecount_threads;\n+\n+\twhile (n--) {\n+\t\tif (pt-\u003eevents) {\n+\t\t\tWSACloseEvent(pt-\u003eevents[0]);\n+\t\t\tlws_free(pt-\u003eevents);\n+\t\t}\n+\t\tpt++;\n+\t}\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_context_late_destroy(struct lws_context *context)\n+{\n+\tint n;\n+\n+\tfor (n \u003d 0; n \u003c FD_HASHTABLE_MODULUS; n++) {\n+\t\tif (context-\u003efd_hashtable[n].wsi)\n+\t\t\tlws_free(context-\u003efd_hashtable[n].wsi);\n+\t}\n+\n+\tWSACleanup();\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_interface_to_sa(int ipv6,\n+\t\tconst char *ifname, struct sockaddr_in *addr, size_t addrlen)\n+{\n+#ifdef LWS_WITH_IPV6\n+\tstruct sockaddr_in6 *addr6 \u003d (struct sockaddr_in6 *)addr;\n+\n+\tif (ipv6) {\n+\t\tif (lws_plat_inet_pton(AF_INET6, ifname, \u0026addr6-\u003esin6_addr) \u003d\u003d 1) {\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+#endif\n+\n+\tlong long address \u003d inet_addr(ifname);\n+\n+\tif (address \u003d\u003d INADDR_NONE) {\n+\t\tstruct hostent *entry \u003d gethostbyname(ifname);\n+\t\tif (entry)\n+\t\t\taddress \u003d ((struct in_addr *)entry-\u003eh_addr_list[0])-\u003es_addr;\n+\t}\n+\n+\tif (address \u003d\u003d INADDR_NONE)\n+\t\treturn -1;\n+\n+\taddr-\u003esin_addr.s_addr \u003d (lws_intptr_t)address;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\n+\tpt-\u003efds[pt-\u003efds_count++].revents \u003d 0;\n+\tpt-\u003eevents[pt-\u003efds_count] \u003d pt-\u003eevents[0];\n+\tWSAEventSelect(wsi-\u003edesc.sockfd, pt-\u003eevents[0],\n+\t\t\t LWS_POLLIN | LWS_POLLHUP | FD_CONNECT);\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_delete_socket_from_fds(struct lws_context *context,\n+\t\t\t\t\t\tstruct lws *wsi, int m)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\n+\tpt-\u003eevents[m + 1] \u003d pt-\u003eevents[pt-\u003efds_count--];\n+}\n+\n+LWS_VISIBLE void\n+lws_plat_service_periodic(struct lws_context *context)\n+{\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_check_connection_error(struct lws *wsi)\n+{\n+\tint optVal;\n+\tint optLen \u003d sizeof(int);\n+\n+\tif (getsockopt(wsi-\u003edesc.sockfd, SOL_SOCKET, SO_ERROR,\n+\t\t\t (char*)\u0026optVal, \u0026optLen) !\u003d SOCKET_ERROR \u0026\u0026 optVal \u0026\u0026\n+\t\toptVal !\u003d LWS_EALREADY \u0026\u0026 optVal !\u003d LWS_EINPROGRESS \u0026\u0026\n+\t\toptVal !\u003d LWS_EWOULDBLOCK \u0026\u0026 optVal !\u003d WSAEINVAL) {\n+\t\t lwsl_debug(\u0022Connect failed SO_ERROR\u003d%d\u005cn\u0022, optVal);\n+\t\t return 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_change_pollfd(struct lws_context *context,\n+\t\t\t struct lws *wsi, struct lws_pollfd *pfd)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tlong networkevents \u003d LWS_POLLHUP | FD_CONNECT;\n+\n+\tif ((pfd-\u003eevents \u0026 LWS_POLLIN))\n+\t\tnetworkevents |\u003d LWS_POLLIN;\n+\n+\tif ((pfd-\u003eevents \u0026 LWS_POLLOUT))\n+\t\tnetworkevents |\u003d LWS_POLLOUT;\n+\n+\tif (WSAEventSelect(wsi-\u003edesc.sockfd,\n+\t\t\tpt-\u003eevents[0],\n+\t\t\t\t\t\t networkevents) !\u003d SOCKET_ERROR)\n+\t\treturn 0;\n+\n+\tlwsl_err(\u0022WSAEventSelect() failed with error %d\u005cn\u0022, LWS_ERRNO);\n+\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE const char *\n+lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)\n+{\n+\tWCHAR *buffer;\n+\tDWORD bufferlen \u003d cnt;\n+\tBOOL ok \u003d FALSE;\n+\n+\tbuffer \u003d lws_malloc(bufferlen * 2, \u0022inet_ntop\u0022);\n+\tif (!buffer) {\n+\t\tlwsl_err(\u0022Out of memory\u005cn\u0022);\n+\t\treturn NULL;\n+\t}\n+\n+\tif (af \u003d\u003d AF_INET) {\n+\t\tstruct sockaddr_in srcaddr;\n+\t\tbzero(\u0026srcaddr, sizeof(srcaddr));\n+\t\tsrcaddr.sin_family \u003d AF_INET;\n+\t\tmemcpy(\u0026(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));\n+\n+\t\tif (!WSAAddressToStringW((struct sockaddr*)\u0026srcaddr, sizeof(srcaddr), 0, buffer, \u0026bufferlen))\n+\t\t\tok \u003d TRUE;\n+#ifdef LWS_WITH_IPV6\n+\t} else if (af \u003d\u003d AF_INET6) {\n+\t\tstruct sockaddr_in6 srcaddr;\n+\t\tbzero(\u0026srcaddr, sizeof(srcaddr));\n+\t\tsrcaddr.sin6_family \u003d AF_INET6;\n+\t\tmemcpy(\u0026(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));\n+\n+\t\tif (!WSAAddressToStringW((struct sockaddr*)\u0026srcaddr, sizeof(srcaddr), 0, buffer, \u0026bufferlen))\n+\t\t\tok \u003d TRUE;\n+#endif\n+\t} else\n+\t\tlwsl_err(\u0022Unsupported type\u005cn\u0022);\n+\n+\tif (!ok) {\n+\t\tint rv \u003d WSAGetLastError();\n+\t\tlwsl_err(\u0022WSAAddressToString() : %d\u005cn\u0022, rv);\n+\t} else {\n+\t\tif (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) \u003c\u003d 0)\n+\t\t\tok \u003d FALSE;\n+\t}\n+\n+\tlws_free(buffer);\n+\treturn ok ? dst : NULL;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_inet_pton(int af, const char *src, void *dst)\n+{\n+\tWCHAR *buffer;\n+\tDWORD bufferlen \u003d strlen(src) + 1;\n+\tBOOL ok \u003d FALSE;\n+\n+\tbuffer \u003d lws_malloc(bufferlen * 2, \u0022inet_pton\u0022);\n+\tif (!buffer) {\n+\t\tlwsl_err(\u0022Out of memory\u005cn\u0022);\n+\t\treturn -1;\n+\t}\n+\n+\tif (MultiByteToWideChar(CP_ACP, 0, src, bufferlen, buffer, bufferlen) \u003c\u003d 0) {\n+\t\tlwsl_err(\u0022Failed to convert multi byte to wide char\u005cn\u0022);\n+\t\tlws_free(buffer);\n+\t\treturn -1;\n+\t}\n+\n+\tif (af \u003d\u003d AF_INET) {\n+\t\tstruct sockaddr_in dstaddr;\n+\t\tint dstaddrlen \u003d sizeof(dstaddr);\n+\t\tbzero(\u0026dstaddr, sizeof(dstaddr));\n+\t\tdstaddr.sin_family \u003d AF_INET;\n+\n+\t\tif (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) \u0026dstaddr, \u0026dstaddrlen)) {\n+\t\t\tok \u003d TRUE;\n+\t\t\tmemcpy(dst, \u0026dstaddr.sin_addr, sizeof(dstaddr.sin_addr));\n+\t\t}\n+#ifdef LWS_WITH_IPV6\n+\t} else if (af \u003d\u003d AF_INET6) {\n+\t\tstruct sockaddr_in6 dstaddr;\n+\t\tint dstaddrlen \u003d sizeof(dstaddr);\n+\t\tbzero(\u0026dstaddr, sizeof(dstaddr));\n+\t\tdstaddr.sin6_family \u003d AF_INET6;\n+\n+\t\tif (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) \u0026dstaddr, \u0026dstaddrlen)) {\n+\t\t\tok \u003d TRUE;\n+\t\t\tmemcpy(dst, \u0026dstaddr.sin6_addr, sizeof(dstaddr.sin6_addr));\n+\t\t}\n+#endif\n+\t} else\n+\t\tlwsl_err(\u0022Unsupported type\u005cn\u0022);\n+\n+\tif (!ok) {\n+\t\tint rv \u003d WSAGetLastError();\n+\t\tlwsl_err(\u0022WSAAddressToString() : %d\u005cn\u0022, rv);\n+\t}\n+\n+\tlws_free(buffer);\n+\treturn ok ? 1 : -1;\n+}\n+\n+LWS_VISIBLE lws_fop_fd_t\n+_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,\n+\t\t const char *vpath, lws_fop_flags_t *flags)\n+{\n+\tHANDLE ret;\n+\tWCHAR buf[MAX_PATH];\n+\tlws_fop_fd_t fop_fd;\n+\tLARGE_INTEGER llFileSize \u003d {0};\n+\n+\tMultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));\n+\tif (((*flags) \u0026 7) \u003d\u003d _O_RDONLY) {\n+\t\tret \u003d CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,\n+\t\t\t NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\n+\t} else {\n+\t\tret \u003d CreateFileW(buf, GENERIC_WRITE, 0, NULL,\n+\t\t\t CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\n+\t}\n+\n+\tif (ret \u003d\u003d LWS_INVALID_FILE)\n+\t\tgoto bail;\n+\n+\tfop_fd \u003d malloc(sizeof(*fop_fd));\n+\tif (!fop_fd)\n+\t\tgoto bail;\n+\n+\tfop_fd-\u003efops \u003d fops;\n+\tfop_fd-\u003efd \u003d ret;\n+\tfop_fd-\u003efilesystem_priv \u003d NULL; /* we don't use it */\n+\tfop_fd-\u003eflags \u003d *flags;\n+\tfop_fd-\u003elen \u003d GetFileSize(ret, NULL);\n+\tif(GetFileSizeEx(ret, \u0026llFileSize))\n+\t\tfop_fd-\u003elen \u003d llFileSize.QuadPart;\n+\n+\tfop_fd-\u003epos \u003d 0;\n+\n+\treturn fop_fd;\n+\n+bail:\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE int\n+_lws_plat_file_close(lws_fop_fd_t *fop_fd)\n+{\n+\tHANDLE fd \u003d (*fop_fd)-\u003efd;\n+\n+\tfree(*fop_fd);\n+\t*fop_fd \u003d NULL;\n+\n+\tCloseHandle((HANDLE)fd);\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE lws_fileofs_t\n+_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)\n+{\n+\tLARGE_INTEGER l;\n+\n+\tl.QuadPart \u003d offset;\n+\treturn SetFilePointerEx((HANDLE)fop_fd-\u003efd, l, NULL, FILE_CURRENT);\n+}\n+\n+LWS_VISIBLE int\n+_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n+\t\t uint8_t *buf, lws_filepos_t len)\n+{\n+\tDWORD _amount;\n+\n+\tif (!ReadFile((HANDLE)fop_fd-\u003efd, buf, (DWORD)len, \u0026_amount, NULL)) {\n+\t\t*amount \u003d 0;\n+\n+\t\treturn 1;\n+\t}\n+\n+\tfop_fd-\u003epos +\u003d _amount;\n+\t*amount \u003d (unsigned long)_amount;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,\n+\t\t\t uint8_t* buf, lws_filepos_t len)\n+{\n+\tDWORD _amount;\n+\n+\tif (!WriteFile((HANDLE)fop_fd-\u003efd, buf, (DWORD)len, \u0026_amount, NULL)) {\n+\t\t*amount \u003d 0;\n+\n+\t\treturn 1;\n+\t}\n+\n+\tfop_fd-\u003epos +\u003d _amount;\n+\t*amount \u003d (unsigned long)_amount;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_plat_init(struct lws_context *context,\n+\t\t struct lws_context_creation_info *info)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[0];\n+\tint i, n \u003d context-\u003ecount_threads;\n+\n+\tfor (i \u003d 0; i \u003c FD_HASHTABLE_MODULUS; i++) {\n+\t\tcontext-\u003efd_hashtable[i].wsi \u003d\n+\t\t\tlws_zalloc(sizeof(struct lws*) * context-\u003emax_fds, \u0022win hashtable\u0022);\n+\n+\t\tif (!context-\u003efd_hashtable[i].wsi)\n+\t\t\treturn -1;\n+\t}\n+\n+\twhile (n--) {\n+\t\tpt-\u003eevents \u003d lws_malloc(sizeof(WSAEVENT) *\n+\t\t\t\t\t(context-\u003efd_limit_per_thread + 1), \u0022event table\u0022);\n+\t\tif (pt-\u003eevents \u003d\u003d NULL) {\n+\t\t\tlwsl_err(\u0022Unable to allocate events array for %d connections\u005cn\u0022,\n+\t\t\t\t\tcontext-\u003efd_limit_per_thread + 1);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tpt-\u003efds_count \u003d 0;\n+\t\tpt-\u003eevents[0] \u003d WSACreateEvent();\n+\n+\t\tpt++;\n+\t}\n+\n+\tcontext-\u003efd_random \u003d 0;\n+\n+#ifdef LWS_WITH_PLUGINS\n+\tif (info-\u003eplugin_dirs)\n+\t\tlws_plat_plugins_init(context, info-\u003eplugin_dirs);\n+#endif\n+\n+\treturn 0;\n+}\n+\n+\n+int kill(int pid, int sig)\n+{\n+\tlwsl_err(\u0022Sorry Windows doesn't support kill().\u0022);\n+\texit(0);\n+}\n+\n+int fork(void)\n+{\n+\tlwsl_err(\u0022Sorry Windows doesn't support fork().\u0022);\n+\texit(0);\n+}\n+\ndiff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h\nindex 16ddcba..80e96a5 100644\n--- a/lib/private-libwebsockets.h\n+++ b/lib/private-libwebsockets.h\n@@ -1094,17 +1094,7 @@ struct lws_context {\n \tint uid, gid;\n \n \tint fd_random;\n-#ifdef LWS_OPENSSL_SUPPORT\n-#define lws_ssl_anybody_has_buffered_read(w) \u005c\n-\t\t(w-\u003evhost-\u003euse_ssl \u0026\u0026 \u005c\n-\t\t w-\u003econtext-\u003ept[(int)w-\u003etsi].pending_read_list)\n-#define lws_ssl_anybody_has_buffered_read_tsi(c, t) \u005c\n-\t\t(/*c-\u003euse_ssl \u0026\u0026 */ \u005c\n-\t\t c-\u003ept[(int)t].pending_read_list)\n-#else\n-#define lws_ssl_anybody_has_buffered_read(ctx) (0)\n-#define lws_ssl_anybody_has_buffered_read_tsi(ctx, t) (0)\n-#endif\n+\n \tint count_wsi_allocated;\n \tint count_cgi_spawned;\n \tunsigned int options;\n@@ -2023,6 +2013,9 @@ lws_get_addr_scope(const char *ipaddr);\n LWS_EXTERN void\n lws_close_free_wsi(struct lws *wsi, enum lws_close_status);\n \n+LWS_EXTERN void\n+lws_free_wsi(struct lws *wsi);\n+\n LWS_EXTERN int\n remove_wsi_socket_from_fds(struct lws *wsi);\n LWS_EXTERN int\n@@ -2297,6 +2290,7 @@ enum lws_ssl_capable_status {\n #define lws_ssl_SSL_CTX_destroy(_a)\n #define lws_ssl_remove_wsi_from_buffered_list(_a)\n #define lws_context_init_ssl_library(_a)\n+#define lws_ssl_anybody_has_buffered_read_tsi(_a, _b) (0)\n #else\n #define LWS_SSL_ENABLED(context) (context-\u003euse_ssl)\n LWS_EXTERN int openssl_websocket_private_data_index;\n@@ -2326,6 +2320,8 @@ LWS_EXTERN int\n lws_ssl_client_connect2(struct lws *wsi);\n LWS_EXTERN void\n lws_ssl_elaborate_error(void);\n+LWS_EXTERN int\n+lws_ssl_anybody_has_buffered_read_tsi(struct lws_context *context, int tsi);\n #ifndef LWS_NO_SERVER\n LWS_EXTERN int\n lws_context_init_server_ssl(struct lws_context_creation_info *info,\n@@ -2474,6 +2470,8 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len);\n #ifdef LWS_WITH_ACCESS_LOG\n LWS_EXTERN int\n lws_access_log(struct lws *wsi);\n+LWS_EXTERN void\n+lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int meth);\n #else\n #define lws_access_log(_a)\n #endif\n@@ -2481,6 +2479,9 @@ lws_access_log(struct lws *wsi);\n LWS_EXTERN int\n lws_cgi_kill_terminated(struct lws_context_per_thread *pt);\n \n+LWS_EXTERN void\n+lws_cgi_remove_and_kill(struct lws *wsi);\n+\n int\n lws_protocol_init(struct lws_context *context);\n \n@@ -2595,6 +2596,11 @@ void\n lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer);\n void\n lws_peer_cull_peer_wait_list(struct lws_context *context);\n+struct lws_peer *\n+lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd);\n+void\n+lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,\n+\t\t struct lws *wsi);\n #endif\n \n #ifdef __cplusplus\ndiff --git a/lib/ranges.c b/lib/ranges.c\ndeleted file mode 100644\nindex bc1578d..0000000\n--- a/lib/ranges.c\n+++ /dev/null\n@@ -1,214 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * RFC7233 ranges parser\n- *\n- * Copyright (C) 2016 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-/*\n- * RFC7233 examples\n- *\n- * o The first 500 bytes (byte offsets 0-499, inclusive):\n- *\n- * bytes\u003d0-499\n- *\n- * o The second 500 bytes (byte offsets 500-999, inclusive):\n- *\n- * bytes\u003d500-999\n- *\n- * o The final 500 bytes (byte offsets 9500-9999, inclusive):\n- *\n- * bytes\u003d-500\n- *\n- * Or:\n- *\n- * bytes\u003d9500-\n- *\n- * o The first and last bytes only (bytes 0 and 9999):\n- *\n- * bytes\u003d0-0,-1\n- *\n- * o Other valid (but not canonical) specifications of the second 500\n- * bytes (byte offsets 500-999, inclusive):\n- *\n- * bytes\u003d500-600,601-999\n- * bytes\u003d500-700,601-999\n- */\n-\n-/*\n- * returns 1 if the range struct represents a usable range\n- * if no ranges header, you get one of these for the whole\n- * file. Otherwise you get one for each valid range in the\n- * header.\n- *\n- * returns 0 if no further valid range forthcoming; rp-\u003estate\n- * may be LWSRS_SYNTAX or LWSRS_COMPLETED\n- */\n-\n-int\n-lws_ranges_next(struct lws_range_parsing *rp)\n-{\n-\tstatic const char * const beq \u003d \u0022bytes\u003d\u0022;\n-\tchar c;\n-\n-\twhile (1) {\n-\n-\t\tc \u003d rp-\u003ebuf[rp-\u003epos];\n-\n-\t\tswitch (rp-\u003estate) {\n-\t\tcase LWSRS_SYNTAX:\n-\t\tcase LWSRS_COMPLETED:\n-\t\t\treturn 0;\n-\n-\t\tcase LWSRS_NO_ACTIVE_RANGE:\n-\t\t\trp-\u003estate \u003d LWSRS_COMPLETED;\n-\t\t\treturn 0;\n-\n-\t\tcase LWSRS_BYTES_EQ: // looking for \u0022bytes\u003d\u0022\n-\t\t\tif (c !\u003d beq[rp-\u003epos]) {\n-\t\t\t\trp-\u003estate \u003d LWSRS_SYNTAX;\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\tif (rp-\u003epos \u003d\u003d 5)\n-\t\t\t\trp-\u003estate \u003d LWSRS_FIRST;\n-\t\t\tbreak;\n-\n-\t\tcase LWSRS_FIRST:\n-\t\t\trp-\u003estart \u003d 0;\n-\t\t\trp-\u003eend \u003d 0;\n-\t\t\trp-\u003estart_valid \u003d 0;\n-\t\t\trp-\u003eend_valid \u003d 0;\n-\n-\t\t\trp-\u003estate \u003d LWSRS_STARTING;\n-\n-\t\t\t// fallthru\n-\n-\t\tcase LWSRS_STARTING:\n-\t\t\tif (c \u003d\u003d '-') {\n-\t\t\t\trp-\u003estate \u003d LWSRS_ENDING;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\t\tif (!(c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')) {\n-\t\t\t\trp-\u003estate \u003d LWSRS_SYNTAX;\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t\trp-\u003estart \u003d (rp-\u003estart * 10) + (c - '0');\n-\t\t\trp-\u003estart_valid \u003d 1;\n-\t\t\tbreak;\n-\n-\t\tcase LWSRS_ENDING:\n-\t\t\tif (c \u003d\u003d ',' || c \u003d\u003d '\u005c0') {\n-\t\t\t\trp-\u003estate \u003d LWSRS_FIRST;\n-\t\t\t\tif (c \u003d\u003d ',')\n-\t\t\t\t\trp-\u003epos++;\n-\n-\t\t\t\t/*\n-\t\t\t\t * By the end of this, start and end are\n-\t\t\t\t * always valid if the range still is\n-\t\t\t\t */\n-\n-\t\t\t\tif (!rp-\u003estart_valid) { /* eg, -500 */\n-\t\t\t\t\tif (rp-\u003eend \u003e rp-\u003eextent)\n-\t\t\t\t\t\trp-\u003eend \u003d rp-\u003eextent;\n-\n-\t\t\t\t\trp-\u003estart \u003d rp-\u003eextent - rp-\u003eend;\n-\t\t\t\t\trp-\u003eend \u003d rp-\u003eextent - 1;\n-\t\t\t\t} else\n-\t\t\t\t\tif (!rp-\u003eend_valid)\n-\t\t\t\t\t\trp-\u003eend \u003d rp-\u003eextent - 1;\n-\n-\t\t\t\trp-\u003edid_try \u003d 1;\n-\n-\t\t\t\t/* end must be \u003e\u003d start or ignore it */\n-\t\t\t\tif (rp-\u003eend \u003c rp-\u003estart) {\n-\t\t\t\t\tif (c \u003d\u003d ',')\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\trp-\u003estate \u003d LWSRS_COMPLETED;\n-\t\t\t\t\treturn 0;\n-\t\t\t\t}\n-\n-\t\t\t\treturn 1; /* issue range */\n-\t\t\t}\n-\n-\t\t\tif (!(c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')) {\n-\t\t\t\trp-\u003estate \u003d LWSRS_SYNTAX;\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t\trp-\u003eend \u003d (rp-\u003eend * 10) + (c - '0');\n-\t\t\trp-\u003eend_valid \u003d 1;\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\trp-\u003epos++;\n-\t}\n-}\n-\n-void\n-lws_ranges_reset(struct lws_range_parsing *rp)\n-{\n-\trp-\u003epos \u003d 0;\n-\trp-\u003ectr \u003d 0;\n-\trp-\u003estart \u003d 0;\n-\trp-\u003eend \u003d 0;\n-\trp-\u003estart_valid \u003d 0;\n-\trp-\u003eend_valid \u003d 0;\n-\trp-\u003estate \u003d LWSRS_BYTES_EQ;\n-}\n-\n-/*\n- * returns count of valid ranges\n- */\n-int\n-lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,\n-\t\tunsigned long long extent)\n-{\n-\trp-\u003eagg \u003d 0;\n-\trp-\u003esend_ctr \u003d 0;\n-\trp-\u003einside \u003d 0;\n-\trp-\u003ecount_ranges \u003d 0;\n-\trp-\u003edid_try \u003d 0;\n-\tlws_ranges_reset(rp);\n-\trp-\u003estate \u003d LWSRS_COMPLETED;\n-\n-\trp-\u003eextent \u003d extent;\n-\n-\tif (lws_hdr_copy(wsi, (char *)rp-\u003ebuf, sizeof(rp-\u003ebuf),\n-\t\t\t WSI_TOKEN_HTTP_RANGE) \u003c\u003d 0)\n-\t\treturn 0;\n-\n-\trp-\u003estate \u003d LWSRS_BYTES_EQ;\n-\n-\twhile (lws_ranges_next(rp)) {\n-\t\trp-\u003ecount_ranges++;\n-\t\trp-\u003eagg +\u003d rp-\u003eend - rp-\u003estart + 1;\n-\t}\n-\n-\tlwsl_debug(\u0022%s: count %d\u005cn\u0022, __func__, rp-\u003ecount_ranges);\n-\tlws_ranges_reset(rp);\n-\n-\tif (rp-\u003edid_try \u0026\u0026 !rp-\u003ecount_ranges)\n-\t\treturn -1; /* \u0022not satisfiable */\n-\n-\tlws_ranges_next(rp);\n-\n-\treturn rp-\u003ecount_ranges;\n-}\ndiff --git a/lib/rewrite.c b/lib/rewrite.c\ndeleted file mode 100644\nindex 2f9b0c4..0000000\n--- a/lib/rewrite.c\n+++ /dev/null\n@@ -1,52 +0,0 @@\n-#include \u0022private-libwebsockets.h\u0022\n-\n-\n-LWS_EXTERN struct lws_rewrite *\n-lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from, const char *to)\n-{\n-\tstruct lws_rewrite *r \u003d lws_malloc(sizeof(*r), \u0022rewrite\u0022);\n-\n-\tif (!r) {\n-\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n-\t\treturn NULL;\n-\t}\n-\n-\tif (hubbub_parser_create(\u0022UTF-8\u0022, false, \u0026r-\u003eparser) !\u003d HUBBUB_OK) {\n-\t\tlws_free(r);\n-\n-\t\treturn NULL;\n-\t}\n-\tr-\u003efrom \u003d from;\n-\tr-\u003efrom_len \u003d strlen(from);\n-\tr-\u003eto \u003d to;\n-\tr-\u003eto_len \u003d strlen(to);\n-\tr-\u003eparams.token_handler.handler \u003d cb;\n-\tr-\u003ewsi \u003d wsi;\n-\tr-\u003eparams.token_handler.pw \u003d (void *)r;\n-\tif (hubbub_parser_setopt(r-\u003eparser, HUBBUB_PARSER_TOKEN_HANDLER,\n-\t\t\t\t \u0026r-\u003eparams) !\u003d HUBBUB_OK) {\n-\t\tlws_free(r);\n-\n-\t\treturn NULL;\n-\t}\n-\n-\treturn r;\n-}\n-\n-LWS_EXTERN int\n-lws_rewrite_parse(struct lws_rewrite *r,\n-\t\t const unsigned char *in, int in_len)\n-{\n-\tif (hubbub_parser_parse_chunk(r-\u003eparser, in, in_len) !\u003d HUBBUB_OK)\n-\t\treturn -1;\n-\n-\treturn 0;\n-}\n-\n-LWS_EXTERN void\n-lws_rewrite_destroy(struct lws_rewrite *r)\n-{\n-\thubbub_parser_destroy(r-\u003eparser);\n-\tlws_free(r);\n-}\n-\ndiff --git a/lib/romfs.c b/lib/romfs.c\ndeleted file mode 100644\nindex 540382e..0000000\n--- a/lib/romfs.c\n+++ /dev/null\n@@ -1,224 +0,0 @@\n-/*\n- * Copyright (C) 2017 National Institute of Advanced Industrial Science\n- * and Technology (AIST)\n- *\n- * All rights reserved.\n- *\n- * Redistribution and use in source and binary forms, with or without\n- * modification, are permitted provided that the following conditions are met:\n- *\n- * Redistributions of source code must retain the above copyright notice, this\n- * list of conditions and the following disclaimer.\n- *\n- * Redistributions in binary form must reproduce the above copyright notice,\n- * this list of conditions and the following disclaimer in the documentation\n- * and/or other materials provided with the distribution.\n- *\n- * Neither the name of AIST nor the names of its contributors may be used\n- * to endorse or promote products derived from this software without specific\n- * prior written permission.\n- *\n- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \u0022AS IS\u0022\n- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n- * POSSIBILITY OF SUCH DAMAGE.\n- */\n-\n-#include \u003cstring.h\u003e\n-#include \u003cstdint.h\u003e\n-#include \u003cstdio.h\u003e\n-#include \u0022romfs.h\u0022\n-#include \u0022esp_spi_flash.h\u0022\n-\n-#define RFS_STRING_MAX 96\n-\n-static u32_be_t cache[(RFS_STRING_MAX + 32) / 4];\n-static romfs_inode_t ci \u003d (romfs_inode_t)cache;\n-static romfs_t cr \u003d (romfs_t)cache;\n-\n-static void\n-set_cache(romfs_inode_t inode, size_t len)\n-{\n-\tspi_flash_read((uint32_t)inode, cache, len);\n-}\n-\n-static uint32_t\n-ntohl(const u32_be_t be)\n-{\n-\treturn ((be \u003e\u003e 24) \u0026 0xff) |\n-\t ((be \u003e\u003e 16) \u0026 0xff) \u003c\u003c 8 |\n-\t ((be \u003e\u003e 8) \u0026 0xff) \u003c\u003c 16 |\n-\t (be \u0026 0xff) \u003c\u003c 24;\n-}\n-static romfs_inode_t\n-romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path);\n-\n-static int\n-plus_padding(const uint8_t *s)\n-{\n-\tint n;\n- \n-\tset_cache((romfs_inode_t)s, RFS_STRING_MAX);\n-\tn \u003d strlen((const char *)cache);\n-\n-\tif (!(n \u0026 15))\n-\t\tn +\u003d 0x10;\n-\n-\treturn (n + 15) \u0026 ~15;\n-}\n-\n-static romfs_inode_t\n-skip_and_pad(romfs_inode_t ri)\n-{\n-\tconst uint8_t *p \u003d ((const uint8_t *)ri) + sizeof(*ri);\n-\n-\treturn (romfs_inode_t)(p + plus_padding(p));\n-}\n-\n-size_t\n-romfs_mount_check(romfs_t romfs)\n-{\n-\tset_cache((romfs_inode_t)romfs, sizeof(*romfs));\n-\n-\tif (cr-\u003emagic1 !\u003d 0x6d6f722d ||\n-\t cr-\u003emagic2 !\u003d 0x2d736631)\n-\t\treturn 0;\n-\n-\treturn ntohl(cr-\u003esize);\n-}\n-\n-static romfs_inode_t\n-romfs_symlink(romfs_t romfs, romfs_inode_t level, romfs_inode_t i)\n-{\n-\tconst char *p \u003d (const char *)skip_and_pad(i);\n-\n-\tif (*p \u003d\u003d '/') {\n-\t\tlevel \u003d skip_and_pad((romfs_inode_t)romfs);\n-\t\tp++;\n-\t}\n-\n-\treturn romfs_lookup(romfs, level, p);\n-}\n-\n-static romfs_inode_t\n-dir_link(romfs_t romfs, romfs_inode_t i)\n-{\n-\tset_cache(i, sizeof(*i));\n-\treturn (romfs_inode_t)((const uint8_t *)romfs +\n-\t\t\t\t\t\tntohl(ci-\u003edir_start));\n-}\n-\n-static romfs_inode_t\n-romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)\n-{\n-\tromfs_inode_t level, i \u003d start, i_in;\n-\tconst char *p, *n, *cp;\n-\tuint32_t next_be;\n-\n-\tif (start \u003d\u003d (romfs_inode_t)romfs)\n-\t\ti \u003d skip_and_pad((romfs_inode_t)romfs);\n-\tlevel \u003d i;\n-\twhile (i !\u003d (romfs_inode_t)romfs) {\n-\t\tp \u003d path;\n-\t\tn \u003d ((const char *)i) + sizeof(*i);\n-\t\ti_in \u003d i;\n-\n-\t\tset_cache(i, sizeof(*i));\n-\t\tnext_be \u003d ci-\u003enext;\n-\n-\t\tcp \u003d (const char *)cache;\n-\t\tset_cache((romfs_inode_t)n, RFS_STRING_MAX);\n-\n-\t\twhile (*p \u0026\u0026 *p !\u003d '/' \u0026\u0026 *cp \u0026\u0026 *p \u003d\u003d *cp \u0026\u0026 (p - path) \u003c RFS_STRING_MAX) {\n-\t\t\tp++;\n-\t\t\tn++;\n-\t\t\tcp++;\n-\t\t}\n-\n-\t\tif (!*cp \u0026\u0026 (!*p || *p \u003d\u003d '/') \u0026\u0026\n-\t\t (ntohl(next_be) \u0026 7) \u003d\u003d RFST_HARDLINK) {\n-\t\t\tset_cache(i, sizeof(*i));\n-\t\t\treturn (romfs_inode_t)\n-\t\t\t ((const uint8_t *)romfs +\n-\t\t\t (ntohl(ci-\u003edir_start) \u0026 ~15));\n-\t\t}\n-\n-\t\tif (!*p \u0026\u0026 !*cp) {\n-\t\t\tset_cache(i, sizeof(*i));\n-\t\t\tif ((ntohl(ci-\u003enext) \u0026 7) \u003d\u003d RFST_SYMLINK) {\n-\t\t\t\ti \u003d romfs_symlink(romfs, level, i);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\treturn i;\n-\t\t}\n-\n-\t\tif (!*p \u0026\u0026 *cp \u003d\u003d '/')\n-\t\t\treturn NULL;\n-\n-\t\tif (*p \u003d\u003d '/' \u0026\u0026 !*cp) {\n-\t\t\tset_cache(i, sizeof(*i));\n-\t\t\tswitch (ntohl(ci-\u003enext) \u0026 7) {\n-\t\t\tcase RFST_SYMLINK:\n-\t\t\t\ti \u003d romfs_symlink(romfs, level, i);\n-\t\t\t\tif (!i)\n-\t\t\t\t\treturn NULL;\n-\t\t\t\ti \u003d dir_link(romfs, i);\n-\t\t\t\twhile (*path !\u003d '/' \u0026\u0026 *path)\n-\t\t\t\t\tpath++;\n-\t\t\t\tif (!*path)\n-\t\t\t\t\treturn NULL;\n-\t\t\t\tpath++;\n-\t\t\t\tcontinue;\n-\t\t\tcase RFST_DIR:\n-\t\t\t\tpath \u003d p + 1;\n-\t\t\t\ti \u003d dir_link(romfs, i);\n-\t\t\t\tbreak;\n-\t\t\tdefault:\n-\t\t\t\tpath \u003d p + 1;\n-\t\t\t\ti \u003d skip_and_pad(i);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tlevel \u003d i;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tset_cache(i, sizeof(*i));\n-\t\tif (!(ntohl(ci-\u003enext) \u0026 ~15))\n-\t\t\treturn NULL;\n-\n-\t\ti \u003d (romfs_inode_t)((const uint8_t *)romfs +\n-\t\t\t\t (ntohl(ci-\u003enext) \u0026 ~15));\n-\t\tif (i \u003d\u003d i_in)\n-\t\t\treturn NULL;\n-\t}\n-\n-\treturn NULL;\n-}\n-\n-const void *\n-romfs_get_info(romfs_t romfs, const char *path, size_t *len, size_t *csum)\n-{\n-\tromfs_inode_t i;\n- \n-\tif (*path \u003d\u003d '/')\n-\t\tpath++;\n-\n-\ti \u003d romfs_lookup(romfs, (romfs_inode_t)romfs, path);\n-\n-\tif (!i)\n-\t\treturn NULL;\n-\n-\tset_cache(i, sizeof(*i));\n-\t*len \u003d ntohl(ci-\u003esize);\n-\tif (csum)\n-\t\t*csum \u003d ntohl(ci-\u003echecksum);\n-\n-\treturn (void *)skip_and_pad(i);\n-}\ndiff --git a/lib/romfs.h b/lib/romfs.h\ndeleted file mode 100644\nindex dab932b..0000000\n--- a/lib/romfs.h\n+++ /dev/null\n@@ -1,63 +0,0 @@\n-/*\n- * Copyright (C) 2017 National Institute of Advanced Industrial Science\n- * and Technology (AIST)\n- *\n- * All rights reserved.\n- *\n- * Redistribution and use in source and binary forms, with or without\n- * modification, are permitted provided that the following conditions are met:\n- *\n- * Redistributions of source code must retain the above copyright notice, this\n- * list of conditions and the following disclaimer.\n- *\n- * Redistributions in binary form must reproduce the above copyright notice,\n- * this list of conditions and the following disclaimer in the documentation\n- * and/or other materials provided with the distribution.\n- *\n- * Neither the name of AIST nor the names of its contributors may be used\n- * to endorse or promote products derived from this software without specific\n- * prior written permission.\n- *\n- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \u0022AS IS\u0022\n- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n- * POSSIBILITY OF SUCH DAMAGE.\n- */\n-\n-typedef uint32_t u32_be_t;\n-\n-struct romfs_superblock {\n-\tu32_be_t magic1;\n-\tu32_be_t magic2;\n-\tu32_be_t size;\n-\tu32_be_t checksum;\n-};\n-\n-struct romfs_i {\n-\tu32_be_t next;\n-\tu32_be_t dir_start;\n-\tu32_be_t size;\n-\tu32_be_t checksum;\n-};\n-\n-enum {\n-\tRFST_HARDLINK\t\u003d 0,\n-\tRFST_DIR\t\u003d 1,\n-\tRFST_SYMLINK\t\u003d 3,\n-};\n-\n-typedef const struct romfs_i *romfs_inode_t;\n-typedef const struct romfs_superblock *romfs_t;\n-\n-const void *\n-romfs_get_info(romfs_t romfs, const char *path, size_t *len, size_t *csum);\n-size_t\n-romfs_mount_check(romfs_t romfs);\n-\ndiff --git a/lib/server-handshake.c b/lib/server-handshake.c\ndeleted file mode 100644\nindex 3d319c3..0000000\n--- a/lib/server-handshake.c\n+++ /dev/null\n@@ -1,360 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2013 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr +\u003d strlen(str); }\n-\n-#ifndef LWS_NO_EXTENSIONS\n-static int\n-lws_extension_server_handshake(struct lws *wsi, char **p, int budget)\n-{\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\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, 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-\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 \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\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 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 \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-\u003evhost-\u003eextensions;\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-\u003ecount_act_ext; m++)\n-\t\t\t\tif (wsi-\u003eactive_extensions[m] \u003d\u003d ext) {\n-\t\t\t\t\tlwsl_info(\u0022extension 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-\u003eprotocol-\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-\u003eactive_extensions[wsi-\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-\u003eact_ext_user[\n-\t\t\t\t\t wsi-\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, (end - *p), \u0022%s\u0022, ext_name);\n-\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_debug(\u0022ext args %s\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\tlwsl_debug(\u0022'%s' '%s'\u005cn\u0022, po-\u003ename, args);\n-\t\t\t\t\t/* only support arg-less options... */\n-\t\t\t\t\tif (po-\u003etype \u003d\u003d EXTARG_NONE \u0026\u0026\n-\t\t\t\t\t !strncmp(args, po-\u003ename,\n-\t\t\t\t\t\t\t strlen(po-\u003ename))) {\n-\t\t\t\t\t\toa.option_name \u003d NULL;\n-\t\t\t\t\t\toa.option_index \u003d po - opts;\n-\t\t\t\t\t\toa.start \u003d NULL;\n-\t\t\t\t\t\tlwsl_debug(\u0022setting %s\u005cn\u0022, po-\u003ename);\n-\t\t\t\t\t\tif (!ext-\u003ecallback(\n-\t\t\t\t\t\t\t\tlws_get_context(wsi), ext, wsi,\n-\t\t\t\t\t\t\t\t LWS_EXT_CB_OPTION_SET,\n-\t\t\t\t\t\t\t\t wsi-\u003eact_ext_user[\n-\t\t\t\t\t\t\t\t wsi-\u003ecount_act_ext],\n-\t\t\t\t\t\t\t\t \u0026oa, (end - *p))) {\n-\n-\t\t\t\t\t\t\t*p +\u003d lws_snprintf(*p, (end - *p), \u0022; %s\u0022, po-\u003ename);\n-\t\t\t\t\t\t\tlwsl_debug(\u0022adding option %s\u005cn\u0022, po-\u003ename);\n-\t\t\t\t\t\t}\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-\t\t\t}\n-\n-\t\t\twsi-\u003ecount_act_ext++;\n-\t\t\tlwsl_parser(\u0022count_act_ext \u003c- %d\u005cn\u0022,\n-\t\t\t\t wsi-\u003ecount_act_ext);\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-int\n-handshake_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_parser(\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 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, n, hash);\n-\n-\taccept_len \u003d lws_b64_encode_string((char *)hash, 20,\n-\t\t\t(char *)pt-\u003eserv_buf, 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 + 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-\u003eprotocol-\u003ename \u0026\u0026\n-\t wsi-\u003eprotocol-\u003ename[0]) {\n-\t\tLWS_CPYAPP(p, \u0022\u005cx0d\u005cx0aSec-WebSocket-Protocol: \u0022);\n-\t\tp +\u003d lws_snprintf(p, 128, \u0022%s\u0022, wsi-\u003eprotocol-\u003ename);\n-\t}\n-\n-#ifndef LWS_NO_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 ((char *)pt-\u003eserv_buf + context-\u003ept_serv_buf_size) - p;\n-\tif (user_callback_handle_rxflow(wsi-\u003eprotocol-\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-\tif (!lws_any_extension_handled(wsi, LWS_EXT_CB_HANDSHAKE_REPLY_TX,\n-\t\t\t\t response, p - response)) {\n-\n-\t\t/* okay send the handshake response accepting the connection */\n-\n-\t\tlwsl_parser(\u0022issuing resp pkt %d len\u005cn\u0022, (int)(p - response));\n-#if defined(DEBUG) \u0026\u0026 ! defined(LWS_WITH_ESP8266)\n-\t\tfwrite(response, 1, p - response, stderr);\n-#endif\n-\t\tn \u003d lws_write(wsi, (unsigned char *)response,\n-\t\t\t p - response, LWS_WRITE_HTTP_HEADERS);\n-\t\tif (n !\u003d (p - response)) {\n-\t\t\tlwsl_debug(\u0022handshake_0405: ERROR writing to socket\u005cn\u0022);\n-\t\t\tgoto bail;\n-\t\t}\n-\n-\t}\n-\n-\t/* alright clean up and set ourselves into established state */\n-\n-\twsi-\u003estate \u003d LWSS_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-\u003eprotocol-\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-\n-\n-bail:\n-\t/* caller will free up his parsing allocations */\n-\treturn -1;\n-}\n-\ndiff --git a/lib/server.c b/lib/server.c\ndeleted file mode 100644\nindex 3ddbb67..0000000\n--- a/lib/server.c\n+++ /dev/null\n@@ -1,3863 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-static const char * const method_names[] \u003d {\n-\t\u0022GET\u0022, \u0022POST\u0022, \u0022OPTIONS\u0022, \u0022PUT\u0022, \u0022PATCH\u0022, \u0022DELETE\u0022, \u0022CONNECT\u0022, \u0022HEAD\u0022,\n-#ifdef LWS_WITH_HTTP2\n-\t\u0022:path\u0022,\n-#endif\n-\t};\n-\n-#if defined (LWS_WITH_ESP8266)\n-#undef memcpy\n-void *memcpy(void *dest, const void *src, size_t n)\n-{\n-\treturn ets_memcpy(dest, src, n);\n-}\n-#endif\n-\n-int\n-lws_context_init_server(struct lws_context_creation_info *info,\n-\t\t\tstruct lws_vhost *vhost)\n-{\n-#if LWS_POSIX\n-\tint n, opt \u003d 1, limit \u003d 1;\n-#endif\n-\tlws_sockfd_type sockfd;\n-\tstruct lws_vhost *vh;\n-\tstruct lws *wsi;\n-\tint m \u003d 0;\n-\n-\t(void)method_names;\n-\t(void)opt;\n-\t/* set up our external listening socket we serve on */\n-\n-\tif (info-\u003eport \u003d\u003d CONTEXT_PORT_NO_LISTEN ||\n-\t info-\u003eport \u003d\u003d CONTEXT_PORT_NO_LISTEN_SERVER)\n-\t\treturn 0;\n-\n-\tvh \u003d vhost-\u003econtext-\u003evhost_list;\n-\twhile (vh) {\n-\t\tif (vh-\u003elisten_port \u003d\u003d info-\u003eport) {\n-\t\t\tif ((!info-\u003eiface \u0026\u0026 !vh-\u003eiface) ||\n-\t\t\t (info-\u003eiface \u0026\u0026 vh-\u003eiface \u0026\u0026\n-\t\t\t !strcmp(info-\u003eiface, vh-\u003eiface))) {\n-\t\t\t\tvhost-\u003elisten_port \u003d info-\u003eport;\n-\t\t\t\tvhost-\u003eiface \u003d info-\u003eiface;\n-\t\t\t\tlwsl_notice(\u0022 using listen skt from vhost %s\u005cn\u0022,\n-\t\t\t\t\t vh-\u003ename);\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t}\n-\t\tvh \u003d vh-\u003evhost_next;\n-\t}\n-\n-#if LWS_POSIX\n-\t(void)n;\n-#if defined(__linux__)\n-\tlimit \u003d vhost-\u003econtext-\u003ecount_threads;\n-#endif\n-\n-\tfor (m \u003d 0; m \u003c limit; m++) {\n-#ifdef LWS_WITH_UNIX_SOCK\n-\tif (LWS_UNIX_SOCK_ENABLED(vhost))\n-\t\tsockfd \u003d socket(AF_UNIX, SOCK_STREAM, 0);\n-\telse\n-#endif\n-#ifdef LWS_WITH_IPV6\n-\tif (LWS_IPV6_ENABLED(vhost))\n-\t\tsockfd \u003d socket(AF_INET6, SOCK_STREAM, 0);\n-\telse\n-#endif\n-\t\tsockfd \u003d socket(AF_INET, SOCK_STREAM, 0);\n-\n-\tif (sockfd \u003d\u003d -1) {\n-#else\n-#if defined(LWS_WITH_ESP8266)\n-\tsockfd \u003d esp8266_create_tcp_listen_socket(vhost);\n-\tif (!lws_sockfd_valid(sockfd)) {\n-#endif\n-#endif\n-\t\tlwsl_err(\u0022ERROR opening socket\u005cn\u0022);\n-\t\treturn 1;\n-\t}\n-#if LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n-\n-#if (defined(WIN32) || defined(_WIN32)) \u0026\u0026 defined(SO_EXCLUSIVEADDRUSE)\n-\t/*\n-\t * only accept that we are the only listener on the port\n-\t * https://msdn.microsoft.com/zh-tw/library/windows/desktop/ms740621(v\u003dvs.85).aspx\n-\t *\n-\t * for lws, to match Linux, we default to exclusive listen\n-\t */\n-\tif (!lws_check_opt(vhost-\u003eoptions, LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE)) {\n-\t\tif (setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,\n-\t\t\t (const void *)\u0026opt, sizeof(opt)) \u003c 0) {\n-\t\t\tlwsl_err(\u0022reuseaddr failed\u005cn\u0022);\n-\t\t\tcompatible_close(sockfd);\n-\t\t\treturn 1;\n-\t\t}\n-\t} else\n-#endif\n-\n-\t/*\n-\t * allow us to restart even if old sockets in TIME_WAIT\n-\t */\n-\tif (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,\n-\t\t (const void *)\u0026opt, sizeof(opt)) \u003c 0) {\n-\t\tlwsl_err(\u0022reuseaddr failed\u005cn\u0022);\n-\t\tcompatible_close(sockfd);\n-\t\treturn 1;\n-\t}\n-\n-#if defined(LWS_WITH_IPV6) \u0026\u0026 defined(IPV6_V6ONLY)\n-\tif (LWS_IPV6_ENABLED(vhost)) {\n-\t\tif (vhost-\u003eoptions \u0026 LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) {\n-\t\t\tint value \u003d (vhost-\u003eoptions \u0026 LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE) ? 1 : 0;\n-\t\t\tif (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,\n-\t\t\t\t\t(const void*)\u0026value, sizeof(value)) \u003c 0) {\n-\t\t\t\tcompatible_close(sockfd);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t}\n-\t}\n-#endif\n-\n-#if defined(__linux__) \u0026\u0026 defined(SO_REUSEPORT)\n-\tn \u003d lws_check_opt(vhost-\u003eoptions, LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE);\n-#if LWS_MAX_SMP \u003e 1\n-\tn \u003d 1;\n-#endif\n-\n-\tif (n)\n-\t\tif (vhost-\u003econtext-\u003ecount_threads \u003e 1)\n-\t\t\tif (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,\n-\t\t\t\t\t(const void *)\u0026opt, sizeof(opt)) \u003c 0) {\n-\t\t\t\tcompatible_close(sockfd);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-#endif\n-#endif\n-\tlws_plat_set_socket_options(vhost, sockfd);\n-\n-#if LWS_POSIX\n-\tn \u003d lws_socket_bind(vhost, sockfd, info-\u003eport, info-\u003eiface);\n-\tif (n \u003c 0)\n-\t\tgoto bail;\n-\tinfo-\u003eport \u003d n;\n-#endif\n-\tvhost-\u003elisten_port \u003d info-\u003eport;\n-\tvhost-\u003eiface \u003d info-\u003eiface;\n-\n-\twsi \u003d lws_zalloc(sizeof(struct lws), \u0022listen wsi\u0022);\n-\tif (wsi \u003d\u003d NULL) {\n-\t\tlwsl_err(\u0022Out of mem\u005cn\u0022);\n-\t\tgoto bail;\n-\t}\n-\twsi-\u003econtext \u003d vhost-\u003econtext;\n-\twsi-\u003edesc.sockfd \u003d sockfd;\n-\twsi-\u003emode \u003d LWSCM_SERVER_LISTENER;\n-\twsi-\u003eprotocol \u003d vhost-\u003eprotocols;\n-\twsi-\u003etsi \u003d m;\n-\twsi-\u003evhost \u003d vhost;\n-\twsi-\u003elistener \u003d 1;\n-\n-#ifdef LWS_WITH_LIBUV\n-\tif (LWS_LIBUV_ENABLED(vhost-\u003econtext))\n-\t\tlws_uv_initvhost(vhost, wsi);\n-#endif\n-\n-\tif (insert_wsi_socket_into_fds(vhost-\u003econtext, wsi))\n-\t\tgoto bail;\n-\n-\tvhost-\u003econtext-\u003ecount_wsi_allocated++;\n-\tvhost-\u003elserv_wsi \u003d wsi;\n-\n-#if LWS_POSIX\n-\tn \u003d listen(wsi-\u003edesc.sockfd, LWS_SOMAXCONN);\n-\tif (n \u003c 0) {\n-\t\tlwsl_err(\u0022listen failed with error %d\u005cn\u0022, LWS_ERRNO);\n-\t\tvhost-\u003elserv_wsi \u003d NULL;\n-\t\tvhost-\u003econtext-\u003ecount_wsi_allocated--;\n-\t\tremove_wsi_socket_from_fds(wsi);\n-\t\tgoto bail;\n-\t}\n-\t} /* for each thread able to independently listen */\n-#else\n-#if defined(LWS_WITH_ESP8266)\n-\tesp8266_tcp_stream_bind(wsi-\u003edesc.sockfd, info-\u003eport, wsi);\n-#endif\n-#endif\n-\tif (!lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {\n-#ifdef LWS_WITH_UNIX_SOCK\n-\t\tif (LWS_UNIX_SOCK_ENABLED(vhost))\n-\t\t\tlwsl_info(\u0022 Listening on \u005c\u0022%s\u005c\u0022\u005cn\u0022, info-\u003eiface);\n-\t\telse\n-#endif\n-\t\t\tlwsl_info(\u0022 Listening on port %d\u005cn\u0022, info-\u003eport);\n- }\n-\n-\treturn 0;\n-\n-bail:\n-\tcompatible_close(sockfd);\n-\n-\treturn 1;\n-}\n-\n-#if defined(LWS_WITH_ESP8266)\n-#undef strchr\n-#define strchr ets_strchr\n-#endif\n-\n-struct lws_vhost *\n-lws_select_vhost(struct lws_context *context, int port, const char *servername)\n-{\n-\tstruct lws_vhost *vhost \u003d context-\u003evhost_list;\n-\tconst char *p;\n-\tint n, m, colon;\n-\n-\tn \u003d strlen(servername);\n-\tcolon \u003d n;\n-\tp \u003d strchr(servername, ':');\n-\tif (p)\n-\t\tcolon \u003d p - servername;\n-\n-\t/* Priotity 1: first try exact matches */\n-\n-\twhile (vhost) {\n-\t\tif (port \u003d\u003d vhost-\u003elisten_port \u0026\u0026\n-\t\t !strncmp(vhost-\u003ename, servername, colon)) {\n-\t\t\tlwsl_info(\u0022SNI: Found: %s\u005cn\u0022, servername);\n-\t\t\treturn vhost;\n-\t\t}\n-\t\tvhost \u003d vhost-\u003evhost_next;\n-\t}\n-\n-\t/*\n-\t * Priority 2: if no exact matches, try matching *.vhost-name\n-\t * unintentional matches are possible but resolve to x.com for *.x.com\n-\t * which is reasonable. If exact match exists we already chose it and\n-\t * never reach here. SSL will still fail it if the cert doesn't allow\n-\t * *.x.com.\n-\t */\n-\tvhost \u003d context-\u003evhost_list;\n-\twhile (vhost) {\n-\t\tm \u003d strlen(vhost-\u003ename);\n-\t\tif (port \u003d\u003d vhost-\u003elisten_port \u0026\u0026\n-\t\t m \u003c\u003d (colon - 2) \u0026\u0026\n-\t\t servername[colon - m - 1] \u003d\u003d '.' \u0026\u0026\n-\t\t !strncmp(vhost-\u003ename, servername + colon - m, m)) {\n-\t\t\tlwsl_info(\u0022SNI: Found %s on wildcard: %s\u005cn\u0022,\n-\t\t\t\t servername, vhost-\u003ename);\n-\t\t\treturn vhost;\n-\t\t}\n-\t\tvhost \u003d vhost-\u003evhost_next;\n-\t}\n-\n-\t/* Priority 3: match the first vhost on our port */\n-\n-\tvhost \u003d context-\u003evhost_list;\n-\twhile (vhost) {\n-\t\tif (port \u003d\u003d vhost-\u003elisten_port) {\n-\t\t\tlwsl_info(\u0022vhost match to %s based on port %d\u005cn\u0022,\n-\t\t\t\t\tvhost-\u003ename, port);\n-\t\t\treturn vhost;\n-\t\t}\n-\t\tvhost \u003d vhost-\u003evhost_next;\n-\t}\n-\n-\t/* no match */\n-\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN const char *\n-lws_get_mimetype(const char *file, const struct lws_http_mount *m)\n-{\n-\tint n \u003d strlen(file);\n-\tconst struct lws_protocol_vhost_options *pvo \u003d NULL;\n-\n-\tif (m)\n-\t\tpvo \u003d m-\u003eextra_mimetypes;\n-\n-\tif (n \u003c 5)\n-\t\treturn NULL;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.ico\u0022))\n-\t\treturn \u0022image/x-icon\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.gif\u0022))\n-\t\treturn \u0022image/gif\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 3], \u0022.js\u0022))\n-\t\treturn \u0022text/javascript\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.png\u0022))\n-\t\treturn \u0022image/png\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.jpg\u0022))\n-\t\treturn \u0022image/jpeg\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 3], \u0022.gz\u0022))\n-\t\treturn \u0022application/gzip\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.JPG\u0022))\n-\t\treturn \u0022image/jpeg\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 5], \u0022.html\u0022))\n-\t\treturn \u0022text/html\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.css\u0022))\n-\t\treturn \u0022text/css\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.txt\u0022))\n-\t\treturn \u0022text/plain\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.svg\u0022))\n-\t\treturn \u0022image/svg+xml\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.ttf\u0022))\n-\t\treturn \u0022application/x-font-ttf\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.otf\u0022))\n-\t\treturn \u0022application/font-woff\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 5], \u0022.woff\u0022))\n-\t\treturn \u0022application/font-woff\u0022;\n-\n-\tif (!strcmp(\u0026file[n - 4], \u0022.xml\u0022))\n-\t\treturn \u0022application/xml\u0022;\n-\n-\twhile (pvo) {\n-\t\tif (pvo-\u003ename[0] \u003d\u003d '*') /* ie, match anything */\n-\t\t\treturn pvo-\u003evalue;\n-\n-\t\tif (!strcmp(\u0026file[n - strlen(pvo-\u003ename)], pvo-\u003ename))\n-\t\t\treturn pvo-\u003evalue;\n-\n-\t\tpvo \u003d pvo-\u003enext;\n-\t}\n-\n-\treturn NULL;\n-}\n-static lws_fop_flags_t\n-lws_vfs_prepare_flags(struct lws *wsi)\n-{\n-\tlws_fop_flags_t f \u003d 0;\n-\n-\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))\n-\t\treturn f;\n-\n-\tif (strstr(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING),\n-\t\t \u0022gzip\u0022)) {\n-\t\tlwsl_info(\u0022client indicates GZIP is acceptable\u005cn\u0022);\n-\t\tf |\u003d LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;\n-\t}\n-\n-\treturn f;\n-}\n-\n-static int\n-lws_http_serve(struct lws *wsi, char *uri, const char *origin,\n-\t const struct lws_http_mount *m)\n-{\n-\tconst struct lws_protocol_vhost_options *pvo \u003d m-\u003einterpret;\n-\tstruct lws_process_html_args args;\n-\tconst char *mimetype;\n-#if !defined(_WIN32_WCE) \u0026\u0026 !defined(LWS_WITH_ESP8266)\n-\tconst struct lws_plat_file_ops *fops;\n-\tconst char *vpath;\n-\tlws_fop_flags_t fflags \u003d LWS_O_RDONLY;\n-#if defined(WIN32) \u0026\u0026 defined(LWS_HAVE__STAT32I64)\n-\tstruct _stat32i64 st;\n-#else\n-\tstruct stat st;\n-#endif\n-\tint spin \u003d 0;\n-#endif\n-\tchar path[256], sym[512];\n-\tunsigned char *p \u003d (unsigned char *)sym + 32 + LWS_PRE, *start \u003d p;\n-\tunsigned char *end \u003d p + sizeof(sym) - 32 - LWS_PRE;\n-#if !defined(WIN32) \u0026\u0026 LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n-\tsize_t len;\n-#endif\n-\tint n;\n-\n-\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, origin, uri);\n-\n-#if !defined(_WIN32_WCE) \u0026\u0026 !defined(LWS_WITH_ESP8266)\n-\n-\tfflags |\u003d lws_vfs_prepare_flags(wsi);\n-\n-\tdo {\n-\t\tspin++;\n-\t\tfops \u003d lws_vfs_select_fops(wsi-\u003econtext-\u003efops, path, \u0026vpath);\n-\n-\t\tif (wsi-\u003eu.http.fop_fd)\n-\t\t\tlws_vfs_file_close(\u0026wsi-\u003eu.http.fop_fd);\n-\n-\t\twsi-\u003eu.http.fop_fd \u003d fops-\u003eLWS_FOP_OPEN(wsi-\u003econtext-\u003efops,\n-\t\t\t\t\t\t\tpath, vpath, \u0026fflags);\n-\t\tif (!wsi-\u003eu.http.fop_fd) {\n-\t\t\tlwsl_err(\u0022Unable to open '%s'\u005cn\u0022, path);\n-\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\t/* if it can't be statted, don't try */\n-\t\tif (fflags \u0026 LWS_FOP_FLAG_VIRTUAL)\n-\t\t\tbreak;\n-#if defined(LWS_WITH_ESP32)\n-\t\tbreak;\n-#endif\n-#if !defined(WIN32)\n-\t\tif (fstat(wsi-\u003eu.http.fop_fd-\u003efd, \u0026st)) {\n-\t\t\tlwsl_info(\u0022unable to stat %s\u005cn\u0022, path);\n-\t\t\tgoto bail;\n-\t\t}\n-#else\n-#if defined(LWS_HAVE__STAT32I64)\n-\t\tif (_stat32i64(path, \u0026st)) {\n-\t\t\tlwsl_info(\u0022unable to stat %s\u005cn\u0022, path);\n-\t\t\tgoto bail;\n-\t\t}\n-#else\n-\t\tif (stat(path, \u0026st)) {\n-\t\t\tlwsl_info(\u0022unable to stat %s\u005cn\u0022, path);\n-\t\t\tgoto bail;\n-\t\t}\n-#endif\n-#endif\n-\n-\t\twsi-\u003eu.http.fop_fd-\u003emod_time \u003d (uint32_t)st.st_mtime;\n-\t\tfflags |\u003d LWS_FOP_FLAG_MOD_TIME_VALID;\n-\n-#if !defined(WIN32) \u0026\u0026 LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n-\t\tif ((S_IFMT \u0026 st.st_mode) \u003d\u003d S_IFLNK) {\n-\t\t\tlen \u003d readlink(path, sym, sizeof(sym) - 1);\n-\t\t\tif (len) {\n-\t\t\t\tlwsl_err(\u0022Failed to read link %s\u005cn\u0022, path);\n-\t\t\t\tgoto bail;\n-\t\t\t}\n-\t\t\tsym[len] \u003d '\u005c0';\n-\t\t\tlwsl_debug(\u0022symlink %s -\u003e %s\u005cn\u0022, path, sym);\n-\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s\u0022, sym);\n-\t\t}\n-#endif\n-\t\tif ((S_IFMT \u0026 st.st_mode) \u003d\u003d S_IFDIR) {\n-\t\t\tlwsl_debug(\u0022default filename append to dir\u005cn\u0022);\n-\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s/index.html\u0022,\n-\t\t\t\t origin, uri);\n-\t\t}\n-\n-\t} while ((S_IFMT \u0026 st.st_mode) !\u003d S_IFREG \u0026\u0026 spin \u003c 5);\n-\n-\tif (spin \u003d\u003d 5)\n-\t\tlwsl_err(\u0022symlink loop %s \u005cn\u0022, path);\n-\n-\tn \u003d sprintf(sym, \u0022%08llX%08lX\u0022,\n-\t\t (unsigned long long)lws_vfs_get_length(wsi-\u003eu.http.fop_fd),\n-\t\t (unsigned long)lws_vfs_get_mod_time(wsi-\u003eu.http.fop_fd));\n-\n-\t/* disable ranges if IF_RANGE token invalid */\n-\n-\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_RANGE))\n-\t\tif (strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_RANGE)))\n-\t\t\t/* differs - defeat Range: */\n-\t\t\twsi-\u003eu.http.ah-\u003efrag_index[WSI_TOKEN_HTTP_RANGE] \u003d 0;\n-\n-\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH)) {\n-\t\t/*\n-\t\t * he thinks he has some version of it already,\n-\t\t * check if the tag matches\n-\t\t */\n-\t\tif (!strcmp(sym, lws_hdr_simple_ptr(wsi,\n-\t\t\t\t\tWSI_TOKEN_HTTP_IF_NONE_MATCH))) {\n-\n-\t\t\tlwsl_debug(\u0022%s: ETAG match %s %s\u005cn\u0022, __func__,\n-\t\t\t\t uri, origin);\n-\n-\t\t\t/* we don't need to send the payload */\n-\t\t\tif (lws_add_http_header_status(wsi,\n-\t\t\t\t\tHTTP_STATUS_NOT_MODIFIED, \u0026p, end))\n-\t\t\t\treturn -1;\n-\n-\t\t\tif (lws_add_http_header_by_token(wsi,\n-\t\t\t\t\tWSI_TOKEN_HTTP_ETAG,\n-\t\t\t\t\t(unsigned char *)sym, n, \u0026p, end))\n-\t\t\t\treturn -1;\n-\n-\t\t\tif (lws_finalize_http_header(wsi, \u0026p, end))\n-\t\t\t\treturn -1;\n-\n-\t\t\tn \u003d lws_write(wsi, start, p - start,\n-\t\t\t\t LWS_WRITE_HTTP_HEADERS |\n-\t\t\t\t LWS_WRITE_H2_STREAM_END);\n-\t\t\tif (n !\u003d (p - start)) {\n-\t\t\t\tlwsl_err(\u0022_write returned %d from %ld\u005cn\u0022, n,\n-\t\t\t\t\t (long)(p - start));\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\n-\t\t\tlws_vfs_file_close(\u0026wsi-\u003eu.http.fop_fd);\n-\n-\t\t\treturn lws_http_transaction_completed(wsi);\n-\t\t}\n-\t}\n-\n-\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,\n-\t\t\t(unsigned char *)sym, n, \u0026p, end))\n-\t\treturn -1;\n-#endif\n-\n-\tmimetype \u003d lws_get_mimetype(path, m);\n-\tif (!mimetype) {\n-\t\tlwsl_err(\u0022unknown mimetype for %s\u005cn\u0022, path);\n- goto bail;\n-\t}\n-\tif (!mimetype[0])\n-\t\tlwsl_debug(\u0022sending no mimetype for %s\u005cn\u0022, path);\n-\n-\twsi-\u003esending_chunked \u003d 0;\n-\n-\t/*\n-\t * check if this is in the list of file suffixes to be interpreted by\n-\t * a protocol\n-\t */\n-\twhile (pvo) {\n-\t\tn \u003d strlen(path);\n-\t\tif (n \u003e (int)strlen(pvo-\u003ename) \u0026\u0026\n-\t\t !strcmp(\u0026path[n - strlen(pvo-\u003ename)], pvo-\u003ename)) {\n-\t\t\twsi-\u003esending_chunked \u003d 1;\n-\t\t\twsi-\u003eprotocol_interpret_idx \u003d (char)(lws_intptr_t)pvo-\u003evalue;\n-\t\t\tlwsl_info(\u0022want %s interpreted by %s\u005cn\u0022, path,\n-\t\t\t\t wsi-\u003evhost-\u003eprotocols[(int)(lws_intptr_t)(pvo-\u003evalue)].name);\n-\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[(int)(lws_intptr_t)(pvo-\u003evalue)];\n-\t\t\tif (lws_ensure_user_space(wsi))\n-\t\t\t\treturn -1;\n-\t\t\tbreak;\n-\t\t}\n-\t\tpvo \u003d pvo-\u003enext;\n-\t}\n-\n-\tif (m-\u003eprotocol) {\n-\t\tconst struct lws_protocols *pp \u003d lws_vhost_name_to_protocol(\n-\t\t\t\t\t\t\twsi-\u003evhost, m-\u003eprotocol);\n-\n-\t\tif (lws_bind_protocol(wsi, pp))\n-\t\t\treturn 1;\n-\t\targs.p \u003d (char *)p;\n-\t\targs.max_len \u003d end - p;\n-\t\tif (pp-\u003ecallback(wsi, LWS_CALLBACK_ADD_HEADERS,\n-\t\t\t\t\t wsi-\u003euser_space, \u0026args, 0))\n-\t\t\treturn -1;\n-\t\tp \u003d (unsigned char *)args.p;\n-\t}\n-\n-\tn \u003d lws_serve_http_file(wsi, path, mimetype, (char *)start, p - start);\n-\n-\tif (n \u003c 0 || ((n \u003e 0) \u0026\u0026 lws_http_transaction_completed(wsi)))\n-\t\treturn -1; /* error or can't reuse connection: close the socket */\n-\n-\treturn 0;\n-bail:\n-\n-\treturn -1;\n-}\n-\n-const struct lws_http_mount *\n-lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)\n-{\n-\tconst struct lws_http_mount *hm, *hit \u003d NULL;\n-\tint best \u003d 0;\n-\n-\thm \u003d wsi-\u003evhost-\u003emount_list;\n-\twhile (hm) {\n-\t\tif (uri_len \u003e\u003d hm-\u003emountpoint_len \u0026\u0026\n-\t\t !strncmp(uri_ptr, hm-\u003emountpoint, hm-\u003emountpoint_len) \u0026\u0026\n-\t\t (uri_ptr[hm-\u003emountpoint_len] \u003d\u003d '\u005c0' ||\n-\t\t uri_ptr[hm-\u003emountpoint_len] \u003d\u003d '/' ||\n-\t\t hm-\u003emountpoint_len \u003d\u003d 1)\n-\t\t ) {\n-\t\t\tif (hm-\u003eorigin_protocol \u003d\u003d LWSMPRO_CALLBACK ||\n-\t\t\t ((hm-\u003eorigin_protocol \u003d\u003d LWSMPRO_CGI ||\n-\t\t\t lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||\n-\t\t\t (wsi-\u003ehttp2_substream \u0026\u0026\n-\t\t\t\tlws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH)) ||\n-\t\t\t hm-\u003eprotocol) \u0026\u0026\n-\t\t\t hm-\u003emountpoint_len \u003e best)) {\n-\t\t\t\tbest \u003d hm-\u003emountpoint_len;\n-\t\t\t\thit \u003d hm;\n-\t\t\t}\n-\t\t}\n-\t\thm \u003d hm-\u003emount_next;\n-\t}\n-\n-\treturn hit;\n-}\n-\n-#if LWS_POSIX\n-\n-static int\n-lws_find_string_in_file(const char *filename, const char *string, int stringlen)\n-{\n-\tchar buf[128];\n-\tint fd, match \u003d 0, pos \u003d 0, n \u003d 0, hit \u003d 0;\n-\n-\tfd \u003d open(filename, O_RDONLY);\n-\tif (fd \u003c 0) {\n-\t\tlwsl_err(\u0022can't open auth file: %s\u005cn\u0022, filename);\n-\t\treturn 1;\n-\t}\n-\n-\twhile (1) {\n-\t\tif (pos \u003d\u003d n) {\n-\t\t\tn \u003d read(fd, buf, sizeof(buf));\n-\t\t\tif (n \u003c\u003d 0) {\n-\t\t\t\tif (match \u003d\u003d stringlen)\n-\t\t\t\t\thit \u003d 1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tpos \u003d 0;\n-\t\t}\n-\n-\t\tif (match \u003d\u003d stringlen) {\n-\t\t\tif (buf[pos] \u003d\u003d '\u005cr' || buf[pos] \u003d\u003d '\u005cn') {\n-\t\t\t\thit \u003d 1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tmatch \u003d 0;\n-\t\t}\n-\n-\t\tif (buf[pos] \u003d\u003d string[match])\n-\t\t\tmatch++;\n-\t\telse\n-\t\t\tmatch \u003d 0;\n-\n-\t\tpos++;\n-\t}\n-\n-\tclose(fd);\n-\n-\treturn hit;\n-}\n-\n-static int\n-lws_unauthorised_basic_auth(struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tunsigned char *start \u003d pt-\u003eserv_buf + LWS_PRE,\n-\t\t *p \u003d start, *end \u003d p + 512;\n-\tchar buf[64];\n-\tint n;\n-\n-\t/* no auth... tell him it is required */\n-\n-\tif (lws_add_http_header_status(wsi, HTTP_STATUS_UNAUTHORIZED, \u0026p, end))\n-\t\treturn -1;\n-\n-\tn \u003d lws_snprintf(buf, sizeof(buf), \u0022Basic realm\u003d\u005c\u0022lwsws\u005c\u0022\u0022);\n-\tif (lws_add_http_header_by_token(wsi,\n-\t\t\tWSI_TOKEN_HTTP_WWW_AUTHENTICATE,\n-\t\t\t(unsigned char *)buf, n, \u0026p, end))\n-\t\treturn -1;\n-\n-\tif (lws_finalize_http_header(wsi, \u0026p, end))\n-\t\treturn -1;\n-\n-\tn \u003d lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS | LWS_WRITE_H2_STREAM_END);\n-\tif (n \u003c 0)\n-\t\treturn -1;\n-\n-\treturn lws_http_transaction_completed(wsi);\n-\n-}\n-\n-#endif\n-\n-int lws_clean_url(char *p)\n-{\n-\tif (p[0] \u003d\u003d 'h' \u0026\u0026 p[1] \u003d\u003d 't' \u0026\u0026 p[2] \u003d\u003d 't' \u0026\u0026 p[3] \u003d\u003d 'p') {\n-\t\tp +\u003d 4;\n-\t\tif (*p \u003d\u003d 's')\n-\t\tp++;\n-\t\tif (*p \u003d\u003d ':') {\n-\t\t\tp++;\n-\t\t\tif (*p \u003d\u003d '/')\n-\t\t\tp++;\n-\t\t}\n-\t}\n-\n-\twhile (*p) {\n-\t\tif (p[0] \u003d\u003d '/' \u0026\u0026 p[1] \u003d\u003d '/') {\n-\t\t\tchar *p1 \u003d p;\n-\t\t\twhile (*p1) {\n-\t\t\t\t*p1 \u003d p1[1];\n-\t\t\t\tp1++;\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t}\n-\t\tp++;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-/*\n- * Produce Apache-compatible log string for wsi, like this:\n- *\n- * 2.31.234.19 - - [27/Mar/2016:03:22:44 +0800]\n- * \u0022GET /aep-screen.png HTTP/1.1\u0022\n- * 200 152987 \u0022https://libwebsockets.org/index.html\u0022\n- * \u0022Mozilla/5.0 (Macint... Chrome/49.0.2623.87 Safari/537.36\u0022\n- *\n- */\n-#ifdef LWS_WITH_ACCESS_LOG\n-static const char * const hver[] \u003d {\n-\t\u0022http/1.0\u0022, \u0022http/1.1\u0022, \u0022http/2\u0022\n-};\n-static void\n-lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int meth)\n-{\n-#ifdef LWS_WITH_IPV6\n-\tchar ads[INET6_ADDRSTRLEN];\n-#else\n-\tchar ads[INET_ADDRSTRLEN];\n-#endif\n-\tchar da[64];\n-\tconst char *pa, *me;\n-\tstruct tm *tmp;\n-\ttime_t t \u003d time(NULL);\n-\tint l \u003d 256, m;\n-\n-\tif (wsi-\u003eaccess_log_pending)\n-\t\tlws_access_log(wsi);\n-\n-\twsi-\u003eaccess_log.header_log \u003d lws_malloc(l, \u0022access log\u0022);\n-\tif (wsi-\u003eaccess_log.header_log) {\n-\n-\t\ttmp \u003d localtime(\u0026t);\n-\t\tif (tmp)\n-\t\t\tstrftime(da, sizeof(da), \u0022%d/%b/%Y:%H:%M:%S %z\u0022, tmp);\n-\t\telse\n-\t\t\tstrcpy(da, \u002201/Jan/1970:00:00:00 +0000\u0022);\n-\n-\t\tpa \u003d lws_get_peer_simple(wsi, ads, sizeof(ads));\n-\t\tif (!pa)\n-\t\t\tpa \u003d \u0022(unknown)\u0022;\n-\n-\t\tif (wsi-\u003ehttp2_substream)\n-\t\t\tme \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);\n-\t\telse\n-\t\t\tme \u003d method_names[meth];\n-\t\tif (!me)\n-\t\t\tme \u003d \u0022(null)\u0022;\n-\n-\t\tlws_snprintf(wsi-\u003eaccess_log.header_log, l,\n-\t\t\t \u0022%s - - [%s] \u005c\u0022%s %s %s\u005c\u0022\u0022,\n-\t\t\t pa, da, me, uri_ptr,\n-\t\t\t hver[wsi-\u003eu.http.request_version]);\n-\n-\t\tl \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);\n-\t\tif (l) {\n-\t\t\twsi-\u003eaccess_log.user_agent \u003d lws_malloc(l + 2, \u0022access log\u0022);\n-\t\t\tif (!wsi-\u003eaccess_log.user_agent) {\n-\t\t\t\tlwsl_err(\u0022OOM getting user agent\u005cn\u0022);\n-\t\t\t\tlws_free_set_NULL(wsi-\u003eaccess_log.header_log);\n-\t\t\t\treturn;\n-\t\t\t}\n-\n-\t\t\tlws_hdr_copy(wsi, wsi-\u003eaccess_log.user_agent,\n-\t\t\t\t\tl + 1, WSI_TOKEN_HTTP_USER_AGENT);\n-\n-\t\t\tfor (m \u003d 0; m \u003c l; m++)\n-\t\t\t\tif (wsi-\u003eaccess_log.user_agent[m] \u003d\u003d '\u005c\u0022')\n-\t\t\t\t\twsi-\u003eaccess_log.user_agent[m] \u003d '\u005c'';\n-\t\t}\n-\t\tl \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER);\n-\t\tif (l) {\n-\t\t\twsi-\u003eaccess_log.referrer \u003d lws_malloc(l + 2, \u0022referrer\u0022);\n-\t\t\tif (!wsi-\u003eaccess_log.referrer) {\n-\t\t\t\tlwsl_err(\u0022OOM getting user agent\u005cn\u0022);\n-\t\t\t\tlws_free_set_NULL(wsi-\u003eaccess_log.user_agent);\n-\t\t\t\tlws_free_set_NULL(wsi-\u003eaccess_log.header_log);\n-\t\t\t\treturn;\n-\t\t\t}\n-\t\t\tlws_hdr_copy(wsi, wsi-\u003eaccess_log.referrer,\n-\t\t\t\t\tl + 1, WSI_TOKEN_HTTP_REFERER);\n-\n-\t\t\tfor (m \u003d 0; m \u003c l; m++)\n-\t\t\t\tif (wsi-\u003eaccess_log.referrer[m] \u003d\u003d '\u005c\u0022')\n-\t\t\t\t\twsi-\u003eaccess_log.referrer[m] \u003d '\u005c'';\n-\t\t}\n-\t\twsi-\u003eaccess_log_pending \u003d 1;\n-\t}\n-}\n-#endif\n-\n-static const unsigned char methods[] \u003d {\n-\tWSI_TOKEN_GET_URI,\n-\tWSI_TOKEN_POST_URI,\n-\tWSI_TOKEN_OPTIONS_URI,\n-\tWSI_TOKEN_PUT_URI,\n-\tWSI_TOKEN_PATCH_URI,\n-\tWSI_TOKEN_DELETE_URI,\n-\tWSI_TOKEN_CONNECT,\n-\tWSI_TOKEN_HEAD_URI,\n-#ifdef LWS_WITH_HTTP2\n-\tWSI_TOKEN_HTTP_COLON_PATH,\n-#endif\n-};\n-\n-static int\n-lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)\n-{\n-\tint n, count \u003d 0;\n-\n-\tfor (n \u003d 0; n \u003c ARRAY_SIZE(methods); n++)\n-\t\tif (lws_hdr_total_length(wsi, methods[n]))\n-\t\t\tcount++;\n-\tif (!count) {\n-\t\tlwsl_warn(\u0022Missing URI in HTTP request\u005cn\u0022);\n-\t\treturn -1;\n-\t}\n-\n-\tif (count !\u003d 1 \u0026\u0026\n-\t !(wsi-\u003ehttp2_substream \u0026\u0026\n-\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH))) {\n-\t\tlwsl_warn(\u0022multiple methods?\u005cn\u0022);\n-\t\treturn -1;\n-\t}\n-\n-\tfor (n \u003d 0; n \u003c ARRAY_SIZE(methods); n++)\n-\t\tif (lws_hdr_total_length(wsi, methods[n])) {\n-\t\t\t*puri_ptr \u003d lws_hdr_simple_ptr(wsi, methods[n]);\n-\t\t\t*puri_len \u003d lws_hdr_total_length(wsi, methods[n]);\n-\t\t\treturn n;\n-\t\t}\n-\n-\treturn -1;\n-}\n-\n-int\n-lws_http_action(struct lws *wsi)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tenum http_connection_type connection_type;\n-\tenum http_version request_version;\n-\tchar content_length_str[32];\n-\tstruct lws_process_html_args args;\n-\tconst struct lws_http_mount *hit \u003d NULL;\n-\tunsigned int n;\n-\tchar http_version_str[10];\n-\tchar http_conn_str[20];\n-\tint http_version_len;\n-\tchar *uri_ptr \u003d NULL, *s;\n-\tint uri_len \u003d 0, meth;\n-\tstatic const char * const oprot[] \u003d {\n-\t\t\u0022http://\u0022, \u0022https://\u0022\n-\t};\n-\n-\tmeth \u003d lws_http_get_uri_and_method(wsi, \u0026uri_ptr, \u0026uri_len);\n-\tif (meth \u003c 0 || meth \u003e\u003d ARRAY_SIZE(method_names))\n-\t\tgoto bail_nuke_ah;\n-\n-\t/* we insist on absolute paths */\n-\n-\tif (!uri_ptr || uri_ptr[0] !\u003d '/') {\n-\t\tlws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);\n-\n-\t\tgoto bail_nuke_ah;\n-\t}\n-\n-\tlwsl_info(\u0022Method: '%s' (%d), request for '%s'\u005cn\u0022, method_names[meth], meth, uri_ptr);\n-\n-\tif (lws_ensure_user_space(wsi))\n-\t\tgoto bail_nuke_ah;\n-\n-\t/* HTTP header had a content length? */\n-\n-\twsi-\u003eu.http.rx_content_length \u003d 0;\n-\tif (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||\n-\t\tlws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||\n-\t\tlws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))\n-\t\twsi-\u003eu.http.rx_content_length \u003d 100 * 1024 * 1024;\n-\n-\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n-\t\tlws_hdr_copy(wsi, content_length_str,\n-\t\t\t sizeof(content_length_str) - 1,\n-\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH);\n-\t\twsi-\u003eu.http.rx_content_length \u003d atoll(content_length_str);\n-\t}\n-\n-\tif (wsi-\u003ehttp2_substream) {\n-\t\twsi-\u003eu.http.request_version \u003d HTTP_VERSION_2;\n-\t} else {\n-\t\t/* http_version? Default to 1.0, override with token: */\n-\t\trequest_version \u003d HTTP_VERSION_1_0;\n-\n-\t\t/* Works for single digit HTTP versions. : */\n-\t\thttp_version_len \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP);\n-\t\tif (http_version_len \u003e 7) {\n-\t\t\tlws_hdr_copy(wsi, http_version_str,\n-\t\t\t\t\tsizeof(http_version_str) - 1, WSI_TOKEN_HTTP);\n-\t\t\tif (http_version_str[5] \u003d\u003d '1' \u0026\u0026 http_version_str[7] \u003d\u003d '1')\n-\t\t\t\trequest_version \u003d HTTP_VERSION_1_1;\n-\t\t}\n-\t\twsi-\u003eu.http.request_version \u003d request_version;\n-\n-\t\t/* HTTP/1.1 defaults to \u0022keep-alive\u0022, 1.0 to \u0022close\u0022 */\n-\t\tif (request_version \u003d\u003d HTTP_VERSION_1_1)\n-\t\t\tconnection_type \u003d HTTP_CONNECTION_KEEP_ALIVE;\n-\t\telse\n-\t\t\tconnection_type \u003d HTTP_CONNECTION_CLOSE;\n-\n-\t\t/* Override default if http \u0022Connection:\u0022 header: */\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {\n-\t\t\tlws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1,\n-\t\t\t\t WSI_TOKEN_CONNECTION);\n-\t\t\thttp_conn_str[sizeof(http_conn_str) - 1] \u003d '\u005c0';\n-\t\t\tif (!strcasecmp(http_conn_str, \u0022keep-alive\u0022))\n-\t\t\t\tconnection_type \u003d HTTP_CONNECTION_KEEP_ALIVE;\n-\t\t\telse\n-\t\t\t\tif (!strcasecmp(http_conn_str, \u0022close\u0022))\n-\t\t\t\t\tconnection_type \u003d HTTP_CONNECTION_CLOSE;\n-\t\t}\n-\t\twsi-\u003eu.http.connection_type \u003d connection_type;\n-\t}\n-\n-\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,\n-\t\t\t\t wsi-\u003euser_space, uri_ptr, uri_len);\n-\tif (n) {\n-\t\tlwsl_info(\u0022LWS_CALLBACK_HTTP closing\u005cn\u0022);\n-\n-\t\treturn 1;\n-\t}\n-\t/*\n-\t * if there is content supposed to be coming,\n-\t * put a timeout on it having arrived\n-\t */\n-\tlws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,\n-\t\t\twsi-\u003econtext-\u003etimeout_secs);\n-#ifdef LWS_OPENSSL_SUPPORT\n-\tif (wsi-\u003eredirect_to_https) {\n-\t\t/*\n-\t\t * we accepted http:// only so we could redirect to\n-\t\t * https://, so issue the redirect. Create the redirection\n-\t\t * URI from the host: header and ignore the path part\n-\t\t */\n-\t\tunsigned char *start \u003d pt-\u003eserv_buf + LWS_PRE, *p \u003d start,\n-\t\t\t *end \u003d p + 512;\n-\n-\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))\n-\t\t\tgoto bail_nuke_ah;\n-\n-\t\tn \u003d sprintf((char *)end, \u0022https://%s/\u0022,\n-\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));\n-\n-\t\tn \u003d lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,\n-\t\t\t\t end, n, \u0026p, end);\n-\t\tif ((int)n \u003c 0)\n-\t\t\tgoto bail_nuke_ah;\n-\n-\t\treturn lws_http_transaction_completed(wsi);\n-\t}\n-#endif\n-\n-#ifdef LWS_WITH_ACCESS_LOG\n-\tlws_prepare_access_log_info(wsi, uri_ptr, meth);\n-#endif\n-\n-\t/* can we serve it from the mount list? */\n-\n-\thit \u003d lws_find_mount(wsi, uri_ptr, uri_len);\n-\tif (!hit) {\n-\t\t/* deferred cleanup and reset to protocols[0] */\n-\n-\t\tlwsl_info(\u0022no hit\u005cn\u0022);\n-\n-\t\tif (lws_bind_protocol(wsi, \u0026wsi-\u003evhost-\u003eprotocols[0]))\n-\t\t\treturn 1;\n-\n-\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n-\t\t\t\t wsi-\u003euser_space, uri_ptr, uri_len);\n-\n-\t\tgoto after;\n-\t}\n-\n-\ts \u003d uri_ptr + hit-\u003emountpoint_len;\n-\n-\t/*\n-\t * if we have a mountpoint like https://xxx.com/yyy\n-\t * there is an implied / at the end for our purposes since\n-\t * we can only mount on a \u0022directory\u0022.\n-\t *\n-\t * But if we just go with that, the browser cannot understand\n-\t * that he is actually looking down one \u0022directory level\u0022, so\n-\t * even though we give him /yyy/abc.html he acts like the\n-\t * current directory level is /. So relative urls like \u0022x.png\u0022\n-\t * wrongly look outside the mountpoint.\n-\t *\n-\t * Therefore if we didn't come in on a url with an explicit\n-\t * / at the end, we must redirect to add it so the browser\n-\t * understands he is one \u0022directory level\u0022 down.\n-\t */\n-\tif ((hit-\u003emountpoint_len \u003e 1 ||\n-\t (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTP ||\n-\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTPS)) \u0026\u0026\n-\t (*s !\u003d '/' ||\n-\t (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTP ||\n-\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTPS)) \u0026\u0026\n-\t (hit-\u003eorigin_protocol !\u003d LWSMPRO_CGI \u0026\u0026\n-\t hit-\u003eorigin_protocol !\u003d LWSMPRO_CALLBACK)) {\n-\t\tunsigned char *start \u003d pt-\u003eserv_buf + LWS_PRE,\n-\t\t\t *p \u003d start, *end \u003d p + 512;\n-\n-\t\tlwsl_debug(\u0022Doing 301 '%s' org %s\u005cn\u0022, s, hit-\u003eorigin);\n-\n-\t\t/* \u003e at start indicates deal with by redirect */\n-\t\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTP ||\n-\t\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTPS)\n-\t\t\tn \u003d lws_snprintf((char *)end, 256, \u0022%s%s\u0022,\n-\t\t\t\t oprot[hit-\u003eorigin_protocol \u0026 1],\n-\t\t\t\t hit-\u003eorigin);\n-\t\telse {\n-\t\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {\n-\t\t\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY))\n-\t\t\t\t\tgoto bail_nuke_ah;\n-\t\t\t\tn \u003d lws_snprintf((char *)end, 256,\n-\t\t\t\t \u0022%s%s%s/\u0022, oprot[!!lws_is_ssl(wsi)],\n-\t\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY),\n-\t\t\t\t uri_ptr);\n-\t\t\t} else\n-\t\t\t\tn \u003d lws_snprintf((char *)end, 256,\n-\t\t\t\t \u0022%s%s%s/\u0022, oprot[!!lws_is_ssl(wsi)],\n-\t\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),\n-\t\t\t\t uri_ptr);\n-\t\t}\n-\n-\t\tlws_clean_url((char *)end);\n-\t\tn \u003d lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,\n-\t\t\t\t end, n, \u0026p, end);\n-\t\tif ((int)n \u003c 0)\n-\t\t\tgoto bail_nuke_ah;\n-\n-\t\treturn lws_http_transaction_completed(wsi);\n-\t}\n-\n-#if LWS_POSIX\n-\t/* basic auth? */\n-\n-\tif (hit-\u003ebasic_auth_login_file) {\n-\t\tchar b64[160], plain[(sizeof(b64) * 3) / 4];\n-\t\tint m;\n-\n-\t\t/* Did he send auth? */\n-\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION))\n-\t\t\treturn lws_unauthorised_basic_auth(wsi);\n-\n-\t\tn \u003d HTTP_STATUS_FORBIDDEN;\n-\n-\t\tm \u003d lws_hdr_copy(wsi, b64, sizeof(b64), WSI_TOKEN_HTTP_AUTHORIZATION);\n-\t\tif (m \u003c 7) {\n-\t\t\tlwsl_err(\u0022b64 auth too long\u005cn\u0022);\n-\t\t\tgoto transaction_result_n;\n-\t\t}\n-\n-\t\tb64[5] \u003d '\u005c0';\n-\t\tif (strcasecmp(b64, \u0022Basic\u0022)) {\n-\t\t\tlwsl_err(\u0022auth missing basic: %s\u005cn\u0022, b64);\n-\t\t\tgoto transaction_result_n;\n-\t\t}\n-\n-\t\t/* It'll be like Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l */\n-\n-\t\tm \u003d lws_b64_decode_string(b64 + 6, plain, sizeof(plain));\n-\t\tif (m \u003c 0) {\n-\t\t\tlwsl_err(\u0022plain auth too long\u005cn\u0022);\n-\t\t\tgoto transaction_result_n;\n-\t\t}\n-\n-\t\tif (!lws_find_string_in_file(hit-\u003ebasic_auth_login_file, plain, m)) {\n-\t\t\tlwsl_err(\u0022basic auth lookup failed\u005cn\u0022);\n-\t\t\treturn lws_unauthorised_basic_auth(wsi);\n-\t\t}\n-\n-\t\tlwsl_notice(\u0022basic auth accepted\u005cn\u0022);\n-\n-\t\t/* accept the auth */\n-\t}\n-#endif\n-\n-#if defined(LWS_WITH_HTTP_PROXY)\n-\t/*\n-\t * The mount is a reverse proxy?\n-\t */\n-\n-\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTPS ||\n-\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTP) {\n-\t\tstruct lws_client_connect_info i;\n-\t\tchar ads[96], rpath[256], *pcolon, *pslash, *p;\n-\t\tint n, na;\n-\n-\t\tmemset(\u0026i, 0, sizeof(i));\n-\t\ti.context \u003d lws_get_context(wsi);\n-\n-\t\tpcolon \u003d strchr(hit-\u003eorigin, ':');\n-\t\tpslash \u003d strchr(hit-\u003eorigin, '/');\n-\t\tif (!pslash) {\n-\t\t\tlwsl_err(\u0022Proxy mount origin '%s' must have /\u005cn\u0022, hit-\u003eorigin);\n-\t\t\treturn -1;\n-\t\t}\n-\t\tif (pcolon \u003e pslash)\n-\t\t\tpcolon \u003d NULL;\n-\t\t\n-\t\tif (pcolon)\n-\t\t\tn \u003d pcolon - hit-\u003eorigin;\n-\t\telse\n-\t\t\tn \u003d pslash - hit-\u003eorigin;\n-\n-\t\tif (n \u003e\u003d sizeof(ads) - 2)\n-\t\t\tn \u003d sizeof(ads) - 2;\n-\n-\t\tmemcpy(ads, hit-\u003eorigin, n);\n-\t\tads[n] \u003d '\u005c0';\n-\n-\t\ti.address \u003d ads;\n-\t\ti.port \u003d 80;\n-\t\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTPS) { \n-\t\t\ti.port \u003d 443;\n-\t\t\ti.ssl_connection \u003d 1;\n-\t\t}\n-\t\tif (pcolon)\n-\t\t\ti.port \u003d atoi(pcolon + 1);\n-\t\t\n-\t\tlws_snprintf(rpath, sizeof(rpath) - 1, \u0022/%s/%s\u0022, pslash + 1, uri_ptr + hit-\u003emountpoint_len);\n-\t\tlws_clean_url(rpath);\n-\t\tna \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_URI_ARGS);\n-\t\tif (na) {\n-\t\t\tp \u003d rpath + strlen(rpath);\n-\t\t\t*p++ \u003d '?';\n-\t\t\tlws_hdr_copy(wsi, p, \u0026rpath[sizeof(rpath) - 1] - p, WSI_TOKEN_HTTP_URI_ARGS);\n-\t\t\twhile (--na) {\n-\t\t\t\tif (*p \u003d\u003d '\u005c0')\n-\t\t\t\t\t*p \u003d '\u0026';\n-\t\t\t\tp++;\n-\t\t\t}\n-\t\t}\n-\t\t\t\t\n-\n-\t\ti.path \u003d rpath;\n-\t\ti.host \u003d i.address;\n-\t\ti.origin \u003d NULL;\n-\t\ti.method \u003d \u0022GET\u0022;\n-\t\ti.parent_wsi \u003d wsi;\n-\t\ti.uri_replace_from \u003d hit-\u003eorigin;\n-\t\ti.uri_replace_to \u003d hit-\u003emountpoint;\n-\n-\t\tlwsl_notice(\u0022proxying to %s port %d url %s, ssl %d, from %s, to %s\u005cn\u0022,\n-\t\t\t\ti.address, i.port, i.path, i.ssl_connection, i.uri_replace_from, i.uri_replace_to);\n-\t\n-\t\tif (!lws_client_connect_via_info(\u0026i)) {\n-\t\t\tlwsl_err(\u0022proxy connect fail\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\treturn 0;\n-\t}\n-#endif\n-\n-\t/*\n-\t * A particular protocol callback is mounted here?\n-\t *\n-\t * For the duration of this http transaction, bind us to the\n-\t * associated protocol\n-\t */\n-\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_CALLBACK || hit-\u003eprotocol) {\n-\t\tconst struct lws_protocols *pp;\n-\t\tconst char *name \u003d hit-\u003eorigin;\n-\t\tif (hit-\u003eprotocol)\n-\t\t\tname \u003d hit-\u003eprotocol;\n-\n-\t\tpp \u003d lws_vhost_name_to_protocol(wsi-\u003evhost, name);\n-\t\tif (!pp) {\n-\t\t\tn \u003d -1;\n-\t\t\tlwsl_err(\u0022Unable to find plugin '%s'\u005cn\u0022,\n-\t\t\t\t hit-\u003eorigin);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\tif (lws_bind_protocol(wsi, pp))\n-\t\t\treturn 1;\n-\n-\t\targs.p \u003d uri_ptr;\n-\t\targs.len \u003d uri_len;\n-\t\targs.max_len \u003d hit-\u003eauth_mask;\n-\t\targs.final \u003d 0; /* used to signal callback dealt with it */\n-\n-\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CHECK_ACCESS_RIGHTS,\n-\t\t\t\t\t wsi-\u003euser_space, \u0026args, 0);\n-\t\tif (n) {\n-\t\t\tlws_return_http_status(wsi, HTTP_STATUS_UNAUTHORIZED,\n-\t\t\t\t\t NULL);\n-\t\t\tgoto bail_nuke_ah;\n-\t\t}\n-\t\tif (args.final) /* callback completely handled it well */\n-\t\t\treturn 0;\n-\n-\t\tif (hit-\u003ecgienv \u0026\u0026 wsi-\u003eprotocol-\u003ecallback(wsi,\n-\t\t\t\tLWS_CALLBACK_HTTP_PMO,\n-\t\t\t\twsi-\u003euser_space, (void *)hit-\u003ecgienv, 0))\n-\t\t\treturn 1;\n-\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {\n-\t\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n-\t\t\t\t\t wsi-\u003euser_space,\n-\t\t\t\t\t uri_ptr + hit-\u003emountpoint_len,\n-\t\t\t\t\t uri_len - hit-\u003emountpoint_len);\n-\t\t\tgoto after;\n-\t\t}\n-\t}\n-\n-#ifdef LWS_WITH_CGI\n-\t/* did we hit something with a cgi:// origin? */\n-\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_CGI) {\n-\t\tconst char *cmd[] \u003d {\n-\t\t\tNULL, /* replace with cgi path */\n-\t\t\tNULL\n-\t\t};\n-\n-\t\tlwsl_debug(\u0022%s: cgi\u005cn\u0022, __func__);\n-\t\tcmd[0] \u003d hit-\u003eorigin;\n-\n-\t\tn \u003d 5;\n-\t\tif (hit-\u003ecgi_timeout)\n-\t\t\tn \u003d hit-\u003ecgi_timeout;\n-\n-\t\tn \u003d lws_cgi(wsi, cmd, hit-\u003emountpoint_len, n,\n-\t\t\t hit-\u003ecgienv);\n-\t\tif (n) {\n-\t\t\tlwsl_err(\u0022%s: cgi failed\u005cn\u0022, __func__);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tgoto deal_body;\n-\t}\n-#endif\n-\n-\tn \u003d strlen(s);\n-\tif (s[0] \u003d\u003d '\u005c0' || (n \u003d\u003d 1 \u0026\u0026 s[n - 1] \u003d\u003d '/'))\n-\t\ts \u003d (char *)hit-\u003edef;\n-\tif (!s)\n-\t\ts \u003d \u0022index.html\u0022;\n-\n-\twsi-\u003ecache_secs \u003d hit-\u003ecache_max_age;\n-\twsi-\u003ecache_reuse \u003d hit-\u003ecache_reusable;\n-\twsi-\u003ecache_revalidate \u003d hit-\u003ecache_revalidate;\n-\twsi-\u003ecache_intermediaries \u003d hit-\u003ecache_intermediaries;\n-\n-\tn \u003d lws_http_serve(wsi, s, hit-\u003eorigin, hit);\n-\tif (n) {\n-\t\t/*\n-\t\t * \tlws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);\n-\t\t */\n-\t\tif (hit-\u003eprotocol) {\n-\t\t\tconst struct lws_protocols *pp \u003d lws_vhost_name_to_protocol(\n-\t\t\t\t\twsi-\u003evhost, hit-\u003eprotocol);\n-\n-\t\t\tif (lws_bind_protocol(wsi, pp))\n-\t\t\t\treturn 1;\n-\n-\t\t\tn \u003d pp-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n-\t\t\t\t\t wsi-\u003euser_space,\n-\t\t\t\t\t uri_ptr + hit-\u003emountpoint_len,\n-\t\t\t\t\t uri_len - hit-\u003emountpoint_len);\n-\t\t} else\n-\t\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n-\t\t\t\t wsi-\u003euser_space, uri_ptr, uri_len);\n-\t}\n-\n-after:\n-\tif (n) {\n-\t\tlwsl_info(\u0022LWS_CALLBACK_HTTP closing\u005cn\u0022);\n-\n-\t\treturn 1;\n-\t}\n-\n-#ifdef LWS_WITH_CGI\n-deal_body:\n-#endif\n-\t/*\n-\t * If we're not issuing a file, check for content_length or\n-\t * HTTP keep-alive. No keep-alive header allocation for\n-\t * ISSUING_FILE, as this uses HTTP/1.0.\n-\t *\n-\t * In any case, return 0 and let lws_read decide how to\n-\t * proceed based on state\n-\t */\n-\tif (wsi-\u003estate !\u003d LWSS_HTTP_ISSUING_FILE) {\n-\t\t/* Prepare to read body if we have a content length: */\n-\t\tlwsl_debug(\u0022wsi-\u003eu.http.rx_content_length %lld %d %d\u005cn\u0022, (long long)wsi-\u003eu.http.rx_content_length, wsi-\u003eupgraded_to_http2, wsi-\u003ehttp2_substream);\n-\t\tif (wsi-\u003eu.http.rx_content_length \u003e 0) {\n-\t\t\tlwsl_notice(\u0022%s: %p: LWSS_HTTP_BODY state set\u005cn\u0022, __func__, wsi);\n-\t\t\twsi-\u003estate \u003d LWSS_HTTP_BODY;\n-\t\t\twsi-\u003eu.http.rx_content_remain \u003d wsi-\u003eu.http.rx_content_length;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-\n-bail_nuke_ah:\n-\t/* we're closing, losing some rx is OK */\n-\tlws_header_table_force_to_detachable_state(wsi);\n-\tlws_header_table_detach(wsi, 1);\n-\n-\treturn 1;\n-\n-#if LWS_POSIX\n-transaction_result_n:\n-\tlws_return_http_status(wsi, n, NULL);\n-\n-\treturn lws_http_transaction_completed(wsi);\n-#endif\n-}\n-\n-static int\n-lws_server_init_wsi_for_ws(struct lws *wsi)\n-{\n-\tint n;\n-\n-\twsi-\u003estate \u003d LWSS_ESTABLISHED;\n-\tlws_restart_ws_ping_pong_timer(wsi);\n-\n-\t/*\n-\t * create the frame buffer for this connection according to the\n-\t * size mentioned in the protocol definition. If 0 there, use\n-\t * a big default for compatibility\n-\t */\n-\n-\tn \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n-\tif (!n)\n-\t\tn \u003d wsi-\u003econtext-\u003ept_serv_buf_size;\n-\tn +\u003d LWS_PRE;\n-\twsi-\u003eu.ws.rx_ubuf \u003d lws_malloc(n + 4 /* 0x0000ffff zlib */, \u0022rx_ubuf\u0022);\n-\tif (!wsi-\u003eu.ws.rx_ubuf) {\n-\t\tlwsl_err(\u0022Out of Mem allocating rx buffer %d\u005cn\u0022, n);\n-\t\treturn 1;\n-\t}\n-\twsi-\u003eu.ws.rx_ubuf_alloc \u003d n;\n-\tlwsl_debug(\u0022Allocating RX buffer %d\u005cn\u0022, n);\n-\n-#if LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n-\tif (!wsi-\u003eparent_carries_io)\n-\t\tif (setsockopt(wsi-\u003edesc.sockfd, SOL_SOCKET, SO_SNDBUF,\n-\t\t (const char *)\u0026n, sizeof n)) {\n-\t\t\tlwsl_warn(\u0022Failed to set SNDBUF to %d\u0022, n);\n-\t\t\treturn 1;\n-\t\t}\n-#endif\n-\n-\t/* notify user code that we're ready to roll */\n-\n-\tif (wsi-\u003eprotocol-\u003ecallback)\n-\t\tif (wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_ESTABLISHED,\n-\t\t\t\t\t wsi-\u003euser_space,\n-#ifdef LWS_OPENSSL_SUPPORT\n-\t\t\t\t\t wsi-\u003essl,\n-#else\n-\t\t\t\t\t NULL,\n-#endif\n-\t\t\t\t\t 0))\n-\t\t\treturn 1;\n-\n-\treturn 0;\n-}\n-\n-int\n-lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)\n-{\n-\tint protocol_len, n \u003d 0, hit, non_space_char_found \u003d 0, m;\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tstruct _lws_header_related hdr;\n-\tstruct allocated_headers *ah;\n-\tunsigned char *obuf \u003d *buf;\n-\tchar protocol_list[128];\n-\tchar protocol_name[64];\n-\tsize_t olen \u003d len;\n-\tchar *p;\n-\n-\tif (len \u003e\u003d 10000000) {\n-\t\tlwsl_err(\u0022%s: assert: len %ld\u005cn\u0022, __func__, (long)len);\n-\t\tassert(0);\n-\t}\n-\n-\tif (!wsi-\u003eu.hdr.ah) {\n-\t\tlwsl_err(\u0022%s: assert: NULL ah\u005cn\u0022, __func__);\n-\t\tassert(0);\n-\t}\n-\n-\tlwsl_hexdump(*buf, len);\n-\n-\twhile (len--) {\n-\t\twsi-\u003emore_rx_waiting \u003d !!len;\n-\n-\t\tif (wsi-\u003emode !\u003d LWSCM_HTTP_SERVING \u0026\u0026\n-\t\t wsi-\u003emode !\u003d LWSCM_HTTP2_SERVING \u0026\u0026\n-\t\t wsi-\u003emode !\u003d LWSCM_HTTP_SERVING_ACCEPTED) {\n-\t\t\tlwsl_err(\u0022%s: bad wsi mode %d\u005cn\u0022, __func__, wsi-\u003emode);\n-\t\t\tgoto bail_nuke_ah;\n-\t\t}\n-\n-\t\tm \u003d lws_parse(wsi, *(*buf)++);\n-\t\tif (m) {\n-\t\t\tif (m \u003d\u003d 2) {\n-\t\t\t\t/*\n-\t\t\t\t * we are transitioning from http with\n-\t\t\t\t * an AH, to raw. Drop the ah and set\n-\t\t\t\t * the mode.\n-\t\t\t\t */\n-raw_transition:\n-\t\t\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\t\t\t\tlws_bind_protocol(wsi, \u0026wsi-\u003evhost-\u003eprotocols[\n-\t\t\t\t wsi-\u003evhost-\u003e\n-\t\t\t\t raw_protocol_index]);\n-\t\t\t\tlwsl_info(\u0022transition to raw vh %s prot %d\u005cn\u0022,\n-\t\t\t\t\t wsi-\u003evhost-\u003ename,\n-\t\t\t\t\t wsi-\u003evhost-\u003eraw_protocol_index);\n-\t\t\t\tif ((wsi-\u003eprotocol-\u003ecallback)(wsi,\n-\t\t\t\t\t\tLWS_CALLBACK_RAW_ADOPT,\n-\t\t\t\t\t\twsi-\u003euser_space, NULL, 0))\n-\t\t\t\t\tgoto bail_nuke_ah;\n-\n-\t\t\t\tlws_header_table_force_to_detachable_state(wsi);\n-\t\t\t\tlws_union_transition(wsi, LWSCM_RAW);\n-\t\t\t\tlws_header_table_detach(wsi, 1);\n-\n-\t\t\t\tif (m \u003d\u003d 2 \u0026\u0026 (wsi-\u003eprotocol-\u003ecallback)(wsi,\n-\t\t\t\t\t\tLWS_CALLBACK_RAW_RX,\n-\t\t\t\t\t\twsi-\u003euser_space, obuf, olen))\n-\t\t\t\t\treturn 1;\n-\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t\tlwsl_info(\u0022lws_parse failed\u005cn\u0022);\n-\t\t\tgoto bail_nuke_ah;\n-\t\t}\n-\n-\t\tif (wsi-\u003eu.hdr.parser_state !\u003d WSI_PARSING_COMPLETE)\n-\t\t\tcontinue;\n-\n-\t\tlwsl_parser(\u0022%s: lws_parse sees parsing complete\u005cn\u0022, __func__);\n-\t\tlwsl_debug(\u0022%s: wsi-\u003emore_rx_waiting\u003d%d\u005cn\u0022, __func__,\n-\t\t\t\twsi-\u003emore_rx_waiting);\n-\n-\t\t/* select vhost */\n-\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {\n-\t\t\tstruct lws_vhost *vhost \u003d lws_select_vhost(\n-\t\t\t\tcontext, wsi-\u003evhost-\u003elisten_port,\n-\t\t\t\tlws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));\n-\n-\t\t\tif (vhost)\n-\t\t\t\twsi-\u003evhost \u003d vhost;\n-\t\t} else\n-\t\t\tlwsl_info(\u0022no host\u005cn\u0022);\n-\n-\t\tif (wsi-\u003emode !\u003d LWSCM_HTTP2_SERVING) {\n-\t\t\twsi-\u003evhost-\u003econn_stats.h1_trans++;\n-\t\t\tif (!wsi-\u003econn_stat_done) {\n-\t\t\t\twsi-\u003evhost-\u003econn_stats.h1_conn++;\n-\t\t\t\twsi-\u003econn_stat_done \u003d 1;\n-\t\t\t}\n-\t\t}\n-\n-\t\t/* check for unwelcome guests */\n-\n-\t\tif (wsi-\u003econtext-\u003ereject_service_keywords) {\n-\t\t\tconst struct lws_protocol_vhost_options *rej \u003d\n-\t\t\t\t\twsi-\u003econtext-\u003ereject_service_keywords;\n-\t\t\tchar ua[384], *msg \u003d NULL;\n-\n-\t\t\tif (lws_hdr_copy(wsi, ua, sizeof(ua) - 1,\n-\t\t\t\t\t WSI_TOKEN_HTTP_USER_AGENT) \u003e 0) {\n-\t\t\t\tua[sizeof(ua) - 1] \u003d '\u005c0';\n-\t\t\t\twhile (rej) {\n-\t\t\t\t\tif (strstr(ua, rej-\u003ename)) {\n-#ifdef LWS_WITH_ACCESS_LOG\n-\t\t\t\t\t\tchar *uri_ptr \u003d NULL;\n-\t\t\t\t\t\tint meth, uri_len;\n-#endif\n-\n-\t\t\t\t\t\tmsg \u003d strchr(rej-\u003evalue, ' ');\n-\t\t\t\t\t\tif (msg)\n-\t\t\t\t\t\t\tmsg++;\n-\t\t\t\t\t\tlws_return_http_status(wsi, atoi(rej-\u003evalue), msg);\n-#ifdef LWS_WITH_ACCESS_LOG\n-\t\t\t\t\t\tmeth \u003d lws_http_get_uri_and_method(wsi,\n-\t\t\t\t\t\t\t\t\u0026uri_ptr, \u0026uri_len);\n-\t\t\t\t\t\tif (meth \u003e\u003d 0)\n-\t\t\t\t\t\t\tlws_prepare_access_log_info(wsi,\n-\t\t\t\t\t\t\t\turi_ptr, meth);\n-\n-\t\t\t\t\t\t/* wsi close will do the log */\n-#endif\n-\t\t\t\t\t\twsi-\u003evhost-\u003econn_stats.rejected++;\n-\t\t\t\t\t\t/*\n-\t\t\t\t\t\t * We don't want anything from\n-\t\t\t\t\t\t * this rejected guy. Follow\n-\t\t\t\t\t\t * the close flow, not the\n-\t\t\t\t\t\t * transaction complete flow.\n-\t\t\t\t\t\t */\n-\t\t\t\t\t\tgoto bail_nuke_ah;\n-\t\t\t\t\t}\n-\t\t\t\t\trej \u003d rej-\u003enext;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\n-\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) {\n-\t\t\tlwsl_info(\u0022Changing to RAW mode\u005cn\u0022);\n-\t\t\tm \u003d 0;\n-\t\t\tgoto raw_transition;\n-\t\t}\n-\n-\t\twsi-\u003emode \u003d LWSCM_PRE_WS_SERVING_ACCEPT;\n-\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n-\n-\t\t/* is this websocket protocol or normal http 1.0? */\n-\n-\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {\n-\t\t\tif (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),\n-\t\t\t\t\t\u0022websocket\u0022)) {\n-\t\t\t\twsi-\u003evhost-\u003econn_stats.ws_upg++;\n-\t\t\t\tlwsl_info(\u0022Upgrade to ws\u005cn\u0022);\n-\t\t\t\tgoto upgrade_ws;\n-\t\t\t}\n-#ifdef LWS_WITH_HTTP2\n-\t\t\tif (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),\n-\t\t\t\t\t\u0022h2c\u0022)) {\n-\t\t\t\twsi-\u003evhost-\u003econn_stats.h2_upg++;\n-\t\t\t\tlwsl_info(\u0022Upgrade to h2c\u005cn\u0022);\n-\t\t\t\tgoto upgrade_h2c;\n-\t\t\t}\n-#endif\n-\t\t\tlwsl_info(\u0022Unknown upgrade\u005cn\u0022);\n-\t\t\t/* dunno what he wanted to upgrade to */\n-\t\t\tgoto bail_nuke_ah;\n-\t\t}\n-\n-\t\t/* no upgrade ack... he remained as HTTP */\n-\n-\t\tlwsl_info(\u0022No upgrade\u005cn\u0022);\n-\t\tah \u003d wsi-\u003eu.hdr.ah;\n-\n-\t\tlws_union_transition(wsi, LWSCM_HTTP_SERVING_ACCEPTED);\n-\t\twsi-\u003estate \u003d LWSS_HTTP;\n-\t\twsi-\u003eu.http.fop_fd \u003d NULL;\n-\n-\t\t/* expose it at the same offset as u.hdr */\n-\t\twsi-\u003eu.http.ah \u003d ah;\n-\t\tlwsl_debug(\u0022%s: wsi %p: ah %p\u005cn\u0022, __func__, (void *)wsi,\n-\t\t\t (void *)wsi-\u003eu.hdr.ah);\n-\n-\t\tn \u003d lws_http_action(wsi);\n-\n-\t\treturn n;\n-\n-#ifdef LWS_WITH_HTTP2\n-upgrade_h2c:\n-\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) {\n-\t\t\tlwsl_info(\u0022missing http2_settings\u005cn\u0022);\n-\t\t\tgoto bail_nuke_ah;\n-\t\t}\n-\n-\t\tlwsl_info(\u0022h2c upgrade...\u005cn\u0022);\n-\n-\t\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);\n-\t\t/* convert the peer's HTTP-Settings */\n-\t\tn \u003d lws_b64_decode_string(p, protocol_list,\n-\t\t\t\t\t sizeof(protocol_list));\n-\t\tif (n \u003c 0) {\n-\t\t\tlwsl_parser(\u0022HTTP2_SETTINGS too long\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\t/* adopt the header info */\n-\n-\t\tah \u003d wsi-\u003eu.hdr.ah;\n-\n-\t\tlws_union_transition(wsi, LWSCM_HTTP2_SERVING);\n-\n-\t\t/* http2 union member has http union struct at start */\n-\t\twsi-\u003eu.http.ah \u003d ah;\n-\n-\t\tif (!wsi-\u003eu.h2.h2n) {\n-\t\t\twsi-\u003eu.h2.h2n \u003d lws_zalloc(sizeof(*wsi-\u003eu.h2.h2n), \u0022h2n\u0022);\n-\t\t\tif (!wsi-\u003eu.h2.h2n)\n-\t\t\t\treturn 1;\n-\t\t}\n-\n-\t\tlws_h2_init(wsi);\n-\n-\t\t/* HTTP2 union */\n-\n-\t\tlws_h2_settings(wsi, \u0026wsi-\u003eu.h2.h2n-\u003eset,\n-\t\t\t\t(unsigned char *)protocol_list, n);\n-\n-\t\tlws_hpack_dynamic_size(wsi, wsi-\u003eu.h2.h2n-\u003eset.s[H2SET_HEADER_TABLE_SIZE]);\n-\n-\t\tstrcpy(protocol_list, \u0022HTTP/1.1 101 Switching Protocols\u005cx0d\u005cx0a\u0022\n-\t\t\t\t \u0022Connection: Upgrade\u005cx0d\u005cx0a\u0022\n-\t\t\t\t \u0022Upgrade: h2c\u005cx0d\u005cx0a\u005cx0d\u005cx0a\u0022);\n-\t\tn \u003d lws_issue_raw(wsi, (unsigned char *)protocol_list,\n-\t\t\t\t\tstrlen(protocol_list));\n-\t\tif (n !\u003d strlen(protocol_list)) {\n-\t\t\tlwsl_debug(\u0022http2 switch: ERROR writing to socket\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\twsi-\u003estate \u003d LWSS_HTTP2_AWAIT_CLIENT_PREFACE;\n-\n-\t\treturn 0;\n-#endif\n-\n-upgrade_ws:\n-\t\tif (!wsi-\u003eprotocol)\n-\t\t\tlwsl_err(\u0022NULL protocol at lws_read\u005cn\u0022);\n-\n-\t\t/*\n-\t\t * It's websocket\n-\t\t *\n-\t\t * Select the first protocol we support from the list\n-\t\t * the client sent us.\n-\t\t *\n-\t\t * Copy it to remove header fragmentation\n-\t\t */\n-\n-\t\tif (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1,\n-\t\t\t\t WSI_TOKEN_PROTOCOL) \u003c 0) {\n-\t\t\tlwsl_err(\u0022protocol list too long\u0022);\n-\t\t\tgoto bail_nuke_ah;\n-\t\t}\n-\n-\t\tprotocol_len \u003d lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);\n-\t\tprotocol_list[protocol_len] \u003d '\u005c0';\n-\t\tp \u003d protocol_list;\n-\t\thit \u003d 0;\n-\n-\t\twhile (*p \u0026\u0026 !hit) {\n-\t\t\tn \u003d 0;\n-\t\t\tnon_space_char_found \u003d 0;\n-\t\t\twhile (n \u003c sizeof(protocol_name) - 1 \u0026\u0026\n-\t\t\t *p \u0026\u0026 *p !\u003d ',') {\n-\t\t\t\t/* ignore leading spaces */\n-\t\t\t\tif (!non_space_char_found \u0026\u0026 *p \u003d\u003d ' ') {\n-\t\t\t\t\tn++;\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\t\t\t\tnon_space_char_found \u003d 1;\n-\t\t\t\tprotocol_name[n++] \u003d *p++;\n-\t\t\t}\n-\t\t\tprotocol_name[n] \u003d '\u005c0';\n-\t\t\tif (*p)\n-\t\t\t\tp++;\n-\n-\t\t\tlwsl_info(\u0022checking %s\u005cn\u0022, protocol_name);\n-\n-\t\t\tn \u003d 0;\n-\t\t\twhile (wsi-\u003evhost-\u003eprotocols[n].callback) {\n-\t\t\t\tlwsl_info(\u0022try %s\u005cn\u0022, wsi-\u003evhost-\u003eprotocols[n].name);\n-\n-\t\t\t\tif (wsi-\u003evhost-\u003eprotocols[n].name \u0026\u0026\n-\t\t\t\t !strcmp(wsi-\u003evhost-\u003eprotocols[n].name,\n-\t\t\t\t\t protocol_name)) {\n-\t\t\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[n];\n-\t\t\t\t\thit \u003d 1;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\n-\t\t\t\tn++;\n-\t\t\t}\n-\t\t}\n-\n-\t\t/* we didn't find a protocol he wanted? */\n-\n-\t\tif (!hit) {\n-\t\t\tif (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {\n-\t\t\t\tlwsl_info(\u0022No protocol from \u005c\u0022%s\u005c\u0022 supported\u005cn\u0022,\n-\t\t\t\t\t protocol_list);\n-\t\t\t\tgoto bail_nuke_ah;\n-\t\t\t}\n-\t\t\t/*\n-\t\t\t * some clients only have one protocol and\n-\t\t\t * do not send the protocol list header...\n-\t\t\t * allow it and match to the vhost's default\n-\t\t\t * protocol (which itself defaults to zero)\n-\t\t\t */\n-\t\t\tlwsl_info(\u0022defaulting to prot handler %d\u005cn\u0022,\n-\t\t\t\twsi-\u003evhost-\u003edefault_protocol_index);\n-\t\t\tn \u003d wsi-\u003evhost-\u003edefault_protocol_index;\n-\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[\n-\t\t\t\t (int)wsi-\u003evhost-\u003edefault_protocol_index];\n-\t\t}\n-\n-\t\t/* allocate wsi-\u003euser storage */\n-\t\tif (lws_ensure_user_space(wsi))\n-\t\t\tgoto bail_nuke_ah;\n-\n-\t\t/*\n-\t\t * Give the user code a chance to study the request and\n-\t\t * have the opportunity to deny it\n-\t\t */\n-\t\tif ((wsi-\u003eprotocol-\u003ecallback)(wsi,\n-\t\t\t\tLWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,\n-\t\t\t\twsi-\u003euser_space,\n-\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {\n-\t\t\tlwsl_warn(\u0022User code denied connection\u005cn\u0022);\n-\t\t\tgoto bail_nuke_ah;\n-\t\t}\n-\n-\t\t/*\n-\t\t * Perform the handshake according to the protocol version the\n-\t\t * client announced\n-\t\t */\n-\n-\t\tswitch (wsi-\u003eietf_spec_revision) {\n-\t\tcase 13:\n-\t\t\tlwsl_parser(\u0022lws_parse calling handshake_04\u005cn\u0022);\n-\t\t\tif (handshake_0405(context, wsi)) {\n-\t\t\t\tlwsl_info(\u0022hs0405 has failed the connection\u005cn\u0022);\n-\t\t\t\tgoto bail_nuke_ah;\n-\t\t\t}\n-\t\t\tbreak;\n-\n-\t\tdefault:\n-\t\t\tlwsl_info(\u0022Unknown client spec version %d\u005cn\u0022,\n-\t\t\t\t wsi-\u003eietf_spec_revision);\n-\t\t\tgoto bail_nuke_ah;\n-\t\t}\n-\n-\t\tlws_same_vh_protocol_insert(wsi, n);\n-\n-\t\t/* we are upgrading to ws, so http/1.1 and keepalive +\n-\t\t * pipelined header considerations about keeping the ah around\n-\t\t * no longer apply. However it's common for the first ws\n-\t\t * protocol data to have been coalesced with the browser\n-\t\t * upgrade request and to already be in the ah rx buffer.\n-\t\t */\n-\n-\t\tlwsl_info(\u0022%s: %p: inheriting ah in ws mode (rxpos:%d, rxlen:%d)\u005cn\u0022,\n-\t\t\t __func__, wsi, wsi-\u003eu.hdr.ah-\u003erxpos,\n-\t\t\t wsi-\u003eu.hdr.ah-\u003erxlen);\n-\t\tlws_pt_lock(pt);\n-\t\thdr \u003d wsi-\u003eu.hdr;\n-\n-\t\tlws_union_transition(wsi, LWSCM_WS_SERVING);\n-\t\t/*\n-\t\t * first service is WS mode will notice this, use the RX and\n-\t\t * then detach the ah (caution: we are not in u.hdr union\n-\t\t * mode any more then... ah_temp member is at start the same\n-\t\t * though)\n-\t\t *\n-\t\t * Because rxpos/rxlen shows something in the ah, we will get\n-\t\t * service guaranteed next time around the event loop\n-\t\t *\n-\t\t * All union members begin with hdr, so we can use it even\n-\t\t * though we transitioned to ws union mode (the ah detach\n-\t\t * code uses it anyway).\n-\t\t */\n-\t\twsi-\u003eu.hdr \u003d hdr;\n-\t\tlws_pt_unlock(pt);\n-\n-\t\tlws_server_init_wsi_for_ws(wsi);\n-\t\tlwsl_parser(\u0022accepted v%02d connection\u005cn\u0022,\n-\t\t\t wsi-\u003eietf_spec_revision);\n-\n-\t\t/* !!! drop ah unreservedly after ESTABLISHED */\n-\t\tif (!wsi-\u003emore_rx_waiting) {\n-\t\t\tlws_header_table_force_to_detachable_state(wsi);\n-\t\t\tlws_header_table_detach(wsi, 1);\n-\t\t}\n-\n-\t\treturn 0;\n-\t} /* while all chars are handled */\n-\n-\treturn 0;\n-\n-bail_nuke_ah:\n-\t/* drop the header info */\n-\t/* we're closing, losing some rx is OK */\n-\tlws_header_table_force_to_detachable_state(wsi);\n-\tlws_header_table_detach(wsi, 1);\n-\n-\treturn 1;\n-}\n-\n-#if defined(LWS_WITH_PEER_LIMITS)\n-\n-/* requires context-\u003elock */\n-static void\n-__lws_peer_remove_from_peer_wait_list(struct lws_context *context,\n-\t\t\t\t struct lws_peer *peer)\n-{\n-\tstruct lws_peer *df;\n-\n-\tlws_start_foreach_llp(struct lws_peer **, p, context-\u003epeer_wait_list) {\n-\t\tif (*p \u003d\u003d peer) {\n-\t\t\tdf \u003d *p;\n-\n-\t\t\t*p \u003d df-\u003epeer_wait_list;\n-\t\t\tdf-\u003epeer_wait_list \u003d NULL;\n-\n-\t\t\treturn;\n-\t\t}\n-\t} lws_end_foreach_llp(p, peer_wait_list);\n-}\n-\n-/* requires context-\u003elock */\n-static void\n-__lws_peer_add_to_peer_wait_list(struct lws_context *context,\n-\t\t\t\t struct lws_peer *peer)\n-{\n-\t__lws_peer_remove_from_peer_wait_list(context, peer);\n-\n-\tpeer-\u003epeer_wait_list \u003d context-\u003epeer_wait_list;\n-\tcontext-\u003epeer_wait_list \u003d peer;\n-}\n-\n-\n-static struct lws_peer *\n-lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd)\n-{\n-\tstruct lws_context *context \u003d vhost-\u003econtext;\n-\tsocklen_t rlen \u003d 0;\n-\tvoid *q;\n-\tuint8_t *q8;\n-\tstruct lws_peer *peer;\n-\tuint32_t hash \u003d 0;\n-\tint n, af \u003d AF_INET;\n-\tstruct sockaddr_storage addr;\n-\n-#ifdef LWS_WITH_IPV6\n-\tif (LWS_IPV6_ENABLED(vhost)) {\n-\t\taf \u003d AF_INET6;\n-\t}\n-#endif\n-\trlen \u003d sizeof(addr);\n-\tif (getpeername(sockfd, (struct sockaddr*)\u0026addr, \u0026rlen))\n-\t\treturn NULL;\n-\n-\tif (af \u003d\u003d AF_INET) {\n-\t\tstruct sockaddr_in *s \u003d (struct sockaddr_in *)\u0026addr;\n-\t\tq \u003d \u0026s-\u003esin_addr;\n-\t\trlen \u003d sizeof(s-\u003esin_addr);\n-\t} else\n-#ifdef LWS_WITH_IPV6\n-\t{\n-\t\tstruct sockaddr_in6 *s \u003d (struct sockaddr_in6 *)\u0026addr;\n-\t\tq \u003d \u0026s-\u003esin6_addr;\n-\t\trlen \u003d sizeof(s-\u003esin6_addr);\n-\t}\n-#else\n-\t\treturn NULL;\n-#endif\n-\n-\tq8 \u003d q;\n-\tfor (n \u003d 0; n \u003c rlen; n++)\n-\t\thash \u003d (((hash \u003c\u003c 4) | (hash \u003e\u003e 28)) * n) ^ q8[n];\n-\n-\thash \u003d hash % context-\u003epl_hash_elements;\n-\n-\tlws_context_lock(context); /* \u003c\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d */\n-\n-\tlws_start_foreach_ll(struct lws_peer *, peerx,\n-\t\t\t context-\u003epl_hash_table[hash]) {\n-\t\tif (peerx-\u003eaf \u003d\u003d af \u0026\u0026 !memcmp(q, peerx-\u003eaddr, rlen)) {\n-\t\t\tlws_context_unlock(context); /* \u003d\u003d\u003d */\n-\t\t\treturn peerx;\n-\t\t}\n-\t} lws_end_foreach_ll(peerx, next);\n-\n-\tlwsl_info(\u0022%s: creating new peer\u005cn\u0022, __func__);\n-\n-\tpeer \u003d lws_zalloc(sizeof(*peer), \u0022peer\u0022);\n-\tif (!peer) {\n-\t\tlws_context_unlock(context); /* \u003d\u003d\u003d */\n-\t\treturn NULL;\n-\t}\n-\n-\tcontext-\u003ecount_peers++;\n-\tpeer-\u003enext \u003d context-\u003epl_hash_table[hash];\n-\tpeer-\u003ehash \u003d hash;\n-\tpeer-\u003eaf \u003d af;\n-\tcontext-\u003epl_hash_table[hash] \u003d peer;\n-\tmemcpy(peer-\u003eaddr, q, rlen);\n-\ttime(\u0026peer-\u003etime_created);\n-\t/*\n-\t * On creation, the peer has no wsi attached, so is created on the\n-\t * wait list. When a wsi is added it is removed from the wait list.\n-\t */\n-\ttime(\u0026peer-\u003etime_closed_all);\n-\t__lws_peer_add_to_peer_wait_list(context, peer);\n-\n-\tlws_context_unlock(context); /* \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003e */\n-\n-\treturn peer;\n-}\n-\n-/* requires context-\u003elock */\n-static int\n-__lws_peer_destroy(struct lws_context *context, struct lws_peer *peer)\n-{\n-\tlws_start_foreach_llp(struct lws_peer **, p,\n-\t\t\t context-\u003epl_hash_table[peer-\u003ehash]) {\n-\t\tif (*p \u003d\u003d peer) {\n-\t\t\tstruct lws_peer *df \u003d *p;\n-\t\t\t*p \u003d df-\u003enext;\n-\t\t\tlws_free(df);\n-\t\t\tcontext-\u003ecount_peers--;\n-\n-\t\t\treturn 0;\n-\t\t}\n-\t} lws_end_foreach_llp(p, next);\n-\n-\treturn 1;\n-}\n-\n-void\n-lws_peer_cull_peer_wait_list(struct lws_context *context)\n-{\n-\tstruct lws_peer *df;\n-\ttime_t t;\n-\n-\ttime(\u0026t);\n-\n-\tif (context-\u003enext_cull \u0026\u0026 t \u003c context-\u003enext_cull)\n-\t\treturn;\n-\n-\tlws_context_lock(context); /* \u003c\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d */\n-\n-\tcontext-\u003enext_cull \u003d t + 5;\n-\n-\tlws_start_foreach_llp(struct lws_peer **, p, context-\u003epeer_wait_list) {\n-\t\tif (t - (*p)-\u003etime_closed_all \u003e 10) {\n-\t\t\tdf \u003d *p;\n-\n-\t\t\t/* remove us from the peer wait list */\n-\t\t\t*p \u003d df-\u003epeer_wait_list;\n-\t\t\tdf-\u003epeer_wait_list \u003d NULL;\n-\n-\t\t\t__lws_peer_destroy(context, df);\n-\t\t\tcontinue; /* we already point to next, if any */\n-\t\t}\n-\t} lws_end_foreach_llp(p, peer_wait_list);\n-\n-\tlws_context_unlock(context); /* \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003e */\n-}\n-\n-static void\n-lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,\n-\t\t struct lws *wsi)\n-{\n-\tif (!peer)\n-\t\treturn;\n-\n-\tlws_context_lock(context); /* \u003c\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d */\n-\n-\tpeer-\u003ecount_wsi++;\n-\twsi-\u003epeer \u003d peer;\n-\t__lws_peer_remove_from_peer_wait_list(context, peer);\n-\n-\tlws_context_unlock(context); /* \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003e */\n-}\n-\n-void\n-lws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer)\n-{\n-\tif (!peer)\n-\t\treturn;\n-\n-\tlws_context_lock(context); /* \u003c\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d */\n-\n-\tassert(peer-\u003ecount_wsi);\n-\tpeer-\u003ecount_wsi--;\n-\n-\tif (!peer-\u003ecount_wsi \u0026\u0026 !peer-\u003ecount_ah) {\n-\t\t/*\n-\t\t * in order that we can accumulate peer activity correctly\n-\t\t * allowing for periods when the peer has no connections,\n-\t\t * we don't synchronously destroy the peer when his last\n-\t\t * wsi closes. Instead we mark the time his last wsi\n-\t\t * closed and add him to a peer_wait_list to be reaped\n-\t\t * later if no further activity is coming.\n-\t\t */\n-\t\ttime(\u0026peer-\u003etime_closed_all);\n-\t\t__lws_peer_add_to_peer_wait_list(context, peer);\n-\t}\n-\n-\tlws_context_unlock(context); /* \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003e */\n-}\n-\n-int\n-lws_peer_confirm_ah_attach_ok(struct lws_context *context, struct lws_peer *peer)\n-{\n-\tif (!peer)\n-\t\treturn 0;\n-\n-\tif (context-\u003eip_limit_ah \u0026\u0026 peer-\u003ecount_ah \u003e\u003d context-\u003eip_limit_ah) {\n-\t\tlwsl_info(\u0022peer reached ah limit %d, deferring\u005cn\u0022,\n-\t\t\t\tcontext-\u003eip_limit_ah);\n-\n-\t\treturn 1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-void\n-lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer)\n-{\n-\tif (!peer)\n-\t\treturn;\n-\n-\tassert(peer-\u003ecount_ah);\n-\tpeer-\u003ecount_ah--;\n-}\n-\n-#endif\n-\n-static int\n-lws_get_idlest_tsi(struct lws_context *context)\n-{\n-\tunsigned int lowest \u003d ~0;\n-\tint n \u003d 0, hit \u003d -1;\n-\n-\tfor (; n \u003c context-\u003ecount_threads; n++) {\n-\t\tif ((unsigned int)context-\u003ept[n].fds_count !\u003d\n-\t\t context-\u003efd_limit_per_thread - 1 \u0026\u0026\n-\t\t (unsigned int)context-\u003ept[n].fds_count \u003c lowest) {\n-\t\t\tlowest \u003d context-\u003ept[n].fds_count;\n-\t\t\thit \u003d n;\n-\t\t}\n-\t}\n-\n-\treturn hit;\n-}\n-\n-struct lws *\n-lws_create_new_server_wsi(struct lws_vhost *vhost)\n-{\n-\tstruct lws *new_wsi;\n-\tint n \u003d lws_get_idlest_tsi(vhost-\u003econtext);\n-\n-\tif (n \u003c 0) {\n-\t\tlwsl_err(\u0022no space for new conn\u005cn\u0022);\n-\t\treturn NULL;\n-\t}\n-\n-\tnew_wsi \u003d lws_zalloc(sizeof(struct lws), \u0022new server wsi\u0022);\n-\tif (new_wsi \u003d\u003d NULL) {\n-\t\tlwsl_err(\u0022Out of memory for new connection\u005cn\u0022);\n-\t\treturn NULL;\n-\t}\n-\n-\tnew_wsi-\u003etsi \u003d n;\n-\tlwsl_debug(\u0022new wsi %p joining vhost %s, tsi %d\u005cn\u0022, new_wsi,\n-\t\t vhost-\u003ename, new_wsi-\u003etsi);\n-\n-\tnew_wsi-\u003evhost \u003d vhost;\n-\tnew_wsi-\u003econtext \u003d vhost-\u003econtext;\n-\tnew_wsi-\u003epending_timeout \u003d NO_PENDING_TIMEOUT;\n-\tnew_wsi-\u003erxflow_change_to \u003d LWS_RXFLOW_ALLOW;\n-\n-\t/* initialize the instance struct */\n-\n-\tnew_wsi-\u003estate \u003d LWSS_HTTP;\n-\tnew_wsi-\u003emode \u003d LWSCM_HTTP_SERVING;\n-\tnew_wsi-\u003ehdr_parsing_completed \u003d 0;\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\tnew_wsi-\u003euse_ssl \u003d LWS_SSL_ENABLED(vhost);\n-#endif\n-\n-\t/*\n-\t * these can only be set once the protocol is known\n-\t * we set an un-established connection's protocol pointer\n-\t * to the start of the supported list, so it can look\n-\t * for matching ones during the handshake\n-\t */\n-\tnew_wsi-\u003eprotocol \u003d vhost-\u003eprotocols;\n-\tnew_wsi-\u003euser_space \u003d NULL;\n-\tnew_wsi-\u003eietf_spec_revision \u003d 0;\n-\tnew_wsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n-\tnew_wsi-\u003eposition_in_fds_table \u003d -1;\n-\n-\tvhost-\u003econtext-\u003ecount_wsi_allocated++;\n-\n-\t/*\n-\t * outermost create notification for wsi\n-\t * no user_space because no protocol selection\n-\t */\n-\tvhost-\u003eprotocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE,\n-\t\t\t\t NULL, NULL, 0);\n-\n-\treturn new_wsi;\n-}\n-\n-LWS_VISIBLE int LWS_WARN_UNUSED_RESULT\n-lws_http_transaction_completed(struct lws *wsi)\n-{\n-\tint n \u003d NO_PENDING_TIMEOUT;\n-\n-\tlwsl_info(\u0022%s: wsi %p\u005cn\u0022, __func__, wsi);\n-\n-\tlws_access_log(wsi);\n-\n-\tif (!wsi-\u003ehdr_parsing_completed) {\n-\t\tlwsl_notice(\u0022%s: ignoring, ah parsing incomplete\u005cn\u0022, __func__);\n-\t\treturn 0;\n-\t}\n-\n-\tlwsl_debug(\u0022%s: wsi %p\u005cn\u0022, __func__, wsi);\n-\t/* if we can't go back to accept new headers, drop the connection */\n-\tif (wsi-\u003ehttp2_substream)\n-\t\treturn 0;\n-\n-\tif (wsi-\u003eseen_zero_length_recv)\n-\t\treturn 1;\n-\n-\tif (wsi-\u003eu.http.connection_type !\u003d HTTP_CONNECTION_KEEP_ALIVE) {\n-\t\tlwsl_info(\u0022%s: %p: close connection\u005cn\u0022, __func__, wsi);\n-\t\treturn 1;\n-\t}\n-\n-\tif (lws_bind_protocol(wsi, \u0026wsi-\u003evhost-\u003eprotocols[0]))\n-\t\treturn 1;\n-\n-\t/* otherwise set ourselves up ready to go again */\n-\twsi-\u003estate \u003d LWSS_HTTP;\n-\twsi-\u003emode \u003d LWSCM_HTTP_SERVING;\n-\twsi-\u003eu.http.tx_content_length \u003d 0;\n-\twsi-\u003eu.http.tx_content_remain \u003d 0;\n-\twsi-\u003ehdr_parsing_completed \u003d 0;\n-#ifdef LWS_WITH_ACCESS_LOG\n-\twsi-\u003eaccess_log.sent \u003d 0;\n-#endif\n-\n-\tif (wsi-\u003evhost-\u003ekeepalive_timeout)\n-\t\tn \u003d PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE;\n-\tlws_set_timeout(wsi, n, wsi-\u003evhost-\u003ekeepalive_timeout);\n-\n-\t/*\n-\t * We already know we are on http1.1 / keepalive and the next thing\n-\t * coming will be another header set.\n-\t *\n-\t * If there is no pending rx and we still have the ah, drop it and\n-\t * reacquire a new ah when the new headers start to arrive. (Otherwise\n-\t * we needlessly hog an ah indefinitely.)\n-\t *\n-\t * However if there is pending rx and we know from the keepalive state\n-\t * that is already at least the start of another header set, simply\n-\t * reset the existing header table and keep it.\n-\t */\n-\tif (wsi-\u003eu.hdr.ah) {\n-\t\tlwsl_debug(\u0022%s: wsi-\u003emore_rx_waiting\u003d%d\u005cn\u0022, __func__,\n-\t\t\t\twsi-\u003emore_rx_waiting);\n-\n-\t\tif (!wsi-\u003emore_rx_waiting) {\n-\t\t\tlws_header_table_force_to_detachable_state(wsi);\n-\t\t\tlws_header_table_detach(wsi, 1);\n-#ifdef LWS_OPENSSL_SUPPORT\n-\t\t\t/*\n-\t\t\t * additionally... if we are hogging an SSL instance\n-\t\t\t * with no pending pipelined headers (or ah now), and\n-\t\t\t * SSL is scarce, drop this connection without waiting\n-\t\t\t */\n-\n-\t\t\tif (wsi-\u003evhost-\u003euse_ssl \u0026\u0026\n-\t\t\t wsi-\u003econtext-\u003esimultaneous_ssl_restriction \u0026\u0026\n-\t\t\t wsi-\u003econtext-\u003esimultaneous_ssl \u003d\u003d\n-\t\t\t\t wsi-\u003econtext-\u003esimultaneous_ssl_restriction) {\n-\t\t\t\tlwsl_info(\u0022%s: simultaneous_ssl_restriction and nothing pipelined\u005cn\u0022, __func__);\n-\t\t\t\treturn 1;\n-\t\t\t}\n-#endif\n-\t\t} else {\n-\t\t\tlws_header_table_reset(wsi, 1);\n-\t\t\t/*\n-\t\t\t * If we kept the ah, we should restrict the amount\n-\t\t\t * of time we are willing to keep it. Otherwise it\n-\t\t\t * will be bound the whole time the connection remains\n-\t\t\t * open.\n-\t\t\t */\n-\t\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,\n-\t\t\t\t\twsi-\u003evhost-\u003ekeepalive_timeout);\n-\t\t}\n-\t}\n-\n-\t/* If we're (re)starting on headers, need other implied init */\n-\twsi-\u003eu.hdr.ues \u003d URIES_IDLE;\n-\n-\tlwsl_info(\u0022%s: %p: keep-alive await new transaction\u005cn\u0022, __func__, wsi);\n-\n-\treturn 0;\n-}\n-\n-/* if not a socket, it's a raw, non-ssl file descriptor */\n-\n-LWS_VISIBLE struct lws *\n-lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,\n-\t\t\t lws_sock_file_fd_type fd, const char *vh_prot_name,\n-\t\t\t struct lws *parent)\n-{\n-\tstruct lws_context *context \u003d vh-\u003econtext;\n-\tstruct lws *new_wsi;\n-\tstruct lws_context_per_thread *pt;\n-\tint n, ssl \u003d 0;\n-\n-#if defined(LWS_WITH_PEER_LIMITS)\n-\tstruct lws_peer *peer \u003d NULL;\n-\n-\tif (type \u0026 LWS_ADOPT_SOCKET \u0026\u0026 !(type \u0026 LWS_ADOPT_WS_PARENTIO)) {\n-\t\tpeer \u003d lws_get_or_create_peer(vh, fd.sockfd);\n-\n-\t\tif (!peer) {\n-\t\t\tlwsl_err(\u0022OOM creating peer\u005cn\u0022);\n-\t\t\treturn NULL;\n-\t\t}\n-\t\tif (context-\u003eip_limit_wsi \u0026\u0026\n-\t\t peer-\u003ecount_wsi \u003e\u003d context-\u003eip_limit_wsi) {\n-\t\t\tlwsl_notice(\u0022Peer reached wsi limit %d\u005cn\u0022,\n-\t\t\t\t\tcontext-\u003eip_limit_wsi);\n-\t\t\tlws_stats_atomic_bump(context, \u0026context-\u003ept[0],\n-\t\t\t\t\t LWSSTATS_C_PEER_LIMIT_WSI_DENIED, 1);\n-\t\t\treturn NULL;\n-\t\t}\n-\t}\n-#endif\n-\n-\tnew_wsi \u003d lws_create_new_server_wsi(vh);\n-\tif (!new_wsi) {\n-\t\tif (type \u0026 LWS_ADOPT_SOCKET \u0026\u0026 !(type \u0026 LWS_ADOPT_WS_PARENTIO))\n-\t\t\tcompatible_close(fd.sockfd);\n-\t\treturn NULL;\n-\t}\n-#if defined(LWS_WITH_PEER_LIMITS)\n-\tif (peer)\n-\t\tlws_peer_add_wsi(context, peer, new_wsi);\n-#endif\n-\tpt \u003d \u0026context-\u003ept[(int)new_wsi-\u003etsi];\n-\tlws_stats_atomic_bump(context, pt, LWSSTATS_C_CONNECTIONS, 1);\n-\n-\tif (parent) {\n-\t\tnew_wsi-\u003eparent \u003d parent;\n-\t\tnew_wsi-\u003esibling_list \u003d parent-\u003echild_list;\n-\t\tparent-\u003echild_list \u003d new_wsi;\n-\n-\t\tif (type \u0026 LWS_ADOPT_WS_PARENTIO)\n-\t\t\tnew_wsi-\u003eparent_carries_io \u003d 1;\n-\t}\n-\n-\tnew_wsi-\u003edesc \u003d fd;\n-\n-\tif (vh_prot_name) {\n-\t\tnew_wsi-\u003eprotocol \u003d lws_vhost_name_to_protocol(new_wsi-\u003evhost,\n-\t\t\t\t\t\t\t vh_prot_name);\n-\t\tif (!new_wsi-\u003eprotocol) {\n-\t\t\tlwsl_err(\u0022Protocol %s not enabled on vhost %s\u005cn\u0022,\n-\t\t\t\t vh_prot_name, new_wsi-\u003evhost-\u003ename);\n-\t\t\tgoto bail;\n-\t\t}\n- if (lws_ensure_user_space(new_wsi)) {\n- lwsl_notice(\u0022OOM trying to get user_space\u005cn\u0022);\n-\t\t\tgoto bail;\n- }\n- if (type \u0026 LWS_ADOPT_WS_PARENTIO) {\n-\t\t\tnew_wsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n-\t\t\tlwsl_debug(\u0022binding to %s\u005cn\u0022, new_wsi-\u003eprotocol-\u003ename);\n-\t\t\tlws_bind_protocol(new_wsi, new_wsi-\u003eprotocol);\n-\t\t\tlws_union_transition(new_wsi, LWSCM_WS_SERVING);\n-\t\t\tlws_server_init_wsi_for_ws(new_wsi);\n-\n-\t\t\treturn new_wsi;\n- }\n-\t} else\n-\t\tif (type \u0026 LWS_ADOPT_HTTP) /* he will transition later */\n-\t\t\tnew_wsi-\u003eprotocol \u003d\n-\t\t\t\t\u0026vh-\u003eprotocols[vh-\u003edefault_protocol_index];\n-\t\telse { /* this is the only time he will transition */\n-\t\t\tlws_bind_protocol(new_wsi,\n-\t\t\t\t\u0026vh-\u003eprotocols[vh-\u003eraw_protocol_index]);\n-\t\t\tlws_union_transition(new_wsi, LWSCM_RAW);\n-\t\t}\n-\n-\tif (type \u0026 LWS_ADOPT_SOCKET) { /* socket desc */\n-\t\tlwsl_debug(\u0022%s: new wsi %p, sockfd %d\u005cn\u0022, __func__, new_wsi,\n-\t\t\t (int)(lws_intptr_t)fd.sockfd);\n-\n-\t\tif (type \u0026 LWS_ADOPT_HTTP)\n-\t\t\t/* the transport is accepted...\n-\t\t\t * give him time to negotiate */\n-\t\t\tlws_set_timeout(new_wsi,\n-\t\t\t\t\tPENDING_TIMEOUT_ESTABLISH_WITH_SERVER,\n-\t\t\t\t\tcontext-\u003etimeout_secs);\n-\n-#if LWS_POSIX \u003d\u003d 0\n-#if defined(LWS_WITH_ESP8266)\n-\t\tesp8266_tcp_stream_accept(accept_fd, new_wsi);\n-#endif\n-#endif\n-\t} else /* file desc */\n-\t\tlwsl_debug(\u0022%s: new wsi %p, filefd %d\u005cn\u0022, __func__, new_wsi,\n-\t\t\t (int)(lws_intptr_t)fd.filefd);\n-\n-\t/*\n-\t * A new connection was accepted. Give the user a chance to\n-\t * set properties of the newly created wsi. There's no protocol\n-\t * selected yet so we issue this to the vhosts's default protocol,\n-\t * itself by default protocols[0]\n-\t */\n-\tn \u003d LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;\n-\tif (!(type \u0026 LWS_ADOPT_HTTP)) {\n-\t\tif (!(type \u0026 LWS_ADOPT_SOCKET))\n-\t\t\tn \u003d LWS_CALLBACK_RAW_ADOPT_FILE;\n-\t\telse\n-\t\t\tn \u003d LWS_CALLBACK_RAW_ADOPT;\n-\t}\n-\n-\tif (!LWS_SSL_ENABLED(new_wsi-\u003evhost) || !(type \u0026 LWS_ADOPT_ALLOW_SSL) ||\n-\t !(type \u0026 LWS_ADOPT_SOCKET)) {\n-\t\t/* non-SSL */\n-\t\tif (!(type \u0026 LWS_ADOPT_HTTP)) {\n-\t\t\tif (!(type \u0026 LWS_ADOPT_SOCKET))\n-\t\t\t\tnew_wsi-\u003emode \u003d LWSCM_RAW_FILEDESC;\n-\t\t\telse\n-\t\t\t\tnew_wsi-\u003emode \u003d LWSCM_RAW;\n-\t\t}\n-\t} else {\n-\t\t/* SSL */\n-\t\tif (!(type \u0026 LWS_ADOPT_HTTP))\n-\t\t\tnew_wsi-\u003emode \u003d LWSCM_SSL_INIT_RAW;\n-\t\telse\n-\t\t\tnew_wsi-\u003emode \u003d LWSCM_SSL_INIT;\n-\n-\t\tssl \u003d 1;\n-\t}\n-\n-\tlws_libev_accept(new_wsi, new_wsi-\u003edesc);\n-\tlws_libuv_accept(new_wsi, new_wsi-\u003edesc);\n-\tlws_libevent_accept(new_wsi, new_wsi-\u003edesc);\n-\n-\tif (!ssl) {\n-\t\tif (insert_wsi_socket_into_fds(context, new_wsi)) {\n-\t\t\tlwsl_err(\u0022%s: fail inserting socket\u005cn\u0022, __func__);\n-\t\t\tgoto fail;\n-\t\t}\n-\t} else\n-\t\tif (lws_server_socket_service_ssl(new_wsi, fd.sockfd)) {\n-\t\t\tlwsl_info(\u0022%s: fail ssl negotiation\u005cn\u0022, __func__);\n-\t\t\tgoto fail;\n-\t\t}\n-\n-\t/*\n-\t * by deferring callback to this point, after insertion to fds,\n-\t * lws_callback_on_writable() can work from the callback\n-\t */\n-\tif ((new_wsi-\u003eprotocol-\u003ecallback)(\n-\t\t\tnew_wsi, n, new_wsi-\u003euser_space, NULL, 0))\n-\t\tgoto fail;\n-\n-\tif (type \u0026 LWS_ADOPT_HTTP) {\n-\t\tif (!lws_header_table_attach(new_wsi, 0))\n-\t\t\tlwsl_debug(\u0022Attached ah immediately\u005cn\u0022);\n-\t\telse\n-\t\t\tlwsl_info(\u0022%s: waiting for ah\u005cn\u0022, __func__);\n-\t}\n-\n-\treturn new_wsi;\n-\n-fail:\n-\tif (type \u0026 LWS_ADOPT_SOCKET)\n-\t\tlws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\n-\treturn NULL;\n-\n-bail:\n- lwsl_notice(\u0022%s: exiting on bail\u005cn\u0022, __func__);\n-\tif (parent)\n-\t\tparent-\u003echild_list \u003d new_wsi-\u003esibling_list;\n-\tif (new_wsi-\u003euser_space)\n-\t\tlws_free(new_wsi-\u003euser_space);\n-\tlws_free(new_wsi);\n- compatible_close(fd.sockfd);\n-\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE struct lws *\n-lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)\n-{\n-\tlws_sock_file_fd_type fd;\n-\n-\tfd.sockfd \u003d accept_fd;\n-\treturn lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |\n-\t\t\tLWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);\n-}\n-\n-LWS_VISIBLE struct lws *\n-lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)\n-{\n-\treturn lws_adopt_socket_vhost(context-\u003evhost_list, accept_fd);\n-}\n-\n-/* Common read-buffer adoption for lws_adopt_*_readbuf */\n-static struct lws*\n-adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)\n-{\n-\tstruct lws_context_per_thread *pt;\n-\tstruct allocated_headers *ah;\n-\tstruct lws_pollfd *pfd;\n-\n-\tif (!wsi)\n-\t\treturn NULL;\n-\n-\tif (!readbuf || len \u003d\u003d 0)\n-\t\treturn wsi;\n-\n-\tif (len \u003e sizeof(ah-\u003erx)) {\n-\t\tlwsl_err(\u0022%s: rx in too big\u005cn\u0022, __func__);\n-\t\tgoto bail;\n-\t}\n-\n-\t/*\n-\t * we can't process the initial read data until we can attach an ah.\n-\t *\n-\t * if one is available, get it and place the data in his ah rxbuf...\n-\t * wsi with ah that have pending rxbuf get auto-POLLIN service.\n-\t *\n-\t * no autoservice because we didn't get a chance to attach the\n-\t * readbuf data to wsi or ah yet, and we will do it next if we get\n-\t * the ah.\n-\t */\n-\tif (wsi-\u003eu.hdr.ah || !lws_header_table_attach(wsi, 0)) {\n-\t\tah \u003d wsi-\u003eu.hdr.ah;\n-\t\tmemcpy(ah-\u003erx, readbuf, len);\n-\t\tah-\u003erxpos \u003d 0;\n-\t\tah-\u003erxlen \u003d (int16_t)len;\n-\n-\t\tlwsl_notice(\u0022%s: calling service on readbuf ah\u005cn\u0022, __func__);\n-\t\tpt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\n-\t\t/* unlike a normal connect, we have the headers already\n-\t\t * (or the first part of them anyway).\n-\t\t * libuv won't come back and service us without a network\n-\t\t * event, so we need to do the header service right here.\n-\t\t */\n-\t\tpfd \u003d \u0026pt-\u003efds[wsi-\u003eposition_in_fds_table];\n-\t\tpfd-\u003erevents |\u003d LWS_POLLIN;\n-\t\tlwsl_err(\u0022%s: calling service\u005cn\u0022, __func__);\n-\t\tif (lws_service_fd_tsi(wsi-\u003econtext, pfd, wsi-\u003etsi))\n-\t\t\t/* service closed us */\n-\t\t\treturn NULL;\n-\n-\t\treturn wsi;\n-\t}\n-\tlwsl_err(\u0022%s: deferring handling ah\u005cn\u0022, __func__);\n-\t/*\n-\t * hum if no ah came, we are on the wait list and must defer\n-\t * dealing with this until the ah arrives.\n-\t *\n-\t * later successful lws_header_table_attach() will apply the\n-\t * below to the rx buffer (via lws_header_table_reset()).\n-\t */\n-\twsi-\u003eu.hdr.preamble_rx \u003d lws_malloc(len, \u0022preamble_rx\u0022);\n-\tif (!wsi-\u003eu.hdr.preamble_rx) {\n-\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n-\t\tgoto bail;\n-\t}\n-\tmemcpy(wsi-\u003eu.hdr.preamble_rx, readbuf, len);\n-\twsi-\u003eu.hdr.preamble_rx_len \u003d len;\n-\n-\treturn wsi;\n-\n-bail:\n-\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE struct lws *\n-lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,\n-\t\t\t const char *readbuf, size_t len)\n-{\n- return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd), readbuf, len);\n-}\n-\n-LWS_VISIBLE struct lws *\n-lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost, lws_sockfd_type accept_fd,\n-\t\t\t const char *readbuf, size_t len)\n-{\n- return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd), readbuf, len);\n-}\n-\n-LWS_VISIBLE int\n-lws_server_socket_service(struct lws_context *context, struct lws *wsi,\n-\t\t\t struct lws_pollfd *pollfd)\n-{\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tlws_sockfd_type accept_fd \u003d LWS_SOCK_INVALID;\n-\tstruct allocated_headers *ah;\n-\tlws_sock_file_fd_type fd;\n-\tint opts \u003d LWS_ADOPT_SOCKET | LWS_ADOPT_ALLOW_SSL;\n-#if LWS_POSIX\n-\tstruct sockaddr_storage cli_addr;\n-\tsocklen_t clilen;\n-#endif\n-\tint n, len;\n-\n-\tswitch (wsi-\u003emode) {\n-\n-\tcase LWSCM_HTTP_SERVING:\n-\tcase LWSCM_HTTP_SERVING_ACCEPTED:\n-\tcase LWSCM_HTTP2_SERVING:\n-\tcase LWSCM_RAW:\n-\n-\t\t/* handle http headers coming in */\n-\n-\t\t/* pending truncated sends have uber priority */\n-\n-\t\tif (wsi-\u003etrunc_len) {\n-\t\t\tif (!(pollfd-\u003erevents \u0026 LWS_POLLOUT))\n-\t\t\t\tbreak;\n-\n-\t\t\tif (lws_issue_raw(wsi, wsi-\u003etrunc_alloc +\n-\t\t\t\t\t wsi-\u003etrunc_offset,\n-\t\t\t\t\t wsi-\u003etrunc_len) \u003c 0)\n-\t\t\t\tgoto fail;\n-\t\t\t/*\n-\t\t\t * we can't afford to allow input processing to send\n-\t\t\t * something new, so spin around he event loop until\n-\t\t\t * he doesn't have any partials\n-\t\t\t */\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\t/* any incoming data ready? */\n-\n-\t\tif (!(pollfd-\u003erevents \u0026 pollfd-\u003eevents \u0026 LWS_POLLIN))\n-\t\t\tgoto try_pollout;\n-\n-\t\t/*\n-\t\t * If we previously just did POLLIN when IN and OUT were\n-\t\t * signalled (because POLLIN processing may have used up\n-\t\t * the POLLOUT), don't let that happen twice in a row...\n-\t\t * next time we see the situation favour POLLOUT\n-\t\t */\n-#if !defined(LWS_WITH_ESP8266)\n-\t\tif (wsi-\u003efavoured_pollin \u0026\u0026\n-\t\t (pollfd-\u003erevents \u0026 pollfd-\u003eevents \u0026 LWS_POLLOUT)) {\n-\t\t\tlwsl_notice(\u0022favouring pollout\u005cn\u0022);\n-\t\t\twsi-\u003efavoured_pollin \u003d 0;\n-\t\t\tgoto try_pollout;\n-\t\t}\n-#endif\n-\n-\t\t/* these states imply we MUST have an ah attached */\n-\n-\t\tif (wsi-\u003emode !\u003d LWSCM_RAW \u0026\u0026 (wsi-\u003estate \u003d\u003d LWSS_HTTP ||\n-\t\t wsi-\u003estate \u003d\u003d LWSS_HTTP_ISSUING_FILE ||\n-\t\t wsi-\u003estate \u003d\u003d LWSS_HTTP_HEADERS)) {\n-\t\t\tif (!wsi-\u003eu.hdr.ah) {\n-\t\t\t\t/* no autoservice beacuse we will do it next */\n-\t\t\t\tif (lws_header_table_attach(wsi, 0)) {\n-\t\t\t\t\tlwsl_info(\u0022wsi %p: failed to acquire ah\u005cn\u0022, wsi);\n-\t\t\t\t\tgoto try_pollout;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tah \u003d wsi-\u003eu.hdr.ah;\n-\n-\t\t\t/* if nothing in ah rx buffer, get some fresh rx */\n-\t\t\tif (ah-\u003erxpos \u003d\u003d ah-\u003erxlen) {\n-\t\t\t\tah-\u003erxlen \u003d lws_ssl_capable_read(wsi, ah-\u003erx,\n-\t\t\t\t\t\t sizeof(ah-\u003erx));\n-\t\t\t\tah-\u003erxpos \u003d 0;\n-\t\t\t\tswitch (ah-\u003erxlen) {\n-\t\t\t\tcase 0:\n-\t\t\t\t\tlwsl_info(\u0022%s: read 0 len a\u005cn\u0022, __func__);\n-\t\t\t\t\twsi-\u003eseen_zero_length_recv \u003d 1;\n-\t\t\t\t\tlws_change_pollfd(wsi, LWS_POLLIN, 0);\n-\t\t\t\t\tgoto try_pollout;\n-\t\t\t\t\t/* fallthru */\n-\t\t\t\tcase LWS_SSL_CAPABLE_ERROR:\n-\t\t\t\t\tgoto fail;\n-\t\t\t\tcase LWS_SSL_CAPABLE_MORE_SERVICE:\n-\t\t\t\t\tah-\u003erxlen \u003d ah-\u003erxpos \u003d 0;\n-\t\t\t\t\tgoto try_pollout;\n-\t\t\t\t}\n-\n-\t\t\t\t/*\n-\t\t\t\t * make sure ah does not get detached if we\n-\t\t\t\t * have live data in the rx\n-\t\t\t\t */\n-\t\t\t\tif (ah-\u003erxlen)\n-\t\t\t\t\twsi-\u003emore_rx_waiting \u003d 1;\n-\t\t\t}\n-\n-\t\t\tif (!(ah-\u003erxpos !\u003d ah-\u003erxlen \u0026\u0026 ah-\u003erxlen)) {\n-\t\t\t\tlwsl_err(\u0022%s: assert: rxpos %d, rxlen %d\u005cn\u0022,\n-\t\t\t\t\t __func__, ah-\u003erxpos, ah-\u003erxlen);\n-\n-\t\t\t\tassert(0);\n-\t\t\t}\n-\t\t\t\n-\t\t\t/* just ignore incoming if waiting for close */\n-\t\t\tif (wsi-\u003estate !\u003d LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE \u0026\u0026\n-\t\t\t wsi-\u003estate !\u003d LWSS_HTTP_ISSUING_FILE) {\n-\t\t\t\t/*\n-\t\t\t\t * otherwise give it to whoever wants it\n-\t\t\t\t * according to the connection state\n-\t\t\t\t */\n-\n-\t\t\t\tn \u003d lws_read(wsi, ah-\u003erx + ah-\u003erxpos,\n-\t\t\t\t\t ah-\u003erxlen - ah-\u003erxpos);\n-\t\t\t\tif (n \u003c 0) /* we closed wsi */\n-\t\t\t\t\treturn 1;\n-\n-\t\t\t\tif (!wsi-\u003eu.hdr.ah)\n-\t\t\t\t\tbreak;\n-\t\t\t\tif ( wsi-\u003eu.hdr.ah-\u003erxlen)\n-\t\t\t\t\t wsi-\u003eu.hdr.ah-\u003erxpos +\u003d n;\n-\n-\t\t\t\tlwsl_debug(\u0022%s: wsi %p: ah read rxpos %d, rxlen %d\u005cn\u0022,\n-\t\t\t\t\t __func__, wsi, wsi-\u003eu.hdr.ah-\u003erxpos,\n-\t\t\t\t\t wsi-\u003eu.hdr.ah-\u003erxlen);\n-\n-\t\t\t\tif (lws_header_table_is_in_detachable_state(wsi) \u0026\u0026\n-\t\t\t\t (wsi-\u003emode !\u003d LWSCM_HTTP_SERVING \u0026\u0026\n-\t\t\t\t wsi-\u003emode !\u003d LWSCM_HTTP_SERVING_ACCEPTED \u0026\u0026\n-\t\t\t\t wsi-\u003emode !\u003d LWSCM_HTTP2_SERVING))\n-\t\t\t\t\tlws_header_table_detach(wsi, 1);\n-\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\t\tgoto try_pollout;\n-\t\t}\n-\n-\t\tlen \u003d lws_ssl_capable_read(wsi, pt-\u003eserv_buf,\n-\t\t\t\t\t context-\u003ept_serv_buf_size);\n-\t\tlwsl_debug(\u0022%s: wsi %p read %d\u005cr\u005cn\u0022, __func__, wsi, len);\n-\t\tswitch (len) {\n-\t\tcase 0:\n-\t\t\tlwsl_info(\u0022%s: read 0 len b\u005cn\u0022, __func__);\n-\n-\t\t\t/* fallthru */\n-\t\tcase LWS_SSL_CAPABLE_ERROR:\n-\t\t\tgoto fail;\n-\t\tcase LWS_SSL_CAPABLE_MORE_SERVICE:\n-\t\t\tgoto try_pollout;\n-\t\t}\n-\t\t\n-\t\tif (wsi-\u003emode \u003d\u003d LWSCM_RAW) {\n-\t\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback,\n-\t\t\t\t\twsi, LWS_CALLBACK_RAW_RX,\n-\t\t\t\t\twsi-\u003euser_space, pt-\u003eserv_buf, len);\n-\t\t\tif (n \u003c 0) {\n-\t\t\t\tlwsl_info(\u0022LWS_CALLBACK_RAW_RX_fail\u005cn\u0022);\n-\t\t\t\tgoto fail;\n-\t\t\t}\n-\t\t\tgoto try_pollout;\n-\t\t}\n-\n-\t\t/* just ignore incoming if waiting for close */\n-\t\tif (wsi-\u003estate !\u003d LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE \u0026\u0026\n-\t\t wsi-\u003estate !\u003d LWSS_HTTP_ISSUING_FILE) {\n-\t\t\t/*\n-\t\t\t * this may want to send\n-\t\t\t * (via HTTP callback for example)\n-\t\t\t */\n-\t\t\tn \u003d lws_read(wsi, pt-\u003eserv_buf, len);\n-\t\t\tif (n \u003c 0) /* we closed wsi */\n-\t\t\t\treturn 1;\n-\t\t\t/*\n-\t\t\t * he may have used up the\n-\t\t\t * writability above, if we will defer POLLOUT\n-\t\t\t * processing in favour of POLLIN, note it\n-\t\t\t */\n-\t\t\tif (pollfd-\u003erevents \u0026 LWS_POLLOUT)\n-\t\t\t\twsi-\u003efavoured_pollin \u003d 1;\n-\t\t\tbreak;\n-\t\t}\n-\t\t/*\n-\t\t * he may have used up the\n-\t\t * writability above, if we will defer POLLOUT\n-\t\t * processing in favour of POLLIN, note it\n-\t\t */\n-\t\tif (pollfd-\u003erevents \u0026 LWS_POLLOUT)\n-\t\t\twsi-\u003efavoured_pollin \u003d 1;\n-\n-try_pollout:\n-\t\t\n-\t\t/* this handles POLLOUT for http serving fragments */\n-\n-\t\tif (!(pollfd-\u003erevents \u0026 LWS_POLLOUT))\n-\t\t\tbreak;\n-\n-\t\t/* one shot */\n-\t\tif (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {\n-\t\t\tlwsl_notice(\u0022%s a\u005cn\u0022, __func__);\n-\t\t\tgoto fail;\n-\t\t}\n-\n-\t\tif (wsi-\u003emode \u003d\u003d LWSCM_RAW) {\n-\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt, LWSSTATS_C_WRITEABLE_CB, 1);\n-#if defined(LWS_WITH_STATS)\n-\t\t\tif (wsi-\u003eactive_writable_req_us) {\n-\t\t\t\tuint64_t ul \u003d time_in_microseconds() - wsi-\u003eactive_writable_req_us;\n-\n-\t\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);\n-\t\t\t\tlws_stats_atomic_max(wsi-\u003econtext, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);\n-\t\t\t\twsi-\u003eactive_writable_req_us \u003d 0;\n-\t\t\t}\n-#endif\n-\t\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback,\n-\t\t\t\t\twsi, LWS_CALLBACK_RAW_WRITEABLE,\n-\t\t\t\t\twsi-\u003euser_space, NULL, 0);\n-\t\t\tif (n \u003c 0) {\n-\t\t\t\tlwsl_info(\u0022writeable_fail\u005cn\u0022);\n-\t\t\t\tgoto fail;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (!wsi-\u003ehdr_parsing_completed)\n-\t\t\tbreak;\n-\n-\t\tif (wsi-\u003estate !\u003d LWSS_HTTP_ISSUING_FILE) {\n-\n-\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt, LWSSTATS_C_WRITEABLE_CB, 1);\n-#if defined(LWS_WITH_STATS)\n-\t\t\tif (wsi-\u003eactive_writable_req_us) {\n-\t\t\t\tuint64_t ul \u003d time_in_microseconds() - wsi-\u003eactive_writable_req_us;\n-\n-\t\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);\n-\t\t\t\tlws_stats_atomic_max(wsi-\u003econtext, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);\n-\t\t\t\twsi-\u003eactive_writable_req_us \u003d 0;\n-\t\t\t}\n-#endif\n-\n-\t\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback,\n-\t\t\t\t\twsi, LWS_CALLBACK_HTTP_WRITEABLE,\n-\t\t\t\t\twsi-\u003euser_space, NULL, 0);\n-\t\t\tif (n \u003c 0) {\n-\t\t\t\tlwsl_info(\u0022writeable_fail\u005cn\u0022);\n-\t\t\t\tgoto fail;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\t/* \u003e0 \u003d\u003d completion, \u003c0 \u003d\u003d error\n-\t\t *\n-\t\t * We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when\n-\t\t * it's done. That's the case even if we just completed the\n-\t\t * send, so wait for that.\n-\t\t */\n-\t\tn \u003d lws_serve_http_file_fragment(wsi);\n-\t\tif (n \u003c 0)\n-\t\t\tgoto fail;\n-\n-\t\tbreak;\n-\n-\tcase LWSCM_SERVER_LISTENER:\n-\n-#if LWS_POSIX\n-\t\t/* pollin means a client has connected to us then */\n-\n-\t\tdo {\n-\t\t\tif (!(pollfd-\u003erevents \u0026 LWS_POLLIN) || !(pollfd-\u003eevents \u0026 LWS_POLLIN))\n-\t\t\t\tbreak;\n-\n-#ifdef LWS_OPENSSL_SUPPORT\n-\t\t\t/*\n-\t\t\t * can we really accept it, with regards to SSL limit?\n-\t\t\t * another vhost may also have had POLLIN on his listener this\n-\t\t\t * round and used it up already\n-\t\t\t */\n-\n-\t\t\tif (wsi-\u003evhost-\u003euse_ssl \u0026\u0026\n-\t\t\t context-\u003esimultaneous_ssl_restriction \u0026\u0026\n-\t\t\t context-\u003esimultaneous_ssl \u003d\u003d\n-\t\t\t\t\t context-\u003esimultaneous_ssl_restriction)\n-\t\t\t\t/* no... ignore it, he won't come again until we are\n-\t\t\t\t * below the simultaneous_ssl_restriction limit and\n-\t\t\t\t * POLLIN is enabled on him again\n-\t\t\t\t */\n-\t\t\t\tbreak;\n-#endif\n-\t\t\t/* listen socket got an unencrypted connection... */\n-\n-\t\t\tclilen \u003d sizeof(cli_addr);\n-\t\t\tlws_latency_pre(context, wsi);\n-\n-\t\t\t/*\n-\t\t\t * We cannot identify the peer who is in the listen\n-\t\t\t * socket connect queue before we accept it; even if\n-\t\t\t * we could, not accepting it due to PEER_LIMITS would\n-\t\t\t * block the connect queue for other legit peers.\n-\t\t\t */\n-\t\t\taccept_fd \u003d accept(pollfd-\u003efd, (struct sockaddr *)\u0026cli_addr,\n-\t\t\t\t\t \u0026clilen);\n-\t\t\tlws_latency(context, wsi, \u0022listener accept\u0022, accept_fd,\n-\t\t\t\t accept_fd \u003e\u003d 0);\n-\t\t\tif (accept_fd \u003c 0) {\n-\t\t\t\tif (LWS_ERRNO \u003d\u003d LWS_EAGAIN ||\n-\t\t\t\t LWS_ERRNO \u003d\u003d LWS_EWOULDBLOCK) {\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\tlwsl_err(\u0022ERROR on accept: %s\u005cn\u0022, strerror(LWS_ERRNO));\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\t\tlws_plat_set_socket_options(wsi-\u003evhost, accept_fd);\n-\n-#if defined(LWS_WITH_IPV6)\n-\t\t\tlwsl_debug(\u0022accepted new conn port %u on fd\u003d%d\u005cn\u0022,\n-\t\t\t\t\t ((cli_addr.ss_family \u003d\u003d AF_INET6) ?\n-\t\t\t\t\t ntohs(((struct sockaddr_in6 *) \u0026cli_addr)-\u003esin6_port) :\n-\t\t\t\t\t ntohs(((struct sockaddr_in *) \u0026cli_addr)-\u003esin_port)),\n-\t\t\t\t\t accept_fd);\n-#else\n-\t\t\tlwsl_debug(\u0022accepted new conn port %u on fd\u003d%d\u005cn\u0022,\n-\t\t\t\t\t ntohs(((struct sockaddr_in *) \u0026cli_addr)-\u003esin_port),\n-\t\t\t\t\t accept_fd);\n-#endif\n-\n-#else\n-\t\t\t/* not very beautiful... */\n-\t\t\taccept_fd \u003d (lws_sockfd_type)pollfd;\n-#endif\n-\t\t\t/*\n-\t\t\t * look at who we connected to and give user code a chance\n-\t\t\t * to reject based on client IP. There's no protocol selected\n-\t\t\t * yet so we issue this to protocols[0]\n-\t\t\t */\n-\t\t\tif ((wsi-\u003evhost-\u003eprotocols[0].callback)(wsi,\n-\t\t\t\t\tLWS_CALLBACK_FILTER_NETWORK_CONNECTION,\n-\t\t\t\t\tNULL, (void *)(lws_intptr_t)accept_fd, 0)) {\n-\t\t\t\tlwsl_debug(\u0022Callback denied network connection\u005cn\u0022);\n-\t\t\t\tcompatible_close(accept_fd);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\t\tif (!(wsi-\u003evhost-\u003eoptions \u0026 LWS_SERVER_OPTION_ONLY_RAW))\n-\t\t\t\topts |\u003d LWS_ADOPT_HTTP;\n-\t\t\telse\n-\t\t\t\topts \u003d LWS_ADOPT_SOCKET;\n-\n-\t\t\tfd.sockfd \u003d accept_fd;\n-\t\t\tif (!lws_adopt_descriptor_vhost(wsi-\u003evhost, opts, fd,\n-\t\t\t\t\t\t\tNULL, NULL))\n-\t\t\t\t/* already closed cleanly as necessary */\n-\t\t\t\treturn 1;\n-\n-#if LWS_POSIX\n-\t\t} while (pt-\u003efds_count \u003c context-\u003efd_limit_per_thread - 1 \u0026\u0026\n-\t\t\t lws_poll_listen_fd(\u0026pt-\u003efds[wsi-\u003eposition_in_fds_table]) \u003e 0);\n-#endif\n-\t\treturn 0;\n-\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\n-\tif (!lws_server_socket_service_ssl(wsi, accept_fd))\n-\t\treturn 0;\n-\n-fail:\n-\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n-\n-\treturn 1;\n-}\n-\n-LWS_VISIBLE int\n-lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,\n-\t\t const char *other_headers, int other_headers_len)\n-{\n-\tstatic const char * const intermediates[] \u003d { \u0022private\u0022, \u0022public\u0022 };\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-#if defined(LWS_WITH_RANGES)\n-\tstruct lws_range_parsing *rp \u003d \u0026wsi-\u003eu.http.range;\n-#endif\n-\tchar cache_control[50], *cc \u003d \u0022no-store\u0022;\n-\tunsigned char *response \u003d pt-\u003eserv_buf + LWS_PRE;\n-\tunsigned char *p \u003d response;\n-\tunsigned char *end \u003d p + context-\u003ept_serv_buf_size - LWS_PRE;\n-\tlws_filepos_t computed_total_content_length;\n-\tint ret \u003d 0, cclen \u003d 8, n \u003d HTTP_STATUS_OK;\n-\tlws_fop_flags_t fflags \u003d LWS_O_RDONLY;\n-#if defined(LWS_WITH_RANGES)\n-\tint ranges;\n-#endif\n-\tconst struct lws_plat_file_ops *fops;\n-\tconst char *vpath;\n-\n-\t/*\n-\t * We either call the platform fops .open with first arg platform fops,\n-\t * or we call fops_zip .open with first arg platform fops, and fops_zip\n-\t * open will decide whether to switch to fops_zip or stay with fops_def.\n-\t *\n-\t * If wsi-\u003eu.http.fop_fd is already set, the caller already opened it\n-\t */\n-\tif (!wsi-\u003eu.http.fop_fd) {\n-\t\tfops \u003d lws_vfs_select_fops(wsi-\u003econtext-\u003efops, file, \u0026vpath);\n-\t\tfflags |\u003d lws_vfs_prepare_flags(wsi);\n-\t\twsi-\u003eu.http.fop_fd \u003d fops-\u003eLWS_FOP_OPEN(wsi-\u003econtext-\u003efops,\n-\t\t\t\t\t\t\tfile, vpath, \u0026fflags);\n-\t\tif (!wsi-\u003eu.http.fop_fd) {\n-\t\t\tlwsl_err(\u0022Unable to open '%s'\u005cn\u0022, file);\n-\n-\t\t\treturn -1;\n-\t\t}\n-\t}\n-\twsi-\u003eu.http.filelen \u003d lws_vfs_get_length(wsi-\u003eu.http.fop_fd);\n-\tcomputed_total_content_length \u003d wsi-\u003eu.http.filelen;\n-\n-#if defined(LWS_WITH_RANGES)\n-\tranges \u003d lws_ranges_init(wsi, rp, wsi-\u003eu.http.filelen);\n-\n-\tlwsl_debug(\u0022Range count %d\u005cn\u0022, ranges);\n-\t/*\n-\t * no ranges -\u003e 200;\n-\t * 1 range -\u003e 206 + Content-Type: normal; Content-Range;\n-\t * more -\u003e 206 + Content-Type: multipart/byteranges\n-\t * \t\tRepeat the true Content-Type in each multipart header\n-\t * \t\talong with Content-Range\n-\t */\n-\tif (ranges \u003c 0) {\n-\t\t/* it means he expressed a range in Range:, but it was illegal */\n-\t\tlws_return_http_status(wsi, HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, NULL);\n-\t\tif (lws_http_transaction_completed(wsi))\n-\t\t\treturn -1; /* \u003c0 means just hang up */\n-\n-\t\tlws_vfs_file_close(\u0026wsi-\u003eu.http.fop_fd);\n-\n-\t\treturn 0; /* \u003d\u003d 0 means we dealt with the transaction complete */\n-\t}\n-\tif (ranges)\n-\t\tn \u003d HTTP_STATUS_PARTIAL_CONTENT;\n-#endif\n-\n-\tif (lws_add_http_header_status(wsi, n, \u0026p, end))\n-\t\treturn -1;\n-\n-\tif ((wsi-\u003eu.http.fop_fd-\u003eflags \u0026 (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |\n-\t\t LWS_FOP_FLAG_COMPR_IS_GZIP)) \u003d\u003d\n-\t (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {\n-\t\tif (lws_add_http_header_by_token(wsi,\n-\t\t\tWSI_TOKEN_HTTP_CONTENT_ENCODING,\n-\t\t\t(unsigned char *)\u0022gzip\u0022, 4, \u0026p, end))\n-\t\t\treturn -1;\n-\t\tlwsl_info(\u0022file is being provided in gzip\u005cn\u0022);\n-\t}\n-\n-\tif (\n-#if defined(LWS_WITH_RANGES)\n-\t ranges \u003c 2 \u0026\u0026\n-#endif\n-\t content_type \u0026\u0026 content_type[0])\n-\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,\n-\t\t\t\t\t\t (unsigned char *)content_type,\n-\t\t\t\t\t\t strlen(content_type), \u0026p, end))\n-\t\t\treturn -1;\n-\n-#if defined(LWS_WITH_RANGES)\n-\tif (ranges \u003e\u003d 2) { /* multipart byteranges */\n-\t\tstrncpy(wsi-\u003eu.http.multipart_content_type, content_type,\n-\t\t\tsizeof(wsi-\u003eu.http.multipart_content_type) - 1);\n-\t\twsi-\u003eu.http.multipart_content_type[\n-\t\t sizeof(wsi-\u003eu.http.multipart_content_type) - 1] \u003d '\u005c0';\n-\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,\n-\t\t\t\t\t\t (unsigned char *)\u0022multipart/byteranges; boundary\u003d_lws\u0022,\n-\t\t\t\t\t\t 20, \u0026p, end))\n-\t\t\treturn -1;\n-\n-\t\t/*\n-\t\t * our overall content length has to include\n-\t\t *\n-\t\t * - (n + 1) x \u0022_lws\u005cr\u005cn\u0022\n-\t\t * - n x Content-Type: xxx/xxx\u005cr\u005cn\n-\t\t * - n x Content-Range: bytes xxx-yyy/zzz\u005cr\u005cn\n-\t\t * - n x /r/n\n-\t\t * - the actual payloads (aggregated in rp-\u003eagg)\n-\t\t *\n-\t\t * Precompute it for the main response header\n-\t\t */\n-\n-\t\tcomputed_total_content_length \u003d (lws_filepos_t)rp-\u003eagg +\n-\t\t\t\t\t\t6 /* final _lws\u005cr\u005cn */;\n-\n-\t\tlws_ranges_reset(rp);\n-\t\twhile (lws_ranges_next(rp)) {\n-\t\t\tn \u003d lws_snprintf(cache_control, sizeof(cache_control),\n-\t\t\t\t\t\u0022bytes %llu-%llu/%llu\u0022,\n-\t\t\t\t\trp-\u003estart, rp-\u003eend, rp-\u003eextent);\n-\n-\t\t\tcomputed_total_content_length +\u003d\n-\t\t\t\t\t6 /* header _lws\u005cr\u005cn */ +\n-\t\t\t\t\t14 + strlen(content_type) + 2 + /* Content-Type: xxx/xxx\u005cr\u005cn */\n-\t\t\t\t\t15 + n + 2 + /* Content-Range: xxxx\u005cr\u005cn */\n-\t\t\t\t\t2; /* /r/n */\n-\t\t}\n-\n-\t\tlws_ranges_reset(rp);\n-\t\tlws_ranges_next(rp);\n-\t}\n-\n-\tif (ranges \u003d\u003d 1) {\n-\t\tcomputed_total_content_length \u003d (lws_filepos_t)rp-\u003eagg;\n-\t\tn \u003d lws_snprintf(cache_control, sizeof(cache_control), \u0022bytes %llu-%llu/%llu\u0022,\n-\t\t\t\trp-\u003estart, rp-\u003eend, rp-\u003eextent);\n-\n-\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_RANGE,\n-\t\t\t\t\t\t (unsigned char *)cache_control,\n-\t\t\t\t\t\t n, \u0026p, end))\n-\t\t\treturn -1;\n-\t}\n-\n-\twsi-\u003eu.http.range.inside \u003d 0;\n-\n-\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ACCEPT_RANGES,\n-\t\t\t\t\t (unsigned char *)\u0022bytes\u0022, 5, \u0026p, end))\n-\t\treturn -1;\n-#endif\n-\n-\tif (!wsi-\u003esending_chunked) {\n-\t\tif (lws_add_http_header_content_length(wsi,\n-\t\t\t\t\t\t computed_total_content_length,\n-\t\t\t\t\t\t \u0026p, end))\n-\t\t\treturn -1;\n-\t} else {\n-\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING,\n-\t\t\t\t\t\t (unsigned char *)\u0022chunked\u0022,\n-\t\t\t\t\t\t 7, \u0026p, end))\n-\t\t\treturn -1;\n-\t}\n-\n-\tif (wsi-\u003ecache_secs \u0026\u0026 wsi-\u003ecache_reuse) {\n-\t\tif (wsi-\u003ecache_revalidate) {\n-\t\t\tcc \u003d cache_control;\n-\t\t\tcclen \u003d sprintf(cache_control, \u0022%s max-age: %u\u0022,\n-\t\t\t\t intermediates[wsi-\u003ecache_intermediaries],\n-\t\t\t\t wsi-\u003ecache_secs);\n-\t\t} else {\n-\t\t\tcc \u003d \u0022no-cache\u0022;\n-\t\t\tcclen \u003d 8;\n-\t\t}\n-\t}\n-\n-\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CACHE_CONTROL,\n-\t\t\t(unsigned char *)cc, cclen, \u0026p, end))\n-\t\treturn -1;\n-\n-\tif (wsi-\u003eu.http.connection_type \u003d\u003d HTTP_CONNECTION_KEEP_ALIVE)\n-\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,\n-\t\t\t\t(unsigned char *)\u0022keep-alive\u0022, 10, \u0026p, end))\n-\t\t\treturn -1;\n-\n-\tif (other_headers) {\n-\t\tif ((end - p) \u003c other_headers_len)\n-\t\t\treturn -1;\n-\t\tmemcpy(p, other_headers, other_headers_len);\n-\t\tp +\u003d other_headers_len;\n-\t}\n-\n-\tif (lws_finalize_http_header(wsi, \u0026p, end))\n-\t\treturn -1;\n-\n-\tret \u003d lws_write(wsi, response, p - response, LWS_WRITE_HTTP_HEADERS);\n-\tif (ret !\u003d (p - response)) {\n-\t\tlwsl_err(\u0022_write returned %d from %ld\u005cn\u0022, ret, (long)(p - response));\n-\t\treturn -1;\n-\t}\n-\n-\twsi-\u003eu.http.filepos \u003d 0;\n-\twsi-\u003estate \u003d LWSS_HTTP_ISSUING_FILE;\n-\n-\tlws_callback_on_writable(wsi);\n-\n-\treturn 0;\n-}\n-\n-int\n-lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len)\n-{\n-\tint m;\n-\n-\tlwsl_parser(\u0022%s: received %d byte packet\u005cn\u0022, __func__, (int)len);\n-#if 0\n-\tlwsl_hexdump(*buf, len);\n-#endif\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\tlws_rxflow_cache(wsi, *buf, 0, len);\n-\t\t\tlwsl_parser(\u0022%s: cached %ld\u005cn\u0022, __func__, (long)len);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\tif (wsi-\u003eu.ws.rx_draining_ext) {\n-\t\t\tm \u003d lws_rx_sm(wsi, 0);\n-\t\t\tif (m \u003c 0)\n-\t\t\t\treturn -1;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\t/* account for what we're using in rxflow buffer */\n-\t\tif (wsi-\u003erxflow_buffer) {\n-\t\t\twsi-\u003erxflow_pos++;\n-\t\t\tassert(wsi-\u003erxflow_pos \u003c\u003d wsi-\u003erxflow_len);\n-\t\t}\n-\n-\t\t/* consume payload bytes efficiently */\n-\t\tif (\n-\t\t wsi-\u003elws_rx_parse_state \u003d\u003d\n-\t\t LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED) {\n-\t\t\tm \u003d lws_payload_until_length_exhausted(wsi, buf, \u0026len);\n-\t\t\tif (wsi-\u003erxflow_buffer)\n-\t\t\t\twsi-\u003erxflow_pos +\u003d m;\n-\t\t}\n-\n-\t\t/* process the byte */\n-\t\tm \u003d lws_rx_sm(wsi, *(*buf)++);\n-\t\tif (m \u003c 0)\n-\t\t\treturn -1;\n-\t\tlen--;\n-\t}\n-\n-\tlwsl_parser(\u0022%s: exit with %d unused\u005cn\u0022, __func__, (int)len);\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_server_get_canonical_hostname(struct lws_context *context,\n-\t\t\t\t struct lws_context_creation_info *info)\n-{\n-\tif (lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))\n-\t\treturn;\n-#if LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n-\t/* find canonical hostname */\n-\tgethostname((char *)context-\u003ecanonical_hostname,\n-\t\t sizeof(context-\u003ecanonical_hostname) - 1);\n-\n-\tlwsl_info(\u0022 canonical_hostname \u003d %s\u005cn\u0022, context-\u003ecanonical_hostname);\n-#else\n-\t(void)context;\n-#endif\n-}\n-\n-#define LWS_MAX_ELEM_NAME 32\n-\n-enum urldecode_stateful {\n-\tUS_NAME,\n-\tUS_IDLE,\n-\tUS_PC1,\n-\tUS_PC2,\n-\n-\tMT_LOOK_BOUND_IN,\n-\tMT_HNAME,\n-\tMT_DISP,\n-\tMT_TYPE,\n-\tMT_IGNORE1,\n-\tMT_IGNORE2,\n-};\n-\n-static const char * const mp_hdr[] \u003d {\n-\t\u0022content-disposition: \u0022,\n-\t\u0022content-type: \u0022,\n-\t\u0022\u005cx0d\u005cx0a\u0022\n-};\n-\n-typedef int (*lws_urldecode_stateful_cb)(void *data,\n-\t\tconst char *name, char **buf, int len, int final);\n-\n-struct lws_urldecode_stateful {\n-\tchar *out;\n-\tvoid *data;\n-\tchar name[LWS_MAX_ELEM_NAME];\n-\tchar temp[LWS_MAX_ELEM_NAME];\n-\tchar content_type[32];\n-\tchar content_disp[32];\n-\tchar content_disp_filename[256];\n-\tchar mime_boundary[128];\n-\tint out_len;\n-\tint pos;\n-\tint hdr_idx;\n-\tint mp;\n-\tint sum;\n-\n-\tunsigned int multipart_form_data:1;\n-\tunsigned int inside_quote:1;\n-\tunsigned int subname:1;\n-\tunsigned int boundary_real_crlf:1;\n-\n-\tenum urldecode_stateful state;\n-\n-\tlws_urldecode_stateful_cb output;\n-};\n-\n-static struct lws_urldecode_stateful *\n-lws_urldecode_s_create(struct lws *wsi, char *out, int out_len, void *data,\n-\t\t lws_urldecode_stateful_cb output)\n-{\n-\tstruct lws_urldecode_stateful *s \u003d lws_zalloc(sizeof(*s), \u0022stateful urldecode\u0022);\n-\tchar buf[200], *p;\n-\tint m \u003d 0;\n-\n-\tif (!s)\n-\t\treturn NULL;\n-\n-\ts-\u003eout \u003d out;\n-\ts-\u003eout_len \u003d out_len;\n-\ts-\u003eoutput \u003d output;\n-\ts-\u003epos \u003d 0;\n-\ts-\u003esum \u003d 0;\n-\ts-\u003emp \u003d 0;\n-\ts-\u003estate \u003d US_NAME;\n-\ts-\u003ename[0] \u003d '\u005c0';\n-\ts-\u003edata \u003d data;\n-\n-\tif (lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_CONTENT_TYPE) \u003e 0) {\n-\t\t/* multipart/form-data; boundary\u003d----WebKitFormBoundarycc7YgAPEIHvgE9Bf */\n-\n-\t\tif (!strncmp(buf, \u0022multipart/form-data\u0022, 19)) {\n-\t\t\ts-\u003emultipart_form_data \u003d 1;\n-\t\t\ts-\u003estate \u003d MT_LOOK_BOUND_IN;\n-\t\t\ts-\u003emp \u003d 2;\n-\t\t\tp \u003d strstr(buf, \u0022boundary\u003d\u0022);\n-\t\t\tif (p) {\n-\t\t\t\tp +\u003d 9;\n-\t\t\t\ts-\u003emime_boundary[m++] \u003d '\u005cx0d';\n-\t\t\t\ts-\u003emime_boundary[m++] \u003d '\u005cx0a';\n-\t\t\t\ts-\u003emime_boundary[m++] \u003d '-';\n-\t\t\t\ts-\u003emime_boundary[m++] \u003d '-';\n-\t\t\t\twhile (m \u003c sizeof(s-\u003emime_boundary) - 1 \u0026\u0026\n-\t\t\t\t *p \u0026\u0026 *p !\u003d ' ')\n-\t\t\t\t\ts-\u003emime_boundary[m++] \u003d *p++;\n-\n-\t\t\t\ts-\u003emime_boundary[m] \u003d '\u005c0';\n-\n-\t\t\t\tlwsl_notice(\u0022boundary '%s'\u005cn\u0022, s-\u003emime_boundary);\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\treturn s;\n-}\n-\n-static int\n-lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in, int len)\n-{\n-\tint n, m, hit \u003d 0;\n-\tchar c, was_end \u003d 0;\n-\n-\twhile (len--) {\n-\t\tif (s-\u003epos \u003d\u003d s-\u003eout_len - s-\u003emp - 1) {\n-\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename, \u0026s-\u003eout, s-\u003epos, 0))\n-\t\t\t\treturn -1;\n-\n-\t\t\twas_end \u003d s-\u003epos;\n-\t\t\ts-\u003epos \u003d 0;\n-\t\t}\n-\t\tswitch (s-\u003estate) {\n-\n-\t\t/* states for url arg style */\n-\n-\t\tcase US_NAME:\n-\t\t\ts-\u003einside_quote \u003d 0;\n-\t\t\tif (*in \u003d\u003d '\u003d') {\n-\t\t\t\ts-\u003ename[s-\u003epos] \u003d '\u005c0';\n-\t\t\t\ts-\u003epos \u003d 0;\n-\t\t\t\ts-\u003estate \u003d US_IDLE;\n-\t\t\t\tin++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (*in \u003d\u003d '\u0026') {\n-\t\t\t\ts-\u003ename[s-\u003epos] \u003d '\u005c0';\n-\t\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename, \u0026s-\u003eout, s-\u003epos, 1))\n-\t\t\t\t\treturn -1;\n-\t\t\t\ts-\u003epos \u003d 0;\n-\t\t\t\ts-\u003estate \u003d US_IDLE;\n-\t\t\t\tin++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (s-\u003epos \u003e\u003d sizeof(s-\u003ename) - 1) {\n-\t\t\t\tlwsl_notice(\u0022Name too long\u005cn\u0022);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\ts-\u003ename[s-\u003epos++] \u003d *in++;\n-\t\t\tbreak;\n-\t\tcase US_IDLE:\n-\t\t\tif (*in \u003d\u003d '%') {\n-\t\t\t\ts-\u003estate++;\n-\t\t\t\tin++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (*in \u003d\u003d '\u0026') {\n-\t\t\t\ts-\u003eout[s-\u003epos] \u003d '\u005c0';\n-\t\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename, \u0026s-\u003eout, s-\u003epos, 1))\n-\t\t\t\t\treturn -1;\n-\t\t\t\ts-\u003epos \u003d 0;\n-\t\t\t\ts-\u003estate \u003d US_NAME;\n-\t\t\t\tin++;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (*in \u003d\u003d '+') {\n-\t\t\t\tin++;\n-\t\t\t\ts-\u003eout[s-\u003epos++] \u003d ' ';\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\ts-\u003eout[s-\u003epos++] \u003d *in++;\n-\t\t\tbreak;\n-\t\tcase US_PC1:\n-\t\t\tn \u003d char_to_hex(*in);\n-\t\t\tif (n \u003c 0)\n-\t\t\t\treturn -1;\n-\n-\t\t\tin++;\n-\t\t\ts-\u003esum \u003d n \u003c\u003c 4;\n-\t\t\ts-\u003estate++;\n-\t\t\tbreak;\n-\n-\t\tcase US_PC2:\n-\t\t\tn \u003d char_to_hex(*in);\n-\t\t\tif (n \u003c 0)\n-\t\t\t\treturn -1;\n-\n-\t\t\tin++;\n-\t\t\ts-\u003eout[s-\u003epos++] \u003d s-\u003esum | n;\n-\t\t\ts-\u003estate \u003d US_IDLE;\n-\t\t\tbreak;\n-\n-\n-\t\t/* states for multipart / mime style */\n-\n-\t\tcase MT_LOOK_BOUND_IN:\n-retry_as_first:\n-\t\t\tif (*in \u003d\u003d s-\u003emime_boundary[s-\u003emp] \u0026\u0026\n-\t\t\t s-\u003emime_boundary[s-\u003emp]) {\n-\t\t\t\tin++;\n-\t\t\t\ts-\u003emp++;\n-\t\t\t\tif (!s-\u003emime_boundary[s-\u003emp]) {\n-\t\t\t\t\ts-\u003emp \u003d 0;\n-\t\t\t\t\ts-\u003estate \u003d MT_IGNORE1;\n-\n-\t\t\t\t\tif (s-\u003epos || was_end)\n-\t\t\t\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename,\n-\t\t\t\t\t\t \u0026s-\u003eout, s-\u003epos, 1))\n-\t\t\t\t\t\t\treturn -1;\n-\n-\t\t\t\t\ts-\u003epos \u003d 0;\n-\n-\t\t\t\t\ts-\u003econtent_disp[0] \u003d '\u005c0';\n-\t\t\t\t\ts-\u003ename[0] \u003d '\u005c0';\n-\t\t\t\t\ts-\u003econtent_disp_filename[0] \u003d '\u005c0';\n-\t\t\t\t\ts-\u003eboundary_real_crlf \u003d 1;\n-\t\t\t\t}\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (s-\u003emp) {\n-\t\t\t\tn \u003d 0;\n-\t\t\t\tif (!s-\u003eboundary_real_crlf)\n-\t\t\t\t\tn \u003d 2;\n-\n-\t\t\t\tmemcpy(s-\u003eout + s-\u003epos, s-\u003emime_boundary + n, s-\u003emp - n);\n-\t\t\t\ts-\u003epos +\u003d s-\u003emp;\n-\t\t\t\ts-\u003emp \u003d 0;\n-\t\t\t\tgoto retry_as_first;\n-\t\t\t}\n-\n-\t\t\ts-\u003eout[s-\u003epos++] \u003d *in;\n-\t\t\tin++;\n-\t\t\ts-\u003emp \u003d 0;\n-\t\t\tbreak;\n-\n-\t\tcase MT_HNAME:\n-\t\t\tm \u003d 0;\n-\t\t\tc \u003d*in;\n-\t\t\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'Z')\n-\t\t\t\tc +\u003d 'a' - 'A';\n-\t\t\tfor (n \u003d 0; n \u003c ARRAY_SIZE(mp_hdr); n++)\n-\t\t\t\tif (c \u003d\u003d mp_hdr[n][s-\u003emp]) {\n-\t\t\t\t\tm++;\n-\t\t\t\t\thit \u003d n;\n-\t\t\t\t}\n-\t\t\tin++;\n-\t\t\tif (!m) {\n-\t\t\t\ts-\u003emp \u003d 0;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\n-\t\t\ts-\u003emp++;\n-\t\t\tif (m !\u003d 1)\n-\t\t\t\tcontinue;\n-\n-\t\t\tif (mp_hdr[hit][s-\u003emp])\n-\t\t\t\tcontinue;\n-\n-\t\t\ts-\u003emp \u003d 0;\n-\t\t\ts-\u003etemp[0] \u003d '\u005c0';\n-\t\t\ts-\u003esubname \u003d 0;\n-\n-\t\t\tif (hit \u003d\u003d 2)\n-\t\t\t\ts-\u003estate \u003d MT_LOOK_BOUND_IN;\n-\t\t\telse\n-\t\t\t\ts-\u003estate +\u003d hit + 1;\n-\t\t\tbreak;\n-\n-\t\tcase MT_DISP:\n-\t\t\t/* form-data; name\u003d\u0022file\u0022; filename\u003d\u0022t.txt\u0022 */\n-\n-\t\t\tif (*in \u003d\u003d '\u005cx0d') {\n-\t\t\t\tif (s-\u003econtent_disp_filename[0])\n-\t\t\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename,\n-\t\t\t\t\t\t \u0026s-\u003eout, s-\u003epos, LWS_UFS_OPEN))\n-\t\t\t\t\t\treturn -1;\n-\t\t\t\ts-\u003estate \u003d MT_IGNORE2;\n-\t\t\t\tgoto done;\n-\t\t\t}\n-\t\t\tif (*in \u003d\u003d ';') {\n-\t\t\t\ts-\u003esubname \u003d 1;\n-\t\t\t\ts-\u003etemp[0] \u003d '\u005c0';\n-\t\t\t\ts-\u003emp \u003d 0;\n-\t\t\t\tgoto done;\n-\t\t\t}\n-\n-\t\t\tif (*in \u003d\u003d '\u005c\u0022') {\n-\t\t\t\ts-\u003einside_quote ^\u003d 1;\n-\t\t\t\tgoto done;\n-\t\t\t}\n-\n-\t\t\tif (s-\u003esubname) {\n-\t\t\t\tif (*in \u003d\u003d '\u003d') {\n-\t\t\t\t\ts-\u003etemp[s-\u003emp] \u003d '\u005c0';\n-\t\t\t\t\ts-\u003esubname \u003d 0;\n-\t\t\t\t\ts-\u003emp \u003d 0;\n-\t\t\t\t\tgoto done;\n-\t\t\t\t}\n-\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003etemp) - 1 \u0026\u0026\n-\t\t\t\t (*in !\u003d ' ' || s-\u003einside_quote))\n-\t\t\t\t\ts-\u003etemp[s-\u003emp++] \u003d *in;\n-\t\t\t\tgoto done;\n-\t\t\t}\n-\n-\t\t\tif (!s-\u003etemp[0]) {\n-\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003econtent_disp) - 1)\n-\t\t\t\t\ts-\u003econtent_disp[s-\u003emp++] \u003d *in;\n-\t\t\t\ts-\u003econtent_disp[s-\u003emp] \u003d '\u005c0';\n-\t\t\t\tgoto done;\n-\t\t\t}\n-\n-\t\t\tif (!strcmp(s-\u003etemp, \u0022name\u0022)) {\n-\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003ename) - 1)\n-\t\t\t\t\ts-\u003ename[s-\u003emp++] \u003d *in;\n-\t\t\t\ts-\u003ename[s-\u003emp] \u003d '\u005c0';\n-\t\t\t\tgoto done;\n-\t\t\t}\n-\n-\t\t\tif (!strcmp(s-\u003etemp, \u0022filename\u0022)) {\n-\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003econtent_disp_filename) - 1)\n-\t\t\t\t\ts-\u003econtent_disp_filename[s-\u003emp++] \u003d *in;\n-\t\t\t\ts-\u003econtent_disp_filename[s-\u003emp] \u003d '\u005c0';\n-\t\t\t\tgoto done;\n-\t\t\t}\n-done:\n-\t\t\tin++;\n-\t\t\tbreak;\n-\n-\t\tcase MT_TYPE:\n-\t\t\tif (*in \u003d\u003d '\u005cx0d')\n-\t\t\t\ts-\u003estate \u003d MT_IGNORE2;\n-\t\t\telse {\n-\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003econtent_type) - 1)\n-\t\t\t\t\ts-\u003econtent_type[s-\u003emp++] \u003d *in;\n-\t\t\t\ts-\u003econtent_type[s-\u003emp] \u003d '\u005c0';\n-\t\t\t}\n-\t\t\tin++;\n-\t\t\tbreak;\n-\n-\t\tcase MT_IGNORE1:\n-\t\t\tif (*in \u003d\u003d '\u005cx0d')\n-\t\t\t\ts-\u003estate \u003d MT_IGNORE2;\n-\t\t\tin++;\n-\t\t\tbreak;\n-\n-\t\tcase MT_IGNORE2:\n-\t\t\ts-\u003emp \u003d 0;\n-\t\t\tif (*in \u003d\u003d '\u005cx0a')\n-\t\t\t\ts-\u003estate \u003d MT_HNAME;\n-\t\t\tin++;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static int\n-lws_urldecode_s_destroy(struct lws_urldecode_stateful *s)\n-{\n-\tint ret \u003d 0;\n-\n-\tif (s-\u003estate !\u003d US_IDLE)\n-\t\tret \u003d -1;\n-\n-\tif (!ret)\n-\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename, \u0026s-\u003eout, s-\u003epos, 1))\n-\t\t\tret \u003d -1;\n-\n-\tlws_free(s);\n-\n-\treturn ret;\n-}\n-\n-struct lws_spa {\n-\tstruct lws_urldecode_stateful *s;\n-\tlws_spa_fileupload_cb opt_cb;\n-\tconst char * const *param_names;\n-\tint count_params;\n-\tchar **params;\n-\tint *param_length;\n-\tvoid *opt_data;\n-\n-\tchar *storage;\n-\tchar *end;\n-\tint max_storage;\n-\n-\tchar finalized;\n-};\n-\n-static int\n-lws_urldecode_spa_lookup(struct lws_spa *spa,\n-\t\t\t const char *name)\n-{\n-\tint n;\n-\n-\tfor (n \u003d 0; n \u003c spa-\u003ecount_params; n++)\n-\t\tif (!strcmp(spa-\u003eparam_names[n], name))\n-\t\t\treturn n;\n-\n-\treturn -1;\n-}\n-\n-static int\n-lws_urldecode_spa_cb(void *data, const char *name, char **buf, int len,\n-\t\t int final)\n-{\n-\tstruct lws_spa *spa \u003d\n-\t\t\t(struct lws_spa *)data;\n-\tint n;\n-\n-\tif (spa-\u003es-\u003econtent_disp_filename[0]) {\n-\t\tif (spa-\u003eopt_cb) {\n-\t\t\tn \u003d spa-\u003eopt_cb(spa-\u003eopt_data, name,\n-\t\t\t\t\tspa-\u003es-\u003econtent_disp_filename,\n-\t\t\t\t\t*buf, len, final);\n-\n-\t\t\tif (n \u003c 0)\n-\t\t\t\treturn -1;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\tn \u003d lws_urldecode_spa_lookup(spa, name);\n-\n-\tif (n \u003d\u003d -1 || !len) /* unrecognized */\n-\t\treturn 0;\n-\n-\tif (!spa-\u003eparams[n])\n-\t\tspa-\u003eparams[n] \u003d *buf;\n-\n-\tif ((*buf) + len \u003e\u003d spa-\u003eend) {\n-\t\tlwsl_notice(\u0022%s: exceeded storage\u005cn\u0022, __func__);\n-\t\treturn -1;\n-\t}\n-\n-\tspa-\u003eparam_length[n] +\u003d len;\n-\n-\t/* move it on inside storage */\n-\t(*buf) +\u003d len;\n-\t*((*buf)++) \u003d '\u005c0';\n-\n-\tspa-\u003es-\u003eout_len -\u003d len + 1;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN struct lws_spa *\n-lws_spa_create(struct lws *wsi, const char * const *param_names,\n-\t\t\t int count_params, int max_storage,\n-\t\t\t lws_spa_fileupload_cb opt_cb, void *opt_data)\n-{\n-\tstruct lws_spa *spa \u003d lws_zalloc(sizeof(*spa), \u0022spa\u0022);\n-\n-\tif (!spa)\n-\t\treturn NULL;\n-\n-\tspa-\u003eparam_names \u003d param_names;\n-\tspa-\u003ecount_params \u003d count_params;\n-\tspa-\u003emax_storage \u003d max_storage;\n-\tspa-\u003eopt_cb \u003d opt_cb;\n-\tspa-\u003eopt_data \u003d opt_data;\n-\n-\tspa-\u003estorage \u003d lws_malloc(max_storage, \u0022spa\u0022);\n-\tif (!spa-\u003estorage)\n-\t\tgoto bail2;\n-\tspa-\u003eend \u003d spa-\u003estorage + max_storage - 1;\n-\n-\tspa-\u003eparams \u003d lws_zalloc(sizeof(char *) * count_params, \u0022spa params\u0022);\n-\tif (!spa-\u003eparams)\n-\t\tgoto bail3;\n-\n-\tspa-\u003es \u003d lws_urldecode_s_create(wsi, spa-\u003estorage, max_storage, spa,\n-\t\t\t\t\tlws_urldecode_spa_cb);\n-\tif (!spa-\u003es)\n-\t\tgoto bail4;\n-\n-\tspa-\u003eparam_length \u003d lws_zalloc(sizeof(int) * count_params, \u0022spa param len\u0022);\n-\tif (!spa-\u003eparam_length)\n-\t\tgoto bail5;\n-\n-\tlwsl_info(\u0022%s: Created SPA %p\u005cn\u0022, __func__, spa);\n-\n-\treturn spa;\n-\n-bail5:\n-\tlws_urldecode_s_destroy(spa-\u003es);\n-bail4:\n-\tlws_free(spa-\u003eparams);\n-bail3:\n-\tlws_free(spa-\u003estorage);\n-bail2:\n-\tlws_free(spa);\n-\n-\treturn NULL;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_spa_process(struct lws_spa *ludspa, const char *in, int len)\n-{\n-\tif (!ludspa) {\n-\t\tlwsl_err(\u0022%s: NULL spa\u005cn\u0022, __func__);\n-\t\treturn -1;\n-\t}\n-\t/* we reject any junk after the last part arrived and we finalized */\n-\tif (ludspa-\u003efinalized)\n-\t\treturn 0;\n-\n-\treturn lws_urldecode_s_process(ludspa-\u003es, in, len);\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_spa_get_length(struct lws_spa *ludspa, int n)\n-{\n-\tif (n \u003e\u003d ludspa-\u003ecount_params)\n-\t\treturn 0;\n-\n-\treturn ludspa-\u003eparam_length[n];\n-}\n-\n-LWS_VISIBLE LWS_EXTERN const char *\n-lws_spa_get_string(struct lws_spa *ludspa, int n)\n-{\n-\tif (n \u003e\u003d ludspa-\u003ecount_params)\n-\t\treturn NULL;\n-\n-\treturn ludspa-\u003eparams[n];\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_spa_finalize(struct lws_spa *spa)\n-{\n-\tif (spa-\u003es) {\n-\t\tlws_urldecode_s_destroy(spa-\u003es);\n-\t\tspa-\u003es \u003d NULL;\n-\t}\n-\n-\tspa-\u003efinalized \u003d 1;\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_spa_destroy(struct lws_spa *spa)\n-{\n-\tint n \u003d 0;\n-\n-\tlwsl_notice(\u0022%s: destroy spa %p\u005cn\u0022, __func__, spa);\n-\n-\tif (spa-\u003es)\n-\t\tlws_urldecode_s_destroy(spa-\u003es);\n-\n-\tlwsl_debug(\u0022%s %p %p %p %p\u005cn\u0022, __func__,\n-\t\t\tspa-\u003eparam_length,\n-\t\t\tspa-\u003eparams,\n-\t\t\tspa-\u003estorage,\n-\t\t\tspa\n-\t\t\t);\n-\n-\tlws_free(spa-\u003eparam_length);\n-\tlws_free(spa-\u003eparams);\n-\tlws_free(spa-\u003estorage);\n-\tlws_free(spa);\n-\n-\treturn n;\n-}\n-\n-#if 0\n-LWS_VISIBLE LWS_EXTERN int\n-lws_spa_destroy(struct lws_spa *spa)\n-{\n-\tint n \u003d 0;\n-\n-\tlwsl_info(\u0022%s: destroy spa %p\u005cn\u0022, __func__, spa);\n-\n-\tif (spa-\u003es)\n-\t\tlws_urldecode_s_destroy(spa-\u003es);\n-\n-\tlwsl_debug(\u0022%s\u005cn\u0022, __func__);\n-\n-\tlws_free(spa-\u003eparam_length);\n-\tlws_free(spa-\u003eparams);\n-\tlws_free(spa-\u003estorage);\n-\tlws_free(spa);\n-\n-\treturn n;\n-}\n-#endif\n-LWS_VISIBLE LWS_EXTERN int\n-lws_chunked_html_process(struct lws_process_html_args *args,\n-\t\t\t struct lws_process_html_state *s)\n-{\n-\tchar *sp, buffer[32];\n-\tconst char *pc;\n-\tint old_len, n;\n-\n-\t/* do replacements */\n-\tsp \u003d args-\u003ep;\n-\told_len \u003d args-\u003elen;\n-\targs-\u003elen \u003d 0;\n-\ts-\u003estart \u003d sp;\n-\twhile (sp \u003c args-\u003ep + old_len) {\n-\n-\t\tif (args-\u003elen + 7 \u003e\u003d args-\u003emax_len) {\n-\t\t\tlwsl_err(\u0022Used up interpret padding\u005cn\u0022);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tif ((!s-\u003epos \u0026\u0026 *sp \u003d\u003d '$') || s-\u003epos) {\n-\t\t\tint hits \u003d 0, hit \u003d 0;\n-\n-\t\t\tif (!s-\u003epos)\n-\t\t\t\ts-\u003estart \u003d sp;\n-\t\t\ts-\u003eswallow[s-\u003epos++] \u003d *sp;\n-\t\t\tif (s-\u003epos \u003d\u003d sizeof(s-\u003eswallow) - 1)\n-\t\t\t\tgoto skip;\n-\t\t\tfor (n \u003d 0; n \u003c s-\u003ecount_vars; n++)\n-\t\t\t\tif (!strncmp(s-\u003eswallow, s-\u003evars[n], s-\u003epos)) {\n-\t\t\t\t\thits++;\n-\t\t\t\t\thit \u003d n;\n-\t\t\t\t}\n-\t\t\tif (!hits) {\n-skip:\n-\t\t\t\ts-\u003eswallow[s-\u003epos] \u003d '\u005c0';\n-\t\t\t\tmemcpy(s-\u003estart, s-\u003eswallow, s-\u003epos);\n-\t\t\t\targs-\u003elen++;\n-\t\t\t\ts-\u003epos \u003d 0;\n-\t\t\t\tsp \u003d s-\u003estart + 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (hits \u003d\u003d 1 \u0026\u0026 s-\u003epos \u003d\u003d strlen(s-\u003evars[hit])) {\n-\t\t\t\tpc \u003d s-\u003ereplace(s-\u003edata, hit);\n-\t\t\t\tif (!pc)\n-\t\t\t\t\tpc \u003d \u0022NULL\u0022;\n-\t\t\t\tn \u003d strlen(pc);\n-\t\t\t\ts-\u003eswallow[s-\u003epos] \u003d '\u005c0';\n-\t\t\t\tif (n !\u003d s-\u003epos) {\n-\t\t\t\t\tmemmove(s-\u003estart + n,\n-\t\t\t\t\t\ts-\u003estart + s-\u003epos,\n-\t\t\t\t\t\told_len - (sp - args-\u003ep));\n-\t\t\t\t\told_len +\u003d (n - s-\u003epos) + 1;\n-\t\t\t\t}\n-\t\t\t\tmemcpy(s-\u003estart, pc, n);\n-\t\t\t\targs-\u003elen++;\n-\t\t\t\tsp \u003d s-\u003estart + 1;\n-\n-\t\t\t\ts-\u003epos \u003d 0;\n-\t\t\t}\n-\t\t\tsp++;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\targs-\u003elen++;\n-\t\tsp++;\n-\t}\n-\n-\t/* no space left for final chunk trailer */\n-\tif (args-\u003efinal \u0026\u0026 args-\u003elen + 7 \u003e\u003d args-\u003emax_len)\n-\t\treturn -1;\n-\n-\tn \u003d sprintf(buffer, \u0022%X\u005cx0d\u005cx0a\u0022, args-\u003elen);\n-\n-\targs-\u003ep -\u003d n;\n-\tmemcpy(args-\u003ep, buffer, n);\n-\targs-\u003elen +\u003d n;\n-\n-\tif (args-\u003efinal) {\n-\t\tsp \u003d args-\u003ep + args-\u003elen;\n-\t\t*sp++ \u003d '\u005cx0d';\n-\t\t*sp++ \u003d '\u005cx0a';\n-\t\t*sp++ \u003d '0';\n-\t\t*sp++ \u003d '\u005cx0d';\n-\t\t*sp++ \u003d '\u005cx0a';\n-\t\t*sp++ \u003d '\u005cx0d';\n-\t\t*sp++ \u003d '\u005cx0a';\n-\t\targs-\u003elen +\u003d 7;\n-\t} else {\n-\t\tsp \u003d args-\u003ep + args-\u003elen;\n-\t\t*sp++ \u003d '\u005cx0d';\n-\t\t*sp++ \u003d '\u005cx0a';\n-\t\targs-\u003elen +\u003d 2;\n-\t}\n-\n-\treturn 0;\n-}\ndiff --git a/lib/server/access-log.c b/lib/server/access-log.c\nnew file mode 100644\nindex 0000000..3cc15e4\n--- /dev/null\n+++ b/lib/server/access-log.c\n@@ -0,0 +1,172 @@\n+/*\n+ * libwebsockets - server access log handling\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+/*\n+ * Produce Apache-compatible log string for wsi, like this:\n+ *\n+ * 2.31.234.19 - - [27/Mar/2016:03:22:44 +0800]\n+ * \u0022GET /aep-screen.png HTTP/1.1\u0022\n+ * 200 152987 \u0022https://libwebsockets.org/index.html\u0022\n+ * \u0022Mozilla/5.0 (Macint... Chrome/49.0.2623.87 Safari/537.36\u0022\n+ *\n+ */\n+\n+extern const char * const method_names[];\n+\n+static const char * const hver[] \u003d {\n+\t\u0022HTTP/1.0\u0022, \u0022HTTP/1.1\u0022, \u0022HTTP/2\u0022\n+};\n+\n+void\n+lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int meth)\n+{\n+#ifdef LWS_WITH_IPV6\n+\tchar ads[INET6_ADDRSTRLEN];\n+#else\n+\tchar ads[INET_ADDRSTRLEN];\n+#endif\n+\tchar da[64];\n+\tconst char *pa, *me;\n+\tstruct tm *tmp;\n+\ttime_t t \u003d time(NULL);\n+\tint l \u003d 256, m;\n+\n+\tif (wsi-\u003eaccess_log_pending)\n+\t\tlws_access_log(wsi);\n+\n+\twsi-\u003eaccess_log.header_log \u003d lws_malloc(l, \u0022access log\u0022);\n+\tif (wsi-\u003eaccess_log.header_log) {\n+\n+\t\ttmp \u003d localtime(\u0026t);\n+\t\tif (tmp)\n+\t\t\tstrftime(da, sizeof(da), \u0022%d/%b/%Y:%H:%M:%S %z\u0022, tmp);\n+\t\telse\n+\t\t\tstrcpy(da, \u002201/Jan/1970:00:00:00 +0000\u0022);\n+\n+\t\tpa \u003d lws_get_peer_simple(wsi, ads, sizeof(ads));\n+\t\tif (!pa)\n+\t\t\tpa \u003d \u0022(unknown)\u0022;\n+\n+\t\tif (wsi-\u003ehttp2_substream)\n+\t\t\tme \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);\n+\t\telse\n+\t\t\tme \u003d method_names[meth];\n+\t\tif (!me)\n+\t\t\tme \u003d \u0022(null)\u0022;\n+\n+\t\tlws_snprintf(wsi-\u003eaccess_log.header_log, l,\n+\t\t\t \u0022%s - - [%s] \u005c\u0022%s %s %s\u005c\u0022\u0022,\n+\t\t\t pa, da, me, uri_ptr,\n+\t\t\t hver[wsi-\u003eu.http.request_version]);\n+\n+\t\tl \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);\n+\t\tif (l) {\n+\t\t\twsi-\u003eaccess_log.user_agent \u003d lws_malloc(l + 2, \u0022access log\u0022);\n+\t\t\tif (!wsi-\u003eaccess_log.user_agent) {\n+\t\t\t\tlwsl_err(\u0022OOM getting user agent\u005cn\u0022);\n+\t\t\t\tlws_free_set_NULL(wsi-\u003eaccess_log.header_log);\n+\t\t\t\treturn;\n+\t\t\t}\n+\n+\t\t\tlws_hdr_copy(wsi, wsi-\u003eaccess_log.user_agent,\n+\t\t\t\t\tl + 1, WSI_TOKEN_HTTP_USER_AGENT);\n+\n+\t\t\tfor (m \u003d 0; m \u003c l; m++)\n+\t\t\t\tif (wsi-\u003eaccess_log.user_agent[m] \u003d\u003d '\u005c\u0022')\n+\t\t\t\t\twsi-\u003eaccess_log.user_agent[m] \u003d '\u005c'';\n+\t\t}\n+\t\tl \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER);\n+\t\tif (l) {\n+\t\t\twsi-\u003eaccess_log.referrer \u003d lws_malloc(l + 2, \u0022referrer\u0022);\n+\t\t\tif (!wsi-\u003eaccess_log.referrer) {\n+\t\t\t\tlwsl_err(\u0022OOM getting user agent\u005cn\u0022);\n+\t\t\t\tlws_free_set_NULL(wsi-\u003eaccess_log.user_agent);\n+\t\t\t\tlws_free_set_NULL(wsi-\u003eaccess_log.header_log);\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t\tlws_hdr_copy(wsi, wsi-\u003eaccess_log.referrer,\n+\t\t\t\t\tl + 1, WSI_TOKEN_HTTP_REFERER);\n+\n+\t\t\tfor (m \u003d 0; m \u003c l; m++)\n+\t\t\t\tif (wsi-\u003eaccess_log.referrer[m] \u003d\u003d '\u005c\u0022')\n+\t\t\t\t\twsi-\u003eaccess_log.referrer[m] \u003d '\u005c'';\n+\t\t}\n+\t\twsi-\u003eaccess_log_pending \u003d 1;\n+\t}\n+}\n+\n+\n+int\n+lws_access_log(struct lws *wsi)\n+{\n+\tchar *p \u003d wsi-\u003eaccess_log.user_agent, ass[512],\n+\t *p1 \u003d wsi-\u003eaccess_log.referrer;\n+\tint l;\n+\n+\tif (!wsi-\u003eaccess_log_pending)\n+\t\treturn 0;\n+\n+\tif (!wsi-\u003eaccess_log.header_log)\n+\t\treturn 0;\n+\n+\tif (!p)\n+\t\tp \u003d \u0022\u0022;\n+\n+\tif (!p1)\n+\t\tp1 \u003d \u0022\u0022;\n+\n+\t/*\n+\t * We do this in two parts to restrict an oversize referrer such that\n+\t * we will always have space left to append an empty useragent, while\n+\t * maintaining the structure of the log text\n+\t */\n+\tl \u003d lws_snprintf(ass, sizeof(ass) - 7, \u0022%s %d %lu \u005c\u0022%s\u0022,\n+\t\t wsi-\u003eaccess_log.header_log,\n+\t\t wsi-\u003eaccess_log.response, wsi-\u003eaccess_log.sent, p1);\n+\tif (strlen(p) \u003e sizeof(ass) - 6 - l)\n+\t\tp[sizeof(ass) - 6 - l] \u003d '\u005c0';\n+\tl +\u003d lws_snprintf(ass + l, sizeof(ass) - 1 - l, \u0022\u005c\u0022 \u005c\u0022%s\u005c\u0022\u005cn\u0022, p);\n+\n+\tif (wsi-\u003evhost-\u003elog_fd !\u003d (int)LWS_INVALID_FILE) {\n+\t\tif (write(wsi-\u003evhost-\u003elog_fd, ass, l) !\u003d l)\n+\t\t\tlwsl_err(\u0022Failed to write log\u005cn\u0022);\n+\t} else\n+\t\tlwsl_err(\u0022%s\u0022, ass);\n+\n+\tif (wsi-\u003eaccess_log.header_log) {\n+\t\tlws_free(wsi-\u003eaccess_log.header_log);\n+\t\twsi-\u003eaccess_log.header_log \u003d NULL;\n+\t}\n+\tif (wsi-\u003eaccess_log.user_agent) {\n+\t\tlws_free(wsi-\u003eaccess_log.user_agent);\n+\t\twsi-\u003eaccess_log.user_agent \u003d NULL;\n+\t}\n+\tif (wsi-\u003eaccess_log.referrer) {\n+\t\tlws_free(wsi-\u003eaccess_log.referrer);\n+\t\twsi-\u003eaccess_log.referrer \u003d NULL;\n+\t}\n+\twsi-\u003eaccess_log_pending \u003d 0;\n+\n+\treturn 0;\n+}\n+\ndiff --git a/lib/server/cgi.c b/lib/server/cgi.c\nnew file mode 100644\nindex 0000000..1b9dfe4\n--- /dev/null\n+++ b/lib/server/cgi.c\n@@ -0,0 +1,1103 @@\n+/*\n+ * libwebsockets - CGI management\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#if defined(WIN32) || defined(_WIN32)\n+#else\n+#include \u003csys/wait.h\u003e\n+#endif\n+\n+static const char *hex \u003d \u00220123456789ABCDEF\u0022;\n+\n+static int\n+urlencode(const char *in, int inlen, char *out, int outlen)\n+{\n+\tchar *start \u003d out, *end \u003d out + outlen;\n+\n+\twhile (inlen-- \u0026\u0026 out \u003c end - 4) {\n+\t\tif ((*in \u003e\u003d 'A' \u0026\u0026 *in \u003c\u003d 'Z') ||\n+\t\t (*in \u003e\u003d 'a' \u0026\u0026 *in \u003c\u003d 'z') ||\n+\t\t (*in \u003e\u003d '0' \u0026\u0026 *in \u003c\u003d '9') ||\n+\t\t *in \u003d\u003d '-' ||\n+\t\t *in \u003d\u003d '_' ||\n+\t\t *in \u003d\u003d '.' ||\n+\t\t *in \u003d\u003d '~') {\n+\t\t\t*out++ \u003d *in++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (*in \u003d\u003d ' ') {\n+\t\t\t*out++ \u003d '+';\n+\t\t\tin++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\t*out++ \u003d '%';\n+\t\t*out++ \u003d hex[(*in) \u003e\u003e 4];\n+\t\t*out++ \u003d hex[(*in++) \u0026 15];\n+\t}\n+\t*out \u003d '\u005c0';\n+\n+\tif (out \u003e\u003d end - 4)\n+\t\treturn -1;\n+\n+\treturn out - start;\n+}\n+\n+static struct lws *\n+lws_create_basic_wsi(struct lws_context *context, int tsi)\n+{\n+\tstruct lws *new_wsi;\n+\n+\tif (!context-\u003evhost_list)\n+\t\treturn NULL;\n+\n+\tif ((unsigned int)context-\u003ept[tsi].fds_count \u003d\u003d\n+\t context-\u003efd_limit_per_thread - 1) {\n+\t\tlwsl_err(\u0022no space for new conn\u005cn\u0022);\n+\t\treturn NULL;\n+\t}\n+\n+\tnew_wsi \u003d lws_zalloc(sizeof(struct lws), \u0022new wsi\u0022);\n+\tif (new_wsi \u003d\u003d NULL) {\n+\t\tlwsl_err(\u0022Out of memory for new connection\u005cn\u0022);\n+\t\treturn NULL;\n+\t}\n+\n+\tnew_wsi-\u003etsi \u003d tsi;\n+\tnew_wsi-\u003econtext \u003d context;\n+\tnew_wsi-\u003epending_timeout \u003d NO_PENDING_TIMEOUT;\n+\tnew_wsi-\u003erxflow_change_to \u003d LWS_RXFLOW_ALLOW;\n+\n+\t/* initialize the instance struct */\n+\n+\tnew_wsi-\u003estate \u003d LWSS_CGI;\n+\tnew_wsi-\u003emode \u003d LWSCM_CGI;\n+\tnew_wsi-\u003ehdr_parsing_completed \u003d 0;\n+\tnew_wsi-\u003eposition_in_fds_table \u003d -1;\n+\n+\t/*\n+\t * these can only be set once the protocol is known\n+\t * we set an unestablished connection's protocol pointer\n+\t * to the start of the defauly vhost supported list, so it can look\n+\t * for matching ones during the handshake\n+\t */\n+\tnew_wsi-\u003eprotocol \u003d context-\u003evhost_list-\u003eprotocols;\n+\tnew_wsi-\u003euser_space \u003d NULL;\n+\tnew_wsi-\u003eietf_spec_revision \u003d 0;\n+\tnew_wsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n+\tcontext-\u003ecount_wsi_allocated++;\n+\n+\treturn new_wsi;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len,\n+\tint timeout_secs, const struct lws_protocol_vhost_options *mp_cgienv)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tchar *env_array[30], cgi_path[400], e[1024], *p \u003d e,\n+\t *end \u003d p + sizeof(e) - 1, tok[256], *t;\n+\tstruct lws_cgi *cgi;\n+\tint n, m, i, uritok \u003d -1;\n+\n+\t/*\n+\t * give the master wsi a cgi struct\n+\t */\n+\n+\twsi-\u003ecgi \u003d lws_zalloc(sizeof(*wsi-\u003ecgi), \u0022new cgi\u0022);\n+\tif (!wsi-\u003ecgi) {\n+\t\tlwsl_err(\u0022%s: OOM\u005cn\u0022, __func__);\n+\t\treturn -1;\n+\t}\n+\n+\twsi-\u003ecgi-\u003eresponse_code \u003d HTTP_STATUS_OK;\n+\n+\tcgi \u003d wsi-\u003ecgi;\n+\tcgi-\u003ewsi \u003d wsi; /* set cgi's owning wsi */\n+\n+\t/* create pipes for [stdin|stdout] and [stderr] */\n+\n+\tfor (n \u003d 0; n \u003c 3; n++)\n+\t\tif (pipe(cgi-\u003epipe_fds[n]) \u003d\u003d -1)\n+\t\t\tgoto bail1;\n+\n+\t/* create cgi wsis for each stdin/out/err fd */\n+\n+\tfor (n \u003d 0; n \u003c 3; n++) {\n+\t\tcgi-\u003estdwsi[n] \u003d lws_create_basic_wsi(wsi-\u003econtext, wsi-\u003etsi);\n+\t\tif (!cgi-\u003estdwsi[n])\n+\t\t\tgoto bail2;\n+\t\tcgi-\u003estdwsi[n]-\u003ecgi_channel \u003d n;\n+\t\tcgi-\u003estdwsi[n]-\u003evhost \u003d wsi-\u003evhost;\n+\n+\t\tlwsl_debug(\u0022%s: cgi %p: pipe fd %d -\u003e fd %d / %d\u005cn\u0022, __func__,\n+\t\t\t cgi-\u003estdwsi[n], n, cgi-\u003epipe_fds[n][!!(n \u003d\u003d 0)],\n+\t\t\t cgi-\u003epipe_fds[n][!(n \u003d\u003d 0)]);\n+\n+\t\t/* read side is 0, stdin we want the write side, others read */\n+\t\tcgi-\u003estdwsi[n]-\u003edesc.sockfd \u003d cgi-\u003epipe_fds[n][!!(n \u003d\u003d 0)];\n+\t\tif (fcntl(cgi-\u003epipe_fds[n][!!(n \u003d\u003d 0)], F_SETFL,\n+\t\t O_NONBLOCK) \u003c 0) {\n+\t\t\tlwsl_err(\u0022%s: setting NONBLOCK failed\u005cn\u0022, __func__);\n+\t\t\tgoto bail2;\n+\t\t}\n+\t}\n+\n+\tfor (n \u003d 0; n \u003c 3; n++) {\n+\t\tlws_libuv_accept(cgi-\u003estdwsi[n], cgi-\u003estdwsi[n]-\u003edesc);\n+\t\tif (insert_wsi_socket_into_fds(wsi-\u003econtext, cgi-\u003estdwsi[n]))\n+\t\t\tgoto bail3;\n+\t\tcgi-\u003estdwsi[n]-\u003eparent \u003d wsi;\n+\t\tcgi-\u003estdwsi[n]-\u003esibling_list \u003d wsi-\u003echild_list;\n+\t\twsi-\u003echild_list \u003d cgi-\u003estdwsi[n];\n+\t}\n+\n+\tlws_change_pollfd(cgi-\u003estdwsi[LWS_STDIN], LWS_POLLIN, LWS_POLLOUT);\n+\tlws_change_pollfd(cgi-\u003estdwsi[LWS_STDOUT], LWS_POLLOUT, LWS_POLLIN);\n+\tlws_change_pollfd(cgi-\u003estdwsi[LWS_STDERR], LWS_POLLOUT, LWS_POLLIN);\n+\n+\tlwsl_debug(\u0022%s: fds in %d, out %d, err %d\u005cn\u0022, __func__,\n+\t\t cgi-\u003estdwsi[LWS_STDIN]-\u003edesc.sockfd,\n+\t\t cgi-\u003estdwsi[LWS_STDOUT]-\u003edesc.sockfd,\n+\t\t cgi-\u003estdwsi[LWS_STDERR]-\u003edesc.sockfd);\n+\n+\tif (timeout_secs)\n+\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);\n+\n+\t/* the cgi stdout is always sending us http1.x header data first */\n+\twsi-\u003ehdr_state \u003d LCHS_HEADER;\n+\n+\t/* add us to the pt list of active cgis */\n+\tlwsl_debug(\u0022%s: adding cgi %p to list\u005cn\u0022, __func__, wsi-\u003ecgi);\n+\tcgi-\u003ecgi_list \u003d pt-\u003ecgi_list;\n+\tpt-\u003ecgi_list \u003d cgi;\n+\n+\t/* prepare his CGI env */\n+\n+\tn \u003d 0;\n+\n+\tif (lws_is_ssl(wsi))\n+\t\tenv_array[n++] \u003d \u0022HTTPS\u003dON\u0022;\n+\tif (wsi-\u003eu.hdr.ah) {\n+\t\tstatic const unsigned char meths[] \u003d {\n+\t\t\tWSI_TOKEN_GET_URI,\n+\t\t\tWSI_TOKEN_POST_URI,\n+\t\t\tWSI_TOKEN_OPTIONS_URI,\n+\t\t\tWSI_TOKEN_PUT_URI,\n+\t\t\tWSI_TOKEN_PATCH_URI,\n+\t\t\tWSI_TOKEN_DELETE_URI,\n+\t\t\tWSI_TOKEN_CONNECT,\n+\t\t\tWSI_TOKEN_HEAD_URI,\n+\t\t#ifdef LWS_WITH_HTTP2\n+\t\t\tWSI_TOKEN_HTTP_COLON_PATH,\n+\t\t#endif\n+\t\t};\n+\t\tstatic const char * const meth_names[] \u003d {\n+\t\t\t\u0022GET\u0022, \u0022POST\u0022, \u0022OPTIONS\u0022, \u0022PUT\u0022, \u0022PATCH\u0022, \u0022DELETE\u0022,\n+\t\t\t\u0022CONNECT\u0022, \u0022:path\u0022\n+\t\t};\n+\n+\t\tif (script_uri_path_len \u003e\u003d 0)\n+\t\t\tfor (m \u003d 0; m \u003c ARRAY_SIZE(meths); m++)\n+\t\t\t\tif (lws_hdr_total_length(wsi, meths[m]) \u003e\u003d\n+\t\t\t\t\t\tscript_uri_path_len) {\n+\t\t\t\t\turitok \u003d meths[m];\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\n+\t\tif (script_uri_path_len \u003c 0 \u0026\u0026 uritok \u003c 0)\n+\t\t\tgoto bail3;\n+//\t\tif (script_uri_path_len \u003c 0)\n+//\t\t\turitok \u003d 0;\n+\n+\t\tif (uritok \u003e\u003d 0) {\n+\t\t\tlws_snprintf(cgi_path, sizeof(cgi_path) - 1,\n+\t\t\t\t \u0022REQUEST_URI\u003d%s\u0022,\n+\t\t\t\t lws_hdr_simple_ptr(wsi, uritok));\n+\t\t\tcgi_path[sizeof(cgi_path) - 1] \u003d '\u005c0';\n+\t\t\tenv_array[n++] \u003d cgi_path;\n+\t\t}\n+\n+\t\tif (m \u003e\u003d 0) {\n+\t\t\tenv_array[n++] \u003d p;\n+\t\t\tif (m \u003c 8)\n+\t\t\t\tp +\u003d lws_snprintf(p, end - p,\n+\t\t\t\t\t\t \u0022REQUEST_METHOD\u003d%s\u0022,\n+\t\t\t\t\t\t meth_names[m]);\n+\t\t\telse\n+\t\t\t\tp +\u003d lws_snprintf(p, end - p,\n+\t\t\t\t\t\t \u0022REQUEST_METHOD\u003d%s\u0022,\n+\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD));\n+\t\t\tp++;\n+\t\t}\n+\n+\t\tenv_array[n++] \u003d p;\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022QUERY_STRING\u003d\u0022);\n+\t\t/* dump the individual URI Arg parameters */\n+\t\tm \u003d 0;\n+\t\twhile (script_uri_path_len \u003e\u003d 0) {\n+\t\t\ti \u003d lws_hdr_copy_fragment(wsi, tok, sizeof(tok),\n+\t\t\t\t\t WSI_TOKEN_HTTP_URI_ARGS, m);\n+\t\t\tif (i \u003c 0)\n+\t\t\t\tbreak;\n+\t\t\tt \u003d tok;\n+\t\t\twhile (*t \u0026\u0026 *t !\u003d '\u003d' \u0026\u0026 p \u003c end - 4)\n+\t\t\t\t*p++ \u003d *t++;\n+\t\t\tif (*t \u003d\u003d '\u003d')\n+\t\t\t\t*p++ \u003d *t++;\n+\t\t\ti \u003d urlencode(t, i- (t - tok), p, end - p);\n+\t\t\tif (i \u003e 0) {\n+\t\t\t\tp +\u003d i;\n+\t\t\t\t*p++ \u003d '\u0026';\n+\t\t\t}\n+\t\t\tm++;\n+\t\t}\n+\t\tif (m)\n+\t\t\tp--;\n+\t\t*p++ \u003d '\u005c0';\n+\n+\t\tif (script_uri_path_len \u003e\u003d 0) {\n+\t\t\tenv_array[n++] \u003d p;\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022PATH_INFO\u003d%s\u0022,\n+\t\t\t\t lws_hdr_simple_ptr(wsi, uritok) +\n+\t\t\t\t script_uri_path_len);\n+\t\t\tp++;\n+\t\t}\n+\t}\n+\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n+\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) {\n+\t\tenv_array[n++] \u003d p;\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022HTTP_REFERER\u003d%s\u0022,\n+\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_REFERER));\n+\t\tp++;\n+\t}\n+\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n+\t lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {\n+\t\tenv_array[n++] \u003d p;\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022HTTP_HOST\u003d%s\u0022,\n+\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));\n+\t\tp++;\n+\t}\n+\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n+\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {\n+\t\tenv_array[n++] \u003d p;\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022HTTP_COOKIE\u003d%s\u0022,\n+\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COOKIE));\n+\t\tp++;\n+\t}\n+\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n+\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) {\n+\t\tenv_array[n++] \u003d p;\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022USER_AGENT\u003d%s\u0022,\n+\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT));\n+\t\tp++;\n+\t}\n+\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n+\t uritok \u003d\u003d WSI_TOKEN_POST_URI) {\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {\n+\t\t\tenv_array[n++] \u003d p;\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022CONTENT_TYPE\u003d%s\u0022,\n+\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE));\n+\t\t\tp++;\n+\t\t}\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n+\t\t\tenv_array[n++] \u003d p;\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022CONTENT_LENGTH\u003d%s\u0022,\n+\t\t\t\t\t lws_hdr_simple_ptr(wsi,\n+\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH));\n+\t\t\tp++;\n+\t\t}\n+\t}\n+\tenv_array[n++] \u003d \u0022PATH\u003d/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin\u0022;\n+\n+\tenv_array[n++] \u003d p;\n+\tp +\u003d lws_snprintf(p, end - p, \u0022SCRIPT_PATH\u003d%s\u0022, exec_array[0]) + 1;\n+\n+\twhile (mp_cgienv) {\n+\t\tenv_array[n++] \u003d p;\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022%s\u003d%s\u0022, mp_cgienv-\u003ename,\n+\t\t\t mp_cgienv-\u003evalue);\n+\t\tlwsl_debug(\u0022 Applying mount-specific cgi env '%s'\u005cn\u0022,\n+\t\t\t env_array[n - 1]);\n+\t\tp++;\n+\t\tmp_cgienv \u003d mp_cgienv-\u003enext;\n+\t}\n+\n+\tenv_array[n++] \u003d \u0022SERVER_SOFTWARE\u003dlibwebsockets\u0022;\n+\tenv_array[n] \u003d NULL;\n+\n+#if 0\n+\tfor (m \u003d 0; m \u003c n; m++)\n+\t\tlwsl_err(\u0022 %s\u005cn\u0022, env_array[m]);\n+#endif\n+\n+\t/*\n+\t * Actually having made the env, as a cgi we don't need the ah\n+\t * any more\n+\t */\n+\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n+\t lws_header_table_is_in_detachable_state(wsi))\n+\t\tlws_header_table_detach(wsi, 0);\n+\n+\t/* we are ready with the redirection pipes... run the thing */\n+#if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)\n+\tcgi-\u003epid \u003d fork();\n+#else\n+\tcgi-\u003epid \u003d vfork();\n+#endif\n+\tif (cgi-\u003epid \u003c 0) {\n+\t\tlwsl_err(\u0022fork failed, errno %d\u0022, errno);\n+\t\tgoto bail3;\n+\t}\n+\n+#if defined(__linux__)\n+\tprctl(PR_SET_PDEATHSIG, SIGTERM);\n+#endif\n+\tif (script_uri_path_len \u003e\u003d 0)\n+\t\t/* stops non-daemonized main processess getting SIGINT\n+\t\t * from TTY */\n+\t\tsetpgrp();\n+\n+\tif (cgi-\u003epid) {\n+\t\t/* we are the parent process */\n+\t\twsi-\u003econtext-\u003ecount_cgi_spawned++;\n+\t\tlwsl_debug(\u0022%s: cgi %p spawned PID %d\u005cn\u0022, __func__,\n+\t\t\t cgi, cgi-\u003epid);\n+\n+\t\tfor (n \u003d 0; n \u003c 3; n++)\n+\t\t\tclose(cgi-\u003epipe_fds[n][!(n \u003d\u003d 0)]);\n+\n+\t\t/* inform cgi owner of the child PID */\n+\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback, wsi,\n+\t\t\t\t\t LWS_CALLBACK_CGI_PROCESS_ATTACH,\n+\t\t\t\t\t wsi-\u003euser_space, NULL, cgi-\u003epid);\n+\t\t(void)n;\n+\n+\t\treturn 0;\n+\t}\n+\n+\t/* somewhere we can at least read things and enter it */\n+\tif (chdir(\u0022/tmp\u0022))\n+\t\tlwsl_notice(\u0022%s: Failed to chdir\u005cn\u0022, __func__);\n+\n+\t/* We are the forked process, redirect and kill inherited things.\n+\t *\n+\t * Because of vfork(), we cannot do anything that changes pages in\n+\t * the parent environment. Stuff that changes kernel state for the\n+\t * process is OK. Stuff that happens after the execvpe() is OK.\n+\t */\n+\n+\tfor (n \u003d 0; n \u003c 3; n++) {\n+\t\tif (dup2(cgi-\u003epipe_fds[n][!(n \u003d\u003d 0)], n) \u003c 0) {\n+\t\t\tlwsl_err(\u0022%s: stdin dup2 failed\u005cn\u0022, __func__);\n+\t\t\tgoto bail3;\n+\t\t}\n+\t\tclose(cgi-\u003epipe_fds[n][!(n \u003d\u003d 0)]);\n+\t}\n+\n+#if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)\n+\tfor (m \u003d 0; m \u003c n; m++) {\n+\t\tp \u003d strchr(env_array[m], '\u003d');\n+\t\t*p++ \u003d '\u005c0';\n+\t\tsetenv(env_array[m], p, 1);\n+\t}\n+\texecvp(exec_array[0], (char * const *)\u0026exec_array[0]);\n+#else\n+\texecvpe(exec_array[0], (char * const *)\u0026exec_array[0], \u0026env_array[0]);\n+#endif\n+\n+\texit(1);\n+\n+bail3:\n+\t/* drop us from the pt cgi list */\n+\tpt-\u003ecgi_list \u003d cgi-\u003ecgi_list;\n+\n+\twhile (--n \u003e\u003d 0)\n+\t\tremove_wsi_socket_from_fds(wsi-\u003ecgi-\u003estdwsi[n]);\n+bail2:\n+\tfor (n \u003d 0; n \u003c 3; n++)\n+\t\tif (wsi-\u003ecgi-\u003estdwsi[n])\n+\t\t\tlws_free_wsi(cgi-\u003estdwsi[n]);\n+\n+bail1:\n+\tfor (n \u003d 0; n \u003c 3; n++) {\n+\t\tif (cgi-\u003epipe_fds[n][0])\n+\t\t\tclose(cgi-\u003epipe_fds[n][0]);\n+\t\tif (cgi-\u003epipe_fds[n][1])\n+\t\t\tclose(cgi-\u003epipe_fds[n][1]);\n+\t}\n+\n+\tlws_free_set_NULL(wsi-\u003ecgi);\n+\n+\tlwsl_err(\u0022%s: failed\u005cn\u0022, __func__);\n+\n+\treturn -1;\n+}\n+\n+/* we have to parse out these headers in the CGI output */\n+\n+static const char * const significant_hdr[SIGNIFICANT_HDR_COUNT] \u003d {\n+\t\u0022content-length: \u0022,\n+\t\u0022location: \u0022,\n+\t\u0022status: \u0022,\n+\t\u0022transfer-encoding: chunked\u0022,\n+};\n+\n+enum header_recode {\n+\tHR_NAME,\n+\tHR_WHITESPACE,\n+\tHR_ARG,\n+\tHR_CRLF,\n+};\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_cgi_write_split_stdout_headers(struct lws *wsi)\n+{\n+\tint n, m, cmd;\n+\tunsigned char buf[LWS_PRE + 1024], *start \u003d \u0026buf[LWS_PRE], *p \u003d start,\n+\t\t\t*end \u003d \u0026buf[sizeof(buf) - 1 - LWS_PRE], *name,\n+\t\t\t*value \u003d NULL;\n+\tchar c, hrs;\n+\n+\tif (!wsi-\u003ecgi)\n+\t\treturn -1;\n+\n+\twhile (wsi-\u003ehdr_state !\u003d LHCS_PAYLOAD) {\n+\t\t/*\n+\t\t * We have to separate header / finalize and payload chunks,\n+\t\t * since they need to be handled separately\n+\t\t */\n+\t\tswitch (wsi-\u003ehdr_state) {\n+\t\tcase LHCS_RESPONSE:\n+\t\t\tlwsl_debug(\u0022LHCS_RESPONSE: issuing response %d\u005cn\u0022,\n+\t\t\t\t wsi-\u003ecgi-\u003eresponse_code);\n+\t\t\tif (lws_add_http_header_status(wsi,\n+\t\t\t\t\t\t wsi-\u003ecgi-\u003eresponse_code,\n+\t\t\t\t\t\t \u0026p, end))\n+\t\t\t\treturn 1;\n+\t\t\tif (!wsi-\u003ecgi-\u003eexplicitly_chunked \u0026\u0026\n+\t\t\t !wsi-\u003ecgi-\u003econtent_length \u0026\u0026\n+\t\t\t\tlws_add_http_header_by_token(wsi,\n+\t\t\t\t\tWSI_TOKEN_HTTP_TRANSFER_ENCODING,\n+\t\t\t\t\t(unsigned char *)\u0022chunked\u0022, 7, \u0026p, end))\n+\t\t\t\treturn 1;\n+\t\t\tif (!(wsi-\u003ehttp2_substream))\n+\t\t\t\tif (lws_add_http_header_by_token(wsi,\n+\t\t\t\t\t\tWSI_TOKEN_CONNECTION,\n+\t\t\t\t\t\t(unsigned char *)\u0022close\u0022, 5,\n+\t\t\t\t\t\t\u0026p, end))\n+\t\t\t\t\treturn 1;\n+\t\t\tn \u003d lws_write(wsi, start, p - start,\n+\t\t\t\t LWS_WRITE_HTTP_HEADERS | LWS_WRITE_NO_FIN);\n+\n+\t\t\t/*\n+\t\t\t * so we have a bunch of http/1 style ascii headers\n+\t\t\t * starting from wsi-\u003ecgi-\u003eheaders_buf through\n+\t\t\t * wsi-\u003ecgi-\u003eheaders_pos. These are OK for http/1\n+\t\t\t * connections, but they're no good for http/2 conns.\n+\t\t\t *\n+\t\t\t * Let's redo them at headers_pos forward using the\n+\t\t\t * correct coding for http/1 or http/2\n+\t\t\t */\n+\t\t\tif (!wsi-\u003ehttp2_substream)\n+\t\t\t\tgoto post_hpack_recode;\n+\n+\t\t\tp \u003d wsi-\u003ecgi-\u003eheaders_start;\n+\t\t\twsi-\u003ecgi-\u003eheaders_start \u003d wsi-\u003ecgi-\u003eheaders_pos;\n+\t\t\twsi-\u003ecgi-\u003eheaders_dumped \u003d wsi-\u003ecgi-\u003eheaders_start;\n+\t\t\thrs \u003d HR_NAME;\n+\t\t\tname \u003d buf;\n+\n+\t\t\twhile (p \u003c wsi-\u003ecgi-\u003eheaders_start) {\n+\t\t\t\tswitch (hrs) {\n+\t\t\t\tcase HR_NAME:\n+\t\t\t\t\t/*\n+\t\t\t\t\t * in http/2 upper-case header names\n+\t\t\t\t\t * are illegal. So convert to lower-\n+\t\t\t\t\t * case.\n+\t\t\t\t\t */\n+\t\t\t\t\tif (name - buf \u003e 64)\n+\t\t\t\t\t\treturn -1;\n+\t\t\t\t\tif (*p !\u003d ':') {\n+\t\t\t\t\t\tif (*p \u003e\u003d 'A' \u0026\u0026 *p \u003c\u003d 'Z')\n+\t\t\t\t\t\t\t*name++ \u003d (*p++) +\n+\t\t\t\t\t\t\t\t ('a' - 'A');\n+\t\t\t\t\t\telse\n+\t\t\t\t\t\t\t*name++ \u003d *p++;\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tp++;\n+\t\t\t\t\t\t*name++ \u003d '\u005c0';\n+\t\t\t\t\t\tvalue \u003d name;\n+\t\t\t\t\t\thrs \u003d HR_WHITESPACE;\n+\t\t\t\t\t}\n+\t\t\t\t\tbreak;\n+\t\t\t\tcase HR_WHITESPACE:\n+\t\t\t\t\tif (*p \u003d\u003d ' ') {\n+\t\t\t\t\t\tp++;\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t\thrs \u003d HR_ARG;\n+\t\t\t\t\t/* fallthru */\n+\t\t\t\tcase HR_ARG:\n+\t\t\t\t\tif (name \u003e end - 64)\n+\t\t\t\t\t\treturn -1;\n+\n+\t\t\t\t\tif (*p !\u003d '\u005cx0a' \u0026\u0026 *p !\u003d '\u005cx0d') {\n+\t\t\t\t\t\t*name++ \u003d *p++;\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t\thrs \u003d HR_CRLF;\n+\t\t\t\t\t/* fallthru */\n+\t\t\t\tcase HR_CRLF:\n+\t\t\t\t\tif ((*p !\u003d '\u005cx0a' \u0026\u0026 *p !\u003d '\u005cx0d') ||\n+\t\t\t\t\t p + 1 \u003d\u003d wsi-\u003ecgi-\u003eheaders_start) {\n+\t\t\t\t\t\t*name \u003d '\u005c0';\n+\t\t\t\t\t\tif ((strcmp((const char *)buf,\n+\t\t\t\t\t\t\t \u0022transfer-encoding\u0022)\n+\t\t\t\t\t\t)) {\n+\t\t\t\t\t\t\tlwsl_debug(\u0022+ %s: %s\u005cn\u0022,\n+\t\t\t\t\t\t\t\t buf, value);\n+\t\t\t\t\t\t\tif (\n+\t\t\t\t\tlws_add_http_header_by_name(wsi, buf,\n+\t\t\t\t\t(unsigned char *)value, name - value,\n+\t\t\t\t\t(unsigned char **)\u0026wsi-\u003ecgi-\u003eheaders_pos,\n+\t\t\t\t\t(unsigned char *)wsi-\u003ecgi-\u003eheaders_end))\n+\t\t\t\t\t\t\t\treturn 1;\n+\t\t\t\t\t\t\thrs \u003d HR_NAME;\n+\t\t\t\t\t\t\tname \u003d buf;\n+\t\t\t\t\t\t\tbreak;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t\tp++;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t}\n+post_hpack_recode:\n+\t\t\t/* finalize cached headers before dumping them */\n+\t\t\tif (lws_finalize_http_header(wsi,\n+\t\t\t\t (unsigned char **)\u0026wsi-\u003ecgi-\u003eheaders_pos,\n+\t\t\t\t (unsigned char *)wsi-\u003ecgi-\u003eheaders_end)) {\n+\n+\t\t\t\tlwsl_notice(\u0022finalize failed\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\n+\t\t\twsi-\u003ehdr_state \u003d LHCS_DUMP_HEADERS;\n+\t\t\twsi-\u003ereason_bf |\u003d LWS_CB_REASON_AUX_BF__CGI_HEADERS;\n+\t\t\tlws_callback_on_writable(wsi);\n+\t\t\t/* back to the loop for writeability again */\n+\t\t\treturn 0;\n+\n+\t\tcase LHCS_DUMP_HEADERS:\n+\n+\t\t\tn \u003d wsi-\u003ecgi-\u003eheaders_pos - wsi-\u003ecgi-\u003eheaders_dumped;\n+\t\t\tif (n \u003e 512)\n+\t\t\t\tn \u003d 512;\n+\n+\t\t\tlwsl_debug(\u0022LHCS_DUMP_HEADERS: %d\u005cn\u0022, n);\n+\n+\t\t\tcmd \u003d LWS_WRITE_HTTP_HEADERS_CONTINUATION;\n+\t\t\tif (wsi-\u003ecgi-\u003eheaders_dumped + n !\u003d\n+\t\t\t wsi-\u003ecgi-\u003eheaders_pos) {\n+\t\t\t\tlwsl_notice(\u0022adding no fin flag\u005cn\u0022);\n+\t\t\t\tcmd |\u003d LWS_WRITE_NO_FIN;\n+\t\t\t}\n+\n+\t\t\tm \u003d lws_write(wsi,\n+\t\t\t\t (unsigned char *)wsi-\u003ecgi-\u003eheaders_dumped,\n+\t\t\t\t n, cmd);\n+\t\t\tif (m \u003c 0) {\n+\t\t\t\tlwsl_debug(\u0022%s: write says %d\u005cn\u0022, __func__, m);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\twsi-\u003ecgi-\u003eheaders_dumped +\u003d n;\n+\t\t\tif (wsi-\u003ecgi-\u003eheaders_dumped \u003d\u003d wsi-\u003ecgi-\u003eheaders_pos) {\n+\t\t\t\twsi-\u003ehdr_state \u003d LHCS_PAYLOAD;\n+\t\t\t\tlws_free_set_NULL(wsi-\u003ecgi-\u003eheaders_buf);\n+\t\t\t\tlwsl_debug(\u0022freed cgi headers\u005cn\u0022);\n+\t\t\t} else {\n+\t\t\t\twsi-\u003ereason_bf |\u003d LWS_CB_REASON_AUX_BF__CGI_HEADERS;\n+\t\t\t\tlws_callback_on_writable(wsi);\n+\t\t\t}\n+\n+\t\t\t/* writeability becomes uncertain now we wrote\n+\t\t\t * something, we must return to the event loop\n+\t\t\t */\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\tif (!wsi-\u003ecgi-\u003eheaders_buf) {\n+\t\t\t/* if we don't already have a headers buf, cook one up */\n+\t\t\tn \u003d 2048;\n+\t\t\tif (wsi-\u003ehttp2_substream)\n+\t\t\t\tn \u003d 4096;\n+\t\t\twsi-\u003ecgi-\u003eheaders_buf \u003d lws_malloc(n + LWS_PRE,\n+\t\t\t\t\t\t\t \u0022cgi hdr buf\u0022);\n+\t\t\tif (!wsi-\u003ecgi-\u003eheaders_buf) {\n+\t\t\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\n+\t\t\tlwsl_debug(\u0022allocated cgi hdrs\u005cn\u0022);\n+\t\t\twsi-\u003ecgi-\u003eheaders_start \u003d wsi-\u003ecgi-\u003eheaders_buf + LWS_PRE;\n+\t\t\twsi-\u003ecgi-\u003eheaders_pos \u003d wsi-\u003ecgi-\u003eheaders_start;\n+\t\t\twsi-\u003ecgi-\u003eheaders_dumped \u003d wsi-\u003ecgi-\u003eheaders_pos;\n+\t\t\twsi-\u003ecgi-\u003eheaders_end \u003d wsi-\u003ecgi-\u003eheaders_buf + n - 1;\n+\n+\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++) {\n+\t\t\t\twsi-\u003ecgi-\u003ematch[n] \u003d 0;\n+\t\t\t\twsi-\u003ecgi-\u003elp \u003d 0;\n+\t\t\t}\n+\t\t}\n+\n+\t\tn \u003d lws_get_socket_fd(wsi-\u003ecgi-\u003estdwsi[LWS_STDOUT]);\n+\t\tif (n \u003c 0)\n+\t\t\treturn -1;\n+\t\tn \u003d read(n, \u0026c, 1);\n+\t\tif (n \u003c 0) {\n+\t\t\tif (errno !\u003d EAGAIN) {\n+\t\t\t\tlwsl_debug(\u0022%s: read says %d\u005cn\u0022, __func__, n);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\telse\n+\t\t\t\tn \u003d 0;\n+\n+\t\t\tif (wsi-\u003ecgi-\u003eheaders_pos \u003e\u003d wsi-\u003ecgi-\u003eheaders_end - 4) {\n+\t\t\t\tlwsl_notice(\u0022CGI hdrs \u003e buf size\u005cn\u0022);\n+\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\t\tif (!n)\n+\t\t\tgoto agin;\n+\n+\t\tlwsl_debug(\u0022-- 0x%02X %c %d %d\u005cn\u0022, (unsigned char)c, c,\n+\t\t\t wsi-\u003ecgi-\u003ematch[1], wsi-\u003ehdr_state);\n+\t\tif (!c)\n+\t\t\treturn -1;\n+\t\tswitch (wsi-\u003ehdr_state) {\n+\t\tcase LCHS_HEADER:\n+\t\t\thdr:\n+\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++) {\n+\t\t\t\t/*\n+\t\t\t\t * significant headers with\n+\t\t\t\t * numeric decimal payloads\n+\t\t\t\t */\n+\t\t\t\tif (!significant_hdr[n][wsi-\u003ecgi-\u003ematch[n]] \u0026\u0026\n+\t\t\t\t (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9') \u0026\u0026\n+\t\t\t\t wsi-\u003ecgi-\u003elp \u003c sizeof(wsi-\u003ecgi-\u003el) - 1) {\n+\t\t\t\t\twsi-\u003ecgi-\u003el[wsi-\u003ecgi-\u003elp++] \u003d c;\n+\t\t\t\t\twsi-\u003ecgi-\u003el[wsi-\u003ecgi-\u003elp] \u003d '\u005c0';\n+\t\t\t\t\tswitch (n) {\n+\t\t\t\t\tcase SIGNIFICANT_HDR_CONTENT_LENGTH:\n+\t\t\t\t\t\twsi-\u003ecgi-\u003econtent_length \u003d\n+\t\t\t\t\t\t\tatoll(wsi-\u003ecgi-\u003el);\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\tcase SIGNIFICANT_HDR_STATUS:\n+\t\t\t\t\t\twsi-\u003ecgi-\u003eresponse_code \u003d\n+\t\t\t\t\t\t\tatol(wsi-\u003ecgi-\u003el);\n+\t\t\t\t\t\tlwsl_debug(\u0022Status set to %d\u005cn\u0022,\n+\t\t\t\t\t\t wsi-\u003ecgi-\u003eresponse_code);\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\tdefault:\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\t/* hits up to the NUL are sticky until next hdr */\n+\t\t\t\tif (significant_hdr[n][wsi-\u003ecgi-\u003ematch[n]]) {\n+\t\t\t\t\tif (tolower(c) \u003d\u003d\n+\t\t\t\t\t significant_hdr[n][wsi-\u003ecgi-\u003ematch[n]])\n+\t\t\t\t\t\twsi-\u003ecgi-\u003ematch[n]++;\n+\t\t\t\t\telse\n+\t\t\t\t\t\twsi-\u003ecgi-\u003ematch[n] \u003d 0;\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\t/* some cgi only send us \u005cx0a for EOL */\n+\t\t\tif (c \u003d\u003d '\u005cx0a') {\n+\t\t\t\twsi-\u003ehdr_state \u003d LCHS_SINGLE_0A;\n+\t\t\t\t*wsi-\u003ecgi-\u003eheaders_pos++ \u003d '\u005cx0d';\n+\t\t\t}\n+\t\t\t*wsi-\u003ecgi-\u003eheaders_pos++ \u003d c;\n+\t\t\tif (c \u003d\u003d '\u005cx0d')\n+\t\t\t\twsi-\u003ehdr_state \u003d LCHS_LF1;\n+\n+\t\t\tif (wsi-\u003ehdr_state !\u003d LCHS_HEADER \u0026\u0026\n+\t\t\t !significant_hdr[SIGNIFICANT_HDR_TRANSFER_ENCODING]\n+\t\t\t\t [wsi-\u003ecgi-\u003ematch[\n+\t\t\t\t\t SIGNIFICANT_HDR_TRANSFER_ENCODING]]) {\n+\t\t\t\tlwsl_debug(\u0022cgi produced chunked\u005cn\u0022);\n+\t\t\t\twsi-\u003ecgi-\u003eexplicitly_chunked \u003d 1;\n+\t\t\t}\n+\n+\t\t\t/* presence of Location: mandates 302 retcode */\n+\t\t\tif (wsi-\u003ehdr_state !\u003d LCHS_HEADER \u0026\u0026\n+\t\t\t !significant_hdr[SIGNIFICANT_HDR_LOCATION][\n+\t\t\t\t wsi-\u003ecgi-\u003ematch[SIGNIFICANT_HDR_LOCATION]]) {\n+\t\t\t\tlwsl_debug(\u0022CGI: Location hdr seen\u005cn\u0022);\n+\t\t\t\twsi-\u003ecgi-\u003eresponse_code \u003d 302;\n+\t\t\t}\n+\n+\t\t\tbreak;\n+\t\tcase LCHS_LF1:\n+\t\t\t*wsi-\u003ecgi-\u003eheaders_pos++ \u003d c;\n+\t\t\tif (c \u003d\u003d '\u005cx0a') {\n+\t\t\t\twsi-\u003ehdr_state \u003d LCHS_CR2;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\t/* we got \u005cr[^\u005cn]... it's unreasonable */\n+\t\t\tlwsl_debug(\u0022%s: funny CRLF 0x%02X\u005cn\u0022, __func__,\n+\t\t\t\t (unsigned char)c);\n+\t\t\treturn -1;\n+\n+\t\tcase LCHS_CR2:\n+\t\t\tif (c \u003d\u003d '\u005cx0d') {\n+\t\t\t\t/* drop the \u005cx0d */\n+\t\t\t\twsi-\u003ehdr_state \u003d LCHS_LF2;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\twsi-\u003ehdr_state \u003d LCHS_HEADER;\n+\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++)\n+\t\t\t\twsi-\u003ecgi-\u003ematch[n] \u003d 0;\n+\t\t\twsi-\u003ecgi-\u003elp \u003d 0;\n+\t\t\tgoto hdr;\n+\n+\t\tcase LCHS_LF2:\n+\t\tcase LCHS_SINGLE_0A:\n+\t\t\tm \u003d wsi-\u003ehdr_state;\n+\t\t\tif (c \u003d\u003d '\u005cx0a') {\n+\t\t\t\tlwsl_debug(\u0022Content-Length: %lld\u005cn\u0022,\n+\t\t\t\t\t(unsigned long long)\n+\t\t\t\t\twsi-\u003ecgi-\u003econtent_length);\n+\t\t\t\twsi-\u003ehdr_state \u003d LHCS_RESPONSE;\n+\t\t\t\t/*\n+\t\t\t\t * drop the \u005c0xa ... finalize\n+\t\t\t\t * will add it if needed (HTTP/1)\n+\t\t\t\t */\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (m \u003d\u003d LCHS_LF2)\n+\t\t\t\t/* we got \u005cr\u005cn\u005cr[^\u005cn]... unreasonable */\n+\t\t\t\treturn -1;\n+\t\t\t/* we got \u005cx0anext header, it's reasonable */\n+\t\t\t*wsi-\u003ecgi-\u003eheaders_pos++ \u003d c;\n+\t\t\twsi-\u003ehdr_state \u003d LCHS_HEADER;\n+\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++)\n+\t\t\t\twsi-\u003ecgi-\u003ematch[n] \u003d 0;\n+\t\t\twsi-\u003ecgi-\u003elp \u003d 0;\n+\t\t\tbreak;\n+\t\tcase LHCS_PAYLOAD:\n+\t\t\tbreak;\n+\t\t}\n+\n+agin:\n+\t\t/* ran out of input, ended the hdrs, or filled up the hdrs buf */\n+\t\tif (!n || wsi-\u003ehdr_state \u003d\u003d LHCS_PAYLOAD)\n+\t\t\treturn 0;\n+\t}\n+\n+\t/* payload processing */\n+\n+\tm \u003d !wsi-\u003ecgi-\u003eexplicitly_chunked \u0026\u0026 !wsi-\u003ecgi-\u003econtent_length;\n+\tn \u003d lws_get_socket_fd(wsi-\u003ecgi-\u003estdwsi[LWS_STDOUT]);\n+\tif (n \u003c 0)\n+\t\treturn -1;\n+\tn \u003d read(n, start, sizeof(buf) - LWS_PRE -\n+\t\t\t (m ? LWS_HTTP_CHUNK_HDR_SIZE : 0));\n+\n+\tif (n \u003c 0 \u0026\u0026 errno !\u003d EAGAIN) {\n+\t\tlwsl_debug(\u0022%s: stdout read says %d\u005cn\u0022, __func__, n);\n+\t\treturn -1;\n+\t}\n+\tif (n \u003e 0) {\n+\t\tif (!wsi-\u003ehttp2_substream \u0026\u0026 m) {\n+\t\t\tchar chdr[LWS_HTTP_CHUNK_HDR_SIZE];\n+\t\t\tm \u003d lws_snprintf(chdr, LWS_HTTP_CHUNK_HDR_SIZE - 3,\n+\t\t\t\t\t \u0022%X\u005cx0d\u005cx0a\u0022, n);\n+\t\t\tmemmove(start + m, start, n);\n+\t\t\tmemcpy(start, chdr, m);\n+\t\t\tmemcpy(start + m + n, \u0022\u005cx0d\u005cx0a\u0022, 2);\n+\t\t\tn +\u003d m + 2;\n+\t\t}\n+\t\tcmd \u003d LWS_WRITE_HTTP;\n+\t\tif (wsi-\u003ecgi-\u003econtent_length_seen + n \u003d\u003d wsi-\u003ecgi-\u003econtent_length)\n+\t\t\tcmd \u003d LWS_WRITE_HTTP_FINAL;\n+\t\tm \u003d lws_write(wsi, (unsigned char *)start, n, cmd);\n+\t\t//lwsl_notice(\u0022write %d\u005cn\u0022, m);\n+\t\tif (m \u003c 0) {\n+\t\t\tlwsl_debug(\u0022%s: stdout write says %d\u005cn\u0022, __func__, m);\n+\t\t\treturn -1;\n+\t\t}\n+\t\twsi-\u003ecgi-\u003econtent_length_seen +\u003d n;\n+\t} else {\n+\t\tif (wsi-\u003ecgi_stdout_zero_length) {\n+\t\t\tlwsl_debug(\u0022%s: stdout is POLLHUP'd\u005cn\u0022, __func__);\n+\t\t\tif (wsi-\u003ehttp2_substream)\n+\t\t\t\tm \u003d lws_write(wsi, (unsigned char *)start, 0,\n+\t\t\t\t\t LWS_WRITE_HTTP_FINAL);\n+\t\t\treturn 1;\n+\t\t}\n+\t\twsi-\u003ecgi_stdout_zero_length \u003d 1;\n+\t}\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_cgi_kill(struct lws *wsi)\n+{\n+\tstruct lws_cgi_args args;\n+\tint status, n;\n+\n+\tlwsl_debug(\u0022%s: %p\u005cn\u0022, __func__, wsi);\n+\n+\tif (!wsi-\u003ecgi)\n+\t\treturn 0;\n+\n+\tif (wsi-\u003ecgi-\u003epid \u003e 0) {\n+\t\tn \u003d waitpid(wsi-\u003ecgi-\u003epid, \u0026status, WNOHANG);\n+\t\tif (n \u003e 0) {\n+\t\t\tlwsl_debug(\u0022%s: PID %d reaped\u005cn\u0022, __func__,\n+\t\t\t\t wsi-\u003ecgi-\u003epid);\n+\t\t\tgoto handled;\n+\t\t}\n+\t\t/* kill the process group */\n+\t\tn \u003d kill(-wsi-\u003ecgi-\u003epid, SIGTERM);\n+\t\tlwsl_debug(\u0022%s: SIGTERM child PID %d says %d (errno %d)\u005cn\u0022,\n+\t\t\t __func__, wsi-\u003ecgi-\u003epid, n, errno);\n+\t\tif (n \u003c 0) {\n+\t\t\t/*\n+\t\t\t * hum seen errno\u003d3 when process is listed in ps,\n+\t\t\t * it seems we don't always retain process grouping\n+\t\t\t *\n+\t\t\t * Direct these fallback attempt to the exact child\n+\t\t\t */\n+\t\t\tn \u003d kill(wsi-\u003ecgi-\u003epid, SIGTERM);\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tn \u003d kill(wsi-\u003ecgi-\u003epid, SIGPIPE);\n+\t\t\t\tif (n \u003c 0) {\n+\t\t\t\t\tn \u003d kill(wsi-\u003ecgi-\u003epid, SIGKILL);\n+\t\t\t\t\tif (n \u003c 0)\n+\t\t\t\t\t\tlwsl_err(\u0022%s: SIGKILL PID %d \u0022\n+\t\t\t\t\t\t\t \u0022failed errno %d \u0022\n+\t\t\t\t\t\t\t \u0022(maybe zombie)\u005cn\u0022,\n+\t\t\t\t\t\t\t __func__,\n+\t\t\t\t\t\t\t wsi-\u003ecgi-\u003epid, errno);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\t/* He could be unkillable because he's a zombie */\n+\t\tn \u003d 1;\n+\t\twhile (n \u003e 0) {\n+\t\t\tn \u003d waitpid(-wsi-\u003ecgi-\u003epid, \u0026status, WNOHANG);\n+\t\t\tif (n \u003e 0)\n+\t\t\t\tlwsl_debug(\u0022%s: reaped PID %d\u005cn\u0022, __func__, n);\n+\t\t\tif (n \u003c\u003d 0) {\n+\t\t\t\tn \u003d waitpid(wsi-\u003ecgi-\u003epid, \u0026status, WNOHANG);\n+\t\t\t\tif (n \u003e 0)\n+\t\t\t\t\tlwsl_debug(\u0022%s: reaped PID %d\u005cn\u0022,\n+\t\t\t\t\t\t __func__, n);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+handled:\n+\targs.stdwsi \u003d \u0026wsi-\u003ecgi-\u003estdwsi[0];\n+\n+\tif (wsi-\u003ecgi-\u003epid !\u003d -1) {\n+\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback, wsi,\n+\t\t\t\t\t\tLWS_CALLBACK_CGI_TERMINATED,\n+\t\t\t\t\t\twsi-\u003euser_space,\n+\t\t\t\t\t\t(void *)\u0026args, wsi-\u003ecgi-\u003epid);\n+\t\twsi-\u003ecgi-\u003epid \u003d -1;\n+\t\tif (n \u0026\u0026 !wsi-\u003ecgi-\u003ebeing_closed)\n+\t\t\tlws_close_free_wsi(wsi, 0);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_EXTERN int\n+lws_cgi_kill_terminated(struct lws_context_per_thread *pt)\n+{\n+\tstruct lws_cgi **pcgi, *cgi \u003d NULL;\n+\tint status, n \u003d 1;\n+\n+\twhile (n \u003e 0) {\n+\t\t/* find finished guys but don't reap yet */\n+\t\tn \u003d waitpid(-1, \u0026status, WNOHANG);\n+\t\tif (n \u003c\u003d 0)\n+\t\t\tcontinue;\n+\t\tlwsl_debug(\u0022%s: observed PID %d terminated\u005cn\u0022, __func__, n);\n+\n+\t\tpcgi \u003d \u0026pt-\u003ecgi_list;\n+\n+\t\t/* check all the subprocesses on the cgi list */\n+\t\twhile (*pcgi) {\n+\t\t\t/* get the next one first as list may change */\n+\t\t\tcgi \u003d *pcgi;\n+\t\t\tpcgi \u003d \u0026(*pcgi)-\u003ecgi_list;\n+\n+\t\t\tif (cgi-\u003epid \u003c\u003d 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\t/* finish sending cached headers */\n+\t\t\tif (cgi-\u003eheaders_buf)\n+\t\t\t\tcontinue;\n+\n+\t\t\t/* wait for stdout to be drained */\n+\t\t\tif (cgi-\u003econtent_length \u003e cgi-\u003econtent_length_seen)\n+\t\t\t\tcontinue;\n+\n+\t\t\tif (cgi-\u003econtent_length) {\n+\t\t\t\tlwsl_debug(\u0022%s: wsi %p: expected content length seen: %lld\u005cn\u0022,\n+\t\t\t\t\t__func__, cgi-\u003ewsi,\n+\t\t\t\t\t(unsigned long long)cgi-\u003econtent_length_seen);\n+\t\t\t}\n+\n+\t\t\t/* reap it */\n+\t\t\twaitpid(n, \u0026status, WNOHANG);\n+\t\t\t/*\n+\t\t\t * he's already terminated so no need for kill()\n+\t\t\t * but we should do the terminated cgi callback\n+\t\t\t * and close him if he's not already closing\n+\t\t\t */\n+\t\t\tif (n \u003d\u003d cgi-\u003epid) {\n+\t\t\t\tlwsl_debug(\u0022%s: found PID %d on cgi list\u005cn\u0022,\n+\t\t\t\t\t __func__, n);\n+\n+\t\t\t\tif (!cgi-\u003econtent_length) {\n+\t\t\t\t\t/*\n+\t\t\t\t\t * well, if he sends chunked...\n+\t\t\t\t\t * give him 2s after the\n+\t\t\t\t\t * cgi terminated to send buffered\n+\t\t\t\t\t */\n+\t\t\t\t\tcgi-\u003echunked_grace++;\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\n+\t\t\t\t/* defeat kill() */\n+\t\t\t\tcgi-\u003epid \u003d 0;\n+\t\t\t\tlws_cgi_kill(cgi-\u003ewsi);\n+\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tcgi \u003d NULL;\n+\t\t}\n+\t\t/* if not found on the cgi list, as he's one of ours, reap */\n+\t\tif (!cgi) {\n+\t\t\tlwsl_debug(\u0022%s: reading PID %d although no cgi match\u005cn\u0022,\n+\t\t\t\t\t__func__, n);\n+\t\t\twaitpid(n, \u0026status, WNOHANG);\n+\t\t}\n+\t}\n+\n+\tpcgi \u003d \u0026pt-\u003ecgi_list;\n+\n+\t/* check all the subprocesses on the cgi list */\n+\twhile (*pcgi) {\n+\t\t/* get the next one first as list may change */\n+\t\tcgi \u003d *pcgi;\n+\t\tpcgi \u003d \u0026(*pcgi)-\u003ecgi_list;\n+\n+\t\tif (cgi-\u003epid \u003c\u003d 0)\n+\t\t\tcontinue;\n+\n+\t\t/* we deferred killing him after reaping his PID */\n+\t\tif (cgi-\u003echunked_grace) {\n+\t\t\tcgi-\u003echunked_grace++;\n+\t\t\tif (cgi-\u003echunked_grace \u003c 2)\n+\t\t\t\tcontinue;\n+\t\t\tgoto finish_him;\n+\t\t}\n+\n+\t\t/* finish sending cached headers */\n+\t\tif (cgi-\u003eheaders_buf)\n+\t\t\tcontinue;\n+\n+\t\t/* wait for stdout to be drained */\n+\t\tif (cgi-\u003econtent_length \u003e cgi-\u003econtent_length_seen)\n+\t\t\tcontinue;\n+\n+\t\tif (cgi-\u003econtent_length)\n+\t\t\tlwsl_debug(\u0022%s: wsi %p: expected content length seen: %lld\u005cn\u0022,\n+\t\t\t\t__func__, cgi-\u003ewsi,\n+\t\t\t\t(unsigned long long)cgi-\u003econtent_length_seen);\n+\n+\t\t/* reap it */\n+\t\tif (waitpid(cgi-\u003epid, \u0026status, WNOHANG) \u003e 0) {\n+\n+\t\t\tif (!cgi-\u003econtent_length) {\n+\t\t\t\t/*\n+\t\t\t\t * well, if he sends chunked...\n+\t\t\t\t * give him 2s after the\n+\t\t\t\t * cgi terminated to send buffered\n+\t\t\t\t */\n+\t\t\t\tcgi-\u003echunked_grace++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+finish_him:\n+\t\t\tlwsl_debug(\u0022%s: found PID %d on cgi list\u005cn\u0022,\n+\t\t\t\t __func__, cgi-\u003epid);\n+\n+\t\t\t/* defeat kill() */\n+\t\t\tcgi-\u003epid \u003d 0;\n+\t\t\tlws_cgi_kill(cgi-\u003ewsi);\n+\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN struct lws *\n+lws_cgi_get_stdwsi(struct lws *wsi, enum lws_enum_stdinouterr ch)\n+{\n+\tif (!wsi-\u003ecgi)\n+\t\treturn NULL;\n+\n+\treturn wsi-\u003ecgi-\u003estdwsi[ch];\n+}\n+\n+void\n+lws_cgi_remove_and_kill(struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tstruct lws_cgi **pcgi \u003d \u0026pt-\u003ecgi_list;\n+\n+\t/* remove us from the cgi list */\n+\tlwsl_debug(\u0022%s: remove cgi %p from list\u005cn\u0022, __func__, wsi-\u003ecgi);\n+\twhile (*pcgi) {\n+\t\tif (*pcgi \u003d\u003d wsi-\u003ecgi) {\n+\t\t\t/* drop us from the pt cgi list */\n+\t\t\t*pcgi \u003d (*pcgi)-\u003ecgi_list;\n+\t\t\tbreak;\n+\t\t}\n+\t\tpcgi \u003d \u0026(*pcgi)-\u003ecgi_list;\n+\t}\n+\tif (wsi-\u003ecgi-\u003eheaders_buf) {\n+\t\tlwsl_debug(\u0022close: freed cgi headers\u005cn\u0022);\n+\t\tlws_free_set_NULL(wsi-\u003ecgi-\u003eheaders_buf);\n+\t}\n+\t/* we have a cgi going, we must kill it */\n+\twsi-\u003ecgi-\u003ebeing_closed \u003d 1;\n+\tlws_cgi_kill(wsi);\n+}\ndiff --git a/lib/server/daemonize.c b/lib/server/daemonize.c\nnew file mode 100644\nindex 0000000..8ec58a3\n--- /dev/null\n+++ b/lib/server/daemonize.c\n@@ -0,0 +1,225 @@\n+/*\n+ * This code is mainly taken from Doug Potter's page\n+ *\n+ * http://www-theorie.physik.unizh.ch/~dpotter/howto/daemonize\n+ *\n+ * I contacted him 2007-04-16 about the license for the original code,\n+ * he replied it is Public Domain. Use the URL above to get the original\n+ * Public Domain version if you want it.\n+ *\n+ * This version is LGPL2.1+SLE like the rest of libwebsockets and is\n+ * Copyright (c)2006 - 2013 Andy Green \u003candy@warmcat.com\u003e\n+ */\n+\n+#include \u003cstdlib.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u003cstdio.h\u003e\n+#include \u003csignal.h\u003e\n+#include \u003csys/types.h\u003e\n+#include \u003csys/stat.h\u003e\n+#include \u003cfcntl.h\u003e\n+#include \u003climits.h\u003e\n+#include \u003cunistd.h\u003e\n+#include \u003cerrno.h\u003e\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+int pid_daemon;\n+static char *lock_path;\n+\n+int get_daemonize_pid()\n+{\n+\treturn pid_daemon;\n+}\n+\n+static void\n+child_handler(int signum)\n+{\n+\tint fd, len, sent;\n+\tchar sz[20];\n+\n+\tswitch (signum) {\n+\n+\tcase SIGALRM: /* timed out daemonizing */\n+\t\texit(0);\n+\t\tbreak;\n+\n+\tcase SIGUSR1: /* positive confirmation we daemonized well */\n+\n+\t\tif (lock_path) {\n+\t\t\t/* Create the lock file as the current user */\n+\n+\t\t\tfd \u003d open(lock_path, O_TRUNC | O_RDWR | O_CREAT, 0640);\n+\t\t\tif (fd \u003c 0) {\n+\t\t\t\tfprintf(stderr,\n+\t\t\t\t \u0022unable to create lock file %s, code\u003d%d (%s)\u005cn\u0022,\n+\t\t\t\t\tlock_path, errno, strerror(errno));\n+\t\t\t\texit(0);\n+\t\t\t}\n+\t\t\tlen \u003d sprintf(sz, \u0022%u\u0022, pid_daemon);\n+\t\t\tsent \u003d write(fd, sz, len);\n+\t\t\tif (sent !\u003d len)\n+\t\t\t\tfprintf(stderr,\n+\t\t\t\t \u0022unable to write pid to lock file %s, code\u003d%d (%s)\u005cn\u0022,\n+\t\t\t\t\t\t lock_path, errno, strerror(errno));\n+\n+\t\t\tclose(fd);\n+\t\t}\n+\t\texit(0);\n+\t\t//!!(sent \u003d\u003d len));\n+\n+\tcase SIGCHLD: /* daemonization failed */\n+\t\texit(0);\n+\t\tbreak;\n+\t}\n+}\n+\n+static void lws_daemon_closing(int sigact)\n+{\n+\tif (getpid() \u003d\u003d pid_daemon)\n+\t\tif (lock_path) {\n+\t\t\tunlink(lock_path);\n+\t\t\tlws_free_set_NULL(lock_path);\n+\t\t}\n+\n+\tkill(getpid(), SIGKILL);\n+}\n+\n+/*\n+ * You just need to call this from your main(), when it\n+ * returns you are all set \u0022in the background\u0022 decoupled\n+ * from the console you were started from.\n+ *\n+ * The process context you called from has been terminated then.\n+ */\n+\n+LWS_VISIBLE int\n+lws_daemonize(const char *_lock_path)\n+{\n+\tstruct sigaction act;\n+\tpid_t sid, parent;\n+\tint n, fd, ret;\n+\tchar buf[10];\n+\n+\t/* already a daemon */\n+//\tif (getppid() \u003d\u003d 1)\n+//\t\treturn 1;\n+\n+\tif (_lock_path) {\n+\t\tfd \u003d open(_lock_path, O_RDONLY);\n+\t\tif (fd \u003e\u003d 0) {\n+\t\t\tn \u003d read(fd, buf, sizeof(buf));\n+\t\t\tclose(fd);\n+\t\t\tif (n) {\n+\t\t\t\tn \u003d atoi(buf);\n+\t\t\t\tret \u003d kill(n, 0);\n+\t\t\t\tif (ret \u003e\u003d 0) {\n+\t\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t \u0022Daemon already running from pid %d\u005cn\u0022, n);\n+\t\t\t\t\texit(1);\n+\t\t\t\t}\n+\t\t\t\tfprintf(stderr,\n+\t\t\t\t \u0022Removing stale lock file %s from dead pid %d\u005cn\u0022,\n+\t\t\t\t\t\t\t\t\t _lock_path, n);\n+\t\t\t\tunlink(lock_path);\n+\t\t\t}\n+\t\t}\n+\n+\t\tn \u003d strlen(_lock_path) + 1;\n+\t\tlock_path \u003d lws_malloc(n);\n+\t\tif (!lock_path) {\n+\t\t\tfprintf(stderr, \u0022Out of mem in lws_daemonize\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\t\tstrcpy(lock_path, _lock_path);\n+\t}\n+\n+\t/* Trap signals that we expect to receive */\n+\tsignal(SIGCHLD, child_handler);\t/* died */\n+\tsignal(SIGUSR1, child_handler); /* was happy */\n+\tsignal(SIGALRM, child_handler); /* timeout daemonizing */\n+\n+\t/* Fork off the parent process */\n+\tpid_daemon \u003d fork();\n+\tif (pid_daemon \u003c 0) {\n+\t\tfprintf(stderr, \u0022unable to fork daemon, code\u003d%d (%s)\u0022,\n+\t\t errno, strerror(errno));\n+\t\texit(9);\n+\t}\n+\n+ /* If we got a good PID, then we can exit the parent process. */\n+\tif (pid_daemon \u003e 0) {\n+\n+ /*\n+ * Wait for confirmation signal from the child via\n+ * SIGCHILD / USR1, or for two seconds to elapse\n+ * (SIGALRM). pause() should not return.\n+ */\n+ alarm(2);\n+\n+ pause();\n+ /* should not be reachable */\n+ exit(1);\n+ }\n+\n+\t/* At this point we are executing as the child process */\n+\tparent \u003d getppid();\n+\tpid_daemon \u003d getpid();\n+\n+\t/* Cancel certain signals */\n+\tsignal(SIGCHLD, SIG_DFL); /* A child process dies */\n+\tsignal(SIGTSTP, SIG_IGN); /* Various TTY signals */\n+\tsignal(SIGTTOU, SIG_IGN);\n+\tsignal(SIGTTIN, SIG_IGN);\n+\tsignal(SIGHUP, SIG_IGN); /* Ignore hangup signal */\n+\n+\t/* Change the file mode mask */\n+\tumask(0);\n+\n+\t/* Create a new SID for the child process */\n+\tsid \u003d setsid();\n+\tif (sid \u003c 0) {\n+\t\tfprintf(stderr,\n+\t\t\t\u0022unable to create a new session, code %d (%s)\u0022,\n+\t\t\terrno, strerror(errno));\n+\t\texit(2);\n+\t}\n+\n+\t/*\n+\t * Change the current working directory. This prevents the current\n+\t * directory from being locked; hence not being able to remove it.\n+\t */\n+\tif (chdir(\u0022/tmp\u0022) \u003c 0) {\n+\t\tfprintf(stderr,\n+\t\t\t\u0022unable to change directory to %s, code %d (%s)\u0022,\n+\t\t\t\u0022/\u0022, errno, strerror(errno));\n+\t\texit(3);\n+\t}\n+\n+\t/* Redirect standard files to /dev/null */\n+\tif (!freopen(\u0022/dev/null\u0022, \u0022r\u0022, stdin))\n+\t\tfprintf(stderr, \u0022unable to freopen() stdin, code %d (%s)\u0022,\n+\t\t\t\t\t\t errno, strerror(errno));\n+\n+\tif (!freopen(\u0022/dev/null\u0022, \u0022w\u0022, stdout))\n+\t\tfprintf(stderr, \u0022unable to freopen() stdout, code %d (%s)\u0022,\n+\t\t\t\t\t\t errno, strerror(errno));\n+\n+\tif (!freopen(\u0022/dev/null\u0022, \u0022w\u0022, stderr))\n+\t\tfprintf(stderr, \u0022unable to freopen() stderr, code %d (%s)\u0022,\n+\t\t\t\t\t\t errno, strerror(errno));\n+\n+\t/* Tell the parent process that we are A-okay */\n+\tkill(parent, SIGUSR1);\n+\n+\tact.sa_handler \u003d lws_daemon_closing;\n+\tsigemptyset(\u0026act.sa_mask);\n+\tact.sa_flags \u003d 0;\n+\n+\tsigaction(SIGTERM, \u0026act, NULL);\n+\n+\t/* return to continue what is now \u0022the daemon\u0022 */\n+\n+\treturn 0;\n+}\n+\ndiff --git a/lib/server/fops-zip.c b/lib/server/fops-zip.c\nnew file mode 100644\nindex 0000000..2b254f6\n--- /dev/null\n+++ b/lib/server/fops-zip.c\n@@ -0,0 +1,669 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Original code used in this source file:\n+ *\n+ * https://github.com/PerBothner/DomTerm.git @912add15f3d0aec\n+ *\n+ * ./lws-term/io.c\n+ * ./lws-term/junzip.c\n+ *\n+ * Copyright (C) 2017 Per Bothner \u003cper@bothner.com\u003e\n+ *\n+ * MIT License\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 deal\n+ * in the Software without restriction, including without limitation the rights\n+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+ * ( 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 FROM,\n+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+ * SOFTWARE.\n+ *\n+ *\n+ * lws rewrite:\n+ *\n+ * Copyright (C) 2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#include \u003czlib.h\u003e\n+\n+/*\n+ * This code works with zip format containers which may have files compressed\n+ * with gzip deflate (type 8) or store uncompressed (type 0).\n+ *\n+ * Linux zip produces such zipfiles by default, eg\n+ *\n+ * $ zip ../myzip.zip file1 file2 file3\n+ */\n+\n+#define ZIP_COMPRESSION_METHOD_STORE 0\n+#define ZIP_COMPRESSION_METHOD_DEFLATE 8\n+\n+typedef struct {\n+\tlws_filepos_t\t\tfilename_start;\n+\tuint32_t\t\tcrc32;\n+\tuint32_t\t\tcomp_size;\n+\tuint32_t\t\tuncomp_size;\n+\tuint32_t\t\toffset;\n+\tuint32_t\t\tmod_time;\n+\tuint16_t\t\tfilename_len;\n+\tuint16_t\t\textra;\n+\tuint16_t\t\tmethod;\n+\tuint16_t\t\tfile_com_len;\n+} lws_fops_zip_hdr_t;\n+\n+typedef struct {\n+\tstruct lws_fop_fd\tfop_fd; /* MUST BE FIRST logical fop_fd into\n+\t \t \t \t \t * file inside zip: fops_zip fops */\n+\tlws_fop_fd_t\t\tzip_fop_fd; /* logical fop fd on to zip file\n+\t \t \t \t \t * itself: using platform fops */\n+\tlws_fops_zip_hdr_t\thdr;\n+\tz_stream\t\tinflate;\n+\tlws_filepos_t\t\tcontent_start;\n+\tlws_filepos_t\t\texp_uncomp_pos;\n+\tunion {\n+\t\tuint8_t\t\ttrailer8[8];\n+\t\tuint32_t\ttrailer32[2];\n+\t} u;\n+\tuint8_t\t\t\trbuf[128]; /* decompression chunk size */\n+\tint\t\t\tentry_count;\n+\n+\tunsigned int\t\tdecompress:1; /* 0 \u003d direct from file */\n+\tunsigned int\t\tadd_gzip_container:1;\n+} *lws_fops_zip_t;\n+\n+struct lws_plat_file_ops fops_zip;\n+#define fop_fd_to_priv(FD) ((lws_fops_zip_t)(FD))\n+\n+static const uint8_t hd[] \u003d { 31, 139, 8, 0, 0, 0, 0, 0, 0, 3 };\n+\n+enum {\n+\tZC_SIGNATURE\t\t\t\t\u003d 0,\n+\tZC_VERSION_MADE_BY \t\t\t\u003d 4,\n+\tZC_VERSION_NEEDED_TO_EXTRACT \t\t\u003d 6,\n+\tZC_GENERAL_PURPOSE_BIT_FLAG \t\t\u003d 8,\n+\tZC_COMPRESSION_METHOD \t\t\t\u003d 10,\n+\tZC_LAST_MOD_FILE_TIME \t\t\t\u003d 12,\n+\tZC_LAST_MOD_FILE_DATE \t\t\t\u003d 14,\n+\tZC_CRC32 \t\t\t\t\u003d 16,\n+\tZC_COMPRESSED_SIZE \t\t\t\u003d 20,\n+\tZC_UNCOMPRESSED_SIZE \t\t\t\u003d 24,\n+\tZC_FILE_NAME_LENGTH \t\t\t\u003d 28,\n+\tZC_EXTRA_FIELD_LENGTH \t\t\t\u003d 30,\n+\n+\tZC_FILE_COMMENT_LENGTH \t\t\t\u003d 32,\n+\tZC_DISK_NUMBER_START \t\t\t\u003d 34,\n+\tZC_INTERNAL_FILE_ATTRIBUTES \t\t\u003d 36,\n+\tZC_EXTERNAL_FILE_ATTRIBUTES \t\t\u003d 38,\n+\tZC_REL_OFFSET_LOCAL_HEADER \t\t\u003d 42,\n+\tZC_DIRECTORY_LENGTH \t\t\t\u003d 46,\n+\n+\tZE_SIGNATURE_OFFSET \t\t\t\u003d 0,\n+\tZE_DESK_NUMBER \t\t\t\t\u003d 4,\n+\tZE_CENTRAL_DIRECTORY_DISK_NUMBER \t\u003d 6,\n+\tZE_NUM_ENTRIES_THIS_DISK \t\t\u003d 8,\n+\tZE_NUM_ENTRIES \t\t\t\t\u003d 10,\n+\tZE_CENTRAL_DIRECTORY_SIZE \t\t\u003d 12,\n+\tZE_CENTRAL_DIR_OFFSET \t\t\t\u003d 16,\n+\tZE_ZIP_COMMENT_LENGTH \t\t\t\u003d 20,\n+\tZE_DIRECTORY_LENGTH \t\t\t\u003d 22,\n+\n+\tZL_REL_OFFSET_CONTENT\t\t\t\u003d 28,\n+\tZL_HEADER_LENGTH\t\t\t\u003d 30,\n+\n+\tLWS_FZ_ERR_SEEK_END_RECORD\t\t\u003d 1,\n+\tLWS_FZ_ERR_READ_END_RECORD,\n+\tLWS_FZ_ERR_END_RECORD_MAGIC,\n+\tLWS_FZ_ERR_END_RECORD_SANITY,\n+\tLWS_FZ_ERR_CENTRAL_SEEK,\n+\tLWS_FZ_ERR_CENTRAL_READ,\n+\tLWS_FZ_ERR_CENTRAL_SANITY,\n+\tLWS_FZ_ERR_NAME_TOO_LONG,\n+\tLWS_FZ_ERR_NAME_SEEK,\n+\tLWS_FZ_ERR_NAME_READ,\n+\tLWS_FZ_ERR_CONTENT_SANITY,\n+\tLWS_FZ_ERR_CONTENT_SEEK,\n+\tLWS_FZ_ERR_SCAN_SEEK,\n+\tLWS_FZ_ERR_NOT_FOUND,\n+\tLWS_FZ_ERR_ZLIB_INIT,\n+\tLWS_FZ_ERR_READ_CONTENT,\n+\tLWS_FZ_ERR_SEEK_COMPRESSED,\n+};\n+\n+static uint16_t\n+get_u16(void *p)\n+{\n+\tconst uint8_t *c \u003d (const uint8_t *)p;\n+\n+\treturn (uint16_t)((c[0] | (c[1] \u003c\u003c 8)));\n+}\n+\n+static uint32_t\n+get_u32(void *p)\n+{\n+\tconst uint8_t *c \u003d (const uint8_t *)p;\n+\n+\treturn (uint32_t)((c[0] | (c[1] \u003c\u003c 8) | (c[2] \u003c\u003c 16) | (c[3] \u003c\u003c 24)));\n+}\n+\n+int\n+lws_fops_zip_scan(lws_fops_zip_t priv, const char *name, int len)\n+{\n+\tlws_filepos_t amount;\n+\tuint8_t buf[96];\n+\tint i;\n+\n+\tif (lws_vfs_file_seek_end(priv-\u003ezip_fop_fd, -ZE_DIRECTORY_LENGTH) \u003c 0)\n+\t\treturn LWS_FZ_ERR_SEEK_END_RECORD;\n+\n+\tif (lws_vfs_file_read(priv-\u003ezip_fop_fd, \u0026amount, buf,\n+\t\t\t ZE_DIRECTORY_LENGTH))\n+\t\treturn LWS_FZ_ERR_READ_END_RECORD;\n+\n+\tif (amount !\u003d ZE_DIRECTORY_LENGTH)\n+\t\treturn LWS_FZ_ERR_READ_END_RECORD;\n+\n+\t/*\n+\t * We require the zip to have the last record right at the end\n+\t * Linux zip always does this if no zip comment.\n+\t */\n+\tif (buf[0] !\u003d 'P' || buf[1] !\u003d 'K' || buf[2] !\u003d 5 || buf[3] !\u003d 6)\n+\t\treturn LWS_FZ_ERR_END_RECORD_MAGIC;\n+\n+\ti \u003d get_u16(buf + ZE_NUM_ENTRIES);\n+\n+\tif (get_u16(buf + ZE_DESK_NUMBER) ||\n+\t get_u16(buf + ZE_CENTRAL_DIRECTORY_DISK_NUMBER) ||\n+\t i !\u003d get_u16(buf + ZE_NUM_ENTRIES_THIS_DISK))\n+\t\treturn LWS_FZ_ERR_END_RECORD_SANITY;\n+\n+\t/* end record is OK... look for our file in the central dir */\n+\n+\tif (lws_vfs_file_seek_set(priv-\u003ezip_fop_fd,\n+\t\t\t\t get_u32(buf + ZE_CENTRAL_DIR_OFFSET)) \u003c 0)\n+\t\treturn LWS_FZ_ERR_CENTRAL_SEEK;\n+\n+\twhile (i--) {\n+\t\tpriv-\u003econtent_start \u003d lws_vfs_tell(priv-\u003ezip_fop_fd);\n+\n+\t\tif (lws_vfs_file_read(priv-\u003ezip_fop_fd, \u0026amount, buf,\n+\t\t\t\t ZC_DIRECTORY_LENGTH))\n+\t\t\treturn LWS_FZ_ERR_CENTRAL_READ;\n+\n+\t\tif (amount !\u003d ZC_DIRECTORY_LENGTH)\n+\t\t\treturn LWS_FZ_ERR_CENTRAL_READ;\n+\n+\t\tif (get_u32(buf + ZC_SIGNATURE) !\u003d 0x02014B50)\n+\t\t\treturn LWS_FZ_ERR_CENTRAL_SANITY;\n+\n+ lwsl_debug(\u0022cstart 0x%lx\u005cn\u0022, (unsigned long)priv-\u003econtent_start);\n+\n+\t\tpriv-\u003ehdr.filename_len \u003d get_u16(buf + ZC_FILE_NAME_LENGTH);\n+\t\tpriv-\u003ehdr.extra \u003d get_u16(buf + ZC_EXTRA_FIELD_LENGTH);\n+\t\tpriv-\u003ehdr.filename_start \u003d lws_vfs_tell(priv-\u003ezip_fop_fd);\n+\n+\t\tpriv-\u003ehdr.method \u003d get_u16(buf + ZC_COMPRESSION_METHOD);\n+\t\tpriv-\u003ehdr.crc32 \u003d get_u32(buf + ZC_CRC32);\n+\t\tpriv-\u003ehdr.comp_size \u003d get_u32(buf + ZC_COMPRESSED_SIZE);\n+\t\tpriv-\u003ehdr.uncomp_size \u003d get_u32(buf + ZC_UNCOMPRESSED_SIZE);\n+\t\tpriv-\u003ehdr.offset \u003d get_u32(buf + ZC_REL_OFFSET_LOCAL_HEADER);\n+\t\tpriv-\u003ehdr.mod_time \u003d get_u32(buf + ZC_LAST_MOD_FILE_TIME);\n+\t\tpriv-\u003ehdr.file_com_len \u003d get_u16(buf + ZC_FILE_COMMENT_LENGTH);\n+\n+\t\tif (priv-\u003ehdr.filename_len !\u003d len)\n+\t\t\tgoto next;\n+\n+\t\tif (len \u003e\u003d sizeof(buf) - 1)\n+\t\t\treturn LWS_FZ_ERR_NAME_TOO_LONG;\n+\n+\t\tif (priv-\u003ezip_fop_fd-\u003efops-\u003eLWS_FOP_READ(priv-\u003ezip_fop_fd,\n+\t\t\t\t\t\t\t\u0026amount, buf, len))\n+\t\t\treturn LWS_FZ_ERR_NAME_READ;\n+\t\tif (amount !\u003d len)\n+\t\t\treturn LWS_FZ_ERR_NAME_READ;\n+\n+\t\tbuf[len] \u003d '\u005c0';\n+\t\tlwsl_debug(\u0022check %s vs %s\u005cn\u0022, buf, name);\n+\n+\t\tif (strcmp((const char *)buf, name))\n+\t\t\tgoto next;\n+\n+\t\t/* we found a match */\n+\t\tif (lws_vfs_file_seek_set(priv-\u003ezip_fop_fd, priv-\u003ehdr.offset) \u003c 0)\n+\t\t\treturn LWS_FZ_ERR_NAME_SEEK;\n+\t\tif (priv-\u003ezip_fop_fd-\u003efops-\u003eLWS_FOP_READ(priv-\u003ezip_fop_fd,\n+\t\t\t\t\t\t\t\u0026amount, buf,\n+\t\t\t\t\t\t\tZL_HEADER_LENGTH))\n+\t\t\treturn LWS_FZ_ERR_NAME_READ;\n+\t\tif (amount !\u003d ZL_HEADER_LENGTH)\n+\t\t\treturn LWS_FZ_ERR_NAME_READ;\n+\n+\t\tpriv-\u003econtent_start \u003d priv-\u003ehdr.offset +\n+\t\t\t\t ZL_HEADER_LENGTH +\n+\t\t\t\t priv-\u003ehdr.filename_len +\n+\t\t\t\t get_u16(buf + ZL_REL_OFFSET_CONTENT);\n+\n+\t\tlwsl_debug(\u0022content supposed to start at 0x%lx\u005cn\u0022,\n+ (unsigned long)priv-\u003econtent_start);\n+\n+\t\tif (priv-\u003econtent_start \u003e priv-\u003ezip_fop_fd-\u003elen)\n+\t\t\treturn LWS_FZ_ERR_CONTENT_SANITY;\n+\n+\t\tif (lws_vfs_file_seek_set(priv-\u003ezip_fop_fd,\n+\t\t\t\t\t priv-\u003econtent_start) \u003c 0)\n+\t\t\treturn LWS_FZ_ERR_CONTENT_SEEK;\n+\n+\t\t/* we are aligned at the start of the content */\n+\n+\t\tpriv-\u003eexp_uncomp_pos \u003d 0;\n+\n+\t\treturn 0;\n+\n+next:\n+\t\tif (i \u0026\u0026 lws_vfs_file_seek_set(priv-\u003ezip_fop_fd,\n+\t\t\t\t\t priv-\u003econtent_start +\n+\t\t\t\t\t ZC_DIRECTORY_LENGTH +\n+\t\t\t\t\t priv-\u003ehdr.filename_len +\n+\t\t\t\t\t priv-\u003ehdr.extra +\n+\t\t\t\t\t priv-\u003ehdr.file_com_len) \u003c 0)\n+\t\t\treturn LWS_FZ_ERR_SCAN_SEEK;\n+\t}\n+\n+\treturn LWS_FZ_ERR_NOT_FOUND;\n+}\n+\n+static int\n+lws_fops_zip_reset_inflate(lws_fops_zip_t priv)\n+{\n+\tif (priv-\u003edecompress)\n+\t\tinflateEnd(\u0026priv-\u003einflate);\n+\n+\tpriv-\u003einflate.zalloc \u003d Z_NULL;\n+\tpriv-\u003einflate.zfree \u003d Z_NULL;\n+\tpriv-\u003einflate.opaque \u003d Z_NULL;\n+\tpriv-\u003einflate.avail_in \u003d 0;\n+\tpriv-\u003einflate.next_in \u003d Z_NULL;\n+\n+\tif (inflateInit2(\u0026priv-\u003einflate, -MAX_WBITS) !\u003d Z_OK) {\n+\t\tlwsl_err(\u0022inflate init failed\u005cn\u0022);\n+\t\treturn LWS_FZ_ERR_ZLIB_INIT;\n+\t}\n+\n+\tif (lws_vfs_file_seek_set(priv-\u003ezip_fop_fd, priv-\u003econtent_start) \u003c 0)\n+\t\treturn LWS_FZ_ERR_CONTENT_SEEK;\n+\n+\tpriv-\u003eexp_uncomp_pos \u003d 0;\n+\n+\treturn 0;\n+}\n+\n+static lws_fop_fd_t\n+lws_fops_zip_open(const struct lws_plat_file_ops *fops, const char *vfs_path,\n+\t\t const char *vpath, lws_fop_flags_t *flags)\n+{\n+\tlws_fop_flags_t local_flags \u003d 0;\n+\tlws_fops_zip_t priv;\n+\tchar rp[192];\n+\tint m;\n+\n+\t/*\n+\t * vpath points at the / after the fops signature in vfs_path, eg\n+\t * with a vfs_path \u0022/var/www/docs/manual.zip/index.html\u0022, vpath\n+\t * will come pointing at \u0022/index.html\u0022\n+\t */\n+\n+\tpriv \u003d lws_zalloc(sizeof(*priv), \u0022fops_zip priv\u0022);\n+\tif (!priv)\n+\t\treturn NULL;\n+\n+\tpriv-\u003efop_fd.fops \u003d \u0026fops_zip;\n+\n+\tm \u003d sizeof(rp) - 1;\n+\tif ((vpath - vfs_path - 1) \u003c m)\n+\t\tm \u003d vpath - vfs_path - 1;\n+\tstrncpy(rp, vfs_path, m);\n+\trp[m] \u003d '\u005c0';\n+\n+\t/* open the zip file itself using the incoming fops, not fops_zip */\n+\n+\tpriv-\u003ezip_fop_fd \u003d fops-\u003eLWS_FOP_OPEN(fops, rp, NULL, \u0026local_flags);\n+\tif (!priv-\u003ezip_fop_fd) {\n+\t\tlwsl_err(\u0022unable to open zip %s\u005cn\u0022, rp);\n+\t\tgoto bail1;\n+\t}\n+\n+\tif (*vpath \u003d\u003d '/')\n+\t\tvpath++;\n+\n+\tm \u003d lws_fops_zip_scan(priv, vpath, strlen(vpath));\n+\tif (m) {\n+\t\tlwsl_err(\u0022unable to find record matching '%s' %d\u005cn\u0022, vpath, m);\n+\t\tgoto bail2;\n+\t}\n+\n+\t/* the directory metadata tells us modification time, so pass it on */\n+\tpriv-\u003efop_fd.mod_time \u003d priv-\u003ehdr.mod_time;\n+\t*flags |\u003d LWS_FOP_FLAG_MOD_TIME_VALID | LWS_FOP_FLAG_VIRTUAL;\n+\tpriv-\u003efop_fd.flags \u003d *flags;\n+\n+\t/* The zip fop_fd is left pointing at the start of the content.\n+\t *\n+\t * 1) Content could be uncompressed (STORE), and we can always serve\n+\t * that directly\n+\t *\n+\t * 2) Content could be compressed (GZIP), and the client can handle\n+\t * receiving GZIP... we can wrap it in a GZIP header and trailer\n+\t * and serve the content part directly. The flag indicating we\n+\t * are providing GZIP directly is set so lws will send the right\n+\t * headers.\n+\t *\n+\t * 3) Content could be compressed (GZIP) but the client can't handle\n+\t * receiving GZIP... we can decompress it and serve as it is\n+\t * inflated piecemeal.\n+\t *\n+\t * 4) Content may be compressed some unknown way... fail\n+\t *\n+\t */\n+\tif (priv-\u003ehdr.method \u003d\u003d ZIP_COMPRESSION_METHOD_STORE) {\n+\t\t/*\n+\t\t * it is stored uncompressed, leave it indicated as\n+\t\t * uncompressed, and just serve it from inside the\n+\t\t * zip with no gzip container;\n+\t\t */\n+\n+\t\tlwsl_info(\u0022direct zip serving (stored)\u005cn\u0022);\n+\n+\t\tpriv-\u003efop_fd.len \u003d priv-\u003ehdr.uncomp_size;\n+\n+\t\treturn \u0026priv-\u003efop_fd;\n+\t}\n+\n+\tif ((*flags \u0026 LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP) \u0026\u0026\n+\t priv-\u003ehdr.method \u003d\u003d ZIP_COMPRESSION_METHOD_DEFLATE) {\n+\n+\t\t/*\n+\t\t * We can serve the gzipped file contents directly as gzip\n+\t\t * from inside the zip container; client says it is OK.\n+\t\t *\n+\t\t * To convert to standalone gzip, we have to add a 10-byte\n+\t\t * constant header and a variable 8-byte trailer around the\n+\t\t * content.\n+\t\t *\n+\t\t * The 8-byte trailer is prepared now and held in the priv.\n+\t\t */\n+\n+\t\tlwsl_info(\u0022direct zip serving (gzipped)\u005cn\u0022);\n+\n+\t\tpriv-\u003efop_fd.len \u003d sizeof(hd) + priv-\u003ehdr.comp_size +\n+\t\t\t\t sizeof(priv-\u003eu);\n+\n+\t\tif (lws_is_be()) {\n+\t\t\tuint8_t *p \u003d priv-\u003eu.trailer8;\n+\n+\t\t\t*p++ \u003d (uint8_t)priv-\u003ehdr.crc32;\n+\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.crc32 \u003e\u003e 8);\n+\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.crc32 \u003e\u003e 16);\n+\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.crc32 \u003e\u003e 24);\n+\t\t\t*p++ \u003d (uint8_t)priv-\u003ehdr.uncomp_size;\n+\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.uncomp_size \u003e\u003e 8);\n+\t\t\t*p++ \u003d (uint8_t)(priv-\u003ehdr.uncomp_size \u003e\u003e 16);\n+\t\t\t*p \u003d (uint8_t)(priv-\u003ehdr.uncomp_size \u003e\u003e 24);\n+\t\t} else {\n+\t\t\tpriv-\u003eu.trailer32[0] \u003d priv-\u003ehdr.crc32;\n+\t\t\tpriv-\u003eu.trailer32[1] \u003d priv-\u003ehdr.uncomp_size;\n+\t\t}\n+\n+\t\t*flags |\u003d LWS_FOP_FLAG_COMPR_IS_GZIP;\n+\t\tpriv-\u003efop_fd.flags \u003d *flags;\n+\t\tpriv-\u003eadd_gzip_container \u003d 1;\n+\n+\t\treturn \u0026priv-\u003efop_fd;\n+\t}\n+\n+\tif (priv-\u003ehdr.method \u003d\u003d ZIP_COMPRESSION_METHOD_DEFLATE) {\n+\n+\t\t/* we must decompress it to serve it */\n+\n+\t\tlwsl_info(\u0022decompressed zip serving\u005cn\u0022);\n+\n+\t\tpriv-\u003efop_fd.len \u003d priv-\u003ehdr.uncomp_size;\n+\n+\t\tif (lws_fops_zip_reset_inflate(priv)) {\n+\t\t\tlwsl_err(\u0022inflate init failed\u005cn\u0022);\n+\t\t\tgoto bail2;\n+\t\t}\n+\n+\t\tpriv-\u003edecompress \u003d 1;\n+\n+\t\treturn \u0026priv-\u003efop_fd;\n+\t}\n+\n+\t/* we can't handle it ... */\n+\n+\tlwsl_err(\u0022zipped file %s compressed in unknown way (%d)\u005cn\u0022, vfs_path,\n+\t\t priv-\u003ehdr.method);\n+\n+bail2:\n+\tlws_vfs_file_close(\u0026priv-\u003ezip_fop_fd);\n+bail1:\n+\tfree(priv);\n+\n+\treturn NULL;\n+}\n+\n+/* ie, we are closing the fop_fd for the file inside the gzip */\n+\n+static int\n+lws_fops_zip_close(lws_fop_fd_t *fd)\n+{\n+\tlws_fops_zip_t priv \u003d fop_fd_to_priv(*fd);\n+\n+\tif (priv-\u003edecompress)\n+\t\tinflateEnd(\u0026priv-\u003einflate);\n+\n+\tlws_vfs_file_close(\u0026priv-\u003ezip_fop_fd); /* close the gzip fop_fd */\n+\n+\tfree(priv);\n+\t*fd \u003d NULL;\n+\n+\treturn 0;\n+}\n+\n+static lws_fileofs_t\n+lws_fops_zip_seek_cur(lws_fop_fd_t fd, lws_fileofs_t offset_from_cur_pos)\n+{\n+\tfd-\u003epos +\u003d offset_from_cur_pos;\n+\n+\treturn fd-\u003epos;\n+}\n+\n+static int\n+lws_fops_zip_read(lws_fop_fd_t fd, lws_filepos_t *amount, uint8_t *buf,\n+\t\t lws_filepos_t len)\n+{\n+\tlws_fops_zip_t priv \u003d fop_fd_to_priv(fd);\n+\tlws_filepos_t ramount, rlen, cur \u003d lws_vfs_tell(fd);\n+\tint ret;\n+\n+\tif (priv-\u003edecompress) {\n+\n+\t\tif (priv-\u003eexp_uncomp_pos !\u003d fd-\u003epos) {\n+\t\t\t/*\n+\t\t\t * there has been a seek in the uncompressed fop_fd\n+\t\t\t * we have to restart the decompression and loop eating\n+\t\t\t * the decompressed data up to the seek point\n+\t\t\t */\n+\t\t\tlwsl_info(\u0022seek in decompressed\u005cn\u0022);\n+\n+\t\t\tlws_fops_zip_reset_inflate(priv);\n+\n+\t\t\twhile (priv-\u003eexp_uncomp_pos !\u003d fd-\u003epos) {\n+\t\t\t\trlen \u003d len;\n+\t\t\t\tif (rlen \u003e fd-\u003epos - priv-\u003eexp_uncomp_pos)\n+\t\t\t\t\trlen \u003d fd-\u003epos - priv-\u003eexp_uncomp_pos;\n+\t\t\t\tif (lws_fops_zip_read(fd, amount, buf, rlen))\n+\t\t\t\t\treturn LWS_FZ_ERR_SEEK_COMPRESSED;\n+\t\t\t}\n+\t\t\t*amount \u003d 0;\n+\t\t}\n+\n+\t\tpriv-\u003einflate.avail_out \u003d (unsigned int)len;\n+\t\tpriv-\u003einflate.next_out \u003d buf;\n+\n+spin:\n+\t\tif (!priv-\u003einflate.avail_in) {\n+\t\t\trlen \u003d sizeof(priv-\u003erbuf);\n+\t\t\tif (rlen \u003e priv-\u003ehdr.comp_size -\n+\t\t\t\t (cur - priv-\u003econtent_start))\n+\t\t\t\trlen \u003d priv-\u003ehdr.comp_size -\n+\t\t\t\t (priv-\u003ehdr.comp_size -\n+\t\t\t\t\tpriv-\u003econtent_start);\n+\n+\t\t\tif (priv-\u003ezip_fop_fd-\u003efops-\u003eLWS_FOP_READ(\n+\t\t\t\t\tpriv-\u003ezip_fop_fd, \u0026ramount, priv-\u003erbuf,\n+\t\t\t\t\trlen))\n+\t\t\t\treturn LWS_FZ_ERR_READ_CONTENT;\n+\n+\t\t\tcur +\u003d ramount;\n+\n+\t\t\tpriv-\u003einflate.avail_in \u003d (unsigned int)ramount;\n+\t\t\tpriv-\u003einflate.next_in \u003d priv-\u003erbuf;\n+\t\t}\n+\n+\t\tret \u003d inflate(\u0026priv-\u003einflate, Z_NO_FLUSH);\n+\t\tif (ret \u003d\u003d Z_STREAM_ERROR)\n+\t\t\treturn ret;\n+\n+\t\tswitch (ret) {\n+\t\tcase Z_NEED_DICT:\n+\t\t\tret \u003d Z_DATA_ERROR;\n+\t\t\t/* and fall through */\n+\t\tcase Z_DATA_ERROR:\n+\t\tcase Z_MEM_ERROR:\n+\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\tif (!priv-\u003einflate.avail_in \u0026\u0026 priv-\u003einflate.avail_out \u0026\u0026\n+\t\t cur !\u003d priv-\u003econtent_start + priv-\u003ehdr.comp_size)\n+\t\t\tgoto spin;\n+\n+\t\t*amount \u003d len - priv-\u003einflate.avail_out;\n+\n+\t\tpriv-\u003eexp_uncomp_pos +\u003d *amount;\n+\t\tfd-\u003epos +\u003d *amount;\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (priv-\u003eadd_gzip_container) {\n+\n+\t\tlwsl_info(\u0022%s: gzip + container\u005cn\u0022, __func__);\n+\t\t*amount \u003d 0;\n+\n+\t\t/* place the canned header at the start */\n+\n+\t\tif (len \u0026\u0026 fd-\u003epos \u003c sizeof(hd)) {\n+\t\t\trlen \u003d sizeof(hd) - fd-\u003epos;\n+\t\t\tif (rlen \u003e len)\n+\t\t\t\trlen \u003d len;\n+\t\t\t/* provide stuff from canned header */\n+\t\t\tmemcpy(buf, hd + fd-\u003epos, (size_t)rlen);\n+\t\t\tfd-\u003epos +\u003d rlen;\n+\t\t\tbuf +\u003d rlen;\n+\t\t\tlen -\u003d rlen;\n+\t\t\t*amount +\u003d rlen;\n+\t\t}\n+\n+\t\t/* serve gzipped data direct from zipfile */\n+\n+\t\tif (len \u0026\u0026 fd-\u003epos \u003e\u003d sizeof(hd) \u0026\u0026\n+\t\t fd-\u003epos \u003c priv-\u003ehdr.comp_size + sizeof(hd)) {\n+\n+\t\t\trlen \u003d priv-\u003ehdr.comp_size - (priv-\u003ezip_fop_fd-\u003epos -\n+\t\t\t\t\t\t priv-\u003econtent_start);\n+\t\t\tif (rlen \u003e len)\n+\t\t\t\trlen \u003d len;\n+\n+\t\t\tif (rlen \u0026\u0026\n+\t\t\t priv-\u003ezip_fop_fd-\u003epos \u003c (priv-\u003ehdr.comp_size +\n+\t\t\t\t\t \t priv-\u003econtent_start)) {\n+\t\t\t\tif (lws_vfs_file_read(priv-\u003ezip_fop_fd,\n+\t\t\t\t\t\t \u0026ramount, buf, rlen))\n+\t\t\t\t\treturn LWS_FZ_ERR_READ_CONTENT;\n+\t\t\t\t*amount +\u003d ramount;\n+\t\t\t\tfd-\u003epos +\u003d ramount; // virtual pos\n+\t\t\t\tbuf +\u003d ramount;\n+\t\t\t\tlen -\u003d ramount;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* place the prepared trailer at the end */\n+\n+\t\tif (len \u0026\u0026 fd-\u003epos \u003e\u003d priv-\u003ehdr.comp_size + sizeof(hd) \u0026\u0026\n+\t\t fd-\u003epos \u003c priv-\u003ehdr.comp_size + sizeof(hd) +\n+\t\t \t sizeof(priv-\u003eu)) {\n+\t\t\tcur \u003d fd-\u003epos - priv-\u003ehdr.comp_size - sizeof(hd);\n+\t\t\trlen \u003d sizeof(priv-\u003eu) - cur;\n+\t\t\tif (rlen \u003e len)\n+\t\t\t\trlen \u003d len;\n+\n+\t\t\tmemcpy(buf, priv-\u003eu.trailer8 + cur, (size_t)rlen);\n+\n+\t\t\t*amount +\u003d rlen;\n+\t\t\tfd-\u003epos +\u003d rlen;\n+\t\t}\n+\n+\t\treturn 0;\n+\t}\n+\n+\tlwsl_info(\u0022%s: store\u005cn\u0022, __func__);\n+\n+\tif (len \u003e priv-\u003ehdr.uncomp_size - (cur - priv-\u003econtent_start))\n+\t\tlen \u003d priv-\u003ehdr.comp_size - (priv-\u003ehdr.comp_size -\n+\t\t\t\t\t priv-\u003econtent_start);\n+\n+\tif (priv-\u003ezip_fop_fd-\u003efops-\u003eLWS_FOP_READ(priv-\u003ezip_fop_fd,\n+\t\t\t\t\t\t amount, buf, len))\n+\t\treturn LWS_FZ_ERR_READ_CONTENT;\n+\n+\treturn 0;\n+}\n+\n+struct lws_plat_file_ops fops_zip \u003d {\n+\tlws_fops_zip_open,\n+\tlws_fops_zip_close,\n+\tlws_fops_zip_seek_cur,\n+\tlws_fops_zip_read,\n+\tNULL,\n+\t{ { \u0022.zip/\u0022, 5 }, { \u0022.jar/\u0022, 5 }, { \u0022.war/\u0022, 5 } },\n+\tNULL,\n+};\ndiff --git a/lib/server/lejp-conf.c b/lib/server/lejp-conf.c\nnew file mode 100644\nindex 0000000..a605737\n--- /dev/null\n+++ b/lib/server/lejp-conf.c\n@@ -0,0 +1,929 @@\n+/*\n+ * libwebsockets web server application\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+#include \u0022../misc/lejp.h\u0022\n+\n+#ifndef _WIN32\n+/* this is needed for Travis CI */\n+#include \u003cdirent.h\u003e\n+#endif\n+\n+#define ESC_INSTALL_DATADIR \u0022_lws_ddir_\u0022\n+\n+static const char * const paths_global[] \u003d {\n+\t\u0022global.uid\u0022,\n+\t\u0022global.gid\u0022,\n+\t\u0022global.count-threads\u0022,\n+\t\u0022global.init-ssl\u0022,\n+\t\u0022global.server-string\u0022,\n+\t\u0022global.plugin-dir\u0022,\n+\t\u0022global.ws-pingpong-secs\u0022,\n+\t\u0022global.timeout-secs\u0022,\n+\t\u0022global.reject-service-keywords[].*\u0022,\n+\t\u0022global.reject-service-keywords[]\u0022,\n+};\n+\n+enum lejp_global_paths {\n+\tLEJPGP_UID,\n+\tLEJPGP_GID,\n+\tLEJPGP_COUNT_THREADS,\n+\tLWJPGP_INIT_SSL,\n+\tLEJPGP_SERVER_STRING,\n+\tLEJPGP_PLUGIN_DIR,\n+\tLWJPGP_PINGPONG_SECS,\n+\tLWJPGP_TIMEOUT_SECS,\n+\tLWJPGP_REJECT_SERVICE_KEYWORDS_NAME,\n+\tLWJPGP_REJECT_SERVICE_KEYWORDS\n+};\n+\n+static const char * const paths_vhosts[] \u003d {\n+\t\u0022vhosts[]\u0022,\n+\t\u0022vhosts[].mounts[]\u0022,\n+\t\u0022vhosts[].name\u0022,\n+\t\u0022vhosts[].port\u0022,\n+\t\u0022vhosts[].interface\u0022,\n+\t\u0022vhosts[].unix-socket\u0022,\n+\t\u0022vhosts[].sts\u0022,\n+\t\u0022vhosts[].host-ssl-key\u0022,\n+\t\u0022vhosts[].host-ssl-cert\u0022,\n+\t\u0022vhosts[].host-ssl-ca\u0022,\n+\t\u0022vhosts[].access-log\u0022,\n+\t\u0022vhosts[].mounts[].mountpoint\u0022,\n+\t\u0022vhosts[].mounts[].origin\u0022,\n+\t\u0022vhosts[].mounts[].protocol\u0022,\n+\t\u0022vhosts[].mounts[].default\u0022,\n+\t\u0022vhosts[].mounts[].auth-mask\u0022,\n+\t\u0022vhosts[].mounts[].cgi-timeout\u0022,\n+\t\u0022vhosts[].mounts[].cgi-env[].*\u0022,\n+\t\u0022vhosts[].mounts[].cache-max-age\u0022,\n+\t\u0022vhosts[].mounts[].cache-reuse\u0022,\n+\t\u0022vhosts[].mounts[].cache-revalidate\u0022,\n+\t\u0022vhosts[].mounts[].basic-auth\u0022,\n+\t\u0022vhosts[].mounts[].cache-intermediaries\u0022,\n+\t\u0022vhosts[].mounts[].extra-mimetypes.*\u0022,\n+\t\u0022vhosts[].mounts[].interpret.*\u0022,\n+\t\u0022vhosts[].ws-protocols[].*.*\u0022,\n+\t\u0022vhosts[].ws-protocols[].*\u0022,\n+\t\u0022vhosts[].ws-protocols[]\u0022,\n+\t\u0022vhosts[].keepalive_timeout\u0022,\n+\t\u0022vhosts[].enable-client-ssl\u0022,\n+\t\u0022vhosts[].ciphers\u0022,\n+\t\u0022vhosts[].ecdh-curve\u0022,\n+\t\u0022vhosts[].noipv6\u0022,\n+\t\u0022vhosts[].ipv6only\u0022,\n+\t\u0022vhosts[].ssl-option-set\u0022,\n+\t\u0022vhosts[].ssl-option-clear\u0022,\n+\t\u0022vhosts[].mounts[].pmo[].*\u0022,\n+\t\u0022vhosts[].headers[].*\u0022,\n+\t\u0022vhosts[].headers[]\u0022,\n+\t\u0022vhosts[].client-ssl-key\u0022,\n+\t\u0022vhosts[].client-ssl-cert\u0022,\n+\t\u0022vhosts[].client-ssl-ca\u0022,\n+\t\u0022vhosts[].client-ssl-ciphers\u0022,\n+\t\u0022vhosts[].onlyraw\u0022,\n+};\n+\n+enum lejp_vhost_paths {\n+\tLEJPVP,\n+\tLEJPVP_MOUNTS,\n+\tLEJPVP_NAME,\n+\tLEJPVP_PORT,\n+\tLEJPVP_INTERFACE,\n+\tLEJPVP_UNIXSKT,\n+\tLEJPVP_STS,\n+\tLEJPVP_HOST_SSL_KEY,\n+\tLEJPVP_HOST_SSL_CERT,\n+\tLEJPVP_HOST_SSL_CA,\n+\tLEJPVP_ACCESS_LOG,\n+\tLEJPVP_MOUNTPOINT,\n+\tLEJPVP_ORIGIN,\n+\tLEJPVP_MOUNT_PROTOCOL,\n+\tLEJPVP_DEFAULT,\n+\tLEJPVP_DEFAULT_AUTH_MASK,\n+\tLEJPVP_CGI_TIMEOUT,\n+\tLEJPVP_CGI_ENV,\n+\tLEJPVP_MOUNT_CACHE_MAX_AGE,\n+\tLEJPVP_MOUNT_CACHE_REUSE,\n+\tLEJPVP_MOUNT_CACHE_REVALIDATE,\n+\tLEJPVP_MOUNT_BASIC_AUTH,\n+\tLEJPVP_MOUNT_CACHE_INTERMEDIARIES,\n+\tLEJPVP_MOUNT_EXTRA_MIMETYPES,\n+\tLEJPVP_MOUNT_INTERPRET,\n+\tLEJPVP_PROTOCOL_NAME_OPT,\n+\tLEJPVP_PROTOCOL_NAME,\n+\tLEJPVP_PROTOCOL,\n+\tLEJPVP_KEEPALIVE_TIMEOUT,\n+\tLEJPVP_ENABLE_CLIENT_SSL,\n+\tLEJPVP_CIPHERS,\n+\tLEJPVP_ECDH_CURVE,\n+\tLEJPVP_NOIPV6,\n+\tLEJPVP_IPV6ONLY,\n+\tLEJPVP_SSL_OPTION_SET,\n+\tLEJPVP_SSL_OPTION_CLEAR,\n+\tLEJPVP_PMO,\n+\tLEJPVP_HEADERS_NAME,\n+\tLEJPVP_HEADERS,\n+\tLEJPVP_CLIENT_SSL_KEY,\n+\tLEJPVP_CLIENT_SSL_CERT,\n+\tLEJPVP_CLIENT_SSL_CA,\n+\tLEJPVP_CLIENT_CIPHERS,\n+\tLEJPVP_FLAG_ONLYRAW,\n+};\n+\n+static const char * const parser_errs[] \u003d {\n+\t\u0022\u0022,\n+\t\u0022\u0022,\n+\t\u0022No opening '{'\u0022,\n+\t\u0022Expected closing '}'\u0022,\n+\t\u0022Expected '\u005c\u0022'\u0022,\n+\t\u0022String underrun\u0022,\n+\t\u0022Illegal unescaped control char\u0022,\n+\t\u0022Illegal escape format\u0022,\n+\t\u0022Illegal hex number\u0022,\n+\t\u0022Expected ':'\u0022,\n+\t\u0022Illegal value start\u0022,\n+\t\u0022Digit required after decimal point\u0022,\n+\t\u0022Bad number format\u0022,\n+\t\u0022Bad exponent format\u0022,\n+\t\u0022Unknown token\u0022,\n+\t\u0022Too many ']'\u0022,\n+\t\u0022Mismatched ']'\u0022,\n+\t\u0022Expected ']'\u0022,\n+\t\u0022JSON nesting limit exceeded\u0022,\n+\t\u0022Nesting tracking used up\u0022,\n+\t\u0022Number too long\u0022,\n+\t\u0022Comma or block end expected\u0022,\n+\t\u0022Unknown\u0022,\n+\t\u0022Parser callback errored (see earlier error)\u0022,\n+};\n+\n+#define MAX_PLUGIN_DIRS 10\n+\n+struct jpargs {\n+\tstruct lws_context_creation_info *info;\n+\tstruct lws_context *context;\n+\tconst struct lws_protocols *protocols;\n+\tconst struct lws_extension *extensions;\n+\tchar *p, *end, valid;\n+\tstruct lws_http_mount *head, *last;\n+\n+\tstruct lws_protocol_vhost_options *pvo;\n+\tstruct lws_protocol_vhost_options *pvo_em;\n+\tstruct lws_protocol_vhost_options *pvo_int;\n+\tstruct lws_http_mount m;\n+\tconst char **plugin_dirs;\n+\tint count_plugin_dirs;\n+\n+\tunsigned int enable_client_ssl:1;\n+\tunsigned int fresh_mount:1;\n+\tunsigned int any_vhosts:1;\n+};\n+\n+static void *\n+lwsws_align(struct jpargs *a)\n+{\n+\tif ((lws_intptr_t)(a-\u003ep) \u0026 15)\n+\t\ta-\u003ep +\u003d 16 - ((lws_intptr_t)(a-\u003ep) \u0026 15);\n+\n+\treturn a-\u003ep;\n+}\n+\n+static int\n+arg_to_bool(const char *s)\n+{\n+\tstatic const char * const on[] \u003d { \u0022on\u0022, \u0022yes\u0022, \u0022true\u0022 };\n+\tint n \u003d atoi(s);\n+\n+\tif (n)\n+\t\treturn 1;\n+\n+\tfor (n \u003d 0; n \u003c ARRAY_SIZE(on); n++)\n+\t\tif (!strcasecmp(s, on[n]))\n+\t\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+static char\n+lejp_globals_cb(struct lejp_ctx *ctx, char reason)\n+{\n+\tstruct jpargs *a \u003d (struct jpargs *)ctx-\u003euser;\n+\tstruct lws_protocol_vhost_options *rej;\n+\tint n;\n+\n+\t/* we only match on the prepared path strings */\n+\tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n+\t\treturn 0;\n+\n+\t/* this catches, eg, vhosts[].headers[].xxx */\n+\tif (reason \u003d\u003d LEJPCB_VAL_STR_END \u0026\u0026\n+\t ctx-\u003epath_match \u003d\u003d LWJPGP_REJECT_SERVICE_KEYWORDS_NAME + 1) {\n+\t\trej \u003d lwsws_align(a);\n+\t\ta-\u003ep +\u003d sizeof(*rej);\n+\n+\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n+\t\trej-\u003enext \u003d a-\u003einfo-\u003ereject_service_keywords;\n+\t\ta-\u003einfo-\u003ereject_service_keywords \u003d rej;\n+\t\trej-\u003ename \u003d a-\u003ep;\n+\t\t lwsl_notice(\u0022 adding rej %s\u003d%s\u005cn\u0022, a-\u003ep, ctx-\u003ebuf);\n+\t\ta-\u003ep +\u003d n - 1;\n+\t\t*(a-\u003ep++) \u003d '\u005c0';\n+\t\trej-\u003evalue \u003d a-\u003ep;\n+\t\trej-\u003eoptions \u003d NULL;\n+\t\tgoto dostring;\n+\t}\n+\n+\tswitch (ctx-\u003epath_match - 1) {\n+\tcase LEJPGP_UID:\n+\t\ta-\u003einfo-\u003euid \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPGP_GID:\n+\t\ta-\u003einfo-\u003egid \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPGP_COUNT_THREADS:\n+\t\ta-\u003einfo-\u003ecount_threads \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LWJPGP_INIT_SSL:\n+\t\tif (arg_to_bool(ctx-\u003ebuf))\n+\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n+\t\treturn 0;\n+\tcase LEJPGP_SERVER_STRING:\n+\t\ta-\u003einfo-\u003eserver_string \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPGP_PLUGIN_DIR:\n+\t\tif (a-\u003ecount_plugin_dirs \u003d\u003d MAX_PLUGIN_DIRS - 1) {\n+\t\t\tlwsl_err(\u0022Too many plugin dirs\u005cn\u0022);\n+\t\t\treturn -1;\n+\t\t}\n+\t\ta-\u003eplugin_dirs[a-\u003ecount_plugin_dirs++] \u003d a-\u003ep;\n+\t\tbreak;\n+\n+\tcase LWJPGP_PINGPONG_SECS:\n+\t\ta-\u003einfo-\u003ews_ping_pong_interval \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\n+\tcase LWJPGP_TIMEOUT_SECS:\n+\t\ta-\u003einfo-\u003etimeout_secs \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+\n+dostring:\n+\ta-\u003ep +\u003d lws_snprintf(a-\u003ep, a-\u003eend - a-\u003ep, \u0022%s\u0022, ctx-\u003ebuf);\n+\t*(a-\u003ep)++ \u003d '\u005c0';\n+\n+\treturn 0;\n+}\n+\n+static char\n+lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)\n+{\n+\tstruct jpargs *a \u003d (struct jpargs *)ctx-\u003euser;\n+\tstruct lws_protocol_vhost_options *pvo, *mp_cgienv, *headers;\n+\tstruct lws_http_mount *m;\n+\tchar *p, *p1;\n+\tint n;\n+\n+#if 0\n+\tlwsl_notice(\u0022 %d: %s (%d)\u005cn\u0022, reason, ctx-\u003epath, ctx-\u003epath_match);\n+\tfor (n \u003d 0; n \u003c ctx-\u003ewildcount; n++)\n+\t\tlwsl_notice(\u0022 %d\u005cn\u0022, ctx-\u003ewild[n]);\n+#endif\n+\n+\tif (reason \u003d\u003d LEJPCB_OBJECT_START \u0026\u0026 ctx-\u003epath_match \u003d\u003d LEJPVP + 1) {\n+\t\t/* set the defaults for this vhost */\n+\t\ta-\u003evalid \u003d 1;\n+\t\ta-\u003ehead \u003d NULL;\n+\t\ta-\u003elast \u003d NULL;\n+\t\ta-\u003einfo-\u003eport \u003d 0;\n+\t\ta-\u003einfo-\u003eiface \u003d NULL;\n+\t\ta-\u003einfo-\u003eprotocols \u003d a-\u003eprotocols;\n+\t\ta-\u003einfo-\u003eextensions \u003d a-\u003eextensions;\n+\t\ta-\u003einfo-\u003essl_cert_filepath \u003d NULL;\n+\t\ta-\u003einfo-\u003essl_private_key_filepath \u003d NULL;\n+\t\ta-\u003einfo-\u003essl_ca_filepath \u003d NULL;\n+\t\ta-\u003einfo-\u003eclient_ssl_cert_filepath \u003d NULL;\n+\t\ta-\u003einfo-\u003eclient_ssl_private_key_filepath \u003d NULL;\n+\t\ta-\u003einfo-\u003eclient_ssl_ca_filepath \u003d NULL;\n+\t\ta-\u003einfo-\u003eclient_ssl_cipher_list \u003d \u0022ECDHE-ECDSA-AES256-GCM-SHA384:\u0022\n+\t\t\t\u0022ECDHE-RSA-AES256-GCM-SHA384:\u0022\n+\t\t\t\u0022DHE-RSA-AES256-GCM-SHA384:\u0022\n+\t\t\t\u0022ECDHE-RSA-AES256-SHA384:\u0022\n+\t\t\t\u0022HIGH:!aNULL:!eNULL:!EXPORT:\u0022\n+\t\t\t\u0022!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:\u0022\n+\t\t\t\u0022!SHA1:!DHE-RSA-AES128-GCM-SHA256:\u0022\n+\t\t\t\u0022!DHE-RSA-AES128-SHA256:\u0022\n+\t\t\t\u0022!AES128-GCM-SHA256:\u0022\n+\t\t\t\u0022!AES128-SHA256:\u0022\n+\t\t\t\u0022!DHE-RSA-AES256-SHA256:\u0022\n+\t\t\t\u0022!AES256-GCM-SHA384:\u0022\n+\t\t\t\u0022!AES256-SHA256\u0022;\n+\t\ta-\u003einfo-\u003etimeout_secs \u003d 5;\n+\t\ta-\u003einfo-\u003essl_cipher_list \u003d \u0022ECDHE-ECDSA-AES256-GCM-SHA384:\u0022\n+\t\t\t\t \u0022ECDHE-RSA-AES256-GCM-SHA384:\u0022\n+\t\t\t\t \u0022DHE-RSA-AES256-GCM-SHA384:\u0022\n+\t\t\t\t \u0022ECDHE-RSA-AES256-SHA384:\u0022\n+\t\t\t\t \u0022HIGH:!aNULL:!eNULL:!EXPORT:\u0022\n+\t\t\t\t \u0022!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:\u0022\n+\t\t\t\t \u0022!SHA1:!DHE-RSA-AES128-GCM-SHA256:\u0022\n+\t\t\t\t \u0022!DHE-RSA-AES128-SHA256:\u0022\n+\t\t\t\t \u0022!AES128-GCM-SHA256:\u0022\n+\t\t\t\t \u0022!AES128-SHA256:\u0022\n+\t\t\t\t \u0022!DHE-RSA-AES256-SHA256:\u0022\n+\t\t\t\t \u0022!AES256-GCM-SHA384:\u0022\n+\t\t\t\t \u0022!AES256-SHA256\u0022;\n+\t\ta-\u003einfo-\u003epvo \u003d NULL;\n+\t\ta-\u003einfo-\u003eheaders \u003d NULL;\n+\t\ta-\u003einfo-\u003ekeepalive_timeout \u003d 5;\n+\t\ta-\u003einfo-\u003elog_filepath \u003d NULL;\n+\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_UNIX_SOCK |\n+\t\t\t\t LWS_SERVER_OPTION_STS | LWS_SERVER_OPTION_ONLY_RAW);\n+\t\ta-\u003eenable_client_ssl \u003d 0;\n+\t}\n+\n+\tif (reason \u003d\u003d LEJPCB_OBJECT_START \u0026\u0026\n+\t ctx-\u003epath_match \u003d\u003d LEJPVP_MOUNTS + 1) {\n+\t\ta-\u003efresh_mount \u003d 1;\n+\t\tmemset(\u0026a-\u003em, 0, sizeof(a-\u003em));\n+\t}\n+\n+\t/* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */\n+\tif (reason \u003d\u003d LEJPCB_OBJECT_START \u0026\u0026\n+\t ctx-\u003epath_match \u003d\u003d LEJPVP_PROTOCOL_NAME + 1) {\n+\t\ta-\u003epvo \u003d lwsws_align(a);\n+\t\ta-\u003ep +\u003d sizeof(*a-\u003epvo);\n+\n+\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n+\t\t/* ie, enable this protocol, no options yet */\n+\t\ta-\u003epvo-\u003enext \u003d a-\u003einfo-\u003epvo;\n+\t\ta-\u003einfo-\u003epvo \u003d a-\u003epvo;\n+\t\ta-\u003epvo-\u003ename \u003d a-\u003ep;\n+\t\tlwsl_notice(\u0022 adding protocol %s\u005cn\u0022, a-\u003ep);\n+\t\ta-\u003ep +\u003d n;\n+\t\ta-\u003epvo-\u003evalue \u003d a-\u003ep;\n+\t\ta-\u003epvo-\u003eoptions \u003d NULL;\n+\t\tgoto dostring;\n+\t}\n+\n+\t/* this catches, eg, vhosts[].headers[].xxx */\n+\tif (reason \u003d\u003d LEJPCB_VAL_STR_END \u0026\u0026\n+\t ctx-\u003epath_match \u003d\u003d LEJPVP_HEADERS_NAME + 1) {\n+\t\theaders \u003d lwsws_align(a);\n+\t\ta-\u003ep +\u003d sizeof(*headers);\n+\n+\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n+\t\t/* ie, enable this protocol, no options yet */\n+\t\theaders-\u003enext \u003d a-\u003einfo-\u003eheaders;\n+\t\ta-\u003einfo-\u003eheaders \u003d headers;\n+\t\theaders-\u003ename \u003d a-\u003ep;\n+\t\t// lwsl_notice(\u0022 adding header %s\u003d%s\u005cn\u0022, a-\u003ep, ctx-\u003ebuf);\n+\t\ta-\u003ep +\u003d n - 1;\n+\t\t*(a-\u003ep++) \u003d ':';\n+\t\tif (a-\u003ep \u003c a-\u003eend)\n+\t\t\t*(a-\u003ep++) \u003d '\u005c0';\n+\t\telse\n+\t\t\t*(a-\u003ep - 1) \u003d '\u005c0';\n+\t\theaders-\u003evalue \u003d a-\u003ep;\n+\t\theaders-\u003eoptions \u003d NULL;\n+\t\tgoto dostring;\n+\t}\n+\n+\tif (reason \u003d\u003d LEJPCB_OBJECT_END \u0026\u0026\n+\t (ctx-\u003epath_match \u003d\u003d LEJPVP + 1 || !ctx-\u003epath[0]) \u0026\u0026\n+\t a-\u003evalid) {\n+\n+\t\tstruct lws_vhost *vhost;\n+\n+\t\t//lwsl_notice(\u0022%s\u005cn\u0022, ctx-\u003epath);\n+\t\tif (!a-\u003einfo-\u003eport) {\n+\t\t\tlwsl_err(\u0022Port required (eg, 443)\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\t\ta-\u003evalid \u003d 0;\n+\t\ta-\u003einfo-\u003emounts \u003d a-\u003ehead;\n+\n+\t\tvhost \u003d lws_create_vhost(a-\u003econtext, a-\u003einfo);\n+\t\tif (!vhost) {\n+\t\t\tlwsl_err(\u0022Failed to create vhost %s\u005cn\u0022,\n+\t\t\t\t a-\u003einfo-\u003evhost_name);\n+\t\t\treturn 1;\n+\t\t}\n+\t\ta-\u003eany_vhosts \u003d 1;\n+\n+\t\tif (a-\u003eenable_client_ssl) {\n+\t\t\tconst char *cert_filepath \u003d a-\u003einfo-\u003eclient_ssl_cert_filepath;\n+\t\t\tconst char *private_key_filepath \u003d a-\u003einfo-\u003eclient_ssl_private_key_filepath;\n+\t\t\tconst char *ca_filepath \u003d a-\u003einfo-\u003eclient_ssl_ca_filepath;\n+\t\t\tconst char *cipher_list \u003d a-\u003einfo-\u003eclient_ssl_cipher_list;\n+\t\t\tmemset(a-\u003einfo, 0, sizeof(*a-\u003einfo));\n+\t\t\ta-\u003einfo-\u003eclient_ssl_cert_filepath \u003d cert_filepath;\n+\t\t\ta-\u003einfo-\u003eclient_ssl_private_key_filepath \u003d private_key_filepath;\n+\t\t\ta-\u003einfo-\u003eclient_ssl_ca_filepath \u003d ca_filepath;\n+\t\t\ta-\u003einfo-\u003eclient_ssl_cipher_list \u003d cipher_list;\n+\t\t\ta-\u003einfo-\u003eoptions \u003d LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n+\t\t\tlws_init_vhost_client_ssl(a-\u003einfo, vhost);\n+\t\t}\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (reason \u003d\u003d LEJPCB_OBJECT_END \u0026\u0026\n+\t ctx-\u003epath_match \u003d\u003d LEJPVP_MOUNTS + 1) {\n+\t\tstatic const char * const mount_protocols[] \u003d {\n+\t\t\t\u0022http://\u0022,\n+\t\t\t\u0022https://\u0022,\n+\t\t\t\u0022file://\u0022,\n+\t\t\t\u0022cgi://\u0022,\n+\t\t\t\u0022\u003ehttp://\u0022,\n+\t\t\t\u0022\u003ehttps://\u0022,\n+\t\t\t\u0022callback://\u0022,\n+\t\t\t\u0022gzip://\u0022,\n+\t\t};\n+\n+\t\tif (!a-\u003efresh_mount)\n+\t\t\treturn 0;\n+\n+\t\tif (!a-\u003em.mountpoint || !a-\u003em.origin) {\n+\t\t\tlwsl_err(\u0022mountpoint and origin required\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\t\tlwsl_debug(\u0022adding mount %s\u005cn\u0022, a-\u003em.mountpoint);\n+\t\tm \u003d lwsws_align(a);\n+\t\tmemcpy(m, \u0026a-\u003em, sizeof(*m));\n+\t\tif (a-\u003elast)\n+\t\t\ta-\u003elast-\u003emount_next \u003d m;\n+\n+\t\tfor (n \u003d 0; n \u003c ARRAY_SIZE(mount_protocols); n++)\n+\t\t\tif (!strncmp(a-\u003em.origin, mount_protocols[n],\n+\t\t\t strlen(mount_protocols[n]))) {\n+\t\t\t\tlwsl_info(\u0022----%s\u005cn\u0022, a-\u003em.origin);\n+\t\t\t\tm-\u003eorigin_protocol \u003d n;\n+\t\t\t\tm-\u003eorigin \u003d a-\u003em.origin +\n+\t\t\t\t\t strlen(mount_protocols[n]);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\tif (n \u003d\u003d ARRAY_SIZE(mount_protocols)) {\n+\t\t\tlwsl_err(\u0022unsupported protocol:// %s\u005cn\u0022, a-\u003em.origin);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\ta-\u003ep +\u003d sizeof(*m);\n+\t\tif (!a-\u003ehead)\n+\t\t\ta-\u003ehead \u003d m;\n+\n+\t\ta-\u003elast \u003d m;\n+\t\ta-\u003efresh_mount \u003d 0;\n+\t}\n+\n+\t/* we only match on the prepared path strings */\n+\tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n+\t\treturn 0;\n+\n+\tswitch (ctx-\u003epath_match - 1) {\n+\tcase LEJPVP_NAME:\n+\t\ta-\u003einfo-\u003evhost_name \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_PORT:\n+\t\ta-\u003einfo-\u003eport \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPVP_INTERFACE:\n+\t\ta-\u003einfo-\u003eiface \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_UNIXSKT:\n+\t\tif (arg_to_bool(ctx-\u003ebuf))\n+\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_UNIX_SOCK;\n+\t\telse\n+\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_UNIX_SOCK);\n+\t\treturn 0;\n+\tcase LEJPVP_STS:\n+\t\tif (arg_to_bool(ctx-\u003ebuf))\n+\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_STS;\n+\t\telse\n+\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_STS);\n+\t\treturn 0;\n+\tcase LEJPVP_HOST_SSL_KEY:\n+\t\ta-\u003einfo-\u003essl_private_key_filepath \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_HOST_SSL_CERT:\n+\t\ta-\u003einfo-\u003essl_cert_filepath \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_HOST_SSL_CA:\n+\t\ta-\u003einfo-\u003essl_ca_filepath \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_ACCESS_LOG:\n+\t\ta-\u003einfo-\u003elog_filepath \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_MOUNTPOINT:\n+\t\ta-\u003em.mountpoint \u003d a-\u003ep;\n+\t\ta-\u003em.mountpoint_len \u003d (unsigned char)strlen(ctx-\u003ebuf);\n+\t\tbreak;\n+\tcase LEJPVP_ORIGIN:\n+\t\tif (!strncmp(ctx-\u003ebuf, \u0022callback://\u0022, 11))\n+\t\t\ta-\u003em.protocol \u003d a-\u003ep + 11;\n+\n+\t\tif (!a-\u003em.origin)\n+\t\t\ta-\u003em.origin \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_DEFAULT:\n+\t\ta-\u003em.def \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_DEFAULT_AUTH_MASK:\n+\t\ta-\u003em.auth_mask \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPVP_MOUNT_CACHE_MAX_AGE:\n+\t\ta-\u003em.cache_max_age \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPVP_MOUNT_CACHE_REUSE:\n+\t\ta-\u003em.cache_reusable \u003d arg_to_bool(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPVP_MOUNT_CACHE_REVALIDATE:\n+\t\ta-\u003em.cache_revalidate \u003d arg_to_bool(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPVP_MOUNT_CACHE_INTERMEDIARIES:\n+\t\ta-\u003em.cache_intermediaries \u003d arg_to_bool(ctx-\u003ebuf);;\n+\t\treturn 0;\n+\tcase LEJPVP_MOUNT_BASIC_AUTH:\n+\t\ta-\u003em.basic_auth_login_file \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_CGI_TIMEOUT:\n+\t\ta-\u003em.cgi_timeout \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPVP_KEEPALIVE_TIMEOUT:\n+\t\ta-\u003einfo-\u003ekeepalive_timeout \u003d atoi(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPVP_CLIENT_CIPHERS:\n+\t\ta-\u003einfo-\u003eclient_ssl_cipher_list \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_CIPHERS:\n+\t\ta-\u003einfo-\u003essl_cipher_list \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_ECDH_CURVE:\n+\t\ta-\u003einfo-\u003eecdh_curve \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_PMO:\n+\tcase LEJPVP_CGI_ENV:\n+\t\tmp_cgienv \u003d lwsws_align(a);\n+\t\ta-\u003ep +\u003d sizeof(*a-\u003em.cgienv);\n+\n+\t\tmp_cgienv-\u003enext \u003d a-\u003em.cgienv;\n+\t\ta-\u003em.cgienv \u003d mp_cgienv;\n+\n+\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n+\t\tmp_cgienv-\u003ename \u003d a-\u003ep;\n+\t\ta-\u003ep +\u003d n;\n+\t\tmp_cgienv-\u003evalue \u003d a-\u003ep;\n+\t\tmp_cgienv-\u003eoptions \u003d NULL;\n+\t\t//lwsl_notice(\u0022 adding pmo / cgi-env '%s' \u003d '%s'\u005cn\u0022, mp_cgienv-\u003ename,\n+\t\t//\t\tmp_cgienv-\u003evalue);\n+\t\tgoto dostring;\n+\n+\tcase LEJPVP_PROTOCOL_NAME_OPT:\n+\t\t/* this catches, eg,\n+\t\t * vhosts[].ws-protocols[].xxx-protocol.yyy-option\n+\t\t * ie, these are options attached to a protocol with { }\n+\t\t */\n+\t\tpvo \u003d lwsws_align(a);\n+\t\ta-\u003ep +\u003d sizeof(*a-\u003epvo);\n+\n+\t\tn \u003d lejp_get_wildcard(ctx, 1, a-\u003ep, a-\u003eend - a-\u003ep);\n+\t\t/* ie, enable this protocol, no options yet */\n+\t\tpvo-\u003enext \u003d a-\u003epvo-\u003eoptions;\n+\t\ta-\u003epvo-\u003eoptions \u003d pvo;\n+\t\tpvo-\u003ename \u003d a-\u003ep;\n+\t\ta-\u003ep +\u003d n;\n+\t\tpvo-\u003evalue \u003d a-\u003ep;\n+\t\tpvo-\u003eoptions \u003d NULL;\n+\t\tbreak;\n+\n+\tcase LEJPVP_MOUNT_EXTRA_MIMETYPES:\n+\t\ta-\u003epvo_em \u003d lwsws_align(a);\n+\t\ta-\u003ep +\u003d sizeof(*a-\u003epvo_em);\n+\n+\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n+\t\t/* ie, enable this protocol, no options yet */\n+\t\ta-\u003epvo_em-\u003enext \u003d a-\u003em.extra_mimetypes;\n+\t\ta-\u003em.extra_mimetypes \u003d a-\u003epvo_em;\n+\t\ta-\u003epvo_em-\u003ename \u003d a-\u003ep;\n+\t\tlwsl_notice(\u0022 adding extra-mimetypes %s -\u003e %s\u005cn\u0022, a-\u003ep, ctx-\u003ebuf);\n+\t\ta-\u003ep +\u003d n;\n+\t\ta-\u003epvo_em-\u003evalue \u003d a-\u003ep;\n+\t\ta-\u003epvo_em-\u003eoptions \u003d NULL;\n+\t\tbreak;\n+\n+\tcase LEJPVP_MOUNT_INTERPRET:\n+\t\ta-\u003epvo_int \u003d lwsws_align(a);\n+\t\ta-\u003ep +\u003d sizeof(*a-\u003epvo_int);\n+\n+\t\tn \u003d lejp_get_wildcard(ctx, 0, a-\u003ep, a-\u003eend - a-\u003ep);\n+\t\t/* ie, enable this protocol, no options yet */\n+\t\ta-\u003epvo_int-\u003enext \u003d a-\u003em.interpret;\n+\t\ta-\u003em.interpret \u003d a-\u003epvo_int;\n+\t\ta-\u003epvo_int-\u003ename \u003d a-\u003ep;\n+\t\tlwsl_notice(\u0022 adding interpret %s -\u003e %s\u005cn\u0022, a-\u003ep,\n+\t\t\t ctx-\u003ebuf);\n+\t\ta-\u003ep +\u003d n;\n+\t\ta-\u003epvo_int-\u003evalue \u003d a-\u003ep;\n+\t\ta-\u003epvo_int-\u003eoptions \u003d NULL;\n+\t\tbreak;\n+\n+\tcase LEJPVP_ENABLE_CLIENT_SSL:\n+\t\ta-\u003eenable_client_ssl \u003d arg_to_bool(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPVP_CLIENT_SSL_KEY:\n+\t\ta-\u003einfo-\u003eclient_ssl_private_key_filepath \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_CLIENT_SSL_CERT:\n+\t\ta-\u003einfo-\u003eclient_ssl_cert_filepath \u003d a-\u003ep;\n+\t\tbreak;\n+\tcase LEJPVP_CLIENT_SSL_CA:\n+\t\ta-\u003einfo-\u003eclient_ssl_ca_filepath \u003d a-\u003ep;\n+\t\tbreak;\n+\n+\tcase LEJPVP_NOIPV6:\n+\t\tif (arg_to_bool(ctx-\u003ebuf))\n+\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_DISABLE_IPV6;\n+\t\telse\n+\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_DISABLE_IPV6);\n+\t\treturn 0;\n+\n+\tcase LEJPVP_FLAG_ONLYRAW:\n+\t\tif (arg_to_bool(ctx-\u003ebuf))\n+\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_ONLY_RAW;\n+\t\telse\n+\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_ONLY_RAW);\n+\t\treturn 0;\n+\n+\tcase LEJPVP_IPV6ONLY:\n+\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY;\n+\t\tif (arg_to_bool(ctx-\u003ebuf))\n+\t\t\ta-\u003einfo-\u003eoptions |\u003d LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE;\n+\t\telse\n+\t\t\ta-\u003einfo-\u003eoptions \u0026\u003d ~(LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);\n+\t\treturn 0;\n+\n+\tcase LEJPVP_SSL_OPTION_SET:\n+\t\ta-\u003einfo-\u003essl_options_set |\u003d atol(ctx-\u003ebuf);\n+\t\treturn 0;\n+\tcase LEJPVP_SSL_OPTION_CLEAR:\n+\t\ta-\u003einfo-\u003essl_options_clear |\u003d atol(ctx-\u003ebuf);\n+\t\treturn 0;\n+\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+\n+dostring:\n+\tp \u003d ctx-\u003ebuf;\n+\tp1 \u003d strstr(p, ESC_INSTALL_DATADIR);\n+\tif (p1) {\n+\t\tn \u003d p1 - p;\n+\t\tif (n \u003e a-\u003eend - a-\u003ep)\n+\t\t\tn \u003d a-\u003eend - a-\u003ep;\n+\t\tstrncpy(a-\u003ep, p, n);\n+\t\ta-\u003ep +\u003d n;\n+\t\ta-\u003ep +\u003d lws_snprintf(a-\u003ep, a-\u003eend - a-\u003ep, \u0022%s\u0022, LWS_INSTALL_DATADIR);\n+\t\tp +\u003d n + strlen(ESC_INSTALL_DATADIR);\n+\t}\n+\n+\ta-\u003ep +\u003d lws_snprintf(a-\u003ep, a-\u003eend - a-\u003ep, \u0022%s\u0022, p);\n+\t*(a-\u003ep)++ \u003d '\u005c0';\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * returns 0 \u003d OK, 1 \u003d can't open, 2 \u003d parsing error\n+ */\n+\n+static int\n+lwsws_get_config(void *user, const char *f, const char * const *paths,\n+\t\t int count_paths, lejp_callback cb)\n+{\n+\tunsigned char buf[128];\n+\tstruct lejp_ctx ctx;\n+\tint n, m, fd;\n+\n+\tfd \u003d open(f, O_RDONLY);\n+\tif (fd \u003c 0) {\n+\t\tlwsl_err(\u0022Cannot open %s\u005cn\u0022, f);\n+\t\treturn 2;\n+\t}\n+\tlwsl_info(\u0022%s: %s\u005cn\u0022, __func__, f);\n+\tlejp_construct(\u0026ctx, cb, user, paths, count_paths);\n+\n+\tdo {\n+\t\tn \u003d read(fd, buf, sizeof(buf));\n+\t\tif (!n)\n+\t\t\tbreak;\n+\n+\t\tm \u003d (int)(signed char)lejp_parse(\u0026ctx, buf, n);\n+\t} while (m \u003d\u003d LEJP_CONTINUE);\n+\n+\tclose(fd);\n+\tn \u003d ctx.line;\n+\tlejp_destruct(\u0026ctx);\n+\n+\tif (m \u003c 0) {\n+\t\tlwsl_err(\u0022%s(%u): parsing error %d: %s\u005cn\u0022, f, n, m,\n+\t\t\t parser_errs[-m]);\n+\t\treturn 2;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+#if defined(LWS_WITH_LIBUV) \u0026\u0026 UV_VERSION_MAJOR \u003e 0\n+\n+static int\n+lwsws_get_config_d(void *user, const char *d, const char * const *paths,\n+\t\t int count_paths, lejp_callback cb)\n+{\n+\tuv_dirent_t dent;\n+\tuv_fs_t req;\n+\tchar path[256];\n+\tint ret \u003d 0, ir;\n+\tuv_loop_t loop;\n+\n+\tir \u003d uv_loop_init(\u0026loop);\n+\tif (ir) {\n+\t\tlwsl_err(\u0022%s: loop init failed %d\u005cn\u0022, __func__, ir);\n+\t}\n+\n+\tif (!uv_fs_scandir(\u0026loop, \u0026req, d, 0, NULL)) {\n+\t\tlwsl_err(\u0022Scandir on %s failed\u005cn\u0022, d);\n+\t\treturn 2;\n+\t}\n+\n+\twhile (uv_fs_scandir_next(\u0026req, \u0026dent) !\u003d UV_EOF) {\n+\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, d, dent.name);\n+\t\tret \u003d lwsws_get_config(user, path, paths, count_paths, cb);\n+\t\tif (ret)\n+\t\t\tgoto bail;\n+\t}\n+\n+bail:\n+\tuv_fs_req_cleanup(\u0026req);\n+\twhile (uv_loop_close(\u0026loop))\n+\t\t;\n+\n+\treturn ret;\n+}\n+\n+#else\n+\n+#ifndef _WIN32\n+static int filter(const struct dirent *ent)\n+{\n+\tif (!strcmp(ent-\u003ed_name, \u0022.\u0022) || !strcmp(ent-\u003ed_name, \u0022..\u0022))\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+#endif\n+\n+static int\n+lwsws_get_config_d(void *user, const char *d, const char * const *paths,\n+\t\t int count_paths, lejp_callback cb)\n+{\n+#ifndef _WIN32\n+\tstruct dirent **namelist;\n+\tchar path[256];\n+\tint n, i, ret \u003d 0;\n+\n+\tn \u003d scandir(d, \u0026namelist, filter, alphasort);\n+\tif (n \u003c 0) {\n+\t\tlwsl_err(\u0022Scandir on %s failed\u005cn\u0022, d);\n+\t\treturn 1;\n+\t}\n+\n+\tfor (i \u003d 0; i \u003c n; i++) {\n+\t\tif (strchr(namelist[i]-\u003ed_name, '~'))\n+\t\t\tgoto skip;\n+\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, d,\n+\t\t\t namelist[i]-\u003ed_name);\n+\t\tret \u003d lwsws_get_config(user, path, paths, count_paths, cb);\n+\t\tif (ret) {\n+\t\t\twhile (i++ \u003c n)\n+\t\t\t\tfree(namelist[i]);\n+\t\t\tgoto bail;\n+\t\t}\n+skip:\n+\t\tfree(namelist[i]);\n+\t}\n+\n+bail:\n+\tfree(namelist);\n+\n+\treturn ret;\n+#else\n+\treturn 0;\n+#endif\n+}\n+\n+#endif\n+\n+int\n+lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,\n+\t\t\t char **cs, int *len)\n+{\n+\tstruct jpargs a;\n+\tconst char * const *old \u003d info-\u003eplugin_dirs;\n+\tchar dd[128];\n+\n+\tmemset(\u0026a, 0, sizeof(a));\n+\n+\ta.info \u003d info;\n+\ta.p \u003d *cs;\n+\ta.end \u003d (a.p + *len) - 1;\n+\ta.valid \u003d 0;\n+\n+\tlwsws_align(\u0026a);\n+\tinfo-\u003eplugin_dirs \u003d (void *)a.p;\n+\ta.plugin_dirs \u003d (void *)a.p; /* writeable version */\n+\ta.p +\u003d MAX_PLUGIN_DIRS * sizeof(void *);\n+\n+\t/* copy any default paths */\n+\n+\twhile (old \u0026\u0026 *old) {\n+\t\ta.plugin_dirs[a.count_plugin_dirs++] \u003d *old;\n+\t\told++;\n+\t}\n+\n+\tlws_snprintf(dd, sizeof(dd) - 1, \u0022%s/conf\u0022, d);\n+\tif (lwsws_get_config(\u0026a, dd, paths_global,\n+\t\t\t ARRAY_SIZE(paths_global), lejp_globals_cb) \u003e 1)\n+\t\treturn 1;\n+\tlws_snprintf(dd, sizeof(dd) - 1, \u0022%s/conf.d\u0022, d);\n+\tif (lwsws_get_config_d(\u0026a, dd, paths_global,\n+\t\t\t ARRAY_SIZE(paths_global), lejp_globals_cb) \u003e 1)\n+\t\treturn 1;\n+\n+\ta.plugin_dirs[a.count_plugin_dirs] \u003d NULL;\n+\n+\t*cs \u003d a.p;\n+\t*len \u003d a.end - a.p;\n+\n+\treturn 0;\n+}\n+\n+int\n+lwsws_get_config_vhosts(struct lws_context *context,\n+\t\t\tstruct lws_context_creation_info *info, const char *d,\n+\t\t\tchar **cs, int *len)\n+{\n+\tstruct jpargs a;\n+\tchar dd[128];\n+\n+\tmemset(\u0026a, 0, sizeof(a));\n+\n+\ta.info \u003d info;\n+\ta.p \u003d *cs;\n+\ta.end \u003d a.p + *len;\n+\ta.valid \u003d 0;\n+\ta.context \u003d context;\n+\ta.protocols \u003d info-\u003eprotocols;\n+\ta.extensions \u003d info-\u003eextensions;\n+\n+\tlws_snprintf(dd, sizeof(dd) - 1, \u0022%s/conf\u0022, d);\n+\tif (lwsws_get_config(\u0026a, dd, paths_vhosts,\n+\t\t\t ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) \u003e 1)\n+\t\treturn 1;\n+\tlws_snprintf(dd, sizeof(dd) - 1, \u0022%s/conf.d\u0022, d);\n+\tif (lwsws_get_config_d(\u0026a, dd, paths_vhosts,\n+\t\t\t ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) \u003e 1)\n+\t\treturn 1;\n+\n+\t*cs \u003d a.p;\n+\t*len \u003d a.end - a.p;\n+\n+\tif (!a.any_vhosts) {\n+\t\tlwsl_err(\u0022Need at least one vhost\u005cn\u0022);\n+\t\treturn 1;\n+\t}\n+\n+//\tlws_finalize_startup(context);\n+\n+\treturn 0;\n+}\ndiff --git a/lib/server/lws-spa.c b/lib/server/lws-spa.c\nnew file mode 100644\nindex 0000000..73117c5\n--- /dev/null\n+++ b/lib/server/lws-spa.c\n@@ -0,0 +1,586 @@\n+/*\n+ * libwebsockets - Stateful urldecode for POST\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#define LWS_MAX_ELEM_NAME 32\n+\n+enum urldecode_stateful {\n+\tUS_NAME,\n+\tUS_IDLE,\n+\tUS_PC1,\n+\tUS_PC2,\n+\n+\tMT_LOOK_BOUND_IN,\n+\tMT_HNAME,\n+\tMT_DISP,\n+\tMT_TYPE,\n+\tMT_IGNORE1,\n+\tMT_IGNORE2,\n+};\n+\n+static const char * const mp_hdr[] \u003d {\n+\t\u0022content-disposition: \u0022,\n+\t\u0022content-type: \u0022,\n+\t\u0022\u005cx0d\u005cx0a\u0022\n+};\n+\n+typedef int (*lws_urldecode_stateful_cb)(void *data,\n+\t\tconst char *name, char **buf, int len, int final);\n+\n+struct lws_urldecode_stateful {\n+\tchar *out;\n+\tvoid *data;\n+\tchar name[LWS_MAX_ELEM_NAME];\n+\tchar temp[LWS_MAX_ELEM_NAME];\n+\tchar content_type[32];\n+\tchar content_disp[32];\n+\tchar content_disp_filename[256];\n+\tchar mime_boundary[128];\n+\tint out_len;\n+\tint pos;\n+\tint hdr_idx;\n+\tint mp;\n+\tint sum;\n+\n+\tunsigned int multipart_form_data:1;\n+\tunsigned int inside_quote:1;\n+\tunsigned int subname:1;\n+\tunsigned int boundary_real_crlf:1;\n+\n+\tenum urldecode_stateful state;\n+\n+\tlws_urldecode_stateful_cb output;\n+};\n+\n+static struct lws_urldecode_stateful *\n+lws_urldecode_s_create(struct lws *wsi, char *out, int out_len, void *data,\n+\t\t lws_urldecode_stateful_cb output)\n+{\n+\tstruct lws_urldecode_stateful *s \u003d lws_zalloc(sizeof(*s),\n+\t\t\t\t\t\t\u0022stateful urldecode\u0022);\n+\tchar buf[200], *p;\n+\tint m \u003d 0;\n+\n+\tif (!s)\n+\t\treturn NULL;\n+\n+\ts-\u003eout \u003d out;\n+\ts-\u003eout_len \u003d out_len;\n+\ts-\u003eoutput \u003d output;\n+\ts-\u003epos \u003d 0;\n+\ts-\u003esum \u003d 0;\n+\ts-\u003emp \u003d 0;\n+\ts-\u003estate \u003d US_NAME;\n+\ts-\u003ename[0] \u003d '\u005c0';\n+\ts-\u003edata \u003d data;\n+\n+\tif (lws_hdr_copy(wsi, buf, sizeof(buf),\n+\t\t\t WSI_TOKEN_HTTP_CONTENT_TYPE) \u003e 0) {\n+\t/* multipart/form-data; boundary\u003d----WebKitFormBoundarycc7YgAPEIHvgE9Bf */\n+\n+\t\tif (!strncmp(buf, \u0022multipart/form-data\u0022, 19)) {\n+\t\t\ts-\u003emultipart_form_data \u003d 1;\n+\t\t\ts-\u003estate \u003d MT_LOOK_BOUND_IN;\n+\t\t\ts-\u003emp \u003d 2;\n+\t\t\tp \u003d strstr(buf, \u0022boundary\u003d\u0022);\n+\t\t\tif (p) {\n+\t\t\t\tp +\u003d 9;\n+\t\t\t\ts-\u003emime_boundary[m++] \u003d '\u005cx0d';\n+\t\t\t\ts-\u003emime_boundary[m++] \u003d '\u005cx0a';\n+\t\t\t\ts-\u003emime_boundary[m++] \u003d '-';\n+\t\t\t\ts-\u003emime_boundary[m++] \u003d '-';\n+\t\t\t\twhile (m \u003c sizeof(s-\u003emime_boundary) - 1 \u0026\u0026\n+\t\t\t\t *p \u0026\u0026 *p !\u003d ' ')\n+\t\t\t\t\ts-\u003emime_boundary[m++] \u003d *p++;\n+\n+\t\t\t\ts-\u003emime_boundary[m] \u003d '\u005c0';\n+\n+\t\t\t\tlwsl_notice(\u0022boundary '%s'\u005cn\u0022, s-\u003emime_boundary);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn s;\n+}\n+\n+static int\n+lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in,\n+\t\t\tint len)\n+{\n+\tint n, m, hit \u003d 0;\n+\tchar c, was_end \u003d 0;\n+\n+\twhile (len--) {\n+\t\tif (s-\u003epos \u003d\u003d s-\u003eout_len - s-\u003emp - 1) {\n+\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename, \u0026s-\u003eout, s-\u003epos, 0))\n+\t\t\t\treturn -1;\n+\n+\t\t\twas_end \u003d s-\u003epos;\n+\t\t\ts-\u003epos \u003d 0;\n+\t\t}\n+\t\tswitch (s-\u003estate) {\n+\n+\t\t/* states for url arg style */\n+\n+\t\tcase US_NAME:\n+\t\t\ts-\u003einside_quote \u003d 0;\n+\t\t\tif (*in \u003d\u003d '\u003d') {\n+\t\t\t\ts-\u003ename[s-\u003epos] \u003d '\u005c0';\n+\t\t\t\ts-\u003epos \u003d 0;\n+\t\t\t\ts-\u003estate \u003d US_IDLE;\n+\t\t\t\tin++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (*in \u003d\u003d '\u0026') {\n+\t\t\t\ts-\u003ename[s-\u003epos] \u003d '\u005c0';\n+\t\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename, \u0026s-\u003eout,\n+\t\t\t\t\t s-\u003epos, 1))\n+\t\t\t\t\treturn -1;\n+\t\t\t\ts-\u003epos \u003d 0;\n+\t\t\t\ts-\u003estate \u003d US_IDLE;\n+\t\t\t\tin++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (s-\u003epos \u003e\u003d sizeof(s-\u003ename) - 1) {\n+\t\t\t\tlwsl_notice(\u0022Name too long\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\ts-\u003ename[s-\u003epos++] \u003d *in++;\n+\t\t\tbreak;\n+\t\tcase US_IDLE:\n+\t\t\tif (*in \u003d\u003d '%') {\n+\t\t\t\ts-\u003estate++;\n+\t\t\t\tin++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (*in \u003d\u003d '\u0026') {\n+\t\t\t\ts-\u003eout[s-\u003epos] \u003d '\u005c0';\n+\t\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename, \u0026s-\u003eout,\n+\t\t\t\t\t s-\u003epos, 1))\n+\t\t\t\t\treturn -1;\n+\t\t\t\ts-\u003epos \u003d 0;\n+\t\t\t\ts-\u003estate \u003d US_NAME;\n+\t\t\t\tin++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (*in \u003d\u003d '+') {\n+\t\t\t\tin++;\n+\t\t\t\ts-\u003eout[s-\u003epos++] \u003d ' ';\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\ts-\u003eout[s-\u003epos++] \u003d *in++;\n+\t\t\tbreak;\n+\t\tcase US_PC1:\n+\t\t\tn \u003d char_to_hex(*in);\n+\t\t\tif (n \u003c 0)\n+\t\t\t\treturn -1;\n+\n+\t\t\tin++;\n+\t\t\ts-\u003esum \u003d n \u003c\u003c 4;\n+\t\t\ts-\u003estate++;\n+\t\t\tbreak;\n+\n+\t\tcase US_PC2:\n+\t\t\tn \u003d char_to_hex(*in);\n+\t\t\tif (n \u003c 0)\n+\t\t\t\treturn -1;\n+\n+\t\t\tin++;\n+\t\t\ts-\u003eout[s-\u003epos++] \u003d s-\u003esum | n;\n+\t\t\ts-\u003estate \u003d US_IDLE;\n+\t\t\tbreak;\n+\n+\n+\t\t/* states for multipart / mime style */\n+\n+\t\tcase MT_LOOK_BOUND_IN:\n+retry_as_first:\n+\t\t\tif (*in \u003d\u003d s-\u003emime_boundary[s-\u003emp] \u0026\u0026\n+\t\t\t s-\u003emime_boundary[s-\u003emp]) {\n+\t\t\t\tin++;\n+\t\t\t\ts-\u003emp++;\n+\t\t\t\tif (!s-\u003emime_boundary[s-\u003emp]) {\n+\t\t\t\t\ts-\u003emp \u003d 0;\n+\t\t\t\t\ts-\u003estate \u003d MT_IGNORE1;\n+\n+\t\t\t\t\tif (s-\u003epos || was_end)\n+\t\t\t\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename,\n+\t\t\t\t\t\t \u0026s-\u003eout, s-\u003epos, 1))\n+\t\t\t\t\t\t\treturn -1;\n+\n+\t\t\t\t\ts-\u003epos \u003d 0;\n+\n+\t\t\t\t\ts-\u003econtent_disp[0] \u003d '\u005c0';\n+\t\t\t\t\ts-\u003ename[0] \u003d '\u005c0';\n+\t\t\t\t\ts-\u003econtent_disp_filename[0] \u003d '\u005c0';\n+\t\t\t\t\ts-\u003eboundary_real_crlf \u003d 1;\n+\t\t\t\t}\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (s-\u003emp) {\n+\t\t\t\tn \u003d 0;\n+\t\t\t\tif (!s-\u003eboundary_real_crlf)\n+\t\t\t\t\tn \u003d 2;\n+\n+\t\t\t\tmemcpy(s-\u003eout + s-\u003epos, s-\u003emime_boundary + n,\n+\t\t\t\t s-\u003emp - n);\n+\t\t\t\ts-\u003epos +\u003d s-\u003emp;\n+\t\t\t\ts-\u003emp \u003d 0;\n+\t\t\t\tgoto retry_as_first;\n+\t\t\t}\n+\n+\t\t\ts-\u003eout[s-\u003epos++] \u003d *in;\n+\t\t\tin++;\n+\t\t\ts-\u003emp \u003d 0;\n+\t\t\tbreak;\n+\n+\t\tcase MT_HNAME:\n+\t\t\tm \u003d 0;\n+\t\t\tc \u003d*in;\n+\t\t\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'Z')\n+\t\t\t\tc +\u003d 'a' - 'A';\n+\t\t\tfor (n \u003d 0; n \u003c ARRAY_SIZE(mp_hdr); n++)\n+\t\t\t\tif (c \u003d\u003d mp_hdr[n][s-\u003emp]) {\n+\t\t\t\t\tm++;\n+\t\t\t\t\thit \u003d n;\n+\t\t\t\t}\n+\t\t\tin++;\n+\t\t\tif (!m) {\n+\t\t\t\ts-\u003emp \u003d 0;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\ts-\u003emp++;\n+\t\t\tif (m !\u003d 1)\n+\t\t\t\tcontinue;\n+\n+\t\t\tif (mp_hdr[hit][s-\u003emp])\n+\t\t\t\tcontinue;\n+\n+\t\t\ts-\u003emp \u003d 0;\n+\t\t\ts-\u003etemp[0] \u003d '\u005c0';\n+\t\t\ts-\u003esubname \u003d 0;\n+\n+\t\t\tif (hit \u003d\u003d 2)\n+\t\t\t\ts-\u003estate \u003d MT_LOOK_BOUND_IN;\n+\t\t\telse\n+\t\t\t\ts-\u003estate +\u003d hit + 1;\n+\t\t\tbreak;\n+\n+\t\tcase MT_DISP:\n+\t\t\t/* form-data; name\u003d\u0022file\u0022; filename\u003d\u0022t.txt\u0022 */\n+\n+\t\t\tif (*in \u003d\u003d '\u005cx0d') {\n+\t\t\t\tif (s-\u003econtent_disp_filename[0])\n+\t\t\t\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename,\n+\t\t\t\t\t\t \u0026s-\u003eout, s-\u003epos,\n+\t\t\t\t\t\t LWS_UFS_OPEN))\n+\t\t\t\t\t\treturn -1;\n+\t\t\t\ts-\u003estate \u003d MT_IGNORE2;\n+\t\t\t\tgoto done;\n+\t\t\t}\n+\t\t\tif (*in \u003d\u003d ';') {\n+\t\t\t\ts-\u003esubname \u003d 1;\n+\t\t\t\ts-\u003etemp[0] \u003d '\u005c0';\n+\t\t\t\ts-\u003emp \u003d 0;\n+\t\t\t\tgoto done;\n+\t\t\t}\n+\n+\t\t\tif (*in \u003d\u003d '\u005c\u0022') {\n+\t\t\t\ts-\u003einside_quote ^\u003d 1;\n+\t\t\t\tgoto done;\n+\t\t\t}\n+\n+\t\t\tif (s-\u003esubname) {\n+\t\t\t\tif (*in \u003d\u003d '\u003d') {\n+\t\t\t\t\ts-\u003etemp[s-\u003emp] \u003d '\u005c0';\n+\t\t\t\t\ts-\u003esubname \u003d 0;\n+\t\t\t\t\ts-\u003emp \u003d 0;\n+\t\t\t\t\tgoto done;\n+\t\t\t\t}\n+\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003etemp) - 1 \u0026\u0026\n+\t\t\t\t (*in !\u003d ' ' || s-\u003einside_quote))\n+\t\t\t\t\ts-\u003etemp[s-\u003emp++] \u003d *in;\n+\t\t\t\tgoto done;\n+\t\t\t}\n+\n+\t\t\tif (!s-\u003etemp[0]) {\n+\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003econtent_disp) - 1)\n+\t\t\t\t\ts-\u003econtent_disp[s-\u003emp++] \u003d *in;\n+\t\t\t\ts-\u003econtent_disp[s-\u003emp] \u003d '\u005c0';\n+\t\t\t\tgoto done;\n+\t\t\t}\n+\n+\t\t\tif (!strcmp(s-\u003etemp, \u0022name\u0022)) {\n+\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003ename) - 1)\n+\t\t\t\t\ts-\u003ename[s-\u003emp++] \u003d *in;\n+\t\t\t\ts-\u003ename[s-\u003emp] \u003d '\u005c0';\n+\t\t\t\tgoto done;\n+\t\t\t}\n+\n+\t\t\tif (!strcmp(s-\u003etemp, \u0022filename\u0022)) {\n+\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003econtent_disp_filename) - 1)\n+\t\t\t\t\ts-\u003econtent_disp_filename[s-\u003emp++] \u003d *in;\n+\t\t\t\ts-\u003econtent_disp_filename[s-\u003emp] \u003d '\u005c0';\n+\t\t\t\tgoto done;\n+\t\t\t}\n+done:\n+\t\t\tin++;\n+\t\t\tbreak;\n+\n+\t\tcase MT_TYPE:\n+\t\t\tif (*in \u003d\u003d '\u005cx0d')\n+\t\t\t\ts-\u003estate \u003d MT_IGNORE2;\n+\t\t\telse {\n+\t\t\t\tif (s-\u003emp \u003c sizeof(s-\u003econtent_type) - 1)\n+\t\t\t\t\ts-\u003econtent_type[s-\u003emp++] \u003d *in;\n+\t\t\t\ts-\u003econtent_type[s-\u003emp] \u003d '\u005c0';\n+\t\t\t}\n+\t\t\tin++;\n+\t\t\tbreak;\n+\n+\t\tcase MT_IGNORE1:\n+\t\t\tif (*in \u003d\u003d '\u005cx0d')\n+\t\t\t\ts-\u003estate \u003d MT_IGNORE2;\n+\t\t\tin++;\n+\t\t\tbreak;\n+\n+\t\tcase MT_IGNORE2:\n+\t\t\ts-\u003emp \u003d 0;\n+\t\t\tif (*in \u003d\u003d '\u005cx0a')\n+\t\t\t\ts-\u003estate \u003d MT_HNAME;\n+\t\t\tin++;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+lws_urldecode_s_destroy(struct lws_urldecode_stateful *s)\n+{\n+\tint ret \u003d 0;\n+\n+\tif (s-\u003estate !\u003d US_IDLE)\n+\t\tret \u003d -1;\n+\n+\tif (!ret)\n+\t\tif (s-\u003eoutput(s-\u003edata, s-\u003ename, \u0026s-\u003eout, s-\u003epos, 1))\n+\t\t\tret \u003d -1;\n+\n+\tlws_free(s);\n+\n+\treturn ret;\n+}\n+\n+struct lws_spa {\n+\tstruct lws_urldecode_stateful *s;\n+\tlws_spa_fileupload_cb opt_cb;\n+\tconst char * const *param_names;\n+\tint count_params;\n+\tchar **params;\n+\tint *param_length;\n+\tvoid *opt_data;\n+\n+\tchar *storage;\n+\tchar *end;\n+\tint max_storage;\n+\n+\tchar finalized;\n+};\n+\n+static int\n+lws_urldecode_spa_lookup(struct lws_spa *spa,\n+\t\t\t const char *name)\n+{\n+\tint n;\n+\n+\tfor (n \u003d 0; n \u003c spa-\u003ecount_params; n++)\n+\t\tif (!strcmp(spa-\u003eparam_names[n], name))\n+\t\t\treturn n;\n+\n+\treturn -1;\n+}\n+\n+static int\n+lws_urldecode_spa_cb(void *data, const char *name, char **buf, int len,\n+\t\t int final)\n+{\n+\tstruct lws_spa *spa \u003d\n+\t\t\t(struct lws_spa *)data;\n+\tint n;\n+\n+\tif (spa-\u003es-\u003econtent_disp_filename[0]) {\n+\t\tif (spa-\u003eopt_cb) {\n+\t\t\tn \u003d spa-\u003eopt_cb(spa-\u003eopt_data, name,\n+\t\t\t\t\tspa-\u003es-\u003econtent_disp_filename,\n+\t\t\t\t\t*buf, len, final);\n+\n+\t\t\tif (n \u003c 0)\n+\t\t\t\treturn -1;\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\tn \u003d lws_urldecode_spa_lookup(spa, name);\n+\n+\tif (n \u003d\u003d -1 || !len) /* unrecognized */\n+\t\treturn 0;\n+\n+\tif (!spa-\u003eparams[n])\n+\t\tspa-\u003eparams[n] \u003d *buf;\n+\n+\tif ((*buf) + len \u003e\u003d spa-\u003eend) {\n+\t\tlwsl_notice(\u0022%s: exceeded storage\u005cn\u0022, __func__);\n+\t\treturn -1;\n+\t}\n+\n+\tspa-\u003eparam_length[n] +\u003d len;\n+\n+\t/* move it on inside storage */\n+\t(*buf) +\u003d len;\n+\t*((*buf)++) \u003d '\u005c0';\n+\n+\tspa-\u003es-\u003eout_len -\u003d len + 1;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN struct lws_spa *\n+lws_spa_create(struct lws *wsi, const char * const *param_names,\n+\t\t\t int count_params, int max_storage,\n+\t\t\t lws_spa_fileupload_cb opt_cb, void *opt_data)\n+{\n+\tstruct lws_spa *spa \u003d lws_zalloc(sizeof(*spa), \u0022spa\u0022);\n+\n+\tif (!spa)\n+\t\treturn NULL;\n+\n+\tspa-\u003eparam_names \u003d param_names;\n+\tspa-\u003ecount_params \u003d count_params;\n+\tspa-\u003emax_storage \u003d max_storage;\n+\tspa-\u003eopt_cb \u003d opt_cb;\n+\tspa-\u003eopt_data \u003d opt_data;\n+\n+\tspa-\u003estorage \u003d lws_malloc(max_storage, \u0022spa\u0022);\n+\tif (!spa-\u003estorage)\n+\t\tgoto bail2;\n+\tspa-\u003eend \u003d spa-\u003estorage + max_storage - 1;\n+\n+\tspa-\u003eparams \u003d lws_zalloc(sizeof(char *) * count_params, \u0022spa params\u0022);\n+\tif (!spa-\u003eparams)\n+\t\tgoto bail3;\n+\n+\tspa-\u003es \u003d lws_urldecode_s_create(wsi, spa-\u003estorage, max_storage, spa,\n+\t\t\t\t\tlws_urldecode_spa_cb);\n+\tif (!spa-\u003es)\n+\t\tgoto bail4;\n+\n+\tspa-\u003eparam_length \u003d lws_zalloc(sizeof(int) * count_params,\n+\t\t\t\t\t\u0022spa param len\u0022);\n+\tif (!spa-\u003eparam_length)\n+\t\tgoto bail5;\n+\n+\tlwsl_info(\u0022%s: Created SPA %p\u005cn\u0022, __func__, spa);\n+\n+\treturn spa;\n+\n+bail5:\n+\tlws_urldecode_s_destroy(spa-\u003es);\n+bail4:\n+\tlws_free(spa-\u003eparams);\n+bail3:\n+\tlws_free(spa-\u003estorage);\n+bail2:\n+\tlws_free(spa);\n+\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_spa_process(struct lws_spa *ludspa, const char *in, int len)\n+{\n+\tif (!ludspa) {\n+\t\tlwsl_err(\u0022%s: NULL spa\u005cn\u0022, __func__);\n+\t\treturn -1;\n+\t}\n+\t/* we reject any junk after the last part arrived and we finalized */\n+\tif (ludspa-\u003efinalized)\n+\t\treturn 0;\n+\n+\treturn lws_urldecode_s_process(ludspa-\u003es, in, len);\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_spa_get_length(struct lws_spa *ludspa, int n)\n+{\n+\tif (n \u003e\u003d ludspa-\u003ecount_params)\n+\t\treturn 0;\n+\n+\treturn ludspa-\u003eparam_length[n];\n+}\n+\n+LWS_VISIBLE LWS_EXTERN const char *\n+lws_spa_get_string(struct lws_spa *ludspa, int n)\n+{\n+\tif (n \u003e\u003d ludspa-\u003ecount_params)\n+\t\treturn NULL;\n+\n+\treturn ludspa-\u003eparams[n];\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_spa_finalize(struct lws_spa *spa)\n+{\n+\tif (spa-\u003es) {\n+\t\tlws_urldecode_s_destroy(spa-\u003es);\n+\t\tspa-\u003es \u003d NULL;\n+\t}\n+\n+\tspa-\u003efinalized \u003d 1;\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_spa_destroy(struct lws_spa *spa)\n+{\n+\tint n \u003d 0;\n+\n+\tlwsl_notice(\u0022%s: destroy spa %p\u005cn\u0022, __func__, spa);\n+\n+\tif (spa-\u003es)\n+\t\tlws_urldecode_s_destroy(spa-\u003es);\n+\n+\tlwsl_debug(\u0022%s %p %p %p %p\u005cn\u0022, __func__,\n+\t\t\tspa-\u003eparam_length,\n+\t\t\tspa-\u003eparams,\n+\t\t\tspa-\u003estorage,\n+\t\t\tspa);\n+\n+\tlws_free(spa-\u003eparam_length);\n+\tlws_free(spa-\u003eparams);\n+\tlws_free(spa-\u003estorage);\n+\tlws_free(spa);\n+\n+\treturn n;\n+}\ndiff --git a/lib/server/parsers.c b/lib/server/parsers.c\nnew file mode 100644\nindex 0000000..f4c412d\n--- /dev/null\n+++ b/lib/server/parsers.c\n@@ -0,0 +1,1781 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+const unsigned char lextable[] \u003d {\n+\t#include \u0022lextable.h\u0022\n+};\n+\n+#define FAIL_CHAR 0x08\n+\n+int LWS_WARN_UNUSED_RESULT\n+lextable_decode(int pos, char c)\n+{\n+\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'Z')\n+\t\tc +\u003d 'a' - 'A';\n+\n+\twhile (1) {\n+\t\tif (lextable[pos] \u0026 (1 \u003c\u003c 7)) { /* 1-byte, fail on mismatch */\n+\t\t\tif ((lextable[pos] \u0026 0x7f) !\u003d c)\n+\t\t\t\treturn -1;\n+\t\t\t/* fall thru */\n+\t\t\tpos++;\n+\t\t\tif (lextable[pos] \u003d\u003d FAIL_CHAR)\n+\t\t\t\treturn -1;\n+\t\t\treturn pos;\n+\t\t}\n+\n+\t\tif (lextable[pos] \u003d\u003d FAIL_CHAR)\n+\t\t\treturn -1;\n+\n+\t\t/* b7 \u003d 0, end or 3-byte */\n+\t\tif (lextable[pos] \u003c FAIL_CHAR) /* terminal marker */\n+\t\t\treturn pos;\n+\n+\t\tif (lextable[pos] \u003d\u003d c) /* goto */\n+\t\t\treturn pos + (lextable[pos + 1]) +\n+\t\t\t\t\t\t(lextable[pos + 2] \u003c\u003c 8);\n+\t\t/* fall thru goto */\n+\t\tpos +\u003d 3;\n+\t\t/* continue */\n+\t}\n+}\n+\n+static struct allocated_headers *\n+_lws_create_ah(struct lws_context_per_thread *pt, ah_data_idx_t data_size)\n+{\n+\tstruct allocated_headers *ah \u003d lws_zalloc(sizeof(*ah), \u0022ah struct\u0022);\n+\n+\tif (!ah)\n+\t\treturn NULL;\n+\n+\tah-\u003edata \u003d lws_malloc(data_size, \u0022ah data\u0022);\n+\tif (!ah-\u003edata) {\n+\t\tlws_free(ah);\n+\n+\t\treturn NULL;\n+\t}\n+\tah-\u003enext \u003d pt-\u003eah_list;\n+\tpt-\u003eah_list \u003d ah;\n+\tah-\u003edata_length \u003d data_size;\n+\tpt-\u003eah_pool_length++;\n+\n+\tlwsl_info(\u0022%s: created ah %p (size %d): pool length %d\u005cn\u0022, __func__,\n+\t\t ah, (int)data_size, pt-\u003eah_pool_length);\n+\n+\treturn ah;\n+}\n+\n+int\n+_lws_destroy_ah(struct lws_context_per_thread *pt, struct allocated_headers *ah)\n+{\n+\tlws_start_foreach_llp(struct allocated_headers **, a, pt-\u003eah_list) {\n+\t\tif ((*a) \u003d\u003d ah) {\n+\t\t\t*a \u003d ah-\u003enext;\n+\t\t\tpt-\u003eah_pool_length--;\n+\t\t\tlwsl_info(\u0022%s: freed ah %p : pool length %d\u005cn\u0022,\n+\t\t\t\t __func__, ah, pt-\u003eah_pool_length);\n+\t\t\tif (ah-\u003edata)\n+\t\t\t\tlws_free(ah-\u003edata);\n+\t\t\tlws_free(ah);\n+\n+\t\t\treturn 0;\n+\t\t}\n+\t} lws_end_foreach_llp(a, next);\n+\n+\treturn 1;\n+}\n+\n+void\n+_lws_header_table_reset(struct allocated_headers *ah)\n+{\n+\t/* init the ah to reflect no headers or data have appeared yet */\n+\tmemset(ah-\u003efrag_index, 0, sizeof(ah-\u003efrag_index));\n+\tmemset(ah-\u003efrags, 0, sizeof(ah-\u003efrags));\n+\tah-\u003enfrag \u003d 0;\n+\tah-\u003epos \u003d 0;\n+\tah-\u003ehttp_response \u003d 0;\n+}\n+\n+// doesn't scrub the ah rxbuffer by default, parent must do if needed\n+\n+void\n+lws_header_table_reset(struct lws *wsi, int autoservice)\n+{\n+\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n+\tstruct lws_context_per_thread *pt;\n+\tstruct lws_pollfd *pfd;\n+\n+\t/* if we have the idea we're resetting 'our' ah, must be bound to one */\n+\tassert(ah);\n+\t/* ah also concurs with ownership */\n+\tassert(ah-\u003ewsi \u003d\u003d wsi);\n+\n+\t_lws_header_table_reset(ah);\n+\n+ wsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_NAME_PART;\n+ wsi-\u003eu.hdr.lextable_pos \u003d 0;\n+\n+\t/* since we will restart the ah, our new headers are not completed */\n+\twsi-\u003ehdr_parsing_completed \u003d 0;\n+\n+\t/* while we hold the ah, keep a timeout on the wsi */\n+\tlws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,\n+\t\t\twsi-\u003evhost-\u003etimeout_secs_ah_idle);\n+\n+\ttime(\u0026ah-\u003eassigned);\n+\n+\t/*\n+\t * if we inherited pending rx (from socket adoption deferred\n+\t * processing), apply and free it.\n+\t */\n+\tif (wsi-\u003eu.hdr.preamble_rx) {\n+\t\tmemcpy(ah-\u003erx, wsi-\u003eu.hdr.preamble_rx,\n+\t\t wsi-\u003eu.hdr.preamble_rx_len);\n+\t\tah-\u003erxlen \u003d wsi-\u003eu.hdr.preamble_rx_len;\n+\t\tlws_free_set_NULL(wsi-\u003eu.hdr.preamble_rx);\n+\n+\t\tif (autoservice) {\n+\t\t\tlwsl_debug(\u0022%s: service on readbuf ah\u005cn\u0022, __func__);\n+\n+\t\t\tpt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\t\t\t/*\n+\t\t\t * Unlike a normal connect, we have the headers already\n+\t\t\t * (or the first part of them anyway)\n+\t\t\t */\n+\t\t\tpfd \u003d \u0026pt-\u003efds[wsi-\u003eposition_in_fds_table];\n+\t\t\tpfd-\u003erevents |\u003d LWS_POLLIN;\n+\t\t\tlwsl_err(\u0022%s: calling service\u005cn\u0022, __func__);\n+\t\t\tlws_service_fd_tsi(wsi-\u003econtext, pfd, wsi-\u003etsi);\n+\t\t}\n+\t}\n+}\n+\n+static void\n+_lws_header_ensure_we_are_on_waiting_list(struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tstruct lws_pollargs pa;\n+\tstruct lws **pwsi \u003d \u0026pt-\u003eah_wait_list;\n+\n+\twhile (*pwsi) {\n+\t\tif (*pwsi \u003d\u003d wsi)\n+\t\t\treturn;\n+\t\tpwsi \u003d \u0026(*pwsi)-\u003eu.hdr.ah_wait_list;\n+\t}\n+\n+\tlwsl_info(\u0022%s: wsi: %p\u005cn\u0022, __func__, wsi);\n+\twsi-\u003eu.hdr.ah_wait_list \u003d pt-\u003eah_wait_list;\n+\tpt-\u003eah_wait_list \u003d wsi;\n+\tpt-\u003eah_wait_list_length++;\n+\n+\t/* we cannot accept input then */\n+\n+\t_lws_change_pollfd(wsi, LWS_POLLIN, 0, \u0026pa);\n+}\n+\n+static int\n+__lws_remove_from_ah_waiting_list(struct lws *wsi)\n+{\n+ struct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tstruct lws **pwsi \u003d\u0026pt-\u003eah_wait_list;\n+\n+\twhile (*pwsi) {\n+\t\tif (*pwsi \u003d\u003d wsi) {\n+\t\t\tlwsl_info(\u0022%s: wsi %p\u005cn\u0022, __func__, wsi);\n+\t\t\t/* point prev guy to our next */\n+\t\t\t*pwsi \u003d wsi-\u003eu.hdr.ah_wait_list;\n+\t\t\t/* we shouldn't point anywhere now */\n+\t\t\twsi-\u003eu.hdr.ah_wait_list \u003d NULL;\n+\t\t\tpt-\u003eah_wait_list_length--;\n+\n+\t\t\treturn 1;\n+\t\t}\n+\t\tpwsi \u003d \u0026(*pwsi)-\u003eu.hdr.ah_wait_list;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int LWS_WARN_UNUSED_RESULT\n+lws_header_table_attach(struct lws *wsi, int autoservice)\n+{\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tstruct lws_pollargs pa;\n+\tint n;\n+\n+\tlwsl_info(\u0022%s: wsi %p: ah %p (tsi %d, count \u003d %d) in\u005cn\u0022, __func__,\n+\t\t (void *)wsi, (void *)wsi-\u003eu.hdr.ah, wsi-\u003etsi,\n+\t\t pt-\u003eah_count_in_use);\n+\n+\t/* if we are already bound to one, just clear it down */\n+\tif (wsi-\u003eu.hdr.ah) {\n+\t\tlwsl_info(\u0022%s: cleardown\u005cn\u0022, __func__);\n+\t\tgoto reset;\n+\t}\n+\n+\tlws_pt_lock(pt);\n+\n+\tn \u003d pt-\u003eah_count_in_use \u003d\u003d context-\u003emax_http_header_pool;\n+#if defined(LWS_WITH_PEER_LIMITS)\n+\tif (!n) {\n+\t\tn \u003d lws_peer_confirm_ah_attach_ok(context, wsi-\u003epeer);\n+\t\tif (n)\n+\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt,\n+\t\t\t\tLWSSTATS_C_PEER_LIMIT_AH_DENIED, 1);\n+\t}\n+#endif\n+\tif (n) {\n+\t\t/*\n+\t\t * Pool is either all busy, or we don't want to give this\n+\t\t * particular guy an ah right now...\n+\t\t *\n+\t\t * Make sure we are on the waiting list, and return that we\n+\t\t * weren't able to provide the ah\n+\t\t */\n+\t\t_lws_header_ensure_we_are_on_waiting_list(wsi);\n+\n+\t\tgoto bail;\n+\t}\n+\n+\t__lws_remove_from_ah_waiting_list(wsi);\n+\n+\twsi-\u003eu.hdr.ah \u003d _lws_create_ah(pt, context-\u003emax_http_header_data);\n+\tif (!wsi-\u003eu.hdr.ah) { /* we could not create an ah */\n+\t\t_lws_header_ensure_we_are_on_waiting_list(wsi);\n+\n+\t\tgoto bail;\n+\t}\n+\n+\twsi-\u003eu.hdr.ah-\u003ein_use \u003d 1;\n+\twsi-\u003eu.hdr.ah-\u003ewsi \u003d wsi; /* mark our owner */\n+\tpt-\u003eah_count_in_use++;\n+\n+#if defined(LWS_WITH_PEER_LIMITS)\n+\tif (wsi-\u003epeer)\n+\t\twsi-\u003epeer-\u003ecount_ah++;\n+#endif\n+\n+\t_lws_change_pollfd(wsi, 0, LWS_POLLIN, \u0026pa);\n+\n+\tlwsl_info(\u0022%s: did attach wsi %p: ah %p: count %d (on exit)\u005cn\u0022, __func__,\n+\t\t (void *)wsi, (void *)wsi-\u003eu.hdr.ah, pt-\u003eah_count_in_use);\n+\n+\tlws_pt_unlock(pt);\n+\n+reset:\n+\n+\t/* and reset the rx state */\n+\twsi-\u003eu.hdr.ah-\u003erxpos \u003d 0;\n+\twsi-\u003eu.hdr.ah-\u003erxlen \u003d 0;\n+\n+\tlws_header_table_reset(wsi, autoservice);\n+\n+#ifndef LWS_NO_CLIENT\n+\tif (wsi-\u003estate \u003d\u003d LWSS_CLIENT_UNCONNECTED)\n+\t\tif (!lws_client_connect_via_info2(wsi))\n+\t\t\t/* our client connect has failed, the wsi\n+\t\t\t * has been closed\n+\t\t\t */\n+\t\t\treturn -1;\n+#endif\n+\n+\treturn 0;\n+\n+bail:\n+\tlws_pt_unlock(pt);\n+\n+\treturn 1;\n+}\n+\n+void\n+lws_header_table_force_to_detachable_state(struct lws *wsi)\n+{\n+\tif (wsi-\u003eu.hdr.ah) {\n+\t\twsi-\u003eu.hdr.ah-\u003erxpos \u003d -1;\n+\t\twsi-\u003eu.hdr.ah-\u003erxlen \u003d -1;\n+\t\twsi-\u003ehdr_parsing_completed \u003d 1;\n+\t}\n+}\n+\n+int\n+lws_header_table_is_in_detachable_state(struct lws *wsi)\n+{\n+\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n+\n+\treturn ah \u0026\u0026 ah-\u003erxpos \u003d\u003d ah-\u003erxlen \u0026\u0026 wsi-\u003ehdr_parsing_completed;\n+}\n+\n+int lws_header_table_detach(struct lws *wsi, int autoservice)\n+{\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tstruct lws_pollargs pa;\n+\tstruct lws **pwsi, **pwsi_eligible;\n+\ttime_t now;\n+\n+\tlws_pt_lock(pt);\n+\t__lws_remove_from_ah_waiting_list(wsi);\n+\tlws_pt_unlock(pt);\n+\n+\tif (!ah)\n+\t\treturn 0;\n+\n+\tlwsl_info(\u0022%s: wsi %p: ah %p (tsi\u003d%d, count \u003d %d)\u005cn\u0022, __func__,\n+\t\t (void *)wsi, (void *)ah, wsi-\u003etsi,\n+\t\t pt-\u003eah_count_in_use);\n+\n+\tif (wsi-\u003eu.hdr.preamble_rx)\n+\t\tlws_free_set_NULL(wsi-\u003eu.hdr.preamble_rx);\n+\n+\t/* may not be detached while he still has unprocessed rx */\n+\tif (!lws_header_table_is_in_detachable_state(wsi)) {\n+\t\tlwsl_err(\u0022%s: %p: CANNOT DETACH rxpos:%d, rxlen:%d, \u0022\n+\t\t\t \u0022wsi-\u003ehdr_parsing_completed \u003d %d\u005cn\u0022, __func__, wsi,\n+\t\t\t ah-\u003erxpos, ah-\u003erxlen, wsi-\u003ehdr_parsing_completed);\n+\t\treturn 0;\n+\t}\n+\n+\tlws_pt_lock(pt);\n+\n+\t/* we did have an ah attached */\n+\ttime(\u0026now);\n+\tif (ah-\u003eassigned \u0026\u0026 now - ah-\u003eassigned \u003e 3) {\n+\t\t/*\n+\t\t * we're detaching the ah, but it was held an\n+\t\t * unreasonably long time\n+\t\t */\n+\t\tlwsl_debug(\u0022%s: wsi %p: ah held %ds, \u0022\n+\t\t\t \u0022ah.rxpos %d, ah.rxlen %d, mode/state %d %d,\u0022\n+\t\t\t \u0022wsi-\u003emore_rx_waiting %d\u005cn\u0022, __func__, wsi,\n+\t\t\t (int)(now - ah-\u003eassigned),\n+\t\t\t ah-\u003erxpos, ah-\u003erxlen, wsi-\u003emode, wsi-\u003estate,\n+\t\t\t wsi-\u003emore_rx_waiting);\n+\t}\n+\n+\tah-\u003eassigned \u003d 0;\n+\n+\t/* if we think we're detaching one, there should be one in use */\n+\tassert(pt-\u003eah_count_in_use \u003e 0);\n+\t/* and this specific one should have been in use */\n+\tassert(ah-\u003ein_use);\n+\twsi-\u003eu.hdr.ah \u003d NULL;\n+\tah-\u003ewsi \u003d NULL; /* no owner */\n+#if defined(LWS_WITH_PEER_LIMITS)\n+\tlws_peer_track_ah_detach(context, wsi-\u003epeer);\n+#endif\n+\n+\tpwsi \u003d \u0026pt-\u003eah_wait_list;\n+\n+\t/* oh there is nobody on the waiting list... leave the ah unattached */\n+\tif (!*pwsi)\n+\t\tgoto nobody_usable_waiting;\n+\n+\t/*\n+\t * at least one wsi on the same tsi is waiting, give it to oldest guy\n+\t * who is allowed to take it (if any)\n+\t */\n+\tlwsl_info(\u0022pt wait list %p\u005cn\u0022, *pwsi);\n+\twsi \u003d NULL;\n+\tpwsi_eligible \u003d NULL;\n+\n+\twhile (*pwsi) {\n+#if defined(LWS_WITH_PEER_LIMITS)\n+\t\t/* are we willing to give this guy an ah? */\n+\t\tif (!lws_peer_confirm_ah_attach_ok(context, (*pwsi)-\u003epeer))\n+#endif\n+\t\t{\n+\t\t\twsi \u003d *pwsi;\n+\t\t\tpwsi_eligible \u003d pwsi;\n+\t\t}\n+#if defined(LWS_WITH_PEER_LIMITS)\n+\t\telse\n+\t\t\tif (!(*pwsi)-\u003eu.hdr.ah_wait_list)\n+\t\t\t\tlws_stats_atomic_bump(context, pt,\n+\t\t\t\t\tLWSSTATS_C_PEER_LIMIT_AH_DENIED, 1);\n+#endif\n+\t\tpwsi \u003d \u0026(*pwsi)-\u003eu.hdr.ah_wait_list;\n+\t}\n+\n+\tif (!wsi) /* everybody waiting already has too many ah... */\n+\t\tgoto nobody_usable_waiting;\n+\n+\tlwsl_info(\u0022%s: last eligible wsi in wait list %p\u005cn\u0022, __func__, wsi);\n+\n+\twsi-\u003eu.hdr.ah \u003d ah;\n+\tah-\u003ewsi \u003d wsi; /* new owner */\n+\n+\t/* and reset the rx state */\n+\tah-\u003erxpos \u003d 0;\n+\tah-\u003erxlen \u003d 0;\n+\tlws_header_table_reset(wsi, autoservice);\n+#if defined(LWS_WITH_PEER_LIMITS)\n+\tif (wsi-\u003epeer)\n+\t\twsi-\u003epeer-\u003ecount_ah++;\n+#endif\n+\n+\t/* clients acquire the ah and then insert themselves in fds table... */\n+\tif (wsi-\u003eposition_in_fds_table !\u003d -1) {\n+\t\tlwsl_info(\u0022%s: Enabling %p POLLIN\u005cn\u0022, __func__, wsi);\n+\n+\t\t/* he has been stuck waiting for an ah, but now his wait is\n+\t\t * over, let him progress */\n+\n+\t\t_lws_change_pollfd(wsi, 0, LWS_POLLIN, \u0026pa);\n+\t}\n+\n+\t/* point prev guy to next guy in list instead */\n+\t*pwsi_eligible \u003d wsi-\u003eu.hdr.ah_wait_list;\n+\t/* the guy who got one is out of the list */\n+\twsi-\u003eu.hdr.ah_wait_list \u003d NULL;\n+\tpt-\u003eah_wait_list_length--;\n+\n+#ifndef LWS_NO_CLIENT\n+\tif (wsi-\u003estate \u003d\u003d LWSS_CLIENT_UNCONNECTED) {\n+\t\tlws_pt_unlock(pt);\n+\n+\t\tif (!lws_client_connect_via_info2(wsi)) {\n+\t\t\t/* our client connect has failed, the wsi\n+\t\t\t * has been closed\n+\t\t\t */\n+\n+\t\t\treturn -1;\n+\t\t}\n+\t\treturn 0;\n+\t}\n+#endif\n+\n+\tassert(!!pt-\u003eah_wait_list_length \u003d\u003d !!(lws_intptr_t)pt-\u003eah_wait_list);\n+bail:\n+\tlwsl_info(\u0022%s: wsi %p: ah %p (tsi\u003d%d, count \u003d %d)\u005cn\u0022, __func__,\n+\t\t (void *)wsi, (void *)ah, pt-\u003etid, pt-\u003eah_count_in_use);\n+\n+\tlws_pt_unlock(pt);\n+\n+\treturn 0;\n+\n+nobody_usable_waiting:\n+\tlwsl_info(\u0022%s: nobody usable waiting\u005cn\u0022, __func__);\n+\t_lws_destroy_ah(pt, ah);\n+\tpt-\u003eah_count_in_use--;\n+\n+\tgoto bail;\n+}\n+\n+LWS_VISIBLE int\n+lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)\n+{\n+\tint n;\n+\n+\tif (!wsi-\u003eu.hdr.ah)\n+\t\treturn 0;\n+\n+\tn \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n+\tif (!n)\n+\t\treturn 0;\n+\tdo {\n+\t\tif (!frag_idx)\n+\t\t\treturn wsi-\u003eu.hdr.ah-\u003efrags[n].len;\n+\t\tn \u003d wsi-\u003eu.hdr.ah-\u003efrags[n].nfrag;\n+\t} while (frag_idx-- \u0026\u0026 n);\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)\n+{\n+\tint n;\n+\tint len \u003d 0;\n+\n+\tif (!wsi-\u003eu.hdr.ah)\n+\t\treturn 0;\n+\n+\tn \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n+\tif (!n)\n+\t\treturn 0;\n+\tdo {\n+\t\tlen +\u003d wsi-\u003eu.hdr.ah-\u003efrags[n].len;\n+\t\tn \u003d wsi-\u003eu.hdr.ah-\u003efrags[n].nfrag;\n+\t} while (n);\n+\n+\treturn len;\n+}\n+\n+LWS_VISIBLE int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,\n+\t\t\t\t enum lws_token_indexes h, int frag_idx)\n+{\n+\tint n \u003d 0;\n+\tint f;\n+\n+\tif (!wsi-\u003eu.hdr.ah)\n+\t\treturn -1;\n+\n+\tf \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n+\n+\tif (!f)\n+\t\treturn -1;\n+\n+\twhile (n \u003c frag_idx) {\n+\t\tf \u003d wsi-\u003eu.hdr.ah-\u003efrags[f].nfrag;\n+\t\tif (!f)\n+\t\t\treturn -1;\n+\t\tn++;\n+\t}\n+\n+\tif (wsi-\u003eu.hdr.ah-\u003efrags[f].len \u003e\u003d len)\n+\t\treturn -1;\n+\n+\tmemcpy(dst, wsi-\u003eu.hdr.ah-\u003edata + wsi-\u003eu.hdr.ah-\u003efrags[f].offset,\n+\t wsi-\u003eu.hdr.ah-\u003efrags[f].len);\n+\tdst[wsi-\u003eu.hdr.ah-\u003efrags[f].len] \u003d '\u005c0';\n+\n+\treturn wsi-\u003eu.hdr.ah-\u003efrags[f].len;\n+}\n+\n+LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len,\n+\t\t\t enum lws_token_indexes h)\n+{\n+\tint toklen \u003d lws_hdr_total_length(wsi, h);\n+\tint n;\n+\n+\tif (toklen \u003e\u003d len)\n+\t\treturn -1;\n+\n+\tif (!wsi-\u003eu.hdr.ah)\n+\t\treturn -1;\n+\n+\tn \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n+\tif (!n)\n+\t\treturn 0;\n+\n+\tdo {\n+\t\tstrcpy(dst,\n+\t\t \u0026wsi-\u003eu.hdr.ah-\u003edata[wsi-\u003eu.hdr.ah-\u003efrags[n].offset]);\n+\t\tdst +\u003d wsi-\u003eu.hdr.ah-\u003efrags[n].len;\n+\t\tn \u003d wsi-\u003eu.hdr.ah-\u003efrags[n].nfrag;\n+\t} while (n);\n+\n+\treturn toklen;\n+}\n+\n+char *lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h)\n+{\n+\tint n;\n+\n+\tn \u003d wsi-\u003eu.hdr.ah-\u003efrag_index[h];\n+\tif (!n)\n+\t\treturn NULL;\n+\n+\treturn wsi-\u003eu.hdr.ah-\u003edata + wsi-\u003eu.hdr.ah-\u003efrags[n].offset;\n+}\n+\n+int LWS_WARN_UNUSED_RESULT\n+lws_pos_in_bounds(struct lws *wsi)\n+{\n+\tif (wsi-\u003eu.hdr.ah-\u003epos \u003c\n+\t (unsigned int)wsi-\u003econtext-\u003emax_http_header_data)\n+\t\treturn 0;\n+\n+\tif (wsi-\u003eu.hdr.ah-\u003epos \u003d\u003d wsi-\u003econtext-\u003emax_http_header_data) {\n+\t\tlwsl_err(\u0022Ran out of header data space\u005cn\u0022);\n+\t\treturn 1;\n+\t}\n+\n+\t/*\n+\t * with these tests everywhere, it should never be able to exceed\n+\t * the limit, only meet it\n+\t */\n+\tlwsl_err(\u0022%s: pos %d, limit %d\u005cn\u0022, __func__, wsi-\u003eu.hdr.ah-\u003epos,\n+\t\t wsi-\u003econtext-\u003emax_http_header_data);\n+\tassert(0);\n+\n+\treturn 1;\n+}\n+\n+int LWS_WARN_UNUSED_RESULT\n+lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s)\n+{\n+\twsi-\u003eu.hdr.ah-\u003enfrag++;\n+\tif (wsi-\u003eu.hdr.ah-\u003enfrag \u003d\u003d ARRAY_SIZE(wsi-\u003eu.hdr.ah-\u003efrags)) {\n+\t\tlwsl_warn(\u0022More hdr frags than we can deal with, dropping\u005cn\u0022);\n+\t\treturn -1;\n+\t}\n+\n+\twsi-\u003eu.hdr.ah-\u003efrag_index[h] \u003d wsi-\u003eu.hdr.ah-\u003enfrag;\n+\n+\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].offset \u003d wsi-\u003eu.hdr.ah-\u003epos;\n+\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].len \u003d 0;\n+\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].nfrag \u003d 0;\n+\n+\tdo {\n+\t\tif (lws_pos_in_bounds(wsi))\n+\t\t\treturn -1;\n+\n+\t\twsi-\u003eu.hdr.ah-\u003edata[wsi-\u003eu.hdr.ah-\u003epos++] \u003d *s;\n+\t\tif (*s)\n+\t\t\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].len++;\n+\t} while (*s++);\n+\n+\treturn 0;\n+}\n+\n+signed char char_to_hex(const char c)\n+{\n+\tif (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')\n+\t\treturn c - '0';\n+\n+\tif (c \u003e\u003d 'a' \u0026\u0026 c \u003c\u003d 'f')\n+\t\treturn c - 'a' + 10;\n+\n+\tif (c \u003e\u003d 'A' \u0026\u0026 c \u003c\u003d 'F')\n+\t\treturn c - 'A' + 10;\n+\n+\treturn -1;\n+}\n+\n+static int LWS_WARN_UNUSED_RESULT\n+issue_char(struct lws *wsi, unsigned char c)\n+{\n+\tunsigned short frag_len;\n+\n+\tif (lws_pos_in_bounds(wsi))\n+\t\treturn -1;\n+\n+\tfrag_len \u003d wsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].len;\n+\t/*\n+\t * If we haven't hit the token limit, just copy the character into\n+\t * the header\n+\t */\n+\tif (frag_len \u003c wsi-\u003eu.hdr.current_token_limit) {\n+\t\twsi-\u003eu.hdr.ah-\u003edata[wsi-\u003eu.hdr.ah-\u003epos++] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.hdr.ah-\u003efrags[wsi-\u003eu.hdr.ah-\u003enfrag].len++;\n+\t\treturn 0;\n+\t}\n+\n+\t/* Insert a null character when we *hit* the limit: */\n+\tif (frag_len \u003d\u003d wsi-\u003eu.hdr.current_token_limit) {\n+\t\tif (lws_pos_in_bounds(wsi))\n+\t\t\treturn -1;\n+\n+\t\twsi-\u003eu.hdr.ah-\u003edata[wsi-\u003eu.hdr.ah-\u003epos++] \u003d '\u005c0';\n+\t\tlwsl_warn(\u0022header %i exceeds limit %d\u005cn\u0022,\n+\t\t\t wsi-\u003eu.hdr.parser_state,\n+\t\t\t wsi-\u003eu.hdr.current_token_limit);\n+\t}\n+\n+\treturn 1;\n+}\n+\n+int\n+lws_parse_urldecode(struct lws *wsi, uint8_t *_c)\n+{\n+\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n+\tunsigned int enc \u003d 0;\n+\tuint8_t c \u003d *_c;\n+\n+\t/*\n+\t * PRIORITY 1\n+\t * special URI processing... convert %xx\n+\t */\n+\tswitch (wsi-\u003eu.hdr.ues) {\n+\tcase URIES_IDLE:\n+\t\tif (c \u003d\u003d '%') {\n+\t\t\twsi-\u003eu.hdr.ues \u003d URIES_SEEN_PERCENT;\n+\t\t\tgoto swallow;\n+\t\t}\n+\t\tbreak;\n+\tcase URIES_SEEN_PERCENT:\n+\t\tif (char_to_hex(c) \u003c 0)\n+\t\t\t/* illegal post-% char */\n+\t\t\tgoto forbid;\n+\n+\t\twsi-\u003eu.hdr.esc_stash \u003d c;\n+\t\twsi-\u003eu.hdr.ues \u003d URIES_SEEN_PERCENT_H1;\n+\t\tgoto swallow;\n+\n+\tcase URIES_SEEN_PERCENT_H1:\n+\t\tif (char_to_hex(c) \u003c 0)\n+\t\t\t/* illegal post-% char */\n+\t\t\tgoto forbid;\n+\n+\t\t*_c \u003d (char_to_hex(wsi-\u003eu.hdr.esc_stash) \u003c\u003c 4) |\n+\t\t\t\tchar_to_hex(c);\n+\t\tc \u003d *_c;\n+\t\tenc \u003d 1;\n+\t\twsi-\u003eu.hdr.ues \u003d URIES_IDLE;\n+\t\tbreak;\n+\t}\n+\n+\t/*\n+\t * PRIORITY 2\n+\t * special URI processing...\n+\t * convert /.. or /... or /../ etc to /\n+\t * convert /./ to /\n+\t * convert // or /// etc to /\n+\t * leave /.dir or whatever alone\n+\t */\n+\n+\tswitch (wsi-\u003eu.hdr.ups) {\n+\tcase URIPS_IDLE:\n+\t\tif (!c)\n+\t\t\treturn -1;\n+\t\t/* genuine delimiter */\n+\t\tif ((c \u003d\u003d '\u0026' || c \u003d\u003d ';') \u0026\u0026 !enc) {\n+\t\t\tif (issue_char(wsi, c) \u003c 0)\n+\t\t\t\treturn -1;\n+\t\t\t/* swallow the terminator */\n+\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n+\t\t\t/* link to next fragment */\n+\t\t\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d ah-\u003enfrag + 1;\n+\t\t\tah-\u003enfrag++;\n+\t\t\tif (ah-\u003enfrag \u003e\u003d ARRAY_SIZE(ah-\u003efrags))\n+\t\t\t\tgoto excessive;\n+\t\t\t/* start next fragment after the \u0026 */\n+\t\t\twsi-\u003eu.hdr.post_literal_equal \u003d 0;\n+\t\t\tah-\u003efrags[ah-\u003enfrag].offset \u003d ah-\u003epos;\n+\t\t\tah-\u003efrags[ah-\u003enfrag].len \u003d 0;\n+\t\t\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d 0;\n+\t\t\tgoto swallow;\n+\t\t}\n+\t\t/* uriencoded \u003d in the name part, disallow */\n+\t\tif (c \u003d\u003d '\u003d' \u0026\u0026 enc \u0026\u0026\n+\t\t ah-\u003efrag_index[WSI_TOKEN_HTTP_URI_ARGS] \u0026\u0026\n+\t\t !wsi-\u003eu.hdr.post_literal_equal) {\n+\t\t\tc \u003d '_';\n+\t\t\t*_c \u003dc;\n+\t\t}\n+\n+\t\t/* after the real \u003d, we don't care how many \u003d */\n+\t\tif (c \u003d\u003d '\u003d' \u0026\u0026 !enc)\n+\t\t\twsi-\u003eu.hdr.post_literal_equal \u003d 1;\n+\n+\t\t/* + to space */\n+\t\tif (c \u003d\u003d '+' \u0026\u0026 !enc) {\n+\t\t\tc \u003d ' ';\n+\t\t\t*_c \u003d c;\n+\t\t}\n+\t\t/* issue the first / always */\n+\t\tif (c \u003d\u003d '/' \u0026\u0026 !ah-\u003efrag_index[WSI_TOKEN_HTTP_URI_ARGS])\n+\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH;\n+\t\tbreak;\n+\tcase URIPS_SEEN_SLASH:\n+\t\t/* swallow subsequent slashes */\n+\t\tif (c \u003d\u003d '/')\n+\t\t\tgoto swallow;\n+\t\t/* track and swallow the first . after / */\n+\t\tif (c \u003d\u003d '.') {\n+\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH_DOT;\n+\t\t\tgoto swallow;\n+\t\t}\n+\t\twsi-\u003eu.hdr.ups \u003d URIPS_IDLE;\n+\t\tbreak;\n+\tcase URIPS_SEEN_SLASH_DOT:\n+\t\t/* swallow second . */\n+\t\tif (c \u003d\u003d '.') {\n+\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH_DOT_DOT;\n+\t\t\tgoto swallow;\n+\t\t}\n+\t\t/* change /./ to / */\n+\t\tif (c \u003d\u003d '/') {\n+\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH;\n+\t\t\tgoto swallow;\n+\t\t}\n+\t\t/* it was like /.dir ... regurgitate the . */\n+\t\twsi-\u003eu.hdr.ups \u003d URIPS_IDLE;\n+\t\tif (issue_char(wsi, '.') \u003c 0)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase URIPS_SEEN_SLASH_DOT_DOT:\n+\n+\t\t/* /../ or /..[End of URI] --\u003e backup to last / */\n+\t\tif (c \u003d\u003d '/' || c \u003d\u003d '?') {\n+\t\t\t/*\n+\t\t\t * back up one dir level if possible\n+\t\t\t * safe against header fragmentation because\n+\t\t\t * the method URI can only be in 1 fragment\n+\t\t\t */\n+\t\t\tif (ah-\u003efrags[ah-\u003enfrag].len \u003e 2) {\n+\t\t\t\tah-\u003epos--;\n+\t\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n+\t\t\t\tdo {\n+\t\t\t\t\tah-\u003epos--;\n+\t\t\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n+\t\t\t\t} while (ah-\u003efrags[ah-\u003enfrag].len \u003e 1 \u0026\u0026\n+\t\t\t\t\t ah-\u003edata[ah-\u003epos] !\u003d '/');\n+\t\t\t}\n+\t\t\twsi-\u003eu.hdr.ups \u003d URIPS_SEEN_SLASH;\n+\t\t\tif (ah-\u003efrags[ah-\u003enfrag].len \u003e 1)\n+\t\t\t\tbreak;\n+\t\t\tgoto swallow;\n+\t\t}\n+\n+\t\t/* /..[^/] ... regurgitate and allow */\n+\n+\t\tif (issue_char(wsi, '.') \u003c 0)\n+\t\t\treturn -1;\n+\t\tif (issue_char(wsi, '.') \u003c 0)\n+\t\t\treturn -1;\n+\t\twsi-\u003eu.hdr.ups \u003d URIPS_IDLE;\n+\t\tbreak;\n+\t}\n+\n+\tif (c \u003d\u003d '?' \u0026\u0026 !enc \u0026\u0026\n+\t !ah-\u003efrag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI arguments */\n+\t\tif (wsi-\u003eu.hdr.ues !\u003d URIES_IDLE)\n+\t\t\tgoto forbid;\n+\n+\t\t/* seal off uri header */\n+\t\tif (issue_char(wsi, '\u005c0') \u003c 0)\n+\t\t\treturn -1;\n+\n+\t\t/* move to using WSI_TOKEN_HTTP_URI_ARGS */\n+\t\tah-\u003enfrag++;\n+\t\tif (ah-\u003enfrag \u003e\u003d ARRAY_SIZE(ah-\u003efrags))\n+\t\t\tgoto excessive;\n+\t\tah-\u003efrags[ah-\u003enfrag].offset \u003d ah-\u003epos;\n+\t\tah-\u003efrags[ah-\u003enfrag].len \u003d 0;\n+\t\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d 0;\n+\n+\t\twsi-\u003eu.hdr.post_literal_equal \u003d 0;\n+\t\tah-\u003efrag_index[WSI_TOKEN_HTTP_URI_ARGS] \u003d ah-\u003enfrag;\n+\t\twsi-\u003eu.hdr.ups \u003d URIPS_IDLE;\n+\t\tgoto swallow;\n+\t}\n+\n+\treturn LPUR_CONTINUE;\n+\n+swallow:\n+\treturn LPUR_SWALLOW;\n+\n+forbid:\n+\treturn LPUR_FORBID;\n+\n+excessive:\n+\treturn LPUR_EXCESSIVE;\n+}\n+\n+static const unsigned char methods[] \u003d {\n+\tWSI_TOKEN_GET_URI,\n+\tWSI_TOKEN_POST_URI,\n+\tWSI_TOKEN_OPTIONS_URI,\n+\tWSI_TOKEN_PUT_URI,\n+\tWSI_TOKEN_PATCH_URI,\n+\tWSI_TOKEN_DELETE_URI,\n+\tWSI_TOKEN_CONNECT,\n+\tWSI_TOKEN_HEAD_URI,\n+};\n+\n+int LWS_WARN_UNUSED_RESULT\n+lws_parse(struct lws *wsi, unsigned char c)\n+{\n+\tstruct allocated_headers *ah \u003d wsi-\u003eu.hdr.ah;\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\n+\tunsigned int n, m;\n+\tint r;\n+\n+\tassert(wsi-\u003eu.hdr.ah);\n+\n+\tswitch (wsi-\u003eu.hdr.parser_state) {\n+\tdefault:\n+\n+\t\tlwsl_parser(\u0022WSI_TOK_(%d) '%c'\u005cn\u0022, wsi-\u003eu.hdr.parser_state, c);\n+\n+\t\t/* collect into malloc'd buffers */\n+\t\t/* optional initial space swallow */\n+\t\tif (!ah-\u003efrags[ah-\u003efrag_index[wsi-\u003eu.hdr.parser_state]].len \u0026\u0026\n+\t\t c \u003d\u003d ' ')\n+\t\t\tbreak;\n+\n+\t\tfor (m \u003d 0; m \u003c ARRAY_SIZE(methods); m++)\n+\t\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d methods[m])\n+\t\t\t\tbreak;\n+\t\tif (m \u003d\u003d ARRAY_SIZE(methods))\n+\t\t\t/* it was not any of the methods */\n+\t\t\tgoto check_eol;\n+\n+\t\t/* special URI processing... end at space */\n+\n+\t\tif (c \u003d\u003d ' ') {\n+\t\t\t/* enforce starting with / */\n+\t\t\tif (!ah-\u003efrags[ah-\u003enfrag].len)\n+\t\t\t\tif (issue_char(wsi, '/') \u003c 0)\n+\t\t\t\t\treturn -1;\n+\n+\t\t\tif (wsi-\u003eu.hdr.ups \u003d\u003d URIPS_SEEN_SLASH_DOT_DOT) {\n+\t\t\t\t/*\n+\t\t\t\t * back up one dir level if possible\n+\t\t\t\t * safe against header fragmentation because\n+\t\t\t\t * the method URI can only be in 1 fragment\n+\t\t\t\t */\n+\t\t\t\tif (ah-\u003efrags[ah-\u003enfrag].len \u003e 2) {\n+\t\t\t\t\tah-\u003epos--;\n+\t\t\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n+\t\t\t\t\tdo {\n+\t\t\t\t\t\tah-\u003epos--;\n+\t\t\t\t\t\tah-\u003efrags[ah-\u003enfrag].len--;\n+\t\t\t\t\t} while (ah-\u003efrags[ah-\u003enfrag].len \u003e 1 \u0026\u0026\n+\t\t\t\t\t\t ah-\u003edata[ah-\u003epos] !\u003d '/');\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\t/* begin parsing HTTP version: */\n+\t\t\tif (issue_char(wsi, '\u005c0') \u003c 0)\n+\t\t\t\treturn -1;\n+\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_HTTP;\n+\t\t\tgoto start_fragment;\n+\t\t}\n+\n+\t\tr \u003d lws_parse_urldecode(wsi, \u0026c);\n+\t\tswitch (r) {\n+\t\tcase LPUR_CONTINUE:\n+\t\t\tbreak;\n+\t\tcase LPUR_SWALLOW:\n+\t\t\tgoto swallow;\n+\t\tcase LPUR_FORBID:\n+\t\t\tgoto forbid;\n+\t\tcase LPUR_EXCESSIVE:\n+\t\t\tgoto excessive;\n+\t\tdefault:\n+\t\t\treturn -1;\n+\t\t}\n+check_eol:\n+\t\t/* bail at EOL */\n+\t\tif (wsi-\u003eu.hdr.parser_state !\u003d WSI_TOKEN_CHALLENGE \u0026\u0026\n+\t\t c \u003d\u003d '\u005cx0d') {\n+\t\t\tif (wsi-\u003eu.hdr.ues !\u003d URIES_IDLE)\n+\t\t\t\tgoto forbid;\n+\n+\t\t\tc \u003d '\u005c0';\n+\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING_SAW_CR;\n+\t\t\tlwsl_parser(\u0022*\u005cn\u0022);\n+\t\t}\n+\n+\t\tn \u003d issue_char(wsi, c);\n+\t\tif ((int)n \u003c 0)\n+\t\t\treturn -1;\n+\t\tif (n \u003e 0)\n+\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING;\n+\n+swallow:\n+\t\t/* per-protocol end of headers management */\n+\n+\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_CHALLENGE)\n+\t\t\tgoto set_parsing_complete;\n+\t\tbreak;\n+\n+\t\t/* collecting and checking a name part */\n+\tcase WSI_TOKEN_NAME_PART:\n+\t\tlwsl_parser(\u0022WSI_TOKEN_NAME_PART '%c' 0x%02X (mode\u003d%d) wsi-\u003eu.hdr.lextable_pos\u003d%d\u005cn\u0022, c, c, wsi-\u003emode, wsi-\u003eu.hdr.lextable_pos);\n+\n+\t\twsi-\u003eu.hdr.lextable_pos \u003d\n+\t\t\t\tlextable_decode(wsi-\u003eu.hdr.lextable_pos, c);\n+\t\t/*\n+\t\t * Server needs to look out for unknown methods...\n+\t\t */\n+\t\tif (wsi-\u003eu.hdr.lextable_pos \u003c 0 \u0026\u0026\n+\t\t (wsi-\u003emode \u003d\u003d LWSCM_HTTP_SERVING)) {\n+\t\t\t/* this is not a header we know about */\n+\t\t\tfor (m \u003d 0; m \u003c ARRAY_SIZE(methods); m++)\n+\t\t\t\tif (ah-\u003efrag_index[methods[m]]) {\n+\t\t\t\t\t/*\n+\t\t\t\t\t * already had the method, no idea what\n+\t\t\t\t\t * this crap from the client is, ignore\n+\t\t\t\t\t */\n+\t\t\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t/*\n+\t\t\t * hm it's an unknown http method from a client in fact,\n+\t\t\t * it cannot be valid http\n+\t\t\t */\n+\t\t\tif (m \u003d\u003d ARRAY_SIZE(methods)) {\n+\t\t\t\t/*\n+\t\t\t\t * are we set up to accept raw in these cases?\n+\t\t\t\t */\n+\t\t\t\tif (lws_check_opt(wsi-\u003evhost-\u003eoptions,\n+\t\t\t\t\t LWS_SERVER_OPTION_FALLBACK_TO_RAW))\n+\t\t\t\t\treturn 2; /* transition to raw */\n+\n+\t\t\t\tlwsl_info(\u0022Unknown method - dropping\u005cn\u0022);\n+\t\t\t\tgoto forbid;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\t/*\n+\t\t * ...otherwise for a client, let him ignore unknown headers\n+\t\t * coming from the server\n+\t\t */\n+\t\tif (wsi-\u003eu.hdr.lextable_pos \u003c 0) {\n+\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (lextable[wsi-\u003eu.hdr.lextable_pos] \u003c FAIL_CHAR) {\n+\t\t\t/* terminal state */\n+\n+\t\t\tn \u003d ((unsigned int)lextable[wsi-\u003eu.hdr.lextable_pos] \u003c\u003c 8) |\n+\t\t\t\t\tlextable[wsi-\u003eu.hdr.lextable_pos + 1];\n+\n+\t\t\tlwsl_parser(\u0022known hdr %d\u005cn\u0022, n);\n+\t\t\tfor (m \u003d 0; m \u003c ARRAY_SIZE(methods); m++)\n+\t\t\t\tif (n \u003d\u003d methods[m] \u0026\u0026\n+\t\t\t\t ah-\u003efrag_index[methods[m]]) {\n+\t\t\t\t\tlwsl_warn(\u0022Duplicated method\u005cn\u0022);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\n+\t\t\t/*\n+\t\t\t * WSORIGIN is protocol equiv to ORIGIN,\n+\t\t\t * JWebSocket likes to send it, map to ORIGIN\n+\t\t\t */\n+\t\t\tif (n \u003d\u003d WSI_TOKEN_SWORIGIN)\n+\t\t\t\tn \u003d WSI_TOKEN_ORIGIN;\n+\n+\t\t\twsi-\u003eu.hdr.parser_state \u003d (enum lws_token_indexes)\n+\t\t\t\t\t\t\t(WSI_TOKEN_GET_URI + n);\n+\n+\t\t\tif (context-\u003etoken_limits)\n+\t\t\t\twsi-\u003eu.hdr.current_token_limit \u003d\n+\t\t\t\t\tcontext-\u003etoken_limits-\u003etoken_limit[\n+\t\t\t\t\t\t wsi-\u003eu.hdr.parser_state];\n+\t\t\telse\n+\t\t\t\twsi-\u003eu.hdr.current_token_limit \u003d\n+\t\t\t\t\twsi-\u003econtext-\u003emax_http_header_data;\n+\n+\t\t\tif (wsi-\u003eu.hdr.parser_state \u003d\u003d WSI_TOKEN_CHALLENGE)\n+\t\t\t\tgoto set_parsing_complete;\n+\n+\t\t\tgoto start_fragment;\n+\t\t}\n+\t\tbreak;\n+\n+start_fragment:\n+\t\tah-\u003enfrag++;\n+excessive:\n+\t\tif (ah-\u003enfrag \u003d\u003d ARRAY_SIZE(ah-\u003efrags)) {\n+\t\t\tlwsl_warn(\u0022More hdr frags than we can deal with\u005cn\u0022);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tah-\u003efrags[ah-\u003enfrag].offset \u003d ah-\u003epos;\n+\t\tah-\u003efrags[ah-\u003enfrag].len \u003d 0;\n+\t\tah-\u003efrags[ah-\u003enfrag].nfrag \u003d 0;\n+\t\tah-\u003efrags[ah-\u003enfrag].flags \u003d 2;\n+\n+\t\tn \u003d ah-\u003efrag_index[wsi-\u003eu.hdr.parser_state];\n+\t\tif (!n) { /* first fragment */\n+\t\t\tah-\u003efrag_index[wsi-\u003eu.hdr.parser_state] \u003d ah-\u003enfrag;\n+\t\t\tah-\u003ehdr_token_idx \u003d wsi-\u003eu.hdr.parser_state;\n+\t\t\tbreak;\n+\t\t}\n+\t\t/* continuation */\n+\t\twhile (ah-\u003efrags[n].nfrag)\n+\t\t\tn \u003d ah-\u003efrags[n].nfrag;\n+\t\tah-\u003efrags[n].nfrag \u003d ah-\u003enfrag;\n+\n+\t\tif (issue_char(wsi, ' ') \u003c 0)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\t\t/* skipping arg part of a name we didn't recognize */\n+\tcase WSI_TOKEN_SKIPPING:\n+\t\tlwsl_parser(\u0022WSI_TOKEN_SKIPPING '%c'\u005cn\u0022, c);\n+\n+\t\tif (c \u003d\u003d '\u005cx0d')\n+\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING_SAW_CR;\n+\t\tbreak;\n+\n+\tcase WSI_TOKEN_SKIPPING_SAW_CR:\n+\t\tlwsl_parser(\u0022WSI_TOKEN_SKIPPING_SAW_CR '%c'\u005cn\u0022, c);\n+\t\tif (wsi-\u003eu.hdr.ues !\u003d URIES_IDLE)\n+\t\t\tgoto forbid;\n+\t\tif (c \u003d\u003d '\u005cx0a') {\n+\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_NAME_PART;\n+\t\t\twsi-\u003eu.hdr.lextable_pos \u003d 0;\n+\t\t} else\n+\t\t\twsi-\u003eu.hdr.parser_state \u003d WSI_TOKEN_SKIPPING;\n+\t\tbreak;\n+\t\t/* we're done, ignore anything else */\n+\n+\tcase WSI_PARSING_COMPLETE:\n+\t\tlwsl_parser(\u0022WSI_PARSING_COMPLETE '%c'\u005cn\u0022, c);\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+\n+set_parsing_complete:\n+\tif (wsi-\u003eu.hdr.ues !\u003d URIES_IDLE)\n+\t\tgoto forbid;\n+\tif (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))\n+\t\t\twsi-\u003eietf_spec_revision \u003d\n+\t\t\t atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));\n+\n+\t\tlwsl_parser(\u0022v%02d hdrs completed\u005cn\u0022, wsi-\u003eietf_spec_revision);\n+\t}\n+\twsi-\u003eu.hdr.parser_state \u003d WSI_PARSING_COMPLETE;\n+\twsi-\u003ehdr_parsing_completed \u003d 1;\n+\n+\treturn 0;\n+\n+forbid:\n+\tlwsl_notice(\u0022 forbidding on uri sanitation\u005cn\u0022);\n+\tlws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);\n+\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE int lws_frame_is_binary(struct lws *wsi)\n+{\n+\treturn wsi-\u003eu.ws.frame_is_binary;\n+}\n+\n+void\n+lws_add_wsi_to_draining_ext_list(struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\n+\tif (wsi-\u003eu.ws.rx_draining_ext)\n+\t\treturn;\n+\n+\tlwsl_ext(\u0022%s: RX EXT DRAINING: Adding to list\u005cn\u0022, __func__);\n+\n+\twsi-\u003eu.ws.rx_draining_ext \u003d 1;\n+\twsi-\u003eu.ws.rx_draining_ext_list \u003d pt-\u003erx_draining_ext_list;\n+\tpt-\u003erx_draining_ext_list \u003d wsi;\n+}\n+\n+void\n+lws_remove_wsi_from_draining_ext_list(struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tstruct lws **w \u003d \u0026pt-\u003erx_draining_ext_list;\n+\n+\tif (!wsi-\u003eu.ws.rx_draining_ext)\n+\t\treturn;\n+\n+\tlwsl_ext(\u0022%s: RX EXT DRAINING: Removing from list\u005cn\u0022, __func__);\n+\n+\twsi-\u003eu.ws.rx_draining_ext \u003d 0;\n+\n+\t/* remove us from context draining ext list */\n+\twhile (*w) {\n+\t\tif (*w \u003d\u003d wsi) {\n+\t\t\t/* if us, point it instead to who we were pointing to */\n+\t\t\t*w \u003d wsi-\u003eu.ws.rx_draining_ext_list;\n+\t\t\tbreak;\n+\t\t}\n+\t\tw \u003d \u0026((*w)-\u003eu.ws.rx_draining_ext_list);\n+\t}\n+\twsi-\u003eu.ws.rx_draining_ext_list \u003d NULL;\n+}\n+\n+/*\n+ * client-parser.c: lws_client_rx_sm() needs to be roughly kept in\n+ * sync with changes here, esp related to ext draining\n+ */\n+\n+int\n+lws_rx_sm(struct lws *wsi, unsigned char c)\n+{\n+\tint callback_action \u003d LWS_CALLBACK_RECEIVE;\n+\tint ret \u003d 0, n, rx_draining_ext \u003d 0;\n+\tstruct lws_tokens eff_buf;\n+\n+\teff_buf.token \u003d NULL;\n+\teff_buf.token_len \u003d 0;\n+\tif (wsi-\u003esocket_is_permanently_unusable)\n+\t\treturn -1;\n+\n+\tswitch (wsi-\u003elws_rx_parse_state) {\n+\tcase LWS_RXPS_NEW:\n+\t\tif (wsi-\u003eu.ws.rx_draining_ext) {\n+\t\t\teff_buf.token \u003d NULL;\n+\t\t\teff_buf.token_len \u003d 0;\n+\t\t\tlws_remove_wsi_from_draining_ext_list(wsi);\n+\t\t\trx_draining_ext \u003d 1;\n+\t\t\tlwsl_debug(\u0022%s: doing draining flow\u005cn\u0022, __func__);\n+\n+\t\t\tgoto drain_extension;\n+\t\t}\n+\t\tswitch (wsi-\u003eietf_spec_revision) {\n+\t\tcase 13:\n+\t\t\t/*\n+\t\t\t * no prepended frame key any more\n+\t\t\t */\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 1;\n+\t\t\tgoto handle_first;\n+\n+\t\tdefault:\n+\t\t\tlwsl_warn(\u0022lws_rx_sm: unknown spec version %d\u005cn\u0022,\n+\t\t\t\t\t\t wsi-\u003eietf_spec_revision);\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\tcase LWS_RXPS_04_mask_1:\n+\t\twsi-\u003eu.ws.mask[1] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_mask_2;\n+\t\tbreak;\n+\tcase LWS_RXPS_04_mask_2:\n+\t\twsi-\u003eu.ws.mask[2] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_mask_3;\n+\t\tbreak;\n+\tcase LWS_RXPS_04_mask_3:\n+\t\twsi-\u003eu.ws.mask[3] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\n+\t\t/*\n+\t\t * start from the zero'th byte in the XOR key buffer since\n+\t\t * this is the start of a frame with a new key\n+\t\t */\n+\n+\t\twsi-\u003eu.ws.mask_idx \u003d 0;\n+\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_1;\n+\t\tbreak;\n+\n+\t/*\n+\t * 04 logical framing from the spec (all this is masked when incoming\n+\t * and has to be unmasked)\n+\t *\n+\t * We ignore the possibility of extension data because we don't\n+\t * negotiate any extensions at the moment.\n+\t *\n+\t * 0 1 2 3\n+\t * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n+\t * +-+-+-+-+-------+-+-------------+-------------------------------+\n+\t * |F|R|R|R| opcode|R| Payload len | Extended payload length |\n+\t * |I|S|S|S| (4) |S| (7) | (16/63) |\n+\t * |N|V|V|V| |V| | (if payload len\u003d\u003d126/127) |\n+\t * | |1|2|3| |4| | |\n+\t * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +\n+\t * | Extended payload length continued, if payload len \u003d\u003d 127 |\n+\t * + - - - - - - - - - - - - - - - +-------------------------------+\n+\t * | | Extension data |\n+\t * +-------------------------------+ - - - - - - - - - - - - - - - +\n+\t * : :\n+\t * +---------------------------------------------------------------+\n+\t * : Application data :\n+\t * +---------------------------------------------------------------+\n+\t *\n+\t * We pass payload through to userland as soon as we get it, ignoring\n+\t * FIN. It's up to userland to buffer it up if it wants to see a\n+\t * whole unfragmented block of the original size (which may be up to\n+\t * 2^63 long!)\n+\t */\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_1:\n+handle_first:\n+\n+\t\twsi-\u003eu.ws.opcode \u003d c \u0026 0xf;\n+\t\twsi-\u003eu.ws.rsv \u003d c \u0026 0x70;\n+\t\twsi-\u003eu.ws.final \u003d !!((c \u003e\u003e 7) \u0026 1);\n+\n+\t\tswitch (wsi-\u003eu.ws.opcode) {\n+\t\tcase LWSWSOPC_TEXT_FRAME:\n+\t\tcase LWSWSOPC_BINARY_FRAME:\n+\t\t\twsi-\u003eu.ws.rsv_first_msg \u003d (c \u0026 0x70);\n+\t\t\twsi-\u003eu.ws.frame_is_binary \u003d\n+\t\t\t wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_BINARY_FRAME;\n+\t\t\twsi-\u003eu.ws.first_fragment \u003d 1;\n+\t\t\tbreak;\n+\t\tcase 3:\n+\t\tcase 4:\n+\t\tcase 5:\n+\t\tcase 6:\n+\t\tcase 7:\n+\t\tcase 0xb:\n+\t\tcase 0xc:\n+\t\tcase 0xd:\n+\t\tcase 0xe:\n+\t\tcase 0xf:\n+\t\t\tlwsl_info(\u0022illegal opcode\u005cn\u0022);\n+\t\t\treturn -1;\n+\t\t}\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN:\n+\n+\t\twsi-\u003eu.ws.this_frame_masked \u003d !!(c \u0026 0x80);\n+\n+\t\tswitch (c \u0026 0x7f) {\n+\t\tcase 126:\n+\t\t\t/* control frames are not allowed to have big lengths */\n+\t\t\tif (wsi-\u003eu.ws.opcode \u0026 8)\n+\t\t\t\tgoto illegal_ctl_length;\n+\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN16_2;\n+\t\t\tbreak;\n+\t\tcase 127:\n+\t\t\t/* control frames are not allowed to have big lengths */\n+\t\t\tif (wsi-\u003eu.ws.opcode \u0026 8)\n+\t\t\t\tgoto illegal_ctl_length;\n+\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_8;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\twsi-\u003eu.ws.rx_packet_length \u003d c \u0026 0x7f;\n+\t\t\tif (wsi-\u003eu.ws.this_frame_masked)\n+\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n+\t\t\telse\n+\t\t\t\tif (wsi-\u003eu.ws.rx_packet_length)\n+\t\t\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n+\t\t\t\telse {\n+\t\t\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n+\t\t\t\t\tgoto spill;\n+\t\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN16_2:\n+\t\twsi-\u003eu.ws.rx_packet_length \u003d c \u003c\u003c 8;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN16_1;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN16_1:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d c;\n+\t\tif (wsi-\u003eu.ws.this_frame_masked)\n+\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n+\t\telse\n+\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_8:\n+\t\tif (c \u0026 0x80) {\n+\t\t\tlwsl_warn(\u0022b63 of length must be zero\u005cn\u0022);\n+\t\t\t/* kill the connection */\n+\t\t\treturn -1;\n+\t\t}\n+#if defined __LP64__\n+\t\twsi-\u003eu.ws.rx_packet_length \u003d ((size_t)c) \u003c\u003c 56;\n+#else\n+\t\twsi-\u003eu.ws.rx_packet_length \u003d 0;\n+#endif\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_7;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_7:\n+#if defined __LP64__\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 48;\n+#endif\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_6;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_6:\n+#if defined __LP64__\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 40;\n+#endif\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_5;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_5:\n+#if defined __LP64__\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 32;\n+#endif\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_4;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_4:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 24;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_3;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_3:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 16;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_2;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_2:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c) \u003c\u003c 8;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_04_FRAME_HDR_LEN64_1;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_04_FRAME_HDR_LEN64_1:\n+\t\twsi-\u003eu.ws.rx_packet_length |\u003d ((size_t)c);\n+\t\tif (wsi-\u003eu.ws.this_frame_masked)\n+\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\tLWS_RXPS_07_COLLECT_FRAME_KEY_1;\n+\t\telse\n+\t\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_1:\n+\t\twsi-\u003eu.ws.mask[0] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_2;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_2:\n+\t\twsi-\u003eu.ws.mask[1] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_3;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_3:\n+\t\twsi-\u003eu.ws.mask[2] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_07_COLLECT_FRAME_KEY_4;\n+\t\tbreak;\n+\n+\tcase LWS_RXPS_07_COLLECT_FRAME_KEY_4:\n+\t\twsi-\u003eu.ws.mask[3] \u003d c;\n+\t\tif (c)\n+\t\t\twsi-\u003eu.ws.all_zero_nonce \u003d 0;\n+\t\twsi-\u003elws_rx_parse_state \u003d\n+\t\t\t\t\tLWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;\n+\t\twsi-\u003eu.ws.mask_idx \u003d 0;\n+\t\tif (wsi-\u003eu.ws.rx_packet_length \u003d\u003d 0) {\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n+\t\t\tgoto spill;\n+\t\t}\n+\t\tbreak;\n+\n+\n+\tcase LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:\n+\t\tassert(wsi-\u003eu.ws.rx_ubuf);\n+\n+\t\tif (wsi-\u003eu.ws.rx_draining_ext)\n+\t\t\tgoto drain_extension;\n+\n+\t\tif (wsi-\u003eu.ws.rx_ubuf_head + LWS_PRE \u003e\u003d\n+\t\t wsi-\u003eu.ws.rx_ubuf_alloc) {\n+\t\t\tlwsl_err(\u0022Attempted overflow \u005cn\u0022);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (wsi-\u003eu.ws.all_zero_nonce)\n+\t\t\twsi-\u003eu.ws.rx_ubuf[LWS_PRE +\n+\t\t\t\t\t (wsi-\u003eu.ws.rx_ubuf_head++)] \u003d c;\n+\t\telse\n+\t\t\twsi-\u003eu.ws.rx_ubuf[LWS_PRE +\n+\t\t\t (wsi-\u003eu.ws.rx_ubuf_head++)] \u003d\n+\t\t\t\t c ^ wsi-\u003eu.ws.mask[\n+\t\t\t\t\t (wsi-\u003eu.ws.mask_idx++) \u0026 3];\n+\n+\t\tif (--wsi-\u003eu.ws.rx_packet_length \u003d\u003d 0) {\n+\t\t\t/* spill because we have the whole frame */\n+\t\t\twsi-\u003elws_rx_parse_state \u003d LWS_RXPS_NEW;\n+\t\t\tgoto spill;\n+\t\t}\n+\n+\t\t/*\n+\t\t * if there's no protocol max frame size given, we are\n+\t\t * supposed to default to context-\u003ept_serv_buf_size\n+\t\t */\n+\n+\t\tif (!wsi-\u003eprotocol-\u003erx_buffer_size \u0026\u0026\n+\t\t wsi-\u003eu.ws.rx_ubuf_head !\u003d wsi-\u003econtext-\u003ept_serv_buf_size)\n+\t\t\tbreak;\n+\t\telse\n+\t\t\tif (wsi-\u003eprotocol-\u003erx_buffer_size \u0026\u0026\n+\t\t\t\t\twsi-\u003eu.ws.rx_ubuf_head !\u003d\n+\t\t\t\t\t\t wsi-\u003eprotocol-\u003erx_buffer_size)\n+\t\t\tbreak;\n+\n+\t\t/* spill because we filled our rx buffer */\n+spill:\n+\t\t/*\n+\t\t * is this frame a control packet we should take care of at this\n+\t\t * layer? If so service it and hide it from the user callback\n+\t\t */\n+\n+\t\tlwsl_parser(\u0022spill on %s\u005cn\u0022, wsi-\u003eprotocol-\u003ename);\n+\n+\t\tswitch (wsi-\u003eu.ws.opcode) {\n+\t\tcase LWSWSOPC_CLOSE:\n+\n+\t\t\t/* is this an acknowledgement of our close? */\n+\t\t\tif (wsi-\u003estate \u003d\u003d LWSS_AWAITING_CLOSE_ACK) {\n+\t\t\t\t/*\n+\t\t\t\t * fine he has told us he is closing too, let's\n+\t\t\t\t * finish our close\n+\t\t\t\t */\n+\t\t\t\tlwsl_parser(\u0022seen client close ack\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tif (wsi-\u003estate \u003d\u003d LWSS_RETURNED_CLOSE_ALREADY)\n+\t\t\t\t/* if he sends us 2 CLOSE, kill him */\n+\t\t\t\treturn -1;\n+\n+\t\t\tif (lws_partial_buffered(wsi)) {\n+\t\t\t\t/*\n+\t\t\t\t * if we're in the middle of something,\n+\t\t\t\t * we can't do a normal close response and\n+\t\t\t\t * have to just close our end.\n+\t\t\t\t */\n+\t\t\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n+\t\t\t\tlwsl_parser(\u0022Closing on peer close due to Pending tx\u005cn\u0022);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\n+\t\t\tif (user_callback_handle_rxflow(\n+\t\t\t\t\twsi-\u003eprotocol-\u003ecallback, wsi,\n+\t\t\t\t\tLWS_CALLBACK_WS_PEER_INITIATED_CLOSE,\n+\t\t\t\t\twsi-\u003euser_space,\n+\t\t\t\t\t\u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n+\t\t\t\t\twsi-\u003eu.ws.rx_ubuf_head))\n+\t\t\t\treturn -1;\n+\n+\t\t\tlwsl_parser(\u0022server sees client close packet\u005cn\u0022);\n+\t\t\twsi-\u003estate \u003d LWSS_RETURNED_CLOSE_ALREADY;\n+\t\t\t/* deal with the close packet contents as a PONG */\n+\t\t\twsi-\u003eu.ws.payload_is_close \u003d 1;\n+\t\t\tgoto process_as_ping;\n+\n+\t\tcase LWSWSOPC_PING:\n+\t\t\tlwsl_info(\u0022received %d byte ping, sending pong\u005cn\u0022,\n+\t\t\t\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n+\n+\t\t\tif (wsi-\u003eu.ws.ping_pending_flag) {\n+\t\t\t\t/*\n+\t\t\t\t * there is already a pending ping payload\n+\t\t\t\t * we should just log and drop\n+\t\t\t\t */\n+\t\t\t\tlwsl_parser(\u0022DROP PING since one pending\u005cn\u0022);\n+\t\t\t\tgoto ping_drop;\n+\t\t\t}\n+process_as_ping:\n+\t\t\t/* control packets can only be \u003c 128 bytes long */\n+\t\t\tif (wsi-\u003eu.ws.rx_ubuf_head \u003e 128 - 3) {\n+\t\t\t\tlwsl_parser(\u0022DROP PING payload too large\u005cn\u0022);\n+\t\t\t\tgoto ping_drop;\n+\t\t\t}\n+\n+\t\t\t/* stash the pong payload */\n+\t\t\tmemcpy(wsi-\u003eu.ws.ping_payload_buf + LWS_PRE,\n+\t\t\t \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n+\t\t\t\twsi-\u003eu.ws.rx_ubuf_head);\n+\n+\t\t\twsi-\u003eu.ws.ping_payload_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n+\t\t\twsi-\u003eu.ws.ping_pending_flag \u003d 1;\n+\n+\t\t\t/* get it sent as soon as possible */\n+\t\t\tlws_callback_on_writable(wsi);\n+ping_drop:\n+\t\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n+\t\t\treturn 0;\n+\n+\t\tcase LWSWSOPC_PONG:\n+\t\t\tlwsl_info(\u0022received pong\u005cn\u0022);\n+\t\t\tlwsl_hexdump(\u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE],\n+\t\t\t wsi-\u003eu.ws.rx_ubuf_head);\n+\n+\t\t\tif (wsi-\u003epending_timeout \u003d\u003d PENDING_TIMEOUT_WS_PONG_CHECK_GET_PONG) {\n+\t\t\t\tlwsl_info(\u0022received expected PONG on wsi %p\u005cn\u0022, wsi);\n+\t\t\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\t\t\t}\n+\n+\t\t\t/* issue it */\n+\t\t\tcallback_action \u003d LWS_CALLBACK_RECEIVE_PONG;\n+\t\t\tbreak;\n+\n+\t\tcase LWSWSOPC_TEXT_FRAME:\n+\t\tcase LWSWSOPC_BINARY_FRAME:\n+\t\tcase LWSWSOPC_CONTINUATION:\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tlwsl_parser(\u0022passing opc %x up to exts\u005cn\u0022,\n+\t\t\t\t wsi-\u003eu.ws.opcode);\n+\t\t\t/*\n+\t\t\t * It's something special we can't understand here.\n+\t\t\t * Pass the payload up to the extension's parsing\n+\t\t\t * state machine.\n+\t\t\t */\n+\n+\t\t\teff_buf.token \u003d \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n+\t\t\teff_buf.token_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n+\n+\t\t\tif (lws_ext_cb_active(wsi, LWS_EXT_CB_EXTENDED_PAYLOAD_RX,\n+\t\t\t\t\t \u0026eff_buf, 0) \u003c\u003d 0)\n+\t\t\t\t/* not handle or fail */\n+\t\t\t\tlwsl_ext(\u0022ext opc opcode 0x%x unknown\u005cn\u0022,\n+\t\t\t\t\t wsi-\u003eu.ws.opcode);\n+\n+\t\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\t/*\n+\t\t * No it's real payload, pass it up to the user callback.\n+\t\t * It's nicely buffered with the pre-padding taken care of\n+\t\t * so it can be sent straight out again using lws_write\n+\t\t */\n+\n+\t\teff_buf.token \u003d \u0026wsi-\u003eu.ws.rx_ubuf[LWS_PRE];\n+\t\teff_buf.token_len \u003d wsi-\u003eu.ws.rx_ubuf_head;\n+\n+\t\tif (wsi-\u003eu.ws.opcode \u003d\u003d LWSWSOPC_PONG \u0026\u0026 !eff_buf.token_len)\n+\t\t\tgoto already_done;\n+\n+drain_extension:\n+\t\tlwsl_ext(\u0022%s: passing %d to ext\u005cn\u0022, __func__, eff_buf.token_len);\n+\n+\t\tif (wsi-\u003estate \u003d\u003d LWSS_RETURNED_CLOSE_ALREADY ||\n+\t\t wsi-\u003estate \u003d\u003d LWSS_AWAITING_CLOSE_ACK)\n+\t\t\tgoto already_done;\n+\n+\t\tn \u003d lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, \u0026eff_buf, 0);\n+\t\t/*\n+\t\t * eff_buf may be pointing somewhere completely different now,\n+\t\t * it's the output\n+\t\t */\n+\t\twsi-\u003eu.ws.first_fragment \u003d 0;\n+\t\tif (n \u003c 0) {\n+\t\t\t/*\n+\t\t\t * we may rely on this to get RX, just drop connection\n+\t\t\t */\n+\t\t\twsi-\u003esocket_is_permanently_unusable \u003d 1;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (rx_draining_ext \u0026\u0026 eff_buf.token_len \u003d\u003d 0)\n+\t\t\tgoto already_done;\n+\n+\t\tif (n \u0026\u0026 eff_buf.token_len)\n+\t\t\t/* extension had more... main loop will come back */\n+\t\t\tlws_add_wsi_to_draining_ext_list(wsi);\n+\t\telse\n+\t\t\tlws_remove_wsi_from_draining_ext_list(wsi);\n+\n+\t\tif (eff_buf.token_len \u003e 0 ||\n+\t\t callback_action \u003d\u003d LWS_CALLBACK_RECEIVE_PONG) {\n+\t\t\teff_buf.token[eff_buf.token_len] \u003d '\u005c0';\n+\n+\t\t\tif (wsi-\u003eprotocol-\u003ecallback) {\n+\n+\t\t\t\tif (callback_action \u003d\u003d LWS_CALLBACK_RECEIVE_PONG)\n+\t\t\t\t\tlwsl_info(\u0022Doing pong callback\u005cn\u0022);\n+\n+\t\t\t\tret \u003d user_callback_handle_rxflow(\n+\t\t\t\t\t\twsi-\u003eprotocol-\u003ecallback,\n+\t\t\t\t\t\twsi,\n+\t\t\t\t\t\t(enum lws_callback_reasons)callback_action,\n+\t\t\t\t\t\twsi-\u003euser_space,\n+\t\t\t\t\t\teff_buf.token,\n+\t\t\t\t\t\teff_buf.token_len);\n+\t\t\t}\n+\t\t\telse\n+\t\t\t\tlwsl_err(\u0022No callback on payload spill!\u005cn\u0022);\n+\t\t}\n+\n+already_done:\n+\t\twsi-\u003eu.ws.rx_ubuf_head \u003d 0;\n+\t\tbreak;\n+\t}\n+\n+\treturn ret;\n+\n+illegal_ctl_length:\n+\n+\tlwsl_warn(\u0022Control frame with xtended length is illegal\u005cn\u0022);\n+\t/* kill the connection */\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE size_t\n+lws_remaining_packet_payload(struct lws *wsi)\n+{\n+\treturn wsi-\u003eu.ws.rx_packet_length;\n+}\n+\n+/* Once we reach LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED, we know how much\n+ * to expect in that state and can deal with it in bulk more efficiently.\n+ */\n+\n+int\n+lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf,\n+\t\t\t\t size_t *len)\n+{\n+\tunsigned char *buffer \u003d *buf, mask[4];\n+\tint buffer_size, n;\n+\tunsigned int avail;\n+\tchar *rx_ubuf;\n+\n+\tif (wsi-\u003eprotocol-\u003erx_buffer_size)\n+\t\tbuffer_size \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n+\telse\n+\t\tbuffer_size \u003d wsi-\u003econtext-\u003ept_serv_buf_size;\n+\tavail \u003d buffer_size - wsi-\u003eu.ws.rx_ubuf_head;\n+\n+\t/* do not consume more than we should */\n+\tif (avail \u003e wsi-\u003eu.ws.rx_packet_length)\n+\t\tavail \u003d wsi-\u003eu.ws.rx_packet_length;\n+\n+\t/* do not consume more than what is in the buffer */\n+\tif (avail \u003e *len)\n+\t\tavail \u003d *len;\n+\n+\t/* we want to leave 1 byte for the parser to handle properly */\n+\tif (avail \u003c\u003d 1)\n+\t\treturn 0;\n+\n+\tavail--;\n+\trx_ubuf \u003d wsi-\u003eu.ws.rx_ubuf + LWS_PRE + wsi-\u003eu.ws.rx_ubuf_head;\n+\tif (wsi-\u003eu.ws.all_zero_nonce)\n+\t\tmemcpy(rx_ubuf, buffer, avail);\n+\telse {\n+\n+\t\tfor (n \u003d 0; n \u003c 4; n++)\n+\t\t\tmask[n] \u003d wsi-\u003eu.ws.mask[(wsi-\u003eu.ws.mask_idx + n) \u0026 3];\n+\n+\t\t/* deal with 4-byte chunks using unwrapped loop */\n+\t\tn \u003d avail \u003e\u003e 2;\n+\t\twhile (n--) {\n+\t\t\t*(rx_ubuf++) \u003d *(buffer++) ^ mask[0];\n+\t\t\t*(rx_ubuf++) \u003d *(buffer++) ^ mask[1];\n+\t\t\t*(rx_ubuf++) \u003d *(buffer++) ^ mask[2];\n+\t\t\t*(rx_ubuf++) \u003d *(buffer++) ^ mask[3];\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*(rx_ubuf++) \u003d *(buffer++) ^ mask[n];\n+\n+\t\twsi-\u003eu.ws.mask_idx \u003d (wsi-\u003eu.ws.mask_idx + avail) \u0026 3;\n+\t}\n+\n+\t(*buf) +\u003d avail;\n+\twsi-\u003eu.ws.rx_ubuf_head +\u003d avail;\n+\twsi-\u003eu.ws.rx_packet_length -\u003d avail;\n+\t*len -\u003d avail;\n+\n+\treturn avail;\n+}\ndiff --git a/lib/server/peer-limits.c b/lib/server/peer-limits.c\nnew file mode 100644\nindex 0000000..daaae9c\n--- /dev/null\n+++ b/lib/server/peer-limits.c\n@@ -0,0 +1,252 @@\n+/*\n+ * libwebsockets - peer limits tracking\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+/* requires context-\u003elock */\n+static void\n+__lws_peer_remove_from_peer_wait_list(struct lws_context *context,\n+\t\t\t\t struct lws_peer *peer)\n+{\n+\tstruct lws_peer *df;\n+\n+\tlws_start_foreach_llp(struct lws_peer **, p, context-\u003epeer_wait_list) {\n+\t\tif (*p \u003d\u003d peer) {\n+\t\t\tdf \u003d *p;\n+\n+\t\t\t*p \u003d df-\u003epeer_wait_list;\n+\t\t\tdf-\u003epeer_wait_list \u003d NULL;\n+\n+\t\t\treturn;\n+\t\t}\n+\t} lws_end_foreach_llp(p, peer_wait_list);\n+}\n+\n+/* requires context-\u003elock */\n+static void\n+__lws_peer_add_to_peer_wait_list(struct lws_context *context,\n+\t\t\t\t struct lws_peer *peer)\n+{\n+\t__lws_peer_remove_from_peer_wait_list(context, peer);\n+\n+\tpeer-\u003epeer_wait_list \u003d context-\u003epeer_wait_list;\n+\tcontext-\u003epeer_wait_list \u003d peer;\n+}\n+\n+\n+struct lws_peer *\n+lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd)\n+{\n+\tstruct lws_context *context \u003d vhost-\u003econtext;\n+\tsocklen_t rlen \u003d 0;\n+\tvoid *q;\n+\tuint8_t *q8;\n+\tstruct lws_peer *peer;\n+\tuint32_t hash \u003d 0;\n+\tint n, af \u003d AF_INET;\n+\tstruct sockaddr_storage addr;\n+\n+#ifdef LWS_WITH_IPV6\n+\tif (LWS_IPV6_ENABLED(vhost)) {\n+\t\taf \u003d AF_INET6;\n+\t}\n+#endif\n+\trlen \u003d sizeof(addr);\n+\tif (getpeername(sockfd, (struct sockaddr*)\u0026addr, \u0026rlen))\n+\t\treturn NULL;\n+\n+\tif (af \u003d\u003d AF_INET) {\n+\t\tstruct sockaddr_in *s \u003d (struct sockaddr_in *)\u0026addr;\n+\t\tq \u003d \u0026s-\u003esin_addr;\n+\t\trlen \u003d sizeof(s-\u003esin_addr);\n+\t} else\n+#ifdef LWS_WITH_IPV6\n+\t{\n+\t\tstruct sockaddr_in6 *s \u003d (struct sockaddr_in6 *)\u0026addr;\n+\t\tq \u003d \u0026s-\u003esin6_addr;\n+\t\trlen \u003d sizeof(s-\u003esin6_addr);\n+\t}\n+#else\n+\t\treturn NULL;\n+#endif\n+\n+\tq8 \u003d q;\n+\tfor (n \u003d 0; n \u003c rlen; n++)\n+\t\thash \u003d (((hash \u003c\u003c 4) | (hash \u003e\u003e 28)) * n) ^ q8[n];\n+\n+\thash \u003d hash % context-\u003epl_hash_elements;\n+\n+\tlws_context_lock(context); /* \u003c\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d */\n+\n+\tlws_start_foreach_ll(struct lws_peer *, peerx,\n+\t\t\t context-\u003epl_hash_table[hash]) {\n+\t\tif (peerx-\u003eaf \u003d\u003d af \u0026\u0026 !memcmp(q, peerx-\u003eaddr, rlen)) {\n+\t\t\tlws_context_unlock(context); /* \u003d\u003d\u003d */\n+\t\t\treturn peerx;\n+\t\t}\n+\t} lws_end_foreach_ll(peerx, next);\n+\n+\tlwsl_info(\u0022%s: creating new peer\u005cn\u0022, __func__);\n+\n+\tpeer \u003d lws_zalloc(sizeof(*peer), \u0022peer\u0022);\n+\tif (!peer) {\n+\t\tlws_context_unlock(context); /* \u003d\u003d\u003d */\n+\t\treturn NULL;\n+\t}\n+\n+\tcontext-\u003ecount_peers++;\n+\tpeer-\u003enext \u003d context-\u003epl_hash_table[hash];\n+\tpeer-\u003ehash \u003d hash;\n+\tpeer-\u003eaf \u003d af;\n+\tcontext-\u003epl_hash_table[hash] \u003d peer;\n+\tmemcpy(peer-\u003eaddr, q, rlen);\n+\ttime(\u0026peer-\u003etime_created);\n+\t/*\n+\t * On creation, the peer has no wsi attached, so is created on the\n+\t * wait list. When a wsi is added it is removed from the wait list.\n+\t */\n+\ttime(\u0026peer-\u003etime_closed_all);\n+\t__lws_peer_add_to_peer_wait_list(context, peer);\n+\n+\tlws_context_unlock(context); /* \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003e */\n+\n+\treturn peer;\n+}\n+\n+/* requires context-\u003elock */\n+static int\n+__lws_peer_destroy(struct lws_context *context, struct lws_peer *peer)\n+{\n+\tlws_start_foreach_llp(struct lws_peer **, p,\n+\t\t\t context-\u003epl_hash_table[peer-\u003ehash]) {\n+\t\tif (*p \u003d\u003d peer) {\n+\t\t\tstruct lws_peer *df \u003d *p;\n+\t\t\t*p \u003d df-\u003enext;\n+\t\t\tlws_free(df);\n+\t\t\tcontext-\u003ecount_peers--;\n+\n+\t\t\treturn 0;\n+\t\t}\n+\t} lws_end_foreach_llp(p, next);\n+\n+\treturn 1;\n+}\n+\n+void\n+lws_peer_cull_peer_wait_list(struct lws_context *context)\n+{\n+\tstruct lws_peer *df;\n+\ttime_t t;\n+\n+\ttime(\u0026t);\n+\n+\tif (context-\u003enext_cull \u0026\u0026 t \u003c context-\u003enext_cull)\n+\t\treturn;\n+\n+\tlws_context_lock(context); /* \u003c\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d */\n+\n+\tcontext-\u003enext_cull \u003d t + 5;\n+\n+\tlws_start_foreach_llp(struct lws_peer **, p, context-\u003epeer_wait_list) {\n+\t\tif (t - (*p)-\u003etime_closed_all \u003e 10) {\n+\t\t\tdf \u003d *p;\n+\n+\t\t\t/* remove us from the peer wait list */\n+\t\t\t*p \u003d df-\u003epeer_wait_list;\n+\t\t\tdf-\u003epeer_wait_list \u003d NULL;\n+\n+\t\t\t__lws_peer_destroy(context, df);\n+\t\t\tcontinue; /* we already point to next, if any */\n+\t\t}\n+\t} lws_end_foreach_llp(p, peer_wait_list);\n+\n+\tlws_context_unlock(context); /* \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003e */\n+}\n+\n+void\n+lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,\n+\t\t struct lws *wsi)\n+{\n+\tif (!peer)\n+\t\treturn;\n+\n+\tlws_context_lock(context); /* \u003c\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d */\n+\n+\tpeer-\u003ecount_wsi++;\n+\twsi-\u003epeer \u003d peer;\n+\t__lws_peer_remove_from_peer_wait_list(context, peer);\n+\n+\tlws_context_unlock(context); /* \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003e */\n+}\n+\n+void\n+lws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer)\n+{\n+\tif (!peer)\n+\t\treturn;\n+\n+\tlws_context_lock(context); /* \u003c\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d */\n+\n+\tassert(peer-\u003ecount_wsi);\n+\tpeer-\u003ecount_wsi--;\n+\n+\tif (!peer-\u003ecount_wsi \u0026\u0026 !peer-\u003ecount_ah) {\n+\t\t/*\n+\t\t * in order that we can accumulate peer activity correctly\n+\t\t * allowing for periods when the peer has no connections,\n+\t\t * we don't synchronously destroy the peer when his last\n+\t\t * wsi closes. Instead we mark the time his last wsi\n+\t\t * closed and add him to a peer_wait_list to be reaped\n+\t\t * later if no further activity is coming.\n+\t\t */\n+\t\ttime(\u0026peer-\u003etime_closed_all);\n+\t\t__lws_peer_add_to_peer_wait_list(context, peer);\n+\t}\n+\n+\tlws_context_unlock(context); /* \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003e */\n+}\n+\n+int\n+lws_peer_confirm_ah_attach_ok(struct lws_context *context, struct lws_peer *peer)\n+{\n+\tif (!peer)\n+\t\treturn 0;\n+\n+\tif (context-\u003eip_limit_ah \u0026\u0026 peer-\u003ecount_ah \u003e\u003d context-\u003eip_limit_ah) {\n+\t\tlwsl_info(\u0022peer reached ah limit %d, deferring\u005cn\u0022,\n+\t\t\t\tcontext-\u003eip_limit_ah);\n+\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void\n+lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer)\n+{\n+\tif (!peer)\n+\t\treturn;\n+\n+\tassert(peer-\u003ecount_ah);\n+\tpeer-\u003ecount_ah--;\n+}\n+\ndiff --git a/lib/server/ranges.c b/lib/server/ranges.c\nnew file mode 100644\nindex 0000000..bc1578d\n--- /dev/null\n+++ b/lib/server/ranges.c\n@@ -0,0 +1,214 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * RFC7233 ranges parser\n+ *\n+ * Copyright (C) 2016 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+/*\n+ * RFC7233 examples\n+ *\n+ * o The first 500 bytes (byte offsets 0-499, inclusive):\n+ *\n+ * bytes\u003d0-499\n+ *\n+ * o The second 500 bytes (byte offsets 500-999, inclusive):\n+ *\n+ * bytes\u003d500-999\n+ *\n+ * o The final 500 bytes (byte offsets 9500-9999, inclusive):\n+ *\n+ * bytes\u003d-500\n+ *\n+ * Or:\n+ *\n+ * bytes\u003d9500-\n+ *\n+ * o The first and last bytes only (bytes 0 and 9999):\n+ *\n+ * bytes\u003d0-0,-1\n+ *\n+ * o Other valid (but not canonical) specifications of the second 500\n+ * bytes (byte offsets 500-999, inclusive):\n+ *\n+ * bytes\u003d500-600,601-999\n+ * bytes\u003d500-700,601-999\n+ */\n+\n+/*\n+ * returns 1 if the range struct represents a usable range\n+ * if no ranges header, you get one of these for the whole\n+ * file. Otherwise you get one for each valid range in the\n+ * header.\n+ *\n+ * returns 0 if no further valid range forthcoming; rp-\u003estate\n+ * may be LWSRS_SYNTAX or LWSRS_COMPLETED\n+ */\n+\n+int\n+lws_ranges_next(struct lws_range_parsing *rp)\n+{\n+\tstatic const char * const beq \u003d \u0022bytes\u003d\u0022;\n+\tchar c;\n+\n+\twhile (1) {\n+\n+\t\tc \u003d rp-\u003ebuf[rp-\u003epos];\n+\n+\t\tswitch (rp-\u003estate) {\n+\t\tcase LWSRS_SYNTAX:\n+\t\tcase LWSRS_COMPLETED:\n+\t\t\treturn 0;\n+\n+\t\tcase LWSRS_NO_ACTIVE_RANGE:\n+\t\t\trp-\u003estate \u003d LWSRS_COMPLETED;\n+\t\t\treturn 0;\n+\n+\t\tcase LWSRS_BYTES_EQ: // looking for \u0022bytes\u003d\u0022\n+\t\t\tif (c !\u003d beq[rp-\u003epos]) {\n+\t\t\t\trp-\u003estate \u003d LWSRS_SYNTAX;\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tif (rp-\u003epos \u003d\u003d 5)\n+\t\t\t\trp-\u003estate \u003d LWSRS_FIRST;\n+\t\t\tbreak;\n+\n+\t\tcase LWSRS_FIRST:\n+\t\t\trp-\u003estart \u003d 0;\n+\t\t\trp-\u003eend \u003d 0;\n+\t\t\trp-\u003estart_valid \u003d 0;\n+\t\t\trp-\u003eend_valid \u003d 0;\n+\n+\t\t\trp-\u003estate \u003d LWSRS_STARTING;\n+\n+\t\t\t// fallthru\n+\n+\t\tcase LWSRS_STARTING:\n+\t\t\tif (c \u003d\u003d '-') {\n+\t\t\t\trp-\u003estate \u003d LWSRS_ENDING;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tif (!(c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')) {\n+\t\t\t\trp-\u003estate \u003d LWSRS_SYNTAX;\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t\trp-\u003estart \u003d (rp-\u003estart * 10) + (c - '0');\n+\t\t\trp-\u003estart_valid \u003d 1;\n+\t\t\tbreak;\n+\n+\t\tcase LWSRS_ENDING:\n+\t\t\tif (c \u003d\u003d ',' || c \u003d\u003d '\u005c0') {\n+\t\t\t\trp-\u003estate \u003d LWSRS_FIRST;\n+\t\t\t\tif (c \u003d\u003d ',')\n+\t\t\t\t\trp-\u003epos++;\n+\n+\t\t\t\t/*\n+\t\t\t\t * By the end of this, start and end are\n+\t\t\t\t * always valid if the range still is\n+\t\t\t\t */\n+\n+\t\t\t\tif (!rp-\u003estart_valid) { /* eg, -500 */\n+\t\t\t\t\tif (rp-\u003eend \u003e rp-\u003eextent)\n+\t\t\t\t\t\trp-\u003eend \u003d rp-\u003eextent;\n+\n+\t\t\t\t\trp-\u003estart \u003d rp-\u003eextent - rp-\u003eend;\n+\t\t\t\t\trp-\u003eend \u003d rp-\u003eextent - 1;\n+\t\t\t\t} else\n+\t\t\t\t\tif (!rp-\u003eend_valid)\n+\t\t\t\t\t\trp-\u003eend \u003d rp-\u003eextent - 1;\n+\n+\t\t\t\trp-\u003edid_try \u003d 1;\n+\n+\t\t\t\t/* end must be \u003e\u003d start or ignore it */\n+\t\t\t\tif (rp-\u003eend \u003c rp-\u003estart) {\n+\t\t\t\t\tif (c \u003d\u003d ',')\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\trp-\u003estate \u003d LWSRS_COMPLETED;\n+\t\t\t\t\treturn 0;\n+\t\t\t\t}\n+\n+\t\t\t\treturn 1; /* issue range */\n+\t\t\t}\n+\n+\t\t\tif (!(c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9')) {\n+\t\t\t\trp-\u003estate \u003d LWSRS_SYNTAX;\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t\trp-\u003eend \u003d (rp-\u003eend * 10) + (c - '0');\n+\t\t\trp-\u003eend_valid \u003d 1;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\trp-\u003epos++;\n+\t}\n+}\n+\n+void\n+lws_ranges_reset(struct lws_range_parsing *rp)\n+{\n+\trp-\u003epos \u003d 0;\n+\trp-\u003ectr \u003d 0;\n+\trp-\u003estart \u003d 0;\n+\trp-\u003eend \u003d 0;\n+\trp-\u003estart_valid \u003d 0;\n+\trp-\u003eend_valid \u003d 0;\n+\trp-\u003estate \u003d LWSRS_BYTES_EQ;\n+}\n+\n+/*\n+ * returns count of valid ranges\n+ */\n+int\n+lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,\n+\t\tunsigned long long extent)\n+{\n+\trp-\u003eagg \u003d 0;\n+\trp-\u003esend_ctr \u003d 0;\n+\trp-\u003einside \u003d 0;\n+\trp-\u003ecount_ranges \u003d 0;\n+\trp-\u003edid_try \u003d 0;\n+\tlws_ranges_reset(rp);\n+\trp-\u003estate \u003d LWSRS_COMPLETED;\n+\n+\trp-\u003eextent \u003d extent;\n+\n+\tif (lws_hdr_copy(wsi, (char *)rp-\u003ebuf, sizeof(rp-\u003ebuf),\n+\t\t\t WSI_TOKEN_HTTP_RANGE) \u003c\u003d 0)\n+\t\treturn 0;\n+\n+\trp-\u003estate \u003d LWSRS_BYTES_EQ;\n+\n+\twhile (lws_ranges_next(rp)) {\n+\t\trp-\u003ecount_ranges++;\n+\t\trp-\u003eagg +\u003d rp-\u003eend - rp-\u003estart + 1;\n+\t}\n+\n+\tlwsl_debug(\u0022%s: count %d\u005cn\u0022, __func__, rp-\u003ecount_ranges);\n+\tlws_ranges_reset(rp);\n+\n+\tif (rp-\u003edid_try \u0026\u0026 !rp-\u003ecount_ranges)\n+\t\treturn -1; /* \u0022not satisfiable */\n+\n+\tlws_ranges_next(rp);\n+\n+\treturn rp-\u003ecount_ranges;\n+}\ndiff --git a/lib/server/rewrite.c b/lib/server/rewrite.c\nnew file mode 100644\nindex 0000000..2f9b0c4\n--- /dev/null\n+++ b/lib/server/rewrite.c\n@@ -0,0 +1,52 @@\n+#include \u0022private-libwebsockets.h\u0022\n+\n+\n+LWS_EXTERN struct lws_rewrite *\n+lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from, const char *to)\n+{\n+\tstruct lws_rewrite *r \u003d lws_malloc(sizeof(*r), \u0022rewrite\u0022);\n+\n+\tif (!r) {\n+\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n+\t\treturn NULL;\n+\t}\n+\n+\tif (hubbub_parser_create(\u0022UTF-8\u0022, false, \u0026r-\u003eparser) !\u003d HUBBUB_OK) {\n+\t\tlws_free(r);\n+\n+\t\treturn NULL;\n+\t}\n+\tr-\u003efrom \u003d from;\n+\tr-\u003efrom_len \u003d strlen(from);\n+\tr-\u003eto \u003d to;\n+\tr-\u003eto_len \u003d strlen(to);\n+\tr-\u003eparams.token_handler.handler \u003d cb;\n+\tr-\u003ewsi \u003d wsi;\n+\tr-\u003eparams.token_handler.pw \u003d (void *)r;\n+\tif (hubbub_parser_setopt(r-\u003eparser, HUBBUB_PARSER_TOKEN_HANDLER,\n+\t\t\t\t \u0026r-\u003eparams) !\u003d HUBBUB_OK) {\n+\t\tlws_free(r);\n+\n+\t\treturn NULL;\n+\t}\n+\n+\treturn r;\n+}\n+\n+LWS_EXTERN int\n+lws_rewrite_parse(struct lws_rewrite *r,\n+\t\t const unsigned char *in, int in_len)\n+{\n+\tif (hubbub_parser_parse_chunk(r-\u003eparser, in, in_len) !\u003d HUBBUB_OK)\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n+LWS_EXTERN void\n+lws_rewrite_destroy(struct lws_rewrite *r)\n+{\n+\thubbub_parser_destroy(r-\u003eparser);\n+\tlws_free(r);\n+}\n+\ndiff --git a/lib/server/server-handshake.c b/lib/server/server-handshake.c\nnew file mode 100644\nindex 0000000..3d319c3\n--- /dev/null\n+++ b/lib/server/server-handshake.c\n@@ -0,0 +1,360 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2013 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr +\u003d strlen(str); }\n+\n+#ifndef LWS_NO_EXTENSIONS\n+static int\n+lws_extension_server_handshake(struct lws *wsi, char **p, int budget)\n+{\n+\tstruct lws_context *context \u003d wsi-\u003econtext;\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, 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-\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 \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\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 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 \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-\u003evhost-\u003eextensions;\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-\u003ecount_act_ext; m++)\n+\t\t\t\tif (wsi-\u003eactive_extensions[m] \u003d\u003d ext) {\n+\t\t\t\t\tlwsl_info(\u0022extension 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-\u003eprotocol-\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-\u003eactive_extensions[wsi-\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-\u003eact_ext_user[\n+\t\t\t\t\t wsi-\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, (end - *p), \u0022%s\u0022, ext_name);\n+\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_debug(\u0022ext args %s\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\tlwsl_debug(\u0022'%s' '%s'\u005cn\u0022, po-\u003ename, args);\n+\t\t\t\t\t/* only support arg-less options... */\n+\t\t\t\t\tif (po-\u003etype \u003d\u003d EXTARG_NONE \u0026\u0026\n+\t\t\t\t\t !strncmp(args, po-\u003ename,\n+\t\t\t\t\t\t\t strlen(po-\u003ename))) {\n+\t\t\t\t\t\toa.option_name \u003d NULL;\n+\t\t\t\t\t\toa.option_index \u003d po - opts;\n+\t\t\t\t\t\toa.start \u003d NULL;\n+\t\t\t\t\t\tlwsl_debug(\u0022setting %s\u005cn\u0022, po-\u003ename);\n+\t\t\t\t\t\tif (!ext-\u003ecallback(\n+\t\t\t\t\t\t\t\tlws_get_context(wsi), ext, wsi,\n+\t\t\t\t\t\t\t\t LWS_EXT_CB_OPTION_SET,\n+\t\t\t\t\t\t\t\t wsi-\u003eact_ext_user[\n+\t\t\t\t\t\t\t\t wsi-\u003ecount_act_ext],\n+\t\t\t\t\t\t\t\t \u0026oa, (end - *p))) {\n+\n+\t\t\t\t\t\t\t*p +\u003d lws_snprintf(*p, (end - *p), \u0022; %s\u0022, po-\u003ename);\n+\t\t\t\t\t\t\tlwsl_debug(\u0022adding option %s\u005cn\u0022, po-\u003ename);\n+\t\t\t\t\t\t}\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+\t\t\t}\n+\n+\t\t\twsi-\u003ecount_act_ext++;\n+\t\t\tlwsl_parser(\u0022count_act_ext \u003c- %d\u005cn\u0022,\n+\t\t\t\t wsi-\u003ecount_act_ext);\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+int\n+handshake_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_parser(\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 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, n, hash);\n+\n+\taccept_len \u003d lws_b64_encode_string((char *)hash, 20,\n+\t\t\t(char *)pt-\u003eserv_buf, 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 + 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-\u003eprotocol-\u003ename \u0026\u0026\n+\t wsi-\u003eprotocol-\u003ename[0]) {\n+\t\tLWS_CPYAPP(p, \u0022\u005cx0d\u005cx0aSec-WebSocket-Protocol: \u0022);\n+\t\tp +\u003d lws_snprintf(p, 128, \u0022%s\u0022, wsi-\u003eprotocol-\u003ename);\n+\t}\n+\n+#ifndef LWS_NO_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 ((char *)pt-\u003eserv_buf + context-\u003ept_serv_buf_size) - p;\n+\tif (user_callback_handle_rxflow(wsi-\u003eprotocol-\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+\tif (!lws_any_extension_handled(wsi, LWS_EXT_CB_HANDSHAKE_REPLY_TX,\n+\t\t\t\t response, p - response)) {\n+\n+\t\t/* okay send the handshake response accepting the connection */\n+\n+\t\tlwsl_parser(\u0022issuing resp pkt %d len\u005cn\u0022, (int)(p - response));\n+#if defined(DEBUG) \u0026\u0026 ! defined(LWS_WITH_ESP8266)\n+\t\tfwrite(response, 1, p - response, stderr);\n+#endif\n+\t\tn \u003d lws_write(wsi, (unsigned char *)response,\n+\t\t\t p - response, LWS_WRITE_HTTP_HEADERS);\n+\t\tif (n !\u003d (p - response)) {\n+\t\t\tlwsl_debug(\u0022handshake_0405: ERROR writing to socket\u005cn\u0022);\n+\t\t\tgoto bail;\n+\t\t}\n+\n+\t}\n+\n+\t/* alright clean up and set ourselves into established state */\n+\n+\twsi-\u003estate \u003d LWSS_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-\u003eprotocol-\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+\n+\n+bail:\n+\t/* caller will free up his parsing allocations */\n+\treturn -1;\n+}\n+\ndiff --git a/lib/server/server.c b/lib/server/server.c\nnew file mode 100644\nindex 0000000..27237a9\n--- /dev/null\n+++ b/lib/server/server.c\n@@ -0,0 +1,3009 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+const char * const method_names[] \u003d {\n+\t\u0022GET\u0022, \u0022POST\u0022, \u0022OPTIONS\u0022, \u0022PUT\u0022, \u0022PATCH\u0022, \u0022DELETE\u0022, \u0022CONNECT\u0022, \u0022HEAD\u0022,\n+#ifdef LWS_WITH_HTTP2\n+\t\u0022:path\u0022,\n+#endif\n+\t};\n+\n+#if defined (LWS_WITH_ESP8266)\n+#undef memcpy\n+void *memcpy(void *dest, const void *src, size_t n)\n+{\n+\treturn ets_memcpy(dest, src, n);\n+}\n+#endif\n+\n+int\n+lws_context_init_server(struct lws_context_creation_info *info,\n+\t\t\tstruct lws_vhost *vhost)\n+{\n+#if LWS_POSIX\n+\tint n, opt \u003d 1, limit \u003d 1;\n+#endif\n+\tlws_sockfd_type sockfd;\n+\tstruct lws_vhost *vh;\n+\tstruct lws *wsi;\n+\tint m \u003d 0;\n+\n+\t(void)method_names;\n+\t(void)opt;\n+\t/* set up our external listening socket we serve on */\n+\n+\tif (info-\u003eport \u003d\u003d CONTEXT_PORT_NO_LISTEN ||\n+\t info-\u003eport \u003d\u003d CONTEXT_PORT_NO_LISTEN_SERVER)\n+\t\treturn 0;\n+\n+\tvh \u003d vhost-\u003econtext-\u003evhost_list;\n+\twhile (vh) {\n+\t\tif (vh-\u003elisten_port \u003d\u003d info-\u003eport) {\n+\t\t\tif ((!info-\u003eiface \u0026\u0026 !vh-\u003eiface) ||\n+\t\t\t (info-\u003eiface \u0026\u0026 vh-\u003eiface \u0026\u0026\n+\t\t\t !strcmp(info-\u003eiface, vh-\u003eiface))) {\n+\t\t\t\tvhost-\u003elisten_port \u003d info-\u003eport;\n+\t\t\t\tvhost-\u003eiface \u003d info-\u003eiface;\n+\t\t\t\tlwsl_notice(\u0022 using listen skt from vhost %s\u005cn\u0022,\n+\t\t\t\t\t vh-\u003ename);\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t}\n+\t\tvh \u003d vh-\u003evhost_next;\n+\t}\n+\n+#if LWS_POSIX\n+\t(void)n;\n+#if defined(__linux__)\n+\tlimit \u003d vhost-\u003econtext-\u003ecount_threads;\n+#endif\n+\n+\tfor (m \u003d 0; m \u003c limit; m++) {\n+#ifdef LWS_WITH_UNIX_SOCK\n+\tif (LWS_UNIX_SOCK_ENABLED(vhost))\n+\t\tsockfd \u003d socket(AF_UNIX, SOCK_STREAM, 0);\n+\telse\n+#endif\n+#ifdef LWS_WITH_IPV6\n+\tif (LWS_IPV6_ENABLED(vhost))\n+\t\tsockfd \u003d socket(AF_INET6, SOCK_STREAM, 0);\n+\telse\n+#endif\n+\t\tsockfd \u003d socket(AF_INET, SOCK_STREAM, 0);\n+\n+\tif (sockfd \u003d\u003d -1) {\n+#else\n+#if defined(LWS_WITH_ESP8266)\n+\tsockfd \u003d esp8266_create_tcp_listen_socket(vhost);\n+\tif (!lws_sockfd_valid(sockfd)) {\n+#endif\n+#endif\n+\t\tlwsl_err(\u0022ERROR opening socket\u005cn\u0022);\n+\t\treturn 1;\n+\t}\n+#if LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n+\n+#if (defined(WIN32) || defined(_WIN32)) \u0026\u0026 defined(SO_EXCLUSIVEADDRUSE)\n+\t/*\n+\t * only accept that we are the only listener on the port\n+\t * https://msdn.microsoft.com/zh-tw/library/\n+\t * windows/desktop/ms740621(v\u003dvs.85).aspx\n+\t *\n+\t * for lws, to match Linux, we default to exclusive listen\n+\t */\n+\tif (!lws_check_opt(vhost-\u003eoptions,\n+\t\t\tLWS_SERVER_OPTION_ALLOW_LISTEN_SHARE)) {\n+\t\tif (setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,\n+\t\t\t (const void *)\u0026opt, sizeof(opt)) \u003c 0) {\n+\t\t\tlwsl_err(\u0022reuseaddr failed\u005cn\u0022);\n+\t\t\tcompatible_close(sockfd);\n+\t\t\treturn 1;\n+\t\t}\n+\t} else\n+#endif\n+\n+\t/*\n+\t * allow us to restart even if old sockets in TIME_WAIT\n+\t */\n+\tif (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,\n+\t\t (const void *)\u0026opt, sizeof(opt)) \u003c 0) {\n+\t\tlwsl_err(\u0022reuseaddr failed\u005cn\u0022);\n+\t\tcompatible_close(sockfd);\n+\t\treturn 1;\n+\t}\n+\n+#if defined(LWS_WITH_IPV6) \u0026\u0026 defined(IPV6_V6ONLY)\n+\tif (LWS_IPV6_ENABLED(vhost)) {\n+\t\tif (vhost-\u003eoptions \u0026 LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) {\n+\t\t\tint value \u003d (vhost-\u003eoptions \u0026\n+\t\t\t\tLWS_SERVER_OPTION_IPV6_V6ONLY_VALUE) ? 1 : 0;\n+\t\t\tif (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,\n+\t\t\t\t (const void*)\u0026value, sizeof(value)) \u003c 0) {\n+\t\t\t\tcompatible_close(sockfd);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t}\n+\t}\n+#endif\n+\n+#if defined(__linux__) \u0026\u0026 defined(SO_REUSEPORT)\n+\tn \u003d lws_check_opt(vhost-\u003eoptions, LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE);\n+#if LWS_MAX_SMP \u003e 1\n+\tn \u003d 1;\n+#endif\n+\n+\tif (n)\n+\t\tif (vhost-\u003econtext-\u003ecount_threads \u003e 1)\n+\t\t\tif (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,\n+\t\t\t\t\t(const void *)\u0026opt, sizeof(opt)) \u003c 0) {\n+\t\t\t\tcompatible_close(sockfd);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+#endif\n+#endif\n+\tlws_plat_set_socket_options(vhost, sockfd);\n+\n+#if LWS_POSIX\n+\tn \u003d lws_socket_bind(vhost, sockfd, info-\u003eport, info-\u003eiface);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\tinfo-\u003eport \u003d n;\n+#endif\n+\tvhost-\u003elisten_port \u003d info-\u003eport;\n+\tvhost-\u003eiface \u003d info-\u003eiface;\n+\n+\twsi \u003d lws_zalloc(sizeof(struct lws), \u0022listen wsi\u0022);\n+\tif (wsi \u003d\u003d NULL) {\n+\t\tlwsl_err(\u0022Out of mem\u005cn\u0022);\n+\t\tgoto bail;\n+\t}\n+\twsi-\u003econtext \u003d vhost-\u003econtext;\n+\twsi-\u003edesc.sockfd \u003d sockfd;\n+\twsi-\u003emode \u003d LWSCM_SERVER_LISTENER;\n+\twsi-\u003eprotocol \u003d vhost-\u003eprotocols;\n+\twsi-\u003etsi \u003d m;\n+\twsi-\u003evhost \u003d vhost;\n+\twsi-\u003elistener \u003d 1;\n+\n+#ifdef LWS_WITH_LIBUV\n+\tif (LWS_LIBUV_ENABLED(vhost-\u003econtext))\n+\t\tlws_uv_initvhost(vhost, wsi);\n+#endif\n+\n+\tif (insert_wsi_socket_into_fds(vhost-\u003econtext, wsi))\n+\t\tgoto bail;\n+\n+\tvhost-\u003econtext-\u003ecount_wsi_allocated++;\n+\tvhost-\u003elserv_wsi \u003d wsi;\n+\n+#if LWS_POSIX\n+\tn \u003d listen(wsi-\u003edesc.sockfd, LWS_SOMAXCONN);\n+\tif (n \u003c 0) {\n+\t\tlwsl_err(\u0022listen failed with error %d\u005cn\u0022, LWS_ERRNO);\n+\t\tvhost-\u003elserv_wsi \u003d NULL;\n+\t\tvhost-\u003econtext-\u003ecount_wsi_allocated--;\n+\t\tremove_wsi_socket_from_fds(wsi);\n+\t\tgoto bail;\n+\t}\n+\t} /* for each thread able to independently listen */\n+#else\n+#if defined(LWS_WITH_ESP8266)\n+\tesp8266_tcp_stream_bind(wsi-\u003edesc.sockfd, info-\u003eport, wsi);\n+#endif\n+#endif\n+\tif (!lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {\n+#ifdef LWS_WITH_UNIX_SOCK\n+\t\tif (LWS_UNIX_SOCK_ENABLED(vhost))\n+\t\t\tlwsl_info(\u0022 Listening on \u005c\u0022%s\u005c\u0022\u005cn\u0022, info-\u003eiface);\n+\t\telse\n+#endif\n+\t\t\tlwsl_info(\u0022 Listening on port %d\u005cn\u0022, info-\u003eport);\n+ }\n+\n+\treturn 0;\n+\n+bail:\n+\tcompatible_close(sockfd);\n+\n+\treturn 1;\n+}\n+\n+#if defined(LWS_WITH_ESP8266)\n+#undef strchr\n+#define strchr ets_strchr\n+#endif\n+\n+struct lws_vhost *\n+lws_select_vhost(struct lws_context *context, int port, const char *servername)\n+{\n+\tstruct lws_vhost *vhost \u003d context-\u003evhost_list;\n+\tconst char *p;\n+\tint n, m, colon;\n+\n+\tn \u003d strlen(servername);\n+\tcolon \u003d n;\n+\tp \u003d strchr(servername, ':');\n+\tif (p)\n+\t\tcolon \u003d p - servername;\n+\n+\t/* Priotity 1: first try exact matches */\n+\n+\twhile (vhost) {\n+\t\tif (port \u003d\u003d vhost-\u003elisten_port \u0026\u0026\n+\t\t !strncmp(vhost-\u003ename, servername, colon)) {\n+\t\t\tlwsl_info(\u0022SNI: Found: %s\u005cn\u0022, servername);\n+\t\t\treturn vhost;\n+\t\t}\n+\t\tvhost \u003d vhost-\u003evhost_next;\n+\t}\n+\n+\t/*\n+\t * Priority 2: if no exact matches, try matching *.vhost-name\n+\t * unintentional matches are possible but resolve to x.com for *.x.com\n+\t * which is reasonable. If exact match exists we already chose it and\n+\t * never reach here. SSL will still fail it if the cert doesn't allow\n+\t * *.x.com.\n+\t */\n+\tvhost \u003d context-\u003evhost_list;\n+\twhile (vhost) {\n+\t\tm \u003d strlen(vhost-\u003ename);\n+\t\tif (port \u003d\u003d vhost-\u003elisten_port \u0026\u0026\n+\t\t m \u003c\u003d (colon - 2) \u0026\u0026\n+\t\t servername[colon - m - 1] \u003d\u003d '.' \u0026\u0026\n+\t\t !strncmp(vhost-\u003ename, servername + colon - m, m)) {\n+\t\t\tlwsl_info(\u0022SNI: Found %s on wildcard: %s\u005cn\u0022,\n+\t\t\t\t servername, vhost-\u003ename);\n+\t\t\treturn vhost;\n+\t\t}\n+\t\tvhost \u003d vhost-\u003evhost_next;\n+\t}\n+\n+\t/* Priority 3: match the first vhost on our port */\n+\n+\tvhost \u003d context-\u003evhost_list;\n+\twhile (vhost) {\n+\t\tif (port \u003d\u003d vhost-\u003elisten_port) {\n+\t\t\tlwsl_info(\u0022vhost match to %s based on port %d\u005cn\u0022,\n+\t\t\t\t\tvhost-\u003ename, port);\n+\t\t\treturn vhost;\n+\t\t}\n+\t\tvhost \u003d vhost-\u003evhost_next;\n+\t}\n+\n+\t/* no match */\n+\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE LWS_EXTERN const char *\n+lws_get_mimetype(const char *file, const struct lws_http_mount *m)\n+{\n+\tint n \u003d strlen(file);\n+\tconst struct lws_protocol_vhost_options *pvo \u003d NULL;\n+\n+\tif (m)\n+\t\tpvo \u003d m-\u003eextra_mimetypes;\n+\n+\tif (n \u003c 5)\n+\t\treturn NULL;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.ico\u0022))\n+\t\treturn \u0022image/x-icon\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.gif\u0022))\n+\t\treturn \u0022image/gif\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 3], \u0022.js\u0022))\n+\t\treturn \u0022text/javascript\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.png\u0022))\n+\t\treturn \u0022image/png\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.jpg\u0022))\n+\t\treturn \u0022image/jpeg\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 3], \u0022.gz\u0022))\n+\t\treturn \u0022application/gzip\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.JPG\u0022))\n+\t\treturn \u0022image/jpeg\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 5], \u0022.html\u0022))\n+\t\treturn \u0022text/html\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.css\u0022))\n+\t\treturn \u0022text/css\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.txt\u0022))\n+\t\treturn \u0022text/plain\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.svg\u0022))\n+\t\treturn \u0022image/svg+xml\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.ttf\u0022))\n+\t\treturn \u0022application/x-font-ttf\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.otf\u0022))\n+\t\treturn \u0022application/font-woff\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 5], \u0022.woff\u0022))\n+\t\treturn \u0022application/font-woff\u0022;\n+\n+\tif (!strcmp(\u0026file[n - 4], \u0022.xml\u0022))\n+\t\treturn \u0022application/xml\u0022;\n+\n+\twhile (pvo) {\n+\t\tif (pvo-\u003ename[0] \u003d\u003d '*') /* ie, match anything */\n+\t\t\treturn pvo-\u003evalue;\n+\n+\t\tif (!strcmp(\u0026file[n - strlen(pvo-\u003ename)], pvo-\u003ename))\n+\t\t\treturn pvo-\u003evalue;\n+\n+\t\tpvo \u003d pvo-\u003enext;\n+\t}\n+\n+\treturn NULL;\n+}\n+static lws_fop_flags_t\n+lws_vfs_prepare_flags(struct lws *wsi)\n+{\n+\tlws_fop_flags_t f \u003d 0;\n+\n+\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))\n+\t\treturn f;\n+\n+\tif (strstr(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING),\n+\t\t \u0022gzip\u0022)) {\n+\t\tlwsl_info(\u0022client indicates GZIP is acceptable\u005cn\u0022);\n+\t\tf |\u003d LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;\n+\t}\n+\n+\treturn f;\n+}\n+\n+static int\n+lws_http_serve(struct lws *wsi, char *uri, const char *origin,\n+\t const struct lws_http_mount *m)\n+{\n+\tconst struct lws_protocol_vhost_options *pvo \u003d m-\u003einterpret;\n+\tstruct lws_process_html_args args;\n+\tconst char *mimetype;\n+#if !defined(_WIN32_WCE) \u0026\u0026 !defined(LWS_WITH_ESP8266)\n+\tconst struct lws_plat_file_ops *fops;\n+\tconst char *vpath;\n+\tlws_fop_flags_t fflags \u003d LWS_O_RDONLY;\n+#if defined(WIN32) \u0026\u0026 defined(LWS_HAVE__STAT32I64)\n+\tstruct _stat32i64 st;\n+#else\n+\tstruct stat st;\n+#endif\n+\tint spin \u003d 0;\n+#endif\n+\tchar path[256], sym[512];\n+\tunsigned char *p \u003d (unsigned char *)sym + 32 + LWS_PRE, *start \u003d p;\n+\tunsigned char *end \u003d p + sizeof(sym) - 32 - LWS_PRE;\n+#if !defined(WIN32) \u0026\u0026 LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n+\tsize_t len;\n+#endif\n+\tint n;\n+\n+\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, origin, uri);\n+\n+#if !defined(_WIN32_WCE) \u0026\u0026 !defined(LWS_WITH_ESP8266)\n+\n+\tfflags |\u003d lws_vfs_prepare_flags(wsi);\n+\n+\tdo {\n+\t\tspin++;\n+\t\tfops \u003d lws_vfs_select_fops(wsi-\u003econtext-\u003efops, path, \u0026vpath);\n+\n+\t\tif (wsi-\u003eu.http.fop_fd)\n+\t\t\tlws_vfs_file_close(\u0026wsi-\u003eu.http.fop_fd);\n+\n+\t\twsi-\u003eu.http.fop_fd \u003d fops-\u003eLWS_FOP_OPEN(wsi-\u003econtext-\u003efops,\n+\t\t\t\t\t\t\tpath, vpath, \u0026fflags);\n+\t\tif (!wsi-\u003eu.http.fop_fd) {\n+\t\t\tlwsl_err(\u0022Unable to open '%s'\u005cn\u0022, path);\n+\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/* if it can't be statted, don't try */\n+\t\tif (fflags \u0026 LWS_FOP_FLAG_VIRTUAL)\n+\t\t\tbreak;\n+#if defined(LWS_WITH_ESP32)\n+\t\tbreak;\n+#endif\n+#if !defined(WIN32)\n+\t\tif (fstat(wsi-\u003eu.http.fop_fd-\u003efd, \u0026st)) {\n+\t\t\tlwsl_info(\u0022unable to stat %s\u005cn\u0022, path);\n+\t\t\tgoto bail;\n+\t\t}\n+#else\n+#if defined(LWS_HAVE__STAT32I64)\n+\t\tif (_stat32i64(path, \u0026st)) {\n+\t\t\tlwsl_info(\u0022unable to stat %s\u005cn\u0022, path);\n+\t\t\tgoto bail;\n+\t\t}\n+#else\n+\t\tif (stat(path, \u0026st)) {\n+\t\t\tlwsl_info(\u0022unable to stat %s\u005cn\u0022, path);\n+\t\t\tgoto bail;\n+\t\t}\n+#endif\n+#endif\n+\n+\t\twsi-\u003eu.http.fop_fd-\u003emod_time \u003d (uint32_t)st.st_mtime;\n+\t\tfflags |\u003d LWS_FOP_FLAG_MOD_TIME_VALID;\n+\n+#if !defined(WIN32) \u0026\u0026 LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n+\t\tif ((S_IFMT \u0026 st.st_mode) \u003d\u003d S_IFLNK) {\n+\t\t\tlen \u003d readlink(path, sym, sizeof(sym) - 1);\n+\t\t\tif (len) {\n+\t\t\t\tlwsl_err(\u0022Failed to read link %s\u005cn\u0022, path);\n+\t\t\t\tgoto bail;\n+\t\t\t}\n+\t\t\tsym[len] \u003d '\u005c0';\n+\t\t\tlwsl_debug(\u0022symlink %s -\u003e %s\u005cn\u0022, path, sym);\n+\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s\u0022, sym);\n+\t\t}\n+#endif\n+\t\tif ((S_IFMT \u0026 st.st_mode) \u003d\u003d S_IFDIR) {\n+\t\t\tlwsl_debug(\u0022default filename append to dir\u005cn\u0022);\n+\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s/index.html\u0022,\n+\t\t\t\t origin, uri);\n+\t\t}\n+\n+\t} while ((S_IFMT \u0026 st.st_mode) !\u003d S_IFREG \u0026\u0026 spin \u003c 5);\n+\n+\tif (spin \u003d\u003d 5)\n+\t\tlwsl_err(\u0022symlink loop %s \u005cn\u0022, path);\n+\n+\tn \u003d sprintf(sym, \u0022%08llX%08lX\u0022,\n+\t\t (unsigned long long)lws_vfs_get_length(wsi-\u003eu.http.fop_fd),\n+\t\t (unsigned long)lws_vfs_get_mod_time(wsi-\u003eu.http.fop_fd));\n+\n+\t/* disable ranges if IF_RANGE token invalid */\n+\n+\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_RANGE))\n+\t\tif (strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_RANGE)))\n+\t\t\t/* differs - defeat Range: */\n+\t\t\twsi-\u003eu.http.ah-\u003efrag_index[WSI_TOKEN_HTTP_RANGE] \u003d 0;\n+\n+\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH)) {\n+\t\t/*\n+\t\t * he thinks he has some version of it already,\n+\t\t * check if the tag matches\n+\t\t */\n+\t\tif (!strcmp(sym, lws_hdr_simple_ptr(wsi,\n+\t\t\t\t\tWSI_TOKEN_HTTP_IF_NONE_MATCH))) {\n+\n+\t\t\tlwsl_debug(\u0022%s: ETAG match %s %s\u005cn\u0022, __func__,\n+\t\t\t\t uri, origin);\n+\n+\t\t\t/* we don't need to send the payload */\n+\t\t\tif (lws_add_http_header_status(wsi,\n+\t\t\t\t\tHTTP_STATUS_NOT_MODIFIED, \u0026p, end))\n+\t\t\t\treturn -1;\n+\n+\t\t\tif (lws_add_http_header_by_token(wsi,\n+\t\t\t\t\tWSI_TOKEN_HTTP_ETAG,\n+\t\t\t\t\t(unsigned char *)sym, n, \u0026p, end))\n+\t\t\t\treturn -1;\n+\n+\t\t\tif (lws_finalize_http_header(wsi, \u0026p, end))\n+\t\t\t\treturn -1;\n+\n+\t\t\tn \u003d lws_write(wsi, start, p - start,\n+\t\t\t\t LWS_WRITE_HTTP_HEADERS |\n+\t\t\t\t LWS_WRITE_H2_STREAM_END);\n+\t\t\tif (n !\u003d (p - start)) {\n+\t\t\t\tlwsl_err(\u0022_write returned %d from %ld\u005cn\u0022, n,\n+\t\t\t\t\t (long)(p - start));\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\n+\t\t\tlws_vfs_file_close(\u0026wsi-\u003eu.http.fop_fd);\n+\n+\t\t\treturn lws_http_transaction_completed(wsi);\n+\t\t}\n+\t}\n+\n+\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,\n+\t\t\t(unsigned char *)sym, n, \u0026p, end))\n+\t\treturn -1;\n+#endif\n+\n+\tmimetype \u003d lws_get_mimetype(path, m);\n+\tif (!mimetype) {\n+\t\tlwsl_err(\u0022unknown mimetype for %s\u005cn\u0022, path);\n+ goto bail;\n+\t}\n+\tif (!mimetype[0])\n+\t\tlwsl_debug(\u0022sending no mimetype for %s\u005cn\u0022, path);\n+\n+\twsi-\u003esending_chunked \u003d 0;\n+\n+\t/*\n+\t * check if this is in the list of file suffixes to be interpreted by\n+\t * a protocol\n+\t */\n+\twhile (pvo) {\n+\t\tn \u003d strlen(path);\n+\t\tif (n \u003e (int)strlen(pvo-\u003ename) \u0026\u0026\n+\t\t !strcmp(\u0026path[n - strlen(pvo-\u003ename)], pvo-\u003ename)) {\n+\t\t\twsi-\u003esending_chunked \u003d 1;\n+\t\t\twsi-\u003eprotocol_interpret_idx \u003d\n+\t\t\t\t\t(char)(lws_intptr_t)pvo-\u003evalue;\n+\t\t\tlwsl_info(\u0022want %s interpreted by %s\u005cn\u0022, path,\n+\t\t\t\t wsi-\u003evhost-\u003eprotocols[\n+\t\t\t\t (int)(lws_intptr_t)(pvo-\u003evalue)].name);\n+\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[\n+\t\t\t (int)(lws_intptr_t)(pvo-\u003evalue)];\n+\t\t\tif (lws_ensure_user_space(wsi))\n+\t\t\t\treturn -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tpvo \u003d pvo-\u003enext;\n+\t}\n+\n+\tif (m-\u003eprotocol) {\n+\t\tconst struct lws_protocols *pp \u003d lws_vhost_name_to_protocol(\n+\t\t\t\t\t\t wsi-\u003evhost, m-\u003eprotocol);\n+\n+\t\tif (lws_bind_protocol(wsi, pp))\n+\t\t\treturn 1;\n+\t\targs.p \u003d (char *)p;\n+\t\targs.max_len \u003d end - p;\n+\t\tif (pp-\u003ecallback(wsi, LWS_CALLBACK_ADD_HEADERS,\n+\t\t\t\t\t wsi-\u003euser_space, \u0026args, 0))\n+\t\t\treturn -1;\n+\t\tp \u003d (unsigned char *)args.p;\n+\t}\n+\n+\tn \u003d lws_serve_http_file(wsi, path, mimetype, (char *)start, p - start);\n+\n+\tif (n \u003c 0 || ((n \u003e 0) \u0026\u0026 lws_http_transaction_completed(wsi)))\n+\t\treturn -1; /* error or can't reuse connection: close the socket */\n+\n+\treturn 0;\n+bail:\n+\n+\treturn -1;\n+}\n+\n+const struct lws_http_mount *\n+lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)\n+{\n+\tconst struct lws_http_mount *hm, *hit \u003d NULL;\n+\tint best \u003d 0;\n+\n+\thm \u003d wsi-\u003evhost-\u003emount_list;\n+\twhile (hm) {\n+\t\tif (uri_len \u003e\u003d hm-\u003emountpoint_len \u0026\u0026\n+\t\t !strncmp(uri_ptr, hm-\u003emountpoint, hm-\u003emountpoint_len) \u0026\u0026\n+\t\t (uri_ptr[hm-\u003emountpoint_len] \u003d\u003d '\u005c0' ||\n+\t\t uri_ptr[hm-\u003emountpoint_len] \u003d\u003d '/' ||\n+\t\t hm-\u003emountpoint_len \u003d\u003d 1)\n+\t\t ) {\n+\t\t\tif (hm-\u003eorigin_protocol \u003d\u003d LWSMPRO_CALLBACK ||\n+\t\t\t ((hm-\u003eorigin_protocol \u003d\u003d LWSMPRO_CGI ||\n+\t\t\t lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||\n+\t\t\t (wsi-\u003ehttp2_substream \u0026\u0026\n+\t\t\t\tlws_hdr_total_length(wsi,\n+\t\t\t\t\t\tWSI_TOKEN_HTTP_COLON_PATH)) ||\n+\t\t\t hm-\u003eprotocol) \u0026\u0026\n+\t\t\t hm-\u003emountpoint_len \u003e best)) {\n+\t\t\t\tbest \u003d hm-\u003emountpoint_len;\n+\t\t\t\thit \u003d hm;\n+\t\t\t}\n+\t\t}\n+\t\thm \u003d hm-\u003emount_next;\n+\t}\n+\n+\treturn hit;\n+}\n+\n+#if LWS_POSIX\n+\n+static int\n+lws_find_string_in_file(const char *filename, const char *string, int stringlen)\n+{\n+\tchar buf[128];\n+\tint fd, match \u003d 0, pos \u003d 0, n \u003d 0, hit \u003d 0;\n+\n+\tfd \u003d open(filename, O_RDONLY);\n+\tif (fd \u003c 0) {\n+\t\tlwsl_err(\u0022can't open auth file: %s\u005cn\u0022, filename);\n+\t\treturn 1;\n+\t}\n+\n+\twhile (1) {\n+\t\tif (pos \u003d\u003d n) {\n+\t\t\tn \u003d read(fd, buf, sizeof(buf));\n+\t\t\tif (n \u003c\u003d 0) {\n+\t\t\t\tif (match \u003d\u003d stringlen)\n+\t\t\t\t\thit \u003d 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tpos \u003d 0;\n+\t\t}\n+\n+\t\tif (match \u003d\u003d stringlen) {\n+\t\t\tif (buf[pos] \u003d\u003d '\u005cr' || buf[pos] \u003d\u003d '\u005cn') {\n+\t\t\t\thit \u003d 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tmatch \u003d 0;\n+\t\t}\n+\n+\t\tif (buf[pos] \u003d\u003d string[match])\n+\t\t\tmatch++;\n+\t\telse\n+\t\t\tmatch \u003d 0;\n+\n+\t\tpos++;\n+\t}\n+\n+\tclose(fd);\n+\n+\treturn hit;\n+}\n+\n+static int\n+lws_unauthorised_basic_auth(struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tunsigned char *start \u003d pt-\u003eserv_buf + LWS_PRE,\n+\t\t *p \u003d start, *end \u003d p + 512;\n+\tchar buf[64];\n+\tint n;\n+\n+\t/* no auth... tell him it is required */\n+\n+\tif (lws_add_http_header_status(wsi, HTTP_STATUS_UNAUTHORIZED, \u0026p, end))\n+\t\treturn -1;\n+\n+\tn \u003d lws_snprintf(buf, sizeof(buf), \u0022Basic realm\u003d\u005c\u0022lwsws\u005c\u0022\u0022);\n+\tif (lws_add_http_header_by_token(wsi,\n+\t\t\tWSI_TOKEN_HTTP_WWW_AUTHENTICATE,\n+\t\t\t(unsigned char *)buf, n, \u0026p, end))\n+\t\treturn -1;\n+\n+\tif (lws_finalize_http_header(wsi, \u0026p, end))\n+\t\treturn -1;\n+\n+\tn \u003d lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS |\n+\t\t\t\t\t LWS_WRITE_H2_STREAM_END);\n+\tif (n \u003c 0)\n+\t\treturn -1;\n+\n+\treturn lws_http_transaction_completed(wsi);\n+\n+}\n+\n+#endif\n+\n+int lws_clean_url(char *p)\n+{\n+\tif (p[0] \u003d\u003d 'h' \u0026\u0026 p[1] \u003d\u003d 't' \u0026\u0026 p[2] \u003d\u003d 't' \u0026\u0026 p[3] \u003d\u003d 'p') {\n+\t\tp +\u003d 4;\n+\t\tif (*p \u003d\u003d 's')\n+\t\tp++;\n+\t\tif (*p \u003d\u003d ':') {\n+\t\t\tp++;\n+\t\t\tif (*p \u003d\u003d '/')\n+\t\t\tp++;\n+\t\t}\n+\t}\n+\n+\twhile (*p) {\n+\t\tif (p[0] \u003d\u003d '/' \u0026\u0026 p[1] \u003d\u003d '/') {\n+\t\t\tchar *p1 \u003d p;\n+\t\t\twhile (*p1) {\n+\t\t\t\t*p1 \u003d p1[1];\n+\t\t\t\tp1++;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\t\tp++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+static const unsigned char methods[] \u003d {\n+\tWSI_TOKEN_GET_URI,\n+\tWSI_TOKEN_POST_URI,\n+\tWSI_TOKEN_OPTIONS_URI,\n+\tWSI_TOKEN_PUT_URI,\n+\tWSI_TOKEN_PATCH_URI,\n+\tWSI_TOKEN_DELETE_URI,\n+\tWSI_TOKEN_CONNECT,\n+\tWSI_TOKEN_HEAD_URI,\n+#ifdef LWS_WITH_HTTP2\n+\tWSI_TOKEN_HTTP_COLON_PATH,\n+#endif\n+};\n+\n+static int\n+lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)\n+{\n+\tint n, count \u003d 0;\n+\n+\tfor (n \u003d 0; n \u003c ARRAY_SIZE(methods); n++)\n+\t\tif (lws_hdr_total_length(wsi, methods[n]))\n+\t\t\tcount++;\n+\tif (!count) {\n+\t\tlwsl_warn(\u0022Missing URI in HTTP request\u005cn\u0022);\n+\t\treturn -1;\n+\t}\n+\n+\tif (count !\u003d 1 \u0026\u0026\n+\t !(wsi-\u003ehttp2_substream \u0026\u0026\n+\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH))) {\n+\t\tlwsl_warn(\u0022multiple methods?\u005cn\u0022);\n+\t\treturn -1;\n+\t}\n+\n+\tfor (n \u003d 0; n \u003c ARRAY_SIZE(methods); n++)\n+\t\tif (lws_hdr_total_length(wsi, methods[n])) {\n+\t\t\t*puri_ptr \u003d lws_hdr_simple_ptr(wsi, methods[n]);\n+\t\t\t*puri_len \u003d lws_hdr_total_length(wsi, methods[n]);\n+\t\t\treturn n;\n+\t\t}\n+\n+\treturn -1;\n+}\n+\n+int\n+lws_http_action(struct lws *wsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\tenum http_connection_type connection_type;\n+\tenum http_version request_version;\n+\tchar content_length_str[32];\n+\tstruct lws_process_html_args args;\n+\tconst struct lws_http_mount *hit \u003d NULL;\n+\tunsigned int n;\n+\tchar http_version_str[10];\n+\tchar http_conn_str[20];\n+\tint http_version_len;\n+\tchar *uri_ptr \u003d NULL, *s;\n+\tint uri_len \u003d 0, meth;\n+\tstatic const char * const oprot[] \u003d {\n+\t\t\u0022http://\u0022, \u0022https://\u0022\n+\t};\n+\n+\tmeth \u003d lws_http_get_uri_and_method(wsi, \u0026uri_ptr, \u0026uri_len);\n+\tif (meth \u003c 0 || meth \u003e\u003d ARRAY_SIZE(method_names))\n+\t\tgoto bail_nuke_ah;\n+\n+\t/* we insist on absolute paths */\n+\n+\tif (!uri_ptr || uri_ptr[0] !\u003d '/') {\n+\t\tlws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);\n+\n+\t\tgoto bail_nuke_ah;\n+\t}\n+\n+\tlwsl_info(\u0022Method: '%s' (%d), request for '%s'\u005cn\u0022, method_names[meth],\n+\t\t meth, uri_ptr);\n+\n+\tif (lws_ensure_user_space(wsi))\n+\t\tgoto bail_nuke_ah;\n+\n+\t/* HTTP header had a content length? */\n+\n+\twsi-\u003eu.http.rx_content_length \u003d 0;\n+\tif (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||\n+\t\tlws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||\n+\t\tlws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))\n+\t\twsi-\u003eu.http.rx_content_length \u003d 100 * 1024 * 1024;\n+\n+\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n+\t\tlws_hdr_copy(wsi, content_length_str,\n+\t\t\t sizeof(content_length_str) - 1,\n+\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH);\n+\t\twsi-\u003eu.http.rx_content_length \u003d atoll(content_length_str);\n+\t}\n+\n+\tif (wsi-\u003ehttp2_substream) {\n+\t\twsi-\u003eu.http.request_version \u003d HTTP_VERSION_2;\n+\t} else {\n+\t\t/* http_version? Default to 1.0, override with token: */\n+\t\trequest_version \u003d HTTP_VERSION_1_0;\n+\n+\t\t/* Works for single digit HTTP versions. : */\n+\t\thttp_version_len \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP);\n+\t\tif (http_version_len \u003e 7) {\n+\t\t\tlws_hdr_copy(wsi, http_version_str,\n+\t\t\t\t sizeof(http_version_str) - 1,\n+\t\t\t\t WSI_TOKEN_HTTP);\n+\t\t\tif (http_version_str[5] \u003d\u003d '1' \u0026\u0026\n+\t\t\t http_version_str[7] \u003d\u003d '1')\n+\t\t\t\trequest_version \u003d HTTP_VERSION_1_1;\n+\t\t}\n+\t\twsi-\u003eu.http.request_version \u003d request_version;\n+\n+\t\t/* HTTP/1.1 defaults to \u0022keep-alive\u0022, 1.0 to \u0022close\u0022 */\n+\t\tif (request_version \u003d\u003d HTTP_VERSION_1_1)\n+\t\t\tconnection_type \u003d HTTP_CONNECTION_KEEP_ALIVE;\n+\t\telse\n+\t\t\tconnection_type \u003d HTTP_CONNECTION_CLOSE;\n+\n+\t\t/* Override default if http \u0022Connection:\u0022 header: */\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {\n+\t\t\tlws_hdr_copy(wsi, http_conn_str,\n+\t\t\t\t sizeof(http_conn_str) - 1,\n+\t\t\t\t WSI_TOKEN_CONNECTION);\n+\t\t\thttp_conn_str[sizeof(http_conn_str) - 1] \u003d '\u005c0';\n+\t\t\tif (!strcasecmp(http_conn_str, \u0022keep-alive\u0022))\n+\t\t\t\tconnection_type \u003d HTTP_CONNECTION_KEEP_ALIVE;\n+\t\t\telse\n+\t\t\t\tif (!strcasecmp(http_conn_str, \u0022close\u0022))\n+\t\t\t\t\tconnection_type \u003d HTTP_CONNECTION_CLOSE;\n+\t\t}\n+\t\twsi-\u003eu.http.connection_type \u003d connection_type;\n+\t}\n+\n+\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,\n+\t\t\t\t wsi-\u003euser_space, uri_ptr, uri_len);\n+\tif (n) {\n+\t\tlwsl_info(\u0022LWS_CALLBACK_HTTP closing\u005cn\u0022);\n+\n+\t\treturn 1;\n+\t}\n+\t/*\n+\t * if there is content supposed to be coming,\n+\t * put a timeout on it having arrived\n+\t */\n+\tlws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,\n+\t\t\twsi-\u003econtext-\u003etimeout_secs);\n+#ifdef LWS_OPENSSL_SUPPORT\n+\tif (wsi-\u003eredirect_to_https) {\n+\t\t/*\n+\t\t * we accepted http:// only so we could redirect to\n+\t\t * https://, so issue the redirect. Create the redirection\n+\t\t * URI from the host: header and ignore the path part\n+\t\t */\n+\t\tunsigned char *start \u003d pt-\u003eserv_buf + LWS_PRE, *p \u003d start,\n+\t\t\t *end \u003d p + 512;\n+\n+\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))\n+\t\t\tgoto bail_nuke_ah;\n+\n+\t\tn \u003d sprintf((char *)end, \u0022https://%s/\u0022,\n+\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));\n+\n+\t\tn \u003d lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,\n+\t\t\t\t end, n, \u0026p, end);\n+\t\tif ((int)n \u003c 0)\n+\t\t\tgoto bail_nuke_ah;\n+\n+\t\treturn lws_http_transaction_completed(wsi);\n+\t}\n+#endif\n+\n+#ifdef LWS_WITH_ACCESS_LOG\n+\tlws_prepare_access_log_info(wsi, uri_ptr, meth);\n+#endif\n+\n+\t/* can we serve it from the mount list? */\n+\n+\thit \u003d lws_find_mount(wsi, uri_ptr, uri_len);\n+\tif (!hit) {\n+\t\t/* deferred cleanup and reset to protocols[0] */\n+\n+\t\tlwsl_info(\u0022no hit\u005cn\u0022);\n+\n+\t\tif (lws_bind_protocol(wsi, \u0026wsi-\u003evhost-\u003eprotocols[0]))\n+\t\t\treturn 1;\n+\n+\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n+\t\t\t\t wsi-\u003euser_space, uri_ptr, uri_len);\n+\n+\t\tgoto after;\n+\t}\n+\n+\ts \u003d uri_ptr + hit-\u003emountpoint_len;\n+\n+\t/*\n+\t * if we have a mountpoint like https://xxx.com/yyy\n+\t * there is an implied / at the end for our purposes since\n+\t * we can only mount on a \u0022directory\u0022.\n+\t *\n+\t * But if we just go with that, the browser cannot understand\n+\t * that he is actually looking down one \u0022directory level\u0022, so\n+\t * even though we give him /yyy/abc.html he acts like the\n+\t * current directory level is /. So relative urls like \u0022x.png\u0022\n+\t * wrongly look outside the mountpoint.\n+\t *\n+\t * Therefore if we didn't come in on a url with an explicit\n+\t * / at the end, we must redirect to add it so the browser\n+\t * understands he is one \u0022directory level\u0022 down.\n+\t */\n+\tif ((hit-\u003emountpoint_len \u003e 1 ||\n+\t (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTP ||\n+\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTPS)) \u0026\u0026\n+\t (*s !\u003d '/' ||\n+\t (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTP ||\n+\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTPS)) \u0026\u0026\n+\t (hit-\u003eorigin_protocol !\u003d LWSMPRO_CGI \u0026\u0026\n+\t hit-\u003eorigin_protocol !\u003d LWSMPRO_CALLBACK)) {\n+\t\tunsigned char *start \u003d pt-\u003eserv_buf + LWS_PRE,\n+\t\t\t *p \u003d start, *end \u003d p + 512;\n+\n+\t\tlwsl_debug(\u0022Doing 301 '%s' org %s\u005cn\u0022, s, hit-\u003eorigin);\n+\n+\t\t/* \u003e at start indicates deal with by redirect */\n+\t\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTP ||\n+\t\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTPS)\n+\t\t\tn \u003d lws_snprintf((char *)end, 256, \u0022%s%s\u0022,\n+\t\t\t\t oprot[hit-\u003eorigin_protocol \u0026 1],\n+\t\t\t\t hit-\u003eorigin);\n+\t\telse {\n+\t\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {\n+\t\t\t\tif (!lws_hdr_total_length(wsi,\n+\t\t\t\t\t\tWSI_TOKEN_HTTP_COLON_AUTHORITY))\n+\t\t\t\t\tgoto bail_nuke_ah;\n+\t\t\t\tn \u003d lws_snprintf((char *)end, 256,\n+\t\t\t\t \u0022%s%s%s/\u0022, oprot[!!lws_is_ssl(wsi)],\n+\t\t\t\t lws_hdr_simple_ptr(wsi,\n+\t\t\t\t\t\tWSI_TOKEN_HTTP_COLON_AUTHORITY),\n+\t\t\t\t uri_ptr);\n+\t\t\t} else\n+\t\t\t\tn \u003d lws_snprintf((char *)end, 256,\n+\t\t\t\t \u0022%s%s%s/\u0022, oprot[!!lws_is_ssl(wsi)],\n+\t\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),\n+\t\t\t\t uri_ptr);\n+\t\t}\n+\n+\t\tlws_clean_url((char *)end);\n+\t\tn \u003d lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,\n+\t\t\t\t end, n, \u0026p, end);\n+\t\tif ((int)n \u003c 0)\n+\t\t\tgoto bail_nuke_ah;\n+\n+\t\treturn lws_http_transaction_completed(wsi);\n+\t}\n+\n+#if LWS_POSIX\n+\t/* basic auth? */\n+\n+\tif (hit-\u003ebasic_auth_login_file) {\n+\t\tchar b64[160], plain[(sizeof(b64) * 3) / 4];\n+\t\tint m;\n+\n+\t\t/* Did he send auth? */\n+\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION))\n+\t\t\treturn lws_unauthorised_basic_auth(wsi);\n+\n+\t\tn \u003d HTTP_STATUS_FORBIDDEN;\n+\n+\t\tm \u003d lws_hdr_copy(wsi, b64, sizeof(b64),\n+\t\t\t\t WSI_TOKEN_HTTP_AUTHORIZATION);\n+\t\tif (m \u003c 7) {\n+\t\t\tlwsl_err(\u0022b64 auth too long\u005cn\u0022);\n+\t\t\tgoto transaction_result_n;\n+\t\t}\n+\n+\t\tb64[5] \u003d '\u005c0';\n+\t\tif (strcasecmp(b64, \u0022Basic\u0022)) {\n+\t\t\tlwsl_err(\u0022auth missing basic: %s\u005cn\u0022, b64);\n+\t\t\tgoto transaction_result_n;\n+\t\t}\n+\n+\t\t/* It'll be like Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l */\n+\n+\t\tm \u003d lws_b64_decode_string(b64 + 6, plain, sizeof(plain));\n+\t\tif (m \u003c 0) {\n+\t\t\tlwsl_err(\u0022plain auth too long\u005cn\u0022);\n+\t\t\tgoto transaction_result_n;\n+\t\t}\n+\n+\t\tif (!lws_find_string_in_file(hit-\u003ebasic_auth_login_file,\n+\t\t\t\t\t plain, m)) {\n+\t\t\tlwsl_err(\u0022basic auth lookup failed\u005cn\u0022);\n+\t\t\treturn lws_unauthorised_basic_auth(wsi);\n+\t\t}\n+\n+\t\tlwsl_notice(\u0022basic auth accepted\u005cn\u0022);\n+\n+\t\t/* accept the auth */\n+\t}\n+#endif\n+\n+#if defined(LWS_WITH_HTTP_PROXY)\n+\t/*\n+\t * The mount is a reverse proxy?\n+\t */\n+\n+\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTPS ||\n+\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTP) {\n+\t\tstruct lws_client_connect_info i;\n+\t\tchar ads[96], rpath[256], *pcolon, *pslash, *p;\n+\t\tint n, na;\n+\n+\t\tmemset(\u0026i, 0, sizeof(i));\n+\t\ti.context \u003d lws_get_context(wsi);\n+\n+\t\tpcolon \u003d strchr(hit-\u003eorigin, ':');\n+\t\tpslash \u003d strchr(hit-\u003eorigin, '/');\n+\t\tif (!pslash) {\n+\t\t\tlwsl_err(\u0022Proxy mount origin '%s' must have /\u005cn\u0022,\n+\t\t\t\t hit-\u003eorigin);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (pcolon \u003e pslash)\n+\t\t\tpcolon \u003d NULL;\n+\t\t\n+\t\tif (pcolon)\n+\t\t\tn \u003d pcolon - hit-\u003eorigin;\n+\t\telse\n+\t\t\tn \u003d pslash - hit-\u003eorigin;\n+\n+\t\tif (n \u003e\u003d sizeof(ads) - 2)\n+\t\t\tn \u003d sizeof(ads) - 2;\n+\n+\t\tmemcpy(ads, hit-\u003eorigin, n);\n+\t\tads[n] \u003d '\u005c0';\n+\n+\t\ti.address \u003d ads;\n+\t\ti.port \u003d 80;\n+\t\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTPS) { \n+\t\t\ti.port \u003d 443;\n+\t\t\ti.ssl_connection \u003d 1;\n+\t\t}\n+\t\tif (pcolon)\n+\t\t\ti.port \u003d atoi(pcolon + 1);\n+\t\t\n+\t\tlws_snprintf(rpath, sizeof(rpath) - 1, \u0022/%s/%s\u0022, pslash + 1,\n+\t\t\t uri_ptr + hit-\u003emountpoint_len);\n+\t\tlws_clean_url(rpath);\n+\t\tna \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_URI_ARGS);\n+\t\tif (na) {\n+\t\t\tp \u003d rpath + strlen(rpath);\n+\t\t\t*p++ \u003d '?';\n+\t\t\tlws_hdr_copy(wsi, p, \u0026rpath[sizeof(rpath) - 1] - p,\n+\t\t\t\t WSI_TOKEN_HTTP_URI_ARGS);\n+\t\t\twhile (--na) {\n+\t\t\t\tif (*p \u003d\u003d '\u005c0')\n+\t\t\t\t\t*p \u003d '\u0026';\n+\t\t\t\tp++;\n+\t\t\t}\n+\t\t}\n+\t\t\t\t\n+\n+\t\ti.path \u003d rpath;\n+\t\ti.host \u003d i.address;\n+\t\ti.origin \u003d NULL;\n+\t\ti.method \u003d \u0022GET\u0022;\n+\t\ti.parent_wsi \u003d wsi;\n+\t\ti.uri_replace_from \u003d hit-\u003eorigin;\n+\t\ti.uri_replace_to \u003d hit-\u003emountpoint;\n+\n+\t\tlwsl_notice(\u0022proxying to %s port %d url %s, ssl %d, from %s, to %s\u005cn\u0022,\n+\t\t\t\ti.address, i.port, i.path, i.ssl_connection,\n+\t\t\t\ti.uri_replace_from, i.uri_replace_to);\n+\t\n+\t\tif (!lws_client_connect_via_info(\u0026i)) {\n+\t\t\tlwsl_err(\u0022proxy connect fail\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\treturn 0;\n+\t}\n+#endif\n+\n+\t/*\n+\t * A particular protocol callback is mounted here?\n+\t *\n+\t * For the duration of this http transaction, bind us to the\n+\t * associated protocol\n+\t */\n+\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_CALLBACK || hit-\u003eprotocol) {\n+\t\tconst struct lws_protocols *pp;\n+\t\tconst char *name \u003d hit-\u003eorigin;\n+\t\tif (hit-\u003eprotocol)\n+\t\t\tname \u003d hit-\u003eprotocol;\n+\n+\t\tpp \u003d lws_vhost_name_to_protocol(wsi-\u003evhost, name);\n+\t\tif (!pp) {\n+\t\t\tn \u003d -1;\n+\t\t\tlwsl_err(\u0022Unable to find plugin '%s'\u005cn\u0022,\n+\t\t\t\t hit-\u003eorigin);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tif (lws_bind_protocol(wsi, pp))\n+\t\t\treturn 1;\n+\n+\t\targs.p \u003d uri_ptr;\n+\t\targs.len \u003d uri_len;\n+\t\targs.max_len \u003d hit-\u003eauth_mask;\n+\t\targs.final \u003d 0; /* used to signal callback dealt with it */\n+\n+\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_CHECK_ACCESS_RIGHTS,\n+\t\t\t\t\t wsi-\u003euser_space, \u0026args, 0);\n+\t\tif (n) {\n+\t\t\tlws_return_http_status(wsi, HTTP_STATUS_UNAUTHORIZED,\n+\t\t\t\t\t NULL);\n+\t\t\tgoto bail_nuke_ah;\n+\t\t}\n+\t\tif (args.final) /* callback completely handled it well */\n+\t\t\treturn 0;\n+\n+\t\tif (hit-\u003ecgienv \u0026\u0026 wsi-\u003eprotocol-\u003ecallback(wsi,\n+\t\t\t\tLWS_CALLBACK_HTTP_PMO,\n+\t\t\t\twsi-\u003euser_space, (void *)hit-\u003ecgienv, 0))\n+\t\t\treturn 1;\n+\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {\n+\t\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n+\t\t\t\t\t wsi-\u003euser_space,\n+\t\t\t\t\t uri_ptr + hit-\u003emountpoint_len,\n+\t\t\t\t\t uri_len - hit-\u003emountpoint_len);\n+\t\t\tgoto after;\n+\t\t}\n+\t}\n+\n+#ifdef LWS_WITH_CGI\n+\t/* did we hit something with a cgi:// origin? */\n+\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_CGI) {\n+\t\tconst char *cmd[] \u003d {\n+\t\t\tNULL, /* replace with cgi path */\n+\t\t\tNULL\n+\t\t};\n+\n+\t\tlwsl_debug(\u0022%s: cgi\u005cn\u0022, __func__);\n+\t\tcmd[0] \u003d hit-\u003eorigin;\n+\n+\t\tn \u003d 5;\n+\t\tif (hit-\u003ecgi_timeout)\n+\t\t\tn \u003d hit-\u003ecgi_timeout;\n+\n+\t\tn \u003d lws_cgi(wsi, cmd, hit-\u003emountpoint_len, n,\n+\t\t\t hit-\u003ecgienv);\n+\t\tif (n) {\n+\t\t\tlwsl_err(\u0022%s: cgi failed\u005cn\u0022, __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tgoto deal_body;\n+\t}\n+#endif\n+\n+\tn \u003d strlen(s);\n+\tif (s[0] \u003d\u003d '\u005c0' || (n \u003d\u003d 1 \u0026\u0026 s[n - 1] \u003d\u003d '/'))\n+\t\ts \u003d (char *)hit-\u003edef;\n+\tif (!s)\n+\t\ts \u003d \u0022index.html\u0022;\n+\n+\twsi-\u003ecache_secs \u003d hit-\u003ecache_max_age;\n+\twsi-\u003ecache_reuse \u003d hit-\u003ecache_reusable;\n+\twsi-\u003ecache_revalidate \u003d hit-\u003ecache_revalidate;\n+\twsi-\u003ecache_intermediaries \u003d hit-\u003ecache_intermediaries;\n+\n+\tn \u003d lws_http_serve(wsi, s, hit-\u003eorigin, hit);\n+\tif (n) {\n+\t\t/*\n+\t\t * \tlws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);\n+\t\t */\n+\t\tif (hit-\u003eprotocol) {\n+\t\t\tconst struct lws_protocols *pp \u003d lws_vhost_name_to_protocol(\n+\t\t\t\t\twsi-\u003evhost, hit-\u003eprotocol);\n+\n+\t\t\tif (lws_bind_protocol(wsi, pp))\n+\t\t\t\treturn 1;\n+\n+\t\t\tn \u003d pp-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n+\t\t\t\t\t wsi-\u003euser_space,\n+\t\t\t\t\t uri_ptr + hit-\u003emountpoint_len,\n+\t\t\t\t\t uri_len - hit-\u003emountpoint_len);\n+\t\t} else\n+\t\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n+\t\t\t\t wsi-\u003euser_space, uri_ptr, uri_len);\n+\t}\n+\n+after:\n+\tif (n) {\n+\t\tlwsl_info(\u0022LWS_CALLBACK_HTTP closing\u005cn\u0022);\n+\n+\t\treturn 1;\n+\t}\n+\n+#ifdef LWS_WITH_CGI\n+deal_body:\n+#endif\n+\t/*\n+\t * If we're not issuing a file, check for content_length or\n+\t * HTTP keep-alive. No keep-alive header allocation for\n+\t * ISSUING_FILE, as this uses HTTP/1.0.\n+\t *\n+\t * In any case, return 0 and let lws_read decide how to\n+\t * proceed based on state\n+\t */\n+\tif (wsi-\u003estate !\u003d LWSS_HTTP_ISSUING_FILE) {\n+\t\t/* Prepare to read body if we have a content length: */\n+\t\tlwsl_debug(\u0022wsi-\u003eu.http.rx_content_length %lld %d %d\u005cn\u0022,\n+\t\t\t (long long)wsi-\u003eu.http.rx_content_length,\n+\t\t\t wsi-\u003eupgraded_to_http2, wsi-\u003ehttp2_substream);\n+\t\tif (wsi-\u003eu.http.rx_content_length \u003e 0) {\n+\t\t\tlwsl_notice(\u0022%s: %p: LWSS_HTTP_BODY state set\u005cn\u0022,\n+\t\t\t\t __func__, wsi);\n+\t\t\twsi-\u003estate \u003d LWSS_HTTP_BODY;\n+\t\t\twsi-\u003eu.http.rx_content_remain \u003d\n+\t\t\t\t\twsi-\u003eu.http.rx_content_length;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+\n+bail_nuke_ah:\n+\t/* we're closing, losing some rx is OK */\n+\tlws_header_table_force_to_detachable_state(wsi);\n+\tlws_header_table_detach(wsi, 1);\n+\n+\treturn 1;\n+\n+#if LWS_POSIX\n+transaction_result_n:\n+\tlws_return_http_status(wsi, n, NULL);\n+\n+\treturn lws_http_transaction_completed(wsi);\n+#endif\n+}\n+\n+static int\n+lws_server_init_wsi_for_ws(struct lws *wsi)\n+{\n+\tint n;\n+\n+\twsi-\u003estate \u003d LWSS_ESTABLISHED;\n+\tlws_restart_ws_ping_pong_timer(wsi);\n+\n+\t/*\n+\t * create the frame buffer for this connection according to the\n+\t * size mentioned in the protocol definition. If 0 there, use\n+\t * a big default for compatibility\n+\t */\n+\n+\tn \u003d wsi-\u003eprotocol-\u003erx_buffer_size;\n+\tif (!n)\n+\t\tn \u003d wsi-\u003econtext-\u003ept_serv_buf_size;\n+\tn +\u003d LWS_PRE;\n+\twsi-\u003eu.ws.rx_ubuf \u003d lws_malloc(n + 4 /* 0x0000ffff zlib */, \u0022rx_ubuf\u0022);\n+\tif (!wsi-\u003eu.ws.rx_ubuf) {\n+\t\tlwsl_err(\u0022Out of Mem allocating rx buffer %d\u005cn\u0022, n);\n+\t\treturn 1;\n+\t}\n+\twsi-\u003eu.ws.rx_ubuf_alloc \u003d n;\n+\tlwsl_debug(\u0022Allocating RX buffer %d\u005cn\u0022, n);\n+\n+#if LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n+\tif (!wsi-\u003eparent_carries_io)\n+\t\tif (setsockopt(wsi-\u003edesc.sockfd, SOL_SOCKET, SO_SNDBUF,\n+\t\t (const char *)\u0026n, sizeof n)) {\n+\t\t\tlwsl_warn(\u0022Failed to set SNDBUF to %d\u0022, n);\n+\t\t\treturn 1;\n+\t\t}\n+#endif\n+\n+\t/* notify user code that we're ready to roll */\n+\n+\tif (wsi-\u003eprotocol-\u003ecallback)\n+\t\tif (wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_ESTABLISHED,\n+\t\t\t\t\t wsi-\u003euser_space,\n+#ifdef LWS_OPENSSL_SUPPORT\n+\t\t\t\t\t wsi-\u003essl,\n+#else\n+\t\t\t\t\t NULL,\n+#endif\n+\t\t\t\t\t 0))\n+\t\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)\n+{\n+\tint protocol_len, n \u003d 0, hit, non_space_char_found \u003d 0, m;\n+\tstruct lws_context *context \u003d lws_get_context(wsi);\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tstruct _lws_header_related hdr;\n+\tstruct allocated_headers *ah;\n+\tunsigned char *obuf \u003d *buf;\n+\tchar protocol_list[128];\n+\tchar protocol_name[64];\n+\tsize_t olen \u003d len;\n+\tchar *p;\n+\n+\tif (len \u003e\u003d 10000000) {\n+\t\tlwsl_err(\u0022%s: assert: len %ld\u005cn\u0022, __func__, (long)len);\n+\t\tassert(0);\n+\t}\n+\n+\tif (!wsi-\u003eu.hdr.ah) {\n+\t\tlwsl_err(\u0022%s: assert: NULL ah\u005cn\u0022, __func__);\n+\t\tassert(0);\n+\t}\n+\n+\tlwsl_hexdump(*buf, len);\n+\n+\twhile (len--) {\n+\t\twsi-\u003emore_rx_waiting \u003d !!len;\n+\n+\t\tif (wsi-\u003emode !\u003d LWSCM_HTTP_SERVING \u0026\u0026\n+\t\t wsi-\u003emode !\u003d LWSCM_HTTP2_SERVING \u0026\u0026\n+\t\t wsi-\u003emode !\u003d LWSCM_HTTP_SERVING_ACCEPTED) {\n+\t\t\tlwsl_err(\u0022%s: bad wsi mode %d\u005cn\u0022, __func__, wsi-\u003emode);\n+\t\t\tgoto bail_nuke_ah;\n+\t\t}\n+\n+\t\tm \u003d lws_parse(wsi, *(*buf)++);\n+\t\tif (m) {\n+\t\t\tif (m \u003d\u003d 2) {\n+\t\t\t\t/*\n+\t\t\t\t * we are transitioning from http with\n+\t\t\t\t * an AH, to raw. Drop the ah and set\n+\t\t\t\t * the mode.\n+\t\t\t\t */\n+raw_transition:\n+\t\t\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\t\t\t\tlws_bind_protocol(wsi, \u0026wsi-\u003evhost-\u003eprotocols[\n+\t\t\t\t wsi-\u003evhost-\u003e\n+\t\t\t\t raw_protocol_index]);\n+\t\t\t\tlwsl_info(\u0022transition to raw vh %s prot %d\u005cn\u0022,\n+\t\t\t\t\t wsi-\u003evhost-\u003ename,\n+\t\t\t\t\t wsi-\u003evhost-\u003eraw_protocol_index);\n+\t\t\t\tif ((wsi-\u003eprotocol-\u003ecallback)(wsi,\n+\t\t\t\t\t\tLWS_CALLBACK_RAW_ADOPT,\n+\t\t\t\t\t\twsi-\u003euser_space, NULL, 0))\n+\t\t\t\t\tgoto bail_nuke_ah;\n+\n+\t\t\t\tlws_header_table_force_to_detachable_state(wsi);\n+\t\t\t\tlws_union_transition(wsi, LWSCM_RAW);\n+\t\t\t\tlws_header_table_detach(wsi, 1);\n+\n+\t\t\t\tif (m \u003d\u003d 2 \u0026\u0026 (wsi-\u003eprotocol-\u003ecallback)(wsi,\n+\t\t\t\t\t\tLWS_CALLBACK_RAW_RX,\n+\t\t\t\t\t\twsi-\u003euser_space, obuf, olen))\n+\t\t\t\t\treturn 1;\n+\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t\tlwsl_info(\u0022lws_parse failed\u005cn\u0022);\n+\t\t\tgoto bail_nuke_ah;\n+\t\t}\n+\n+\t\tif (wsi-\u003eu.hdr.parser_state !\u003d WSI_PARSING_COMPLETE)\n+\t\t\tcontinue;\n+\n+\t\tlwsl_parser(\u0022%s: lws_parse sees parsing complete\u005cn\u0022, __func__);\n+\t\tlwsl_debug(\u0022%s: wsi-\u003emore_rx_waiting\u003d%d\u005cn\u0022, __func__,\n+\t\t\t\twsi-\u003emore_rx_waiting);\n+\n+\t\t/* select vhost */\n+\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {\n+\t\t\tstruct lws_vhost *vhost \u003d lws_select_vhost(\n+\t\t\t\tcontext, wsi-\u003evhost-\u003elisten_port,\n+\t\t\t\tlws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));\n+\n+\t\t\tif (vhost)\n+\t\t\t\twsi-\u003evhost \u003d vhost;\n+\t\t} else\n+\t\t\tlwsl_info(\u0022no host\u005cn\u0022);\n+\n+\t\tif (wsi-\u003emode !\u003d LWSCM_HTTP2_SERVING) {\n+\t\t\twsi-\u003evhost-\u003econn_stats.h1_trans++;\n+\t\t\tif (!wsi-\u003econn_stat_done) {\n+\t\t\t\twsi-\u003evhost-\u003econn_stats.h1_conn++;\n+\t\t\t\twsi-\u003econn_stat_done \u003d 1;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* check for unwelcome guests */\n+\n+\t\tif (wsi-\u003econtext-\u003ereject_service_keywords) {\n+\t\t\tconst struct lws_protocol_vhost_options *rej \u003d\n+\t\t\t\t\twsi-\u003econtext-\u003ereject_service_keywords;\n+\t\t\tchar ua[384], *msg \u003d NULL;\n+\n+\t\t\tif (lws_hdr_copy(wsi, ua, sizeof(ua) - 1,\n+\t\t\t\t\t WSI_TOKEN_HTTP_USER_AGENT) \u003e 0) {\n+\t\t\t\tua[sizeof(ua) - 1] \u003d '\u005c0';\n+\t\t\t\twhile (rej) {\n+\t\t\t\t\tif (strstr(ua, rej-\u003ename)) {\n+#ifdef LWS_WITH_ACCESS_LOG\n+\t\t\t\t\t\tchar *uri_ptr \u003d NULL;\n+\t\t\t\t\t\tint meth, uri_len;\n+#endif\n+\n+\t\t\t\t\t\tmsg \u003d strchr(rej-\u003evalue, ' ');\n+\t\t\t\t\t\tif (msg)\n+\t\t\t\t\t\t\tmsg++;\n+\t\t\t\t\t\tlws_return_http_status(wsi,\n+\t\t\t\t\t\t\tatoi(rej-\u003evalue), msg);\n+#ifdef LWS_WITH_ACCESS_LOG\n+\t\t\t\t\t\tmeth \u003d lws_http_get_uri_and_method(wsi,\n+\t\t\t\t\t\t\t\t\u0026uri_ptr, \u0026uri_len);\n+\t\t\t\t\t\tif (meth \u003e\u003d 0)\n+\t\t\t\t\t\t\tlws_prepare_access_log_info(wsi,\n+\t\t\t\t\t\t\t\turi_ptr, meth);\n+\n+\t\t\t\t\t\t/* wsi close will do the log */\n+#endif\n+\t\t\t\t\t\twsi-\u003evhost-\u003econn_stats.rejected++;\n+\t\t\t\t\t\t/*\n+\t\t\t\t\t\t * We don't want anything from\n+\t\t\t\t\t\t * this rejected guy. Follow\n+\t\t\t\t\t\t * the close flow, not the\n+\t\t\t\t\t\t * transaction complete flow.\n+\t\t\t\t\t\t */\n+\t\t\t\t\t\tgoto bail_nuke_ah;\n+\t\t\t\t\t}\n+\t\t\t\t\trej \u003d rej-\u003enext;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\n+\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) {\n+\t\t\tlwsl_info(\u0022Changing to RAW mode\u005cn\u0022);\n+\t\t\tm \u003d 0;\n+\t\t\tgoto raw_transition;\n+\t\t}\n+\n+\t\twsi-\u003emode \u003d LWSCM_PRE_WS_SERVING_ACCEPT;\n+\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n+\n+\t\t/* is this websocket protocol or normal http 1.0? */\n+\n+\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {\n+\t\t\tif (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),\n+\t\t\t\t\t\u0022websocket\u0022)) {\n+\t\t\t\twsi-\u003evhost-\u003econn_stats.ws_upg++;\n+\t\t\t\tlwsl_info(\u0022Upgrade to ws\u005cn\u0022);\n+\t\t\t\tgoto upgrade_ws;\n+\t\t\t}\n+#ifdef LWS_WITH_HTTP2\n+\t\t\tif (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),\n+\t\t\t\t\t\u0022h2c\u0022)) {\n+\t\t\t\twsi-\u003evhost-\u003econn_stats.h2_upg++;\n+\t\t\t\tlwsl_info(\u0022Upgrade to h2c\u005cn\u0022);\n+\t\t\t\tgoto upgrade_h2c;\n+\t\t\t}\n+#endif\n+\t\t\tlwsl_info(\u0022Unknown upgrade\u005cn\u0022);\n+\t\t\t/* dunno what he wanted to upgrade to */\n+\t\t\tgoto bail_nuke_ah;\n+\t\t}\n+\n+\t\t/* no upgrade ack... he remained as HTTP */\n+\n+\t\tlwsl_info(\u0022No upgrade\u005cn\u0022);\n+\t\tah \u003d wsi-\u003eu.hdr.ah;\n+\n+\t\tlws_union_transition(wsi, LWSCM_HTTP_SERVING_ACCEPTED);\n+\t\twsi-\u003estate \u003d LWSS_HTTP;\n+\t\twsi-\u003eu.http.fop_fd \u003d NULL;\n+\n+\t\t/* expose it at the same offset as u.hdr */\n+\t\twsi-\u003eu.http.ah \u003d ah;\n+\t\tlwsl_debug(\u0022%s: wsi %p: ah %p\u005cn\u0022, __func__, (void *)wsi,\n+\t\t\t (void *)wsi-\u003eu.hdr.ah);\n+\n+\t\tn \u003d lws_http_action(wsi);\n+\n+\t\treturn n;\n+\n+#ifdef LWS_WITH_HTTP2\n+upgrade_h2c:\n+\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) {\n+\t\t\tlwsl_info(\u0022missing http2_settings\u005cn\u0022);\n+\t\t\tgoto bail_nuke_ah;\n+\t\t}\n+\n+\t\tlwsl_info(\u0022h2c upgrade...\u005cn\u0022);\n+\n+\t\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);\n+\t\t/* convert the peer's HTTP-Settings */\n+\t\tn \u003d lws_b64_decode_string(p, protocol_list,\n+\t\t\t\t\t sizeof(protocol_list));\n+\t\tif (n \u003c 0) {\n+\t\t\tlwsl_parser(\u0022HTTP2_SETTINGS too long\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\t/* adopt the header info */\n+\n+\t\tah \u003d wsi-\u003eu.hdr.ah;\n+\n+\t\tlws_union_transition(wsi, LWSCM_HTTP2_SERVING);\n+\n+\t\t/* http2 union member has http union struct at start */\n+\t\twsi-\u003eu.http.ah \u003d ah;\n+\n+\t\tif (!wsi-\u003eu.h2.h2n) {\n+\t\t\twsi-\u003eu.h2.h2n \u003d lws_zalloc(sizeof(*wsi-\u003eu.h2.h2n), \u0022h2n\u0022);\n+\t\t\tif (!wsi-\u003eu.h2.h2n)\n+\t\t\t\treturn 1;\n+\t\t}\n+\n+\t\tlws_h2_init(wsi);\n+\n+\t\t/* HTTP2 union */\n+\n+\t\tlws_h2_settings(wsi, \u0026wsi-\u003eu.h2.h2n-\u003eset,\n+\t\t\t\t(unsigned char *)protocol_list, n);\n+\n+\t\tlws_hpack_dynamic_size(wsi, wsi-\u003eu.h2.h2n-\u003eset.s[\n+\t\t H2SET_HEADER_TABLE_SIZE]);\n+\n+\t\tstrcpy(protocol_list, \u0022HTTP/1.1 101 Switching Protocols\u005cx0d\u005cx0a\u0022\n+\t\t\t\t \u0022Connection: Upgrade\u005cx0d\u005cx0a\u0022\n+\t\t\t\t \u0022Upgrade: h2c\u005cx0d\u005cx0a\u005cx0d\u005cx0a\u0022);\n+\t\tn \u003d lws_issue_raw(wsi, (unsigned char *)protocol_list,\n+\t\t\t\t\tstrlen(protocol_list));\n+\t\tif (n !\u003d strlen(protocol_list)) {\n+\t\t\tlwsl_debug(\u0022http2 switch: ERROR writing to socket\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\twsi-\u003estate \u003d LWSS_HTTP2_AWAIT_CLIENT_PREFACE;\n+\n+\t\treturn 0;\n+#endif\n+\n+upgrade_ws:\n+\t\tif (!wsi-\u003eprotocol)\n+\t\t\tlwsl_err(\u0022NULL protocol at lws_read\u005cn\u0022);\n+\n+\t\t/*\n+\t\t * It's websocket\n+\t\t *\n+\t\t * Select the first protocol we support from the list\n+\t\t * the client sent us.\n+\t\t *\n+\t\t * Copy it to remove header fragmentation\n+\t\t */\n+\n+\t\tif (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1,\n+\t\t\t\t WSI_TOKEN_PROTOCOL) \u003c 0) {\n+\t\t\tlwsl_err(\u0022protocol list too long\u0022);\n+\t\t\tgoto bail_nuke_ah;\n+\t\t}\n+\n+\t\tprotocol_len \u003d lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);\n+\t\tprotocol_list[protocol_len] \u003d '\u005c0';\n+\t\tp \u003d protocol_list;\n+\t\thit \u003d 0;\n+\n+\t\twhile (*p \u0026\u0026 !hit) {\n+\t\t\tn \u003d 0;\n+\t\t\tnon_space_char_found \u003d 0;\n+\t\t\twhile (n \u003c sizeof(protocol_name) - 1 \u0026\u0026\n+\t\t\t *p \u0026\u0026 *p !\u003d ',') {\n+\t\t\t\t/* ignore leading spaces */\n+\t\t\t\tif (!non_space_char_found \u0026\u0026 *p \u003d\u003d ' ') {\n+\t\t\t\t\tn++;\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t\tnon_space_char_found \u003d 1;\n+\t\t\t\tprotocol_name[n++] \u003d *p++;\n+\t\t\t}\n+\t\t\tprotocol_name[n] \u003d '\u005c0';\n+\t\t\tif (*p)\n+\t\t\t\tp++;\n+\n+\t\t\tlwsl_info(\u0022checking %s\u005cn\u0022, protocol_name);\n+\n+\t\t\tn \u003d 0;\n+\t\t\twhile (wsi-\u003evhost-\u003eprotocols[n].callback) {\n+\t\t\t\tlwsl_info(\u0022try %s\u005cn\u0022,\n+\t\t\t\t\t wsi-\u003evhost-\u003eprotocols[n].name);\n+\n+\t\t\t\tif (wsi-\u003evhost-\u003eprotocols[n].name \u0026\u0026\n+\t\t\t\t !strcmp(wsi-\u003evhost-\u003eprotocols[n].name,\n+\t\t\t\t\t protocol_name)) {\n+\t\t\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[n];\n+\t\t\t\t\thit \u003d 1;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\n+\t\t\t\tn++;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* we didn't find a protocol he wanted? */\n+\n+\t\tif (!hit) {\n+\t\t\tif (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {\n+\t\t\t\tlwsl_info(\u0022No protocol from \u005c\u0022%s\u005c\u0022 supported\u005cn\u0022,\n+\t\t\t\t\t protocol_list);\n+\t\t\t\tgoto bail_nuke_ah;\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t * some clients only have one protocol and\n+\t\t\t * do not send the protocol list header...\n+\t\t\t * allow it and match to the vhost's default\n+\t\t\t * protocol (which itself defaults to zero)\n+\t\t\t */\n+\t\t\tlwsl_info(\u0022defaulting to prot handler %d\u005cn\u0022,\n+\t\t\t\twsi-\u003evhost-\u003edefault_protocol_index);\n+\t\t\tn \u003d wsi-\u003evhost-\u003edefault_protocol_index;\n+\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[\n+\t\t\t\t (int)wsi-\u003evhost-\u003edefault_protocol_index];\n+\t\t}\n+\n+\t\t/* allocate wsi-\u003euser storage */\n+\t\tif (lws_ensure_user_space(wsi))\n+\t\t\tgoto bail_nuke_ah;\n+\n+\t\t/*\n+\t\t * Give the user code a chance to study the request and\n+\t\t * have the opportunity to deny it\n+\t\t */\n+\t\tif ((wsi-\u003eprotocol-\u003ecallback)(wsi,\n+\t\t\t\tLWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,\n+\t\t\t\twsi-\u003euser_space,\n+\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {\n+\t\t\tlwsl_warn(\u0022User code denied connection\u005cn\u0022);\n+\t\t\tgoto bail_nuke_ah;\n+\t\t}\n+\n+\t\t/*\n+\t\t * Perform the handshake according to the protocol version the\n+\t\t * client announced\n+\t\t */\n+\n+\t\tswitch (wsi-\u003eietf_spec_revision) {\n+\t\tcase 13:\n+\t\t\tlwsl_parser(\u0022lws_parse calling handshake_04\u005cn\u0022);\n+\t\t\tif (handshake_0405(context, wsi)) {\n+\t\t\t\tlwsl_info(\u0022hs0405 has failed the connection\u005cn\u0022);\n+\t\t\t\tgoto bail_nuke_ah;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tlwsl_info(\u0022Unknown client spec version %d\u005cn\u0022,\n+\t\t\t\t wsi-\u003eietf_spec_revision);\n+\t\t\tgoto bail_nuke_ah;\n+\t\t}\n+\n+\t\tlws_same_vh_protocol_insert(wsi, n);\n+\n+\t\t/* we are upgrading to ws, so http/1.1 and keepalive +\n+\t\t * pipelined header considerations about keeping the ah around\n+\t\t * no longer apply. However it's common for the first ws\n+\t\t * protocol data to have been coalesced with the browser\n+\t\t * upgrade request and to already be in the ah rx buffer.\n+\t\t */\n+\n+\t\tlwsl_info(\u0022%s: %p: inheriting ws ah (rxpos:%d, rxlen:%d)\u005cn\u0022,\n+\t\t\t __func__, wsi, wsi-\u003eu.hdr.ah-\u003erxpos,\n+\t\t\t wsi-\u003eu.hdr.ah-\u003erxlen);\n+\t\tlws_pt_lock(pt);\n+\t\thdr \u003d wsi-\u003eu.hdr;\n+\n+\t\tlws_union_transition(wsi, LWSCM_WS_SERVING);\n+\t\t/*\n+\t\t * first service is WS mode will notice this, use the RX and\n+\t\t * then detach the ah (caution: we are not in u.hdr union\n+\t\t * mode any more then... ah_temp member is at start the same\n+\t\t * though)\n+\t\t *\n+\t\t * Because rxpos/rxlen shows something in the ah, we will get\n+\t\t * service guaranteed next time around the event loop\n+\t\t *\n+\t\t * All union members begin with hdr, so we can use it even\n+\t\t * though we transitioned to ws union mode (the ah detach\n+\t\t * code uses it anyway).\n+\t\t */\n+\t\twsi-\u003eu.hdr \u003d hdr;\n+\t\tlws_pt_unlock(pt);\n+\n+\t\tlws_server_init_wsi_for_ws(wsi);\n+\t\tlwsl_parser(\u0022accepted v%02d connection\u005cn\u0022,\n+\t\t\t wsi-\u003eietf_spec_revision);\n+\n+\t\t/* !!! drop ah unreservedly after ESTABLISHED */\n+\t\tif (!wsi-\u003emore_rx_waiting) {\n+\t\t\tlws_header_table_force_to_detachable_state(wsi);\n+\t\t\tlws_header_table_detach(wsi, 1);\n+\t\t}\n+\n+\t\treturn 0;\n+\t} /* while all chars are handled */\n+\n+\treturn 0;\n+\n+bail_nuke_ah:\n+\t/* drop the header info */\n+\t/* we're closing, losing some rx is OK */\n+\tlws_header_table_force_to_detachable_state(wsi);\n+\tlws_header_table_detach(wsi, 1);\n+\n+\treturn 1;\n+}\n+\n+\n+static int\n+lws_get_idlest_tsi(struct lws_context *context)\n+{\n+\tunsigned int lowest \u003d ~0;\n+\tint n \u003d 0, hit \u003d -1;\n+\n+\tfor (; n \u003c context-\u003ecount_threads; n++) {\n+\t\tif ((unsigned int)context-\u003ept[n].fds_count !\u003d\n+\t\t context-\u003efd_limit_per_thread - 1 \u0026\u0026\n+\t\t (unsigned int)context-\u003ept[n].fds_count \u003c lowest) {\n+\t\t\tlowest \u003d context-\u003ept[n].fds_count;\n+\t\t\thit \u003d n;\n+\t\t}\n+\t}\n+\n+\treturn hit;\n+}\n+\n+struct lws *\n+lws_create_new_server_wsi(struct lws_vhost *vhost)\n+{\n+\tstruct lws *new_wsi;\n+\tint n \u003d lws_get_idlest_tsi(vhost-\u003econtext);\n+\n+\tif (n \u003c 0) {\n+\t\tlwsl_err(\u0022no space for new conn\u005cn\u0022);\n+\t\treturn NULL;\n+\t}\n+\n+\tnew_wsi \u003d lws_zalloc(sizeof(struct lws), \u0022new server wsi\u0022);\n+\tif (new_wsi \u003d\u003d NULL) {\n+\t\tlwsl_err(\u0022Out of memory for new connection\u005cn\u0022);\n+\t\treturn NULL;\n+\t}\n+\n+\tnew_wsi-\u003etsi \u003d n;\n+\tlwsl_debug(\u0022new wsi %p joining vhost %s, tsi %d\u005cn\u0022, new_wsi,\n+\t\t vhost-\u003ename, new_wsi-\u003etsi);\n+\n+\tnew_wsi-\u003evhost \u003d vhost;\n+\tnew_wsi-\u003econtext \u003d vhost-\u003econtext;\n+\tnew_wsi-\u003epending_timeout \u003d NO_PENDING_TIMEOUT;\n+\tnew_wsi-\u003erxflow_change_to \u003d LWS_RXFLOW_ALLOW;\n+\n+\t/* initialize the instance struct */\n+\n+\tnew_wsi-\u003estate \u003d LWSS_HTTP;\n+\tnew_wsi-\u003emode \u003d LWSCM_HTTP_SERVING;\n+\tnew_wsi-\u003ehdr_parsing_completed \u003d 0;\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\tnew_wsi-\u003euse_ssl \u003d LWS_SSL_ENABLED(vhost);\n+#endif\n+\n+\t/*\n+\t * these can only be set once the protocol is known\n+\t * we set an un-established connection's protocol pointer\n+\t * to the start of the supported list, so it can look\n+\t * for matching ones during the handshake\n+\t */\n+\tnew_wsi-\u003eprotocol \u003d vhost-\u003eprotocols;\n+\tnew_wsi-\u003euser_space \u003d NULL;\n+\tnew_wsi-\u003eietf_spec_revision \u003d 0;\n+\tnew_wsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n+\tnew_wsi-\u003eposition_in_fds_table \u003d -1;\n+\n+\tvhost-\u003econtext-\u003ecount_wsi_allocated++;\n+\n+\t/*\n+\t * outermost create notification for wsi\n+\t * no user_space because no protocol selection\n+\t */\n+\tvhost-\u003eprotocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE,\n+\t\t\t\t NULL, NULL, 0);\n+\n+\treturn new_wsi;\n+}\n+\n+LWS_VISIBLE int LWS_WARN_UNUSED_RESULT\n+lws_http_transaction_completed(struct lws *wsi)\n+{\n+\tint n \u003d NO_PENDING_TIMEOUT;\n+\n+\tlwsl_info(\u0022%s: wsi %p\u005cn\u0022, __func__, wsi);\n+\n+\tlws_access_log(wsi);\n+\n+\tif (!wsi-\u003ehdr_parsing_completed) {\n+\t\tlwsl_notice(\u0022%s: ignoring, ah parsing incomplete\u005cn\u0022, __func__);\n+\t\treturn 0;\n+\t}\n+\n+\tlwsl_debug(\u0022%s: wsi %p\u005cn\u0022, __func__, wsi);\n+\t/* if we can't go back to accept new headers, drop the connection */\n+\tif (wsi-\u003ehttp2_substream)\n+\t\treturn 0;\n+\n+\tif (wsi-\u003eseen_zero_length_recv)\n+\t\treturn 1;\n+\n+\tif (wsi-\u003eu.http.connection_type !\u003d HTTP_CONNECTION_KEEP_ALIVE) {\n+\t\tlwsl_info(\u0022%s: %p: close connection\u005cn\u0022, __func__, wsi);\n+\t\treturn 1;\n+\t}\n+\n+\tif (lws_bind_protocol(wsi, \u0026wsi-\u003evhost-\u003eprotocols[0]))\n+\t\treturn 1;\n+\n+\t/* otherwise set ourselves up ready to go again */\n+\twsi-\u003estate \u003d LWSS_HTTP;\n+\twsi-\u003emode \u003d LWSCM_HTTP_SERVING;\n+\twsi-\u003eu.http.tx_content_length \u003d 0;\n+\twsi-\u003eu.http.tx_content_remain \u003d 0;\n+\twsi-\u003ehdr_parsing_completed \u003d 0;\n+#ifdef LWS_WITH_ACCESS_LOG\n+\twsi-\u003eaccess_log.sent \u003d 0;\n+#endif\n+\n+\tif (wsi-\u003evhost-\u003ekeepalive_timeout)\n+\t\tn \u003d PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE;\n+\tlws_set_timeout(wsi, n, wsi-\u003evhost-\u003ekeepalive_timeout);\n+\n+\t/*\n+\t * We already know we are on http1.1 / keepalive and the next thing\n+\t * coming will be another header set.\n+\t *\n+\t * If there is no pending rx and we still have the ah, drop it and\n+\t * reacquire a new ah when the new headers start to arrive. (Otherwise\n+\t * we needlessly hog an ah indefinitely.)\n+\t *\n+\t * However if there is pending rx and we know from the keepalive state\n+\t * that is already at least the start of another header set, simply\n+\t * reset the existing header table and keep it.\n+\t */\n+\tif (wsi-\u003eu.hdr.ah) {\n+\t\tlwsl_debug(\u0022%s: wsi-\u003emore_rx_waiting\u003d%d\u005cn\u0022, __func__,\n+\t\t\t\twsi-\u003emore_rx_waiting);\n+\n+\t\tif (!wsi-\u003emore_rx_waiting) {\n+\t\t\tlws_header_table_force_to_detachable_state(wsi);\n+\t\t\tlws_header_table_detach(wsi, 1);\n+#ifdef LWS_OPENSSL_SUPPORT\n+\t\t\t/*\n+\t\t\t * additionally... if we are hogging an SSL instance\n+\t\t\t * with no pending pipelined headers (or ah now), and\n+\t\t\t * SSL is scarce, drop this connection without waiting\n+\t\t\t */\n+\n+\t\t\tif (wsi-\u003evhost-\u003euse_ssl \u0026\u0026\n+\t\t\t wsi-\u003econtext-\u003esimultaneous_ssl_restriction \u0026\u0026\n+\t\t\t wsi-\u003econtext-\u003esimultaneous_ssl \u003d\u003d\n+\t\t\t\t wsi-\u003econtext-\u003esimultaneous_ssl_restriction) {\n+\t\t\t\tlwsl_info(\u0022%s: simultaneous_ssl_restriction\u005cn\u0022,\n+\t\t\t\t\t __func__);\n+\t\t\t\treturn 1;\n+\t\t\t}\n+#endif\n+\t\t} else {\n+\t\t\tlws_header_table_reset(wsi, 1);\n+\t\t\t/*\n+\t\t\t * If we kept the ah, we should restrict the amount\n+\t\t\t * of time we are willing to keep it. Otherwise it\n+\t\t\t * will be bound the whole time the connection remains\n+\t\t\t * open.\n+\t\t\t */\n+\t\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,\n+\t\t\t\t\twsi-\u003evhost-\u003ekeepalive_timeout);\n+\t\t}\n+\t}\n+\n+\t/* If we're (re)starting on headers, need other implied init */\n+\twsi-\u003eu.hdr.ues \u003d URIES_IDLE;\n+\n+\tlwsl_info(\u0022%s: %p: keep-alive await new transaction\u005cn\u0022, __func__, wsi);\n+\n+\treturn 0;\n+}\n+\n+/* if not a socket, it's a raw, non-ssl file descriptor */\n+\n+LWS_VISIBLE struct lws *\n+lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,\n+\t\t\t lws_sock_file_fd_type fd, const char *vh_prot_name,\n+\t\t\t struct lws *parent)\n+{\n+\tstruct lws_context *context \u003d vh-\u003econtext;\n+\tstruct lws *new_wsi;\n+\tstruct lws_context_per_thread *pt;\n+\tint n, ssl \u003d 0;\n+\n+#if defined(LWS_WITH_PEER_LIMITS)\n+\tstruct lws_peer *peer \u003d NULL;\n+\n+\tif (type \u0026 LWS_ADOPT_SOCKET \u0026\u0026 !(type \u0026 LWS_ADOPT_WS_PARENTIO)) {\n+\t\tpeer \u003d lws_get_or_create_peer(vh, fd.sockfd);\n+\n+\t\tif (!peer) {\n+\t\t\tlwsl_err(\u0022OOM creating peer\u005cn\u0022);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tif (context-\u003eip_limit_wsi \u0026\u0026\n+\t\t peer-\u003ecount_wsi \u003e\u003d context-\u003eip_limit_wsi) {\n+\t\t\tlwsl_notice(\u0022Peer reached wsi limit %d\u005cn\u0022,\n+\t\t\t\t\tcontext-\u003eip_limit_wsi);\n+\t\t\tlws_stats_atomic_bump(context, \u0026context-\u003ept[0],\n+\t\t\t\t\t LWSSTATS_C_PEER_LIMIT_WSI_DENIED, 1);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+#endif\n+\n+\tnew_wsi \u003d lws_create_new_server_wsi(vh);\n+\tif (!new_wsi) {\n+\t\tif (type \u0026 LWS_ADOPT_SOCKET \u0026\u0026 !(type \u0026 LWS_ADOPT_WS_PARENTIO))\n+\t\t\tcompatible_close(fd.sockfd);\n+\t\treturn NULL;\n+\t}\n+#if defined(LWS_WITH_PEER_LIMITS)\n+\tif (peer)\n+\t\tlws_peer_add_wsi(context, peer, new_wsi);\n+#endif\n+\tpt \u003d \u0026context-\u003ept[(int)new_wsi-\u003etsi];\n+\tlws_stats_atomic_bump(context, pt, LWSSTATS_C_CONNECTIONS, 1);\n+\n+\tif (parent) {\n+\t\tnew_wsi-\u003eparent \u003d parent;\n+\t\tnew_wsi-\u003esibling_list \u003d parent-\u003echild_list;\n+\t\tparent-\u003echild_list \u003d new_wsi;\n+\n+\t\tif (type \u0026 LWS_ADOPT_WS_PARENTIO)\n+\t\t\tnew_wsi-\u003eparent_carries_io \u003d 1;\n+\t}\n+\n+\tnew_wsi-\u003edesc \u003d fd;\n+\n+\tif (vh_prot_name) {\n+\t\tnew_wsi-\u003eprotocol \u003d lws_vhost_name_to_protocol(new_wsi-\u003evhost,\n+\t\t\t\t\t\t\t vh_prot_name);\n+\t\tif (!new_wsi-\u003eprotocol) {\n+\t\t\tlwsl_err(\u0022Protocol %s not enabled on vhost %s\u005cn\u0022,\n+\t\t\t\t vh_prot_name, new_wsi-\u003evhost-\u003ename);\n+\t\t\tgoto bail;\n+\t\t}\n+ if (lws_ensure_user_space(new_wsi)) {\n+ lwsl_notice(\u0022OOM trying to get user_space\u005cn\u0022);\n+\t\t\tgoto bail;\n+ }\n+ if (type \u0026 LWS_ADOPT_WS_PARENTIO) {\n+\t\t\tnew_wsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n+\t\t\tlwsl_debug(\u0022binding to %s\u005cn\u0022, new_wsi-\u003eprotocol-\u003ename);\n+\t\t\tlws_bind_protocol(new_wsi, new_wsi-\u003eprotocol);\n+\t\t\tlws_union_transition(new_wsi, LWSCM_WS_SERVING);\n+\t\t\tlws_server_init_wsi_for_ws(new_wsi);\n+\n+\t\t\treturn new_wsi;\n+ }\n+\t} else\n+\t\tif (type \u0026 LWS_ADOPT_HTTP) /* he will transition later */\n+\t\t\tnew_wsi-\u003eprotocol \u003d\n+\t\t\t\t\u0026vh-\u003eprotocols[vh-\u003edefault_protocol_index];\n+\t\telse { /* this is the only time he will transition */\n+\t\t\tlws_bind_protocol(new_wsi,\n+\t\t\t\t\u0026vh-\u003eprotocols[vh-\u003eraw_protocol_index]);\n+\t\t\tlws_union_transition(new_wsi, LWSCM_RAW);\n+\t\t}\n+\n+\tif (type \u0026 LWS_ADOPT_SOCKET) { /* socket desc */\n+\t\tlwsl_debug(\u0022%s: new wsi %p, sockfd %d\u005cn\u0022, __func__, new_wsi,\n+\t\t\t (int)(lws_intptr_t)fd.sockfd);\n+\n+\t\tif (type \u0026 LWS_ADOPT_HTTP)\n+\t\t\t/* the transport is accepted...\n+\t\t\t * give him time to negotiate */\n+\t\t\tlws_set_timeout(new_wsi,\n+\t\t\t\t\tPENDING_TIMEOUT_ESTABLISH_WITH_SERVER,\n+\t\t\t\t\tcontext-\u003etimeout_secs);\n+\n+#if LWS_POSIX \u003d\u003d 0\n+#if defined(LWS_WITH_ESP8266)\n+\t\tesp8266_tcp_stream_accept(accept_fd, new_wsi);\n+#endif\n+#endif\n+\t} else /* file desc */\n+\t\tlwsl_debug(\u0022%s: new wsi %p, filefd %d\u005cn\u0022, __func__, new_wsi,\n+\t\t\t (int)(lws_intptr_t)fd.filefd);\n+\n+\t/*\n+\t * A new connection was accepted. Give the user a chance to\n+\t * set properties of the newly created wsi. There's no protocol\n+\t * selected yet so we issue this to the vhosts's default protocol,\n+\t * itself by default protocols[0]\n+\t */\n+\tn \u003d LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;\n+\tif (!(type \u0026 LWS_ADOPT_HTTP)) {\n+\t\tif (!(type \u0026 LWS_ADOPT_SOCKET))\n+\t\t\tn \u003d LWS_CALLBACK_RAW_ADOPT_FILE;\n+\t\telse\n+\t\t\tn \u003d LWS_CALLBACK_RAW_ADOPT;\n+\t}\n+\n+\tif (!LWS_SSL_ENABLED(new_wsi-\u003evhost) || !(type \u0026 LWS_ADOPT_ALLOW_SSL) ||\n+\t !(type \u0026 LWS_ADOPT_SOCKET)) {\n+\t\t/* non-SSL */\n+\t\tif (!(type \u0026 LWS_ADOPT_HTTP)) {\n+\t\t\tif (!(type \u0026 LWS_ADOPT_SOCKET))\n+\t\t\t\tnew_wsi-\u003emode \u003d LWSCM_RAW_FILEDESC;\n+\t\t\telse\n+\t\t\t\tnew_wsi-\u003emode \u003d LWSCM_RAW;\n+\t\t}\n+\t} else {\n+\t\t/* SSL */\n+\t\tif (!(type \u0026 LWS_ADOPT_HTTP))\n+\t\t\tnew_wsi-\u003emode \u003d LWSCM_SSL_INIT_RAW;\n+\t\telse\n+\t\t\tnew_wsi-\u003emode \u003d LWSCM_SSL_INIT;\n+\n+\t\tssl \u003d 1;\n+\t}\n+\n+\tlws_libev_accept(new_wsi, new_wsi-\u003edesc);\n+\tlws_libuv_accept(new_wsi, new_wsi-\u003edesc);\n+\tlws_libevent_accept(new_wsi, new_wsi-\u003edesc);\n+\n+\tif (!ssl) {\n+\t\tif (insert_wsi_socket_into_fds(context, new_wsi)) {\n+\t\t\tlwsl_err(\u0022%s: fail inserting socket\u005cn\u0022, __func__);\n+\t\t\tgoto fail;\n+\t\t}\n+\t} else\n+\t\tif (lws_server_socket_service_ssl(new_wsi, fd.sockfd)) {\n+\t\t\tlwsl_info(\u0022%s: fail ssl negotiation\u005cn\u0022, __func__);\n+\t\t\tgoto fail;\n+\t\t}\n+\n+\t/*\n+\t * by deferring callback to this point, after insertion to fds,\n+\t * lws_callback_on_writable() can work from the callback\n+\t */\n+\tif ((new_wsi-\u003eprotocol-\u003ecallback)(\n+\t\t\tnew_wsi, n, new_wsi-\u003euser_space, NULL, 0))\n+\t\tgoto fail;\n+\n+\tif (type \u0026 LWS_ADOPT_HTTP) {\n+\t\tif (!lws_header_table_attach(new_wsi, 0))\n+\t\t\tlwsl_debug(\u0022Attached ah immediately\u005cn\u0022);\n+\t\telse\n+\t\t\tlwsl_info(\u0022%s: waiting for ah\u005cn\u0022, __func__);\n+\t}\n+\n+\treturn new_wsi;\n+\n+fail:\n+\tif (type \u0026 LWS_ADOPT_SOCKET)\n+\t\tlws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\n+\treturn NULL;\n+\n+bail:\n+ lwsl_notice(\u0022%s: exiting on bail\u005cn\u0022, __func__);\n+\tif (parent)\n+\t\tparent-\u003echild_list \u003d new_wsi-\u003esibling_list;\n+\tif (new_wsi-\u003euser_space)\n+\t\tlws_free(new_wsi-\u003euser_space);\n+\tlws_free(new_wsi);\n+ compatible_close(fd.sockfd);\n+\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE struct lws *\n+lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)\n+{\n+\tlws_sock_file_fd_type fd;\n+\n+\tfd.sockfd \u003d accept_fd;\n+\treturn lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |\n+\t\t\tLWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);\n+}\n+\n+LWS_VISIBLE struct lws *\n+lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)\n+{\n+\treturn lws_adopt_socket_vhost(context-\u003evhost_list, accept_fd);\n+}\n+\n+/* Common read-buffer adoption for lws_adopt_*_readbuf */\n+static struct lws*\n+adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)\n+{\n+\tstruct lws_context_per_thread *pt;\n+\tstruct allocated_headers *ah;\n+\tstruct lws_pollfd *pfd;\n+\n+\tif (!wsi)\n+\t\treturn NULL;\n+\n+\tif (!readbuf || len \u003d\u003d 0)\n+\t\treturn wsi;\n+\n+\tif (len \u003e sizeof(ah-\u003erx)) {\n+\t\tlwsl_err(\u0022%s: rx in too big\u005cn\u0022, __func__);\n+\t\tgoto bail;\n+\t}\n+\n+\t/*\n+\t * we can't process the initial read data until we can attach an ah.\n+\t *\n+\t * if one is available, get it and place the data in his ah rxbuf...\n+\t * wsi with ah that have pending rxbuf get auto-POLLIN service.\n+\t *\n+\t * no autoservice because we didn't get a chance to attach the\n+\t * readbuf data to wsi or ah yet, and we will do it next if we get\n+\t * the ah.\n+\t */\n+\tif (wsi-\u003eu.hdr.ah || !lws_header_table_attach(wsi, 0)) {\n+\t\tah \u003d wsi-\u003eu.hdr.ah;\n+\t\tmemcpy(ah-\u003erx, readbuf, len);\n+\t\tah-\u003erxpos \u003d 0;\n+\t\tah-\u003erxlen \u003d (int16_t)len;\n+\n+\t\tlwsl_notice(\u0022%s: calling service on readbuf ah\u005cn\u0022, __func__);\n+\t\tpt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n+\n+\t\t/* unlike a normal connect, we have the headers already\n+\t\t * (or the first part of them anyway).\n+\t\t * libuv won't come back and service us without a network\n+\t\t * event, so we need to do the header service right here.\n+\t\t */\n+\t\tpfd \u003d \u0026pt-\u003efds[wsi-\u003eposition_in_fds_table];\n+\t\tpfd-\u003erevents |\u003d LWS_POLLIN;\n+\t\tlwsl_err(\u0022%s: calling service\u005cn\u0022, __func__);\n+\t\tif (lws_service_fd_tsi(wsi-\u003econtext, pfd, wsi-\u003etsi))\n+\t\t\t/* service closed us */\n+\t\t\treturn NULL;\n+\n+\t\treturn wsi;\n+\t}\n+\tlwsl_err(\u0022%s: deferring handling ah\u005cn\u0022, __func__);\n+\t/*\n+\t * hum if no ah came, we are on the wait list and must defer\n+\t * dealing with this until the ah arrives.\n+\t *\n+\t * later successful lws_header_table_attach() will apply the\n+\t * below to the rx buffer (via lws_header_table_reset()).\n+\t */\n+\twsi-\u003eu.hdr.preamble_rx \u003d lws_malloc(len, \u0022preamble_rx\u0022);\n+\tif (!wsi-\u003eu.hdr.preamble_rx) {\n+\t\tlwsl_err(\u0022OOM\u005cn\u0022);\n+\t\tgoto bail;\n+\t}\n+\tmemcpy(wsi-\u003eu.hdr.preamble_rx, readbuf, len);\n+\twsi-\u003eu.hdr.preamble_rx_len \u003d len;\n+\n+\treturn wsi;\n+\n+bail:\n+\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\n+\treturn NULL;\n+}\n+\n+LWS_VISIBLE struct lws *\n+lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,\n+\t\t\t const char *readbuf, size_t len)\n+{\n+ return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd),\n+ \t\t\t readbuf, len);\n+}\n+\n+LWS_VISIBLE struct lws *\n+lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,\n+\t\t\t lws_sockfd_type accept_fd,\n+\t\t\t const char *readbuf, size_t len)\n+{\n+ return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd),\n+ \t\t\t readbuf, len);\n+}\n+\n+LWS_VISIBLE int\n+lws_server_socket_service(struct lws_context *context, struct lws *wsi,\n+\t\t\t struct lws_pollfd *pollfd)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tlws_sockfd_type accept_fd \u003d LWS_SOCK_INVALID;\n+\tstruct allocated_headers *ah;\n+\tlws_sock_file_fd_type fd;\n+\tint opts \u003d LWS_ADOPT_SOCKET | LWS_ADOPT_ALLOW_SSL;\n+#if LWS_POSIX\n+\tstruct sockaddr_storage cli_addr;\n+\tsocklen_t clilen;\n+#endif\n+\tint n, len;\n+\n+\tswitch (wsi-\u003emode) {\n+\n+\tcase LWSCM_HTTP_SERVING:\n+\tcase LWSCM_HTTP_SERVING_ACCEPTED:\n+\tcase LWSCM_HTTP2_SERVING:\n+\tcase LWSCM_RAW:\n+\n+\t\t/* handle http headers coming in */\n+\n+\t\t/* pending truncated sends have uber priority */\n+\n+\t\tif (wsi-\u003etrunc_len) {\n+\t\t\tif (!(pollfd-\u003erevents \u0026 LWS_POLLOUT))\n+\t\t\t\tbreak;\n+\n+\t\t\tif (lws_issue_raw(wsi, wsi-\u003etrunc_alloc +\n+\t\t\t\t\t wsi-\u003etrunc_offset,\n+\t\t\t\t\t wsi-\u003etrunc_len) \u003c 0)\n+\t\t\t\tgoto fail;\n+\t\t\t/*\n+\t\t\t * we can't afford to allow input processing to send\n+\t\t\t * something new, so spin around he event loop until\n+\t\t\t * he doesn't have any partials\n+\t\t\t */\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* any incoming data ready? */\n+\n+\t\tif (!(pollfd-\u003erevents \u0026 pollfd-\u003eevents \u0026 LWS_POLLIN))\n+\t\t\tgoto try_pollout;\n+\n+\t\t/*\n+\t\t * If we previously just did POLLIN when IN and OUT were\n+\t\t * signalled (because POLLIN processing may have used up\n+\t\t * the POLLOUT), don't let that happen twice in a row...\n+\t\t * next time we see the situation favour POLLOUT\n+\t\t */\n+#if !defined(LWS_WITH_ESP8266)\n+\t\tif (wsi-\u003efavoured_pollin \u0026\u0026\n+\t\t (pollfd-\u003erevents \u0026 pollfd-\u003eevents \u0026 LWS_POLLOUT)) {\n+\t\t\tlwsl_notice(\u0022favouring pollout\u005cn\u0022);\n+\t\t\twsi-\u003efavoured_pollin \u003d 0;\n+\t\t\tgoto try_pollout;\n+\t\t}\n+#endif\n+\n+\t\t/* these states imply we MUST have an ah attached */\n+\n+\t\tif (wsi-\u003emode !\u003d LWSCM_RAW \u0026\u0026 (wsi-\u003estate \u003d\u003d LWSS_HTTP ||\n+\t\t wsi-\u003estate \u003d\u003d LWSS_HTTP_ISSUING_FILE ||\n+\t\t wsi-\u003estate \u003d\u003d LWSS_HTTP_HEADERS)) {\n+\t\t\tif (!wsi-\u003eu.hdr.ah) {\n+\t\t\t\t/* no autoservice beacuse we will do it next */\n+\t\t\t\tif (lws_header_table_attach(wsi, 0)) {\n+\t\t\t\t\tlwsl_info(\u0022wsi %p: ah get fail\u005cn\u0022, wsi);\n+\t\t\t\t\tgoto try_pollout;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tah \u003d wsi-\u003eu.hdr.ah;\n+\n+\t\t\t/* if nothing in ah rx buffer, get some fresh rx */\n+\t\t\tif (ah-\u003erxpos \u003d\u003d ah-\u003erxlen) {\n+\t\t\t\tah-\u003erxlen \u003d lws_ssl_capable_read(wsi, ah-\u003erx,\n+\t\t\t\t\t\t sizeof(ah-\u003erx));\n+\t\t\t\tah-\u003erxpos \u003d 0;\n+\t\t\t\tswitch (ah-\u003erxlen) {\n+\t\t\t\tcase 0:\n+\t\t\t\t\tlwsl_info(\u0022%s: read 0 len a\u005cn\u0022, __func__);\n+\t\t\t\t\twsi-\u003eseen_zero_length_recv \u003d 1;\n+\t\t\t\t\tlws_change_pollfd(wsi, LWS_POLLIN, 0);\n+\t\t\t\t\tgoto try_pollout;\n+\t\t\t\t\t/* fallthru */\n+\t\t\t\tcase LWS_SSL_CAPABLE_ERROR:\n+\t\t\t\t\tgoto fail;\n+\t\t\t\tcase LWS_SSL_CAPABLE_MORE_SERVICE:\n+\t\t\t\t\tah-\u003erxlen \u003d ah-\u003erxpos \u003d 0;\n+\t\t\t\t\tgoto try_pollout;\n+\t\t\t\t}\n+\n+\t\t\t\t/*\n+\t\t\t\t * make sure ah does not get detached if we\n+\t\t\t\t * have live data in the rx\n+\t\t\t\t */\n+\t\t\t\tif (ah-\u003erxlen)\n+\t\t\t\t\twsi-\u003emore_rx_waiting \u003d 1;\n+\t\t\t}\n+\n+\t\t\tif (!(ah-\u003erxpos !\u003d ah-\u003erxlen \u0026\u0026 ah-\u003erxlen)) {\n+\t\t\t\tlwsl_err(\u0022%s: assert: rxpos %d, rxlen %d\u005cn\u0022,\n+\t\t\t\t\t __func__, ah-\u003erxpos, ah-\u003erxlen);\n+\n+\t\t\t\tassert(0);\n+\t\t\t}\n+\t\t\t\n+\t\t\t/* just ignore incoming if waiting for close */\n+\t\t\tif (wsi-\u003estate !\u003d LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE \u0026\u0026\n+\t\t\t wsi-\u003estate !\u003d LWSS_HTTP_ISSUING_FILE) {\n+\t\t\t\t/*\n+\t\t\t\t * otherwise give it to whoever wants it\n+\t\t\t\t * according to the connection state\n+\t\t\t\t */\n+\n+\t\t\t\tn \u003d lws_read(wsi, ah-\u003erx + ah-\u003erxpos,\n+\t\t\t\t\t ah-\u003erxlen - ah-\u003erxpos);\n+\t\t\t\tif (n \u003c 0) /* we closed wsi */\n+\t\t\t\t\treturn 1;\n+\n+\t\t\t\tif (!wsi-\u003eu.hdr.ah)\n+\t\t\t\t\tbreak;\n+\t\t\t\tif ( wsi-\u003eu.hdr.ah-\u003erxlen)\n+\t\t\t\t\t wsi-\u003eu.hdr.ah-\u003erxpos +\u003d n;\n+\n+\t\t\t\tlwsl_debug(\u0022%s: wsi %p: ah read rxpos %d, rxlen %d\u005cn\u0022,\n+\t\t\t\t\t __func__, wsi, wsi-\u003eu.hdr.ah-\u003erxpos,\n+\t\t\t\t\t wsi-\u003eu.hdr.ah-\u003erxlen);\n+\n+\t\t\t\tif (lws_header_table_is_in_detachable_state(wsi) \u0026\u0026\n+\t\t\t\t (wsi-\u003emode !\u003d LWSCM_HTTP_SERVING \u0026\u0026\n+\t\t\t\t wsi-\u003emode !\u003d LWSCM_HTTP_SERVING_ACCEPTED \u0026\u0026\n+\t\t\t\t wsi-\u003emode !\u003d LWSCM_HTTP2_SERVING))\n+\t\t\t\t\tlws_header_table_detach(wsi, 1);\n+\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tgoto try_pollout;\n+\t\t}\n+\n+\t\tlen \u003d lws_ssl_capable_read(wsi, pt-\u003eserv_buf,\n+\t\t\t\t\t context-\u003ept_serv_buf_size);\n+\t\tlwsl_debug(\u0022%s: wsi %p read %d\u005cr\u005cn\u0022, __func__, wsi, len);\n+\t\tswitch (len) {\n+\t\tcase 0:\n+\t\t\tlwsl_info(\u0022%s: read 0 len b\u005cn\u0022, __func__);\n+\n+\t\t\t/* fallthru */\n+\t\tcase LWS_SSL_CAPABLE_ERROR:\n+\t\t\tgoto fail;\n+\t\tcase LWS_SSL_CAPABLE_MORE_SERVICE:\n+\t\t\tgoto try_pollout;\n+\t\t}\n+\t\t\n+\t\tif (wsi-\u003emode \u003d\u003d LWSCM_RAW) {\n+\t\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback,\n+\t\t\t\t\twsi, LWS_CALLBACK_RAW_RX,\n+\t\t\t\t\twsi-\u003euser_space, pt-\u003eserv_buf, len);\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tlwsl_info(\u0022LWS_CALLBACK_RAW_RX_fail\u005cn\u0022);\n+\t\t\t\tgoto fail;\n+\t\t\t}\n+\t\t\tgoto try_pollout;\n+\t\t}\n+\n+\t\t/* just ignore incoming if waiting for close */\n+\t\tif (wsi-\u003estate !\u003d LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE \u0026\u0026\n+\t\t wsi-\u003estate !\u003d LWSS_HTTP_ISSUING_FILE) {\n+\t\t\t/*\n+\t\t\t * this may want to send\n+\t\t\t * (via HTTP callback for example)\n+\t\t\t */\n+\t\t\tn \u003d lws_read(wsi, pt-\u003eserv_buf, len);\n+\t\t\tif (n \u003c 0) /* we closed wsi */\n+\t\t\t\treturn 1;\n+\t\t\t/*\n+\t\t\t * he may have used up the\n+\t\t\t * writability above, if we will defer POLLOUT\n+\t\t\t * processing in favour of POLLIN, note it\n+\t\t\t */\n+\t\t\tif (pollfd-\u003erevents \u0026 LWS_POLLOUT)\n+\t\t\t\twsi-\u003efavoured_pollin \u003d 1;\n+\t\t\tbreak;\n+\t\t}\n+\t\t/*\n+\t\t * he may have used up the\n+\t\t * writability above, if we will defer POLLOUT\n+\t\t * processing in favour of POLLIN, note it\n+\t\t */\n+\t\tif (pollfd-\u003erevents \u0026 LWS_POLLOUT)\n+\t\t\twsi-\u003efavoured_pollin \u003d 1;\n+\n+try_pollout:\n+\t\t\n+\t\t/* this handles POLLOUT for http serving fragments */\n+\n+\t\tif (!(pollfd-\u003erevents \u0026 LWS_POLLOUT))\n+\t\t\tbreak;\n+\n+\t\t/* one shot */\n+\t\tif (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {\n+\t\t\tlwsl_notice(\u0022%s a\u005cn\u0022, __func__);\n+\t\t\tgoto fail;\n+\t\t}\n+\n+\t\tif (wsi-\u003emode \u003d\u003d LWSCM_RAW) {\n+\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt,\n+\t\t\t\t\t\tLWSSTATS_C_WRITEABLE_CB, 1);\n+#if defined(LWS_WITH_STATS)\n+\t\t\tif (wsi-\u003eactive_writable_req_us) {\n+\t\t\t\tuint64_t ul \u003d time_in_microseconds() -\n+\t\t\t\t\t\twsi-\u003eactive_writable_req_us;\n+\n+\t\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt,\n+\t\t\t\t\t\tLWSSTATS_MS_WRITABLE_DELAY, ul);\n+\t\t\t\tlws_stats_atomic_max(wsi-\u003econtext, pt,\n+\t\t\t\t\t LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);\n+\t\t\t\twsi-\u003eactive_writable_req_us \u003d 0;\n+\t\t\t}\n+#endif\n+\t\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback,\n+\t\t\t\t\twsi, LWS_CALLBACK_RAW_WRITEABLE,\n+\t\t\t\t\twsi-\u003euser_space, NULL, 0);\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tlwsl_info(\u0022writeable_fail\u005cn\u0022);\n+\t\t\t\tgoto fail;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (!wsi-\u003ehdr_parsing_completed)\n+\t\t\tbreak;\n+\n+\t\tif (wsi-\u003estate !\u003d LWSS_HTTP_ISSUING_FILE) {\n+\n+\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt,\n+\t\t\t\t\t\tLWSSTATS_C_WRITEABLE_CB, 1);\n+#if defined(LWS_WITH_STATS)\n+\t\t\tif (wsi-\u003eactive_writable_req_us) {\n+\t\t\t\tuint64_t ul \u003d time_in_microseconds() -\n+\t\t\t\t\t\twsi-\u003eactive_writable_req_us;\n+\n+\t\t\t\tlws_stats_atomic_bump(wsi-\u003econtext, pt,\n+\t\t\t\t\t\tLWSSTATS_MS_WRITABLE_DELAY, ul);\n+\t\t\t\tlws_stats_atomic_max(wsi-\u003econtext, pt,\n+\t\t\t\t\t LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);\n+\t\t\t\twsi-\u003eactive_writable_req_us \u003d 0;\n+\t\t\t}\n+#endif\n+\n+\t\t\tn \u003d user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback,\n+\t\t\t\t\twsi, LWS_CALLBACK_HTTP_WRITEABLE,\n+\t\t\t\t\twsi-\u003euser_space, NULL, 0);\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tlwsl_info(\u0022writeable_fail\u005cn\u0022);\n+\t\t\t\tgoto fail;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* \u003e0 \u003d\u003d completion, \u003c0 \u003d\u003d error\n+\t\t *\n+\t\t * We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when\n+\t\t * it's done. That's the case even if we just completed the\n+\t\t * send, so wait for that.\n+\t\t */\n+\t\tn \u003d lws_serve_http_file_fragment(wsi);\n+\t\tif (n \u003c 0)\n+\t\t\tgoto fail;\n+\n+\t\tbreak;\n+\n+\tcase LWSCM_SERVER_LISTENER:\n+\n+#if LWS_POSIX\n+\t\t/* pollin means a client has connected to us then */\n+\n+\t\tdo {\n+\t\t\tif (!(pollfd-\u003erevents \u0026 LWS_POLLIN) ||\n+\t\t\t !(pollfd-\u003eevents \u0026 LWS_POLLIN))\n+\t\t\t\tbreak;\n+\n+#ifdef LWS_OPENSSL_SUPPORT\n+\t\t\t/*\n+\t\t\t * can we really accept it, with regards to SSL limit?\n+\t\t\t * another vhost may also have had POLLIN on his listener this\n+\t\t\t * round and used it up already\n+\t\t\t */\n+\n+\t\t\tif (wsi-\u003evhost-\u003euse_ssl \u0026\u0026\n+\t\t\t context-\u003esimultaneous_ssl_restriction \u0026\u0026\n+\t\t\t context-\u003esimultaneous_ssl \u003d\u003d\n+\t\t\t\t\t context-\u003esimultaneous_ssl_restriction)\n+\t\t\t\t/* no... ignore it, he won't come again until we are\n+\t\t\t\t * below the simultaneous_ssl_restriction limit and\n+\t\t\t\t * POLLIN is enabled on him again\n+\t\t\t\t */\n+\t\t\t\tbreak;\n+#endif\n+\t\t\t/* listen socket got an unencrypted connection... */\n+\n+\t\t\tclilen \u003d sizeof(cli_addr);\n+\t\t\tlws_latency_pre(context, wsi);\n+\n+\t\t\t/*\n+\t\t\t * We cannot identify the peer who is in the listen\n+\t\t\t * socket connect queue before we accept it; even if\n+\t\t\t * we could, not accepting it due to PEER_LIMITS would\n+\t\t\t * block the connect queue for other legit peers.\n+\t\t\t */\n+\t\t\taccept_fd \u003d accept(pollfd-\u003efd, (struct sockaddr *)\u0026cli_addr,\n+\t\t\t\t\t \u0026clilen);\n+\t\t\tlws_latency(context, wsi, \u0022listener accept\u0022, accept_fd,\n+\t\t\t\t accept_fd \u003e\u003d 0);\n+\t\t\tif (accept_fd \u003c 0) {\n+\t\t\t\tif (LWS_ERRNO \u003d\u003d LWS_EAGAIN ||\n+\t\t\t\t LWS_ERRNO \u003d\u003d LWS_EWOULDBLOCK) {\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\tlwsl_err(\u0022ERROR on accept: %s\u005cn\u0022, strerror(LWS_ERRNO));\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tlws_plat_set_socket_options(wsi-\u003evhost, accept_fd);\n+\n+#if defined(LWS_WITH_IPV6)\n+\t\t\tlwsl_debug(\u0022accepted new conn port %u on fd\u003d%d\u005cn\u0022,\n+\t\t\t\t((cli_addr.ss_family \u003d\u003d AF_INET6) ?\n+\t\t\t\tntohs(((struct sockaddr_in6 *) \u0026cli_addr)-\u003esin6_port) :\n+\t\t\t\tntohs(((struct sockaddr_in *) \u0026cli_addr)-\u003esin_port)),\n+\t\t\t\taccept_fd);\n+#else\n+\t\t\tlwsl_debug(\u0022accepted new conn port %u on fd\u003d%d\u005cn\u0022,\n+\t\t\t\t ntohs(((struct sockaddr_in *) \u0026cli_addr)-\u003esin_port),\n+\t\t\t\t accept_fd);\n+#endif\n+\n+#else\n+\t\t\t/* not very beautiful... */\n+\t\t\taccept_fd \u003d (lws_sockfd_type)pollfd;\n+#endif\n+\t\t\t/*\n+\t\t\t * look at who we connected to and give user code a chance\n+\t\t\t * to reject based on client IP. There's no protocol selected\n+\t\t\t * yet so we issue this to protocols[0]\n+\t\t\t */\n+\t\t\tif ((wsi-\u003evhost-\u003eprotocols[0].callback)(wsi,\n+\t\t\t\t\tLWS_CALLBACK_FILTER_NETWORK_CONNECTION,\n+\t\t\t\t\tNULL, (void *)(lws_intptr_t)accept_fd, 0)) {\n+\t\t\t\tlwsl_debug(\u0022Callback denied network connection\u005cn\u0022);\n+\t\t\t\tcompatible_close(accept_fd);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tif (!(wsi-\u003evhost-\u003eoptions \u0026 LWS_SERVER_OPTION_ONLY_RAW))\n+\t\t\t\topts |\u003d LWS_ADOPT_HTTP;\n+\t\t\telse\n+\t\t\t\topts \u003d LWS_ADOPT_SOCKET;\n+\n+\t\t\tfd.sockfd \u003d accept_fd;\n+\t\t\tif (!lws_adopt_descriptor_vhost(wsi-\u003evhost, opts, fd,\n+\t\t\t\t\t\t\tNULL, NULL))\n+\t\t\t\t/* already closed cleanly as necessary */\n+\t\t\t\treturn 1;\n+\n+#if LWS_POSIX\n+\t\t} while (pt-\u003efds_count \u003c context-\u003efd_limit_per_thread - 1 \u0026\u0026\n+\t\t\t lws_poll_listen_fd(\u0026pt-\u003efds[wsi-\u003eposition_in_fds_table]) \u003e 0);\n+#endif\n+\t\treturn 0;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tif (!lws_server_socket_service_ssl(wsi, accept_fd))\n+\t\treturn 0;\n+\n+fail:\n+\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);\n+\n+\treturn 1;\n+}\n+\n+LWS_VISIBLE int\n+lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,\n+\t\t const char *other_headers, int other_headers_len)\n+{\n+\tstatic const char * const intermediates[] \u003d { \u0022private\u0022, \u0022public\u0022 };\n+\tstruct lws_context *context \u003d lws_get_context(wsi);\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+#if defined(LWS_WITH_RANGES)\n+\tstruct lws_range_parsing *rp \u003d \u0026wsi-\u003eu.http.range;\n+#endif\n+\tchar cache_control[50], *cc \u003d \u0022no-store\u0022;\n+\tunsigned char *response \u003d pt-\u003eserv_buf + LWS_PRE;\n+\tunsigned char *p \u003d response;\n+\tunsigned char *end \u003d p + context-\u003ept_serv_buf_size - LWS_PRE;\n+\tlws_filepos_t computed_total_content_length;\n+\tint ret \u003d 0, cclen \u003d 8, n \u003d HTTP_STATUS_OK;\n+\tlws_fop_flags_t fflags \u003d LWS_O_RDONLY;\n+#if defined(LWS_WITH_RANGES)\n+\tint ranges;\n+#endif\n+\tconst struct lws_plat_file_ops *fops;\n+\tconst char *vpath;\n+\n+\t/*\n+\t * We either call the platform fops .open with first arg platform fops,\n+\t * or we call fops_zip .open with first arg platform fops, and fops_zip\n+\t * open will decide whether to switch to fops_zip or stay with fops_def.\n+\t *\n+\t * If wsi-\u003eu.http.fop_fd is already set, the caller already opened it\n+\t */\n+\tif (!wsi-\u003eu.http.fop_fd) {\n+\t\tfops \u003d lws_vfs_select_fops(wsi-\u003econtext-\u003efops, file, \u0026vpath);\n+\t\tfflags |\u003d lws_vfs_prepare_flags(wsi);\n+\t\twsi-\u003eu.http.fop_fd \u003d fops-\u003eLWS_FOP_OPEN(wsi-\u003econtext-\u003efops,\n+\t\t\t\t\t\t\tfile, vpath, \u0026fflags);\n+\t\tif (!wsi-\u003eu.http.fop_fd) {\n+\t\t\tlwsl_err(\u0022Unable to open '%s'\u005cn\u0022, file);\n+\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\twsi-\u003eu.http.filelen \u003d lws_vfs_get_length(wsi-\u003eu.http.fop_fd);\n+\tcomputed_total_content_length \u003d wsi-\u003eu.http.filelen;\n+\n+#if defined(LWS_WITH_RANGES)\n+\tranges \u003d lws_ranges_init(wsi, rp, wsi-\u003eu.http.filelen);\n+\n+\tlwsl_debug(\u0022Range count %d\u005cn\u0022, ranges);\n+\t/*\n+\t * no ranges -\u003e 200;\n+\t * 1 range -\u003e 206 + Content-Type: normal; Content-Range;\n+\t * more -\u003e 206 + Content-Type: multipart/byteranges\n+\t * \t\tRepeat the true Content-Type in each multipart header\n+\t * \t\talong with Content-Range\n+\t */\n+\tif (ranges \u003c 0) {\n+\t\t/* it means he expressed a range in Range:, but it was illegal */\n+\t\tlws_return_http_status(wsi, HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE,\n+\t\t\t\t NULL);\n+\t\tif (lws_http_transaction_completed(wsi))\n+\t\t\treturn -1; /* \u003c0 means just hang up */\n+\n+\t\tlws_vfs_file_close(\u0026wsi-\u003eu.http.fop_fd);\n+\n+\t\treturn 0; /* \u003d\u003d 0 means we dealt with the transaction complete */\n+\t}\n+\tif (ranges)\n+\t\tn \u003d HTTP_STATUS_PARTIAL_CONTENT;\n+#endif\n+\n+\tif (lws_add_http_header_status(wsi, n, \u0026p, end))\n+\t\treturn -1;\n+\n+\tif ((wsi-\u003eu.http.fop_fd-\u003eflags \u0026 (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |\n+\t\t LWS_FOP_FLAG_COMPR_IS_GZIP)) \u003d\u003d\n+\t (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {\n+\t\tif (lws_add_http_header_by_token(wsi,\n+\t\t\tWSI_TOKEN_HTTP_CONTENT_ENCODING,\n+\t\t\t(unsigned char *)\u0022gzip\u0022, 4, \u0026p, end))\n+\t\t\treturn -1;\n+\t\tlwsl_info(\u0022file is being provided in gzip\u005cn\u0022);\n+\t}\n+\n+\tif (\n+#if defined(LWS_WITH_RANGES)\n+\t ranges \u003c 2 \u0026\u0026\n+#endif\n+\t content_type \u0026\u0026 content_type[0])\n+\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,\n+\t\t\t\t\t\t (unsigned char *)content_type,\n+\t\t\t\t\t\t strlen(content_type), \u0026p, end))\n+\t\t\treturn -1;\n+\n+#if defined(LWS_WITH_RANGES)\n+\tif (ranges \u003e\u003d 2) { /* multipart byteranges */\n+\t\tstrncpy(wsi-\u003eu.http.multipart_content_type, content_type,\n+\t\t\tsizeof(wsi-\u003eu.http.multipart_content_type) - 1);\n+\t\twsi-\u003eu.http.multipart_content_type[\n+\t\t sizeof(wsi-\u003eu.http.multipart_content_type) - 1] \u003d '\u005c0';\n+\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,\n+\t\t\t (unsigned char *)\u0022multipart/byteranges; boundary\u003d_lws\u0022,\n+\t\t\t 20, \u0026p, end))\n+\t\t\treturn -1;\n+\n+\t\t/*\n+\t\t * our overall content length has to include\n+\t\t *\n+\t\t * - (n + 1) x \u0022_lws\u005cr\u005cn\u0022\n+\t\t * - n x Content-Type: xxx/xxx\u005cr\u005cn\n+\t\t * - n x Content-Range: bytes xxx-yyy/zzz\u005cr\u005cn\n+\t\t * - n x /r/n\n+\t\t * - the actual payloads (aggregated in rp-\u003eagg)\n+\t\t *\n+\t\t * Precompute it for the main response header\n+\t\t */\n+\n+\t\tcomputed_total_content_length \u003d (lws_filepos_t)rp-\u003eagg +\n+\t\t\t\t\t\t6 /* final _lws\u005cr\u005cn */;\n+\n+\t\tlws_ranges_reset(rp);\n+\t\twhile (lws_ranges_next(rp)) {\n+\t\t\tn \u003d lws_snprintf(cache_control, sizeof(cache_control),\n+\t\t\t\t\t\u0022bytes %llu-%llu/%llu\u0022,\n+\t\t\t\t\trp-\u003estart, rp-\u003eend, rp-\u003eextent);\n+\n+\t\t\tcomputed_total_content_length +\u003d\n+\t\t\t\t6 /* header _lws\u005cr\u005cn */ +\n+\t\t\t\t/* Content-Type: xxx/xxx\u005cr\u005cn */\n+\t\t\t\t14 + strlen(content_type) + 2 +\n+\t\t\t\t/* Content-Range: xxxx\u005cr\u005cn */\n+\t\t\t\t15 + n + 2 +\n+\t\t\t\t2; /* /r/n */\n+\t\t}\n+\n+\t\tlws_ranges_reset(rp);\n+\t\tlws_ranges_next(rp);\n+\t}\n+\n+\tif (ranges \u003d\u003d 1) {\n+\t\tcomputed_total_content_length \u003d (lws_filepos_t)rp-\u003eagg;\n+\t\tn \u003d lws_snprintf(cache_control, sizeof(cache_control),\n+\t\t\t\t \u0022bytes %llu-%llu/%llu\u0022,\n+\t\t\t\t rp-\u003estart, rp-\u003eend, rp-\u003eextent);\n+\n+\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_RANGE,\n+\t\t\t\t\t\t (unsigned char *)cache_control,\n+\t\t\t\t\t\t n, \u0026p, end))\n+\t\t\treturn -1;\n+\t}\n+\n+\twsi-\u003eu.http.range.inside \u003d 0;\n+\n+\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ACCEPT_RANGES,\n+\t\t\t\t\t (unsigned char *)\u0022bytes\u0022, 5, \u0026p, end))\n+\t\treturn -1;\n+#endif\n+\n+\tif (!wsi-\u003esending_chunked) {\n+\t\tif (lws_add_http_header_content_length(wsi,\n+\t\t\t\t\t\t computed_total_content_length,\n+\t\t\t\t\t\t \u0026p, end))\n+\t\t\treturn -1;\n+\t} else {\n+\t\tif (lws_add_http_header_by_token(wsi,\n+\t\t\t\t\t\t WSI_TOKEN_HTTP_TRANSFER_ENCODING,\n+\t\t\t\t\t\t (unsigned char *)\u0022chunked\u0022,\n+\t\t\t\t\t\t 7, \u0026p, end))\n+\t\t\treturn -1;\n+\t}\n+\n+\tif (wsi-\u003ecache_secs \u0026\u0026 wsi-\u003ecache_reuse) {\n+\t\tif (wsi-\u003ecache_revalidate) {\n+\t\t\tcc \u003d cache_control;\n+\t\t\tcclen \u003d sprintf(cache_control, \u0022%s max-age: %u\u0022,\n+\t\t\t\t intermediates[wsi-\u003ecache_intermediaries],\n+\t\t\t\t wsi-\u003ecache_secs);\n+\t\t} else {\n+\t\t\tcc \u003d \u0022no-cache\u0022;\n+\t\t\tcclen \u003d 8;\n+\t\t}\n+\t}\n+\n+\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CACHE_CONTROL,\n+\t\t\t(unsigned char *)cc, cclen, \u0026p, end))\n+\t\treturn -1;\n+\n+\tif (wsi-\u003eu.http.connection_type \u003d\u003d HTTP_CONNECTION_KEEP_ALIVE)\n+\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,\n+\t\t\t\t(unsigned char *)\u0022keep-alive\u0022, 10, \u0026p, end))\n+\t\t\treturn -1;\n+\n+\tif (other_headers) {\n+\t\tif ((end - p) \u003c other_headers_len)\n+\t\t\treturn -1;\n+\t\tmemcpy(p, other_headers, other_headers_len);\n+\t\tp +\u003d other_headers_len;\n+\t}\n+\n+\tif (lws_finalize_http_header(wsi, \u0026p, end))\n+\t\treturn -1;\n+\n+\tret \u003d lws_write(wsi, response, p - response, LWS_WRITE_HTTP_HEADERS);\n+\tif (ret !\u003d (p - response)) {\n+\t\tlwsl_err(\u0022_write returned %d from %ld\u005cn\u0022, ret,\n+\t\t\t (long)(p - response));\n+\t\treturn -1;\n+\t}\n+\n+\twsi-\u003eu.http.filepos \u003d 0;\n+\twsi-\u003estate \u003d LWSS_HTTP_ISSUING_FILE;\n+\n+\tlws_callback_on_writable(wsi);\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len)\n+{\n+\tint m;\n+\n+\tlwsl_parser(\u0022%s: received %d byte packet\u005cn\u0022, __func__, (int)len);\n+#if 0\n+\tlwsl_hexdump(*buf, len);\n+#endif\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\tlws_rxflow_cache(wsi, *buf, 0, len);\n+\t\t\tlwsl_parser(\u0022%s: cached %ld\u005cn\u0022, __func__, (long)len);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tif (wsi-\u003eu.ws.rx_draining_ext) {\n+\t\t\tm \u003d lws_rx_sm(wsi, 0);\n+\t\t\tif (m \u003c 0)\n+\t\t\t\treturn -1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* account for what we're using in rxflow buffer */\n+\t\tif (wsi-\u003erxflow_buffer) {\n+\t\t\twsi-\u003erxflow_pos++;\n+\t\t\tassert(wsi-\u003erxflow_pos \u003c\u003d wsi-\u003erxflow_len);\n+\t\t}\n+\n+\t\t/* consume payload bytes efficiently */\n+\t\tif (\n+\t\t wsi-\u003elws_rx_parse_state \u003d\u003d\n+\t\t LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED) {\n+\t\t\tm \u003d lws_payload_until_length_exhausted(wsi, buf, \u0026len);\n+\t\t\tif (wsi-\u003erxflow_buffer)\n+\t\t\t\twsi-\u003erxflow_pos +\u003d m;\n+\t\t}\n+\n+\t\t/* process the byte */\n+\t\tm \u003d lws_rx_sm(wsi, *(*buf)++);\n+\t\tif (m \u003c 0)\n+\t\t\treturn -1;\n+\t\tlen--;\n+\t}\n+\n+\tlwsl_parser(\u0022%s: exit with %d unused\u005cn\u0022, __func__, (int)len);\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE void\n+lws_server_get_canonical_hostname(struct lws_context *context,\n+\t\t\t\t struct lws_context_creation_info *info)\n+{\n+\tif (lws_check_opt(info-\u003eoptions,\n+\t\t\tLWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))\n+\t\treturn;\n+#if LWS_POSIX \u0026\u0026 !defined(LWS_WITH_ESP32)\n+\t/* find canonical hostname */\n+\tgethostname((char *)context-\u003ecanonical_hostname,\n+\t\t sizeof(context-\u003ecanonical_hostname) - 1);\n+\n+\tlwsl_info(\u0022 canonical_hostname \u003d %s\u005cn\u0022, context-\u003ecanonical_hostname);\n+#else\n+\t(void)context;\n+#endif\n+}\n+\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_chunked_html_process(struct lws_process_html_args *args,\n+\t\t\t struct lws_process_html_state *s)\n+{\n+\tchar *sp, buffer[32];\n+\tconst char *pc;\n+\tint old_len, n;\n+\n+\t/* do replacements */\n+\tsp \u003d args-\u003ep;\n+\told_len \u003d args-\u003elen;\n+\targs-\u003elen \u003d 0;\n+\ts-\u003estart \u003d sp;\n+\twhile (sp \u003c args-\u003ep + old_len) {\n+\n+\t\tif (args-\u003elen + 7 \u003e\u003d args-\u003emax_len) {\n+\t\t\tlwsl_err(\u0022Used up interpret padding\u005cn\u0022);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif ((!s-\u003epos \u0026\u0026 *sp \u003d\u003d '$') || s-\u003epos) {\n+\t\t\tint hits \u003d 0, hit \u003d 0;\n+\n+\t\t\tif (!s-\u003epos)\n+\t\t\t\ts-\u003estart \u003d sp;\n+\t\t\ts-\u003eswallow[s-\u003epos++] \u003d *sp;\n+\t\t\tif (s-\u003epos \u003d\u003d sizeof(s-\u003eswallow) - 1)\n+\t\t\t\tgoto skip;\n+\t\t\tfor (n \u003d 0; n \u003c s-\u003ecount_vars; n++)\n+\t\t\t\tif (!strncmp(s-\u003eswallow, s-\u003evars[n], s-\u003epos)) {\n+\t\t\t\t\thits++;\n+\t\t\t\t\thit \u003d n;\n+\t\t\t\t}\n+\t\t\tif (!hits) {\n+skip:\n+\t\t\t\ts-\u003eswallow[s-\u003epos] \u003d '\u005c0';\n+\t\t\t\tmemcpy(s-\u003estart, s-\u003eswallow, s-\u003epos);\n+\t\t\t\targs-\u003elen++;\n+\t\t\t\ts-\u003epos \u003d 0;\n+\t\t\t\tsp \u003d s-\u003estart + 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (hits \u003d\u003d 1 \u0026\u0026 s-\u003epos \u003d\u003d strlen(s-\u003evars[hit])) {\n+\t\t\t\tpc \u003d s-\u003ereplace(s-\u003edata, hit);\n+\t\t\t\tif (!pc)\n+\t\t\t\t\tpc \u003d \u0022NULL\u0022;\n+\t\t\t\tn \u003d strlen(pc);\n+\t\t\t\ts-\u003eswallow[s-\u003epos] \u003d '\u005c0';\n+\t\t\t\tif (n !\u003d s-\u003epos) {\n+\t\t\t\t\tmemmove(s-\u003estart + n,\n+\t\t\t\t\t\ts-\u003estart + s-\u003epos,\n+\t\t\t\t\t\told_len - (sp - args-\u003ep));\n+\t\t\t\t\told_len +\u003d (n - s-\u003epos) + 1;\n+\t\t\t\t}\n+\t\t\t\tmemcpy(s-\u003estart, pc, n);\n+\t\t\t\targs-\u003elen++;\n+\t\t\t\tsp \u003d s-\u003estart + 1;\n+\n+\t\t\t\ts-\u003epos \u003d 0;\n+\t\t\t}\n+\t\t\tsp++;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\targs-\u003elen++;\n+\t\tsp++;\n+\t}\n+\n+\t/* no space left for final chunk trailer */\n+\tif (args-\u003efinal \u0026\u0026 args-\u003elen + 7 \u003e\u003d args-\u003emax_len)\n+\t\treturn -1;\n+\n+\tn \u003d sprintf(buffer, \u0022%X\u005cx0d\u005cx0a\u0022, args-\u003elen);\n+\n+\targs-\u003ep -\u003d n;\n+\tmemcpy(args-\u003ep, buffer, n);\n+\targs-\u003elen +\u003d n;\n+\n+\tif (args-\u003efinal) {\n+\t\tsp \u003d args-\u003ep + args-\u003elen;\n+\t\t*sp++ \u003d '\u005cx0d';\n+\t\t*sp++ \u003d '\u005cx0a';\n+\t\t*sp++ \u003d '0';\n+\t\t*sp++ \u003d '\u005cx0d';\n+\t\t*sp++ \u003d '\u005cx0a';\n+\t\t*sp++ \u003d '\u005cx0d';\n+\t\t*sp++ \u003d '\u005cx0a';\n+\t\targs-\u003elen +\u003d 7;\n+\t} else {\n+\t\tsp \u003d args-\u003ep + args-\u003elen;\n+\t\t*sp++ \u003d '\u005cx0d';\n+\t\t*sp++ \u003d '\u005cx0a';\n+\t\targs-\u003elen +\u003d 2;\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/lib/server/ssl-server.c b/lib/server/ssl-server.c\nnew file mode 100644\nindex 0000000..a9516f2\n--- /dev/null\n+++ b/lib/server/ssl-server.c\n@@ -0,0 +1,477 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022private-libwebsockets.h\u0022\n+\n+extern int openssl_websocket_private_data_index,\n+ openssl_SSL_CTX_private_data_index;\n+\n+extern void\n+lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);\n+\n+#if !defined(LWS_WITH_MBEDTLS)\n+static int\n+OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)\n+{\n+\tSSL *ssl;\n+\tint n;\n+\tstruct lws *wsi;\n+\n+\tssl \u003d X509_STORE_CTX_get_ex_data(x509_ctx,\n+\t\tSSL_get_ex_data_X509_STORE_CTX_idx());\n+\n+\t/*\n+\t * !!! nasty openssl requires the index to come as a library-scope\n+\t * static\n+\t */\n+\twsi \u003d SSL_get_ex_data(ssl, openssl_websocket_private_data_index);\n+\n+\tn \u003d wsi-\u003evhost-\u003eprotocols[0].callback(wsi,\n+\t\t\tLWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,\n+\t\t\t\t\t x509_ctx, ssl, preverify_ok);\n+\n+\t/* convert return code from 0 \u003d OK to 1 \u003d OK */\n+\treturn !n;\n+}\n+#endif\n+\n+static int\n+lws_context_ssl_init_ecdh(struct lws_vhost *vhost)\n+{\n+#ifdef LWS_SSL_SERVER_WITH_ECDH_CERT\n+\tEC_KEY *EC_key \u003d NULL;\n+\tEVP_PKEY *pkey;\n+\tint KeyType;\n+\tX509 *x;\n+\n+\tif (!lws_check_opt(vhost-\u003econtext-\u003eoptions, LWS_SERVER_OPTION_SSL_ECDH))\n+\t\treturn 0;\n+\n+\tlwsl_notice(\u0022 Using ECDH certificate support\u005cn\u0022);\n+\n+\t/* Get X509 certificate from ssl context */\n+\tx \u003d sk_X509_value(vhost-\u003essl_ctx-\u003eextra_certs, 0);\n+\tif (!x) {\n+\t\tlwsl_err(\u0022%s: x is NULL\u005cn\u0022, __func__);\n+\t\treturn 1;\n+\t}\n+\t/* Get the public key from certificate */\n+\tpkey \u003d X509_get_pubkey(x);\n+\tif (!pkey) {\n+\t\tlwsl_err(\u0022%s: pkey is NULL\u005cn\u0022, __func__);\n+\n+\t\treturn 1;\n+\t}\n+\t/* Get the key type */\n+\tKeyType \u003d EVP_PKEY_type(pkey-\u003etype);\n+\n+\tif (EVP_PKEY_EC !\u003d KeyType) {\n+\t\tlwsl_notice(\u0022Key type is not EC\u005cn\u0022);\n+\t\treturn 0;\n+\t}\n+\t/* Get the key */\n+\tEC_key \u003d EVP_PKEY_get1_EC_KEY(pkey);\n+\t/* Set ECDH parameter */\n+\tif (!EC_key) {\n+\t\tlwsl_err(\u0022%s: ECDH key is NULL \u005cn\u0022, __func__);\n+\t\treturn 1;\n+\t}\n+\tSSL_CTX_set_tmp_ecdh(vhost-\u003essl_ctx, EC_key);\n+\tEC_KEY_free(EC_key);\n+#endif\n+\treturn 0;\n+}\n+\n+static int\n+lws_context_ssl_init_ecdh_curve(struct lws_context_creation_info *info,\n+\t\t\t\tstruct lws_vhost *vhost)\n+{\n+#if defined(LWS_HAVE_OPENSSL_ECDH_H) \u0026\u0026 !defined(LWS_WITH_MBEDTLS)\n+\tEC_KEY *ecdh;\n+\tint ecdh_nid;\n+\tconst char *ecdh_curve \u003d \u0022prime256v1\u0022;\n+\n+\tif (info-\u003eecdh_curve)\n+\t\tecdh_curve \u003d info-\u003eecdh_curve;\n+\n+\tecdh_nid \u003d OBJ_sn2nid(ecdh_curve);\n+\tif (NID_undef \u003d\u003d ecdh_nid) {\n+\t\tlwsl_err(\u0022SSL: Unknown curve name '%s'\u0022, ecdh_curve);\n+\t\treturn 1;\n+\t}\n+\n+\tecdh \u003d EC_KEY_new_by_curve_name(ecdh_nid);\n+\tif (NULL \u003d\u003d ecdh) {\n+\t\tlwsl_err(\u0022SSL: Unable to create curve '%s'\u0022, ecdh_curve);\n+\t\treturn 1;\n+\t}\n+\tSSL_CTX_set_tmp_ecdh(vhost-\u003essl_ctx, ecdh);\n+\tEC_KEY_free(ecdh);\n+\n+\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_SINGLE_ECDH_USE);\n+\n+\tlwsl_notice(\u0022 SSL ECDH curve '%s'\u005cn\u0022, ecdh_curve);\n+#else\n+#if !defined(LWS_WITH_MBEDTLS)\n+\tlwsl_notice(\u0022 OpenSSL doesn't support ECDH\u005cn\u0022);\n+#endif\n+#endif\n+\treturn 0;\n+}\n+\n+#if !defined(LWS_WITH_MBEDTLS) \u0026\u0026 defined(SSL_TLSEXT_ERR_NOACK) \u0026\u0026 !defined(OPENSSL_NO_TLSEXT)\n+static int\n+lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)\n+{\n+\tstruct lws_context *context \u003d (struct lws_context *)arg;\n+\tstruct lws_vhost *vhost, *vh;\n+\tconst char *servername;\n+\n+\tif (!ssl)\n+\t\treturn SSL_TLSEXT_ERR_NOACK;\n+\n+\t/*\n+\t * We can only get ssl accepted connections by using a vhost's ssl_ctx\n+\t * find out which listening one took us and only match vhosts on the\n+\t * same port.\n+\t */\n+\tvh \u003d context-\u003evhost_list;\n+\twhile (vh) {\n+\t\tif (!vh-\u003ebeing_destroyed \u0026\u0026 vh-\u003essl_ctx \u003d\u003d SSL_get_SSL_CTX(ssl))\n+\t\t\tbreak;\n+\t\tvh \u003d vh-\u003evhost_next;\n+\t}\n+\n+\tif (!vh) {\n+\t\tassert(vh); /* can't match the incoming vh? */\n+\t\treturn SSL_TLSEXT_ERR_OK;\n+\t}\n+\n+\tservername \u003d SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);\n+\tif (!servername) {\n+\t\t/* the client doesn't know what hostname it wants */\n+\t\tlwsl_info(\u0022SNI: Unknown ServerName: %s\u005cn\u0022, servername);\n+\n+\t\treturn SSL_TLSEXT_ERR_OK;\n+\t}\n+\n+\tvhost \u003d lws_select_vhost(context, vh-\u003elisten_port, servername);\n+\tif (!vhost) {\n+\t\tlwsl_info(\u0022SNI: none: %s:%d\u005cn\u0022, servername, vh-\u003elisten_port);\n+\n+\t\treturn SSL_TLSEXT_ERR_OK;\n+\t}\n+\n+\tlwsl_info(\u0022SNI: Found: %s:%d\u005cn\u0022, servername, vh-\u003elisten_port);\n+\n+\t/* select the ssl ctx from the selected vhost for this conn */\n+\tSSL_set_SSL_CTX(ssl, vhost-\u003essl_ctx);\n+\n+\treturn SSL_TLSEXT_ERR_OK;\n+}\n+#endif\n+\n+LWS_VISIBLE int\n+lws_context_init_server_ssl(struct lws_context_creation_info *info,\n+\t\t\t struct lws_vhost *vhost)\n+{\n+\tstruct lws_context *context \u003d vhost-\u003econtext;\n+\tstruct lws wsi;\n+\tunsigned long error;\n+\tint n;\n+\n+\tif (!lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {\n+\t\tvhost-\u003euse_ssl \u003d 0;\n+\t\treturn 0;\n+\t}\n+\n+\t/*\n+\t * If he is giving a cert filepath, take it as a sign he wants to use\n+\t * it on this vhost. User code can leave the cert filepath NULL and\n+\t * set the LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX option itself, in\n+\t * which case he's expected to set up the cert himself at\n+\t * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which\n+\t * provides the vhost SSL_CTX * in the user parameter.\n+\t */\n+\tif (info-\u003essl_cert_filepath)\n+\t\tinfo-\u003eoptions |\u003d LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX;\n+\n+\tif (info-\u003eport !\u003d CONTEXT_PORT_NO_LISTEN) {\n+\n+\t\tvhost-\u003euse_ssl \u003d lws_check_opt(info-\u003eoptions,\n+\t\t\t\t\tLWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX);\n+\n+\t\tif (vhost-\u003euse_ssl \u0026\u0026 info-\u003essl_cipher_list)\n+\t\t\tlwsl_notice(\u0022 SSL ciphers: '%s'\u005cn\u0022, info-\u003essl_cipher_list);\n+\n+\t\tif (vhost-\u003euse_ssl)\n+\t\t\tlwsl_notice(\u0022 Using SSL mode\u005cn\u0022);\n+\t\telse\n+\t\t\tlwsl_notice(\u0022 Using non-SSL mode\u005cn\u0022);\n+\t}\n+\n+\t/*\n+\t * give him a fake wsi with context + vhost set, so he can use\n+\t * lws_get_context() in the callback\n+\t */\n+\tmemset(\u0026wsi, 0, sizeof(wsi));\n+\twsi.vhost \u003d vhost;\n+\twsi.context \u003d context;\n+\n+\t(void)n;\n+\t(void)error;\n+\n+\t/*\n+\t * Firefox insists on SSLv23 not SSLv3\n+\t * Konq disables SSLv2 by default now, SSLv23 works\n+\t *\n+\t * SSLv23_server_method() is the openssl method for \u0022allow all TLS\n+\t * versions\u0022, compared to e.g. TLSv1_2_server_method() which only allows\n+\t * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options()\n+\t */\n+#if !defined(LWS_WITH_MBEDTLS)\n+\t{\n+\t\tSSL_METHOD *method;\n+\n+\t\tmethod \u003d (SSL_METHOD *)SSLv23_server_method();\n+\t\tif (!method) {\n+\t\t\terror \u003d ERR_get_error();\n+\t\t\tlwsl_err(\u0022problem creating ssl method %lu: %s\u005cn\u0022,\n+\t\t\t\t\terror, ERR_error_string(error,\n+\t\t\t\t\t (char *)context-\u003ept[0].serv_buf));\n+\t\t\treturn 1;\n+\t\t}\n+\t\tvhost-\u003essl_ctx \u003d SSL_CTX_new(method);\t/* create context */\n+\t\tif (!vhost-\u003essl_ctx) {\n+\t\t\terror \u003d ERR_get_error();\n+\t\t\tlwsl_err(\u0022problem creating ssl context %lu: %s\u005cn\u0022,\n+\t\t\t\t\terror, ERR_error_string(error,\n+\t\t\t\t\t (char *)context-\u003ept[0].serv_buf));\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+#else\n+\t{\n+\t\tconst SSL_METHOD *method \u003d TLSv1_2_server_method();\n+\n+\t\tvhost-\u003essl_ctx \u003d SSL_CTX_new(method);\t/* create context */\n+\t\tif (!vhost-\u003essl_ctx) {\n+\t\t\tlwsl_err(\u0022problem creating ssl context\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t}\n+#endif\n+#if !defined(LWS_WITH_MBEDTLS)\n+\n+\t/* associate the lws context with the SSL_CTX */\n+\n+\tSSL_CTX_set_ex_data(vhost-\u003essl_ctx,\n+\t\t\topenssl_SSL_CTX_private_data_index, (char *)vhost-\u003econtext);\n+\t/* Disable SSLv2 and SSLv3 */\n+\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);\n+#ifdef SSL_OP_NO_COMPRESSION\n+\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_NO_COMPRESSION);\n+#endif\n+\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_SINGLE_DH_USE);\n+\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);\n+\n+\tif (info-\u003essl_cipher_list)\n+\t\tSSL_CTX_set_cipher_list(vhost-\u003essl_ctx,\n+\t\t\t\t\t\tinfo-\u003essl_cipher_list);\n+#endif\n+\n+\t/* as a server, are we requiring clients to identify themselves? */\n+\n+\tif (lws_check_opt(info-\u003eoptions,\n+\t\t\t LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) {\n+\t\tint verify_options \u003d SSL_VERIFY_PEER;\n+\n+\t\tif (!lws_check_opt(info-\u003eoptions,\n+\t\t\t\t LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))\n+\t\t\tverify_options |\u003d SSL_VERIFY_FAIL_IF_NO_PEER_CERT;\n+\n+#if !defined(LWS_WITH_MBEDTLS)\n+\t\tSSL_CTX_set_session_id_context(vhost-\u003essl_ctx,\n+\t\t\t\t(unsigned char *)context, sizeof(void *));\n+\n+\t\t/* absolutely require the client cert */\n+\n+\t\tSSL_CTX_set_verify(vhost-\u003essl_ctx,\n+\t\t verify_options, OpenSSL_verify_callback);\n+#endif\n+\t}\n+\n+#if !defined(LWS_WITH_MBEDTLS) \u0026\u0026 !defined(OPENSSL_NO_TLSEXT)\n+\tSSL_CTX_set_tlsext_servername_callback(vhost-\u003essl_ctx,\n+\t\t\t\t\t lws_ssl_server_name_cb);\n+\tSSL_CTX_set_tlsext_servername_arg(vhost-\u003essl_ctx, context);\n+#endif\n+\n+\t/*\n+\t * give user code a chance to load certs into the server\n+\t * allowing it to verify incoming client certs\n+\t */\n+#if !defined(LWS_WITH_MBEDTLS)\n+\tif (info-\u003essl_ca_filepath \u0026\u0026\n+\t !SSL_CTX_load_verify_locations(vhost-\u003essl_ctx,\n+\t\t\t\t\t info-\u003essl_ca_filepath, NULL)) {\n+\t\tlwsl_err(\u0022%s: SSL_CTX_load_verify_locations unhappy\u005cn\u0022, __func__);\n+\t}\n+#endif\n+\tif (vhost-\u003euse_ssl) {\n+\t\tif (lws_context_ssl_init_ecdh_curve(info, vhost))\n+\t\t\treturn -1;\n+\n+\t\tvhost-\u003eprotocols[0].callback(\u0026wsi,\n+\t\t\tLWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,\n+\t\t\tvhost-\u003essl_ctx, NULL, 0);\n+\t}\n+\n+\tif (lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT))\n+\t\t/* Normally SSL listener rejects non-ssl, optionally allow */\n+\t\tvhost-\u003eallow_non_ssl_on_ssl_port \u003d 1;\n+\n+\tif (info-\u003essl_options_set)\n+\t\tSSL_CTX_set_options(vhost-\u003essl_ctx, info-\u003essl_options_set);\n+\n+/* SSL_clear_options introduced in 0.9.8m */\n+#if !defined(LWS_WITH_MBEDTLS)\n+#if (OPENSSL_VERSION_NUMBER \u003e\u003d 0x009080df) \u0026\u0026 !defined(USE_WOLFSSL)\n+\tif (info-\u003essl_options_clear)\n+\t\tSSL_CTX_clear_options(vhost-\u003essl_ctx, info-\u003essl_options_clear);\n+#endif\n+#endif\n+\n+\tlwsl_info(\u0022 SSL options 0x%lX\u005cn\u0022, SSL_CTX_get_options(vhost-\u003essl_ctx));\n+\n+\tif (vhost-\u003euse_ssl \u0026\u0026 info-\u003essl_cert_filepath) {\n+\t\t/*\n+\t\t * The user code can choose to either pass the cert and\n+\t\t * key filepaths using the info members like this, or it can\n+\t\t * leave them NULL; force the vhost SSL_CTX init using the info\n+\t\t * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and\n+\t\t * set up the cert himself using the user callback\n+\t\t * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which\n+\t\t * happened just above and has the vhost SSL_CTX * in the user\n+\t\t * parameter.\n+\t\t */\n+#if !defined(LWS_WITH_MBEDTLS)\n+\t\t/* set the local certificate from CertFile */\n+\t\tn \u003d SSL_CTX_use_certificate_chain_file(vhost-\u003essl_ctx,\n+\t\t\t\t\tinfo-\u003essl_cert_filepath);\n+\t\tif (n !\u003d 1) {\n+\t\t\terror \u003d ERR_get_error();\n+\t\t\tlwsl_err(\u0022problem getting cert '%s' %lu: %s\u005cn\u0022,\n+\t\t\t\tinfo-\u003essl_cert_filepath,\n+\t\t\t\terror,\n+\t\t\t\tERR_error_string(error,\n+\t\t\t\t\t (char *)context-\u003ept[0].serv_buf));\n+\t\t\treturn 1;\n+\t\t}\n+\t\tlws_ssl_bind_passphrase(vhost-\u003essl_ctx, info);\n+#else\n+\t\tuint8_t *p;\n+\t\tlws_filepos_t flen;\n+\t\tint err;\n+\n+\t\tif (alloc_pem_to_der_file(vhost-\u003econtext, info-\u003essl_cert_filepath, \u0026p,\n+\t\t\t\t \u0026flen)) {\n+\t\t\tlwsl_err(\u0022couldn't find cert file %s\u005cn\u0022,\n+\t\t\t\t info-\u003essl_cert_filepath);\n+\n+\t\t\treturn 1;\n+\t\t}\n+\t\terr \u003d SSL_CTX_use_certificate_ASN1(vhost-\u003essl_ctx, flen, p);\n+\t\tif (!err) {\n+\t\t\tlwsl_err(\u0022Problem loading cert\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+#if !defined(LWS_WITH_ESP32)\n+\t\tfree(p);\n+\t\tp \u003d NULL;\n+#endif\n+\n+\t\tif (info-\u003essl_private_key_filepath) {\n+\t\t\tif (alloc_pem_to_der_file(vhost-\u003econtext,\n+\t\t\t\t info-\u003essl_private_key_filepath, \u0026p, \u0026flen)) {\n+\t\t\t\tlwsl_err(\u0022couldn't find cert file %s\u005cn\u0022,\n+\t\t\t\t\t info-\u003essl_cert_filepath);\n+\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t\terr \u003d SSL_CTX_use_PrivateKey_ASN1(0, vhost-\u003essl_ctx, p, flen);\n+\t\t\tif (!err) {\n+\t\t\t\tlwsl_err(\u0022Problem loading key\u005cn\u0022);\n+\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\t\t}\n+\n+#if !defined(LWS_WITH_ESP32)\n+\t\tfree(p);\n+\t\tp \u003d NULL;\n+#endif\n+#endif\n+\t\tif (info-\u003essl_private_key_filepath !\u003d NULL) {\n+#if !defined(LWS_WITH_MBEDTLS)\n+\t\t\t/* set the private key from KeyFile */\n+\t\t\tif (SSL_CTX_use_PrivateKey_file(vhost-\u003essl_ctx,\n+\t\t\t\t info-\u003essl_private_key_filepath,\n+\t\t\t\t\t\t SSL_FILETYPE_PEM) !\u003d 1) {\n+\t\t\t\terror \u003d ERR_get_error();\n+\t\t\t\tlwsl_err(\u0022ssl problem getting key '%s' %lu: %s\u005cn\u0022,\n+\t\t\t\t\t info-\u003essl_private_key_filepath, error,\n+\t\t\t\t\t ERR_error_string(error,\n+\t\t\t\t\t (char *)context-\u003ept[0].serv_buf));\n+\t\t\t\treturn 1;\n+\t\t\t}\n+#endif\n+\t\t} else\n+\t\t\tif (vhost-\u003eprotocols[0].callback(\u0026wsi,\n+\t\t\t\tLWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,\n+\t\t\t\tvhost-\u003essl_ctx, NULL, 0)) {\n+\t\t\t\tlwsl_err(\u0022ssl private key not set\u005cn\u0022);\n+\n+\t\t\t\treturn 1;\n+\t\t\t}\n+#if !defined(LWS_WITH_MBEDTLS)\n+\t\t/* verify private key */\n+\t\tif (!SSL_CTX_check_private_key(vhost-\u003essl_ctx)) {\n+\t\t\tlwsl_err(\u0022Private SSL key doesn't match cert\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+#endif\n+\t}\n+\tif (vhost-\u003euse_ssl) {\n+\t\tif (lws_context_ssl_init_ecdh(vhost))\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * SSL is happy and has a cert it's content with\n+\t\t * If we're supporting HTTP2, initialize that\n+\t\t */\n+\t\tlws_context_init_http2_ssl(vhost);\n+\t}\n+\n+\treturn 0;\n+}\n+\ndiff --git a/lib/sha-1.c b/lib/sha-1.c\ndeleted file mode 100644\nindex 9353fbe..0000000\n--- a/lib/sha-1.c\n+++ /dev/null\n@@ -1,300 +0,0 @@\n-/*\n- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.\n- * All rights reserved.\n- *\n- * Redistribution and use in source and binary forms, with or without\n- * modification, are permitted provided that the following conditions\n- * are met:\n- * 1. Redistributions of source code must retain the above copyright\n- * notice, this list of conditions and the following disclaimer.\n- * 2. Redistributions in binary form must reproduce the above copyright\n- * notice, this list of conditions and the following disclaimer in the\n- * documentation and/or other materials provided with the distribution.\n- * 3. Neither the name of the project nor the names of its contributors\n- * may be used to endorse or promote products derived from this software\n- * without specific prior written permission.\n- *\n- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND\n- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE\n- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n- * SUCH DAMAGE.\n- */\n-/*\n- * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)\n- * based on: http://csrc.nist.gov/fips/fip180-1.txt\n- * implemented by Jun-ichiro itojun Itoh \u003citojun@itojun.org\u003e\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-#ifdef LWS_HAVE_SYS_TYPES_H\n-#include \u003csys/types.h\u003e\n-#endif\n-\n-struct sha1_ctxt {\n-\tunion {\n-\t\tunsigned char\t\tb8[20];\n-\t\tunsigned int\t\tb32[5];\n-\t} h;\n-\tunion {\n-\t\tunsigned char\t\tb8[8];\n-\t\tu_int64_t\t\tb64[1];\n-\t} c;\n-\tunion {\n-\t\tunsigned char\t\tb8[64];\n-\t\tunsigned int\t\tb32[16];\n-\t} m;\n-\tunsigned char\t\t\tcount;\n-};\n-\n-/* sanity check */\n-#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)\n-# define unsupported 1\n-#elif BYTE_ORDER !\u003d BIG_ENDIAN\n-# if BYTE_ORDER !\u003d LITTLE_ENDIAN\n-# define unsupported 1\n-# endif\n-#endif\n-\n-#ifndef unsupported\n-\n-/* constant table */\n-static const unsigned int _K[] \u003d\n-\t\t\t{ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };\n-#define\tK(t)\t_K[(t) / 20]\n-\n-#define\tF0(b, c, d)\t(((b) \u0026 (c)) | ((~(b)) \u0026 (d)))\n-#define\tF1(b, c, d)\t(((b) ^ (c)) ^ (d))\n-#define\tF2(b, c, d)\t(((b) \u0026 (c)) | ((b) \u0026 (d)) | ((c) \u0026 (d)))\n-#define\tF3(b, c, d)\t(((b) ^ (c)) ^ (d))\n-\n-#define\tS(n, x)\t\t(((x) \u003c\u003c (n)) | ((x) \u003e\u003e (32 - n)))\n-\n-#define\tH(n)\t(ctxt-\u003eh.b32[(n)])\n-#define\tCOUNT\t(ctxt-\u003ecount)\n-#define\tBCOUNT\t(ctxt-\u003ec.b64[0] / 8)\n-#define\tW(n)\t(ctxt-\u003em.b32[(n)])\n-\n-#define\tPUTBYTE(x)\t{ \u005c\n-\tctxt-\u003em.b8[(COUNT % 64)] \u003d (x);\t\t\u005c\n-\tCOUNT++;\t\t\t\t\u005c\n-\tCOUNT %\u003d 64;\t\t\t\t\u005c\n-\tctxt-\u003ec.b64[0] +\u003d 8;\t\t\t\u005c\n-\tif (COUNT % 64 \u003d\u003d 0)\t\t\t\u005c\n-\t\tsha1_step(ctxt);\t\t\u005c\n-\t}\n-\n-#define\tPUTPAD(x)\t{ \u005c\n-\tctxt-\u003em.b8[(COUNT % 64)] \u003d (x);\t\t\u005c\n-\tCOUNT++;\t\t\t\t\u005c\n-\tCOUNT %\u003d 64;\t\t\t\t\u005c\n-\tif (COUNT % 64 \u003d\u003d 0)\t\t\t\u005c\n-\t\tsha1_step(ctxt);\t\t\u005c\n-\t}\n-\n-\n-static void\n-sha1_step(struct sha1_ctxt *ctxt)\n-{\n-\tunsigned int\ta, b, c, d, e, tmp;\n-\tsize_t t, s;\n-\n-#if BYTE_ORDER \u003d\u003d LITTLE_ENDIAN\n-\tstruct sha1_ctxt tctxt;\n-\n-\tmemcpy(\u0026tctxt.m.b8[0], \u0026ctxt-\u003em.b8[0], 64);\n-\tctxt-\u003em.b8[0] \u003d tctxt.m.b8[3]; ctxt-\u003em.b8[1] \u003d tctxt.m.b8[2];\n-\tctxt-\u003em.b8[2] \u003d tctxt.m.b8[1]; ctxt-\u003em.b8[3] \u003d tctxt.m.b8[0];\n-\tctxt-\u003em.b8[4] \u003d tctxt.m.b8[7]; ctxt-\u003em.b8[5] \u003d tctxt.m.b8[6];\n-\tctxt-\u003em.b8[6] \u003d tctxt.m.b8[5]; ctxt-\u003em.b8[7] \u003d tctxt.m.b8[4];\n-\tctxt-\u003em.b8[8] \u003d tctxt.m.b8[11]; ctxt-\u003em.b8[9] \u003d tctxt.m.b8[10];\n-\tctxt-\u003em.b8[10] \u003d tctxt.m.b8[9]; ctxt-\u003em.b8[11] \u003d tctxt.m.b8[8];\n-\tctxt-\u003em.b8[12] \u003d tctxt.m.b8[15]; ctxt-\u003em.b8[13] \u003d tctxt.m.b8[14];\n-\tctxt-\u003em.b8[14] \u003d tctxt.m.b8[13]; ctxt-\u003em.b8[15] \u003d tctxt.m.b8[12];\n-\tctxt-\u003em.b8[16] \u003d tctxt.m.b8[19]; ctxt-\u003em.b8[17] \u003d tctxt.m.b8[18];\n-\tctxt-\u003em.b8[18] \u003d tctxt.m.b8[17]; ctxt-\u003em.b8[19] \u003d tctxt.m.b8[16];\n-\tctxt-\u003em.b8[20] \u003d tctxt.m.b8[23]; ctxt-\u003em.b8[21] \u003d tctxt.m.b8[22];\n-\tctxt-\u003em.b8[22] \u003d tctxt.m.b8[21]; ctxt-\u003em.b8[23] \u003d tctxt.m.b8[20];\n-\tctxt-\u003em.b8[24] \u003d tctxt.m.b8[27]; ctxt-\u003em.b8[25] \u003d tctxt.m.b8[26];\n-\tctxt-\u003em.b8[26] \u003d tctxt.m.b8[25]; ctxt-\u003em.b8[27] \u003d tctxt.m.b8[24];\n-\tctxt-\u003em.b8[28] \u003d tctxt.m.b8[31]; ctxt-\u003em.b8[29] \u003d tctxt.m.b8[30];\n-\tctxt-\u003em.b8[30] \u003d tctxt.m.b8[29]; ctxt-\u003em.b8[31] \u003d tctxt.m.b8[28];\n-\tctxt-\u003em.b8[32] \u003d tctxt.m.b8[35]; ctxt-\u003em.b8[33] \u003d tctxt.m.b8[34];\n-\tctxt-\u003em.b8[34] \u003d tctxt.m.b8[33]; ctxt-\u003em.b8[35] \u003d tctxt.m.b8[32];\n-\tctxt-\u003em.b8[36] \u003d tctxt.m.b8[39]; ctxt-\u003em.b8[37] \u003d tctxt.m.b8[38];\n-\tctxt-\u003em.b8[38] \u003d tctxt.m.b8[37]; ctxt-\u003em.b8[39] \u003d tctxt.m.b8[36];\n-\tctxt-\u003em.b8[40] \u003d tctxt.m.b8[43]; ctxt-\u003em.b8[41] \u003d tctxt.m.b8[42];\n-\tctxt-\u003em.b8[42] \u003d tctxt.m.b8[41]; ctxt-\u003em.b8[43] \u003d tctxt.m.b8[40];\n-\tctxt-\u003em.b8[44] \u003d tctxt.m.b8[47]; ctxt-\u003em.b8[45] \u003d tctxt.m.b8[46];\n-\tctxt-\u003em.b8[46] \u003d tctxt.m.b8[45]; ctxt-\u003em.b8[47] \u003d tctxt.m.b8[44];\n-\tctxt-\u003em.b8[48] \u003d tctxt.m.b8[51]; ctxt-\u003em.b8[49] \u003d tctxt.m.b8[50];\n-\tctxt-\u003em.b8[50] \u003d tctxt.m.b8[49]; ctxt-\u003em.b8[51] \u003d tctxt.m.b8[48];\n-\tctxt-\u003em.b8[52] \u003d tctxt.m.b8[55]; ctxt-\u003em.b8[53] \u003d tctxt.m.b8[54];\n-\tctxt-\u003em.b8[54] \u003d tctxt.m.b8[53]; ctxt-\u003em.b8[55] \u003d tctxt.m.b8[52];\n-\tctxt-\u003em.b8[56] \u003d tctxt.m.b8[59]; ctxt-\u003em.b8[57] \u003d tctxt.m.b8[58];\n-\tctxt-\u003em.b8[58] \u003d tctxt.m.b8[57]; ctxt-\u003em.b8[59] \u003d tctxt.m.b8[56];\n-\tctxt-\u003em.b8[60] \u003d tctxt.m.b8[63]; ctxt-\u003em.b8[61] \u003d tctxt.m.b8[62];\n-\tctxt-\u003em.b8[62] \u003d tctxt.m.b8[61]; ctxt-\u003em.b8[63] \u003d tctxt.m.b8[60];\n-#endif\n-\n-\ta \u003d H(0); b \u003d H(1); c \u003d H(2); d \u003d H(3); e \u003d H(4);\n-\n-\tfor (t \u003d 0; t \u003c 20; t++) {\n-\t\ts \u003d t \u0026 0x0f;\n-\t\tif (t \u003e\u003d 16)\n-\t\t\tW(s) \u003d S(1, W((s+13) \u0026 0x0f) ^ W((s+8) \u0026 0x0f) ^\n-\t\t\t\t\t\t\tW((s+2) \u0026 0x0f) ^ W(s));\n-\n-\t\ttmp \u003d S(5, a) + F0(b, c, d) + e + W(s) + K(t);\n-\t\te \u003d d; d \u003d c; c \u003d S(30, b); b \u003d a; a \u003d tmp;\n-\t}\n-\tfor (t \u003d 20; t \u003c 40; t++) {\n-\t\ts \u003d t \u0026 0x0f;\n-\t\tW(s) \u003d S(1, W((s+13) \u0026 0x0f) ^ W((s+8) \u0026 0x0f) ^\n-\t\t\t\t\t\t\tW((s+2) \u0026 0x0f) ^ W(s));\n-\t\ttmp \u003d S(5, a) + F1(b, c, d) + e + W(s) + K(t);\n-\t\te \u003d d; d \u003d c; c \u003d S(30, b); b \u003d a; a \u003d tmp;\n-\t}\n-\tfor (t \u003d 40; t \u003c 60; t++) {\n-\t\ts \u003d t \u0026 0x0f;\n-\t\tW(s) \u003d S(1, W((s+13) \u0026 0x0f) ^ W((s+8) \u0026 0x0f) ^\n-\t\t\t\t\t\t\tW((s+2) \u0026 0x0f) ^ W(s));\n-\t\ttmp \u003d S(5, a) + F2(b, c, d) + e + W(s) + K(t);\n-\t\te \u003d d; d \u003d c; c \u003d S(30, b); b \u003d a; a \u003d tmp;\n-\t}\n-\tfor (t \u003d 60; t \u003c 80; t++) {\n-\t\ts \u003d t \u0026 0x0f;\n-\t\tW(s) \u003d S(1, W((s+13) \u0026 0x0f) ^ W((s+8) \u0026 0x0f) ^\n-\t\t\t\t\t\t\tW((s+2) \u0026 0x0f) ^ W(s));\n-\t\ttmp \u003d S(5, a) + F3(b, c, d) + e + W(s) + K(t);\n-\t\te \u003d d; d \u003d c; c \u003d S(30, b); b \u003d a; a \u003d tmp;\n-\t}\n-\n-\tH(0) \u003d H(0) + a;\n-\tH(1) \u003d H(1) + b;\n-\tH(2) \u003d H(2) + c;\n-\tH(3) \u003d H(3) + d;\n-\tH(4) \u003d H(4) + e;\n-\n-\tbzero(\u0026ctxt-\u003em.b8[0], 64);\n-}\n-\n-/*------------------------------------------------------------*/\n-\n-static void\n-_sha1_init(struct sha1_ctxt *ctxt)\n-{\n-\tbzero(ctxt, sizeof(struct sha1_ctxt));\n-\tH(0) \u003d 0x67452301;\n-\tH(1) \u003d 0xefcdab89;\n-\tH(2) \u003d 0x98badcfe;\n-\tH(3) \u003d 0x10325476;\n-\tH(4) \u003d 0xc3d2e1f0;\n-}\n-\n-void\n-sha1_pad(struct sha1_ctxt *ctxt)\n-{\n-\tsize_t padlen;\t\t/*pad length in bytes*/\n-\tsize_t padstart;\n-\n-\tPUTPAD(0x80);\n-\n-\tpadstart \u003d COUNT % 64;\n-\tpadlen \u003d 64 - padstart;\n-\tif (padlen \u003c 8) {\n-\t\tbzero(\u0026ctxt-\u003em.b8[padstart], padlen);\n-\t\tCOUNT +\u003d (unsigned char)padlen;\n-\t\tCOUNT %\u003d 64;\n-\t\tsha1_step(ctxt);\n-\t\tpadstart \u003d COUNT % 64;\t/* should be 0 */\n-\t\tpadlen \u003d 64 - padstart;\t/* should be 64 */\n-\t}\n-\tbzero(\u0026ctxt-\u003em.b8[padstart], padlen - 8);\n-\tCOUNT +\u003d ((unsigned char)padlen - 8);\n-\tCOUNT %\u003d 64;\n-#if BYTE_ORDER \u003d\u003d BIG_ENDIAN\n-\tPUTPAD(ctxt-\u003ec.b8[0]); PUTPAD(ctxt-\u003ec.b8[1]);\n-\tPUTPAD(ctxt-\u003ec.b8[2]); PUTPAD(ctxt-\u003ec.b8[3]);\n-\tPUTPAD(ctxt-\u003ec.b8[4]); PUTPAD(ctxt-\u003ec.b8[5]);\n-\tPUTPAD(ctxt-\u003ec.b8[6]); PUTPAD(ctxt-\u003ec.b8[7]);\n-#else\n-\tPUTPAD(ctxt-\u003ec.b8[7]); PUTPAD(ctxt-\u003ec.b8[6]);\n-\tPUTPAD(ctxt-\u003ec.b8[5]); PUTPAD(ctxt-\u003ec.b8[4]);\n-\tPUTPAD(ctxt-\u003ec.b8[3]); PUTPAD(ctxt-\u003ec.b8[2]);\n-\tPUTPAD(ctxt-\u003ec.b8[1]); PUTPAD(ctxt-\u003ec.b8[0]);\n-#endif\n-}\n-\n-void\n-sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len)\n-{\n-\tsize_t gaplen;\n-\tsize_t gapstart;\n-\tsize_t off;\n-\tsize_t copysiz;\n-\n-\toff \u003d 0;\n-\n-\twhile (off \u003c len) {\n-\t\tgapstart \u003d COUNT % 64;\n-\t\tgaplen \u003d 64 - gapstart;\n-\n-\t\tcopysiz \u003d (gaplen \u003c len - off) ? gaplen : len - off;\n-\t\tmemcpy(\u0026ctxt-\u003em.b8[gapstart], \u0026input[off], copysiz);\n-\t\tCOUNT +\u003d (unsigned char)copysiz;\n-\t\tCOUNT %\u003d 64;\n-\t\tctxt-\u003ec.b64[0] +\u003d copysiz * 8;\n-\t\tif (COUNT % 64 \u003d\u003d 0)\n-\t\t\tsha1_step(ctxt);\n-\t\toff +\u003d copysiz;\n-\t}\n-}\n-\n-void\n-sha1_result(struct sha1_ctxt *ctxt, void *digest0)\n-{\n-\tunsigned char *digest;\n-\n-\tdigest \u003d (unsigned char *)digest0;\n-\tsha1_pad(ctxt);\n-#if BYTE_ORDER \u003d\u003d BIG_ENDIAN\n-\tmemcpy(digest, \u0026ctxt-\u003eh.b8[0], 20);\n-#else\n-\tdigest[0] \u003d ctxt-\u003eh.b8[3]; digest[1] \u003d ctxt-\u003eh.b8[2];\n-\tdigest[2] \u003d ctxt-\u003eh.b8[1]; digest[3] \u003d ctxt-\u003eh.b8[0];\n-\tdigest[4] \u003d ctxt-\u003eh.b8[7]; digest[5] \u003d ctxt-\u003eh.b8[6];\n-\tdigest[6] \u003d ctxt-\u003eh.b8[5]; digest[7] \u003d ctxt-\u003eh.b8[4];\n-\tdigest[8] \u003d ctxt-\u003eh.b8[11]; digest[9] \u003d ctxt-\u003eh.b8[10];\n-\tdigest[10] \u003d ctxt-\u003eh.b8[9]; digest[11] \u003d ctxt-\u003eh.b8[8];\n-\tdigest[12] \u003d ctxt-\u003eh.b8[15]; digest[13] \u003d ctxt-\u003eh.b8[14];\n-\tdigest[14] \u003d ctxt-\u003eh.b8[13]; digest[15] \u003d ctxt-\u003eh.b8[12];\n-\tdigest[16] \u003d ctxt-\u003eh.b8[19]; digest[17] \u003d ctxt-\u003eh.b8[18];\n-\tdigest[18] \u003d ctxt-\u003eh.b8[17]; digest[19] \u003d ctxt-\u003eh.b8[16];\n-#endif\n-}\n-\n-/*\n- * This should look and work like the libcrypto implementation\n- */\n-\n-LWS_VISIBLE unsigned char *\n-lws_SHA1(const unsigned char *d, size_t n, unsigned char *md)\n-{\n-\tstruct sha1_ctxt ctx;\n-\n-\t_sha1_init(\u0026ctx);\n-\tsha1_loop(\u0026ctx, d, n);\n-\tsha1_result(\u0026ctx, (void *)md);\n-\n-\treturn md;\n-}\n-\n-#endif /*unsupported*/\ndiff --git a/lib/smtp.c b/lib/smtp.c\ndeleted file mode 100644\nindex 9eaa059..0000000\n--- a/lib/smtp.c\n+++ /dev/null\n@@ -1,241 +0,0 @@\n-/*\n- * SMTP support for libwebsockets\n- *\n- * Copyright (C) 2016 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This program is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * General Public License for more details.\n- *\n- * You should have received a copy of the GNU General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-static unsigned int\n-lwsgs_now_secs(void)\n-{\n-\tstruct timeval tv;\n-\n-\tgettimeofday(\u0026tv, NULL);\n-\n-\treturn tv.tv_sec;\n-}\n-\n-static void\n-ccb(uv_handle_t* handle)\n-{\n-\n-}\n-\n-static void\n-alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)\n-{\n-\tstruct lws_email *email \u003d (struct lws_email *)handle-\u003edata;\n-\n-\t*buf \u003d uv_buf_init(email-\u003eemail_buf, sizeof(email-\u003eemail_buf) - 1);\n-}\n-\n-static void\n-on_write_end(uv_write_t *req, int status) {\n-\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n-\tif (status \u003d\u003d -1) {\n-\t\tfprintf(stderr, \u0022error on_write_end\u0022);\n-\t\treturn;\n-\t}\n-}\n-\n-static void\n-lwsgs_email_read(struct uv_stream_s *s, ssize_t nread, const uv_buf_t *buf)\n-{\n-\tstruct lws_email *email \u003d (struct lws_email *)s-\u003edata;\n-\tstatic const short retcodes[] \u003d {\n-\t\t0,\t/* idle */\n-\t\t0,\t/* connecting */\n-\t\t220,\t/* connected */\n-\t\t250,\t/* helo */\n-\t\t250,\t/* from */\n-\t\t250,\t/* to */\n-\t\t354,\t/* data */\n-\t\t250,\t/* body */\n-\t\t221,\t/* quit */\n-\t};\n-\tuv_write_t write_req;\n-\tuv_buf_t wbuf;\n-\tint n;\n-\n-\tif (nread \u003e\u003d 0)\n-\t\temail-\u003eemail_buf[nread] \u003d '\u005c0';\n-\tlwsl_notice(\u0022%s: %s\u005cn\u0022, __func__, buf-\u003ebase);\n-\tif (nread \u003d\u003d -1) {\n-\t\tlwsl_err(\u0022%s: failed\u005cn\u0022, __func__);\n-\t\treturn;\n-\t}\n-\n-\tn \u003d atoi(buf-\u003ebase);\n-\tif (n !\u003d retcodes[email-\u003eestate]) {\n-\t\tlwsl_err(\u0022%s: bad response from server\u005cn\u0022, __func__);\n-\t\tgoto close_conn;\n-\t}\n-\n-\tswitch (email-\u003eestate) {\n-\tcase LGSSMTP_CONNECTED:\n-\t\tn \u003d sprintf(email-\u003econtent, \u0022HELO %s\u005cn\u0022, email-\u003eemail_helo);\n-\t\temail-\u003eestate \u003d LGSSMTP_SENT_HELO;\n-\t\tbreak;\n-\tcase LGSSMTP_SENT_HELO:\n-\t\tn \u003d sprintf(email-\u003econtent, \u0022MAIL FROM: \u003c%s\u003e\u005cn\u0022, email-\u003eemail_from);\n-\t\temail-\u003eestate \u003d LGSSMTP_SENT_FROM;\n-\t\tbreak;\n-\tcase LGSSMTP_SENT_FROM:\n-\t\tn \u003d sprintf(email-\u003econtent, \u0022RCPT TO: \u003c%s\u003e\u005cn\u0022, email-\u003eemail_to);\n-\t\temail-\u003eestate \u003d LGSSMTP_SENT_TO;\n-\t\tbreak;\n-\tcase LGSSMTP_SENT_TO:\n-\t\tn \u003d sprintf(email-\u003econtent, \u0022DATA\u005cn\u0022);\n-\t\temail-\u003eestate \u003d LGSSMTP_SENT_DATA;\n-\t\tbreak;\n-\tcase LGSSMTP_SENT_DATA:\n-\t\tif (email-\u003eon_get_body(email, email-\u003econtent, email-\u003emax_content_size))\n-\t\t\treturn;\n-\t\tn \u003d strlen(email-\u003econtent);\n-\t\temail-\u003eestate \u003d LGSSMTP_SENT_BODY;\n-\t\tbreak;\n-\tcase LGSSMTP_SENT_BODY:\n-\t\tn \u003d sprintf(email-\u003econtent, \u0022quit\u005cn\u0022);\n-\t\temail-\u003eestate \u003d LGSSMTP_SENT_QUIT;\n-\t\tbreak;\n-\tcase LGSSMTP_SENT_QUIT:\n-\t\tlwsl_notice(\u0022%s: done\u005cn\u0022, __func__);\n-\t\temail-\u003eon_sent(email);\n-\t\temail-\u003eestate \u003d LGSSMTP_IDLE;\n-\t\tgoto close_conn;\n-\tdefault:\n-\t\treturn;\n-\t}\n-\n-\tputs(email-\u003econtent);\n-\twbuf \u003d uv_buf_init(email-\u003econtent, n);\n-\tuv_write(\u0026write_req, s, \u0026wbuf, 1, on_write_end);\n-\n-\treturn;\n-\n-close_conn:\n-\n-\tuv_close((uv_handle_t *)s, ccb);\n-}\n-\n-static void\n-lwsgs_email_on_connect(uv_connect_t *req, int status)\n-{\n-\tstruct lws_email *email \u003d (struct lws_email *)req-\u003edata;\n-\n-\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n-\n-\tif (status \u003d\u003d -1) {\n-\t\tlwsl_err(\u0022%s: failed\u005cn\u0022, __func__);\n-\t\treturn;\n-\t}\n-\n-\tuv_read_start(req-\u003ehandle, alloc_buffer, lwsgs_email_read);\n-\temail-\u003eestate \u003d LGSSMTP_CONNECTED;\n-}\n-\n-\n-static void\n-uv_timeout_cb_email(uv_timer_t *w\n-#if UV_VERSION_MAJOR \u003d\u003d 0\n-\t\t, int status\n-#endif\n-)\n-{\n-\tstruct lws_email *email \u003d lws_container_of(w, struct lws_email,\n-\t\t\t\t\t\t timeout_email);\n-\ttime_t now \u003d lwsgs_now_secs();\n-\tstruct sockaddr_in req_addr;\n-\n-\tswitch (email-\u003eestate) {\n-\tcase LGSSMTP_IDLE:\n-\n-\t\tif (email-\u003eon_next(email))\n-\t\t\tbreak;\n-\n-\t\temail-\u003eestate \u003d LGSSMTP_CONNECTING;\n-\n-\t\tuv_tcp_init(email-\u003eloop, \u0026email-\u003eemail_client);\n-\t\tif (uv_ip4_addr(email-\u003eemail_smtp_ip, 25, \u0026req_addr)) {\n-\t\t\tlwsl_err(\u0022Unable to convert mailserver ads\u005cn\u0022);\n-\t\t\treturn;\n-\t\t}\n-\n-\t\tlwsl_notice(\u0022LGSSMTP_IDLE: connecting\u005cn\u0022);\n-\n-\t\temail-\u003eemail_connect_started \u003d now;\n-\t\temail-\u003eemail_connect_req.data \u003d email;\n-\t\temail-\u003eemail_client.data \u003d email;\n-\t\tuv_tcp_connect(\u0026email-\u003eemail_connect_req, \u0026email-\u003eemail_client,\n-\t\t\t (struct sockaddr *)\u0026req_addr,\n-\t\t\t lwsgs_email_on_connect);\n-\n-\t\tuv_timer_start(\u0026email-\u003etimeout_email,\n-\t\t\t uv_timeout_cb_email, 5000, 0);\n-\n-\t\tbreak;\n-\n-\tcase LGSSMTP_CONNECTING:\n-\t\tif (email-\u003eemail_connect_started - now \u003e 5) {\n-\t\t\tlwsl_err(\u0022mail session timed out\u005cn\u0022);\n-\t\t\t/* !!! kill the connection */\n-\t\t\tuv_close((uv_handle_t *) \u0026email-\u003eemail_connect_req, ccb);\n-\t\t\temail-\u003eestate \u003d LGSSMTP_IDLE;\n-\t\t}\n-\t\tbreak;\n-\n-\tdefault:\n-\t\tbreak;\n-\t}\n-}\n-\n-LWS_VISIBLE LWS_EXTERN int\n-lws_email_init(struct lws_email *email, uv_loop_t *loop, int max_content)\n-{\n-\temail-\u003econtent \u003d lws_malloc(max_content, \u0022email content\u0022);\n-\tif (!email-\u003econtent)\n-\t\treturn 1;\n-\n-\temail-\u003emax_content_size \u003d max_content;\n-\tuv_timer_init(loop, \u0026email-\u003etimeout_email);\n-\n-\temail-\u003eloop \u003d loop;\n-\n-\t/* trigger him one time in a bit */\n-\tuv_timer_start(\u0026email-\u003etimeout_email, uv_timeout_cb_email, 2000, 0);\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE LWS_EXTERN void\n-lws_email_check(struct lws_email *email)\n-{\n-\tuv_timer_start(\u0026email-\u003etimeout_email, uv_timeout_cb_email, 1000, 0);\n-}\n-\n-LWS_VISIBLE LWS_EXTERN void\n-lws_email_destroy(struct lws_email *email)\n-{\n-\tif (email-\u003econtent)\n-\t\tlws_free_set_NULL(email-\u003econtent);\n-\n-\tuv_timer_stop(\u0026email-\u003etimeout_email);\n-\tuv_close((uv_handle_t *)\u0026email-\u003etimeout_email, NULL);\n-}\n-\ndiff --git a/lib/ssl-client.c b/lib/ssl-client.c\ndeleted file mode 100644\nindex b7cde51..0000000\n--- a/lib/ssl-client.c\n+++ /dev/null\n@@ -1,623 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-extern int openssl_websocket_private_data_index,\n- openssl_SSL_CTX_private_data_index;\n-\n-extern void\n-lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);\n-\n-extern int lws_ssl_get_error(struct lws *wsi, int n);\n-\n-#if defined(USE_WOLFSSL)\n-#else\n-\n-static int\n-OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)\n-{\n-#if defined(LWS_WITH_MBEDTLS)\n-\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n-\n-\treturn 0;\n-#else\n-\tSSL *ssl;\n-\tint n;\n-\tstruct lws *wsi;\n-\n-\t/* keep old behaviour accepting self-signed server certs */\n-\tif (!preverify_ok) {\n-\t\tint err \u003d X509_STORE_CTX_get_error(x509_ctx);\n-\n-\t\tif (err !\u003d X509_V_OK) {\n-\t\t\tssl \u003d X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());\n-\t\t\twsi \u003d SSL_get_ex_data(ssl, openssl_websocket_private_data_index);\n-\n-\t\t\tif ((err \u003d\u003d X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||\n-\t\t\t\t\terr \u003d\u003d X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \u0026\u0026\n-\t\t\t\t\twsi-\u003euse_ssl \u0026 LCCSCF_ALLOW_SELFSIGNED) {\n-\t\t\t\tlwsl_notice(\u0022accepting self-signed certificate (verify_callback)\u005cn\u0022);\n-\t\t\t\tX509_STORE_CTX_set_error(x509_ctx, X509_V_OK);\n-\t\t\t\treturn 1;\t// ok\n-\t\t\t} else if ((err \u003d\u003d X509_V_ERR_CERT_NOT_YET_VALID ||\n-\t\t\t\t\terr \u003d\u003d X509_V_ERR_CERT_HAS_EXPIRED) \u0026\u0026\n-\t\t\t\t\twsi-\u003euse_ssl \u0026 LCCSCF_ALLOW_EXPIRED) {\n-\t\t\t\tif (err \u003d\u003d X509_V_ERR_CERT_NOT_YET_VALID)\n-\t\t\t\t\tlwsl_notice(\u0022accepting not yet valid certificate (verify_callback)\u005cn\u0022);\n-\t\t\t\telse if (err \u003d\u003d X509_V_ERR_CERT_HAS_EXPIRED)\n-\t\t\t\t\tlwsl_notice(\u0022accepting expired certificate (verify_callback)\u005cn\u0022);\n-\t\t\t\tX509_STORE_CTX_set_error(x509_ctx, X509_V_OK);\n-\t\t\t\treturn 1;\t// ok\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\tssl \u003d X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());\n-\twsi \u003d SSL_get_ex_data(ssl, openssl_websocket_private_data_index);\n-\n-\tn \u003d lws_get_context_protocol(wsi-\u003econtext, 0).callback(wsi,\n-\t\t\tLWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION,\n-\t\t\tx509_ctx, ssl, preverify_ok);\n-\n-\t/* keep old behaviour if something wrong with server certs */\n-\t/* if ssl error is overruled in callback and cert is ok,\n-\t * X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); must be set and\n-\t * return value is 0 from callback */\n-\tif (!preverify_ok) {\n-\t\tint err \u003d X509_STORE_CTX_get_error(x509_ctx);\n-\n-\t\tif (err !\u003d X509_V_OK) {\t/* cert validation error was not handled in callback */\n-\t\t\tint depth \u003d X509_STORE_CTX_get_error_depth(x509_ctx);\n-\t\t\tconst char* msg \u003d X509_verify_cert_error_string(err);\n-\t\t\tlwsl_err(\u0022SSL error: %s (preverify_ok\u003d%d;err\u003d%d;depth\u003d%d)\u005cn\u0022, msg, preverify_ok, err, depth);\n-\t\t\treturn preverify_ok;\t// not ok\n-\t\t}\n-\t}\n-\t/* convert callback return code from 0 \u003d OK to verify callback return value 1 \u003d OK */\n-\treturn !n;\n-#endif\n-}\n-#endif\n-\n-int\n-lws_ssl_client_bio_create(struct lws *wsi)\n-{\n-\tchar hostname[128], *p;\n-\n-\tif (lws_hdr_copy(wsi, hostname, sizeof(hostname),\n-\t\t\t _WSI_TOKEN_CLIENT_HOST) \u003c\u003d 0) {\n-\t\tlwsl_err(\u0022%s: Unable to get hostname\u005cn\u0022, __func__);\n-\n-\t\treturn -1;\n-\t}\n-\n-\t/*\n-\t * remove any :port part on the hostname... necessary for network\n-\t * connection but typical certificates do not contain it\n-\t */\n-\tp \u003d hostname;\n-\twhile (*p) {\n-\t\tif (*p \u003d\u003d ':') {\n-\t\t\t*p \u003d '\u005c0';\n-\t\t\tbreak;\n-\t\t}\n-\t\tp++;\n-\t}\n-\n-\twsi-\u003essl \u003d SSL_new(wsi-\u003evhost-\u003essl_client_ctx);\n-\tif (!wsi-\u003essl) {\n-\t\tlwsl_err(\u0022SSL_new failed: %s\u005cn\u0022,\n-\t\t ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));\n-\t\tlws_ssl_elaborate_error();\n-\t\treturn -1;\n-\t}\n-\n-#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)\n-\tif (wsi-\u003evhost-\u003essl_info_event_mask)\n-\t\tSSL_set_info_callback(wsi-\u003essl, lws_ssl_info_callback);\n-#endif\n-\n-#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host\n-\tX509_VERIFY_PARAM *param;\n-\t(void)param;\n-\n-\tif (!(wsi-\u003euse_ssl \u0026 LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {\n-\t\tparam \u003d SSL_get0_param(wsi-\u003essl);\n-\t\t/* Enable automatic hostname checks */\n-\t\tX509_VERIFY_PARAM_set_hostflags(param,\n-\t\t\t\t\t\tX509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);\n-\t\tX509_VERIFY_PARAM_set1_host(param, hostname, 0);\n-\t}\n-\n-#endif\n-\n-#if !defined(USE_WOLFSSL) \u0026\u0026 !defined(LWS_WITH_MBEDTLS)\n-#ifndef USE_OLD_CYASSL\n-\t/* OpenSSL_client_verify_callback will be called @ SSL_connect() */\n-\tSSL_set_verify(wsi-\u003essl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback);\n-#endif\n-#endif\n-\n-#if !defined(USE_WOLFSSL) \u0026\u0026 !defined(LWS_WITH_MBEDTLS)\n-\tSSL_set_mode(wsi-\u003essl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);\n-#endif\n-\t/*\n-\t * use server name indication (SNI), if supported,\n-\t * when establishing connection\n-\t */\n-#ifdef USE_WOLFSSL\n-#ifdef USE_OLD_CYASSL\n-#ifdef CYASSL_SNI_HOST_NAME\n-\tCyaSSL_UseSNI(wsi-\u003essl, CYASSL_SNI_HOST_NAME, hostname, strlen(hostname));\n-#endif\n-#else\n-#ifdef WOLFSSL_SNI_HOST_NAME\n-\twolfSSL_UseSNI(wsi-\u003essl, WOLFSSL_SNI_HOST_NAME, hostname, strlen(hostname));\n-#endif\n-#endif\n-#else\n-#if defined(LWS_WITH_MBEDTLS)\n-\tif (wsi-\u003evhost-\u003ex509_client_CA)\n-\t\tSSL_set_verify(wsi-\u003essl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback);\n-\telse\n-\t\tSSL_set_verify(wsi-\u003essl, SSL_VERIFY_NONE, OpenSSL_client_verify_callback);\n-\n-#else\n-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME\n-\tSSL_set_tlsext_host_name(wsi-\u003essl, hostname);\n-#endif\n-#endif\n-#endif\n-\n-#ifdef USE_WOLFSSL\n-\t/*\n-\t * wolfSSL/CyaSSL does certificate verification differently\n-\t * from OpenSSL.\n-\t * If we should ignore the certificate, we need to set\n-\t * this before SSL_new and SSL_connect is called.\n-\t * Otherwise the connect will simply fail with error code -155\n-\t */\n-#ifdef USE_OLD_CYASSL\n-\tif (wsi-\u003euse_ssl \u003d\u003d 2)\n-\t\tCyaSSL_set_verify(wsi-\u003essl, SSL_VERIFY_NONE, NULL);\n-#else\n-\tif (wsi-\u003euse_ssl \u003d\u003d 2)\n-\t\twolfSSL_set_verify(wsi-\u003essl, SSL_VERIFY_NONE, NULL);\n-#endif\n-#endif /* USE_WOLFSSL */\n-\n-#if !defined(LWS_WITH_MBEDTLS)\n-\twsi-\u003eclient_bio \u003d BIO_new_socket(wsi-\u003edesc.sockfd, BIO_NOCLOSE);\n-\tSSL_set_bio(wsi-\u003essl, wsi-\u003eclient_bio, wsi-\u003eclient_bio);\n-#else\n-\tSSL_set_fd(wsi-\u003essl, wsi-\u003edesc.sockfd);\n-#endif\n-\n-#ifdef USE_WOLFSSL\n-#ifdef USE_OLD_CYASSL\n-\tCyaSSL_set_using_nonblock(wsi-\u003essl, 1);\n-#else\n-\twolfSSL_set_using_nonblock(wsi-\u003essl, 1);\n-#endif\n-#else\n-#if !defined(LWS_WITH_MBEDTLS)\n-\tBIO_set_nbio(wsi-\u003eclient_bio, 1); /* nonblocking */\n-#endif\n-#endif\n-\n-#if !defined(LWS_WITH_MBEDTLS)\n-\tSSL_set_ex_data(wsi-\u003essl, openssl_websocket_private_data_index,\n-\t\t\twsi);\n-#endif\n-\n-\treturn 0;\n-}\n-\n-#if defined(LWS_WITH_MBEDTLS)\n-int ERR_get_error(void)\n-{\n-\treturn 0;\n-}\n-#endif\n-\n-int\n-lws_ssl_client_connect1(struct lws *wsi)\n-{\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tint n \u003d 0;\n-\n-\tlws_latency_pre(context, wsi);\n-\n-\tn \u003d SSL_connect(wsi-\u003essl);\n-\n-\tlws_latency(context, wsi,\n-\t \u0022SSL_connect LWSCM_WSCL_ISSUE_HANDSHAKE\u0022, n, n \u003e 0);\n-\n-\tif (n \u003c 0) {\n-\t\tn \u003d lws_ssl_get_error(wsi, n);\n-\n-\t\tif (n \u003d\u003d SSL_ERROR_WANT_READ)\n-\t\t\tgoto some_wait;\n-\n-\t\tif (n \u003d\u003d SSL_ERROR_WANT_WRITE) {\n-\t\t\t/*\n-\t\t\t * wants us to retry connect due to\n-\t\t\t * state of the underlying ssl layer...\n-\t\t\t * but since it may be stalled on\n-\t\t\t * blocked write, no incoming data may\n-\t\t\t * arrive to trigger the retry.\n-\t\t\t * Force (possibly many times if the SSL\n-\t\t\t * state persists in returning the\n-\t\t\t * condition code, but other sockets\n-\t\t\t * are getting serviced inbetweentimes)\n-\t\t\t * us to get called back when writable.\n-\t\t\t */\n-\t\t\tlwsl_info(\u0022%s: WANT_WRITE... retrying\u005cn\u0022, __func__);\n-\t\t\tlws_callback_on_writable(wsi);\n-some_wait:\n-\t\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SSL;\n-\n-\t\t\treturn 0; /* no error */\n-\t\t}\n-\n-\t\t{\n-\t\t\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\t\t\tchar *p \u003d (char *)\u0026pt-\u003eserv_buf[0];\n-\t\t\tchar *sb \u003d p;\n-\n-\t\t\tlwsl_err(\u0022ssl hs1 error, X509_V_ERR \u003d %d: %s\u005cn\u0022,\n-\t\t\t\t n, ERR_error_string(n, sb));\n-\t\t\tlws_ssl_elaborate_error();\n-\t\t}\n-\n-\t\tn \u003d -1;\n-\t}\n-\n-\tif (n \u003c\u003d 0) {\n-\t\t/*\n-\t\t * retry if new data comes until we\n-\t\t * run into the connection timeout or win\n-\t\t */\n-\n-\t\tunsigned long error \u003d ERR_get_error();\n-\n-\t\tif (error !\u003d SSL_ERROR_NONE) {\n-\t\t\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\t\t\tchar *p \u003d (char *)\u0026pt-\u003eserv_buf[0];\n-\t\t\tchar *sb \u003d p;\n-\t\t\tlwsl_err(\u0022SSL connect error %lu: %s\u005cn\u0022,\n-\t\t\t\terror, ERR_error_string(error, sb));\n-\t\t\treturn -1;\n-\t\t}\n-\t}\n-\n-\treturn 1;\n-}\n-\n-int\n-lws_ssl_client_connect2(struct lws *wsi)\n-{\n-\tstruct lws_context *context \u003d wsi-\u003econtext;\n-\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n-\tchar *p \u003d (char *)\u0026pt-\u003eserv_buf[0];\n-\tchar *sb \u003d p;\n-\tint n \u003d 0;\n-\n-\tif (wsi-\u003emode \u003d\u003d LWSCM_WSCL_WAITING_SSL) {\n-\t\tlws_latency_pre(context, wsi);\n-\t\tn \u003d SSL_connect(wsi-\u003essl);\n-\t\tlwsl_debug(\u0022%s: SSL_connect says %d\u005cn\u0022, __func__, n);\n-\n-\t\tlws_latency(context, wsi,\n-\t\t\t \u0022SSL_connect LWSCM_WSCL_WAITING_SSL\u0022, n, n \u003e 0);\n-\n-\t\tif (n \u003c 0) {\n-\t\t\tn \u003d lws_ssl_get_error(wsi, n);\n-\n-\t\t\tif (n \u003d\u003d SSL_ERROR_WANT_READ) {\n-\t\t\t\tlwsl_info(\u0022SSL_connect WANT_READ... retrying\u005cn\u0022);\n-\n-\t\t\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SSL;\n-\n-\t\t\t\treturn 0; /* no error */\n-\t\t\t}\n-\n-\t\t\tif (n \u003d\u003d SSL_ERROR_WANT_WRITE) {\n-\t\t\t\t/*\n-\t\t\t\t * wants us to retry connect due to\n-\t\t\t\t * state of the underlying ssl layer...\n-\t\t\t\t * but since it may be stalled on\n-\t\t\t\t * blocked write, no incoming data may\n-\t\t\t\t * arrive to trigger the retry.\n-\t\t\t\t * Force (possibly many times if the SSL\n-\t\t\t\t * state persists in returning the\n-\t\t\t\t * condition code, but other sockets\n-\t\t\t\t * are getting serviced inbetweentimes)\n-\t\t\t\t * us to get called back when writable.\n-\t\t\t\t */\n-\t\t\t\tlwsl_info(\u0022SSL_connect WANT_WRITE... retrying\u005cn\u0022);\n-\t\t\t\tlws_callback_on_writable(wsi);\n-\n-\t\t\t\twsi-\u003emode \u003d LWSCM_WSCL_WAITING_SSL;\n-\n-\t\t\t\treturn 0; /* no error */\n-\t\t\t}\n-\n-\t\t\tn \u003d -1;\n-\t\t}\n-\n-\t\tif (n \u003c\u003d 0) {\n-\t\t\t/*\n-\t\t\t * retry if new data comes until we\n-\t\t\t * run into the connection timeout or win\n-\t\t\t */\n-\t\t\tunsigned long error \u003d ERR_get_error();\n-\t\t\tif (error !\u003d SSL_ERROR_NONE) {\n-\t\t\t\tlwsl_err(\u0022SSL connect error %lu: %s\u005cn\u0022,\n-\t\t\t\t\t error, ERR_error_string(error, sb));\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-#if defined(LWS_WITH_MBEDTLS)\n-\t{\n-\t\tX509 *peer \u003d SSL_get_peer_certificate(wsi-\u003essl);\n-\n-\t\tif (!peer) {\n-\t\t\tlwsl_notice(\u0022peer did not provide cert\u005cn\u0022);\n-\n-\t\t\treturn -1;\n-\t\t}\n-\t\tlwsl_notice(\u0022peer provided cert\u005cn\u0022);\n-\t}\n-#endif\n-\n-#ifndef USE_WOLFSSL\n-\t/*\n-\t * See comment above about wolfSSL certificate\n-\t * verification\n-\t */\n-\tlws_latency_pre(context, wsi);\n-\tn \u003d SSL_get_verify_result(wsi-\u003essl);\n-\tlws_latency(context, wsi,\n-\t\t\u0022SSL_get_verify_result LWS_CONNMODE..HANDSHAKE\u0022, n, n \u003e 0);\n-\n-\tlwsl_debug(\u0022get_verify says %d\u005cn\u0022, n);\n-\n-\tif (n !\u003d X509_V_OK) {\n-\t\tif ((n \u003d\u003d X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||\n-\t\t n \u003d\u003d X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \u0026\u0026\n-\t\t (wsi-\u003euse_ssl \u0026 LCCSCF_ALLOW_SELFSIGNED)) {\n-\t\t\tlwsl_notice(\u0022accepting self-signed certificate\u005cn\u0022);\n-\t\t} else if ((n \u003d\u003d X509_V_ERR_CERT_NOT_YET_VALID ||\n-\t\t n \u003d\u003d X509_V_ERR_CERT_HAS_EXPIRED) \u0026\u0026\n-\t\t (wsi-\u003euse_ssl \u0026 LCCSCF_ALLOW_EXPIRED)) {\n-\t\t\tlwsl_notice(\u0022accepting expired certificate\u005cn\u0022);\n-\t\t} else if (n \u003d\u003d X509_V_ERR_CERT_NOT_YET_VALID) {\n-\t\t\tlwsl_notice(\u0022Cert is from the future... \u0022\n-\t\t\t\t \u0022probably our clock... accepting...\u005cn\u0022);\n-\t\t} else {\n-\t\t\tlwsl_err(\u0022server's cert didn't look good, X509_V_ERR \u003d %d: %s\u005cn\u0022,\n-\t\t\t\t n, ERR_error_string(n, sb));\n-\t\t\tlws_ssl_elaborate_error();\n-\t\t\treturn -1;\n-\t\t}\n-\t}\n-\n-#endif /* USE_WOLFSSL */\n-\n-\treturn 1;\n-}\n-\n-\n-int lws_context_init_client_ssl(struct lws_context_creation_info *info,\n-\t\t\t\tstruct lws_vhost *vhost)\n-{\n-\tSSL_METHOD *method \u003d NULL;\n-\tstruct lws wsi;\n-\tunsigned long error;\n-\tconst char *ca_filepath \u003d info-\u003essl_ca_filepath;\n-#if !defined(LWS_WITH_MBEDTLS)\n-\tconst char *cipher_list \u003d info-\u003essl_cipher_list;\n-\tconst char *private_key_filepath \u003d info-\u003essl_private_key_filepath;\n-\tconst char *cert_filepath \u003d info-\u003essl_cert_filepath;\n-\tint n;\n-\n-\tif (vhost-\u003eoptions \u0026 LWS_SERVER_OPTION_ONLY_RAW)\n-\t\treturn 0;\n-\n-\t/*\n-\t * for backwards-compatibility default to using ssl_... members, but\n-\t * if the newer client-specific ones are given, use those\n-\t */\n-\tif (info-\u003eclient_ssl_cipher_list)\n-\t\tcipher_list \u003d info-\u003eclient_ssl_cipher_list;\n-\tif (info-\u003eclient_ssl_cert_filepath)\n-\t\tcert_filepath \u003d info-\u003eclient_ssl_cert_filepath;\n-\tif (info-\u003eclient_ssl_private_key_filepath)\n-\t\tprivate_key_filepath \u003d info-\u003eclient_ssl_private_key_filepath;\n-#endif\n-\tif (info-\u003eclient_ssl_ca_filepath)\n-\t\tca_filepath \u003d info-\u003eclient_ssl_ca_filepath;\n-\n-\tif (!lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))\n-\t\treturn 0;\n-\n-\tif (vhost-\u003essl_client_ctx)\n-\t\treturn 0;\n-\n-\tif (info-\u003eprovided_client_ssl_ctx) {\n-\t\t/* use the provided OpenSSL context if given one */\n-\t\tvhost-\u003essl_client_ctx \u003d info-\u003eprovided_client_ssl_ctx;\n-\t\t/* nothing for lib to delete */\n-\t\tvhost-\u003euser_supplied_ssl_ctx \u003d 1;\n-\n-\t\treturn 0;\n-\t}\n-\n-\t/* basic openssl init already happened in context init */\n-\n-\t/* choose the most recent spin of the api */\n-#if defined(LWS_HAVE_TLS_CLIENT_METHOD)\n-\tmethod \u003d (SSL_METHOD *)TLS_client_method();\n-#elif defined(LWS_HAVE_TLSV1_2_CLIENT_METHOD)\n-\tmethod \u003d (SSL_METHOD *)TLSv1_2_client_method();\n-#else\n-\tmethod \u003d (SSL_METHOD *)SSLv23_client_method();\n-#endif\n-\tif (!method) {\n-\t\terror \u003d ERR_get_error();\n-\t\tlwsl_err(\u0022problem creating ssl method %lu: %s\u005cn\u0022,\n-\t\t\terror, ERR_error_string(error,\n-\t\t\t\t (char *)vhost-\u003econtext-\u003ept[0].serv_buf));\n-\t\treturn 1;\n-\t}\n-\t/* create context */\n-\tvhost-\u003essl_client_ctx \u003d SSL_CTX_new(method);\n-\tif (!vhost-\u003essl_client_ctx) {\n-\t\terror \u003d ERR_get_error();\n-\t\tlwsl_err(\u0022problem creating ssl context %lu: %s\u005cn\u0022,\n-\t\t\terror, ERR_error_string(error,\n-\t\t\t\t (char *)vhost-\u003econtext-\u003ept[0].serv_buf));\n-\t\treturn 1;\n-\t}\n-\n-\tlwsl_notice(\u0022created client ssl context for %s\u005cn\u0022, vhost-\u003ename);\n-\n-#ifdef SSL_OP_NO_COMPRESSION\n-\tSSL_CTX_set_options(vhost-\u003essl_client_ctx, SSL_OP_NO_COMPRESSION);\n-#endif\n-\n-#if defined(LWS_WITH_MBEDTLS)\n-\tif (ca_filepath) {\n-\t\tlws_filepos_t len;\n-\t\tuint8_t *buf;\n-\t\t/*\n-\t\t * prototype this here, the shim does not export it in the\n-\t\t * header, and we need to use the shim unchanged for ESP32 case\n-\t\t */\n-\t\tX509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len);\n-\n-\t\tif (alloc_file(vhost-\u003econtext, ca_filepath, \u0026buf, \u0026len)) {\n-\t\t\tlwsl_err(\u0022Load CA cert file %s failed\u005cn\u0022, ca_filepath);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\tvhost-\u003ex509_client_CA \u003d d2i_X509(NULL, buf, len);\n-\t\tfree(buf);\n-\t\tif (!vhost-\u003ex509_client_CA) {\n-\t\t\tlwsl_err(\u0022client CA: x509 parse failed\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t\tSSL_CTX_add_client_CA(vhost-\u003essl_client_ctx,\n-\t\t\t\t vhost-\u003ex509_client_CA);\n-\n-\t\tlwsl_notice(\u0022client loaded CA for verification %s\u005cn\u0022, ca_filepath);\n-\t}\n-#else\n-\tSSL_CTX_set_options(vhost-\u003essl_client_ctx,\n-\t\t\t SSL_OP_CIPHER_SERVER_PREFERENCE);\n-\n-\tif (cipher_list)\n-\t\tSSL_CTX_set_cipher_list(vhost-\u003essl_client_ctx, cipher_list);\n-\n-#ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS\n-\tif (!lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))\n-\t\t/* loads OS default CA certs */\n-\t\tSSL_CTX_set_default_verify_paths(vhost-\u003essl_client_ctx);\n-#endif\n-\n-\t/* openssl init for cert verification (for client sockets) */\n-\tif (!ca_filepath) {\n-\t\tif (!SSL_CTX_load_verify_locations(\n-\t\t\tvhost-\u003essl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS))\n-\t\t\tlwsl_err(\u0022Unable to load SSL Client certs from %s \u0022\n-\t\t\t \u0022(set by LWS_OPENSSL_CLIENT_CERTS) -- \u0022\n-\t\t\t \u0022client ssl isn't going to work\u005cn\u0022,\n-\t\t\t LWS_OPENSSL_CLIENT_CERTS);\n-\t} else\n-\t\tif (!SSL_CTX_load_verify_locations(\n-\t\t\tvhost-\u003essl_client_ctx, ca_filepath, NULL)) {\n-\t\t\tlwsl_err(\n-\t\t\t\t\u0022Unable to load SSL Client certs \u0022\n-\t\t\t\t\u0022file from %s -- client ssl isn't \u0022\n-\t\t\t\t\u0022going to work\u005cn\u0022, info-\u003eclient_ssl_ca_filepath);\n-\t\t\tlws_ssl_elaborate_error();\n-\t\t}\n-\t\telse\n-\t\t\tlwsl_info(\u0022loaded ssl_ca_filepath\u005cn\u0022);\n-\n-\t/*\n-\t * callback allowing user code to load extra verification certs\n-\t * helping the client to verify server identity\n-\t */\n-\n-\t/* support for client-side certificate authentication */\n-\tif (cert_filepath) {\n-\t\tlwsl_notice(\u0022%s: doing cert filepath\u005cn\u0022, __func__);\n-\t\tn \u003d SSL_CTX_use_certificate_chain_file(vhost-\u003essl_client_ctx,\n-\t\t\t\t\t\t cert_filepath);\n-\t\tif (n \u003c 1) {\n-\t\t\tlwsl_err(\u0022problem %d getting cert '%s'\u005cn\u0022, n,\n-\t\t\t\t cert_filepath);\n-\t\t\tlws_ssl_elaborate_error();\n-\t\t\treturn 1;\n-\t\t}\n-\t\tlwsl_notice(\u0022Loaded client cert %s\u005cn\u0022, cert_filepath);\n-\t}\n-\tif (private_key_filepath) {\n-\t\tlwsl_notice(\u0022%s: doing private key filepath\u005cn\u0022, __func__);\n-\t\tlws_ssl_bind_passphrase(vhost-\u003essl_client_ctx, info);\n-\t\t/* set the private key from KeyFile */\n-\t\tif (SSL_CTX_use_PrivateKey_file(vhost-\u003essl_client_ctx,\n-\t\t private_key_filepath, SSL_FILETYPE_PEM) !\u003d 1) {\n-\t\t\tlwsl_err(\u0022use_PrivateKey_file '%s'\u005cn\u0022,\n-\t\t\t\t private_key_filepath);\n-\t\t\tlws_ssl_elaborate_error();\n-\t\t\treturn 1;\n-\t\t}\n-\t\tlwsl_notice(\u0022Loaded client cert private key %s\u005cn\u0022,\n-\t\t\t private_key_filepath);\n-\n-\t\t/* verify private key */\n-\t\tif (!SSL_CTX_check_private_key(vhost-\u003essl_client_ctx)) {\n-\t\t\tlwsl_err(\u0022Private SSL key doesn't match cert\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\t}\n-#endif\n-\t/*\n-\t * give him a fake wsi with context set, so he can use\n-\t * lws_get_context() in the callback\n-\t */\n-\tmemset(\u0026wsi, 0, sizeof(wsi));\n-\twsi.vhost \u003d vhost;\n-\twsi.context \u003d vhost-\u003econtext;\n-\n-\tvhost-\u003eprotocols[0].callback(\u0026wsi,\n-\t\t\tLWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,\n-\t\t\t\t vhost-\u003essl_client_ctx, NULL, 0);\n-\n-\treturn 0;\n-}\ndiff --git a/lib/ssl-http2.c b/lib/ssl-http2.c\ndeleted file mode 100644\nindex 4931d90..0000000\n--- a/lib/ssl-http2.c\n+++ /dev/null\n@@ -1,152 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- *\n- * Some or all of this file is based on code from nghttp2, which has the\n- * following license. Since it's more liberal than lws license, you're also\n- * at liberty to get the original code from\n- * https://github.com/tatsuhiro-t/nghttp2 under his liberal terms alone.\n- *\n- * nghttp2 - HTTP/2.0 C Library\n- *\n- * Copyright (c) 2012 Tatsuhiro Tsujikawa\n- *\n- * Permission is hereby granted, free of charge, to any person obtaining\n- * a copy of this software and associated documentation files (the\n- * \u0022Software\u0022), to deal in the Software without restriction, including\n- * without limitation the rights to use, copy, modify, merge, publish,\n- * distribute, sublicense, and/or sell copies of the Software, and to\n- * permit persons to whom the Software is furnished to do so, subject to\n- * the following conditions:\n- *\n- * The above copyright notice and this permission notice shall be\n- * included in all copies or substantial portions of the Software.\n- *\n- * THE SOFTWARE IS PROVIDED \u0022AS IS\u0022, WITHOUT WARRANTY OF ANY KIND,\n- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-#if !defined(LWS_NO_SERVER)\n-#if defined(LWS_OPENSSL_SUPPORT)\n-\n-#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) \u0026\u0026 OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000L)\n-\n-struct alpn_ctx {\n-\tunsigned char *data;\n-\tunsigned short len;\n-};\n-\n-\n-static int\n-alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen,\n-\tconst unsigned char *in, unsigned int inlen, void *arg)\n-{\n-#if !defined(LWS_WITH_MBEDTLS)\n-\tstruct alpn_ctx *alpn_ctx \u003d arg;\n-\n-\tif (SSL_select_next_proto((unsigned char **)out, outlen, alpn_ctx-\u003edata,\n-\t\t\t\t alpn_ctx-\u003elen, in, inlen) !\u003d\n-\t OPENSSL_NPN_NEGOTIATED)\n-\t\treturn SSL_TLSEXT_ERR_NOACK;\n-#endif\n-\treturn SSL_TLSEXT_ERR_OK;\n-}\n-#endif\n-\n-LWS_VISIBLE void\n-lws_context_init_http2_ssl(struct lws_vhost *vhost)\n-{\n-#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) \u0026\u0026 OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000L)\n-\tstatic struct alpn_ctx protos \u003d { (unsigned char *)\u0022\u005cx02h2\u0022\n-\t\t\t\t\t \u0022\u005cx08http/1.1\u0022, 6 + 9 };\n-\n-\tSSL_CTX_set_alpn_select_cb(vhost-\u003essl_ctx, alpn_cb, \u0026protos);\n-\tlwsl_notice(\u0022 HTTP2 / ALPN enabled\u005cn\u0022);\n-#else\n-\tlwsl_notice(\n-\t\t\u0022 HTTP2 / ALPN configured but not supported by OpenSSL 0x%lx\u005cn\u0022,\n-\t\t OPENSSL_VERSION_NUMBER);\n-#endif // OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000L\n-}\n-\n-int lws_h2_configure_if_upgraded(struct lws *wsi)\n-{\n-#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) \u0026\u0026 OPENSSL_VERSION_NUMBER \u003e\u003d 0x10002000L)\n-\tstruct allocated_headers *ah;\n-\tconst unsigned char *name \u003d NULL;\n-\tchar cstr[10];\n-\tunsigned len;\n-\n-\tSSL_get0_alpn_selected(wsi-\u003essl, \u0026name, \u0026len);\n-\tif (!len) {\n-\t\tlwsl_info(\u0022no ALPN upgrade\u005cn\u0022);\n-\t\treturn 0;\n-\t}\n-\n-\tif (len \u003e sizeof(cstr) - 1)\n-\t\tlen \u003d sizeof(cstr) - 1;\n-\n-\tmemcpy(cstr, name, len);\n-\tcstr[len] \u003d '\u005c0';\n-\n-\tlwsl_info(\u0022negotiated '%s' using ALPN\u005cn\u0022, cstr);\n-\twsi-\u003euse_ssl \u003d 1;\n-\tif (strncmp((char *)name, \u0022http/1.1\u0022, 8) \u003d\u003d 0)\n-\t\treturn 0;\n-\n-\t/* http2 */\n-\n-\twsi-\u003eupgraded_to_http2 \u003d 1;\n-\twsi-\u003evhost-\u003econn_stats.h2_alpn++;\n-\n-\t/* adopt the header info */\n-\n-\tah \u003d wsi-\u003eu.hdr.ah;\n-\n-\tlws_union_transition(wsi, LWSCM_HTTP2_SERVING);\n-\twsi-\u003estate \u003d LWSS_HTTP2_AWAIT_CLIENT_PREFACE;\n-\n-\t/* http2 union member has http union struct at start */\n-\twsi-\u003eu.http.ah \u003d ah;\n-\n-\twsi-\u003eu.h2.h2n \u003d lws_zalloc(sizeof(*wsi-\u003eu.h2.h2n), \u0022h2n\u0022);\n-\tif (!wsi-\u003eu.h2.h2n)\n-\t\treturn 1;\n-\n-\tlws_h2_init(wsi);\n-\n-\t/* HTTP2 union */\n-\n-\tlws_hpack_dynamic_size(wsi, wsi-\u003eu.h2.h2n-\u003eset.s[H2SET_HEADER_TABLE_SIZE]);\n-\twsi-\u003eu.h2.tx_cr \u003d 65535;\n-\n-\tlwsl_info(\u0022%s: wsi %p: configured for h2\u005cn\u0022, __func__, wsi);\n-\n-\treturn 0;\n-#endif\n-}\n-#endif\n-#endif\ndiff --git a/lib/ssl-server.c b/lib/ssl-server.c\ndeleted file mode 100644\nindex a9516f2..0000000\n--- a/lib/ssl-server.c\n+++ /dev/null\n@@ -1,477 +0,0 @@\n-/*\n- * libwebsockets - small server side websockets and web server implementation\n- *\n- * Copyright (C) 2010-2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022private-libwebsockets.h\u0022\n-\n-extern int openssl_websocket_private_data_index,\n- openssl_SSL_CTX_private_data_index;\n-\n-extern void\n-lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);\n-\n-#if !defined(LWS_WITH_MBEDTLS)\n-static int\n-OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)\n-{\n-\tSSL *ssl;\n-\tint n;\n-\tstruct lws *wsi;\n-\n-\tssl \u003d X509_STORE_CTX_get_ex_data(x509_ctx,\n-\t\tSSL_get_ex_data_X509_STORE_CTX_idx());\n-\n-\t/*\n-\t * !!! nasty openssl requires the index to come as a library-scope\n-\t * static\n-\t */\n-\twsi \u003d SSL_get_ex_data(ssl, openssl_websocket_private_data_index);\n-\n-\tn \u003d wsi-\u003evhost-\u003eprotocols[0].callback(wsi,\n-\t\t\tLWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,\n-\t\t\t\t\t x509_ctx, ssl, preverify_ok);\n-\n-\t/* convert return code from 0 \u003d OK to 1 \u003d OK */\n-\treturn !n;\n-}\n-#endif\n-\n-static int\n-lws_context_ssl_init_ecdh(struct lws_vhost *vhost)\n-{\n-#ifdef LWS_SSL_SERVER_WITH_ECDH_CERT\n-\tEC_KEY *EC_key \u003d NULL;\n-\tEVP_PKEY *pkey;\n-\tint KeyType;\n-\tX509 *x;\n-\n-\tif (!lws_check_opt(vhost-\u003econtext-\u003eoptions, LWS_SERVER_OPTION_SSL_ECDH))\n-\t\treturn 0;\n-\n-\tlwsl_notice(\u0022 Using ECDH certificate support\u005cn\u0022);\n-\n-\t/* Get X509 certificate from ssl context */\n-\tx \u003d sk_X509_value(vhost-\u003essl_ctx-\u003eextra_certs, 0);\n-\tif (!x) {\n-\t\tlwsl_err(\u0022%s: x is NULL\u005cn\u0022, __func__);\n-\t\treturn 1;\n-\t}\n-\t/* Get the public key from certificate */\n-\tpkey \u003d X509_get_pubkey(x);\n-\tif (!pkey) {\n-\t\tlwsl_err(\u0022%s: pkey is NULL\u005cn\u0022, __func__);\n-\n-\t\treturn 1;\n-\t}\n-\t/* Get the key type */\n-\tKeyType \u003d EVP_PKEY_type(pkey-\u003etype);\n-\n-\tif (EVP_PKEY_EC !\u003d KeyType) {\n-\t\tlwsl_notice(\u0022Key type is not EC\u005cn\u0022);\n-\t\treturn 0;\n-\t}\n-\t/* Get the key */\n-\tEC_key \u003d EVP_PKEY_get1_EC_KEY(pkey);\n-\t/* Set ECDH parameter */\n-\tif (!EC_key) {\n-\t\tlwsl_err(\u0022%s: ECDH key is NULL \u005cn\u0022, __func__);\n-\t\treturn 1;\n-\t}\n-\tSSL_CTX_set_tmp_ecdh(vhost-\u003essl_ctx, EC_key);\n-\tEC_KEY_free(EC_key);\n-#endif\n-\treturn 0;\n-}\n-\n-static int\n-lws_context_ssl_init_ecdh_curve(struct lws_context_creation_info *info,\n-\t\t\t\tstruct lws_vhost *vhost)\n-{\n-#if defined(LWS_HAVE_OPENSSL_ECDH_H) \u0026\u0026 !defined(LWS_WITH_MBEDTLS)\n-\tEC_KEY *ecdh;\n-\tint ecdh_nid;\n-\tconst char *ecdh_curve \u003d \u0022prime256v1\u0022;\n-\n-\tif (info-\u003eecdh_curve)\n-\t\tecdh_curve \u003d info-\u003eecdh_curve;\n-\n-\tecdh_nid \u003d OBJ_sn2nid(ecdh_curve);\n-\tif (NID_undef \u003d\u003d ecdh_nid) {\n-\t\tlwsl_err(\u0022SSL: Unknown curve name '%s'\u0022, ecdh_curve);\n-\t\treturn 1;\n-\t}\n-\n-\tecdh \u003d EC_KEY_new_by_curve_name(ecdh_nid);\n-\tif (NULL \u003d\u003d ecdh) {\n-\t\tlwsl_err(\u0022SSL: Unable to create curve '%s'\u0022, ecdh_curve);\n-\t\treturn 1;\n-\t}\n-\tSSL_CTX_set_tmp_ecdh(vhost-\u003essl_ctx, ecdh);\n-\tEC_KEY_free(ecdh);\n-\n-\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_SINGLE_ECDH_USE);\n-\n-\tlwsl_notice(\u0022 SSL ECDH curve '%s'\u005cn\u0022, ecdh_curve);\n-#else\n-#if !defined(LWS_WITH_MBEDTLS)\n-\tlwsl_notice(\u0022 OpenSSL doesn't support ECDH\u005cn\u0022);\n-#endif\n-#endif\n-\treturn 0;\n-}\n-\n-#if !defined(LWS_WITH_MBEDTLS) \u0026\u0026 defined(SSL_TLSEXT_ERR_NOACK) \u0026\u0026 !defined(OPENSSL_NO_TLSEXT)\n-static int\n-lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)\n-{\n-\tstruct lws_context *context \u003d (struct lws_context *)arg;\n-\tstruct lws_vhost *vhost, *vh;\n-\tconst char *servername;\n-\n-\tif (!ssl)\n-\t\treturn SSL_TLSEXT_ERR_NOACK;\n-\n-\t/*\n-\t * We can only get ssl accepted connections by using a vhost's ssl_ctx\n-\t * find out which listening one took us and only match vhosts on the\n-\t * same port.\n-\t */\n-\tvh \u003d context-\u003evhost_list;\n-\twhile (vh) {\n-\t\tif (!vh-\u003ebeing_destroyed \u0026\u0026 vh-\u003essl_ctx \u003d\u003d SSL_get_SSL_CTX(ssl))\n-\t\t\tbreak;\n-\t\tvh \u003d vh-\u003evhost_next;\n-\t}\n-\n-\tif (!vh) {\n-\t\tassert(vh); /* can't match the incoming vh? */\n-\t\treturn SSL_TLSEXT_ERR_OK;\n-\t}\n-\n-\tservername \u003d SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);\n-\tif (!servername) {\n-\t\t/* the client doesn't know what hostname it wants */\n-\t\tlwsl_info(\u0022SNI: Unknown ServerName: %s\u005cn\u0022, servername);\n-\n-\t\treturn SSL_TLSEXT_ERR_OK;\n-\t}\n-\n-\tvhost \u003d lws_select_vhost(context, vh-\u003elisten_port, servername);\n-\tif (!vhost) {\n-\t\tlwsl_info(\u0022SNI: none: %s:%d\u005cn\u0022, servername, vh-\u003elisten_port);\n-\n-\t\treturn SSL_TLSEXT_ERR_OK;\n-\t}\n-\n-\tlwsl_info(\u0022SNI: Found: %s:%d\u005cn\u0022, servername, vh-\u003elisten_port);\n-\n-\t/* select the ssl ctx from the selected vhost for this conn */\n-\tSSL_set_SSL_CTX(ssl, vhost-\u003essl_ctx);\n-\n-\treturn SSL_TLSEXT_ERR_OK;\n-}\n-#endif\n-\n-LWS_VISIBLE int\n-lws_context_init_server_ssl(struct lws_context_creation_info *info,\n-\t\t\t struct lws_vhost *vhost)\n-{\n-\tstruct lws_context *context \u003d vhost-\u003econtext;\n-\tstruct lws wsi;\n-\tunsigned long error;\n-\tint n;\n-\n-\tif (!lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {\n-\t\tvhost-\u003euse_ssl \u003d 0;\n-\t\treturn 0;\n-\t}\n-\n-\t/*\n-\t * If he is giving a cert filepath, take it as a sign he wants to use\n-\t * it on this vhost. User code can leave the cert filepath NULL and\n-\t * set the LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX option itself, in\n-\t * which case he's expected to set up the cert himself at\n-\t * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which\n-\t * provides the vhost SSL_CTX * in the user parameter.\n-\t */\n-\tif (info-\u003essl_cert_filepath)\n-\t\tinfo-\u003eoptions |\u003d LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX;\n-\n-\tif (info-\u003eport !\u003d CONTEXT_PORT_NO_LISTEN) {\n-\n-\t\tvhost-\u003euse_ssl \u003d lws_check_opt(info-\u003eoptions,\n-\t\t\t\t\tLWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX);\n-\n-\t\tif (vhost-\u003euse_ssl \u0026\u0026 info-\u003essl_cipher_list)\n-\t\t\tlwsl_notice(\u0022 SSL ciphers: '%s'\u005cn\u0022, info-\u003essl_cipher_list);\n-\n-\t\tif (vhost-\u003euse_ssl)\n-\t\t\tlwsl_notice(\u0022 Using SSL mode\u005cn\u0022);\n-\t\telse\n-\t\t\tlwsl_notice(\u0022 Using non-SSL mode\u005cn\u0022);\n-\t}\n-\n-\t/*\n-\t * give him a fake wsi with context + vhost set, so he can use\n-\t * lws_get_context() in the callback\n-\t */\n-\tmemset(\u0026wsi, 0, sizeof(wsi));\n-\twsi.vhost \u003d vhost;\n-\twsi.context \u003d context;\n-\n-\t(void)n;\n-\t(void)error;\n-\n-\t/*\n-\t * Firefox insists on SSLv23 not SSLv3\n-\t * Konq disables SSLv2 by default now, SSLv23 works\n-\t *\n-\t * SSLv23_server_method() is the openssl method for \u0022allow all TLS\n-\t * versions\u0022, compared to e.g. TLSv1_2_server_method() which only allows\n-\t * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options()\n-\t */\n-#if !defined(LWS_WITH_MBEDTLS)\n-\t{\n-\t\tSSL_METHOD *method;\n-\n-\t\tmethod \u003d (SSL_METHOD *)SSLv23_server_method();\n-\t\tif (!method) {\n-\t\t\terror \u003d ERR_get_error();\n-\t\t\tlwsl_err(\u0022problem creating ssl method %lu: %s\u005cn\u0022,\n-\t\t\t\t\terror, ERR_error_string(error,\n-\t\t\t\t\t (char *)context-\u003ept[0].serv_buf));\n-\t\t\treturn 1;\n-\t\t}\n-\t\tvhost-\u003essl_ctx \u003d SSL_CTX_new(method);\t/* create context */\n-\t\tif (!vhost-\u003essl_ctx) {\n-\t\t\terror \u003d ERR_get_error();\n-\t\t\tlwsl_err(\u0022problem creating ssl context %lu: %s\u005cn\u0022,\n-\t\t\t\t\terror, ERR_error_string(error,\n-\t\t\t\t\t (char *)context-\u003ept[0].serv_buf));\n-\t\t\treturn 1;\n-\t\t}\n-\t}\n-#else\n-\t{\n-\t\tconst SSL_METHOD *method \u003d TLSv1_2_server_method();\n-\n-\t\tvhost-\u003essl_ctx \u003d SSL_CTX_new(method);\t/* create context */\n-\t\tif (!vhost-\u003essl_ctx) {\n-\t\t\tlwsl_err(\u0022problem creating ssl context\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-\n-\t}\n-#endif\n-#if !defined(LWS_WITH_MBEDTLS)\n-\n-\t/* associate the lws context with the SSL_CTX */\n-\n-\tSSL_CTX_set_ex_data(vhost-\u003essl_ctx,\n-\t\t\topenssl_SSL_CTX_private_data_index, (char *)vhost-\u003econtext);\n-\t/* Disable SSLv2 and SSLv3 */\n-\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);\n-#ifdef SSL_OP_NO_COMPRESSION\n-\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_NO_COMPRESSION);\n-#endif\n-\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_SINGLE_DH_USE);\n-\tSSL_CTX_set_options(vhost-\u003essl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);\n-\n-\tif (info-\u003essl_cipher_list)\n-\t\tSSL_CTX_set_cipher_list(vhost-\u003essl_ctx,\n-\t\t\t\t\t\tinfo-\u003essl_cipher_list);\n-#endif\n-\n-\t/* as a server, are we requiring clients to identify themselves? */\n-\n-\tif (lws_check_opt(info-\u003eoptions,\n-\t\t\t LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) {\n-\t\tint verify_options \u003d SSL_VERIFY_PEER;\n-\n-\t\tif (!lws_check_opt(info-\u003eoptions,\n-\t\t\t\t LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))\n-\t\t\tverify_options |\u003d SSL_VERIFY_FAIL_IF_NO_PEER_CERT;\n-\n-#if !defined(LWS_WITH_MBEDTLS)\n-\t\tSSL_CTX_set_session_id_context(vhost-\u003essl_ctx,\n-\t\t\t\t(unsigned char *)context, sizeof(void *));\n-\n-\t\t/* absolutely require the client cert */\n-\n-\t\tSSL_CTX_set_verify(vhost-\u003essl_ctx,\n-\t\t verify_options, OpenSSL_verify_callback);\n-#endif\n-\t}\n-\n-#if !defined(LWS_WITH_MBEDTLS) \u0026\u0026 !defined(OPENSSL_NO_TLSEXT)\n-\tSSL_CTX_set_tlsext_servername_callback(vhost-\u003essl_ctx,\n-\t\t\t\t\t lws_ssl_server_name_cb);\n-\tSSL_CTX_set_tlsext_servername_arg(vhost-\u003essl_ctx, context);\n-#endif\n-\n-\t/*\n-\t * give user code a chance to load certs into the server\n-\t * allowing it to verify incoming client certs\n-\t */\n-#if !defined(LWS_WITH_MBEDTLS)\n-\tif (info-\u003essl_ca_filepath \u0026\u0026\n-\t !SSL_CTX_load_verify_locations(vhost-\u003essl_ctx,\n-\t\t\t\t\t info-\u003essl_ca_filepath, NULL)) {\n-\t\tlwsl_err(\u0022%s: SSL_CTX_load_verify_locations unhappy\u005cn\u0022, __func__);\n-\t}\n-#endif\n-\tif (vhost-\u003euse_ssl) {\n-\t\tif (lws_context_ssl_init_ecdh_curve(info, vhost))\n-\t\t\treturn -1;\n-\n-\t\tvhost-\u003eprotocols[0].callback(\u0026wsi,\n-\t\t\tLWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,\n-\t\t\tvhost-\u003essl_ctx, NULL, 0);\n-\t}\n-\n-\tif (lws_check_opt(info-\u003eoptions, LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT))\n-\t\t/* Normally SSL listener rejects non-ssl, optionally allow */\n-\t\tvhost-\u003eallow_non_ssl_on_ssl_port \u003d 1;\n-\n-\tif (info-\u003essl_options_set)\n-\t\tSSL_CTX_set_options(vhost-\u003essl_ctx, info-\u003essl_options_set);\n-\n-/* SSL_clear_options introduced in 0.9.8m */\n-#if !defined(LWS_WITH_MBEDTLS)\n-#if (OPENSSL_VERSION_NUMBER \u003e\u003d 0x009080df) \u0026\u0026 !defined(USE_WOLFSSL)\n-\tif (info-\u003essl_options_clear)\n-\t\tSSL_CTX_clear_options(vhost-\u003essl_ctx, info-\u003essl_options_clear);\n-#endif\n-#endif\n-\n-\tlwsl_info(\u0022 SSL options 0x%lX\u005cn\u0022, SSL_CTX_get_options(vhost-\u003essl_ctx));\n-\n-\tif (vhost-\u003euse_ssl \u0026\u0026 info-\u003essl_cert_filepath) {\n-\t\t/*\n-\t\t * The user code can choose to either pass the cert and\n-\t\t * key filepaths using the info members like this, or it can\n-\t\t * leave them NULL; force the vhost SSL_CTX init using the info\n-\t\t * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and\n-\t\t * set up the cert himself using the user callback\n-\t\t * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which\n-\t\t * happened just above and has the vhost SSL_CTX * in the user\n-\t\t * parameter.\n-\t\t */\n-#if !defined(LWS_WITH_MBEDTLS)\n-\t\t/* set the local certificate from CertFile */\n-\t\tn \u003d SSL_CTX_use_certificate_chain_file(vhost-\u003essl_ctx,\n-\t\t\t\t\tinfo-\u003essl_cert_filepath);\n-\t\tif (n !\u003d 1) {\n-\t\t\terror \u003d ERR_get_error();\n-\t\t\tlwsl_err(\u0022problem getting cert '%s' %lu: %s\u005cn\u0022,\n-\t\t\t\tinfo-\u003essl_cert_filepath,\n-\t\t\t\terror,\n-\t\t\t\tERR_error_string(error,\n-\t\t\t\t\t (char *)context-\u003ept[0].serv_buf));\n-\t\t\treturn 1;\n-\t\t}\n-\t\tlws_ssl_bind_passphrase(vhost-\u003essl_ctx, info);\n-#else\n-\t\tuint8_t *p;\n-\t\tlws_filepos_t flen;\n-\t\tint err;\n-\n-\t\tif (alloc_pem_to_der_file(vhost-\u003econtext, info-\u003essl_cert_filepath, \u0026p,\n-\t\t\t\t \u0026flen)) {\n-\t\t\tlwsl_err(\u0022couldn't find cert file %s\u005cn\u0022,\n-\t\t\t\t info-\u003essl_cert_filepath);\n-\n-\t\t\treturn 1;\n-\t\t}\n-\t\terr \u003d SSL_CTX_use_certificate_ASN1(vhost-\u003essl_ctx, flen, p);\n-\t\tif (!err) {\n-\t\t\tlwsl_err(\u0022Problem loading cert\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-#if !defined(LWS_WITH_ESP32)\n-\t\tfree(p);\n-\t\tp \u003d NULL;\n-#endif\n-\n-\t\tif (info-\u003essl_private_key_filepath) {\n-\t\t\tif (alloc_pem_to_der_file(vhost-\u003econtext,\n-\t\t\t\t info-\u003essl_private_key_filepath, \u0026p, \u0026flen)) {\n-\t\t\t\tlwsl_err(\u0022couldn't find cert file %s\u005cn\u0022,\n-\t\t\t\t\t info-\u003essl_cert_filepath);\n-\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t\terr \u003d SSL_CTX_use_PrivateKey_ASN1(0, vhost-\u003essl_ctx, p, flen);\n-\t\t\tif (!err) {\n-\t\t\t\tlwsl_err(\u0022Problem loading key\u005cn\u0022);\n-\n-\t\t\t\treturn 1;\n-\t\t\t}\n-\t\t}\n-\n-#if !defined(LWS_WITH_ESP32)\n-\t\tfree(p);\n-\t\tp \u003d NULL;\n-#endif\n-#endif\n-\t\tif (info-\u003essl_private_key_filepath !\u003d NULL) {\n-#if !defined(LWS_WITH_MBEDTLS)\n-\t\t\t/* set the private key from KeyFile */\n-\t\t\tif (SSL_CTX_use_PrivateKey_file(vhost-\u003essl_ctx,\n-\t\t\t\t info-\u003essl_private_key_filepath,\n-\t\t\t\t\t\t SSL_FILETYPE_PEM) !\u003d 1) {\n-\t\t\t\terror \u003d ERR_get_error();\n-\t\t\t\tlwsl_err(\u0022ssl problem getting key '%s' %lu: %s\u005cn\u0022,\n-\t\t\t\t\t info-\u003essl_private_key_filepath, error,\n-\t\t\t\t\t ERR_error_string(error,\n-\t\t\t\t\t (char *)context-\u003ept[0].serv_buf));\n-\t\t\t\treturn 1;\n-\t\t\t}\n-#endif\n-\t\t} else\n-\t\t\tif (vhost-\u003eprotocols[0].callback(\u0026wsi,\n-\t\t\t\tLWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,\n-\t\t\t\tvhost-\u003essl_ctx, NULL, 0)) {\n-\t\t\t\tlwsl_err(\u0022ssl private key not set\u005cn\u0022);\n-\n-\t\t\t\treturn 1;\n-\t\t\t}\n-#if !defined(LWS_WITH_MBEDTLS)\n-\t\t/* verify private key */\n-\t\tif (!SSL_CTX_check_private_key(vhost-\u003essl_ctx)) {\n-\t\t\tlwsl_err(\u0022Private SSL key doesn't match cert\u005cn\u0022);\n-\t\t\treturn 1;\n-\t\t}\n-#endif\n-\t}\n-\tif (vhost-\u003euse_ssl) {\n-\t\tif (lws_context_ssl_init_ecdh(vhost))\n-\t\t\treturn 1;\n-\n-\t\t/*\n-\t\t * SSL is happy and has a cert it's content with\n-\t\t * If we're supporting HTTP2, initialize that\n-\t\t */\n-\t\tlws_context_init_http2_ssl(vhost);\n-\t}\n-\n-\treturn 0;\n-}\n-\ndiff --git a/lib/ssl.c b/lib/ssl.c\nindex 15bc810..0a647b4 100644\n--- a/lib/ssl.c\n+++ b/lib/ssl.c\n@@ -383,6 +383,26 @@ lws_ssl_destroy(struct lws_vhost *vhost)\n #endif\n }\n \n+int\n+lws_ssl_anybody_has_buffered_read_tsi(struct lws_context *context, int tsi)\n+{\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n+\tstruct lws *wsi, *wsi_next;\n+\n+\twsi \u003d pt-\u003epending_read_list;\n+\twhile (wsi) {\n+\t\twsi_next \u003d wsi-\u003epending_read_list_next;\n+\t\tpt-\u003efds[wsi-\u003eposition_in_fds_table].revents |\u003d\n+\t\t\tpt-\u003efds[wsi-\u003eposition_in_fds_table].events \u0026 LWS_POLLIN;\n+\t\tif (pt-\u003efds[wsi-\u003eposition_in_fds_table].revents \u0026 LWS_POLLIN)\n+\t\t\treturn 1;\n+\n+\t\twsi \u003d wsi_next;\n+\t}\n+\n+\treturn 0;\n+}\n+\n LWS_VISIBLE void\n lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)\n {\n","s":{"c":1745674065,"u": 91451}}
],"g": 464522,"chitpc": 0,"ehitpc": 0,"indexed":0
,
"ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "7d0a"}