@encharm/cws 4.5.3 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/CLAUDE.md +83 -0
- package/README.md +20 -4
- package/binding.gyp +8 -2
- package/dist/bindings/cws_darwin_arm64_node115.node +0 -0
- package/dist/bindings/cws_darwin_arm64_node127.node +0 -0
- package/dist/bindings/cws_darwin_arm64_node137.node +0 -0
- package/dist/bindings/cws_darwin_arm64_node147.node +0 -0
- package/dist/bindings/cws_linux_arm64_node115.node +0 -0
- package/dist/bindings/cws_linux_arm64_node127.node +0 -0
- package/dist/bindings/cws_linux_arm64_node137.node +0 -0
- package/dist/bindings/cws_linux_arm64_node147.node +0 -0
- package/dist/bindings/cws_linux_x64_node115.node +0 -0
- package/dist/bindings/cws_linux_x64_node127.node +0 -0
- package/dist/bindings/cws_linux_x64_node137.node +0 -0
- package/dist/bindings/cws_linux_x64_node147.node +0 -0
- package/dist/bindings/cws_win32_x64_node115.node +0 -0
- package/dist/bindings/cws_win32_x64_node127.node +0 -0
- package/dist/bindings/cws_win32_x64_node137.node +0 -0
- package/dist/bindings/cws_win32_x64_node147.node +0 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +15 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +2 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +16 -2
- package/dist/shared.d.ts +1 -0
- package/dist/shared.js +3 -2
- package/package.json +1 -1
- package/src/Addon.cpp +4 -1
- package/src/Addon.h +80 -15
- package/src/Extensions.cpp +7 -1
- package/src/Extensions.h +2 -1
- package/src/Group.cpp +1 -1
- package/src/Group.h +4 -1
- package/src/HTTPSocket.cpp +1 -1
- package/src/Hub.cpp +11 -76
- package/src/Hub.h +12 -10
- package/src/Networking.h +11 -0
- package/src/Socket.h +201 -6
- package/src/WebSocket.cpp +8 -5
- package/src/Zlib.cpp +138 -0
- package/src/Zlib.h +38 -0
- package/src/cSNode.cpp +2 -0
- package/src/cSNode.h +4 -0
- package/src/headers/26/acorn_version.h +6 -0
- package/src/headers/26/aliased_buffer-inl.h +264 -0
- package/src/headers/26/aliased_buffer.h +205 -0
- package/src/headers/26/aliased_struct-inl.h +143 -0
- package/src/headers/26/aliased_struct.h +248 -0
- package/src/headers/26/amaro_version.h +6 -0
- package/src/headers/26/async_context_frame.h +33 -0
- package/src/headers/26/async_wrap-inl.h +123 -0
- package/src/headers/26/async_wrap.h +254 -0
- package/src/headers/26/base_object-inl.h +333 -0
- package/src/headers/26/base_object.h +339 -0
- package/src/headers/26/base_object_types.h +76 -0
- package/src/headers/26/blob_serializer_deserializer-inl.h +385 -0
- package/src/headers/26/blob_serializer_deserializer.h +142 -0
- package/src/headers/26/builtin_info.h +57 -0
- package/src/headers/26/callback_queue-inl.h +97 -0
- package/src/headers/26/callback_queue.h +79 -0
- package/src/headers/26/cares_wrap.h +475 -0
- package/src/headers/26/cleanup_queue-inl.h +36 -0
- package/src/headers/26/cleanup_queue.h +79 -0
- package/src/headers/26/compile_cache.h +134 -0
- package/src/headers/26/connect_wrap.h +26 -0
- package/src/headers/26/connection_wrap.h +30 -0
- package/src/headers/26/cppgc_helpers-inl.h +69 -0
- package/src/headers/26/cppgc_helpers.h +162 -0
- package/src/headers/26/crypto/crypto_aes.h +107 -0
- package/src/headers/26/crypto/crypto_argon2.h +88 -0
- package/src/headers/26/crypto/crypto_bio.h +193 -0
- package/src/headers/26/crypto/crypto_chacha20_poly1305.h +62 -0
- package/src/headers/26/crypto/crypto_cipher.h +291 -0
- package/src/headers/26/crypto/crypto_common.h +48 -0
- package/src/headers/26/crypto/crypto_context.h +219 -0
- package/src/headers/26/crypto/crypto_dh.h +104 -0
- package/src/headers/26/crypto/crypto_dsa.h +50 -0
- package/src/headers/26/crypto/crypto_ec.h +102 -0
- package/src/headers/26/crypto/crypto_hash.h +157 -0
- package/src/headers/26/crypto/crypto_hkdf.h +62 -0
- package/src/headers/26/crypto/crypto_hmac.h +92 -0
- package/src/headers/26/crypto/crypto_kem.h +131 -0
- package/src/headers/26/crypto/crypto_keygen.h +382 -0
- package/src/headers/26/crypto/crypto_keys.h +366 -0
- package/src/headers/26/crypto/crypto_kmac.h +79 -0
- package/src/headers/26/crypto/crypto_pbkdf2.h +76 -0
- package/src/headers/26/crypto/crypto_pqc.h +39 -0
- package/src/headers/26/crypto/crypto_random.h +127 -0
- package/src/headers/26/crypto/crypto_rsa.h +108 -0
- package/src/headers/26/crypto/crypto_scrypt.h +85 -0
- package/src/headers/26/crypto/crypto_sig.h +159 -0
- package/src/headers/26/crypto/crypto_spkac.h +21 -0
- package/src/headers/26/crypto/crypto_timing.h +20 -0
- package/src/headers/26/crypto/crypto_tls.h +342 -0
- package/src/headers/26/crypto/crypto_turboshake.h +105 -0
- package/src/headers/26/crypto/crypto_util.h +775 -0
- package/src/headers/26/crypto/crypto_x509.h +140 -0
- package/src/headers/26/dataqueue/queue.h +311 -0
- package/src/headers/26/debug_utils-inl.h +291 -0
- package/src/headers/26/debug_utils.h +200 -0
- package/src/headers/26/diagnosticfilename-inl.h +33 -0
- package/src/headers/26/embedded_data.h +17 -0
- package/src/headers/26/encoding_binding.h +59 -0
- package/src/headers/26/env-inl.h +956 -0
- package/src/headers/26/env.h +1294 -0
- package/src/headers/26/env_properties.h +562 -0
- package/src/headers/26/ffi/data.h +30 -0
- package/src/headers/26/ffi/fast.h +96 -0
- package/src/headers/26/ffi/jit_memory.h +26 -0
- package/src/headers/26/ffi/types.h +99 -0
- package/src/headers/26/handle_wrap.h +123 -0
- package/src/headers/26/histogram-inl.h +211 -0
- package/src/headers/26/histogram.h +474 -0
- package/src/headers/26/inspector/dom_storage_agent.h +68 -0
- package/src/headers/26/inspector/inspector_object_utils.h +38 -0
- package/src/headers/26/inspector/io_agent.h +30 -0
- package/src/headers/26/inspector/main_thread_interface.h +116 -0
- package/src/headers/26/inspector/network_agent.h +110 -0
- package/src/headers/26/inspector/network_inspector.h +45 -0
- package/src/headers/26/inspector/network_requests_buffer.h +195 -0
- package/src/headers/26/inspector/network_resource_manager.h +29 -0
- package/src/headers/26/inspector/node_json.h +24 -0
- package/src/headers/26/inspector/node_string.h +101 -0
- package/src/headers/26/inspector/notification_emitter.h +38 -0
- package/src/headers/26/inspector/protocol_helper.h +27 -0
- package/src/headers/26/inspector/runtime_agent.h +41 -0
- package/src/headers/26/inspector/storage_agent.h +33 -0
- package/src/headers/26/inspector/target_agent.h +59 -0
- package/src/headers/26/inspector/target_manager.h +70 -0
- package/src/headers/26/inspector/tracing_agent.h +43 -0
- package/src/headers/26/inspector/worker_agent.h +40 -0
- package/src/headers/26/inspector/worker_inspector.h +124 -0
- package/src/headers/26/inspector_agent.h +168 -0
- package/src/headers/26/inspector_io.h +78 -0
- package/src/headers/26/inspector_profiler.h +149 -0
- package/src/headers/26/inspector_socket.h +60 -0
- package/src/headers/26/inspector_socket_server.h +110 -0
- package/src/headers/26/js_native_api.h +634 -0
- package/src/headers/26/js_native_api_types.h +244 -0
- package/src/headers/26/js_native_api_v8.h +485 -0
- package/src/headers/26/js_native_api_v8_internals.h +45 -0
- package/src/headers/26/js_stream.h +57 -0
- package/src/headers/26/json_utils.h +172 -0
- package/src/headers/26/large_pages/node_large_page.h +34 -0
- package/src/headers/26/lru_cache-inl.h +69 -0
- package/src/headers/26/memory_tracker-inl.h +461 -0
- package/src/headers/26/memory_tracker.h +341 -0
- package/src/headers/26/module_wrap.h +231 -0
- package/src/headers/26/ncrypto.h +2008 -0
- package/src/headers/26/node.h +1693 -0
- package/src/headers/26/node_api.h +265 -0
- package/src/headers/26/node_api_internals.h +48 -0
- package/src/headers/26/node_api_types.h +58 -0
- package/src/headers/26/node_binding.h +170 -0
- package/src/headers/26/node_blob.h +160 -0
- package/src/headers/26/node_bob-inl.h +36 -0
- package/src/headers/26/node_bob.h +107 -0
- package/src/headers/26/node_buffer.h +92 -0
- package/src/headers/26/node_builtins.h +239 -0
- package/src/headers/26/node_concepts.h +46 -0
- package/src/headers/26/node_config_file.h +77 -0
- package/src/headers/26/node_constants.h +82 -0
- package/src/headers/26/node_context_data.h +171 -0
- package/src/headers/26/node_contextify.h +261 -0
- package/src/headers/26/node_crypto.h +66 -0
- package/src/headers/26/node_debug.h +30 -0
- package/src/headers/26/node_diagnostics_channel.h +121 -0
- package/src/headers/26/node_dir.h +52 -0
- package/src/headers/26/node_dotenv.h +45 -0
- package/src/headers/26/node_errors.h +378 -0
- package/src/headers/26/node_exit_code.h +54 -0
- package/src/headers/26/node_external_reference.h +171 -0
- package/src/headers/26/node_ffi.h +212 -0
- package/src/headers/26/node_file-inl.h +421 -0
- package/src/headers/26/node_file.h +561 -0
- package/src/headers/26/node_file_utils.h +39 -0
- package/src/headers/26/node_hash.h +212 -0
- package/src/headers/26/node_http2.h +1202 -0
- package/src/headers/26/node_http2_state.h +159 -0
- package/src/headers/26/node_http_common-inl.h +199 -0
- package/src/headers/26/node_http_common.h +535 -0
- package/src/headers/26/node_i18n.h +132 -0
- package/src/headers/26/node_internals.h +485 -0
- package/src/headers/26/node_locks.h +184 -0
- package/src/headers/26/node_main_instance.h +67 -0
- package/src/headers/26/node_mem-inl.h +113 -0
- package/src/headers/26/node_mem.h +45 -0
- package/src/headers/26/node_messaging.h +389 -0
- package/src/headers/26/node_metadata.h +172 -0
- package/src/headers/26/node_modules.h +102 -0
- package/src/headers/26/node_mutex.h +323 -0
- package/src/headers/26/node_object_wrap.h +145 -0
- package/src/headers/26/node_options-inl.h +524 -0
- package/src/headers/26/node_options.h +710 -0
- package/src/headers/26/node_perf.h +167 -0
- package/src/headers/26/node_perf_common.h +103 -0
- package/src/headers/26/node_platform.h +290 -0
- package/src/headers/26/node_process-inl.h +26 -0
- package/src/headers/26/node_process.h +112 -0
- package/src/headers/26/node_profiling.h +38 -0
- package/src/headers/26/node_realm-inl.h +156 -0
- package/src/headers/26/node_realm.h +236 -0
- package/src/headers/26/node_report.h +43 -0
- package/src/headers/26/node_revert.h +82 -0
- package/src/headers/26/node_root_certs.h +2937 -0
- package/src/headers/26/node_sea.h +101 -0
- package/src/headers/26/node_shadow_realm.h +46 -0
- package/src/headers/26/node_snapshot_builder.h +57 -0
- package/src/headers/26/node_snapshotable.h +167 -0
- package/src/headers/26/node_sockaddr-inl.h +248 -0
- package/src/headers/26/node_sockaddr.h +459 -0
- package/src/headers/26/node_sqlite.h +607 -0
- package/src/headers/26/node_stat_watcher.h +73 -0
- package/src/headers/26/node_task_runner.h +92 -0
- package/src/headers/26/node_threadsafe_cow-inl.h +54 -0
- package/src/headers/26/node_threadsafe_cow.h +105 -0
- package/src/headers/26/node_union_bytes.h +81 -0
- package/src/headers/26/node_url.h +101 -0
- package/src/headers/26/node_url_pattern.h +118 -0
- package/src/headers/26/node_v8.h +78 -0
- package/src/headers/26/node_v8_embedder.h +26 -0
- package/src/headers/26/node_v8_platform-inl.h +96 -0
- package/src/headers/26/node_version.h +116 -0
- package/src/headers/26/node_wasi.h +184 -0
- package/src/headers/26/node_wasm_web_api.h +55 -0
- package/src/headers/26/node_watchdog.h +164 -0
- package/src/headers/26/node_webstorage.h +62 -0
- package/src/headers/26/node_worker.h +162 -0
- package/src/headers/26/path.h +36 -0
- package/src/headers/26/permission/boolean_permission.h +50 -0
- package/src/headers/26/permission/fs_permission.h +192 -0
- package/src/headers/26/permission/permission.h +155 -0
- package/src/headers/26/permission/permission_base.h +79 -0
- package/src/headers/26/pipe_wrap.h +80 -0
- package/src/headers/26/quic/application.h +279 -0
- package/src/headers/26/quic/arena.h +373 -0
- package/src/headers/26/quic/bindingdata.h +440 -0
- package/src/headers/26/quic/cid.h +127 -0
- package/src/headers/26/quic/data.h +358 -0
- package/src/headers/26/quic/defs.h +417 -0
- package/src/headers/26/quic/endpoint.h +519 -0
- package/src/headers/26/quic/guard.h +5 -0
- package/src/headers/26/quic/http3.h +25 -0
- package/src/headers/26/quic/packet.h +166 -0
- package/src/headers/26/quic/preferredaddress.h +72 -0
- package/src/headers/26/quic/session.h +770 -0
- package/src/headers/26/quic/session_manager.h +107 -0
- package/src/headers/26/quic/sessionticket.h +110 -0
- package/src/headers/26/quic/streams.h +518 -0
- package/src/headers/26/quic/tlscontext.h +353 -0
- package/src/headers/26/quic/tokens.h +263 -0
- package/src/headers/26/quic/transportparams.h +184 -0
- package/src/headers/26/req_wrap-inl.h +175 -0
- package/src/headers/26/req_wrap.h +79 -0
- package/src/headers/26/spawn_sync.h +243 -0
- package/src/headers/26/stream_base-inl.h +170 -0
- package/src/headers/26/stream_base.h +487 -0
- package/src/headers/26/stream_pipe.h +76 -0
- package/src/headers/26/stream_wrap.h +137 -0
- package/src/headers/26/string_bytes.h +114 -0
- package/src/headers/26/string_decoder-inl.h +31 -0
- package/src/headers/26/string_decoder.h +49 -0
- package/src/headers/26/tcp_wrap.h +138 -0
- package/src/headers/26/threadpoolwork-inl.h +70 -0
- package/src/headers/26/timer_wrap-inl.h +32 -0
- package/src/headers/26/timer_wrap.h +87 -0
- package/src/headers/26/timers.h +70 -0
- package/src/headers/26/tracing/agent.h +125 -0
- package/src/headers/26/tracing/agent_legacy.h +146 -0
- package/src/headers/26/tracing/agent_perfetto.h +145 -0
- package/src/headers/26/tracing/node_trace_buffer.h +91 -0
- package/src/headers/26/tracing/node_trace_writer.h +79 -0
- package/src/headers/26/tracing/trace_event.h +27 -0
- package/src/headers/26/tracing/trace_event_helper.h +40 -0
- package/src/headers/26/tracing/trace_event_legacy.h +1113 -0
- package/src/headers/26/tracing/trace_event_legacy_inl.h +711 -0
- package/src/headers/26/tracing/trace_event_perfetto.h +47 -0
- package/src/headers/26/tracing/traced_value.h +167 -0
- package/src/headers/26/tty_wrap.h +65 -0
- package/src/headers/26/udp_wrap.h +231 -0
- package/src/headers/26/undici_version.h +6 -0
- package/src/headers/26/util-inl.h +788 -0
- package/src/headers/26/util.h +1207 -0
- package/src/headers/26/v8-cpp-heap-external.h +56 -0
- package/src/headers/26/v8-external-memory-accounter.h +60 -0
- package/src/headers/26/v8-fast-api-calls.h +784 -0
- package/src/headers/26/v8-inspector-protocol.h +13 -0
- package/src/headers/26/v8-inspector.h +458 -0
- package/src/headers/26/v8-metrics.h +273 -0
- package/src/headers/26/v8-trace-categories.h +28 -0
- package/src/headers/26/v8-unwinder-state.h +30 -0
- package/src/headers/26/v8-util.h +549 -0
- package/src/headers/26/v8-value-serializer-version.h +24 -0
- package/src/headers/26/v8-version-string.h +38 -0
- package/src/headers/26/v8-wasm-trap-handler-posix.h +31 -0
- package/src/headers/26/v8-wasm-trap-handler-win.h +28 -0
- package/src/headers/26/zlib_version.h +6 -0
- package/dist/bindings/cws_darwin_arm64_node115.node.dSYM/Contents/Info.plist +0 -20
- package/dist/bindings/cws_darwin_arm64_node115.node.dSYM/Contents/Resources/DWARF/cws_darwin_arm64_node115.node +0 -0
- package/dist/bindings/cws_darwin_arm64_node115.node.dSYM/Contents/Resources/Relocations/aarch64/cws_darwin_arm64_node115.node.yml +0 -931
- package/dist/bindings/cws_darwin_arm64_node127.node.dSYM/Contents/Info.plist +0 -20
- package/dist/bindings/cws_darwin_arm64_node127.node.dSYM/Contents/Resources/DWARF/cws_darwin_arm64_node127.node +0 -0
- package/dist/bindings/cws_darwin_arm64_node127.node.dSYM/Contents/Resources/Relocations/aarch64/cws_darwin_arm64_node127.node.yml +0 -931
package/src/Group.h
CHANGED
|
@@ -41,6 +41,9 @@ protected:
|
|
|
41
41
|
unsigned int maxPayload;
|
|
42
42
|
Hub *hub;
|
|
43
43
|
int extensionOptions;
|
|
44
|
+
int deflateWindowBits = 15;
|
|
45
|
+
int deflateMemLevel = 8;
|
|
46
|
+
int deflateLevel = 1;
|
|
44
47
|
cS::Timer *timer = nullptr, *httpTimer = nullptr;
|
|
45
48
|
const char *userPingMessage;
|
|
46
49
|
size_t userPingMessageLength;
|
|
@@ -61,7 +64,7 @@ protected:
|
|
|
61
64
|
void addHttpSocket(HttpSocket<isServer> *httpSocket);
|
|
62
65
|
void removeHttpSocket(HttpSocket<isServer> *httpSocket);
|
|
63
66
|
|
|
64
|
-
Group(int extensionOptions, unsigned int maxPayload, Hub *hub, cS::NodeData *nodeData);
|
|
67
|
+
Group(int extensionOptions, unsigned int maxPayload, Hub *hub, cS::NodeData *nodeData, int deflateWindowBits = 15, int deflateMemLevel = 8, int deflateLevel = 1);
|
|
65
68
|
void stopListening();
|
|
66
69
|
|
|
67
70
|
public:
|
package/src/HTTPSocket.cpp
CHANGED
|
@@ -210,7 +210,7 @@ void HttpSocket<isServer>::upgrade(const char *secKey, const char *extensions, s
|
|
|
210
210
|
std::string extensionsResponse;
|
|
211
211
|
if (extensionsLength) {
|
|
212
212
|
Group<isServer> *group = Group<isServer>::from(this);
|
|
213
|
-
ExtensionsNegotiator<cWS::SERVER> extensionsNegotiator(group->extensionOptions);
|
|
213
|
+
ExtensionsNegotiator<cWS::SERVER> extensionsNegotiator(group->extensionOptions, group->deflateWindowBits);
|
|
214
214
|
extensionsNegotiator.readOffer(std::string(extensions, extensionsLength));
|
|
215
215
|
extensionsResponse = extensionsNegotiator.generateOffer();
|
|
216
216
|
if (extensionsNegotiator.getNegotiatedOptions() & PERMESSAGE_DEFLATE) {
|
package/src/Hub.cpp
CHANGED
|
@@ -5,87 +5,22 @@
|
|
|
5
5
|
|
|
6
6
|
namespace cWS {
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
// windowBits 9..15 and memLevel 1..9 select the per-socket memory tier (zlib uses
|
|
9
|
+
// about 4x the window plus a 2^(memLevel+9) byte hash table): 15/8 = ~256 KB,
|
|
10
|
+
// 12/5 = ~32 KB, 10/3 = ~8 KB, 9/2 = ~4 KB. Smaller tiers trade ratio for memory.
|
|
11
|
+
// level 1..9: with zlib-ng level 1 is the very fast "quick" strategy (~8% worse
|
|
12
|
+
// ratio than zlib level 1), level 2 matches zlib level 1's ratio at higher speed.
|
|
13
|
+
zlib::Stream *Hub::allocateDefaultCompressor(int level, int windowBits, int memLevel) {
|
|
14
|
+
return zlib::createDeflate(level, windowBits, memLevel);
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
char *Hub::deflate(char *data, size_t &length,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
z_stream *compressor = slidingDeflateWindow ? slidingDeflateWindow : &deflationStream;
|
|
17
|
-
|
|
18
|
-
compressor->next_in = (Bytef *) data;
|
|
19
|
-
compressor->avail_in = (unsigned int) length;
|
|
20
|
-
|
|
21
|
-
// note: zlib requires more than 6 bytes with Z_SYNC_FLUSH
|
|
22
|
-
const int DEFLATE_OUTPUT_CHUNK = LARGE_BUFFER_SIZE;
|
|
23
|
-
|
|
24
|
-
int err;
|
|
25
|
-
do {
|
|
26
|
-
compressor->next_out = (Bytef *) zlibBuffer;
|
|
27
|
-
compressor->avail_out = DEFLATE_OUTPUT_CHUNK;
|
|
28
|
-
|
|
29
|
-
err = ::deflate(compressor, Z_SYNC_FLUSH);
|
|
30
|
-
if (Z_OK == err && compressor->avail_out == 0) {
|
|
31
|
-
dynamicZlibBuffer.append(zlibBuffer, DEFLATE_OUTPUT_CHUNK - compressor->avail_out);
|
|
32
|
-
continue;
|
|
33
|
-
} else {
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
} while (true);
|
|
37
|
-
|
|
38
|
-
// note: should not change avail_out
|
|
39
|
-
if (!slidingDeflateWindow) {
|
|
40
|
-
deflateReset(compressor);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (dynamicZlibBuffer.length()) {
|
|
44
|
-
dynamicZlibBuffer.append(zlibBuffer, DEFLATE_OUTPUT_CHUNK - compressor->avail_out);
|
|
45
|
-
|
|
46
|
-
length = dynamicZlibBuffer.length() - 4;
|
|
47
|
-
return (char *) dynamicZlibBuffer.data();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
length = DEFLATE_OUTPUT_CHUNK - compressor->avail_out - 4;
|
|
51
|
-
return zlibBuffer;
|
|
17
|
+
char *Hub::deflate(char *data, size_t &length, zlib::Stream *slidingDeflateWindow) {
|
|
18
|
+
zlib::Stream *compressor = slidingDeflateWindow ? slidingDeflateWindow : deflationStream;
|
|
19
|
+
return zlib::deflate(compressor, data, length, zlibBuffer, LARGE_BUFFER_SIZE, dynamicZlibBuffer, !slidingDeflateWindow);
|
|
52
20
|
}
|
|
53
21
|
|
|
54
|
-
// todo: let's go through this code once more some time!
|
|
55
22
|
char *Hub::inflate(char *data, size_t &length, size_t maxPayload) {
|
|
56
|
-
dynamicZlibBuffer
|
|
57
|
-
|
|
58
|
-
inflationStream.next_in = (Bytef *) data;
|
|
59
|
-
inflationStream.avail_in = (unsigned int) length;
|
|
60
|
-
|
|
61
|
-
int err;
|
|
62
|
-
do {
|
|
63
|
-
inflationStream.next_out = (Bytef *) zlibBuffer;
|
|
64
|
-
inflationStream.avail_out = LARGE_BUFFER_SIZE;
|
|
65
|
-
err = ::inflate(&inflationStream, Z_FINISH);
|
|
66
|
-
if (!inflationStream.avail_in) {
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
dynamicZlibBuffer.append(zlibBuffer, LARGE_BUFFER_SIZE - inflationStream.avail_out);
|
|
71
|
-
} while (err == Z_BUF_ERROR && dynamicZlibBuffer.length() <= maxPayload);
|
|
72
|
-
|
|
73
|
-
inflateReset(&inflationStream);
|
|
74
|
-
|
|
75
|
-
if ((err != Z_BUF_ERROR && err != Z_OK) || dynamicZlibBuffer.length() > maxPayload) {
|
|
76
|
-
length = 0;
|
|
77
|
-
return nullptr;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (dynamicZlibBuffer.length()) {
|
|
81
|
-
dynamicZlibBuffer.append(zlibBuffer, LARGE_BUFFER_SIZE - inflationStream.avail_out);
|
|
82
|
-
|
|
83
|
-
length = dynamicZlibBuffer.length();
|
|
84
|
-
return (char *) dynamicZlibBuffer.data();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
length = LARGE_BUFFER_SIZE - inflationStream.avail_out;
|
|
88
|
-
return zlibBuffer;
|
|
23
|
+
return zlib::inflate(inflationStream, data, length, maxPayload, zlibBuffer, LARGE_BUFFER_SIZE, dynamicZlibBuffer);
|
|
89
24
|
}
|
|
90
25
|
|
|
91
26
|
void Hub::onServerAccept(cS::Socket *s) {
|
package/src/Hub.h
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
#include "Group.h"
|
|
5
5
|
#include "cSNode.h"
|
|
6
6
|
#include <string>
|
|
7
|
-
#include
|
|
7
|
+
#include "Zlib.h"
|
|
8
8
|
#include <mutex>
|
|
9
9
|
#include <map>
|
|
10
10
|
|
|
@@ -18,10 +18,10 @@ protected:
|
|
|
18
18
|
Group<CLIENT> *group;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
static
|
|
21
|
+
static zlib::Stream *allocateDefaultCompressor(int level = 1, int windowBits = 15, int memLevel = 8);
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
char *deflate(char *data, size_t &length,
|
|
23
|
+
zlib::Stream *inflationStream = nullptr, *deflationStream = nullptr;
|
|
24
|
+
char *deflate(char *data, size_t &length, zlib::Stream *slidingDeflateWindow);
|
|
25
25
|
char *inflate(char *data, size_t &length, size_t maxPayload);
|
|
26
26
|
char *zlibBuffer;
|
|
27
27
|
std::string dynamicZlibBuffer;
|
|
@@ -32,8 +32,8 @@ protected:
|
|
|
32
32
|
|
|
33
33
|
public:
|
|
34
34
|
template <bool isServer>
|
|
35
|
-
Group<isServer> *createGroup(int extensionOptions = 0, unsigned int maxPayload = 16777216) {
|
|
36
|
-
return new Group<isServer>(extensionOptions, maxPayload, this, nodeData);
|
|
35
|
+
Group<isServer> *createGroup(int extensionOptions = 0, unsigned int maxPayload = 16777216, int deflateWindowBits = 15, int deflateMemLevel = 8, int deflateLevel = 1) {
|
|
36
|
+
return new Group<isServer>(extensionOptions, maxPayload, this, nodeData, deflateWindowBits, deflateMemLevel, deflateLevel);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
template <bool isServer>
|
|
@@ -48,10 +48,11 @@ public:
|
|
|
48
48
|
|
|
49
49
|
Hub(int extensionOptions = 0, bool useDefaultLoop = false, unsigned int maxPayload = 16777216) : cS::Node(LARGE_BUFFER_SIZE, WebSocketProtocol<SERVER, WebSocket<SERVER>>::CONSUME_PRE_PADDING, WebSocketProtocol<SERVER, WebSocket<SERVER>>::CONSUME_POST_PADDING, useDefaultLoop),
|
|
50
50
|
Group<SERVER>(extensionOptions, maxPayload, this, nodeData), Group<CLIENT>(0, maxPayload, this, nodeData) {
|
|
51
|
-
|
|
51
|
+
inflationStream = zlib::createInflate(15);
|
|
52
52
|
zlibBuffer = new char[LARGE_BUFFER_SIZE];
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
// shared compressor for groups without a per-socket sliding window
|
|
55
|
+
deflationStream = allocateDefaultCompressor();
|
|
55
56
|
|
|
56
57
|
#ifdef CWS_THREADSAFE
|
|
57
58
|
getLoop()->preCbData = nodeData;
|
|
@@ -67,14 +68,15 @@ public:
|
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
~Hub() {
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
zlib::destroy(inflationStream);
|
|
72
|
+
zlib::destroy(deflationStream);
|
|
72
73
|
delete [] zlibBuffer;
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
using cS::Node::run;
|
|
76
77
|
using cS::Node::poll;
|
|
77
78
|
using cS::Node::getLoop;
|
|
79
|
+
using cS::Node::getNodeData;
|
|
78
80
|
using Group<SERVER>::onConnection;
|
|
79
81
|
using Group<CLIENT>::onConnection;
|
|
80
82
|
using Group<SERVER>::onTransfer;
|
package/src/Networking.h
CHANGED
|
@@ -215,6 +215,17 @@ struct WIN32_EXPORT NodeData {
|
|
|
215
215
|
std::vector<Poll *> changePollQueue;
|
|
216
216
|
static void asyncCallback(Async *async);
|
|
217
217
|
|
|
218
|
+
// Write corking: every send() issued during one event-loop iteration is
|
|
219
|
+
// queued and flushed with a single gathered write per socket from the
|
|
220
|
+
// loop's prepare/check hooks (see Socket::flushCorked). One CorkState per
|
|
221
|
+
// loop, shared by pointer between every NodeData copy (Groups copy the
|
|
222
|
+
// Hub's NodeData). Disabled with the CWS_CORK=0 environment variable.
|
|
223
|
+
struct CorkState {
|
|
224
|
+
bool enabled = false;
|
|
225
|
+
std::vector<Poll *> pending;
|
|
226
|
+
};
|
|
227
|
+
CorkState *corkState = nullptr;
|
|
228
|
+
|
|
218
229
|
static int getMemoryBlockIndex(size_t length) {
|
|
219
230
|
return (int) ((length >> 4) + bool(length & 15));
|
|
220
231
|
}
|
package/src/Socket.h
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
#define SOCKET_CWS_H
|
|
3
3
|
|
|
4
4
|
#include "Networking.h"
|
|
5
|
+
#ifndef _WIN32
|
|
6
|
+
#include <sys/uio.h>
|
|
7
|
+
#endif
|
|
5
8
|
|
|
6
9
|
namespace cS {
|
|
7
10
|
|
|
@@ -33,6 +36,12 @@ protected:
|
|
|
33
36
|
void *user = nullptr;
|
|
34
37
|
NodeData *nodeData;
|
|
35
38
|
|
|
39
|
+
// Corking (see NodeData::CorkState). Only WebSockets opt in; HttpSocket
|
|
40
|
+
// objects are deleted synchronously in Hub::upgrade so they must never
|
|
41
|
+
// sit in the pending list. Plain TCP only, SSL keeps the immediate path.
|
|
42
|
+
bool corkable = false;
|
|
43
|
+
bool corkPending = false;
|
|
44
|
+
|
|
36
45
|
// this is not needed by HttpSocket!
|
|
37
46
|
struct Queue {
|
|
38
47
|
struct Message {
|
|
@@ -91,6 +100,7 @@ protected:
|
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
void transfer(NodeData *nodeData, void (*cb)(Poll *)) {
|
|
103
|
+
flushCorkedOnClose();
|
|
94
104
|
// userData is invalid from now on till onTransfer
|
|
95
105
|
setUserData(new TransferData({getFd(), ssl, getCb(), getPoll(), getUserData(), nodeData, cb}));
|
|
96
106
|
stop(this->nodeData->loop);
|
|
@@ -160,10 +170,17 @@ protected:
|
|
|
160
170
|
Queue::Message *messagePtr = socket->messageQueue.front();
|
|
161
171
|
int sent = SSL_write(socket->ssl, messagePtr->data, (int) messagePtr->length);
|
|
162
172
|
if (sent == (ssize_t) messagePtr->length) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
173
|
+
// Pop before the callback: it may close/terminate this socket,
|
|
174
|
+
// which frees the queue (use-after-free otherwise).
|
|
175
|
+
auto callback = messagePtr->callback;
|
|
176
|
+
void *callbackData = messagePtr->callbackData, *reserved = messagePtr->reserved;
|
|
166
177
|
socket->messageQueue.pop();
|
|
178
|
+
if (callback) {
|
|
179
|
+
callback(p, callbackData, false, reserved);
|
|
180
|
+
if (socket->isClosed()) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
167
184
|
if (socket->messageQueue.empty()) {
|
|
168
185
|
if ((socket->state.poll & UV_WRITABLE) && SSL_want(socket->ssl) != SSL_WRITING) {
|
|
169
186
|
socket->change(socket->nodeData->loop, socket, socket->setPoll(UV_READABLE));
|
|
@@ -235,10 +252,17 @@ protected:
|
|
|
235
252
|
Queue::Message *messagePtr = socket->messageQueue.front();
|
|
236
253
|
ssize_t sent = ::send(socket->getFd(), messagePtr->data, messagePtr->length, MSG_NOSIGNAL);
|
|
237
254
|
if (sent == (ssize_t) messagePtr->length) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
255
|
+
// Pop before the callback: it may close/terminate this socket,
|
|
256
|
+
// which frees the queue (use-after-free otherwise).
|
|
257
|
+
auto callback = messagePtr->callback;
|
|
258
|
+
void *callbackData = messagePtr->callbackData, *reserved = messagePtr->reserved;
|
|
241
259
|
socket->messageQueue.pop();
|
|
260
|
+
if (callback) {
|
|
261
|
+
callback(p, callbackData, false, reserved);
|
|
262
|
+
if (socket->isClosed()) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
242
266
|
if (socket->messageQueue.empty()) {
|
|
243
267
|
// todo, remove bit, don't set directly
|
|
244
268
|
socket->change(socket->nodeData->loop, socket, socket->setPoll(UV_READABLE));
|
|
@@ -358,6 +382,21 @@ protected:
|
|
|
358
382
|
void sendTransformed(const char *message, size_t length, void(*callback)(void *socket, void *data, bool cancelled, void *reserved), void *callbackData, D transformData) {
|
|
359
383
|
size_t estimatedLength = T::estimate(message, length) + sizeof(Queue::Message);
|
|
360
384
|
|
|
385
|
+
if (corkActive()) {
|
|
386
|
+
// Frame now, write later: everything sent to this socket during the
|
|
387
|
+
// current loop iteration goes out in one gathered write (uncork()).
|
|
388
|
+
Queue::Message *messagePtr = allocMessage(estimatedLength - sizeof(Queue::Message));
|
|
389
|
+
messagePtr->length = T::transform(message, (char *) messagePtr->data, length, transformData);
|
|
390
|
+
messagePtr->callback = callback;
|
|
391
|
+
messagePtr->callbackData = callbackData;
|
|
392
|
+
enqueue(messagePtr);
|
|
393
|
+
if (!corkPending) {
|
|
394
|
+
corkPending = true;
|
|
395
|
+
nodeData->corkState->pending.push_back(this);
|
|
396
|
+
}
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
361
400
|
if (hasEmptyQueue()) {
|
|
362
401
|
if (estimatedLength <= cS::NodeData::preAllocMaxSize) {
|
|
363
402
|
int memoryLength = (int) estimatedLength;
|
|
@@ -477,8 +516,164 @@ public:
|
|
|
477
516
|
}
|
|
478
517
|
}
|
|
479
518
|
|
|
519
|
+
// ---- Write corking ------------------------------------------------------
|
|
520
|
+
|
|
521
|
+
bool corkActive() {
|
|
522
|
+
return corkable && !ssl && nodeData->corkState && nodeData->corkState->enabled;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
void setCorkable(bool enable) {
|
|
526
|
+
corkable = enable;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
void unregisterCork() {
|
|
530
|
+
if (!corkPending) {
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
corkPending = false;
|
|
534
|
+
std::vector<Poll *> &pending = nodeData->corkState->pending;
|
|
535
|
+
for (size_t i = 0; i < pending.size(); i++) {
|
|
536
|
+
if (pending[i] == this) {
|
|
537
|
+
pending[i] = pending.back();
|
|
538
|
+
pending.pop_back();
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// One gathered write of (up to MAX_IOV) messages from the queue head.
|
|
545
|
+
// Returns bytes written or -1 with errno/WSAGetLastError set. Never pops.
|
|
546
|
+
ssize_t writeQueueGathered() {
|
|
547
|
+
static const int MAX_IOV = 64;
|
|
548
|
+
#ifdef _WIN32
|
|
549
|
+
WSABUF bufs[MAX_IOV];
|
|
550
|
+
DWORD n = 0;
|
|
551
|
+
for (Queue::Message *m = messageQueue.front(); m && n < MAX_IOV; m = m->nextMessage) {
|
|
552
|
+
bufs[n].buf = (CHAR *) m->data;
|
|
553
|
+
bufs[n].len = (ULONG) m->length;
|
|
554
|
+
n++;
|
|
555
|
+
}
|
|
556
|
+
DWORD sent = 0;
|
|
557
|
+
if (WSASend(getFd(), bufs, n, &sent, 0, nullptr, nullptr) == SOCKET_ERROR) {
|
|
558
|
+
return -1;
|
|
559
|
+
}
|
|
560
|
+
return (ssize_t) sent;
|
|
561
|
+
#else
|
|
562
|
+
iovec iov[MAX_IOV];
|
|
563
|
+
int n = 0;
|
|
564
|
+
for (Queue::Message *m = messageQueue.front(); m && n < MAX_IOV; m = m->nextMessage) {
|
|
565
|
+
iov[n].iov_base = (void *) m->data;
|
|
566
|
+
iov[n].iov_len = m->length;
|
|
567
|
+
n++;
|
|
568
|
+
}
|
|
569
|
+
msghdr msg = {};
|
|
570
|
+
msg.msg_iov = iov;
|
|
571
|
+
msg.msg_iovlen = n;
|
|
572
|
+
return ::sendmsg(getFd(), &msg, MSG_NOSIGNAL);
|
|
573
|
+
#endif
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Consumes `sent` bytes from the queue head. Fully written messages are
|
|
577
|
+
// popped (their callbacks appended to `callbacks` if given); a partially
|
|
578
|
+
// written head is advanced in place. Returns true if the write was partial.
|
|
579
|
+
struct PendingCallback {
|
|
580
|
+
void (*callback)(void *socket, void *data, bool cancelled, void *reserved);
|
|
581
|
+
void *callbackData, *reserved;
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
bool consumeSent(ssize_t sent, std::vector<PendingCallback> *callbacks) {
|
|
585
|
+
while (sent > 0 && !messageQueue.empty()) {
|
|
586
|
+
Queue::Message *m = messageQueue.front();
|
|
587
|
+
if ((size_t) sent >= m->length) {
|
|
588
|
+
sent -= m->length;
|
|
589
|
+
if (callbacks && m->callback) {
|
|
590
|
+
callbacks->push_back({m->callback, m->callbackData, m->reserved});
|
|
591
|
+
}
|
|
592
|
+
messageQueue.pop();
|
|
593
|
+
} else {
|
|
594
|
+
m->length -= sent;
|
|
595
|
+
m->data += sent;
|
|
596
|
+
messageQueue.totalLength -= sent;
|
|
597
|
+
return true;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Flush this socket's corked queue. Called from the loop's prepare/check
|
|
604
|
+
// hooks via flushCorked(). Whatever cannot be written now is left to the
|
|
605
|
+
// regular UV_WRITABLE drain loop, which also surfaces hard errors (onEnd).
|
|
606
|
+
void uncork() {
|
|
607
|
+
corkPending = false;
|
|
608
|
+
if (isClosed() || messageQueue.empty()) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
std::vector<PendingCallback> callbacks;
|
|
613
|
+
bool stalled = false;
|
|
614
|
+
while (!messageQueue.empty() && !stalled) {
|
|
615
|
+
ssize_t sent = writeQueueGathered();
|
|
616
|
+
if (sent < 0) {
|
|
617
|
+
stalled = true; // would block, or hard error: drain loop reports it
|
|
618
|
+
} else {
|
|
619
|
+
stalled = consumeSent(sent, &callbacks);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (!messageQueue.empty()) {
|
|
624
|
+
if ((getPoll() & UV_WRITABLE) == 0) {
|
|
625
|
+
setPoll(getPoll() | UV_WRITABLE);
|
|
626
|
+
changePoll(this);
|
|
627
|
+
}
|
|
628
|
+
} else if (getPoll() & UV_WRITABLE) {
|
|
629
|
+
change(nodeData->loop, this, setPoll(UV_READABLE));
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
for (PendingCallback &c : callbacks) {
|
|
633
|
+
c.callback(this, c.callbackData, false, c.reserved);
|
|
634
|
+
if (isClosed()) {
|
|
635
|
+
break; // callback closed us; nothing further may touch the fd
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Best effort on close/terminate/transfer: push what was corked during this
|
|
641
|
+
// iteration to the kernel so send() immediately followed by terminate()
|
|
642
|
+
// still delivers. Callbacks are not invoked; the caller drains the queue.
|
|
643
|
+
void flushCorkedOnClose() {
|
|
644
|
+
if (!corkPending) {
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
unregisterCork();
|
|
648
|
+
if (isClosed()) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
while (!messageQueue.empty()) {
|
|
652
|
+
ssize_t sent = writeQueueGathered();
|
|
653
|
+
if (sent <= 0 || consumeSent(sent, nullptr)) {
|
|
654
|
+
break;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Loop hook: flush every socket that corked writes since the last hook.
|
|
660
|
+
static void flushCorked(NodeData *nodeData) {
|
|
661
|
+
if (!nodeData->corkState || nodeData->corkState->pending.empty()) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
// Swap out the list: callbacks run during uncork() may cork new writes
|
|
665
|
+
// (picked up by the next hook) or close other sockets (their deletion
|
|
666
|
+
// is deferred to libuv's close phase, so pointers stay valid here).
|
|
667
|
+
std::vector<Poll *> batch;
|
|
668
|
+
batch.swap(nodeData->corkState->pending);
|
|
669
|
+
for (Poll *p : batch) {
|
|
670
|
+
((Socket *) p)->uncork();
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
480
674
|
template <class T>
|
|
481
675
|
void closeSocket() {
|
|
676
|
+
unregisterCork();
|
|
482
677
|
uv_os_sock_t fd = getFd();
|
|
483
678
|
Context *netContext = nodeData->netContext;
|
|
484
679
|
stop(nodeData->loop);
|
package/src/WebSocket.cpp
CHANGED
|
@@ -7,10 +7,12 @@ namespace cWS {
|
|
|
7
7
|
template <bool isServer>
|
|
8
8
|
WebSocket<isServer>::WebSocket(bool perMessageDeflate, cS::Socket *socket) : cS::Socket(std::move(*socket)) {
|
|
9
9
|
compressionStatus = perMessageDeflate ? CompressionStatus::ENABLED : CompressionStatus::DISABLED;
|
|
10
|
+
setCorkable(true);
|
|
10
11
|
|
|
11
12
|
// if we are created in a group with sliding deflate window allocate it here
|
|
12
13
|
if (Group<isServer>::from(this)->extensionOptions & SLIDING_DEFLATE_WINDOW) {
|
|
13
|
-
|
|
14
|
+
Group<isServer> *group = Group<isServer>::from(this);
|
|
15
|
+
slidingDeflateWindow = Hub::allocateDefaultCompressor(group->deflateLevel, group->deflateWindowBits, group->deflateMemLevel);
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -51,7 +53,7 @@ void WebSocket<isServer>::send(const char *message, size_t length, OpCode opCode
|
|
|
51
53
|
|
|
52
54
|
static size_t transform(const char *src, char *dst, size_t length, TransformData transformData) {
|
|
53
55
|
if (transformData.compress) {
|
|
54
|
-
char *deflated = Group<isServer>::from(transformData.s)->hub->deflate((char *) src, length, (
|
|
56
|
+
char *deflated = Group<isServer>::from(transformData.s)->hub->deflate((char *) src, length, (zlib::Stream *) transformData.s->slidingDeflateWindow);
|
|
55
57
|
return WebSocketProtocol<isServer, WebSocket<isServer>>::formatMessage(dst, deflated, length, transformData.opCode, length, true);
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -214,10 +216,10 @@ void WebSocket<isServer>::terminate() {
|
|
|
214
216
|
|
|
215
217
|
#ifdef CWS_THREADSAFE
|
|
216
218
|
std::lock_guard<std::recursive_mutex> lockGuard(*nodeData->asyncMutex);
|
|
219
|
+
#endif
|
|
217
220
|
if (isClosed()) {
|
|
218
221
|
return;
|
|
219
222
|
}
|
|
220
|
-
#endif
|
|
221
223
|
|
|
222
224
|
WebSocket<isServer>::onEnd(this);
|
|
223
225
|
}
|
|
@@ -288,6 +290,8 @@ template <bool isServer>
|
|
|
288
290
|
void WebSocket<isServer>::onEnd(cS::Socket *s) {
|
|
289
291
|
WebSocket<isServer> *webSocket = static_cast<WebSocket<isServer> *>(s);
|
|
290
292
|
|
|
293
|
+
webSocket->flushCorkedOnClose();
|
|
294
|
+
|
|
291
295
|
if (!webSocket->isShuttingDown()) {
|
|
292
296
|
Group<isServer>::from(webSocket)->removeWebSocket(webSocket);
|
|
293
297
|
Group<isServer>::from(webSocket)->disconnectionHandler(webSocket, 1006, nullptr, 0);
|
|
@@ -310,8 +314,7 @@ void WebSocket<isServer>::onEnd(cS::Socket *s) {
|
|
|
310
314
|
// remove any per-websocket zlib memory
|
|
311
315
|
if (webSocket->slidingDeflateWindow) {
|
|
312
316
|
// this relates to Hub::allocateDefaultCompressor
|
|
313
|
-
|
|
314
|
-
delete (z_stream *) webSocket->slidingDeflateWindow;
|
|
317
|
+
zlib::destroy((zlib::Stream *) webSocket->slidingDeflateWindow);
|
|
315
318
|
webSocket->slidingDeflateWindow = nullptr;
|
|
316
319
|
}
|
|
317
320
|
}
|
package/src/Zlib.cpp
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#include "Zlib.h"
|
|
2
|
+
|
|
3
|
+
#ifdef CWS_ZLIB_NG
|
|
4
|
+
#include "zlib-ng.h"
|
|
5
|
+
typedef zng_stream ZStream;
|
|
6
|
+
#define ZFN(name) zng_##name
|
|
7
|
+
#define CWS_ZLIB_BACKEND "zlib-ng " ZLIBNG_VERSION
|
|
8
|
+
#else
|
|
9
|
+
#include <zlib.h>
|
|
10
|
+
typedef z_stream ZStream;
|
|
11
|
+
#define ZFN(name) name
|
|
12
|
+
#define CWS_ZLIB_BACKEND "zlib " ZLIB_VERSION
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
namespace cWS {
|
|
16
|
+
namespace zlib {
|
|
17
|
+
|
|
18
|
+
struct Stream {
|
|
19
|
+
ZStream zs;
|
|
20
|
+
bool isDeflate;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
typedef decltype(ZStream::next_in) InPtr;
|
|
24
|
+
typedef decltype(ZStream::next_out) OutPtr;
|
|
25
|
+
|
|
26
|
+
Stream *createDeflate(int level, int windowBits, int memLevel) {
|
|
27
|
+
Stream *stream = new Stream();
|
|
28
|
+
stream->isDeflate = true;
|
|
29
|
+
ZFN(deflateInit2)(&stream->zs, level, Z_DEFLATED, -windowBits, memLevel, Z_DEFAULT_STRATEGY);
|
|
30
|
+
return stream;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Stream *createInflate(int windowBits) {
|
|
34
|
+
Stream *stream = new Stream();
|
|
35
|
+
stream->isDeflate = false;
|
|
36
|
+
ZFN(inflateInit2)(&stream->zs, -windowBits);
|
|
37
|
+
return stream;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void reset(Stream *stream) {
|
|
41
|
+
if (stream->isDeflate) {
|
|
42
|
+
ZFN(deflateReset)(&stream->zs);
|
|
43
|
+
} else {
|
|
44
|
+
ZFN(inflateReset)(&stream->zs);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void destroy(Stream *stream) {
|
|
49
|
+
if (!stream) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (stream->isDeflate) {
|
|
53
|
+
ZFN(deflateEnd)(&stream->zs);
|
|
54
|
+
} else {
|
|
55
|
+
ZFN(inflateEnd)(&stream->zs);
|
|
56
|
+
}
|
|
57
|
+
delete stream;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
char *deflate(Stream *stream, char *data, size_t &length, char *buffer, size_t bufferSize, std::string &dynamic, bool resetAfter) {
|
|
61
|
+
ZStream &zs = stream->zs;
|
|
62
|
+
dynamic.clear();
|
|
63
|
+
|
|
64
|
+
zs.next_in = (InPtr) data;
|
|
65
|
+
zs.avail_in = (unsigned int) length;
|
|
66
|
+
|
|
67
|
+
// note: zlib requires more than 6 bytes of output space with Z_SYNC_FLUSH
|
|
68
|
+
int err;
|
|
69
|
+
do {
|
|
70
|
+
zs.next_out = (OutPtr) buffer;
|
|
71
|
+
zs.avail_out = (unsigned int) bufferSize;
|
|
72
|
+
|
|
73
|
+
err = ZFN(deflate)(&zs, Z_SYNC_FLUSH);
|
|
74
|
+
if (Z_OK == err && zs.avail_out == 0) {
|
|
75
|
+
dynamic.append(buffer, bufferSize - zs.avail_out);
|
|
76
|
+
continue;
|
|
77
|
+
} else {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
} while (true);
|
|
81
|
+
|
|
82
|
+
// note: must not change avail_out
|
|
83
|
+
if (resetAfter) {
|
|
84
|
+
ZFN(deflateReset)(&zs);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (dynamic.length()) {
|
|
88
|
+
dynamic.append(buffer, bufferSize - zs.avail_out);
|
|
89
|
+
length = dynamic.length() - 4;
|
|
90
|
+
return (char *) dynamic.data();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
length = bufferSize - zs.avail_out - 4;
|
|
94
|
+
return buffer;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
char *inflate(Stream *stream, char *data, size_t &length, size_t maxPayload, char *buffer, size_t bufferSize, std::string &dynamic) {
|
|
98
|
+
ZStream &zs = stream->zs;
|
|
99
|
+
dynamic.clear();
|
|
100
|
+
|
|
101
|
+
zs.next_in = (InPtr) data;
|
|
102
|
+
zs.avail_in = (unsigned int) length;
|
|
103
|
+
|
|
104
|
+
int err;
|
|
105
|
+
do {
|
|
106
|
+
zs.next_out = (OutPtr) buffer;
|
|
107
|
+
zs.avail_out = (unsigned int) bufferSize;
|
|
108
|
+
err = ZFN(inflate)(&zs, Z_FINISH);
|
|
109
|
+
if (!zs.avail_in) {
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
dynamic.append(buffer, bufferSize - zs.avail_out);
|
|
114
|
+
} while (err == Z_BUF_ERROR && dynamic.length() <= maxPayload);
|
|
115
|
+
|
|
116
|
+
ZFN(inflateReset)(&zs);
|
|
117
|
+
|
|
118
|
+
if ((err != Z_BUF_ERROR && err != Z_OK) || dynamic.length() > maxPayload) {
|
|
119
|
+
length = 0;
|
|
120
|
+
return nullptr;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (dynamic.length()) {
|
|
124
|
+
dynamic.append(buffer, bufferSize - zs.avail_out);
|
|
125
|
+
length = dynamic.length();
|
|
126
|
+
return (char *) dynamic.data();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
length = bufferSize - zs.avail_out;
|
|
130
|
+
return buffer;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const char *backend() {
|
|
134
|
+
return CWS_ZLIB_BACKEND;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
}
|