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 "SolidSyslogSwitchingSender.h"
6 : :
7 : : #include <stdbool.h>
8 : : #include <stddef.h>
9 : : #include <stdint.h>
10 : :
11 : : #include "SolidSyslogError.h"
12 : : #include "SolidSyslogErrorCategory.h"
13 : : #include "SolidSyslogNullSender.h"
14 : : #include "SolidSyslogPoolAllocator.h"
15 : : #include "SolidSyslogPrival.h"
16 : : #include "SolidSyslogSwitchingSenderErrors.h"
17 : : #include "SolidSyslogSwitchingSenderPrivate.h"
18 : : #include "SolidSyslogTunables.h"
19 : :
20 : : struct SolidSyslogSender;
21 : :
22 : : static bool SwitchingSender_IsValidConfig(const struct SolidSyslogSwitchingSenderConfig* config);
23 : : static inline bool SwitchingSender_HasNullInnerSender(const struct SolidSyslogSwitchingSenderConfig* config);
24 : : static inline size_t SwitchingSender_IndexFromHandle(const struct SolidSyslogSender* base);
25 : : static inline void SwitchingSender_CleanupAtIndex(size_t index, void* context);
26 : :
27 : : static bool SwitchingSender_InUse[SOLIDSYSLOG_SWITCHING_SENDER_POOL_SIZE];
28 : : static struct SolidSyslogSwitchingSender SwitchingSender_Pool[SOLIDSYSLOG_SWITCHING_SENDER_POOL_SIZE];
29 : : static struct SolidSyslogPoolAllocator SwitchingSender_Allocator = {
30 : : SwitchingSender_InUse,
31 : : SOLIDSYSLOG_SWITCHING_SENDER_POOL_SIZE
32 : : };
33 : :
34 : 186 : struct SolidSyslogSender* SolidSyslogSwitchingSender_Create(const struct SolidSyslogSwitchingSenderConfig* config)
35 : : {
36 : 186 : struct SolidSyslogSender* handle = SolidSyslogNullSender_Get();
37 [ + + ]: 186 : if (SwitchingSender_IsValidConfig(config))
38 : : {
39 : 177 : size_t index = SolidSyslogPoolAllocator_AcquireFirstFree(&SwitchingSender_Allocator);
40 [ + + ]: 177 : if (SolidSyslogPoolAllocator_IndexIsValid(&SwitchingSender_Allocator, index))
41 : : {
42 : 175 : SolidSyslogSwitchingSender_Initialise(&SwitchingSender_Pool[index].Base, config);
43 : 175 : handle = &SwitchingSender_Pool[index].Base;
44 : : }
45 : : else
46 : : {
47 : 2 : SwitchingSender_Report(
48 : : SOLIDSYSLOG_POOL_EXHAUSTED_SEVERITY,
49 : : SOLIDSYSLOG_CAT_POOL_EXHAUSTED,
50 : : SOLIDSYSLOG_SWITCHING_SENDER_ERROR_POOL_EXHAUSTED
51 : : );
52 : : }
53 : : }
54 : 186 : return handle;
55 : : }
56 : :
57 : 186 : static bool SwitchingSender_IsValidConfig(const struct SolidSyslogSwitchingSenderConfig* config)
58 : : {
59 : 186 : bool valid = false;
60 [ + + ]: 186 : if (config == NULL)
61 : : {
62 : 2 : SwitchingSender_Report(
63 : : SOLIDSYSLOG_BAD_CONFIG_FATAL_SEVERITY,
64 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
65 : : SOLIDSYSLOG_SWITCHING_SENDER_ERROR_NULL_CONFIG
66 : : );
67 : : }
68 [ + + ]: 184 : else if (config->Senders == NULL)
69 : : {
70 : 1 : SwitchingSender_Report(
71 : : SOLIDSYSLOG_BAD_CONFIG_FATAL_SEVERITY,
72 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
73 : : SOLIDSYSLOG_SWITCHING_SENDER_ERROR_NULL_SENDERS
74 : : );
75 : : }
76 [ + + ]: 183 : else if (config->SenderCount == 0U)
77 : : {
78 : 2 : SwitchingSender_Report(
79 : : SOLIDSYSLOG_BAD_CONFIG_FATAL_SEVERITY,
80 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
81 : : SOLIDSYSLOG_SWITCHING_SENDER_ERROR_NO_SENDERS
82 : : );
83 : : }
84 [ + + ]: 181 : else if (config->Selector == NULL)
85 : : {
86 : 1 : SwitchingSender_Report(
87 : : SOLIDSYSLOG_BAD_CONFIG_FATAL_SEVERITY,
88 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
89 : : SOLIDSYSLOG_SWITCHING_SENDER_ERROR_NULL_SELECTOR
90 : : );
91 : : }
92 [ + + ]: 180 : else if (SwitchingSender_HasNullInnerSender(config))
93 : : {
94 : 3 : SwitchingSender_Report(
95 : : SOLIDSYSLOG_BAD_CONFIG_FATAL_SEVERITY,
96 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
97 : : SOLIDSYSLOG_SWITCHING_SENDER_ERROR_NULL_INNER_SENDER
98 : : );
99 : : }
100 : : else
101 : : {
102 : 177 : valid = true;
103 : : }
104 : 186 : return valid;
105 : : }
106 : :
107 : : /* The Selector's index is bounds-checked on every Send, but the element it
108 : : * lands on is not: a NULL there would be called as a vtable. Refusing the
109 : : * array here keeps that check off the Send path. */
110 : 180 : static inline bool SwitchingSender_HasNullInnerSender(const struct SolidSyslogSwitchingSenderConfig* config)
111 : : {
112 : 180 : bool hole = false;
113 [ + + + + ]: 443 : for (size_t index = 0U; (index < config->SenderCount) && !hole; index++)
114 : : {
115 : 263 : hole = config->Senders[index] == NULL;
116 : : }
117 : 180 : return hole;
118 : : }
119 : :
120 : 178 : void SolidSyslogSwitchingSender_Destroy(struct SolidSyslogSender* base)
121 : : {
122 : 178 : size_t index = SwitchingSender_IndexFromHandle(base);
123 : 178 : bool released =
124 [ + + + + ]: 354 : SolidSyslogPoolAllocator_IndexIsValid(&SwitchingSender_Allocator, index) &&
125 : 176 : SolidSyslogPoolAllocator_FreeIfInUse(&SwitchingSender_Allocator, index, SwitchingSender_CleanupAtIndex, NULL);
126 [ + + ]: 178 : if (!released)
127 : : {
128 : 3 : SwitchingSender_Report(
129 : : SOLIDSYSLOG_UNKNOWN_DESTROY_SEVERITY,
130 : : SOLIDSYSLOG_CAT_UNKNOWN_DESTROY,
131 : : SOLIDSYSLOG_SWITCHING_SENDER_ERROR_UNKNOWN_DESTROY
132 : : );
133 : : }
134 : 178 : }
135 : :
136 : 178 : static inline size_t SwitchingSender_IndexFromHandle(const struct SolidSyslogSender* base)
137 : : {
138 : 178 : size_t result = SOLIDSYSLOG_SWITCHING_SENDER_POOL_SIZE;
139 [ + + ]: 180 : for (size_t poolIndex = 0U; poolIndex < SOLIDSYSLOG_SWITCHING_SENDER_POOL_SIZE; poolIndex++)
140 : : {
141 [ + + ]: 178 : if (base == &SwitchingSender_Pool[poolIndex].Base)
142 : : {
143 : 176 : result = poolIndex;
144 : 176 : break;
145 : : }
146 : : }
147 : 178 : return result;
148 : : }
149 : :
150 : 175 : static inline void SwitchingSender_CleanupAtIndex(size_t index, void* context)
151 : : {
152 : : (void) context;
153 : 175 : SolidSyslogSwitchingSender_Cleanup(&SwitchingSender_Pool[index].Base);
154 : 175 : }
|