Replace CAsyncSocketEx custom WinSock wrapper — Boost.Asio or Windows IOCP
Classification¶
Abandoned by operator decision on 2026-05-21. This historical record preserves the old Boost/POCO analysis only as provenance; do not promote it without a new active item.
Summary¶
CAsyncSocketEx is ~3,000 lines of custom WinSock2 async infrastructure that
dispatches I/O events via hidden Win32 window messages (WM_SOCKETEX_NOTIFY,
WM_SOCKETEX_TRIGGER, etc.). This hidden-window message pump approach is
fragile, non-testable, and limits concurrency to the UI thread's message rate.
Two viable replacement paths are documented below as idea material; neither is selected for active work.
Current Pain Points¶
// AsyncSocketEx.h:80 — window-message event dispatch
#define WM_SOCKETEX_TRIGGER (WM_USER + 0x101 + 0)
#define WM_SOCKETEX_NOTIFY (WM_USER + 0x101 + 3)
#define MAX_SOCKETS (0xBFFF - WM_SOCKETEX_NOTIFY + 1)
// AsyncSocketEx.h:296 — async DNS via deprecated WinSock 1 callback
char *m_pAsyncGetHostByNameBuffer;
HANDLE m_hAsyncGetHostByNameHandle;
// UDPSocket.h:78 — raw pointer queue + per-socket lock
CTypedPtrList<CPtrList, SServerUDPPacket*> controlpacket_queue;
CCriticalSection sendLocker;
Files Affected¶
| File | Role |
|---|---|
srchybrid/AsyncSocketEx.h / .cpp |
The custom WinSock wrapper — delete under either path |
srchybrid/EMSocket.h / .cpp |
TCP stream layer — migrate |
srchybrid/ServerSocket.h / .cpp |
Server TCP connections — migrate |
srchybrid/UDPSocket.h / .cpp |
UDP datagram layer — migrate |
srchybrid/ListenSocket.cpp |
Incoming connection acceptor — migrate |
| ~65 additional files | Consumers of CAsyncSocketEx or raw SOCKET handles |
Option A — Boost.Asio¶
Prerequisites: Boost added as a dependency (any version ≥ 1.74).
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
using boost::asio::ip::udp;
// Shared io_context (replaces hidden helper window + message loop)
boost::asio::io_context io_ctx;
// Async TCP connect
tcp::socket sock(io_ctx);
sock.async_connect(endpoint, [](boost::system::error_code ec) { ... });
// Async DNS (replaces m_hAsyncGetHostByNameHandle)
tcp::resolver resolver(io_ctx);
resolver.async_resolve("host", "4662", [](auto ec, auto results) { ... });
// Async UDP send
udp::socket usock(io_ctx);
usock.async_send_to(boost::asio::buffer(data), remote_ep,
[](boost::system::error_code ec, std::size_t bytes) { ... });
Pros: Cross-platform; rich async primitives; composable with SSL (Boost.SSL);
large community and test coverage.
Cons: Large dependency; significant API surface change across 70+ files;
requires io_context threading model decision (single-thread poll vs. thread-pool).
Migration order:
1. Introduce boost::asio::io_context as application singleton.
2. Port CUDPSocket first — simpler than TCP.
3. Port CListenSocket / CServerSocket.
4. Port CEMSocket last — most complex, handles stream framing.
5. Keep CAsyncSocketEx alive in parallel; delete after all consumers are migrated.
Option B — Windows IOCP (no Boost dependency)¶
Replace the hidden-window message pump with a proper I/O Completion Port (IOCP) thread pool using standard Win32 APIs available on all supported Windows versions.
// Create IOCP
HANDLE hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
// Associate socket with IOCP
CreateIoCompletionPort((HANDLE)sock, hIocp, (ULONG_PTR)pClient, 0);
// Post overlapped receive
WSAOVERLAPPED ov = {};
WSARecv(sock, &wsaBuf, 1, &bytesRecv, &flags, &ov, NULL);
// Worker thread dequeues completed I/O
DWORD bytes; ULONG_PTR key; OVERLAPPED *pOv;
GetQueuedCompletionStatus(hIocp, &bytes, &key, &pOv, INFINITE);
// dispatch based on key / pOv
Pros: Zero new dependencies; highest performance on Windows; natural fit
with the Win10-only target; eliminates the hidden window entirely.
Cons: Lower-level API; completion-packet dispatch must be written by hand;
no built-in async DNS (use GetAddrInfoEx with completion routine or a
dedicated resolver thread).
Async DNS replacement for Option B:
// GetAddrInfoExW with completion routine (Vista+)
ADDRINFOEXW hints = { .ai_family = AF_INET };
GetAddrInfoExW(L"host", L"4662", NS_DNS, NULL, &hints,
&pResult, NULL, &overlapped, CompletionRoutine, &hCancel);
Recommendation¶
| Criterion | Option A (Boost.Asio) | Option B (IOCP) |
|---|---|---|
| Lines of new code | Low (Asio handles plumbing) | Medium (IOCP dispatch layer) |
| External dependency | Yes (Boost) | No |
| Cross-platform future | Yes | Windows-only |
| API familiarity | Moderate | Lower |
| Performance ceiling | High (Asio uses IOCP internally on Windows) | Identical |
If Boost is already adopted (see REF-009), prefer Option A. If staying dependency-free, use Option B.
Acceptance Criteria (both options)¶
- [ ]
CAsyncSocketEx/AsyncSocketEx.h/.cppdeleted - [ ] Hidden helper window (
CAsyncSocketExHelperWindow) eliminated - [ ]
WSAAsyncGetHostByNameremoved; replaced with async DNS - [ ] UDP packet queue uses standard containers with
std::mutex - [ ] TCP and UDP async I/O verified under load testing
- [ ] Compile-time: no
WM_SOCKETEX_*message defines remain