diff --git a/lib/Makefile.am b/lib/Makefile.am index b6198b67..3b5f4fd2 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -8,6 +8,7 @@ dist_libwebsockets_la_SOURCES=libwebsockets.c \ client-handshake.c \ extension.c \ extension-deflate-stream.c extension-deflate-stream.h \ + extension-deflate-frame.c extension-deflate-frame.h\ private-libwebsockets.h diff --git a/lib/extension-deflate-frame.c b/lib/extension-deflate-frame.c new file mode 100644 index 00000000..09e27008 --- /dev/null +++ b/lib/extension-deflate-frame.c @@ -0,0 +1,205 @@ +#include "private-libwebsockets.h" +#include "extension-deflate-frame.h" +#include +#include +#include + +#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; + int n; + + 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) { + lws_log(LWS_LOG_WARNING, "deflateInit returned %d", n); + return 1; + } + n = deflateInit2(&conn->zs_out, + DEFLATE_FRAME_COMPRESSION_LEVEL, Z_DEFLATED, + -LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL, + Z_DEFAULT_STRATEGY); + if (n != Z_OK) { + lws_log(LWS_LOG_WARNING, "deflateInit returned %d", n); + return 1; + } + conn->buf_in_length = MAX_USER_RX_BUFFER; + conn->buf_out_length = MAX_USER_RX_BUFFER; + conn->compressed_out = 0; + conn->buf_in = (unsigned char *)malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_in_length + + LWS_SEND_BUFFER_POST_PADDING); + conn->buf_out = (unsigned char *)malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_out_length + + LWS_SEND_BUFFER_POST_PADDING); + lws_log(LWS_LOG_DEBUG, "zlibs constructed"); + break; + + case LWS_EXT_CALLBACK_DESTROY: + free(conn->buf_in); + free(conn->buf_out); + conn->buf_in_length = 0; + conn->buf_out_length = 0; + conn->compressed_out = 0; + (void)inflateEnd(&conn->zs_in); + (void)deflateEnd(&conn->zs_out); + lws_log(LWS_LOG_DEBUG, "zlibs destructed"); + break; + + case LWS_EXT_CALLBACK_PAYLOAD_RX: + if ((libwebsocket_get_reserved_bits(wsi) & 0x40) == 0) + return 0; + + /* + * inflate the incoming payload + */ + conn->zs_in.next_in = (unsigned char *)eff_buf->token; + conn->zs_in.avail_in = eff_buf->token_len; + + conn->zs_in.next_in[eff_buf->token_len + 0] = 0; + conn->zs_in.next_in[eff_buf->token_len + 1] = 0; + conn->zs_in.next_in[eff_buf->token_len + 2] = 0xff; + conn->zs_in.next_in[eff_buf->token_len + 3] = 0xff; + conn->zs_in.avail_in += 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_DATA_ERROR: + case Z_MEM_ERROR: + /* + * screwed.. close the connection... we will get a + * destroy callback to take care of closing nicely + */ + lws_log(LWS_LOG_ERROR, "zlib error inflate %d: %s", n, conn->zs_in.msg); + return -1; + } + + if (conn->zs_in.avail_in > 0) + { + size_t len_so_far = (conn->zs_in.next_out - (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING)); + unsigned char *new_buf; + conn->buf_in_length *= 2; + new_buf = (unsigned char *)malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_in_length + + LWS_SEND_BUFFER_POST_PADDING); + memcpy(new_buf + LWS_SEND_BUFFER_PRE_PADDING, + conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING, + len_so_far); + free(conn->buf_in); + conn->buf_in = new_buf; + conn->zs_in.next_out = (new_buf + LWS_SEND_BUFFER_PRE_PADDING + len_so_far); + conn->zs_in.avail_out = (conn->buf_in_length - len_so_far); + } + else + { + break; + } + } + + /* 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 + */ + conn->zs_out.next_in = (unsigned char *)eff_buf->token; + conn->zs_out.avail_in = eff_buf->token_len; + + 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 + */ + lws_log(LWS_LOG_ERROR, "zlib error deflate"); + + return -1; + } + + if (conn->zs_out.avail_in > 0) + { + size_t len_so_far = (conn->zs_out.next_out - (conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING)); + unsigned char *new_buf; + conn->buf_out_length *= 2; + new_buf = (unsigned char *)malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_out_length + + LWS_SEND_BUFFER_POST_PADDING); + memcpy(new_buf + LWS_SEND_BUFFER_PRE_PADDING, + conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING, + len_so_far); + free(conn->buf_out); + conn->buf_out = new_buf; + conn->zs_out.next_out = (new_buf + LWS_SEND_BUFFER_PRE_PADDING + len_so_far); + conn->zs_out.avail_out = (conn->buf_out_length - len_so_far); + } + else + { + break; + } + } + + 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") == 0) + { + return 1; + } + break; + + default: + break; + } + + return 0; +} diff --git a/lib/extension-deflate-frame.h b/lib/extension-deflate-frame.h new file mode 100644 index 00000000..88b27c1e --- /dev/null +++ b/lib/extension-deflate-frame.h @@ -0,0 +1,21 @@ + +#include + +#define DEFLATE_FRAME_COMPRESSION_LEVEL 1 + +struct lws_ext_deflate_frame_conn { + z_stream zs_in; + z_stream zs_out; + int buf_in_length; + int buf_out_length; + int compressed_out; + unsigned char *buf_in; + unsigned char *buf_out; +}; + +extern 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); diff --git a/lib/extension.c b/lib/extension.c index 89093087..c302f416 100644 --- a/lib/extension.c +++ b/lib/extension.c @@ -1,5 +1,6 @@ #include "private-libwebsockets.h" +#include "extension-deflate-frame.h" #include "extension-deflate-stream.h" #include "extension-x-google-mux.h" @@ -11,11 +12,24 @@ struct libwebsocket_extension libwebsocket_internal_extensions[] = { sizeof (struct lws_ext_x_google_mux_conn) }, #endif +#ifdef LWS_EXT_DEFLATE_STREAM { "deflate-stream", lws_extension_callback_deflate_stream, sizeof (struct lws_ext_deflate_stream_conn) }, +#else + { + "x-webkit-deflate-frame", + lws_extension_callback_deflate_frame, + sizeof (struct lws_ext_deflate_frame_conn) + }, + { + "deflate-frame", + lws_extension_callback_deflate_frame, + sizeof (struct lws_ext_deflate_frame_conn) + }, +#endif { /* terminator */ NULL, NULL, 0 } diff --git a/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj index 8c371f3f..e199c14b 100644 --- a/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj +++ b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj @@ -1,274 +1,279 @@ - - - - - Debug static - Win32 - - - Debug - Win32 - - - Debug - x64 - - - Release DLL - Win32 - - - Release DLL - x64 - - - Release static - Win32 - - - Release - Win32 - - - Release - x64 - - - - {332BF17E-FD30-4363-975A-AA731A827B4F} - Win32Proj - libwebsocketswin32 - - - - StaticLibrary - true - Unicode - - - StaticLibrary - true - Unicode - - - StaticLibrary - true - Unicode - - - StaticLibrary - true - Unicode - - - StaticLibrary - false - true - Unicode - - - StaticLibrary - false - true - Unicode - - - StaticLibrary - - - DynamicLibrary - true - - - - - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\output\ - D:\Libraries\libwebsockets\output\;$(LibraryPath) - libwebsockets_vc100-mt-sgd - - - D:\Libraries\libwebsockets\output\;$(LibraryPath) - - - D:\Libraries\libwebsockets\output\;$(LibraryPath) - - - libwebsockets_vc100-mt-s - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ../win32helpers;../zlib - false - - - Windows - true - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ../win32helpers;../zlib - MultiThreadedDebug - false - - - Windows - true - - - $(OutDir)libwebsockets_vc100-mt-sgd$(TargetExt) - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ../win32helpers;../zlib - - - Windows - true - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ../win32helpers;../zlib - - - Windows - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - ../win32helpers;../zlib - MultiThreaded - false - - - Windows - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - ../win32helpers;../zlib - - - Windows - true - true - true - - - - - ../win32helpers;../zlib - WIN32 - false - MultiThreaded - - - $(OutDir)libwebsockets_vc100-mt-s.lib - - - - - ../win32helpers;../zlib - WIN32;LWS_INTERNAL;LWS_DLL - false - MultiThreaded - false - Speed - true - - - $(OutDir)libwebsockets_vc100-mt-s.lib - - - Ws2_32.lib;..\..\output\ZLib_vc100-mt-s.lib;%(AdditionalDependencies) - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + Debug static + Win32 + + + Debug + Win32 + + + Debug + x64 + + + Release DLL + Win32 + + + Release DLL + x64 + + + Release static + Win32 + + + Release + Win32 + + + Release + x64 + + + + {332BF17E-FD30-4363-975A-AA731A827B4F} + Win32Proj + libwebsocketswin32 + + + + StaticLibrary + true + Unicode + + + StaticLibrary + true + Unicode + + + StaticLibrary + true + Unicode + + + StaticLibrary + true + Unicode + + + StaticLibrary + false + true + Unicode + + + StaticLibrary + false + true + Unicode + + + StaticLibrary + + + DynamicLibrary + true + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)..\output\ + D:\Libraries\libwebsockets\output\;$(LibraryPath) + libwebsockets_vc100-mt-sgd + + + D:\Libraries\libwebsockets\output\;$(LibraryPath) + + + D:\Libraries\libwebsockets\output\;$(LibraryPath) + + + libwebsockets_vc100-mt-s + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + false + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + MultiThreadedDebug + false + + + Windows + true + + + $(OutDir)libwebsockets_vc100-mt-sgd$(TargetExt) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + MultiThreaded + false + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + + + Windows + true + true + true + + + + + ../win32helpers;../zlib + WIN32 + false + MultiThreaded + + + $(OutDir)libwebsockets_vc100-mt-s.lib + + + + + ../win32helpers;../zlib + WIN32;LWS_INTERNAL;LWS_DLL + false + MultiThreaded + false + Speed + true + StreamingSIMDExtensions2 + Fast + true + + + $(OutDir)libwebsockets_vc100-mt-s.lib + + + Ws2_32.lib;..\..\output\ZLib_vc100-mt-s.lib;%(AdditionalDependencies) + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters index 3c6edbb3..05ff11a2 100644 --- a/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters +++ b/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters @@ -1,72 +1,78 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Source Files - - - Header Files - - - \ No newline at end of file + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + +