Parent epic: #40 (E13 Cross-Platform CI and Windows)
Goal
Replace the leaked struct sockaddr_in* in the Resolver/Datagram/Stream interfaces with an opaque SolidSyslogAddress type. The concrete address type (sockaddr_in, or a Winsock equivalent) stays inside the platform source; senders and other platform-agnostic code only see a forward declaration and an opaquely-sized storage buffer. Public API stops including <netinet/in.h>.
Outcomes
- Platform-agnostic code (senders, dispatch) no longer includes POSIX socket headers.
- A sender holds an address inside its own storage via the storage pattern; it can pass a pointer to the address to Stream/Datagram without knowing the layout.
- Switching between POSIX and Winsock builds does not require any source change in senders or dispatch code — the platform-specific address header is selected by the include path.
- Alignment is preserved so platform code can safely cast the storage to the underlying address struct.
Scope
- New platform-specific header
Platform/<OS>/Interface/SolidSyslogAddress.h:
- Forward declaration of
struct SolidSyslogAddress.
- Platform-sized
SolidSyslogAddressStorage typedef — an array of void* to guarantee alignment (MISRA-compliant; no unions).
SolidSyslogAddress_FromStorage(SolidSyslogAddressStorage*) accessor.
- New platform source
Platform/<OS>/Source/SolidSyslogAddress.c providing the concrete struct and the FromStorage implementation.
- Resolver vtable signature:
struct SolidSyslogAddress* replaces struct sockaddr_in*.
- Datagram vtable signature:
const struct SolidSyslogAddress* replaces const struct sockaddr_in* in SendTo.
- Stream vtable signature:
const struct SolidSyslogAddress* replaces const struct sockaddr_in* in Open.
- Sender structs switch from
struct sockaddr_in addr to SolidSyslogAddressStorage addrStorage + SolidSyslogAddress* obtained via FromStorage.
- Platform implementations of Resolver/Datagram/Stream cast internally to the concrete type, via a
uint8_t* view for strict-aliasing safety.
Out of scope
- IPv6 support — the storage is sized to hold the widest concrete address struct (
struct sockaddr_storage worth of bytes) so IPv6 will fit without future API churn, but activating IPv6 resolution is a separate story.
- Non-IP transports (Unix sockets, etc.) — not on the roadmap.
Design notes
- No unions — MISRA 19.2 flags unions as problematic. Storage is an array of
void* whose count is sized to cover the concrete address struct on both 32-bit and 64-bit targets (e.g. 32 pointers = 128 bytes on 32-bit, 256 bytes on 64-bit; always ≥ sizeof(struct sockaddr_storage)).
- Alignment by construction — the pointer-array storage inherits
alignof(void*), which meets or exceeds the alignment requirement of any sockaddr_* struct on supported platforms.
- Aliasing — platform code casts
SolidSyslogAddressStorage* to uint8_t* (a character type, permitted to alias any object under C99 strict aliasing), then to the concrete struct type, or uses memcpy for in/out copies when that is clearer.
- Because each build targets exactly one platform, there is no multi-platform ABI concern — the
SolidSyslogAddress shape is fixed at build time by the active Platform/<OS>/ include path.
- Depends on the platform folder reorganisation being in place first (otherwise the address header has no natural home).
Context
Pairs with S12.11 (honest error reporting) at the same interface boundary — both touch Resolver.Resolve, Datagram.Open, Stream.Open signatures, so doing them in sequence avoids churning the same signatures twice. Unblocks the Winsock stories (S13.04, S13.09) by removing the POSIX type leak from their public contract.
Parent epic: #40 (E13 Cross-Platform CI and Windows)
Goal
Replace the leaked
struct sockaddr_in*in the Resolver/Datagram/Stream interfaces with an opaqueSolidSyslogAddresstype. The concrete address type (sockaddr_in, or a Winsock equivalent) stays inside the platform source; senders and other platform-agnostic code only see a forward declaration and an opaquely-sized storage buffer. Public API stops including<netinet/in.h>.Outcomes
Scope
Platform/<OS>/Interface/SolidSyslogAddress.h:struct SolidSyslogAddress.SolidSyslogAddressStoragetypedef — an array ofvoid*to guarantee alignment (MISRA-compliant; no unions).SolidSyslogAddress_FromStorage(SolidSyslogAddressStorage*)accessor.Platform/<OS>/Source/SolidSyslogAddress.cproviding the concrete struct and theFromStorageimplementation.struct SolidSyslogAddress*replacesstruct sockaddr_in*.const struct SolidSyslogAddress*replacesconst struct sockaddr_in*inSendTo.const struct SolidSyslogAddress*replacesconst struct sockaddr_in*inOpen.struct sockaddr_in addrtoSolidSyslogAddressStorage addrStorage+SolidSyslogAddress*obtained viaFromStorage.uint8_t*view for strict-aliasing safety.Out of scope
struct sockaddr_storageworth of bytes) so IPv6 will fit without future API churn, but activating IPv6 resolution is a separate story.Design notes
void*whose count is sized to cover the concrete address struct on both 32-bit and 64-bit targets (e.g. 32 pointers = 128 bytes on 32-bit, 256 bytes on 64-bit; always ≥sizeof(struct sockaddr_storage)).alignof(void*), which meets or exceeds the alignment requirement of anysockaddr_*struct on supported platforms.SolidSyslogAddressStorage*touint8_t*(a character type, permitted to alias any object under C99 strict aliasing), then to the concrete struct type, or usesmemcpyfor in/out copies when that is clearer.SolidSyslogAddressshape is fixed at build time by the activePlatform/<OS>/include path.Context
Pairs with S12.11 (honest error reporting) at the same interface boundary — both touch Resolver.Resolve, Datagram.Open, Stream.Open signatures, so doing them in sequence avoids churning the same signatures twice. Unblocks the Winsock stories (S13.04, S13.09) by removing the POSIX type leak from their public contract.