4.20 The Descriptor Store
A service may hand file descriptors to the manager and get them back after a restart it did not choose. This is what lets a stateful daemon — one holding a listening socket, say — restart without dropping what it already had.
The manager MUST support a per-service maximum, which MAY be zero. Zero disables the store for that service, and a service MUST NOT assume a store exists.
4.20.1 Storing #
On an authenticated datagram carrying FDSTORE=1 with descriptors
attached, the manager MUST:
- If the store is disabled for this service, close the descriptors and record the rejection.
- If the store already holds its maximum, close the descriptors and record the rejection. It MUST NOT evict an existing entry — a full store is full, and silently discarding something the service is relying on to survive a restart would be worse than refusing the new one.
- Store them under the value of
FDNAMEif present and non-empty, and under the namestoredotherwise. - Note
FDPOLL=0if present.
A datagram MAY carry several descriptors. Each becomes its own entry under the one name, and each is independently subject to the maximum — so a datagram carrying more than will fit has some stored and the rest closed.
Several entries MAY share a name.
FDPOLL=0 asks the manager not to monitor the descriptors for error
conditions. A manager MAY monitor stored descriptors and remove ones
that have become invalid; a manager that does not MUST still accept the
field.
4.20.2 Removing #
FDSTOREREMOVE=1 with FDNAME MUST remove every entry of that name and
close its descriptors. A name matching nothing is a no-op and MUST NOT
be an error.
FDSTOREREMOVE=1 without FDNAME MUST be treated as a malformed
line, rejecting the whole datagram (§4.17). A remove with no name has no
defined meaning, and the alternative readings — remove everything,
remove the default name, do nothing — are far enough apart that guessing
between them silently is worse than refusing.
4.20.3 Returning them #
When the service starts again, the manager MUST pass the stored descriptors to the new process:
- Placed consecutively, starting at descriptor 3, with close-on-exec cleared.
LISTEN_FDSset to the number of descriptors passed.LISTEN_FDNAMESset to the names, colon-separated, in the same order as the descriptor numbers.LISTEN_PIDset to the new process's own PID.- The store cleared.
LISTEN_PID is what lets a service verify that the variables are
addressed to it rather than inherited from an ancestor. A conforming
client checks it against its own PID before trusting LISTEN_FDS, and
treats a mismatch as meaning no descriptors were passed — so a manager
that omits it hands descriptors to a service that will not take them.
All four variables MUST be absent when no descriptors are passed, and
the manager MUST NOT allow any of them to be set by a configurable
environment layer. A LISTEN_FDS reaching a service that was passed
nothing points its descriptor-adopting code at whatever happens to be at
descriptor 3.
Descriptors are returned to the service's main process only. A hook or a probe MUST NOT receive them.
The store MUST be cleared once the descriptors have been passed. The manager MUST NOT clear it when a start attempt fails before that point — the descriptors are still the service's, and the next attempt should get them.
A returned listening socket conveys, to every client that connects, the
identity of the process that called listen() on it — the previous
instance of the service. A service that receives listening sockets from
the store SHOULD restamp them with its own identity before accepting
(the Peios Kernel TRM §3.5), so that clients verifying the peer see the
instance actually serving them.
4.20.4 When the store is emptied #
The manager MUST clear the store, closing its descriptors, when:
- the service is stopped deliberately — by a client, or as part of a system shutdown; or
- the service's definition is withdrawn and its entry is finally discarded.
The manager MUST NOT clear it on a restart the service did not ask for — a crash, or a restart policy acting on one. That case is the entire purpose of the mechanism: the descriptors survive exactly the restart the service could not prepare for.