Releases: vbacollective/wasabi
Release list
v2.3.8-beta
Wasabi v2.3.8-beta
This release consolidates module hardening through a deep audit of memory management and strict compliance with RFC 6455 (WebSocket) and MQTT v5 specifications. The focus of this update was to eliminate undefined behavior in long-running systems and ensure data integrity during large-scale data streams.
Bug Fixes
WebSocket Protocol (RFC 6455)
ProcessCloseFrame: Corrected response array allocation
The previous implementation had a flaw in the replyFrame array dimension when handling server-initiated closes. The code now performs dynamic ReDim based on the presence or absence of a payload (reason string) in the close frame, ensuring that the header and the 4-byte mask are transmitted without memory corruption or index errors.
SendPongFrame: Masking key precedence order
The logic for constructing the PONG frame has been corrected. Assigning the mask to the frame's control bytes now occurs before the XOR encryption process. This ensures that the PONG payload is always masked with values already persisted in the output buffer, strictly aligning with BuildWSFrame behavior.
ProcessFrames: Strict validation of reserved bits (RSV2/RSV3)
In compliance with section 5.2 of RFC 6455, the frame parser now validates if reserved bits 2 and 3 are active. Since Wasabi does not negotiate extensions using these bits, their presence now results in the immediate termination of the connection with error code 1002 (Protocol Error), protecting the client against malformed or incompatible data streams.
WebSocketSendClose: FSM refinement in STATE_CLOSING
The state transition during the termination handshake has been improved. The module now correctly signals the STATE_CLOSING status and waits for the server's close echo before releasing socket resources, preventing "socket hung" errors during rapid connect/disconnect cycles.
MQTT v5
MqttUnsubscribe: Fixed static Packet ID
Fixed a bug where MqttUnsubscribe used a fixed Packet ID (10). The function now correctly utilizes the MqttNextPacketId global counter, ensuring each unsubscription request has a unique identifier, which is essential for tracking UNSUBACK in complex sessions.
MqttReceive: Migration from literals to protocol constants
The processing of disconnect packets was refactored to use the MQTT_DISCONNECT constant instead of the numeric literal 14. This change ensures code consistency and prevents silent breaks if the internal enumeration is expanded or modified in the future.
MqttPublish: PayloadLen calculation stabilization
Removed the use of the IIf function in the publication packet size calculation. In VBA, IIf always evaluates both arguments, which could introduce unwanted side effects. The calculation now uses a standard conditional structure, ensuring that space for the Packet ID is only reserved when QoS is greater than 0.
Memory Management and x64 Correctness
EnsureBufferCapacity: Expanded memory ceiling to 256 MB
The previous 16 MB limit for data fragments was identified as insufficient for industrial use cases and large binary payload transfers. The safety limit has been raised to 256 MB, with an aggressive growth strategy to minimize memory reallocations during frame accumulation.
Base64Encode: x64 idiomatic array initialization check
The input array integrity check was corrected to use the idiomatic (Not Not Bytes) = 0 pattern. The previous approach was inconsistent and could fail on 64-bit hosts due to how VBA handles pointers for uninitialized SafeArrays.
ReceiveHTTPResponse: TLS buffer draining
Fixed a flaw where the recvBuffer was not properly cleared after the successful extraction of an HTTP header on secure connections. This prevents old handshake remains from being reprocessed by the TLSDecrypt function, eliminating "Incomplete Message" errors in WSS Proxy tunnels.
WebSocketGetStats: Overflow protection for long-running connections
The uptime variable was converted from Long to Double. The previous calculation suffered from a signed overflow error after approximately 24 days of active connection. The new logic supports virtually unlimited connection times while maintaining telemetry calculation accuracy.
Notes
This release retains the -beta suffix while we finalize the validation of the new 256 MB memory model in Access 32-bit environments. The MQTT 5.0 and WebSocket WSS communication core is considered stable for integration into real-time automation and monitoring tools.
If you encounter any regression, please open a GitHub Issue detailing the scenario and the error code returned by WasabiGetErrorDescription.
MQTTX Bug Reported by Savings_Mission_534 https://www.reddit.com/r/vba/comments/1t9q3nc/comment/ol4zycm
v2.3.7-beta
Wasabi v2.3.7-beta
This release delivers a comprehensive structural overhaul focused on Winsock spec compliance, memory safety, x64 pointer correctness, MQTT v5 protocol alignment, and API naming consistency. It is not a feature release. Every change addresses a correctness or stability defect that could manifest silently in production workbooks.
Bug Fixes
Winsock Core and Asynchronous I/O
FeedBuffer: Exhaustive FD_READ draining via FIONREAD loop
The previous implementation read up to 64 KB per FD_READ event and returned. This violated the level-triggered contract of WSAAsyncSelect: if bytes remained in the kernel buffer after a partial read, Windows would not fire a new FD_READ event, causing the connection to silently stall until the next polling cycle. FeedBuffer is now a closed Do loop driven by ioctlsocket(FIONREAD) that continues reading until the kernel reports zero available bytes, fully satisfying the Winsock specification.
RawSendFor: Graceful handling of partial send() writes
The send path now loops until all bytes in a frame are flushed to the kernel, correctly handling partial writes that can occur when the socket send buffer is under pressure during large transfers.
ResolveAndConnect: IPv6 address truncation on x64
An incorrect CLng conversion was silently truncating IPv6 addresses whose pointer values exceeded 2 GB on 64-bit hosts. The affected code path now applies the correct 64-bit mask (&HFFFFFFFF^) via getaddrinfo, making IPv6 resolution reliable under VBA7.
TLS and SSPI
GenerateNtlmToken: Corrupt NTLM token decoding
StrConv was being used to decode Base64-encoded NTLM challenge tokens before passing them to InitializeSecurityContext. StrConv applies codepage transformations that corrupt arbitrary binary data. The function now uses CryptStringToBinaryW from crypt32.dll to decode tokens byte-for-byte as intended by the SSPI contract.
DoTLSHandshake: Buffer overflow on oversized server certificates
If a server delivered a certificate chain whose total size exceeded 32 KB across fragmented SEC_E_INCOMPLETE_MESSAGE reads, the internal receive buffer could overflow. The handshake loop now performs a bounds-checked ReDim Preserve on the accumulation buffer before each sock_recv call, allowing it to handle arbitrarily large certificate chains without risk.
CloseSession: Double-free of SecHandle and CredHandle resources
Disconnect paths could invoke FreeCredentialsHandle and DeleteSecurityContext on already-released handles when CloseSession was called through multiple code paths for the same connection. The cleanup routine is now routed exclusively through CleanupHandle, which performs a single guarded release of both handles and nullifies the pointers on exit, eliminating crashes in EXCEL.EXE caused by double-free.
HTTP proxy tunnel: Silent auth failure on second NTLM pass
The second-pass NTLM credential submission was not validating the server's response code. A rejected credential could produce a non-200 response that was silently interpreted as a successful tunnel, causing the subsequent TLS handshake to fail with a confusing SSPI error. The tunnel validation now strictly checks for 200 before proceeding.
WebSocket Protocol (RFC 6455)
Close frame: Malformed header for payloadless close
Sending a Close frame with no reason string (the common case when disconnecting with code 1000 and no reason) incorrectly set the payload length field to 2, implying that two bytes of payload followed. The correct encoding for a code-only close is a 4-byte frame: FIN+opcode, mask+length=2, and the 4-byte masking key with the two status code bytes XOR-masked against it. Wasabi was emitting the header with length=2 but constructing the body as if length=0, producing a malformed frame that caused NGINX and HAProxy to drop the client. The close frame builder now branches correctly on payload length.
Offline queue: Unbounded memory growth (OOM protection)
OfflineQueueEnabled grew the internal text and binary offline queues without limit. Under a sustained network outage with active sends, this would consume all available process memory. Both queues are now hard-capped at 10,000 entries. Attempts to enqueue beyond this limit emit a log warning and drop the message rather than expanding the buffer.
MQTT v5
MqttSubscribe / MqttUnsubscribe: Missing Property Length byte causing broker timeout
MQTT v5 requires a Property Length varint field in the variable header of SUBSCRIBE and UNSUBSCRIBE packets, even when no properties are present. The missing 0x00 byte caused compliant brokers such as HiveMQ to parse the packet incorrectly, producing a timeout instead of a SUBACK. The byte is now correctly injected.
MqttDecodeVarInt: Truncated VarInt multiplier
The VarInt decoder used an incorrect upper bound for the multiplier loop, limiting readable packet sizes to well below the MQTT v5 theoretical maximum of 268,435,455 bytes. The loop guard is now multiplier > 268435456, restoring full protocol range.
Memory Safety and x64 Pointer Correctness
WasabiAsyncWndProc: lParam read width mismatch on x64
The async window procedure was extracting the connection handle from lParam using a 4-byte CopyMemory call in a context where lParam is 8 bytes on a 64-bit host. This produced undefined behavior and potential handle misidentification. The extraction now uses a bitmask (CLng(lParam And &HFFFFFFFF&)) that is safe on both 32-bit and 64-bit targets.
TickDiff: Signed overflow on long-running connections
Subtracting two GetTickCount values in a Long context produced negative results after approximately 24.9 days of uptime, causing inactivity timeout and ping scheduling logic to malfunction. The computation now casts through CDbl with a 32-bit mask before comparison, making it overflow-safe for arbitrarily long connections.
BuildWSFrame: Uninitialized array guard before CopyMemory
A CopyMemory call into the frame buffer could be reached before the target array was dimensioned in certain zero-length payload paths, producing a runtime error. An initialization guard now ensures the buffer is allocated before any memory copy.
BuildWSFrame: payloadLen = 127 overflow protection
A payload length of exactly 127 triggered the 16-bit extended length path, which is incorrect: 127 is a reserved value in the WebSocket framing spec and the extended length path begins at 126. A guard now prevents this case from producing a malformed frame header.
WebSocketSendBatch / WebSocketSendBatchBinary: flushBuf scope instability
The flush buffer variable was declared at a scope that could be uninitialized if the payload array was empty, causing an error on the first ReDim or CopyMemory. The variable is now scoped and initialized at the top of the batch loop before any conditional branch.
API Changes
The following identifiers have been renamed for naming consistency and clarity. All old names have been removed. See the Migration Guide below for a complete mapping.
Symmetry between binary and text variants:
TcpSend is now TcpSendBinary. TcpReceive is now TcpReceiveBinary. TcpBroadcast is now TcpBroadcastBinary. WebSocketBroadcast is now WebSocketBroadcastText. WebSocketSendMTUAware is now WebSocketSendTextMTUAware.
Semantic corrections:
WebSocketGetErrorDescription is now WasabiGetErrorDescription. The previous name was misleading because the function reports errors from TCP and MQTT contexts in addition to WebSocket. WebSocketSetBufferSizes is now WebSocketSetBufferSize (singular). MqttPingReq is now MqttSendPing, hiding internal MQTT protocol terminology from the public API surface.
Win32 declaration reorganization:
All Declare Function / Declare Sub statements have been reorganized into named groups by source library (advapi32, bcrypt, crypt32, kernel32, secur32, user32, winhttp, ws2_32) and sorted alphabetically within each group. This is an internal change with no effect on behavior.
Migration Guide
The table below covers every identifier that changed in this release. No other public API surface was modified.
| Previous name | Current name | Notes |
|---|---|---|
TcpSend |
TcpSendBinary |
Raw byte array send on TCP handles |
TcpReceive |
TcpReceiveBinary |
Raw byte array receive on TCP handles |
TcpBroadcast |
TcpBroadcastBinary |
Byte array broadcast to all TCP handles |
WebSocketBroadcast |
WebSocketBroadcastText |
Text broadcast to all WebSocket handles |
WebSocketSendMTUAware |
WebSocketSendTextMTUAware |
MTU-fragmented text send |
WebSocketGetErrorDescription |
WasabiGetErrorDescription |
Error description covering TCP, WebSocket, and MQTT |
WebSocketSetBufferSizes |
WebSocketSetBufferSize |
Receive and fragment buffer size configuration |
MqttPingReq |
MqttSendPing |
MQTT PINGREQ keep-alive |
All renamed functions carry identical signatures. A project-wide find-and-replace on each old name is sufficient to migrate. No parameter changes, no behavioral changes.
Notes
This release carries the -beta suffix because the async thunk memory model has not yet been validated under all VBA host configurations (Excel 32-bit, Excel 64-bit, Access, and VB6). The core TCP, WebSocket, and MQTT paths are considered stable. The async subsystem (WasabiUseAsync, WasabiAsyncWndProc) should be treated as production-candidate but not production-certified until the next tagged release.
If you encounter any regression introduced by this release, please open an issue with the error code from `WasabiGetErrorDescript...
v2.3.6-beta
Wasabi v2.3.6
This release brings a significant internal restructuring alongside a handful of meaningful behavioral changes. The public API surface stays largely compatible with v2.3.5, with the exception of two renamed functions. Most of what changed lives under the hood: a cleaner code layout, stronger cryptographic primitives, better documentation of internal structures, and a more stable foundation for the async system introduced in the previous cycle.
Breaking Changes
WebSocketSend renamed to WebSocketSendText
WebSocketReceive renamed to WebSocketReceiveText
The old names are no longer present. This rename was made to align with the binary counterparts (WebSocketSendBinary, WebSocketReceiveBinary) and make the intent of each function unambiguous at a glance. A global find-and-replace in any workbook that calls these functions is all that's needed.
Security
Replaced RtlGenRandom with BCryptGenRandom
The internal random byte generation used for WebSocket frame masking keys previously called RtlGenRandom (exported from advapi32.dll under the undocumented alias SystemFunction036). This worked fine in practice, but relying on an undocumented export is not something to depend on long-term. The call now goes through BCryptGenRandom from bcrypt.dll with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag, which is the documented, supported path for cryptographically strong random bytes on Windows Vista and later. The behavior is identical from the outside; this is purely an internal correctness improvement.
Async Event-Driven Model (Experimental)
This feature is experimental. The underlying mechanism involves native Win32 window subclassing via a machine-code thunk, which comes with some hard constraints you need to be aware of before using it in production.
The async model introduced in the previous release is now better documented and stabilized, but the subclassing mechanism still has sharp edges:
Do not edit code in the VBE while an async connection is active. Doing so will crash the host application. The thunk holds a pointer into the VBA runtime, and the VBE's project reset path does not give Wasabi a chance to clean up before tearing down the runtime.
Do not use the Pause button (yellow square) in the VBE while async is running. This also triggers a project reset and will cause a crash for the same reason.
The correct way to stop an async session is either:
- Calling
WebSocketDisconnectorWebSocketDisconnectAllfrom your code, which properly unregisters the socket fromWSAAsyncSelect, restores the original window procedure, destroys the hidden window, and releases the thunk memory. - Clicking the Reset button (blue square) in the VBE, but only after calling one of the disconnect functions first. Clicking Reset without disconnecting first is unsafe.
The thunk contains a guard that attempts to detect whether the VBA runtime is still alive before dispatching, but explicit cleanup is the only reliable approach. Treat this the same way you would treat any unmanaged resource.
Everything else about the async model works as described in the API reference. The handler object must be stored at module or workbook level, the five callback methods must be implemented, and the connection must already be established before calling WasabiUseAsync.
Code Organization
The module was reorganized into a numbered section layout to make navigation easier in the VBE, which does not have a file outline view:
1. API Declarations
2. Constants
3. Types & Structs
4. Enums
5. Global Variables
6. Low-Level Memory & Thunks
7. Windows Messaging & Async Core
8. Time & Buffer Utilities
9. Connection Pool Management
10. Network Infrastructure (MTU, Proxy, TCP, Certificates)
11. WebSocket Protocol Core
12. TCP/Buffering Core
13. MQTT Protocol Core
14. Middleware & Queueing
15. Public APIs (TCP, WebSocket, MQTT, Compression)
This is a pure organizational change. No logic was moved or modified as part of the restructure; the diff between sections only reflects repositioned declarations and renamed groupings.
All constants, enums, and type definitions were also moved into their respective sections rather than being scattered. WasabiError, MqttPacketType, and WasabiConnectionMode now live in section 4 alongside the other enums. Constants like BUFFER_SIZE, MSG_QUEUE_SIZE, and the socket/TLS/crypto constants are now grouped under section 2 with comments indicating which subsystem they belong to.
Internal Documentation
All private types, structs, and key functions now carry JSDoc-style block comments describing their purpose and fields. This is primarily useful if you ever need to read or modify the internals, and it also makes it easier to follow the data flow between the TLS, WebSocket, and MQTT layers when something goes wrong and you need to trace it.
The license header was also updated to JSDoc block format for consistency with the rest of the file.
Fixes and Minor Improvements
INVALID_SOCKET is now declared once per compilation target (64-bit or 32-bit) at the top of the global variables section, removing the redundant #If VBA7 block that previously re-declared it mid-file.
The HOSTENT64 type declaration was moved to the types section alongside HOSTENT32, where it belongs. Previously it was declared much later in the file, away from the other network structs.
The BCRYPT_USE_SYSTEM_PREFERRED_RNG constant is now explicitly declared rather than inlined as a magic number, consistent with how every other Win32 constant is handled in the module.
Notes on Upgrading from v2.3.5
The only change that will break existing code is the rename of WebSocketSend and WebSocketReceive. Everything else is either internal or additive. If your code does not call either of those two functions directly, upgrading is a drop-in replacement.
v2.3.5-beta
Wasabi v2.3.5‑beta
Agnostic compression, hardened MQTT 5, and a fully modular engine — all inside the same zero‑dependency .bas file.
This release solidifies the architectural foundations that were already running under the hood. No breaking APIs; every existing project will work exactly as before. What has changed is that the internal boundaries between transport, protocol, compression, and middleware are now officially stable and ready to be used by extension authors.
Engine Architecture: Dumb Pipe + Pluggable Everything
The core TCP / TLS / Schannel machinery ("the Dumb Pipe") is now completely decoupled from high‑level logic. Three injection points are formally exposed and documented:
WasabiUseProtocol— intercept parsed WebSocket messages (text and binary) directly, bypassing the internal queue.WasabiUseMiddleware— intercept raw byte arrays before framing (send) and after deframing (receive); multiple middlewares can be chained.WasabiUseCompression— replace or provide the compression algorithm; the engine no longer assumes any particular library.
This transforms Wasabi from a monolithic WebSocket client into a networking framework that can host custom protocols, encryption layers, and alternative compressors.
Compression Is Now Truly Optional (and Pluggable)
The previous documentation incorrectly suggested zlib1.dll was a required dependency for permessage‑deflate. In reality, the engine has always used an internal CompressionHandler interface (Inversion of Control). The built‑in deflate path is now an official extension (ExtWasabiZlib.cls) that can be swapped for LZ4, Brotli, Zstandard, or an identity pass‑through.
- The core
.basfile has zero mandatory external dependencies — exactly as designed. - If you never register a compression handler, absolutely nothing is linked or loaded.
MQTT 5.0 Support Hardened
The MQTT client now formally supports features that were already partially active in previous releases:
- User Properties:
MqttPublishacceptsmetaKey/metaValue(property identifier0x26), which are forwarded to MQTT 5 brokers. - Reason Codes & Metadata:
MqttReceiveparses and surfaces Reason Codes and optional diagnostic strings from CONNACK and DISCONNECT packets. - The internal parser correctly decodes MQTT 5 variable‑length property blocks, allowing future extension without breaking changes.
ASM Thunks & Zero‑Copy: Same Brutal Performance
The machine‑code engine (x86 / x64) that was introduced in v2.3.3 and validated in v2.3.4 remains untouched. It still drives:
ws_mask(XOR masking at C‑speed)mem_zero(hardware‑backed buffer wiping)mem_find(instant delimiter scan forTcpReceiveUntil)tick_diff(overflow‑safe tick arithmetic)
Internal Refinements (No User‑Visible Changes)
- The compression and protocol handler slots are now always initialised; calling
WasabiUseCompressionon a handle that was connected without deflate will simply leave the slot empty. - Error propagation wrapped in registered extensions is clarified: extensions must manage their own errors — the engine does not intercept exceptions thrown by middleware or protocol handlers.
CleanupHandlehas been reviewed to guarantee that extensionOnDisconnectcallbacks fire before the underlying socket is closed.
v2.3.4-beta
Wasabi v2.3.4-beta
This update addresses a critical edge case in the Schannel/TLS engine where graceful server disconnections were being misidentified as fatal cryptographic errors, improving the overall stability of long-lived connections (such as Discord Gateway or MQTT brokers).
Bug Fixes
- Fixed Phantom Decryption Errors (
ERR 15): Resolved an issue inTLSDecryptwhere a graceful TLS session termination by the server (sending aclose_notifyalert) caused Schannel to returnSEC_I_CONTEXT_EXPIRED. Previously, Wasabi treated this normal teardown as a decryption failure. - Fixed Zombie Socket Writes (
ERR 10): Because the connection state wasn't properly closed after aclose_notify, Wasabi would attempt to send queued data (or pings) to a dead TCP socket, resulting in a localWSAECONNABORTED(10053) crash. This has been completely eliminated.
Technical Details & Under the Hood
- Added the
SEC_I_CONTEXT_EXPIRED(0x90317) constant to the core Schannel definitions. - The
TLSDecryptroutine now interceptsSEC_I_CONTEXT_EXPIRED, gracefully sets the internal connection state toSTATE_CLOSED, and silently delegates the flow to theAutoReconnectengine without throwing false-positive UI or log errors. - Impact:
AutoReconnectnow works flawlessly on server-initiated disconnects, preventing the cascadingERR 15->ERR 10failure loop.
v2.3.3-beta
Wasabi v2.3.3-beta
What's New
High-Performance Assembly Engine (Wasabi ASM)
This release introduces a paradigm shift in VBA networking performance. We have successfully offloaded critical byte-processing bottlenecks from the interpreted VBA runtime directly to the CPU via Machine Code Thunks. Wasabi now executes native x86 and x64 instructions for heavy lifting, achieving C-level throughput.
Integrated Low-Level Thunks
ws_mask(Assembly): A complete rewrite of the WebSocket XOR masking logic. By eliminating the high-overhead VBAFor...Nextloops, payloads ranging from kilobytes to several megabytes are now masked in microseconds.mem_zero(Assembly): Implements hardware-level memory zeroing using therep stosbinstruction. This provides a lightning-fast way to clear internal buffers without the overhead of external DLL calls.mem_find(Assembly): An ultra-optimized "Needle in a Haystack" search engine powered by therepe cmpsbinstruction. It allows Wasabi to scan massive TCP streams for delimiters almost instantaneously.
Core Engine Otimizations
- Native Entropy via
RtlGenRandom: Replaced the legacyCryptGenRandom(which required complex CSP context management) with theSystemFunction036(RtlGenRandom) API. This fetches cryptographically secure random bytes for WebSocket masking directly from the Windows Kernel with significantly lower latency. - ASM-Powered
TcpReceiveUntil: The blocking read-until-delimiter logic has been refactored to use themem_findthunk. Searching for patterns like\r\nor custom binary delimiters no longer blocks the Office UI thread during large data transfers. - Proactive Buffer Sanitization: Updated the
CleanupHandleroutine to utilize the newmem_zeroengine. Upon connection teardown, all sensitive buffers (recvBuffer,DecryptBuffer,TcpRecvBuffer) are physically zeroed in RAM to prevent data leakage and improve security.
Internal Architecture & Bug Fixes
- Discord Gateway Fix (Error 4002): Resolved a critical race condition/logic bug where payload data was being XORed in-place over uninitialized memory segments. Introduced a dedicated copy-buffer step before masking to ensure full compatibility with Discord's strict frame validation.
- Zero-Footprint Encapsulation: All assembly-related infrastructure (
LoadThunk,WasabiMemFind,m_ptr*pointers) is now strictlyPrivate. The engine complexity is completely abstracted away, leaving a clean, high-level API for the end user. - Binary Lifecycle Management: Added
InitWasabiThunksandShutdownWasabiThunksprocedures. These manage the safe allocation of executable memory viaVirtualAllocwithPAGE_EXECUTE_READWRITEpermissions and ensure all allocated pages are freed immediately uponWSACleanup. - Dead Code Elimination (JIT Cleanup): Stripped legacy bitwise math functions (
U32Shl1,SHR32,ROTL32,ADD32) and unused thunks likeswap_32. This reduces the module size and minimizes the memory footprint. - Hardened
SafeArrayLen: Improved the pointer-based array length detection. By usingVarPtrArrayandCopyMemoryFromPtrinstead ofOn Errortraps, the module is now significantly more stable when handling uninitialized dynamic arrays.
Validated
Full test suite executed on Windows 10/11 (x86 & x64) across Excel 365, Word, and Access:
| Test Case | Status | Details |
|---|---|---|
| Discord IDENTIFY Masking | ✅ Passed | Resolved 4002 error; handshake stable. |
| Throughput (10MB Payload) | ✅ Passed | Masking overhead is now sub-millisecond. |
| Secure Wipe on Close | ✅ Passed | Verified RAM zeroing via memory dump. |
TcpReceiveUntil Scanner |
✅ Passed | ASM scan found \r\n in 1MB buffer instantly. |
| x64 FastCall Alignment | ✅ Passed | Registers (RCX, RDX, R8, R9) verified stable. |
| x86 Stack Integrity | ✅ Passed | Ret 16 cleanup verified; no stack corruption. |
| Kernel Entropy | ✅ Passed | RtlGenRandom successfully seeding mask keys. |
Tip
Performance Impact: With the Wasabi ASM Engine, processing overhead for the networking layer is now effectively "free" in terms of CPU cycles. This allows your VBA project to dedicate 100% of its execution time to your bot's logic or data processing rather than handling protocol-level math.
v2.3.2-beta
Wasabi v2.3.2-beta
What's New
TCP Client Support
Wasabi now ships with a full native TCP client alongside the existing WebSocket layer. Both modes share the same connection pool, handle system, proxy infrastructure, and TLS stack — no additional setup required.
Connection
TcpConnect(host, port, outHandle)— plain TCP connection with Happy Eyeballs IPv4/IPv6 racingTcpConnectTLS(host, port, outHandle)— TLS 1.2/1.3 over TCP using the existing SChannel stackTcpDisconnect(handle)— clean teardownTcpIsConnected(handle)— connection state checkTcpGetConnectionCount()— active TCP handle countTcpGetAllHandles()— array of all active TCP handles
I/O
TcpSend(data(), handle)— send raw byte arrayTcpSendText(text, handle)— send UTF-8 encoded stringTcpReceive(handle)— receive available bytes as byte arrayTcpReceiveText(handle)— receive available bytes as UTF-8 stringTcpReceiveUntil(delimiter, timeoutMs, handle)— blocking read until delimiter found or timeout, leftover bytes preserved in buffer for next callTcpFlushBuffer(handle)— discard pending receive bufferTcpGetPendingBytes(handle)— bytes waiting in receive bufferTcpBroadcast(data(), handle)— send byte array to all active TCP handlesTcpBroadcastText(text)— send UTF-8 string to all active TCP handles
Configuration
TcpSetNoDelay(enabled, handle)— toggle Nagle algorithm at any time, even mid-connectionTcpSetInactivityTimeout(timeoutMs, handle)— auto-close connection after period of silenceTcpSetReceiveTimeout(timeoutMs, handle)— per-handle receive timeoutTcpSetBufferSize(bufferSize, handle)— custom receive buffer size (8KB to 16MB)TcpSetPreferIPv6(enabled, handle)— prefer IPv6 in Happy Eyeballs raceTcpSetMTU(mtu, handle)— manual MTU override (576–9000)TcpSetAutoMTU(enabled, handle)— enable/disable automatic MTU discovery via TCP_MAXSEGTcpSetErrorDialog(enabled, handle)— show MsgBox on errorsTcpSetLogCallback(callbackName, handle)— per-handle log routing to VBA procedure
TLS
TcpSetCertValidation(enabled, handle)— enable full server certificate chain validationTcpSetRevocationCheck(enabled, handle)— enable CRL/OCSP revocation checkingTcpSetClientCert(thumbprintOrSubject, handle)— load client certificate from Windows MY storeTcpSetClientCertPfx(pfxPath, pfxPassword, handle)— load client certificate from PFX file
Proxy
TcpSetProxy(host, port, user, pass, type, handle)— HTTP or SOCKS5 proxyTcpClearProxy(handle)— remove proxy configurationTcpAutoDiscoverProxy(handle)— auto-detect system proxy via WinHTTP IE configTcpGetProxyInfo(handle)— proxy configuration summary
Diagnostics & Stats
TcpGetStats(handle)— full stats string: bytes sent/received, messages, uptime, pending bytes, proxy, mode, host, portTcpResetStats(handle)— reset countersTcpGetUptime(handle)— seconds since connection establishedTcpGetLatency(handle)— last measured RTT in msTcpGetMTUInfo(handle)— MTU, MSS, optimal frame sizeTcpGetHost(handle)— connected hostTcpGetPort(handle)— connected portTcpGetMode(handle)— returnsMODE_TCPorMODE_TCP_TLSTcpGetLastError(handle)— lastWasabiErrorenum valueTcpGetLastErrorCode(handle)— last system error codeTcpGetTechnicalDetails(handle)— human-readable error description
Internal Architecture
- New
WasabiConnectionModeenum:MODE_WEBSOCKET,MODE_TCP,MODE_TCP_TLS - New
TcpConnectInternalprivate function extracts pure connection logic shared by all modes ConnectHandlerefactored as a thin wrapper:TcpConnectInternal+ WebSocket handshakeFeedBuffernow branches by connection mode — WebSocket frames go toProcessFrames, TCP raw data goes directly toTcpRecvBufferTickMaintenancenow skips WebSocket-specific ping logic for TCP handlesWebSocketDisconnectandWebSocketDisconnectAllnow mode-aware, TCP handles routed toTcpDisconnectWebSocketGetConnectionCountandWebSocketGetAllHandlesnow filter byMODE_WEBSOCKETonlySafeArrayLenrewritten withoutOn ErrorusingVarPtrArray+CopyMemoryFromPtrto safely detect uninitialized arrays
Validated
Full test suite executed against tcpbin.com:4242 (plain TCP) and example.com:443 (TLS):
| Test | Result |
|---|---|
| Plain TCP connect/disconnect | ✅ 156ms RTT |
| TLS handshake (Cloudflare) | ✅ 125ms, HTTP 200 OK |
| Ping/Echo x5 | ✅ 5/5, avg 156ms RTT |
| Inactivity timeout | ✅ fired at exactly 2000ms |
| TcpReceiveUntil (CrLf, Lf, pipe, timeout) | ✅ all delimiters correct |
| 100-message load test | ✅ 100/100 in 469ms, zero loss |
| 5 simultaneous connections | ✅ all isolated, correct echo per handle |
| NoDelay toggle mid-connection | ✅ applied correctly |
| Reconnection after forced disconnect | ✅ handle reused, echo restored |
| Stats accuracy | ✅ bytes sent/received, messages tracked correctly |
v2.3.1-beta
Wasabi v2.3.1-beta
Fixed
- Header Initialization (Error 9): Fixed a "Subscript out of range" crash in
WebSocketAddHeaderthat occurred when attempting to add custom HTTP headers before a connection handle was fully allocated in memory. The internal.CustomHeadersarray now safely initializes on demand. - Header Persistence (Auth Bug): Fixed a silent architectural bug where the internal
ResetConnectionStateroutine would wipe.CustomHeaderCountimmediately before the handshake. Custom headers, such as Authorization Bearer tokens and Corporate Proxies configurations, now correctly persist through the connection lifecycle and are properly transmitted to the server.
v2.3.0-beta
Wasabi v2.3.0-beta
Added
- MQTT QoS 2 (Exactly Once): Implemented the complete four-way acknowledgment handshake (
PUBREC,PUBREL,PUBCOMP). The internalMqttInFlightqueue now fully supports QoS 2, ensuring critical messages are never duplicated or lost, clearing them only when the finalPUBCOMPconfirmation arrives. - Offline Queueing: Added
WebSocketSetOfflineQueueing. When enabled, messages (Text, Binary, and MQTT Publishes) sent while the socket is disconnected are safely buffered in secondary memory queues. Once theAutoReconnectsubsystem restores the connection, all buffered messages are automatically flushed to the server in their exact original order. - Ping Jitter: Enhanced
WebSocketSetPingIntervalwith a newjitterMaxMsparameter. This introduces pseudo-random variance to automatic keepalive pings, effectively bypassing strict anti-bot gateways that disconnect clients with perfectly robotic heartbeat timings.
Changed
- Dynamic Buffer Initialization: Heavily optimized
AllocConnectionto initializerecvBuffer,DecryptBuffer, andFragmentBufferat a lightweight 4KB instead of their maximum limits. Buffers now grow elastically on demand, saving approximately ~750KB of static RAM per newly allocated connection handle. - Strict UTF-8 Enforcement: Replaced all legacy
StrConv(..., vbFromUnicode)calls with the nativeStringToUtf8function during WebSocket and HTTP Proxy handshakes. This guarantees strict RFC compliance and prevents payload corruption on systems with non-ANSI localizations.
Fixed
- Zlib Decompression Overflow: Fixed a silent failure in
InflatePayloadwhere highly compressed incoming payloads (like massive JSONs) exceeded the static output buffer allocation. The function now dynamically expands the buffer in 16KB chunks usingZ_BUF_ERRORchecks until decompression is fully complete. - Close Frame Integer Overflow: Rewrote the status code bit-shifting logic in
ProcessCloseFrameto use 32-bit math (CLng), preventing fatal VBA overflow crashes if a server transmits a malformed close code where the first byte exceeds 127. - VBA Scoping Conflicts: Fixed a compilation error caused by duplicate
Dim j As Longdeclarations insideMqttReceivedue to VBA's function-level scoping limitations.
Notes
- This beta introduces enterprise-level connection resilience designed for unstable networks, complex bot gateways, and high-stakes MQTT broadcasting.
- Testing: Verified in 32-bit/64-bit Office environments. The complete MQTT QoS 2 lifecycle (Publish, Receive, and Full Acknowledgment) was verified against EMQX public brokers.
v2.2.1-vNext
Wasabi v2.2.1-vNext
Fixed
In the WebSocketGetUptime function, there was a condition using .Connected, which was part of WasabiConnection. This system, which no longer exists and was causing a Property not found error, was resolved by changing to the new state system .State = STATE_OPEN.