Skip to content

Releases: vbacollective/wasabi

v2.3.8-beta

Choose a tag to compare

@uesleibros uesleibros released this 11 May 18:29
cb1c07d

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

Choose a tag to compare

@uesleibros uesleibros released this 11 May 01:51
0c049cc

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...

Read more

v2.3.6-beta

Choose a tag to compare

@uesleibros uesleibros released this 10 May 02:25
01fa84a

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 WebSocketDisconnect or WebSocketDisconnectAll from your code, which properly unregisters the socket from WSAAsyncSelect, 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

Choose a tag to compare

@uesleibros uesleibros released this 07 May 18:25
771c81c

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 .bas file 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: MqttPublish accepts metaKey / metaValue (property identifier 0x26), which are forwarded to MQTT 5 brokers.
  • Reason Codes & Metadata: MqttReceive parses 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 for TcpReceiveUntil)
  • tick_diff (overflow‑safe tick arithmetic)

Internal Refinements (No User‑Visible Changes)

  • The compression and protocol handler slots are now always initialised; calling WasabiUseCompression on 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.
  • CleanupHandle has been reviewed to guarantee that extension OnDisconnect callbacks fire before the underlying socket is closed.

v2.3.4-beta

Choose a tag to compare

@uesleibros uesleibros released this 07 May 01:29
f9da149

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 in TLSDecrypt where a graceful TLS session termination by the server (sending a close_notify alert) caused Schannel to return SEC_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 a close_notify, Wasabi would attempt to send queued data (or pings) to a dead TCP socket, resulting in a local WSAECONNABORTED (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 TLSDecrypt routine now intercepts SEC_I_CONTEXT_EXPIRED, gracefully sets the internal connection state to STATE_CLOSED, and silently delegates the flow to the AutoReconnect engine without throwing false-positive UI or log errors.
  • Impact: AutoReconnect now works flawlessly on server-initiated disconnects, preventing the cascading ERR 15 -> ERR 10 failure loop.

v2.3.3-beta

Choose a tag to compare

@uesleibros uesleibros released this 06 May 21:51
c379c41

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 VBA For...Next loops, payloads ranging from kilobytes to several megabytes are now masked in microseconds.
  • mem_zero (Assembly): Implements hardware-level memory zeroing using the rep stosb instruction. 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 the repe cmpsb instruction. It allows Wasabi to scan massive TCP streams for delimiters almost instantaneously.
Core Engine Otimizations
  • Native Entropy via RtlGenRandom: Replaced the legacy CryptGenRandom (which required complex CSP context management) with the SystemFunction036 (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 the mem_find thunk. Searching for patterns like \r\n or custom binary delimiters no longer blocks the Office UI thread during large data transfers.
  • Proactive Buffer Sanitization: Updated the CleanupHandle routine to utilize the new mem_zero engine. 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 strictly Private. The engine complexity is completely abstracted away, leaving a clean, high-level API for the end user.
  • Binary Lifecycle Management: Added InitWasabiThunks and ShutdownWasabiThunks procedures. These manage the safe allocation of executable memory via VirtualAlloc with PAGE_EXECUTE_READWRITE permissions and ensure all allocated pages are freed immediately upon WSACleanup.
  • Dead Code Elimination (JIT Cleanup): Stripped legacy bitwise math functions (U32Shl1, SHR32, ROTL32, ADD32) and unused thunks like swap_32. This reduces the module size and minimizes the memory footprint.
  • Hardened SafeArrayLen: Improved the pointer-based array length detection. By using VarPtrArray and CopyMemoryFromPtr instead of On Error traps, 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

Choose a tag to compare

@uesleibros uesleibros released this 06 May 00:43
e069ac0

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 racing
  • TcpConnectTLS(host, port, outHandle) — TLS 1.2/1.3 over TCP using the existing SChannel stack
  • TcpDisconnect(handle) — clean teardown
  • TcpIsConnected(handle) — connection state check
  • TcpGetConnectionCount() — active TCP handle count
  • TcpGetAllHandles() — array of all active TCP handles
I/O
  • TcpSend(data(), handle) — send raw byte array
  • TcpSendText(text, handle) — send UTF-8 encoded string
  • TcpReceive(handle) — receive available bytes as byte array
  • TcpReceiveText(handle) — receive available bytes as UTF-8 string
  • TcpReceiveUntil(delimiter, timeoutMs, handle) — blocking read until delimiter found or timeout, leftover bytes preserved in buffer for next call
  • TcpFlushBuffer(handle) — discard pending receive buffer
  • TcpGetPendingBytes(handle) — bytes waiting in receive buffer
  • TcpBroadcast(data(), handle) — send byte array to all active TCP handles
  • TcpBroadcastText(text) — send UTF-8 string to all active TCP handles
Configuration
  • TcpSetNoDelay(enabled, handle) — toggle Nagle algorithm at any time, even mid-connection
  • TcpSetInactivityTimeout(timeoutMs, handle) — auto-close connection after period of silence
  • TcpSetReceiveTimeout(timeoutMs, handle) — per-handle receive timeout
  • TcpSetBufferSize(bufferSize, handle) — custom receive buffer size (8KB to 16MB)
  • TcpSetPreferIPv6(enabled, handle) — prefer IPv6 in Happy Eyeballs race
  • TcpSetMTU(mtu, handle) — manual MTU override (576–9000)
  • TcpSetAutoMTU(enabled, handle) — enable/disable automatic MTU discovery via TCP_MAXSEG
  • TcpSetErrorDialog(enabled, handle) — show MsgBox on errors
  • TcpSetLogCallback(callbackName, handle) — per-handle log routing to VBA procedure
TLS
  • TcpSetCertValidation(enabled, handle) — enable full server certificate chain validation
  • TcpSetRevocationCheck(enabled, handle) — enable CRL/OCSP revocation checking
  • TcpSetClientCert(thumbprintOrSubject, handle) — load client certificate from Windows MY store
  • TcpSetClientCertPfx(pfxPath, pfxPassword, handle) — load client certificate from PFX file
Proxy
  • TcpSetProxy(host, port, user, pass, type, handle) — HTTP or SOCKS5 proxy
  • TcpClearProxy(handle) — remove proxy configuration
  • TcpAutoDiscoverProxy(handle) — auto-detect system proxy via WinHTTP IE config
  • TcpGetProxyInfo(handle) — proxy configuration summary
Diagnostics & Stats
  • TcpGetStats(handle) — full stats string: bytes sent/received, messages, uptime, pending bytes, proxy, mode, host, port
  • TcpResetStats(handle) — reset counters
  • TcpGetUptime(handle) — seconds since connection established
  • TcpGetLatency(handle) — last measured RTT in ms
  • TcpGetMTUInfo(handle) — MTU, MSS, optimal frame size
  • TcpGetHost(handle) — connected host
  • TcpGetPort(handle) — connected port
  • TcpGetMode(handle) — returns MODE_TCP or MODE_TCP_TLS
  • TcpGetLastError(handle) — last WasabiError enum value
  • TcpGetLastErrorCode(handle) — last system error code
  • TcpGetTechnicalDetails(handle) — human-readable error description

Internal Architecture

  • New WasabiConnectionMode enum: MODE_WEBSOCKET, MODE_TCP, MODE_TCP_TLS
  • New TcpConnectInternal private function extracts pure connection logic shared by all modes
  • ConnectHandle refactored as a thin wrapper: TcpConnectInternal + WebSocket handshake
  • FeedBuffer now branches by connection mode — WebSocket frames go to ProcessFrames, TCP raw data goes directly to TcpRecvBuffer
  • TickMaintenance now skips WebSocket-specific ping logic for TCP handles
  • WebSocketDisconnect and WebSocketDisconnectAll now mode-aware, TCP handles routed to TcpDisconnect
  • WebSocketGetConnectionCount and WebSocketGetAllHandles now filter by MODE_WEBSOCKET only
  • SafeArrayLen rewritten without On Error using VarPtrArray + CopyMemoryFromPtr to 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

Choose a tag to compare

@uesleibros uesleibros released this 05 May 23:41
db15c7c

Wasabi v2.3.1-beta

Fixed

  • Header Initialization (Error 9): Fixed a "Subscript out of range" crash in WebSocketAddHeader that occurred when attempting to add custom HTTP headers before a connection handle was fully allocated in memory. The internal .CustomHeaders array now safely initializes on demand.
  • Header Persistence (Auth Bug): Fixed a silent architectural bug where the internal ResetConnectionState routine would wipe .CustomHeaderCount immediately 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

Choose a tag to compare

@uesleibros uesleibros released this 05 May 22:46
07b6c12

Wasabi v2.3.0-beta

Added

  • MQTT QoS 2 (Exactly Once): Implemented the complete four-way acknowledgment handshake (PUBREC, PUBREL, PUBCOMP). The internal MqttInFlight queue now fully supports QoS 2, ensuring critical messages are never duplicated or lost, clearing them only when the final PUBCOMP confirmation 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 the AutoReconnect subsystem restores the connection, all buffered messages are automatically flushed to the server in their exact original order.
  • Ping Jitter: Enhanced WebSocketSetPingInterval with a new jitterMaxMs parameter. 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 AllocConnection to initialize recvBuffer, DecryptBuffer, and FragmentBuffer at 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 native StringToUtf8 function 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 InflatePayload where highly compressed incoming payloads (like massive JSONs) exceeded the static output buffer allocation. The function now dynamically expands the buffer in 16KB chunks using Z_BUF_ERROR checks until decompression is fully complete.
  • Close Frame Integer Overflow: Rewrote the status code bit-shifting logic in ProcessCloseFrame to 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 Long declarations inside MqttReceive due 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

Choose a tag to compare

@uesleibros uesleibros released this 05 May 04:21
e7e813b

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.