SD_VARLIN...D_UPGRADE(3)
π sd_varlink_reply_and_upgrade β bestie, we're leaving Varlink behind
okay so real talk: this is the sd_varlink_reply_and_upgrade family from sd-varlink.h (section 3 of the manual, if you're keeping score). It's giving "we had a whole Varlink convo and now we're switching protocols mid-call, no biggie." Let me walk you through it π«Ά
β¨ NAME β¨
sd_varlink_reply_and_upgrade, sd_varlink_respond_and_upgrade, sd_varlink_respond_and_upgradeb, sd_varlink_respond_and_upgradebo, sd_varlink_bind_upgrade, sd_varlink_upgrade_t β reply to a Varlink method call and then take over the connection for a raw protocol. main character energy fr π
π SYNOPSIS π
#include <systemd/sd-varlink.h>
typedef int (*sd_varlink_upgrade_t)(sd_varlink *link, int input_fd, int output_fd, void *userdata);
int sd_varlink_reply_and_upgrade(sd_varlink *link,
sd_json_variant *parameters,
int *ret_input_fd, int *ret_output_fd);
int sd_varlink_respond_and_upgrade(sd_varlink *link,
sd_json_variant *parameters);
int sd_varlink_respond_and_upgradeb(sd_varlink *link, ...);
int sd_varlink_respond_and_upgradebo(sd_varlink *link, ...);
int sd_varlink_bind_upgrade(sd_varlink *link,
sd_varlink_upgrade_t callback);
πΈ DESCRIPTION πΈ
So these functions are the server side of a Varlink protocol upgrade. Here's the tea: a Varlink client can ask for an upgrade when it invokes a method (peep sd_varlink_call(3) and the SD_VARLINK_METHOD_UPGRADE flag that gets passed to method callbacks π). When a method is invoked that way, the server is allowed to send one final reply and then straight-up abandon the Varlink protocol on that connection entirely β handing the underlying socket or pipe file descriptors back to the caller so an arbitrary, non-Varlink ("raw") protocol can be spoken over them instead. It's literally the same vibe as HTTP's "Upgrade:" mechanism, and it's so useful for methods that negotiate a switch to a streaming or binary protocol. obsessed β¨
sd_varlink_reply_and_upgrade()
This one sends a final reply to the currently processed method call, then takes over the connection's file descriptors synchronously. It wants:
- the Varlink connection object (
link) - a JSON object with the reply parameters β which may be
NULL, no pressure bestie - two output pointers for the file descriptors
The parameters object gets validated against the method's declared reply signature, if known. And the reply is flushed to the connection before the file descriptors come back to you, so the client has received the full reply before the caller starts speaking the upgraded protocol. On success the connection is detached from its event loop (if there is one) and disconnected, and ownership of the file descriptors is transferred to the caller β which is now responsible for eventually closing them with close(2). you break it, you close it π
The returned file descriptors are switched to blocking mode. Now, for bidirectional sockets, a single underlying file descriptor carries both directions β in that case ret_input_fd and ret_output_fd come back as two independent (duplicated) descriptors referring to the same socket, so they may be closed separately. For transports backed by a pair of pipes, the two descriptors are different and refer to the distinct read and write ends. Either ret_input_fd or ret_output_fd (but not both) may be NULL; in that case the unwanted direction is shut down (if they refer to the same socket, see shutdown(2)) or closed (if they're separate file descriptors) rather than returned. cute, right? π
β οΈ heads up bestie:sd_varlink_reply_and_upgrade()blocks synchronously until the reply has been flushed to the socket. A misbehaving or adversarial client that just stops reading could stall the caller. So it should not be used in servers that multiplex many Varlink connections in a single event loop, because one stalled connection would block progress on all the others. That's giving main-character-syndrome-in-a-bad-way. Usesd_varlink_respond_and_upgrade()in that case instead, periodt.
sd_varlink_respond_and_upgrade()
The asynchronous counterpart, the glow-up version π It enqueues the final reply and returns immediately β no blocking, and it doesn't return the file descriptors directly. The reply then gets flushed by the event loop during regular sd_varlink_process(3) invocations. Once the reply has been fully flushed, the connection's file descriptors are handed to the upgrade callback that you previously registered with sd_varlink_bind_upgrade(), and the Varlink connection is disconnected. This variant is the right choice for servers handling many connections concurrently, because it never blocks on a single client. slay π
sd_varlink_respond_and_upgradeb()
Similar to sd_varlink_respond_and_upgrade(), but instead of expecting a fully constructed sd_json_variant object carrying the reply parameters, that object gets constructed on-the-fly from the variadic argument list β in a style identical to sd_json_build(3). β¨
sd_varlink_respond_and_upgradebo()
Identical to sd_varlink_respond_and_upgradeb(), except an enclosing JSON object is added implicitly, so the argument list is expected to consist of object field pairs only β in a style identical to sd_json_buildo(3). the "o" stands for "object, obviously" π¦
sd_varlink_bind_upgrade()
This one registers the upgrade callback that gets invoked once a reply enqueued via sd_varlink_respond_and_upgrade() (or one of its variants) has been flushed to the connection. The callback is of type sd_varlink_upgrade_t and receives:
- the Varlink connection object
- the input and output file descriptors of the (now upgraded) connection
- the userdata pointer associated with the connection (see
sd_varlink_set_userdata(3))
Ownership of the two file descriptors is transferred to the callback β regardless of whether the callback later fails or not. No take-backs π«Ά The descriptor semantics (blocking mode, duplication for bidirectional sockets, distinct ends for pipe pairs) match exactly what's described for sd_varlink_reply_and_upgrade() above. And passing NULL as the callback removes a previously registered callback. clean up after yourself, bestie π
β RETURN VALUE β
On success, sd_varlink_reply_and_upgrade(), sd_varlink_respond_and_upgrade(), sd_varlink_respond_and_upgradeb() and sd_varlink_respond_and_upgradebo() return a positive integer. sd_varlink_bind_upgrade() returns a non-negative integer on success. On failure, they all return a negative errno-style error code. as they should π
π Errors
Returned errors may indicate the following problems, and yes we're going through all of them:
-EINVALβ An argument is invalid. (you passed something cursed π)-ENOTCONNβ The Varlink connection object is not connected. (the link said "it's not me, it's you" π)-EBUSYβ The connection is not currently processing a method call, so there is no reply to send. When returned bysd_varlink_bind_upgrade(), a different upgrade callback was already registered on the connection. (one upgrade at a time, this is a monogamous connection β)-EPROTOβ The currently processed method call did not request a protocol upgrade, hence the connection may not be taken over. (rude of you to assume tbh)-EBADMSGβ The client sent unexpected data before the upgrade completed, i.e. it pipelined raw protocol data before receiving the upgrade reply. (jumping the gun, not cute π)-ENOMEMβ Memory allocation failed. (the vibes ran out of RAM π)
π§ NOTES π§
The functions described here are available as a shared library, which can be compiled against and linked to with the libsystemd pkg-config(1) file. iconic, honestly.
The code described here uses getenv(3), which is declared to be not multi-thread-safe. That means the code calling the functions described here must not call setenv(3) from a parallel thread. It's recommended to only do calls to setenv() from an early phase of the program, when no other threads have been started. no sneaky threading shenanigans, bestie π«Ά
π HISTORY π
sd_varlink_reply_and_upgrade()was added in version 261.sd_varlink_respond_and_upgrade(),sd_varlink_respond_and_upgradeb(),sd_varlink_respond_and_upgradebo()andsd_varlink_bind_upgrade()were added in version 262.
they're new, they're fresh, they're upgraded β¨
π SEE ALSO π
systemd(1), sd-varlink(3), sd_varlink_reply(3), sd_varlink_call(3), sd_varlink_call_and_upgrade(3), sd_varlink_process(3), sd_varlink_set_userdata(3), sd_json_build(3)
and that's the whole page, bestie π this one ships with systemd 262.1 β go forth and upgrade those connections, you absolute legend. mwah π
π¦ where this page comes from
- arch rolling: systemd-libs 262.1-1 Β· LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later WITH Linux-syscall-note
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms