Index · Directives systemd 262~devel

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 take over the connection for a raw protocol

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

These functions implement the server side of a Varlink protocol upgrade. A Varlink client may request an upgrade when invoking a method (see sd_varlink_call(3) and the SD_VARLINK_METHOD_UPGRADE flag passed to method callbacks). If a method is invoked this way, the server may send one final reply and then abandon the Varlink protocol on the connection entirely, handing the underlying socket or pipe file descriptors back to the caller so that an arbitrary, non-Varlink ("raw") protocol may be spoken over them instead. This is useful for methods that negotiate a switch to a streaming or binary protocol, in a manner similar to the "Upgrade:" mechanism of HTTP.

sd_varlink_reply_and_upgrade() sends a final reply to the currently processed method call and then takes over the connection's file descriptors synchronously. It takes the Varlink connection object, a JSON object with the reply parameters (which may be NULL), and two output pointers for the file descriptors. The parameters object is validated against the method's declared reply signature, if known. The reply is flushed to the connection before the file descriptors are returned, so that 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 any) and disconnected, and ownership of the file descriptors is transferred to the caller, which is responsible for eventually closing them with close(2).

The returned file descriptors are switched to blocking mode. For bidirectional sockets a single underlying file descriptor carries both directions; in this case ret_input_fd and ret_output_fd are returned 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 differ 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 separate file descriptors) rather than returned.

Note that sd_varlink_reply_and_upgrade() blocks synchronously until the reply has been flushed to the socket. A misbehaving or adversarial client that stops reading could stall the caller. It should hence not be used in servers that multiplex many Varlink connections in a single event loop, as one stalled connection would block progress on all others. Use sd_varlink_respond_and_upgrade() in that case instead.

sd_varlink_respond_and_upgrade() is the asynchronous counterpart of sd_varlink_reply_and_upgrade(). It enqueues the final reply and returns immediately, without blocking and without returning the file descriptors directly. The reply is subsequently 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 previously registered with sd_varlink_bind_upgrade(), and the Varlink connection is disconnected. This variant is the right choice for servers that handle many connections concurrently, as it never blocks on a single client.

sd_varlink_respond_and_upgradeb() is similar to sd_varlink_respond_and_upgrade(), but instead of expecting a fully constructed sd_json_variant object carrying the reply parameters, this object is constructed on-the-fly from the variadic argument list, in a style identical to sd_json_build(3). sd_varlink_respond_and_upgradebo() is identical to sd_varlink_respond_and_upgradeb(), but an enclosing JSON object is added implicitly, so that the argument list is expected to consist of object field pairs only, in a style identical to sd_json_buildo(3).

sd_varlink_bind_upgrade() registers the upgrade callback that is 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, and 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 if the callback later fails or not). The descriptor semantics (blocking mode, duplication for bidirectional sockets, distinct ends for pipe pairs) match those described for sd_varlink_reply_and_upgrade() above. Passing NULL as callback removes a previously registered callback.

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.

Errors

Returned errors may indicate the following problems:

-EINVAL

An argument is invalid.

-ENOTCONN

The Varlink connection object is not connected.

-EBUSY

The connection is not currently processing a method call, so there is no reply to send. When returned by sd_varlink_bind_upgrade(), a different upgrade callback was already registered on the connection.

-EPROTO

The currently processed method call did not request a protocol upgrade, hence the connection may not be taken over.

-EBADMSG

The client sent unexpected data before the upgrade completed, i.e. it pipelined raw protocol data before receiving the upgrade reply.

-ENOMEM

Memory allocation failed.

Notes

Functions described here are available as a shared library, which can be compiled against and linked to with the libsystemd pkg-config(1) file.

The code described here uses getenv(3), which is declared to be not multi-thread-safe. This means that the code calling the functions described here must not call setenv(3) from a parallel thread. It is recommended to only do calls to setenv() from an early phase of the program when no other threads have been started.

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() and sd_varlink_bind_upgrade() were added in version 262.

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)