Branch data Line data Source code
1 : : /* SPDX-FileCopyrightText: Copyright 2026 Cozens Software Solutions Limited
2 : : * SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0 OR LicenseRef-COSOSO-Commercial
3 : : */
4 : :
5 : : #include "SolidSyslogUdpPayload.h"
6 : : #include "SolidSyslogTunables.h"
7 : : #include "SolidSyslogUtf8.h"
8 : :
9 : : enum
10 : : {
11 : : IPV4_HEADER_BYTES = 20U,
12 : : IPV6_HEADER_BYTES = 40U,
13 : : UDP_HEADER_BYTES = 8U,
14 : : /* RFC 5426 section 3.2: the message sizes a receiver of each family must accept,
15 : : * and the sizes it names as the safest assumption for a sender that does
16 : : * not know the path MTU. Each leaves room for options or extension headers
17 : : * inside the family's minimum MTU - 576 for IPv4, 1280 for IPv6. */
18 : : IPV4_UNKNOWN_PATH_MESSAGE_BYTES = 480U,
19 : : IPV6_UNKNOWN_PATH_MESSAGE_BYTES = 1180U
20 : : };
21 : :
22 : : static inline size_t UdpPayload_FindLastCodepointStart(const uint8_t* buffer, size_t length);
23 : : static inline bool UdpPayload_LastCodepointExtendsPastCut(
24 : : const uint8_t* buffer,
25 : : size_t length,
26 : : size_t lastCodepointStart
27 : : );
28 : : static inline size_t UdpPayload_ExpectedSequenceLength(uint8_t startByte);
29 : :
30 : 5 : size_t SolidSyslogUdpPayload_FromMtu(size_t mtu, bool isIpv6)
31 : : {
32 [ + + ]: 5 : size_t overhead = (isIpv6 ? IPV6_HEADER_BYTES : IPV4_HEADER_BYTES) + UDP_HEADER_BYTES;
33 : 5 : size_t payload = 0U;
34 [ + + ]: 5 : if (mtu > overhead)
35 : : {
36 : 4 : payload = mtu - overhead;
37 : : }
38 : 5 : return payload;
39 : : }
40 : :
41 : 11 : size_t SolidSyslogUdpPayload_UnknownPath(bool isIpv6)
42 : : {
43 [ + + ]: 11 : return isIpv6 ? (size_t) IPV6_UNKNOWN_PATH_MESSAGE_BYTES : (size_t) IPV4_UNKNOWN_PATH_MESSAGE_BYTES;
44 : : }
45 : :
46 : 83 : size_t SolidSyslogUdpPayload_Stated(SolidSyslogUdpPayloadLimitFunction limit, void* context)
47 : : {
48 : 83 : size_t stated = 0U;
49 [ + + ]: 83 : if (limit != NULL)
50 : : {
51 : 23 : stated = limit(context);
52 : : }
53 [ + + ]: 83 : if (stated == 0U)
54 : : {
55 : 65 : stated = (size_t) SOLIDSYSLOG_UDP_IPV4_PAYLOAD_LIMIT;
56 : : }
57 : 83 : return stated;
58 : : }
59 : :
60 : 33 : size_t SolidSyslogUdpPayload_TrimToCodepointBoundary(const uint8_t* buffer, size_t length)
61 : : {
62 : 33 : size_t trimmed = length;
63 [ + + ]: 33 : if (trimmed > 0U)
64 : : {
65 : 22 : size_t lastCodepointStart = UdpPayload_FindLastCodepointStart(buffer, trimmed);
66 [ + + ]: 22 : if (UdpPayload_LastCodepointExtendsPastCut(buffer, trimmed, lastCodepointStart))
67 : : {
68 : 7 : trimmed = lastCodepointStart;
69 : : }
70 : : }
71 : 33 : return trimmed;
72 : : }
73 : :
74 : 22 : static inline size_t UdpPayload_FindLastCodepointStart(const uint8_t* buffer, size_t length)
75 : : {
76 : 22 : size_t startIndex = length - 1U;
77 [ + + + + ]: 32 : while ((startIndex > 0U) && SolidSyslogUtf8_IsContinuationByte((char) buffer[startIndex]))
78 : : {
79 : 10 : startIndex--;
80 : : }
81 : 22 : return startIndex;
82 : : }
83 : :
84 : 22 : static inline bool UdpPayload_LastCodepointExtendsPastCut(
85 : : const uint8_t* buffer,
86 : : size_t length,
87 : : size_t lastCodepointStart
88 : : )
89 : : {
90 : 22 : return (lastCodepointStart + UdpPayload_ExpectedSequenceLength(buffer[lastCodepointStart])) > length;
91 : : }
92 : :
93 : : /* 11110xxx is the only remaining pattern - invalid bytes never reach here
94 : : * because the formatter guarantees valid UTF-8 upstream. */
95 : 22 : static inline size_t UdpPayload_ExpectedSequenceLength(uint8_t startByte)
96 : : {
97 : 22 : char b = (char) startByte;
98 : 22 : size_t length = 0U;
99 [ + + ]: 22 : if (SolidSyslogUtf8_IsAsciiByte(b))
100 : : {
101 : 12 : length = 1U;
102 : : }
103 [ + + ]: 10 : else if (SolidSyslogUtf8_IsTwoByteLead(b))
104 : : {
105 : 3 : length = 2U;
106 : : }
107 [ + + ]: 7 : else if (SolidSyslogUtf8_IsThreeByteLead(b))
108 : : {
109 : 3 : length = 3U;
110 : : }
111 : : else
112 : : {
113 : 4 : length = 4U;
114 : : }
115 : 22 : return length;
116 : : }
|