SolidSyslog coverage report
Current view: top level - Core/Source - SolidSyslogStreamSender.c (source / functions) Coverage Total Hit
Test: SolidSyslog Lines: 100.0 % 90 90
Test Date: 2026-11-12 23:14:35 Functions: 100.0 % 19 19
Branches: 100.0 % 28 28

             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 "SolidSyslogEndpoint.h"
      10                 :             : #include "SolidSyslogEndpointHostPrivate.h"
      11                 :             : #include "SolidSyslogError.h"
      12                 :             : #include "SolidSyslogFormatter.h"
      13                 :             : #include "SolidSyslogNullSender.h"
      14                 :             : #include "SolidSyslogResolver.h"
      15                 :             : #include "SolidSyslogSenderDefinition.h"
      16                 :             : #include "SolidSyslogSenderHealth.h"
      17                 :             : #include "SolidSyslogStream.h"
      18                 :             : #include "SolidSyslogStreamSender.h"
      19                 :             : #include "SolidSyslogStreamSenderErrors.h"
      20                 :             : #include "SolidSyslogStreamSenderPrivate.h"
      21                 :             : #include "SolidSyslogTransport.h"
      22                 :             : 
      23                 :             : const struct SolidSyslogErrorSource SolidSyslogStreamSenderErrorSource = {
      24                 :             :     "StreamSender",
      25                 :             :     SolidSyslogStreamSenderErrors_Name
      26                 :             : };
      27                 :             : 
      28                 :             : struct SolidSyslogAddress;
      29                 :             : struct SolidSyslogFormatter;
      30                 :             : 
      31                 :             : enum
      32                 :             : {
      33                 :             :     UINT32_MAX_DECIMAL_DIGITS = 10,
      34                 :             :     OCTET_COUNTING_SEPARATOR = 1,
      35                 :             :     OCTET_COUNTING_NULL_TERMINATOR = 1,
      36                 :             :     OCTET_COUNTING_PREFIX_CAPACITY =
      37                 :             :         UINT32_MAX_DECIMAL_DIGITS + OCTET_COUNTING_SEPARATOR + OCTET_COUNTING_NULL_TERMINATOR
      38                 :             : };
      39                 :             : 
      40                 :             : static bool StreamSender_Send(struct SolidSyslogSender* base, const void* buffer, size_t size);
      41                 :             : static void StreamSender_Disconnect(struct SolidSyslogSender* base);
      42                 :             : 
      43                 :             : static inline void StreamSender_UpdateDeliveryHealth(struct SolidSyslogStreamSender* self, bool delivered);
      44                 :             : static inline struct SolidSyslogStreamSender* StreamSender_SelfFromBase(struct SolidSyslogSender* base);
      45                 :             : 
      46                 :             : static inline bool StreamSender_Reconcile(struct SolidSyslogStreamSender* self);
      47                 :             : static inline void StreamSender_DisconnectIfStale(struct SolidSyslogStreamSender* self);
      48                 :             : static inline bool StreamSender_ConfigurationMoved(
      49                 :             :     const struct SolidSyslogStreamSender* self,
      50                 :             :     uint32_t endpointVersion,
      51                 :             :     uint32_t streamVersion
      52                 :             : );
      53                 :             : static inline bool StreamSender_EnsureConnected(struct SolidSyslogStreamSender* self);
      54                 :             : static inline bool StreamSender_Connected(const struct SolidSyslogStreamSender* self);
      55                 :             : static bool StreamSender_Connect(struct SolidSyslogStreamSender* self);
      56                 :             : static bool StreamSender_ResolveDestination(struct SolidSyslogStreamSender* self, struct SolidSyslogAddress* addr);
      57                 :             : static inline void StreamSender_CloseStream(struct SolidSyslogStreamSender* self);
      58                 :             : static bool StreamSender_TransmitFramed(struct SolidSyslogStreamSender* self, const void* buffer, size_t size);
      59                 :             : static struct SolidSyslogFormatter* StreamSender_FormatOctetCountingPrefix(
      60                 :             :     SolidSyslogFormatterStorage* storage,
      61                 :             :     size_t messageSize
      62                 :             : );
      63                 :             : static bool StreamSender_SendBytes(struct SolidSyslogStreamSender* self, const void* data, size_t len);
      64                 :             : static void StreamSender_NilEndpoint(struct SolidSyslogEndpoint* endpoint, void* context);
      65                 :             : static uint32_t StreamSender_NilEndpointVersion(void* context);
      66                 :             : 
      67                 :         219 : void SolidSyslogStreamSender_Initialise(
      68                 :             :     struct SolidSyslogSender* base,
      69                 :             :     const struct SolidSyslogStreamSenderConfig* config
      70                 :             : )
      71                 :             : {
      72                 :         219 :     struct SolidSyslogStreamSender* self = StreamSender_SelfFromBase(base);
      73                 :         219 :     self->Base.Send = StreamSender_Send;
      74                 :         219 :     self->Base.Disconnect = StreamSender_Disconnect;
      75                 :         219 :     self->Config.Resolver = config->Resolver;
      76                 :         219 :     self->Config.Stream = config->Stream;
      77                 :         219 :     self->Config.Address = config->Address;
      78         [ +  + ]:         219 :     self->Config.Endpoint = (config->Endpoint != NULL) ? config->Endpoint : StreamSender_NilEndpoint;
      79                 :         219 :     self->Config.EndpointVersion =
      80         [ +  + ]:         219 :         (config->EndpointVersion != NULL) ? config->EndpointVersion : StreamSender_NilEndpointVersion;
      81                 :         219 :     self->Config.EndpointContext = config->EndpointContext;
      82                 :         219 :     self->Connected = false;
      83                 :         219 :     self->DeliveryHealthy = true;
      84                 :         219 :     self->LastEndpointVersion = 0;
      85                 :         219 :     self->LastStreamVersion = 0;
      86                 :         219 : }
      87                 :             : 
      88                 :         219 : void SolidSyslogStreamSender_Cleanup(struct SolidSyslogSender* base)
      89                 :             : {
      90                 :             :     /* Disconnect first so the live Config.Stream is still reachable; then overwrite the
      91                 :             :      * abstract base with the shared NullSender vtable so use-after-destroy is a safe
      92                 :             :      * no-op rather than a NULL-fn-pointer crash. Derived fields are private to this TU
      93                 :             :      * so the next SolidSyslogStreamSender_Initialise overwrites them; no need to wipe here. */
      94                 :         219 :     StreamSender_Disconnect(base);
      95                 :         219 :     *base = *SolidSyslogNullSender_Get();
      96                 :         219 : }
      97                 :             : 
      98                 :        3457 : static bool StreamSender_Send(struct SolidSyslogSender* base, const void* buffer, size_t size)
      99                 :             : {
     100                 :        3457 :     struct SolidSyslogStreamSender* self = StreamSender_SelfFromBase(base);
     101   [ +  +  +  + ]:        3457 :     bool delivered = StreamSender_Reconcile(self) && StreamSender_TransmitFramed(self, buffer, size);
     102                 :        3457 :     StreamSender_UpdateDeliveryHealth(self, delivered);
     103                 :        3457 :     return delivered;
     104                 :             : }
     105                 :             : 
     106                 :        3457 : static inline void StreamSender_UpdateDeliveryHealth(struct SolidSyslogStreamSender* self, bool delivered)
     107                 :             : {
     108                 :             :     static const struct SolidSyslogSenderHealthReporter reporter = {
     109                 :             :         .Source = &SolidSyslogStreamSenderErrorSource,
     110                 :             :         .FailedDetail = (int32_t) SOLIDSYSLOG_STREAM_SENDER_ERROR_DELIVERY_FAILED,
     111                 :             :         .RestoredDetail = (int32_t) SOLIDSYSLOG_STREAM_SENDER_ERROR_DELIVERY_RESTORED
     112                 :             :     };
     113                 :        3457 :     SolidSyslogSenderHealth_Update(&self->DeliveryHealthy, delivered, &reporter);
     114                 :        3457 : }
     115                 :             : 
     116                 :        3457 : static inline bool StreamSender_Reconcile(struct SolidSyslogStreamSender* self)
     117                 :             : {
     118                 :        3457 :     StreamSender_DisconnectIfStale(self);
     119                 :        3457 :     return StreamSender_EnsureConnected(self);
     120                 :             : }
     121                 :             : 
     122                 :        3457 : static inline void StreamSender_DisconnectIfStale(struct SolidSyslogStreamSender* self)
     123                 :             : {
     124                 :        3457 :     uint32_t endpointVersion = self->Config.EndpointVersion(self->Config.EndpointContext);
     125                 :        3457 :     uint32_t streamVersion = SolidSyslogStream_Version(self->Config.Stream);
     126                 :             : 
     127         [ +  + ]:        3457 :     if (StreamSender_ConfigurationMoved(self, endpointVersion, streamVersion))
     128                 :             :     {
     129                 :         114 :         StreamSender_Disconnect(&self->Base);
     130                 :         114 :         self->LastEndpointVersion = endpointVersion;
     131                 :         114 :         self->LastStreamVersion = streamVersion;
     132                 :             :     }
     133                 :        3457 : }
     134                 :             : 
     135                 :        3457 : static inline bool StreamSender_ConfigurationMoved(
     136                 :             :     const struct SolidSyslogStreamSender* self,
     137                 :             :     uint32_t endpointVersion,
     138                 :             :     uint32_t streamVersion
     139                 :             : )
     140                 :             : {
     141   [ +  +  +  + ]:        3457 :     return (endpointVersion != self->LastEndpointVersion) || (streamVersion != self->LastStreamVersion);
     142                 :             : }
     143                 :             : 
     144                 :        3457 : static inline bool StreamSender_EnsureConnected(struct SolidSyslogStreamSender* self)
     145                 :             : {
     146   [ +  +  +  + ]:        3457 :     return StreamSender_Connected(self) || StreamSender_Connect(self);
     147                 :             : }
     148                 :             : 
     149                 :        5494 : static inline bool StreamSender_Connected(const struct SolidSyslogStreamSender* self)
     150                 :             : {
     151                 :        5494 :     return self->Connected;
     152                 :             : }
     153                 :             : 
     154                 :        1668 : static bool StreamSender_Connect(struct SolidSyslogStreamSender* self)
     155                 :             : {
     156                 :        1668 :     struct SolidSyslogAddress* addr = self->Config.Address;
     157                 :             : 
     158         [ +  + ]:        1668 :     if (StreamSender_ResolveDestination(self, addr))
     159                 :             :     {
     160                 :        1665 :         self->Connected = SolidSyslogStream_Open(self->Config.Stream, addr);
     161                 :             :     }
     162                 :             : 
     163                 :        1668 :     return StreamSender_Connected(self);
     164                 :             : }
     165                 :             : 
     166                 :        1668 : static bool StreamSender_ResolveDestination(struct SolidSyslogStreamSender* self, struct SolidSyslogAddress* addr)
     167                 :             : {
     168                 :             :     SolidSyslogFormatterStorage hostStorage[SOLIDSYSLOG_FORMATTER_STORAGE_SIZE(SOLIDSYSLOG_MAX_HOST_SIZE)];
     169                 :        1668 :     struct SolidSyslogFormatter* hostFormatter = SolidSyslogFormatter_Create(hostStorage, SOLIDSYSLOG_MAX_HOST_SIZE);
     170                 :             :     struct SolidSyslogEndpointHost hostSink;
     171                 :        1668 :     SolidSyslogEndpointHost_FromFormatter(&hostSink, hostFormatter);
     172                 :        1668 :     struct SolidSyslogEndpoint endpoint = {.Host = &hostSink, .Port = 0};
     173                 :             : 
     174                 :        1668 :     self->Config.Endpoint(&endpoint, self->Config.EndpointContext);
     175                 :             : 
     176                 :        1668 :     return SolidSyslogResolver_Resolve(
     177                 :             :         self->Config.Resolver,
     178                 :             :         SOLIDSYSLOG_TRANSPORT_TCP,
     179                 :             :         SolidSyslogFormatter_AsFormattedBuffer(hostFormatter),
     180                 :        1668 :         endpoint.Port,
     181                 :             :         addr
     182                 :             :     );
     183                 :             : }
     184                 :             : 
     185                 :         369 : static void StreamSender_Disconnect(struct SolidSyslogSender* base)
     186                 :             : {
     187                 :         369 :     struct SolidSyslogStreamSender* self = StreamSender_SelfFromBase(base);
     188                 :             : 
     189         [ +  + ]:         369 :     if (StreamSender_Connected(self))
     190                 :             :     {
     191                 :         183 :         StreamSender_CloseStream(self);
     192                 :             :     }
     193                 :         369 : }
     194                 :             : 
     195                 :        4045 : static inline struct SolidSyslogStreamSender* StreamSender_SelfFromBase(struct SolidSyslogSender* base)
     196                 :             : {
     197                 :        4045 :     return (struct SolidSyslogStreamSender*) base;
     198                 :             : }
     199                 :             : 
     200                 :        1267 : static inline void StreamSender_CloseStream(struct SolidSyslogStreamSender* self)
     201                 :             : {
     202                 :        1267 :     SolidSyslogStream_Close(self->Config.Stream);
     203                 :        1267 :     self->Connected = false;
     204                 :        1267 : }
     205                 :             : 
     206                 :        3056 : static bool StreamSender_TransmitFramed(struct SolidSyslogStreamSender* self, const void* buffer, size_t size)
     207                 :             : {
     208                 :             :     SolidSyslogFormatterStorage prefixStorage[SOLIDSYSLOG_FORMATTER_STORAGE_SIZE(OCTET_COUNTING_PREFIX_CAPACITY)];
     209                 :        3056 :     struct SolidSyslogFormatter* prefix = StreamSender_FormatOctetCountingPrefix(prefixStorage, size);
     210                 :             : 
     211                 :        6112 :     return StreamSender_SendBytes(
     212                 :             :                self,
     213                 :        3056 :                SolidSyslogFormatter_AsFormattedBuffer(prefix),
     214                 :             :                SolidSyslogFormatter_Length(prefix)
     215   [ +  +  +  + ]:        5030 :            ) &&
     216                 :        1974 :            StreamSender_SendBytes(self, buffer, size);
     217                 :             : }
     218                 :             : 
     219                 :        3056 : static struct SolidSyslogFormatter* StreamSender_FormatOctetCountingPrefix(
     220                 :             :     SolidSyslogFormatterStorage* storage,
     221                 :             :     size_t messageSize
     222                 :             : )
     223                 :             : {
     224                 :        3056 :     struct SolidSyslogFormatter* f = SolidSyslogFormatter_Create(storage, OCTET_COUNTING_PREFIX_CAPACITY);
     225                 :        3056 :     SolidSyslogFormatter_Uint32(f, (uint32_t) messageSize);
     226                 :        3056 :     SolidSyslogFormatter_AsciiCharacter(f, ' ');
     227                 :        3056 :     return f;
     228                 :             : }
     229                 :             : 
     230                 :        5030 : static bool StreamSender_SendBytes(struct SolidSyslogStreamSender* self, const void* data, size_t len)
     231                 :             : {
     232                 :        5030 :     bool sent = SolidSyslogStream_Send(self->Config.Stream, data, len);
     233                 :             : 
     234         [ +  + ]:        5030 :     if (!sent)
     235                 :             :     {
     236                 :        1084 :         StreamSender_CloseStream(self);
     237                 :             :     }
     238                 :             : 
     239                 :        5030 :     return sent;
     240                 :             : }
     241                 :             : 
     242                 :        1598 : static void StreamSender_NilEndpoint(struct SolidSyslogEndpoint* endpoint, void* context)
     243                 :             : {
     244                 :             :     (void) context;
     245                 :        1598 :     SolidSyslogEndpointHost_String(endpoint->Host, "", 0);
     246                 :        1598 :     endpoint->Port = 0;
     247                 :        1598 : }
     248                 :             : 
     249                 :        3377 : static uint32_t StreamSender_NilEndpointVersion(void* context)
     250                 :             : {
     251                 :             :     (void) context;
     252                 :        3377 :     return 0U;
     253                 :             : }
        

Generated by: LCOV version 2.0-1