Repository navigation
The failure-policy release. 0.3.0 lets a device decide what a full queue gives up,
reports every failed call a platform makes with the platform's own code, names every
error it raises, and adds VxWorks 6.4.
Still 0.x, for the reason 0.1.0 gave: the label describes platform breadth and the
absence of field integrations, not the maturity of the code. This release does break
the public API. Every break is listed below, under Before you upgrade.
What's in this release
- A discard policy for every queue. The ring, the store and the logger ask one
function of yours what a full queue gives up - the oldest records, the newest, or
the logger itself under Halt - at the moment each has to decide, so the answer can
change on a running device.OnHalttells the device when the logger stops. - Loss is reported once per run. The buffers, the store, the senders and the
logger each report when a run of losses starts, and the sequence number shows each
loss at the collector. - A store that fails stops using its device. The first failed device operation
freezes the store, reported once; delivery continues without storage. - A stored record that fails verification is discarded and the rest delivered;
one the policy cannot yet check waits for its key. - Errors name themselves. Severity, category and detail each have a name function,
and a platform's own code - errno, an FRESULT, an lfs error - travels in the event's
NativeCode. - The IPv4 payload limit is stated where the stack cannot discover the path MTU.
- Every transport refuses Open while open, every TCP stream bounds its connect at
five minutes, and no stream takes a record after the collector has closed the
connection.
Platforms added: VxWorks 6.4. The full list is POSIX, Windows, C11 atomics, OpenSSL,
Mbed TLS, lwIP Raw API, lwIP Sockets API, FreeRTOS-Plus-TCP, FreeRTOS, CMSIS-RTOS2,
VxWorks 6.4, ChaN FatFs, FreeRTOS-Plus-FAT and LittleFS.
Before you upgrade
These break source compatibility with 0.2.0.
Wiring the logger:
- The circular buffer takes a discard policy.
SolidSyslogCircularBuffer_Create
takes two more arguments, aSolidSyslogDiscardPolicyFunctionand its context.
NULL, NULLbuilds, but applies Oldest: a full ring now drops its oldest records to
make room, where 0.2.0 refused the newest. To keep 0.2.0's behaviour, pass a
function that answersSOLIDSYSLOG_DISCARD_POLICY_NEWEST. - The block store takes its policy as a function. In
SolidSyslogBlockStoreConfig,DiscardPolicyis replaced byGetDiscardPolicy
andDiscardPolicyContext, andOnStoreFull,StoreFullContextand the
SolidSyslogStoreFullCallbacktype are removed.NULLapplies Oldest, as a zeroed
0.2.0 config did. - Halt belongs to the logger. A store whose policy answers Halt refuses the record
that does not fit, as under Newest. The logger stops only when its own policy
answers Halt, set through the newGetDiscardPolicyandDiscardPolicyContexton
SolidSyslogConfig. Give the logger, the store and the buffer the same function,
and move anOnStoreFullcallback to the logger's newOnHaltandHaltContext.
A logger left on the default carries on past a full store, and the records the
store refuses are lost and reported asSOLIDSYSLOG_CAT_STORE_RECORDS_LOST. A halt
no longer latches: the firstSolidSyslog_Serviceafter the policy stops answering
Halt resumes, with everything held still in place. SolidSyslogStore_IsHaltedis removed, with the Store vtable'sIsHaltedslot.
SolidSyslog_ServicereturnsSOLIDSYSLOG_SERVICE_HALTEDwhile the logger is
halted, andOnHaltis called when it halts.- Sleep takes a
uint32_t.SolidSyslogSleepFunction,SolidSyslogPosix_Sleep
andSolidSyslogWindows_Sleeptakeuint32_t millisecondsrather thanint.
Change the parameter of any sleep function you wrote. - A connect deadline is at most five minutes. A
SOLIDSYSLOG_TCP_CONNECT_TIMEOUT_MSaboveSOLIDSYSLOG_TCP_CONNECT_TIMEOUT_MS_MAX
stops the build, and aSolidSyslogTcpConnectTimeoutFunctionthat answers more is
held to it. - A manifest or IDE build needs the new source list. 0.3.0 adds Core sources,
among them the functions that name error codes, which every shipped error source
refers to, so a project still compiling 0.2.0's list does not link. Regenerate it
with themanifesttarget. CMake andsolidsyslog.mkconsumers pick the new
sources up unaided.
Platform packs:
- Three datagrams take a config.
SolidSyslogLwipRawDatagram_Create,
SolidSyslogLwipSocketDatagram_CreateandSolidSyslogPlusTcpDatagram_Createeach
take a pointer to a config that states the IPv4 payload the path carries, which
these stacks cannot discover.NULLkeeps 0.2.0's 480 octets, now the
SOLIDSYSLOG_UDP_IPV4_PAYLOAD_LIMITtunable. - The POSIX message-queue buffer takes a mutex and a discard policy, and no
message size.SolidSyslogPosixMessageQueueBuffer_Createtakes a mutex first,
maxMessagesas asize_trather than along, and a discard-policy function and
its context last.maxMessageSizeis gone: the queue's messages are
SOLIDSYSLOG_MAX_MESSAGE_SIZEbytes. PassSolidSyslogPosixMutex_Create()unless
one thread both logs and callsSolidSyslog_Service. The queue's name is unlinked
as soon as it is open, so it is reachable by name only for that moment and a crash
leaves none behind; a queue that already exists under the name is refused,
reported as ERROR with the errno, where 0.2.0 opened it.NULLfor the policy applies Oldest: a full queue now gives up
its oldest record, where 0.2.0 dropped the newest, and a function answering
SOLIDSYSLOG_DISCARD_POLICY_NEWESTkeeps 0.2.0's behaviour. A full queue is
reported asSOLIDSYSLOG_CAT_BUFFER_RECORDS_LOSTat WARNING, once per run of
losses, where 0.2.0 raisedSOLIDSYSLOG_CAT_BUFFER_BACKEND_FAILEDat ERROR for
every refused record.
Error handlers:
SolidSyslogErrorEventhas two new fields and a new order:Severity,
Category,HasNativeCode,Source,Detail,NativeCode. A handler that reads
the fields by name needs no change; code that builds an event with a positional
initialiser does.- A handler must not call back into SolidSyslog - not
SolidSyslog_Log, not
SolidSyslog_Service, nor any Create or Destroy. 0.2.0's documentation did not say
so. A handler that logs its events through the library has to record them instead,
and log them from your own code once it has returned. - Eight new categories can reach a handler:
SOLIDSYSLOG_CAT_BUFFER_RECORDS_LOST,
SOLIDSYSLOG_CAT_DATAGRAM_NEXT_HOP_UNRESOLVED,SOLIDSYSLOG_CAT_FILE_IO_FAILED,
SOLIDSYSLOG_CAT_SENDER_RECORDS_LOST,SOLIDSYSLOG_CAT_STORE_WRITE_FAILED,
SOLIDSYSLOG_CAT_STORE_FROZEN,SOLIDSYSLOG_CAT_STORE_RECORD_DISCARDEDand
SOLIDSYSLOG_CAT_STORE_RECORDS_LOST. Check what yours does with a category it does
not recognise.
Adapters you wrote yourself:
- Buffer has a new
IsFullslot, and it is not optional.SolidSyslog_Service
calls it whenever it holds a record for the sender, so a buffer written for 0.2.0
that leaves it unset still builds, and calls through a null pointer once a send
fails with no store. A buffer that never queues answers false. - Store:
Writereturnsenum SolidSyslogStoreWriteResultrather thanbool,
and theIsHaltedslot is gone. - BlockDevice and File:
Sizereturnsbooland writes the size through a new
parameter, andSolidSyslogBlockDevice_SizeandSolidSyslogFile_Sizechange with
it. Return false when the size cannot be learned: a store takes that as a failed
device, where 0.2.0's 0 on error read as an empty block. - SecurityPolicy:
OpenRecordreturnsenum SolidSyslogSecurityPolicyOpenResult
rather thanbool. AnswerSOLIDSYSLOG_SECURITY_POLICY_OPEN_REJECTEDfor a record
that fails verification, which the store discards, and
SOLIDSYSLOG_SECURITY_POLICY_OPEN_COULD_NOT_RUNwhere the key is unavailable or the
backend fails, which the store keeps and tries again. - Datagram and Stream must refuse
Openon a transport that is already open:
return false, keep what is held, and report it. A Datagram over a stack that drops
what it has accepted while it resolves the next hop confirms the next hop before
answering SENT, and a Stream'sSendmakes sure the peer has not closed its end
before taking a record.SolidSyslogDatagramDefinition.hand
SolidSyslogStreamDefinition.hstate each in full. - Error sources have a
DetailNamefield. Set it to your role's
SolidSyslog<Role>Errors_Nameso a handler can name your codes, and report a
platform's own code withSolidSyslog_ErrorWithNativeCode.
These build unchanged but behave differently:
- Mount the store's volume before creating the store. The block store opens its
device when it is created, and a failure there freezes it, reported as
SOLIDSYSLOG_CAT_STORE_FROZENwithSOLIDSYSLOG_BLOCK_STORE_ERROR_OPEN_FAILED.
Create the store once the volume is mounted, and the logger after it. - A store whose device fails stops using it. The first failed device operation
is reported once; delivery continues without storage until the store is created
again, and what the device held stays on it for the next start. - A stored record the policy cannot check is kept. A keyed policy that cannot get
its key while reading a record leaves it in the store, with the records behind it,
and tries again on the next pass. 0.2.0 discarded it. - With no store, a refused record is held, not dropped at once.
SolidSyslog_Serviceretries it on each pass and returns
SOLIDSYSLOG_SERVICE_BLOCKEDmeanwhile. Records logged in the meantime wait in the
buffer, and once it fills the logger's policy decides: under the default, Oldest,
the held record goes first. A store that has frozen behaves the same way. - The record Service works on lives in the logger, not on the stack of the task
that calls it. Static RAM grows bySOLIDSYSLOG_MAX_MESSAGE_SIZEfor each logger in
the pool - 480 bytes at the defaults - and the service task's stack needs that
much less. SolidSyslogSwitchingSender_Createrefuses a NULL element withinSenderCount,
and aSenderCountof 0, and returns the NullSender, so nothing is sent through it.
A selector that answers an index out of range still routes the record to the
NullSender, and the loss is now reported asSOLIDSYSLOG_CAT_SENDER_RECORDS_LOSTat
CRITICAL, once per run, where 0.2.0 said nothing.- The UDP sender reports a record it cannot send even trimmed. One that trims to
nothing, or is refused for size again once trimmed, is discarded as before, and the
loss is now reported asSOLIDSYSLOG_CAT_SENDER_RECORDS_LOSTat ERROR, once per run. - On POSIX, a dead peer is detected at the keepalive window.
TCP_USER_TIMEOUTis
set to the idle period plus the interval across every probe, 85 s at the defaults,
so a silent peer is dropped one window after it last sent anything and an
unacknowledged write one window after it was sent. 0.2.0 set a fixed 30 s, which on
Linux also cut keepalive short at about 55 s. To detect sooner, lower the three
SOLIDSYSLOG_TCP_KEEPALIVE_*tunables. Deletecounts an absent path as removed on ChaN FatFs, FreeRTOS-Plus-FAT, POSIX
and Windows, as the File contract has always said. 0.2.0 answered false, which froze
the store as a media fault at the next eviction or drain.SolidSyslogBlockStore_Createrefuses a policy whose trailer does not fit. A
SolidSyslogSecurityPolicywith aTrailerSizeaboveSOLIDSYSLOG_MAX_INTEGRITY_SIZE,
and a NULL config orBlockDevice, are each reported at CRITICAL underBAD_CONFIG
and Create returns the NullStore. 0.2.0 stored records with the Null policy,
unprotected and unreported, in the first case.- Both TLS streams poll the handshake every 10 ms, not every millisecond. The
budget still counts the sleeps requested, so a sleep that rounds up to a coarse tick
stretches it ten times less. - The lwIP Sockets TCP stream compiles only where
LWIP_SOCKET_SELECTis on. A
build with it off keeps the rest of the pack, where 0.2.0 failed to compile it. - The OpenSSL stream keeps a stricter TLS setting. Its security level 2 and
TLS 1.2 minimum are floors: a higher@SECLEVELin a profile'sCipherList, or a
stricterMinProtocolor@SECLEVELin the host'sopenssl.cnf, now applies,
where 0.2.0 lowered it to the floor. A TLS 1.2 collector without secure
renegotiation is refused even whereopenssl.cnfsetsUnsafeLegacyServerConnect
orUnsafeLegacyRenegotiation.
A collector accepted before may now be refused. MaxBlocksis clamped to 98, not 99.- A second
Openon an open transport fails and is reported at CRITICAL. Only
code that opens a transport it holds can meet this. - On FreeRTOS-Plus-TCP, a datagram to an unresolved next hop waits up to
SOLIDSYSLOG_DATAGRAM_RESOLVE_WAIT_MS, 100 ms by default, on the task that sends,
where 0.2.0 yielded once for about 50 ms. A next hop still unresolved fails the
send and is reported.
Documentation corrected in this release, where acting on the old text would have
cost you:
- A CMake host consumer of the OpenSSL pack calls
find_package(OpenSSL 3.0 REQUIRED)itself; the documented recipe did not, and does not configure. SolidSyslogMetaSdwithout a counter is a fatalBAD_CONFIG: no meta element is
emitted. The docs called it degraded, and said everysequenceIdwould read 1.- FreeRTOS needs
configUSE_MUTEXES=1as well as static allocation; without both the
mutex does not link. - The POSIX message-queue buffer needs a real mutex whenever
LogandServicerun
on different threads. - Rotating the Mbed TLS PEM-buffer source means writing the new PEM over the original
buffer, whoseLengthat Create covers the largest PEM it will hold, with NULs after
the PEM; re-pointing the config, as documented, changes nothing. - On every address pack, an address drawn past its pool is a shared fallback, not a
Null object. One SolidSyslog instance per process is the supported configuration,
and under it no two senders use the fallback at once. - A
SolidSyslogSleepFunctionmust wait at least the time asked: connect, resolve
and handshake budgets count the sleeps requested, so a yield spends them at once. - A stored record is sealed per record, not as a store: removing records, or flipping
which are marked sent, is not detected on the device.
RFC compliance at this release
| RFC | Total | Supported | Partial | Not Met | N/A |
|---|---|---|---|---|---|
| RFC 5424 | 40 | 33 | 0 | 0 | 7 |
| RFC 5425 | 21 | 16 | 0 | 0 | 5 |
| RFC 5426 | 16 | 7 | 0 | 0 | 9 |
| RFC 6587 | 8 | 7 | 0 | 0 | 1 |
No clause changed status since 0.2.0, and no row was added or removed. One note
changed: the RFC 5424 section 5 row now names the UDP sender's trim of a record the
path will not carry as the one deliberate alteration, which RFC 5426 section 3.1
permits, and its status stays Supported.
The maintainer's assessment, not a certification. Each status describes the
library with a conforming platform supplying the roles it needs, and depends on
the components selected, including any you write yourself, which the library
cannot speak for. The full matrix at this release, one row and one note per
clause:
docs/rfc-compliance.md at v0.3.0.
Known limitations
Every limitation 0.2.0 shipped with is resolved in this release: the OpenSSL
pin-first ordering (#919),
the lwIP Raw resolver's IPv6 answer
(#842), and the store's
unreported verification and write failures
(#921).
The pre-release audit of 0.3.0 read every documentation page against the code
again and questioned nine behaviours
(#1061); each is fixed in
this release or confirmed as designed and documented as such, so no defect is
tracked at this release. Where a platform diverges from a role's contract by
design, that is stated on the platform's page rather than here.
Verifying this release
Six assets are attached: the CycloneDX SBOM, the content-tree SHA-256, and the
offline documentation bundle, each with a cosign signature bundle. Signing is
keyless via GitHub OIDC, so each signature commits to the workflow run that
produced it. There is no personal key. The content-tree hash is reproducible from
any clone. Commands:
docs/security/release-verification.md at v0.3.0.
The check that matters is that a bundle verifies, not that the assets are
present.
⚠ BREAKING CHANGES
- the POSIX message-queue buffer creates its own queue, at the library's message size (#1078)
Features
- a sender reports the records it drops (#1079) (a800364)
- every axis of an error event names itself (#1039) (5e96a25)
- every File and network pack reports the failing call and its native code (#1052) (cce9a8f)
- S41.01 Core builds for VxWorks 6.4 and boots in QEMU Malta (#937) (02115ab)
- S41.02 VxWorks 6.4 pack skeleton and mutex (#932) (2bcd6c8)
- S41.03 VxWorks 6.4 UDP datagram and IPv4 resolver (#939) (ca677f0)
- S41.07 remote runner for the VxWorks 6.4 QEMU target (#940) (f5399cb)
- S41.09 VxWorks 6.4 atomic counter (#960) (23ee76e)
- S41.10 VxWorks 6.4 clock, uptime, hostname and sleep (#956) (f27408d)
- S41.11 VxWorks 6.4 TCP stream (#961) (67a86c3)
- S41.12 VxWorks 6.4 file, for the store (#968) (b45e937)
- S41.14 VxWorks 6.4 store on HRFS as well as dosFs (#970) (195d3e7)
- S41.15 VxWorks 6.4 file and store report the file system call that failed (#976) (87da5fb)
- S41.16 VxWorks 6.4 datagram returns SENT only once the next hop is resolved (#988) (4d15707)
- S42.01 the Plus-TCP datagram returns SENT only once the next hop is resolved (#1036) (69d4fe6)
- S43.01 the store freezes on its first media fault (#1011) (697a99d)
- S43.02 the store discards a record that fails verification and carries on (#1013) (14f3da9)
- S43.03 a security policy's OpenRecord says whether it opened, rejected, or could not run (#1014) (57ea219)
- S43.04 the store reports once when records start being lost (#1015) (8561254)
- S43.05 buffers report once when records start being lost (#1016) (9dfdf91)
- S43.07 with a store that keeps nothing, Service stops at the first failed send (#1022) (cfef5f1)
- S43.08 the discard policy is set once, on the logger (#1025) (b1d8d59)
- S43.10 File Size reports failure rather than an empty file (#1027) (212fc60)
- S43.11 buffers apply the discard policy (#1028) (20ea7f8)
- the error event carries the platform's native code as a field (#1042) (436454d)
- the integrator states the IPv4 payload limit where the stack cannot discover the path MTU (#1035) (4c73ade)
- VxWorks 6.4 platform support (6819c2b)
Bug Fixes
- every File Delete counts an absent path as removed (#1072) (a8df857)
- every TCP stream bounds the connect deadline at five minutes (#1031) (fa83da7)
- every transport refuses Open while it is already open, and reports it (#1049) (a01cc8e)
- no stream takes a record after the collector has closed the connection (#1053) (dac9961)
- SolidSyslogBlockStore_Create refuses a NULL config or BlockDevice (#1075) (b685658)
- the block store refuses a security policy whose trailer does not fit (#1074) (26d5acc)
- the block store's used bytes follow occupancy again after a refusal (#1032) (7b6c76b)
- the lwIP Raw resolvers refuse an IPv6 answer the transports cannot send to (#1045) (a70d9ad)
- the lwIP Sockets stream compiles only where lwip_select exists (#1073) (abe68f2)
- the Mbed TLS stream tells the library it is deliberately not naming the peer (#1044) (89a6d99)
- the OpenSSL stream names a fingerprint mismatch ahead of an expired issuer (#1034) (29631ed), closes #919
- the OpenSSL stream raises its TLS floors and keeps a stricter setting (#1076) (aab701c)
- the POSIX message-queue buffer creates its own queue, at the library's message size (#1078) (0a2cd3c)
- the POSIX TCP stream derives its user timeout from the keepalive tunables (#1077) (3c99803)
- the TLS handshake polls every 10 ms, so a coarse sleep stretches its budget less (#1069) (bb33aa6)
- VxWorks 6.4 Delete answers removed only for a removed or absent path (#1040) (44f243f)
- VxWorks 6.4 Exists asks stat, not open, whether a path is there (#1041) (7019a30)
- VxWorks 6.4 review sweep - resolver, runner hardening, and comments and docs said once (#981) (bd687bc)