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 <stdbool.h>
6 : : #include <stddef.h>
7 : : #include <stdint.h>
8 : :
9 : : #include "SolidSyslogError.h"
10 : : #include "SolidSyslogNullSender.h"
11 : : #include "SolidSyslogPrival.h"
12 : : #include "SolidSyslogSender.h"
13 : : #include "SolidSyslogSenderCategories.h"
14 : : #include "SolidSyslogSenderDefinition.h"
15 : : #include "SolidSyslogSwitchingSender.h"
16 : : #include "SolidSyslogSwitchingSenderErrors.h"
17 : : #include "SolidSyslogSwitchingSenderPrivate.h"
18 : :
19 : : const struct SolidSyslogErrorSource SolidSyslogSwitchingSenderErrorSource = {
20 : : "SwitchingSender",
21 : : SolidSyslogSwitchingSenderErrors_Name
22 : : };
23 : :
24 : : static bool SwitchingSender_Send(struct SolidSyslogSender* base, const void* buffer, size_t size);
25 : : static void SwitchingSender_Disconnect(struct SolidSyslogSender* base);
26 : :
27 : : static inline struct SolidSyslogSwitchingSender* SwitchingSender_SelfFromBase(struct SolidSyslogSender* base);
28 : : static inline void SwitchingSender_SelectSender(struct SolidSyslogSwitchingSender* self);
29 : : static inline bool SwitchingSender_SenderChanged(
30 : : const struct SolidSyslogSwitchingSender* self,
31 : : const struct SolidSyslogSender* requestedSender
32 : : );
33 : : static inline void SwitchingSender_SwitchTo(
34 : : struct SolidSyslogSwitchingSender* self,
35 : : struct SolidSyslogSender* newCurrent
36 : : );
37 : : static inline struct SolidSyslogSender* SwitchingSender_RequestedSender(struct SolidSyslogSwitchingSender* self);
38 : : static inline void SwitchingSender_ReportOutOfRange(struct SolidSyslogSwitchingSender* self);
39 : :
40 : 175 : void SolidSyslogSwitchingSender_Initialise(
41 : : struct SolidSyslogSender* base,
42 : : const struct SolidSyslogSwitchingSenderConfig* config
43 : : )
44 : : {
45 : 175 : struct SolidSyslogSwitchingSender* self = SwitchingSender_SelfFromBase(base);
46 : 175 : self->Base.Send = SwitchingSender_Send;
47 : 175 : self->Base.Disconnect = SwitchingSender_Disconnect;
48 : 175 : self->Config = *config;
49 : 175 : self->CurrentSender = SolidSyslogNullSender_Get();
50 : 175 : self->OutOfRangeReported = false;
51 : 175 : }
52 : :
53 : 175 : void SolidSyslogSwitchingSender_Cleanup(struct SolidSyslogSender* base)
54 : : {
55 : : /* Overwrite the abstract base with the shared NullSender vtable so use-after-destroy
56 : : * is a safe no-op. SwitchingSender does not own its inner senders' connections, so
57 : : * unlike UdpSender/StreamSender there is nothing to disconnect first. Derived fields
58 : : * are private to this TU; the next SolidSyslogSwitchingSender_Initialise overwrites them. */
59 : 175 : *base = *SolidSyslogNullSender_Get();
60 : 175 : }
61 : :
62 : 4123 : static bool SwitchingSender_Send(struct SolidSyslogSender* base, const void* buffer, size_t size)
63 : : {
64 : 4123 : struct SolidSyslogSwitchingSender* self = SwitchingSender_SelfFromBase(base);
65 : 4123 : SwitchingSender_SelectSender(self);
66 : 4123 : return SolidSyslogSender_Send(self->CurrentSender, buffer, size);
67 : : }
68 : :
69 : 6 : static void SwitchingSender_Disconnect(struct SolidSyslogSender* base)
70 : : {
71 : 6 : struct SolidSyslogSwitchingSender* self = SwitchingSender_SelfFromBase(base);
72 : 6 : SolidSyslogSender_Disconnect(self->CurrentSender);
73 : 6 : }
74 : :
75 : 4304 : static inline struct SolidSyslogSwitchingSender* SwitchingSender_SelfFromBase(struct SolidSyslogSender* base)
76 : : {
77 : 4304 : return (struct SolidSyslogSwitchingSender*) base;
78 : : }
79 : :
80 : 4123 : static inline void SwitchingSender_SelectSender(struct SolidSyslogSwitchingSender* self)
81 : : {
82 : 4123 : struct SolidSyslogSender* requestedSender = SwitchingSender_RequestedSender(self);
83 : :
84 [ + + ]: 4123 : if (SwitchingSender_SenderChanged(self, requestedSender))
85 : : {
86 : 177 : SwitchingSender_SwitchTo(self, requestedSender);
87 : : }
88 : 4123 : }
89 : :
90 : 4123 : static inline bool SwitchingSender_SenderChanged(
91 : : const struct SolidSyslogSwitchingSender* self,
92 : : const struct SolidSyslogSender* requestedSender
93 : : )
94 : : {
95 : 4123 : return requestedSender != self->CurrentSender;
96 : : }
97 : :
98 : 177 : static inline void SwitchingSender_SwitchTo(
99 : : struct SolidSyslogSwitchingSender* self,
100 : : struct SolidSyslogSender* newCurrent
101 : : )
102 : : {
103 : 177 : SolidSyslogSender_Disconnect(self->CurrentSender);
104 : 177 : self->CurrentSender = newCurrent;
105 : 177 : }
106 : :
107 : : /* An out-of-range selector index resolves to the shared NullSender.
108 : : * NullSender.Send returns true so the Service algorithm drops the message - a
109 : : * misconfigured selector must not retain messages in the Store - and the loss
110 : : * is reported. */
111 : 4123 : static inline struct SolidSyslogSender* SwitchingSender_RequestedSender(struct SolidSyslogSwitchingSender* self)
112 : : {
113 : 4123 : struct SolidSyslogSender* result = SolidSyslogNullSender_Get();
114 : 4123 : uint8_t index = self->Config.Selector(self->Config.SelectorContext);
115 : :
116 [ + + ]: 4123 : if (index < self->Config.SenderCount)
117 : : {
118 : 3371 : result = self->Config.Senders[index];
119 : 3371 : self->OutOfRangeReported = false;
120 : : }
121 : : else
122 : : {
123 : 752 : SwitchingSender_ReportOutOfRange(self);
124 : : }
125 : :
126 : 4123 : return result;
127 : : }
128 : :
129 : : /* One report stands for a run of out-of-range indexes; the next index in range
130 : : * ends the run. Checked where the index is read rather than on a switch, as
131 : : * CurrentSender starts as the NullSender and a selector out of range from the
132 : : * first Send never switches. */
133 : 752 : static inline void SwitchingSender_ReportOutOfRange(struct SolidSyslogSwitchingSender* self)
134 : : {
135 [ + + ]: 752 : if (!self->OutOfRangeReported)
136 : : {
137 : 42 : SwitchingSender_Report(
138 : : SOLIDSYSLOG_SEVERITY_CRITICAL,
139 : : SOLIDSYSLOG_CAT_SENDER_RECORDS_LOST,
140 : : SOLIDSYSLOG_SWITCHING_SENDER_ERROR_SELECTOR_OUT_OF_RANGE
141 : : );
142 : 42 : self->OutOfRangeReported = true;
143 : : }
144 : 752 : }
|