diff options
Diffstat (limited to 'src/engine/external/libwebsockets/extension-deflate-frame.c')
| -rw-r--r-- | src/engine/external/libwebsockets/extension-deflate-frame.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/src/engine/external/libwebsockets/extension-deflate-frame.c b/src/engine/external/libwebsockets/extension-deflate-frame.c new file mode 100644 index 00000000..13b2b8de --- /dev/null +++ b/src/engine/external/libwebsockets/extension-deflate-frame.c @@ -0,0 +1,288 @@ +#include "private-libwebsockets.h" +#include "extension-deflate-frame.h" +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#define LWS_ZLIB_WINDOW_BITS 15 +#define LWS_ZLIB_MEMLEVEL 8 + +int lws_extension_callback_deflate_frame( + struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct lws_ext_deflate_frame_conn *conn = + (struct lws_ext_deflate_frame_conn *)user; + struct lws_tokens *eff_buf = (struct lws_tokens *)in; + size_t current_payload, remaining_payload, total_payload; + int n; + size_t len_so_far; + + switch (reason) { + + /* + * for deflate-frame, both client and server sides act the same + */ + + case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: + case LWS_EXT_CALLBACK_CONSTRUCT: + conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL; + conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL; + conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL; + n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS); + if (n != Z_OK) { + lwsl_ext("deflateInit returned %d\n", n); + return 1; + } + n = deflateInit2(&conn->zs_out, + (context->listen_port ? + DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER : + DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT), + Z_DEFLATED, + -LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL, + Z_DEFAULT_STRATEGY); + if (n != Z_OK) { + lwsl_ext("deflateInit2 returned %d\n", n); + return 1; + } + conn->buf_pre_used = 0; + conn->buf_pre_length = 0; + conn->buf_in_length = sizeof(conn->buf_in); + conn->buf_out_length = sizeof(conn->buf_out); + conn->compressed_out = 0; + conn->buf_pre = NULL; + conn->buf_in = lws_malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_in_length + + LWS_SEND_BUFFER_POST_PADDING); + if (!conn->buf_in) + goto bail; + conn->buf_out = lws_malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_out_length + + LWS_SEND_BUFFER_POST_PADDING); + if (!conn->buf_out) + goto bail; + lwsl_ext("zlibs constructed\n"); + break; +bail: + lwsl_err("Out of mem\n"); + (void)inflateEnd(&conn->zs_in); + (void)deflateEnd(&conn->zs_out); + return -1; + + case LWS_EXT_CALLBACK_DESTROY: + lws_free(conn->buf_pre); + lws_free(conn->buf_in); + lws_free(conn->buf_out); + conn->buf_pre_used = 0; + conn->buf_pre_length = 0; + conn->buf_in_length = 0; + conn->buf_out_length = 0; + conn->compressed_out = 0; + (void)inflateEnd(&conn->zs_in); + (void)deflateEnd(&conn->zs_out); + lwsl_ext("zlibs destructed\n"); + break; + + case LWS_EXT_CALLBACK_PAYLOAD_RX: + if (!(wsi->u.ws.rsv & 0x40)) + return 0; + + /* + * inflate the incoming payload + */ + current_payload = eff_buf->token_len; + + remaining_payload = wsi->u.ws.rx_packet_length; + if (remaining_payload) { + total_payload = conn->buf_pre_used + + current_payload + + remaining_payload; + + if (conn->buf_pre_length < total_payload) { + conn->buf_pre_length = total_payload; + lws_free(conn->buf_pre); + conn->buf_pre = lws_malloc(total_payload + 4); + if (!conn->buf_pre) { + lwsl_err("Out of memory\n"); + return -1; + } + } + + memcpy(conn->buf_pre + conn->buf_pre_used, + eff_buf->token, current_payload); + conn->buf_pre_used += current_payload; + + eff_buf->token = NULL; + eff_buf->token_len = 0; + + return 0; + } + if (conn->buf_pre_used) { + total_payload = conn->buf_pre_used + + current_payload; + + memcpy(conn->buf_pre + conn->buf_pre_used, + eff_buf->token, current_payload); + conn->buf_pre_used = 0; + + conn->zs_in.next_in = conn->buf_pre; + } else { + total_payload = current_payload; + + conn->zs_in.next_in = (unsigned char *)eff_buf->token; + } + + conn->zs_in.next_in[total_payload + 0] = 0; + conn->zs_in.next_in[total_payload + 1] = 0; + conn->zs_in.next_in[total_payload + 2] = 0xff; + conn->zs_in.next_in[total_payload + 3] = 0xff; + + conn->zs_in.avail_in = total_payload + 4; + + conn->zs_in.next_out = + conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING; + conn->zs_in.avail_out = conn->buf_in_length; + + while (1) { + n = inflate(&conn->zs_in, Z_SYNC_FLUSH); + switch (n) { + case Z_NEED_DICT: + case Z_STREAM_ERROR: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + /* + * screwed.. close the connection... + * we will get a destroy callback to take care + * of closing nicely + */ + lwsl_info("zlib error inflate %d: %s\n", + n, conn->zs_in.msg); + return -1; + } + + if (conn->zs_in.avail_out) + break; + + len_so_far = conn->zs_in.next_out - + (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING); + + conn->buf_in_length *= 2; + if (conn->buf_in_length > LWS_MAX_ZLIB_CONN_BUFFER) { + lwsl_ext("zlib in buffer hit limit %u\n", + LWS_MAX_ZLIB_CONN_BUFFER); + return -1; + } + conn->buf_in = lws_realloc(conn->buf_in, + LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_in_length + + LWS_SEND_BUFFER_POST_PADDING); + if (!conn->buf_in) { + lwsl_err("Out of memory\n"); + return -1; + } + lwsl_debug( + "deflate-frame ext RX did realloc to %ld\n", + conn->buf_in_length); + conn->zs_in.next_out = conn->buf_in + + LWS_SEND_BUFFER_PRE_PADDING + len_so_far; + conn->zs_in.avail_out = + conn->buf_in_length - len_so_far; + } + + /* rewrite the buffer pointers and length */ + eff_buf->token = + (char *)(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING); + eff_buf->token_len = (int)(conn->zs_in.next_out - + (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING)); + + return 0; + + case LWS_EXT_CALLBACK_PAYLOAD_TX: + /* + * deflate the outgoing payload + */ + current_payload = eff_buf->token_len; + + conn->zs_out.next_in = (unsigned char *)eff_buf->token; + conn->zs_out.avail_in = current_payload; + + conn->zs_out.next_out = + conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING; + conn->zs_out.avail_out = conn->buf_out_length; + + while (1) { + n = deflate(&conn->zs_out, Z_SYNC_FLUSH); + if (n == Z_STREAM_ERROR) { + /* + * screwed.. close the connection... we will + * get a destroy callback to take care of + * closing nicely + */ + lwsl_ext("zlib error deflate\n"); + + return -1; + } + + if (conn->zs_out.avail_out) + break; + + len_so_far = (conn->zs_out.next_out - + (conn->buf_out + + LWS_SEND_BUFFER_PRE_PADDING)); + conn->buf_out_length *= 2; + if (conn->buf_out_length > LWS_MAX_ZLIB_CONN_BUFFER) { + lwsl_ext("zlib out hit limit %u\n", + LWS_MAX_ZLIB_CONN_BUFFER); + return -1; + } + conn->buf_out = lws_realloc(conn->buf_out, + LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_out_length + + LWS_SEND_BUFFER_POST_PADDING); + if (!conn->buf_out) { + lwsl_err("Out of memory\n"); + return -1; + } + lwsl_debug( + "deflate-frame ext TX did realloc to %ld\n", + conn->buf_in_length); + + conn->zs_out.next_out = (conn->buf_out + + LWS_SEND_BUFFER_PRE_PADDING + len_so_far); + conn->zs_out.avail_out = + (conn->buf_out_length - len_so_far); + } + + conn->compressed_out = 1; + + /* rewrite the buffer pointers and length */ + eff_buf->token = (char *)(conn->buf_out + + LWS_SEND_BUFFER_PRE_PADDING); + eff_buf->token_len = (int)(conn->zs_out.next_out - + (conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING)) - 4; + + return 0; + + case LWS_EXT_CALLBACK_PACKET_TX_PRESEND: + if (conn->compressed_out) { + conn->compressed_out = 0; + *((unsigned char *)eff_buf->token) |= 0x40; + } + break; + + case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION: + /* Avoid x-webkit-deflate-frame extension on client */ + if (!strcmp((char *)in, "x-webkit-deflate-frame")) + return 1; + break; + + default: + break; + } + + return 0; +} + |