Skip to content

fix: an oversize datagram is lost on any platform that cannot detect oversize #736

Description

@DavidCozens

SolidSyslogUdpSender never trims a record on a datagram platform that collapses
OVERSIZE into FAILED, so a record larger than the path can carry is handed to
the stack whole and then lost.

Why

UdpSender_TransmitDatagram sends at full size and consults MaxPayload only
after a rejection:

result = SolidSyslogDatagram_SendTo(self->Config.Datagram, buffer, size, ...);
if (result == SOLIDSYSLOG_DATAGRAM_SEND_RESULT_OVERSIZE)
{
    result = UdpSender_RetryAfterOversize(self, buffer, size);
}

SolidSyslogDatagram.h explicitly permits an implementation that cannot detect
oversize to collapse it into FAILED, so those platforms are conforming. What
does not hold is the recovery: with no OVERSIZE, the trim path never runs, and
MaxPayload — which those platforms answer honestly with the IPv6-safe floor —
is never asked.

SOLIDSYSLOG_MAX_MESSAGE_SIZE defaults to 2048 against a 1232-byte safe payload,
so this is the out-of-the-box case for any record over about 1.2 KB, not an edge.

Detects oversize: Posix (EMSGSIZE), Windows.
Does not: FreeRTOS-Plus-TCP, lwIP (Raw API) — both report
SOLIDSYSLOG_UDP_IPV6_SAFE_PAYLOAD from MaxPayload and never return
OVERSIZE.

Two shapes, and a trade-off to settle first

Platform-side. A non-detecting adapter compares size against its own
MaxPayload and returns OVERSIZE itself. Core is unchanged, the contract is
untouched, and each platform uses its own honest number. Costs a repeated check
per adapter.

Caller-side. UdpSender clips to MaxPayload before the first send.
One place, and it makes MaxPayload meaningful everywhere rather than only on
the recovery path.

Either way there is a real trade-off, and it should be decided deliberately
rather than fallen into: today a 1300-byte record on a 1500-byte-MTU link reaches
the collector, because nothing trims it. Under both fixes it would be trimmed to
1232 on a platform that reports the conservative floor. Determinism is bought
with some records that currently get through whole.

That argues for the platform-side shape plus a better MaxPayload where the
stack can tell us — but that is a design decision, not a foregone one.

Acceptance

  • A record larger than the path can carry is trimmed and delivered rather than
    lost, on every shipped datagram platform
  • Trimming still respects UTF-8 codepoint boundaries
    (SolidSyslogUdpPayload_TrimToCodepointBoundary)
  • A record that fits is never trimmed
  • The exception notes come off the affected platform pages

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions