123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- #include "private-libwebsockets.h"
- #include "extension-permessage-deflate.h"
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- #define LWS_ZLIB_MEMLEVEL 8
- const struct lws_ext_options lws_ext_pm_deflate_options[] = {
-
- { "server_no_context_takeover", EXTARG_NONE },
- { "client_no_context_takeover", EXTARG_NONE },
- { "server_max_window_bits", EXTARG_OPT_DEC },
- { "client_max_window_bits", EXTARG_OPT_DEC },
-
- { "rx_buf_size", EXTARG_DEC },
- { "tx_buf_size", EXTARG_DEC },
- { "compression_level", EXTARG_DEC },
- { "mem_level", EXTARG_DEC },
- { NULL, 0 },
- };
- static void
- lws_extension_pmdeflate_restrict_args(struct lws *wsi,
- struct lws_ext_pm_deflate_priv *priv)
- {
- int n, extra;
-
- n = wsi->context->pt_serv_buf_size;
- if (wsi->protocol->rx_buffer_size)
- n = wsi->protocol->rx_buffer_size;
- extra = 7;
- while (n >= 1 << (extra + 1))
- extra++;
- if (extra < priv->args[PMD_RX_BUF_PWR2]) {
- priv->args[PMD_RX_BUF_PWR2] = extra;
- lwsl_err(" Capping pmd rx to %d\n", 1 << extra);
- }
- }
- LWS_VISIBLE int
- lws_extension_callback_pm_deflate(struct lws_context *context,
- const struct lws_extension *ext,
- struct lws *wsi,
- enum lws_extension_callback_reasons reason,
- void *user, void *in, size_t len)
- {
- struct lws_ext_pm_deflate_priv *priv =
- (struct lws_ext_pm_deflate_priv *)user;
- struct lws_tokens *eff_buf = (struct lws_tokens *)in;
- static unsigned char trail[] = { 0, 0, 0xff, 0xff };
- int n, ret = 0, was_fin = 0, extra;
- struct lws_ext_option_arg *oa;
- switch (reason) {
- case LWS_EXT_CB_NAMED_OPTION_SET:
- oa = in;
- if (!oa->option_name)
- break;
- for (n = 0; n < ARRAY_SIZE(lws_ext_pm_deflate_options); n++)
- if (!strcmp(lws_ext_pm_deflate_options[n].name, oa->option_name))
- break;
- if (n == ARRAY_SIZE(lws_ext_pm_deflate_options))
- break;
- oa->option_index = n;
-
- case LWS_EXT_CB_OPTION_SET:
- oa = in;
- lwsl_info("%s: option set: idx %d, %s, len %d\n", __func__,
- oa->option_index, oa->start, oa->len);
- if (oa->start)
- priv->args[oa->option_index] = atoi(oa->start);
- else
- priv->args[oa->option_index] = 1;
- lws_extension_pmdeflate_restrict_args(wsi, priv);
- break;
- case LWS_EXT_CB_OPTION_CONFIRM:
- if (priv->args[PMD_SERVER_MAX_WINDOW_BITS] < 8 ||
- priv->args[PMD_SERVER_MAX_WINDOW_BITS] > 15 ||
- priv->args[PMD_CLIENT_MAX_WINDOW_BITS] < 8 ||
- priv->args[PMD_CLIENT_MAX_WINDOW_BITS] > 15)
- return -1;
- break;
- case LWS_EXT_CB_CLIENT_CONSTRUCT:
- case LWS_EXT_CB_CONSTRUCT:
- n = context->pt_serv_buf_size;
- if (wsi->protocol->rx_buffer_size)
- n = wsi->protocol->rx_buffer_size;
- if (n < 128) {
- lwsl_err(" permessage-deflate requires the protocol (%s) to have an RX buffer >= 128\n",
- wsi->protocol->name);
- return -1;
- }
-
- priv = lws_zalloc(sizeof(*priv));
- *((void **)user) = priv;
- lwsl_ext("%s: LWS_EXT_CB_*CONSTRUCT\n", __func__);
- memset(priv, 0, sizeof(*priv));
-
- if (in)
- *((const struct lws_ext_options **)in) =
- lws_ext_pm_deflate_options;
-
- case LWS_EXT_CB_OPTION_DEFAULT:
-
- priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER] = 0,
- priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER] = 0;
- priv->args[PMD_SERVER_MAX_WINDOW_BITS] = 15;
- priv->args[PMD_CLIENT_MAX_WINDOW_BITS] = 15;
-
- priv->args[PMD_RX_BUF_PWR2] = 10;
- priv->args[PMD_TX_BUF_PWR2] = 10;
- priv->args[PMD_COMP_LEVEL] = 1;
- priv->args[PMD_MEM_LEVEL] = 8;
- lws_extension_pmdeflate_restrict_args(wsi, priv);
- break;
- case LWS_EXT_CB_DESTROY:
- lwsl_ext("%s: LWS_EXT_CB_DESTROY\n", __func__);
- lws_free(priv->buf_rx_inflated);
- lws_free(priv->buf_tx_deflated);
- if (priv->rx_init)
- (void)inflateEnd(&priv->rx);
- if (priv->tx_init)
- (void)deflateEnd(&priv->tx);
- lws_free(priv);
- return ret;
- case LWS_EXT_CB_PAYLOAD_RX:
- lwsl_ext(" %s: LWS_EXT_CB_PAYLOAD_RX: in %d, existing in %d\n",
- __func__, eff_buf->token_len, priv->rx.avail_in);
- if (!(wsi->u.ws.rsv_first_msg & 0x40))
- return 0;
- #if 0
- for (n = 0; n < eff_buf->token_len; n++) {
- printf("%02X ", (unsigned char)eff_buf->token[n]);
- if ((n & 15) == 15)
- printf("\n");
- }
- printf("\n");
- #endif
- if (!priv->rx_init)
- if (inflateInit2(&priv->rx, -priv->args[PMD_SERVER_MAX_WINDOW_BITS]) != Z_OK) {
- lwsl_err("%s: iniflateInit failed\n", __func__);
- return -1;
- }
- priv->rx_init = 1;
- if (!priv->buf_rx_inflated)
- priv->buf_rx_inflated = lws_malloc(LWS_PRE + 7 + 5 +
- (1 << priv->args[PMD_RX_BUF_PWR2]));
- if (!priv->buf_rx_inflated) {
- lwsl_err("%s: OOM\n", __func__);
- return -1;
- }
-
- if (!priv->rx.avail_in && eff_buf->token && eff_buf->token_len) {
- priv->rx.next_in = (unsigned char *)eff_buf->token;
- priv->rx.avail_in = eff_buf->token_len;
- }
- priv->rx.next_out = priv->buf_rx_inflated + LWS_PRE;
- eff_buf->token = (char *)priv->rx.next_out;
- priv->rx.avail_out = 1 << priv->args[PMD_RX_BUF_PWR2];
- if (priv->rx_held_valid) {
- lwsl_ext("-- RX piling on held byte --\n");
- *(priv->rx.next_out++) = priv->rx_held;
- priv->rx.avail_out--;
- priv->rx_held_valid = 0;
- }
-
- if (!priv->rx.avail_in && wsi->u.ws.final &&
- !wsi->u.ws.rx_packet_length) {
- lwsl_ext("RX APPEND_TRAILER-DO\n");
- was_fin = 1;
- priv->rx.next_in = trail;
- priv->rx.avail_in = sizeof(trail);
- }
- n = inflate(&priv->rx, Z_NO_FLUSH);
- lwsl_ext("inflate ret %d, avi %d, avo %d, wsifinal %d\n", n,
- priv->rx.avail_in, priv->rx.avail_out, wsi->u.ws.final);
- switch (n) {
- case Z_NEED_DICT:
- case Z_STREAM_ERROR:
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- lwsl_info("zlib error inflate %d: %s\n",
- n, priv->rx.msg);
- return -1;
- }
-
- if (!priv->rx.avail_in && wsi->u.ws.final &&
- !wsi->u.ws.rx_packet_length && !was_fin &&
- priv->rx.avail_out
- ) {
- lwsl_ext("RX APPEND_TRAILER-DO\n");
- was_fin = 1;
- priv->rx.next_in = trail;
- priv->rx.avail_in = sizeof(trail);
- n = inflate(&priv->rx, Z_SYNC_FLUSH);
- lwsl_ext("RX trailer inf returned %d, avi %d, avo %d\n", n,
- priv->rx.avail_in, priv->rx.avail_out);
- switch (n) {
- case Z_NEED_DICT:
- case Z_STREAM_ERROR:
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- lwsl_info("zlib error inflate %d: %s\n",
- n, priv->rx.msg);
- return -1;
- }
- }
-
- if (!priv->rx.avail_out) {
- lwsl_ext("-- rx grabbing held --\n");
-
- priv->rx_held = *(--priv->rx.next_out);
- priv->rx_held_valid = 1;
- }
- eff_buf->token_len = (char *)priv->rx.next_out - eff_buf->token;
- priv->count_rx_between_fin += eff_buf->token_len;
- lwsl_ext(" %s: RX leaving with new effbuff len %d, "
- "ret %d, rx.avail_in=%d, TOTAL RX since FIN %lu\n",
- __func__, eff_buf->token_len, priv->rx_held_valid,
- priv->rx.avail_in,
- (unsigned long)priv->count_rx_between_fin);
- if (was_fin) {
- priv->count_rx_between_fin = 0;
- if (priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER]) {
- (void)inflateEnd(&priv->rx);
- priv->rx_init = 0;
- }
- }
- #if 0
- for (n = 0; n < eff_buf->token_len; n++)
- putchar(eff_buf->token[n]);
- puts("\n");
- #endif
- return priv->rx_held_valid;
- case LWS_EXT_CB_PAYLOAD_TX:
- if (!priv->tx_init)
- if (deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
- Z_DEFLATED,
- -priv->args[PMD_CLIENT_MAX_WINDOW_BITS +
- !wsi->vhost->listen_port],
- priv->args[PMD_MEM_LEVEL],
- Z_DEFAULT_STRATEGY) != Z_OK) {
- lwsl_ext("inflateInit2 failed\n");
- return 1;
- }
- priv->tx_init = 1;
- if (!priv->buf_tx_deflated)
- priv->buf_tx_deflated = lws_malloc(LWS_PRE + 7 + 5 +
- (1 << priv->args[PMD_TX_BUF_PWR2]));
- if (!priv->buf_tx_deflated) {
- lwsl_err("%s: OOM\n", __func__);
- return -1;
- }
- if (eff_buf->token) {
- lwsl_ext("%s: TX: eff_buf length %d\n", __func__,
- eff_buf->token_len);
- priv->tx.next_in = (unsigned char *)eff_buf->token;
- priv->tx.avail_in = eff_buf->token_len;
- }
- #if 0
- for (n = 0; n < eff_buf->token_len; n++) {
- printf("%02X ", (unsigned char)eff_buf->token[n]);
- if ((n & 15) == 15)
- printf("\n");
- }
- printf("\n");
- #endif
- priv->tx.next_out = priv->buf_tx_deflated + LWS_PRE + 5;
- eff_buf->token = (char *)priv->tx.next_out;
- priv->tx.avail_out = 1 << priv->args[PMD_TX_BUF_PWR2];
- n = deflate(&priv->tx, Z_SYNC_FLUSH);
- if (n == Z_STREAM_ERROR) {
- lwsl_ext("%s: Z_STREAM_ERROR\n", __func__);
- return -1;
- }
- if (priv->tx_held_valid) {
- priv->tx_held_valid = 0;
- if (priv->tx.avail_out == 1 << priv->args[PMD_TX_BUF_PWR2])
-
- *(--eff_buf->token) = priv->tx_held[0];
- else {
-
- eff_buf->token -= 5;
- for (n = 0; n < 5; n++)
- eff_buf->token[n] = priv->tx_held[n];
- }
- }
- priv->compressed_out = 1;
- eff_buf->token_len = (int)(priv->tx.next_out -
- (unsigned char *)eff_buf->token);
-
- extra = !!(len & LWS_WRITE_NO_FIN) || !priv->tx.avail_out;
- if (eff_buf->token_len >= 4 + extra) {
- lwsl_ext("tx held %d\n", 4 + extra);
- priv->tx_held_valid = extra;
- for (n = 3 + extra; n >= 0; n--)
- priv->tx_held[n] = *(--priv->tx.next_out);
- eff_buf->token_len -= 4 + extra;
- }
- lwsl_ext(" TX rewritten with new effbuff len %d, ret %d\n",
- eff_buf->token_len, !priv->tx.avail_out);
- return !priv->tx.avail_out;
- case LWS_EXT_CB_PACKET_TX_PRESEND:
- if (!priv->compressed_out)
- break;
- priv->compressed_out = 0;
- if ((*(eff_buf->token) & 0x80) && priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {
- (void)deflateEnd(&priv->tx);
- priv->tx_init = 0;
- }
- n = *(eff_buf->token) & 15;
-
- if (n == LWSWSOPC_TEXT_FRAME || n == LWSWSOPC_BINARY_FRAME)
- *eff_buf->token |= 0x40;
- #if 0
- for (n = 0; n < eff_buf->token_len; n++) {
- printf("%02X ", (unsigned char)eff_buf->token[n]);
- if ((n & 15) == 15)
- puts("\n");
- }
- puts("\n");
- #endif
- lwsl_ext("%s: tx opcode 0x%02X\n", __func__,
- (unsigned char)*eff_buf->token);
- break;
- default:
- break;
- }
- return 0;
- }
|