1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "private-lib-core.h" 26d4afb5ceSopenharmony_ci#include "extension-permessage-deflate.h" 27d4afb5ceSopenharmony_ci#include <stdio.h> 28d4afb5ceSopenharmony_ci#include <string.h> 29d4afb5ceSopenharmony_ci#include <assert.h> 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ci#define LWS_ZLIB_MEMLEVEL 8 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_ciconst struct lws_ext_options lws_ext_pm_deflate_options[] = { 34d4afb5ceSopenharmony_ci /* public RFC7692 settings */ 35d4afb5ceSopenharmony_ci { "server_no_context_takeover", EXTARG_NONE }, 36d4afb5ceSopenharmony_ci { "client_no_context_takeover", EXTARG_NONE }, 37d4afb5ceSopenharmony_ci { "server_max_window_bits", EXTARG_OPT_DEC }, 38d4afb5ceSopenharmony_ci { "client_max_window_bits", EXTARG_OPT_DEC }, 39d4afb5ceSopenharmony_ci /* ones only user code can set */ 40d4afb5ceSopenharmony_ci { "rx_buf_size", EXTARG_DEC }, 41d4afb5ceSopenharmony_ci { "tx_buf_size", EXTARG_DEC }, 42d4afb5ceSopenharmony_ci { "compression_level", EXTARG_DEC }, 43d4afb5ceSopenharmony_ci { "mem_level", EXTARG_DEC }, 44d4afb5ceSopenharmony_ci { NULL, 0 }, /* sentinel */ 45d4afb5ceSopenharmony_ci}; 46d4afb5ceSopenharmony_ci 47d4afb5ceSopenharmony_cistatic void 48d4afb5ceSopenharmony_cilws_extension_pmdeflate_restrict_args(struct lws *wsi, 49d4afb5ceSopenharmony_ci struct lws_ext_pm_deflate_priv *priv) 50d4afb5ceSopenharmony_ci{ 51d4afb5ceSopenharmony_ci int n, extra; 52d4afb5ceSopenharmony_ci 53d4afb5ceSopenharmony_ci /* cap the RX buf at the nearest power of 2 to protocol rx buf */ 54d4afb5ceSopenharmony_ci 55d4afb5ceSopenharmony_ci n = (int)wsi->a.context->pt_serv_buf_size; 56d4afb5ceSopenharmony_ci if (wsi->a.protocol->rx_buffer_size) 57d4afb5ceSopenharmony_ci n = (int)wsi->a.protocol->rx_buffer_size; 58d4afb5ceSopenharmony_ci 59d4afb5ceSopenharmony_ci extra = 7; 60d4afb5ceSopenharmony_ci while (n >= 1 << (extra + 1)) 61d4afb5ceSopenharmony_ci extra++; 62d4afb5ceSopenharmony_ci 63d4afb5ceSopenharmony_ci if (extra < priv->args[PMD_RX_BUF_PWR2]) { 64d4afb5ceSopenharmony_ci priv->args[PMD_RX_BUF_PWR2] = (unsigned char)extra; 65d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, " Capping pmd rx to %d", 1 << extra); 66d4afb5ceSopenharmony_ci } 67d4afb5ceSopenharmony_ci} 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_cistatic unsigned char trail[] = { 0, 0, 0xff, 0xff }; 70d4afb5ceSopenharmony_ci 71d4afb5ceSopenharmony_ciLWS_VISIBLE int 72d4afb5ceSopenharmony_cilws_extension_callback_pm_deflate(struct lws_context *context, 73d4afb5ceSopenharmony_ci const struct lws_extension *ext, 74d4afb5ceSopenharmony_ci struct lws *wsi, 75d4afb5ceSopenharmony_ci enum lws_extension_callback_reasons reason, 76d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 77d4afb5ceSopenharmony_ci{ 78d4afb5ceSopenharmony_ci struct lws_ext_pm_deflate_priv *priv = 79d4afb5ceSopenharmony_ci (struct lws_ext_pm_deflate_priv *)user; 80d4afb5ceSopenharmony_ci struct lws_ext_pm_deflate_rx_ebufs *pmdrx = 81d4afb5ceSopenharmony_ci (struct lws_ext_pm_deflate_rx_ebufs *)in; 82d4afb5ceSopenharmony_ci struct lws_ext_option_arg *oa; 83d4afb5ceSopenharmony_ci int n, ret = 0, was_fin = 0, m; 84d4afb5ceSopenharmony_ci unsigned int pen = 0; 85d4afb5ceSopenharmony_ci int penbits = 0; 86d4afb5ceSopenharmony_ci 87d4afb5ceSopenharmony_ci switch (reason) { 88d4afb5ceSopenharmony_ci case LWS_EXT_CB_NAMED_OPTION_SET: 89d4afb5ceSopenharmony_ci oa = in; 90d4afb5ceSopenharmony_ci if (!oa->option_name) 91d4afb5ceSopenharmony_ci break; 92d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "named option set: %s", oa->option_name); 93d4afb5ceSopenharmony_ci for (n = 0; n < (int)LWS_ARRAY_SIZE(lws_ext_pm_deflate_options); 94d4afb5ceSopenharmony_ci n++) 95d4afb5ceSopenharmony_ci if (!strcmp(lws_ext_pm_deflate_options[n].name, 96d4afb5ceSopenharmony_ci oa->option_name)) 97d4afb5ceSopenharmony_ci break; 98d4afb5ceSopenharmony_ci 99d4afb5ceSopenharmony_ci if (n == (int)LWS_ARRAY_SIZE(lws_ext_pm_deflate_options)) 100d4afb5ceSopenharmony_ci break; 101d4afb5ceSopenharmony_ci oa->option_index = n; 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_ci /* fallthru */ 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci case LWS_EXT_CB_OPTION_SET: 106d4afb5ceSopenharmony_ci oa = in; 107d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "option set: idx %d, %s, len %d", 108d4afb5ceSopenharmony_ci oa->option_index, oa->start, oa->len); 109d4afb5ceSopenharmony_ci if (oa->start) 110d4afb5ceSopenharmony_ci priv->args[oa->option_index] = (unsigned char)atoi(oa->start); 111d4afb5ceSopenharmony_ci else 112d4afb5ceSopenharmony_ci priv->args[oa->option_index] = 1; 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_ci if (priv->args[PMD_CLIENT_MAX_WINDOW_BITS] == 8) 115d4afb5ceSopenharmony_ci priv->args[PMD_CLIENT_MAX_WINDOW_BITS] = 9; 116d4afb5ceSopenharmony_ci 117d4afb5ceSopenharmony_ci lws_extension_pmdeflate_restrict_args(wsi, priv); 118d4afb5ceSopenharmony_ci break; 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci case LWS_EXT_CB_OPTION_CONFIRM: 121d4afb5ceSopenharmony_ci if (priv->args[PMD_SERVER_MAX_WINDOW_BITS] < 8 || 122d4afb5ceSopenharmony_ci priv->args[PMD_SERVER_MAX_WINDOW_BITS] > 15 || 123d4afb5ceSopenharmony_ci priv->args[PMD_CLIENT_MAX_WINDOW_BITS] < 8 || 124d4afb5ceSopenharmony_ci priv->args[PMD_CLIENT_MAX_WINDOW_BITS] > 15) 125d4afb5ceSopenharmony_ci return -1; 126d4afb5ceSopenharmony_ci break; 127d4afb5ceSopenharmony_ci 128d4afb5ceSopenharmony_ci case LWS_EXT_CB_CLIENT_CONSTRUCT: 129d4afb5ceSopenharmony_ci case LWS_EXT_CB_CONSTRUCT: 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_ci n = (int)context->pt_serv_buf_size; 132d4afb5ceSopenharmony_ci if (wsi->a.protocol->rx_buffer_size) 133d4afb5ceSopenharmony_ci n = (int)wsi->a.protocol->rx_buffer_size; 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_ci if (n < 128) { 136d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, " permessage-deflate requires the protocol " 137d4afb5ceSopenharmony_ci "(%s) to have an RX buffer >= 128", 138d4afb5ceSopenharmony_ci wsi->a.protocol->name); 139d4afb5ceSopenharmony_ci return -1; 140d4afb5ceSopenharmony_ci } 141d4afb5ceSopenharmony_ci 142d4afb5ceSopenharmony_ci /* fill in **user */ 143d4afb5ceSopenharmony_ci priv = lws_zalloc(sizeof(*priv), "pmd priv"); 144d4afb5ceSopenharmony_ci *((void **)user) = priv; 145d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "LWS_EXT_CB_*CONSTRUCT"); 146d4afb5ceSopenharmony_ci memset(priv, 0, sizeof(*priv)); 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci /* fill in pointer to options list */ 149d4afb5ceSopenharmony_ci if (in) 150d4afb5ceSopenharmony_ci *((const struct lws_ext_options **)in) = 151d4afb5ceSopenharmony_ci lws_ext_pm_deflate_options; 152d4afb5ceSopenharmony_ci 153d4afb5ceSopenharmony_ci /* fallthru */ 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_ci case LWS_EXT_CB_OPTION_DEFAULT: 156d4afb5ceSopenharmony_ci 157d4afb5ceSopenharmony_ci /* set the public, RFC7692 defaults... */ 158d4afb5ceSopenharmony_ci 159d4afb5ceSopenharmony_ci priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER] = 0, 160d4afb5ceSopenharmony_ci priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER] = 0; 161d4afb5ceSopenharmony_ci priv->args[PMD_SERVER_MAX_WINDOW_BITS] = 15; 162d4afb5ceSopenharmony_ci priv->args[PMD_CLIENT_MAX_WINDOW_BITS] = 15; 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci /* ...and the ones the user code can override */ 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_ci priv->args[PMD_RX_BUF_PWR2] = 10; /* ie, 1024 */ 167d4afb5ceSopenharmony_ci priv->args[PMD_TX_BUF_PWR2] = 10; /* ie, 1024 */ 168d4afb5ceSopenharmony_ci priv->args[PMD_COMP_LEVEL] = 1; 169d4afb5ceSopenharmony_ci priv->args[PMD_MEM_LEVEL] = 8; 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_ci lws_extension_pmdeflate_restrict_args(wsi, priv); 172d4afb5ceSopenharmony_ci break; 173d4afb5ceSopenharmony_ci 174d4afb5ceSopenharmony_ci case LWS_EXT_CB_DESTROY: 175d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "LWS_EXT_CB_DESTROY"); 176d4afb5ceSopenharmony_ci lws_free(priv->buf_rx_inflated); 177d4afb5ceSopenharmony_ci lws_free(priv->buf_tx_deflated); 178d4afb5ceSopenharmony_ci if (priv->rx_init) 179d4afb5ceSopenharmony_ci (void)inflateEnd(&priv->rx); 180d4afb5ceSopenharmony_ci if (priv->tx_init) 181d4afb5ceSopenharmony_ci (void)deflateEnd(&priv->tx); 182d4afb5ceSopenharmony_ci lws_free(priv); 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci return ret; 185d4afb5ceSopenharmony_ci 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci case LWS_EXT_CB_PAYLOAD_RX: 188d4afb5ceSopenharmony_ci /* 189d4afb5ceSopenharmony_ci * ie, we are INFLATING 190d4afb5ceSopenharmony_ci */ 191d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, " LWS_EXT_CB_PAYLOAD_RX: in %d, existing in %d", 192d4afb5ceSopenharmony_ci pmdrx->eb_in.len, priv->rx.avail_in); 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci /* 195d4afb5ceSopenharmony_ci * If this frame is not marked as compressed, 196d4afb5ceSopenharmony_ci * there is nothing we should do with it 197d4afb5ceSopenharmony_ci */ 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_ci if (!(wsi->ws->rsv_first_msg & 0x40) || (wsi->ws->opcode & 8)) 200d4afb5ceSopenharmony_ci /* 201d4afb5ceSopenharmony_ci * This is a bit different than DID_NOTHING... we have 202d4afb5ceSopenharmony_ci * identified using ext-private bits in the packet, or 203d4afb5ceSopenharmony_ci * by it being a control fragment that we SHOULD not do 204d4afb5ceSopenharmony_ci * anything to it, parent should continue as if we 205d4afb5ceSopenharmony_ci * processed it 206d4afb5ceSopenharmony_ci */ 207d4afb5ceSopenharmony_ci return PMDR_NOTHING_WE_SHOULD_DO; 208d4afb5ceSopenharmony_ci 209d4afb5ceSopenharmony_ci /* 210d4afb5ceSopenharmony_ci * we shouldn't come back in here if we already applied the 211d4afb5ceSopenharmony_ci * trailer for this compressed packet 212d4afb5ceSopenharmony_ci */ 213d4afb5ceSopenharmony_ci if (!wsi->ws->pmd_trailer_application) 214d4afb5ceSopenharmony_ci return PMDR_DID_NOTHING; 215d4afb5ceSopenharmony_ci 216d4afb5ceSopenharmony_ci pmdrx->eb_out.len = 0; 217d4afb5ceSopenharmony_ci 218d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "LWS_EXT_CB_PAYLOAD_RX: in %d, " 219d4afb5ceSopenharmony_ci "existing avail in %d, pkt fin: %d", 220d4afb5ceSopenharmony_ci pmdrx->eb_in.len, priv->rx.avail_in, wsi->ws->final); 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_ci /* if needed, initialize the inflator */ 223d4afb5ceSopenharmony_ci 224d4afb5ceSopenharmony_ci if (!priv->rx_init) { 225d4afb5ceSopenharmony_ci if (inflateInit2(&priv->rx, 226d4afb5ceSopenharmony_ci -priv->args[PMD_SERVER_MAX_WINDOW_BITS]) != Z_OK) { 227d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "iniflateInit failed"); 228d4afb5ceSopenharmony_ci return PMDR_FAILED; 229d4afb5ceSopenharmony_ci } 230d4afb5ceSopenharmony_ci priv->rx_init = 1; 231d4afb5ceSopenharmony_ci if (!priv->buf_rx_inflated) 232d4afb5ceSopenharmony_ci priv->buf_rx_inflated = lws_malloc( 233d4afb5ceSopenharmony_ci (unsigned int)(LWS_PRE + 7 + 5 + 234d4afb5ceSopenharmony_ci (1 << priv->args[PMD_RX_BUF_PWR2])), 235d4afb5ceSopenharmony_ci "pmd rx inflate buf"); 236d4afb5ceSopenharmony_ci if (!priv->buf_rx_inflated) { 237d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "OOM"); 238d4afb5ceSopenharmony_ci return PMDR_FAILED; 239d4afb5ceSopenharmony_ci } 240d4afb5ceSopenharmony_ci } 241d4afb5ceSopenharmony_ci 242d4afb5ceSopenharmony_ci#if 0 243d4afb5ceSopenharmony_ci /* 244d4afb5ceSopenharmony_ci * don't give us new input while we still work through 245d4afb5ceSopenharmony_ci * the last input 246d4afb5ceSopenharmony_ci */ 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_ci if (priv->rx.avail_in && pmdrx->eb_in.token && 249d4afb5ceSopenharmony_ci pmdrx->eb_in.len) { 250d4afb5ceSopenharmony_ci lwsl_wsi_warn(wsi, "priv->rx.avail_in %d while getting new in", 251d4afb5ceSopenharmony_ci priv->rx.avail_in); 252d4afb5ceSopenharmony_ci // assert(0); 253d4afb5ceSopenharmony_ci } 254d4afb5ceSopenharmony_ci#endif 255d4afb5ceSopenharmony_ci if (!priv->rx.avail_in && pmdrx->eb_in.token && pmdrx->eb_in.len) { 256d4afb5ceSopenharmony_ci priv->rx.next_in = (unsigned char *)pmdrx->eb_in.token; 257d4afb5ceSopenharmony_ci priv->rx.avail_in = (uInt)pmdrx->eb_in.len; 258d4afb5ceSopenharmony_ci } 259d4afb5ceSopenharmony_ci 260d4afb5ceSopenharmony_ci priv->rx.next_out = priv->buf_rx_inflated + LWS_PRE; 261d4afb5ceSopenharmony_ci pmdrx->eb_out.token = priv->rx.next_out; 262d4afb5ceSopenharmony_ci priv->rx.avail_out = (uInt)(1 << priv->args[PMD_RX_BUF_PWR2]); 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci /* so... if... 265d4afb5ceSopenharmony_ci * 266d4afb5ceSopenharmony_ci * - he has no remaining input content for this message, and 267d4afb5ceSopenharmony_ci * 268d4afb5ceSopenharmony_ci * - and this is the final fragment, and 269d4afb5ceSopenharmony_ci * 270d4afb5ceSopenharmony_ci * - we used everything that could be drained on the input side 271d4afb5ceSopenharmony_ci * 272d4afb5ceSopenharmony_ci * ...then put back the 00 00 FF FF the sender stripped as our 273d4afb5ceSopenharmony_ci * input to zlib 274d4afb5ceSopenharmony_ci */ 275d4afb5ceSopenharmony_ci if (!priv->rx.avail_in && 276d4afb5ceSopenharmony_ci wsi->ws->final && 277d4afb5ceSopenharmony_ci !wsi->ws->rx_packet_length && 278d4afb5ceSopenharmony_ci wsi->ws->pmd_trailer_application) { 279d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "trailer apply 1"); 280d4afb5ceSopenharmony_ci was_fin = 1; 281d4afb5ceSopenharmony_ci wsi->ws->pmd_trailer_application = 0; 282d4afb5ceSopenharmony_ci priv->rx.next_in = trail; 283d4afb5ceSopenharmony_ci priv->rx.avail_in = sizeof(trail); 284d4afb5ceSopenharmony_ci } 285d4afb5ceSopenharmony_ci 286d4afb5ceSopenharmony_ci /* 287d4afb5ceSopenharmony_ci * if after all that there's nothing pending and nothing to give 288d4afb5ceSopenharmony_ci * him right now, bail without having done anything 289d4afb5ceSopenharmony_ci */ 290d4afb5ceSopenharmony_ci 291d4afb5ceSopenharmony_ci if (!priv->rx.avail_in) 292d4afb5ceSopenharmony_ci return PMDR_DID_NOTHING; 293d4afb5ceSopenharmony_ci 294d4afb5ceSopenharmony_ci n = inflate(&priv->rx, was_fin ? Z_SYNC_FLUSH : Z_NO_FLUSH); 295d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "inflate ret %d, avi %d, avo %d, wsifinal %d", n, 296d4afb5ceSopenharmony_ci priv->rx.avail_in, priv->rx.avail_out, wsi->ws->final); 297d4afb5ceSopenharmony_ci switch (n) { 298d4afb5ceSopenharmony_ci case Z_NEED_DICT: 299d4afb5ceSopenharmony_ci case Z_STREAM_ERROR: 300d4afb5ceSopenharmony_ci case Z_DATA_ERROR: 301d4afb5ceSopenharmony_ci case Z_MEM_ERROR: 302d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "zlib error inflate %d: \"%s\"", 303d4afb5ceSopenharmony_ci n, priv->rx.msg); 304d4afb5ceSopenharmony_ci return PMDR_FAILED; 305d4afb5ceSopenharmony_ci } 306d4afb5ceSopenharmony_ci 307d4afb5ceSopenharmony_ci /* 308d4afb5ceSopenharmony_ci * track how much input was used, and advance it 309d4afb5ceSopenharmony_ci */ 310d4afb5ceSopenharmony_ci 311d4afb5ceSopenharmony_ci pmdrx->eb_in.token = pmdrx->eb_in.token + 312d4afb5ceSopenharmony_ci ((unsigned int)pmdrx->eb_in.len - (unsigned int)priv->rx.avail_in); 313d4afb5ceSopenharmony_ci pmdrx->eb_in.len = (int)priv->rx.avail_in; 314d4afb5ceSopenharmony_ci 315d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "%d %d %d %d %d", 316d4afb5ceSopenharmony_ci priv->rx.avail_in, 317d4afb5ceSopenharmony_ci wsi->ws->final, 318d4afb5ceSopenharmony_ci (int)wsi->ws->rx_packet_length, 319d4afb5ceSopenharmony_ci was_fin, 320d4afb5ceSopenharmony_ci wsi->ws->pmd_trailer_application); 321d4afb5ceSopenharmony_ci 322d4afb5ceSopenharmony_ci if (!priv->rx.avail_in && 323d4afb5ceSopenharmony_ci wsi->ws->final && 324d4afb5ceSopenharmony_ci !wsi->ws->rx_packet_length && 325d4afb5ceSopenharmony_ci !was_fin && 326d4afb5ceSopenharmony_ci wsi->ws->pmd_trailer_application) { 327d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "RX trailer apply 2"); 328d4afb5ceSopenharmony_ci 329d4afb5ceSopenharmony_ci /* we overallocated just for this situation where 330d4afb5ceSopenharmony_ci * we might issue something */ 331d4afb5ceSopenharmony_ci priv->rx.avail_out += 5; 332d4afb5ceSopenharmony_ci 333d4afb5ceSopenharmony_ci was_fin = 1; 334d4afb5ceSopenharmony_ci wsi->ws->pmd_trailer_application = 0; 335d4afb5ceSopenharmony_ci priv->rx.next_in = trail; 336d4afb5ceSopenharmony_ci priv->rx.avail_in = sizeof(trail); 337d4afb5ceSopenharmony_ci n = inflate(&priv->rx, Z_SYNC_FLUSH); 338d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "RX trailer infl ret %d, avi %d, avo %d", 339d4afb5ceSopenharmony_ci n, priv->rx.avail_in, priv->rx.avail_out); 340d4afb5ceSopenharmony_ci switch (n) { 341d4afb5ceSopenharmony_ci case Z_NEED_DICT: 342d4afb5ceSopenharmony_ci case Z_STREAM_ERROR: 343d4afb5ceSopenharmony_ci case Z_DATA_ERROR: 344d4afb5ceSopenharmony_ci case Z_MEM_ERROR: 345d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "zlib error inflate %d: %s", 346d4afb5ceSopenharmony_ci n, priv->rx.msg); 347d4afb5ceSopenharmony_ci return -1; 348d4afb5ceSopenharmony_ci } 349d4afb5ceSopenharmony_ci 350d4afb5ceSopenharmony_ci assert(priv->rx.avail_out); 351d4afb5ceSopenharmony_ci } 352d4afb5ceSopenharmony_ci 353d4afb5ceSopenharmony_ci pmdrx->eb_out.len = lws_ptr_diff(priv->rx.next_out, 354d4afb5ceSopenharmony_ci pmdrx->eb_out.token); 355d4afb5ceSopenharmony_ci priv->count_rx_between_fin = priv->count_rx_between_fin + (size_t)pmdrx->eb_out.len; 356d4afb5ceSopenharmony_ci 357d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, " RX leaving with new effbuff len %d, " 358d4afb5ceSopenharmony_ci "rx.avail_in=%d, TOTAL RX since FIN %lu", 359d4afb5ceSopenharmony_ci pmdrx->eb_out.len, priv->rx.avail_in, 360d4afb5ceSopenharmony_ci (unsigned long)priv->count_rx_between_fin); 361d4afb5ceSopenharmony_ci 362d4afb5ceSopenharmony_ci if (was_fin) { 363d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "was_fin"); 364d4afb5ceSopenharmony_ci priv->count_rx_between_fin = 0; 365d4afb5ceSopenharmony_ci if (priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER]) { 366d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "PMD_SERVER_NO_CONTEXT_TAKEOVER"); 367d4afb5ceSopenharmony_ci (void)inflateEnd(&priv->rx); 368d4afb5ceSopenharmony_ci priv->rx_init = 0; 369d4afb5ceSopenharmony_ci } 370d4afb5ceSopenharmony_ci 371d4afb5ceSopenharmony_ci return PMDR_EMPTY_FINAL; 372d4afb5ceSopenharmony_ci } 373d4afb5ceSopenharmony_ci 374d4afb5ceSopenharmony_ci if (priv->rx.avail_in) 375d4afb5ceSopenharmony_ci return PMDR_HAS_PENDING; 376d4afb5ceSopenharmony_ci 377d4afb5ceSopenharmony_ci return PMDR_EMPTY_NONFINAL; 378d4afb5ceSopenharmony_ci 379d4afb5ceSopenharmony_ci case LWS_EXT_CB_PAYLOAD_TX: 380d4afb5ceSopenharmony_ci 381d4afb5ceSopenharmony_ci /* 382d4afb5ceSopenharmony_ci * ie, we are DEFLATING 383d4afb5ceSopenharmony_ci * 384d4afb5ceSopenharmony_ci * initialize us if needed 385d4afb5ceSopenharmony_ci */ 386d4afb5ceSopenharmony_ci 387d4afb5ceSopenharmony_ci if (!priv->tx_init) { 388d4afb5ceSopenharmony_ci n = deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL], 389d4afb5ceSopenharmony_ci Z_DEFLATED, 390d4afb5ceSopenharmony_ci -priv->args[PMD_SERVER_MAX_WINDOW_BITS + 391d4afb5ceSopenharmony_ci (wsi->a.vhost->listen_port <= 0)], 392d4afb5ceSopenharmony_ci priv->args[PMD_MEM_LEVEL], 393d4afb5ceSopenharmony_ci Z_DEFAULT_STRATEGY); 394d4afb5ceSopenharmony_ci if (n != Z_OK) { 395d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "inflateInit2 failed %d", n); 396d4afb5ceSopenharmony_ci return PMDR_FAILED; 397d4afb5ceSopenharmony_ci } 398d4afb5ceSopenharmony_ci priv->tx_init = 1; 399d4afb5ceSopenharmony_ci } 400d4afb5ceSopenharmony_ci 401d4afb5ceSopenharmony_ci if (!priv->buf_tx_deflated) 402d4afb5ceSopenharmony_ci priv->buf_tx_deflated = lws_malloc((unsigned int)(LWS_PRE + 7 + 5 + 403d4afb5ceSopenharmony_ci (1 << priv->args[PMD_TX_BUF_PWR2])), 404d4afb5ceSopenharmony_ci "pmd tx deflate buf"); 405d4afb5ceSopenharmony_ci if (!priv->buf_tx_deflated) { 406d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "OOM"); 407d4afb5ceSopenharmony_ci return PMDR_FAILED; 408d4afb5ceSopenharmony_ci } 409d4afb5ceSopenharmony_ci 410d4afb5ceSopenharmony_ci /* hook us up with any deflated input that the caller has */ 411d4afb5ceSopenharmony_ci 412d4afb5ceSopenharmony_ci if (pmdrx->eb_in.token) { 413d4afb5ceSopenharmony_ci 414d4afb5ceSopenharmony_ci assert(!priv->tx.avail_in); 415d4afb5ceSopenharmony_ci 416d4afb5ceSopenharmony_ci priv->count_tx_between_fin = priv->count_tx_between_fin + (size_t)pmdrx->eb_in.len; 417d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "TX: eb_in length %d, " 418d4afb5ceSopenharmony_ci "TOTAL TX since FIN: %d", 419d4afb5ceSopenharmony_ci pmdrx->eb_in.len, 420d4afb5ceSopenharmony_ci (int)priv->count_tx_between_fin); 421d4afb5ceSopenharmony_ci priv->tx.next_in = (unsigned char *)pmdrx->eb_in.token; 422d4afb5ceSopenharmony_ci priv->tx.avail_in = (uInt)pmdrx->eb_in.len; 423d4afb5ceSopenharmony_ci } 424d4afb5ceSopenharmony_ci 425d4afb5ceSopenharmony_ci priv->tx.next_out = priv->buf_tx_deflated + LWS_PRE + 5; 426d4afb5ceSopenharmony_ci pmdrx->eb_out.token = priv->tx.next_out; 427d4afb5ceSopenharmony_ci priv->tx.avail_out = (uInt)(1 << priv->args[PMD_TX_BUF_PWR2]); 428d4afb5ceSopenharmony_ci 429d4afb5ceSopenharmony_ci pen = 0; 430d4afb5ceSopenharmony_ci penbits = 0; 431d4afb5ceSopenharmony_ci deflatePending(&priv->tx, &pen, &penbits); 432d4afb5ceSopenharmony_ci pen = pen | (unsigned int)penbits; 433d4afb5ceSopenharmony_ci 434d4afb5ceSopenharmony_ci if (!priv->tx.avail_in && (len & LWS_WRITE_NO_FIN)) { 435d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "no available in, pen: %u", pen); 436d4afb5ceSopenharmony_ci 437d4afb5ceSopenharmony_ci if (!pen) 438d4afb5ceSopenharmony_ci return PMDR_DID_NOTHING; 439d4afb5ceSopenharmony_ci } 440d4afb5ceSopenharmony_ci 441d4afb5ceSopenharmony_ci m = Z_NO_FLUSH; 442d4afb5ceSopenharmony_ci if (!(len & LWS_WRITE_NO_FIN)) { 443d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "deflate with SYNC_FLUSH, pkt len %d", 444d4afb5ceSopenharmony_ci (int)wsi->ws->rx_packet_length); 445d4afb5ceSopenharmony_ci m = Z_SYNC_FLUSH; 446d4afb5ceSopenharmony_ci } 447d4afb5ceSopenharmony_ci 448d4afb5ceSopenharmony_ci n = deflate(&priv->tx, m); 449d4afb5ceSopenharmony_ci if (n == Z_STREAM_ERROR) { 450d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, "Z_STREAM_ERROR"); 451d4afb5ceSopenharmony_ci return PMDR_FAILED; 452d4afb5ceSopenharmony_ci } 453d4afb5ceSopenharmony_ci 454d4afb5ceSopenharmony_ci pen = (!priv->tx.avail_out) && n != Z_STREAM_END; 455d4afb5ceSopenharmony_ci 456d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "deflate ret %d, len 0x%x", n, 457d4afb5ceSopenharmony_ci (unsigned int)len); 458d4afb5ceSopenharmony_ci 459d4afb5ceSopenharmony_ci if ((len & 0xf) == LWS_WRITE_TEXT) 460d4afb5ceSopenharmony_ci priv->tx_first_frame_type = LWSWSOPC_TEXT_FRAME; 461d4afb5ceSopenharmony_ci if ((len & 0xf) == LWS_WRITE_BINARY) 462d4afb5ceSopenharmony_ci priv->tx_first_frame_type = LWSWSOPC_BINARY_FRAME; 463d4afb5ceSopenharmony_ci 464d4afb5ceSopenharmony_ci pmdrx->eb_out.len = lws_ptr_diff(priv->tx.next_out, 465d4afb5ceSopenharmony_ci pmdrx->eb_out.token); 466d4afb5ceSopenharmony_ci 467d4afb5ceSopenharmony_ci if (m == Z_SYNC_FLUSH && !(len & LWS_WRITE_NO_FIN) && !pen && 468d4afb5ceSopenharmony_ci pmdrx->eb_out.len < 4) { 469d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "FAIL want to trim out length %d", 470d4afb5ceSopenharmony_ci (int)pmdrx->eb_out.len); 471d4afb5ceSopenharmony_ci assert(0); 472d4afb5ceSopenharmony_ci } 473d4afb5ceSopenharmony_ci 474d4afb5ceSopenharmony_ci if (!(len & LWS_WRITE_NO_FIN) && 475d4afb5ceSopenharmony_ci m == Z_SYNC_FLUSH && 476d4afb5ceSopenharmony_ci !pen && 477d4afb5ceSopenharmony_ci pmdrx->eb_out.len >= 4) { 478d4afb5ceSopenharmony_ci // lwsl_wsi_err(wsi, "Trimming 4 from end of write"); 479d4afb5ceSopenharmony_ci priv->tx.next_out -= 4; 480d4afb5ceSopenharmony_ci priv->tx.avail_out += 4; 481d4afb5ceSopenharmony_ci priv->count_tx_between_fin = 0; 482d4afb5ceSopenharmony_ci 483d4afb5ceSopenharmony_ci assert(priv->tx.next_out[0] == 0x00 && 484d4afb5ceSopenharmony_ci priv->tx.next_out[1] == 0x00 && 485d4afb5ceSopenharmony_ci priv->tx.next_out[2] == 0xff && 486d4afb5ceSopenharmony_ci priv->tx.next_out[3] == 0xff); 487d4afb5ceSopenharmony_ci } 488d4afb5ceSopenharmony_ci 489d4afb5ceSopenharmony_ci 490d4afb5ceSopenharmony_ci /* 491d4afb5ceSopenharmony_ci * track how much input was used and advance it 492d4afb5ceSopenharmony_ci */ 493d4afb5ceSopenharmony_ci 494d4afb5ceSopenharmony_ci pmdrx->eb_in.token = pmdrx->eb_in.token + 495d4afb5ceSopenharmony_ci ((unsigned int)pmdrx->eb_in.len - (unsigned int)priv->tx.avail_in); 496d4afb5ceSopenharmony_ci pmdrx->eb_in.len = (int)priv->tx.avail_in; 497d4afb5ceSopenharmony_ci 498d4afb5ceSopenharmony_ci priv->compressed_out = 1; 499d4afb5ceSopenharmony_ci pmdrx->eb_out.len = lws_ptr_diff(priv->tx.next_out, 500d4afb5ceSopenharmony_ci pmdrx->eb_out.token); 501d4afb5ceSopenharmony_ci 502d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, " TX rewritten with new eb_in len %d, " 503d4afb5ceSopenharmony_ci "eb_out len %d, deflatePending %d", 504d4afb5ceSopenharmony_ci pmdrx->eb_in.len, pmdrx->eb_out.len, pen); 505d4afb5ceSopenharmony_ci 506d4afb5ceSopenharmony_ci if (pmdrx->eb_in.len || pen) 507d4afb5ceSopenharmony_ci return PMDR_HAS_PENDING; 508d4afb5ceSopenharmony_ci 509d4afb5ceSopenharmony_ci if (!(len & LWS_WRITE_NO_FIN)) 510d4afb5ceSopenharmony_ci return PMDR_EMPTY_FINAL; 511d4afb5ceSopenharmony_ci 512d4afb5ceSopenharmony_ci return PMDR_EMPTY_NONFINAL; 513d4afb5ceSopenharmony_ci 514d4afb5ceSopenharmony_ci case LWS_EXT_CB_PACKET_TX_PRESEND: 515d4afb5ceSopenharmony_ci if (!priv->compressed_out) 516d4afb5ceSopenharmony_ci break; 517d4afb5ceSopenharmony_ci priv->compressed_out = 0; 518d4afb5ceSopenharmony_ci 519d4afb5ceSopenharmony_ci /* 520d4afb5ceSopenharmony_ci * we may have not produced any output for the actual "first" 521d4afb5ceSopenharmony_ci * write... in that case, we need to fix up the inappropriate 522d4afb5ceSopenharmony_ci * use of CONTINUATION when the first real write does come. 523d4afb5ceSopenharmony_ci */ 524d4afb5ceSopenharmony_ci if (priv->tx_first_frame_type & 0xf) { 525d4afb5ceSopenharmony_ci *pmdrx->eb_in.token = (unsigned char)((((unsigned char)*pmdrx->eb_in.token) & (unsigned char)~0xf) | 526d4afb5ceSopenharmony_ci ((unsigned char)priv->tx_first_frame_type & (unsigned char)0xf)); 527d4afb5ceSopenharmony_ci /* 528d4afb5ceSopenharmony_ci * We have now written the "first" fragment, only 529d4afb5ceSopenharmony_ci * do that once 530d4afb5ceSopenharmony_ci */ 531d4afb5ceSopenharmony_ci priv->tx_first_frame_type = 0; 532d4afb5ceSopenharmony_ci } 533d4afb5ceSopenharmony_ci 534d4afb5ceSopenharmony_ci n = *(pmdrx->eb_in.token) & 15; 535d4afb5ceSopenharmony_ci 536d4afb5ceSopenharmony_ci /* set RSV1, but not on CONTINUATION */ 537d4afb5ceSopenharmony_ci if (n == LWSWSOPC_TEXT_FRAME || n == LWSWSOPC_BINARY_FRAME) 538d4afb5ceSopenharmony_ci *pmdrx->eb_in.token |= 0x40; 539d4afb5ceSopenharmony_ci 540d4afb5ceSopenharmony_ci lwsl_wsi_ext(wsi, "PRESEND compressed: ws frame 0x%02X, len %d", 541d4afb5ceSopenharmony_ci ((*pmdrx->eb_in.token) & 0xff), 542d4afb5ceSopenharmony_ci pmdrx->eb_in.len); 543d4afb5ceSopenharmony_ci 544d4afb5ceSopenharmony_ci if (((*pmdrx->eb_in.token) & 0x80) && /* fin */ 545d4afb5ceSopenharmony_ci priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) { 546d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "PMD_CLIENT_NO_CONTEXT_TAKEOVER"); 547d4afb5ceSopenharmony_ci (void)deflateEnd(&priv->tx); 548d4afb5ceSopenharmony_ci priv->tx_init = 0; 549d4afb5ceSopenharmony_ci } 550d4afb5ceSopenharmony_ci 551d4afb5ceSopenharmony_ci break; 552d4afb5ceSopenharmony_ci 553d4afb5ceSopenharmony_ci default: 554d4afb5ceSopenharmony_ci break; 555d4afb5ceSopenharmony_ci } 556d4afb5ceSopenharmony_ci 557d4afb5ceSopenharmony_ci return 0; 558d4afb5ceSopenharmony_ci} 559d4afb5ceSopenharmony_ci 560